embox

Форк
0
/
bcm283x_spi0.c 
389 строк · 14.0 Кб
1
/**
2
 * @file bcm283x_spi0.c
3
 * @brief 
4
 * @author kpishere
5
 * @version 0.1
6
 * @date 2021.07.16
7
 */
8
#include <errno.h>
9

10
#include <drivers/common/memory.h>
11
#include <drivers/spi.h>
12
#include <embox/unit.h>
13
#include <framework/mod/options.h>
14
#include <hal/reg.h>
15
#include <util/log.h>
16
#include <util/math.h>
17
#include <kernel/printk.h>
18
#include <asm/delay.h>
19
#include <assert.h>
20

21
#include <drivers/dma/pl330_dma.h>
22

23
#include <drivers/gpio/gpio.h>
24
#include <drivers/gpio/bcm283x/bcm283x_gpio.h>
25
#include <drivers/spi.h>
26

27
#include "bcm283x_spi0.h"
28
#include "bcm283x_spi_dev.h"
29

30
#define PBASE                     OPTION_GET(NUMBER,base_addr)
31
#define SPI_BUS_CLOCK_DIVISOR     OPTION_GET(NUMBER,spi_bus_clock_divisor)
32
#define SPI_INT0                  OPTION_GET(NUMBER,spi_int)
33

34

35

36
// command block must be 256 bit aligned in memory
37
#define MEM_ALGN_256 (0x00000020)
38

39
// Toggle an extra GPIO pin at various points to debug/test timing
40
#if 0
41
    #define DRIVER_TESTING
42
    #define PIN ( 1 << 25 )
43
#endif
44

45
/* Errata to BCM2835 behaviour: documentation states that the SPI0 DLEN register is only used for DMA. 
46
 * However, even when DMA is not being utilized, setting it from a value != 0 or 1 gets rid of an 
47
 * excess idle clock cycle that is present when transmitting each byte. (by default in Polled SPI 
48
 * Mode each 8 bits transfer in 9 clocks) With DLEN=2 each byte is clocked to the bus in 8 cycles, 
49
 * observed to improve max throughput from 56.8mbps to 63.3mbps (+11.4%, quite close to the 
50
 * theoretical +12.5%)
51
 * https://www.raspberrypi.org/forums/viewtopic.php?f=44&t=181154
52
 */
53
#define DLEN_NO_DMA_VALUE 2;
54

55
struct bcm283x_spi_regs {
56
    uint32_t cs; /* SPI Master Control and Status */
57
    
58
/* RW: DMA Mode (DMAEN set)
59
    If TA is clear, the first 32-bit write to this register will control 
60
    SPIDLEN and SPICS. Subsequent reads and writes will be taken as 
61
    four-byte data words to be read/written to the FIFOs Poll/Interrupt 
62
    Mode (DMAEN clear, TA set) Writes to the register write bytes to TX FIFO. 
63
    Reads from register read bytes from the RX FIFO
64
 */
65
    uint32_t fifo; /* SPI Master TX and RX FIFOs */
66

67
/* RW: 15:0 Clock Divider SCLK = Core Clock / CDIV
68
    If CDIV is set to 0, the divisor is 65536. The divisor must be a power of 2.
69
    Odd numbers rounded down. The maximum SPI clock rate is of the APB clock.
70
 */
71
    uint32_t clk; /* SPI Master Clock Divider */
72

73
/* RW: 15:0 Data Length - The number of bytes to transfer.
74
    This field is only valid for DMA mode (DMAEN set) and controls how many bytes 
75
    to transmit (and therefore receive).
76
 */     
77
    uint32_t dlen; /* SPI Master Data Length */
78

79
/* RW: 3:0 This sets the Output Hold delay in APB clocks. A value of 0 causes a 1 clock delay. */
80
    uint32_t ltoh; /* SPI LOSSI mode TOH */
81

82
/* RW: This register controls the generation of the DREQ and Panic signals to an 
83
    external DMA engine The DREQ signals are generated when the FIFOs reach their 
84
    defined levels and need servicing. The Panic signals instruct the external DMA engine 
85
    to raise the priority of its AXI requests.*/
86
    uint32_t dc; /* SPI DMA DREQ Controls */
87
};
88

89
#define REGS_SPI0 ((struct bcm283x_spi_regs *)(PBASE))
90
#define BCM283X_SPI0_TX_FIFO_LEN (16*sizeof(uint32_t))
91
#define BCM283X_SPI0_RX_FIFO_LEN (16*sizeof(uint32_t))
92
#define BCM283X_SPI0_TX_FIFO_FL  (4*sizeof(uint32_t))
93
#define BCM283X_SPI0_RX_FIFO_HW  (3*sizeof(uint32_t))
94

95
#define BCM283X_PRIV(x) ((struct bcm283x_spi_dev *)(x)->priv)
96

97
static int bcm283x_spi0_init(void) {
98
    uint32_t pins_spi_Alt0 =( 1 << 7 ) | ( 1 << 8 ) | ( 1 << 9 ) | ( 1 << 10 ) | ( 1 << 11 );    
99
    gpio_setup_mode(GPIO_PORT_A, pins_spi_Alt0, GPIO_MODE_OUT_ALTERNATE | GPIO_ALTERNATE(GFAlt0) );
100

101
#ifdef DRIVER_TESTING
102
    gpio_setup_mode(GPIO_PORT_A, PIN, GPIO_MODE_OUTPUT);
103
#endif
104

105
    // Initialize the Control and Status register to defaults:
106
    //CS=0 (Chip Select), CPHA=0 (Clock Phase), CPOL=0 (Clock Polarity), 
107
    //CSPOL=0 (Chip Select Polarity), TA=0 (Transfer not active), and reset TX and RX queues.
108
    REGS_SPI0->cs = SPI0_CS(0);
109
    REGS_SPI0->clk = SPI_BUS_CLOCK_DIVISOR;
110
    REGS_SPI0->dlen = DLEN_NO_DMA_VALUE;
111

112
    return 0;
113
}
114

115
static irq_return_t bcm283x_spi_intrd_irq_handler(unsigned int irq_nr, void *data);
116

117
static int bcm283x_spi0_attach(struct spi_device *dev) {
118
    int res = 0;
119

120
    if( !(REGS_SPI0->cs & SPI0_CS_INTD) && !(REGS_SPI0->cs & SPI0_CS_INTR) ) {
121
        res = irq_attach(SPI_INT0, bcm283x_spi_intrd_irq_handler, 0x00, dev, "SPI0 IRQ");
122
    }
123
    return res;
124
}
125

126
static int bcm283x_spi0_select(struct spi_device *dev, int cs) {
127
    int res = 0;
128
    if (cs < 0 || cs > 3) {
129
        log_error("Only cs=0..3 are avalable!");
130
        return -EINVAL;
131
    }
132
    if( dev->flags & SPI_CS_ACTIVE ) {
133
    }
134
    if( dev->flags & SPI_CS_INACTIVE ) {
135
    }
136

137
    // If flag set for either interrupt option, register interrupt function
138
    if( dev->flags & SPI_CS_IRQD ) {   
139
        res = bcm283x_spi0_attach(dev);     
140
        REGS_SPI0->cs |= SPI0_CS_INTD;
141
    }
142
    if( dev->flags & SPI_CS_IRQR ) {        
143
        res = bcm283x_spi0_attach(dev);     
144
        REGS_SPI0->cs |= SPI0_CS_INTR;
145
    }
146
    // If no flags set for interrupt, detatch interrupt
147
    if( !(dev->flags & SPI_CS_IRQR) && !(dev->flags & SPI_CS_IRQD)
148
        && irq_nr_valid(SPI_INT0) == 0 ) {
149
        res = irq_detach(SPI_INT0, dev);
150
    }
151

152
    // Enable DMA
153
    if( dev->flags & SPI_CS_DMAEN 
154
        && !(REGS_SPI0->cs & SPI0_CS_DMAEN) ) {
155
        assert( BCM283X_PRIV(dev)->dma_chan_out != BCM283X_PRIV(dev)->dma_chan_in );
156

157
        REGS_SPI0->cs |= SPI0_CS_DMAEN;
158
        REGS_SPI0->dc = BCM283X_PRIV(dev)->dma_levels;
159

160
        /* Set Panic and Priority levels at High 2/3rds and then Low 1/3rd respectively
161
         * If they are not set, DMA_LEVELS() must be about double higher.
162
         */
163
        dma_config_extended(BCM283X_PRIV(dev)->dma_chan_in, NULL, DMA_CS_PANIC_PRIORITY(0x0C) | DMA_CS_PRIORITY(0x06) );
164
        // Channel out receives data from SPI fifo to memory in    
165
        dma_config_extended(BCM283X_PRIV(dev)->dma_chan_out, BCM283X_PRIV(dev)->dma_complete,
166
        		DMA_CS_PANIC_PRIORITY(0x0C) | DMA_CS_PRIORITY(0x06));
167
    }
168

169

170
    // If no flags set for interrupt, cause interrupt to detatch
171
    if( !(dev->flags & SPI_CS_DMAEN) && (REGS_SPI0->cs & SPI0_CS_DMAEN) ) {
172
        dma_config_extended(BCM283X_PRIV(dev)->dma_chan_out, NULL, 0x00);
173
        REGS_SPI0->cs &= ~( SPI0_CS_DMAEN );
174
    }
175

176
    // set default CPHA=0 (Clock Phase), CPOL=0 (Clock Polarity)
177
    REGS_SPI0->cs &= ~(SPI0_CS_CPOL | SPI0_CS_CPHA); 
178
    if(dev->flags & SPI_CS_MODE(SPI_MODE_1)) REGS_SPI0->cs |= SPI0_CS_CPHA;
179
    if(dev->flags & SPI_CS_MODE(SPI_MODE_2)) REGS_SPI0->cs |= SPI0_CS_CPOL;
180

181
    // A clock divisor value is set
182
    if( (dev->flags >> 16) ) {
183
        REGS_SPI0->clk = (dev->flags >> 16);
184
    }
185

186
    // Set the CS lines
187
    REGS_SPI0->cs &= ~SPI0_CS(0xFF);
188
    REGS_SPI0->cs |= SPI0_CS(cs);
189

190
    // Set the CS hold delay
191
    REGS_SPI0->ltoh = 0;
192
    return res;
193
}
194

195
static int bcm283x_spi0_do_transfer(struct spi_device *dev, uint8_t *inbuf
196
        , uint8_t *outbuf, int tx_count, int rx_count) {
197
    int tx_cnt, rx_cnt;
198

199
    irq_lock();
200
    tx_cnt = rx_cnt = 0;
201
    /* Do not add log_debug() or some another stuff here, */
202
    while ( ( tx_cnt < tx_count && inbuf != NULL ) 
203
        ||  (rx_cnt < rx_count && outbuf != NULL ) ) {
204
        if(tx_cnt < tx_count ) {
205
            if( inbuf != NULL ) {
206
                // Wait for FIFO to have 1-byte space    
207
                while( !(REGS_SPI0->cs & SPI0_CS_TXD) ) {
208
#ifdef DRIVER_TESTING
209
                    gpio_set(GPIO_PORT_A, PIN, GPIO_PIN_HIGH );
210
                    gpio_set(GPIO_PORT_A, PIN, GPIO_PIN_LOW );
211
#endif
212
                }; 
213
                REGS_SPI0->fifo = inbuf[tx_cnt++];
214
            } else { 
215
                // write without waiting for buffer ready
216
                REGS_SPI0->fifo = 0x00;
217
            }
218
        }
219
        if( rx_cnt < rx_count && outbuf != NULL ) {
220
            while ( !(REGS_SPI0->cs & SPI0_CS_RXD) ); // Wait for rx byte
221
            outbuf[rx_cnt++] = REGS_SPI0->fifo;
222
        }
223
    }
224
    // read out FIFO incoming buffer
225
    while( REGS_SPI0->cs & SPI0_CS_RXD ) { 
226
        uint32_t discard;
227
        discard += REGS_SPI0->fifo;    
228
    }
229
    // Wait for tx to complete
230
    while( !(REGS_SPI0->cs & SPI0_CS_DONE) ) {
231
#ifdef DRIVER_TESTING
232
        gpio_set(GPIO_PORT_A, PIN, GPIO_PIN_HIGH );
233
        gpio_set(GPIO_PORT_A, PIN, GPIO_PIN_LOW );
234
#endif
235
    };   
236
    irq_unlock();
237

238
    return max(tx_cnt, rx_cnt);         
239
}
240

241
// Interrupt for data send required or complete
242
static irq_return_t bcm283x_spi_intrd_irq_handler(unsigned int irq_nr, void *data) {
243
	irq_return_t ret = IRQ_HANDLED;
244
	struct spi_device *dev = (struct spi_device*) data;
245

246
	// Transmit and receive with CS asserted
247
	if ((REGS_SPI0->cs & (SPI0_CS_DONE | SPI0_CS_TA))
248
			&& BCM283X_PRIV(dev)->count > 0) {
249
		BCM283X_PRIV(dev)->count -= bcm283x_spi0_do_transfer(dev,
250
		BCM283X_PRIV(dev)->in, BCM283X_PRIV(dev)->out,
251
				min(BCM283X_SPI0_TX_FIFO_FL, BCM283X_PRIV(dev)->count),
252
				min(BCM283X_SPI0_TX_FIFO_FL, BCM283X_PRIV(dev)->count));
253
		if (BCM283X_PRIV(dev)->count <= 0) {
254
			REGS_SPI0->cs &= ~SPI0_CS_TA; // De-assert
255
		}
256
		if (BCM283X_PRIV(dev)->send_complete && BCM283X_PRIV(dev)->count <= 0) {
257
			BCM283X_PRIV(dev)->send_complete(dev, BCM283X_PRIV(dev)->count);
258
		}
259
	}
260

261
	// Receive with CS un-asserted
262
	if ((REGS_SPI0->cs & SPI0_CS_RXR)) {
263
		BCM283X_PRIV(dev)->count = bcm283x_spi0_do_transfer(dev,
264
				BCM283X_PRIV(dev)->in, BCM283X_PRIV(dev)->out,
265
					min(BCM283X_SPI0_RX_FIFO_HW, BCM283X_PRIV(dev)->count),
266
					min(BCM283X_SPI0_RX_FIFO_HW, BCM283X_PRIV(dev)->count));
267
		if (BCM283X_PRIV(dev)->received_data && BCM283X_PRIV(dev)->count > 0) {
268
			BCM283X_PRIV(dev)->send_complete(dev, BCM283X_PRIV(dev)->count);
269
		}
270
	}
271
	return ret;
272
}
273

274
static struct dma_ctrl_blk *bcm283x_init_dma_block_spi_in(struct spi_device *dev,
275
		struct dma_mem_handle  *mem_handle, uint32_t offset, void *src, uint32_t bytes,
276
		struct dma_ctrl_blk *next_conbk, bool int_enable) {
277

278
	assert( (((uint32_t)(mem_handle->physical_addr) + offset) & ~MEM_ALGN_256 ) == ((uint32_t)(mem_handle->physical_addr) + offset));
279

280
	struct dma_ctrl_blk *cbp = (struct dma_ctrl_blk *)(mem_handle->physical_addr + offset);
281
	cbp->ti = DMA_TI_PERMAP(DMA_PERMAP_SPI_TX) | DMA_TI_SRC_INC | DMA_TI_DEST_DREQ | DMA_TI_WAIT_RESP;
282
	cbp->dest_ad = (uint32_t)DMA_PERF_TO_BUS((uint32_t)&(REGS_SPI0->fifo));
283
	cbp->stride = 0x0;
284

285
	cbp->source_ad = (uint32_t)DMA_PHYS_TO_BUS((uint32_t)src);
286
	cbp->txfr_len = bytes;
287
	cbp->nextconbk = ( next_conbk == NULL ? 0x00 : (uint32_t)DMA_PHYS_TO_BUS((uint32_t)next_conbk) );
288

289
	if(int_enable){
290
		cbp->ti |= DMA_TI_INTEN;
291
	}
292
	else {
293
		cbp->ti &= ~DMA_TI_INTEN;
294
	}
295

296
	return cbp;
297
}
298

299
static struct dma_ctrl_blk *bcm283x_init_dma_block_spi_out(struct spi_device *dev,
300
		struct dma_mem_handle  *mem_handle, uint32_t offset, void *dest, uint32_t bytes,
301
		struct dma_ctrl_blk *next_conbk, bool int_enable) {
302

303
	assert( (((uint32_t)(mem_handle->physical_addr) + offset) & ~MEM_ALGN_256 ) == ((uint32_t)(mem_handle->physical_addr) + offset));
304

305
	struct dma_ctrl_blk *cbp = (struct dma_ctrl_blk *)(mem_handle->physical_addr + offset);
306
	cbp->ti = DMA_TI_PERMAP(DMA_PERMAP_SPI_RX) | DMA_TI_DEST_INC | DMA_TI_SRC_DREQ | DMA_TI_WAIT_RESP;
307
	cbp->source_ad = (uint32_t)DMA_PERF_TO_BUS((uint32_t)&(REGS_SPI0->fifo));
308
	cbp->stride = 0x0;
309

310
	cbp->dest_ad = (uint32_t)DMA_PHYS_TO_BUS((uint32_t)dest);
311
	cbp->txfr_len = bytes;
312
	cbp->nextconbk = ( next_conbk == NULL ? 0x00 : (uint32_t)DMA_PHYS_TO_BUS((uint32_t)next_conbk) );
313

314
	if(int_enable) {
315
		cbp->ti |= DMA_TI_INTEN;
316
	}
317
	else {
318
		cbp->ti &= ~DMA_TI_INTEN;
319
	}
320

321
	return cbp;
322
}
323

324
/*
325
    // Hi 16 bits are length, lower 8 bits are the lower 8 bits of SPI control register
326
 * 
327
 * For SPI Device: txfr_len is in top sixteen bits and control register settings are in [7:0]
328
 * (the bottom eight bits) for TA = 1, CS, CPOL, CPHA 
329
*/
330

331
static int bcm283x_spi0_transfer(struct spi_device *dev, uint8_t *inbuf, uint8_t *outbuf, int count) {
332

333
    // Interrupt mode
334
    if( ( (REGS_SPI0->cs & SPI0_CS_INTD) || (REGS_SPI0->cs & SPI0_CS_INTR) ) ) {
335
        if(count < 0) {
336
            // count < 0 is signal to trigger interrupt and return
337
            BCM283X_PRIV(dev)->count = -1 * count;    /* set the target amount to output in series of interrupt transfers */
338
            BCM283X_PRIV(dev)->in = inbuf;
339
            BCM283X_PRIV(dev)->out = outbuf;
340
            REGS_SPI0->dlen = DLEN_NO_DMA_VALUE;
341
            REGS_SPI0->cs |= SPI0_CS_CLEAR( SPI0_tx_fifo | SPI0_rx_fifo ) | SPI0_CS_TA; // clear FIFO and Assert
342
            return 0;
343
        } else {
344
            // called in interrupt handler to send/receive data
345
            BCM283X_PRIV(dev)->count -= bcm283x_spi0_do_transfer(dev, inbuf, outbuf, min(BCM283X_SPI0_TX_FIFO_FL,count), BCM283X_SPI0_RX_FIFO_HW);
346
            REGS_SPI0->cs &= ~SPI0_CS_TA; // De-assert
347
            return 0;
348
        }
349
    }
350

351
    // DMA Mode
352
    if(REGS_SPI0->cs & SPI0_CS_DMAEN) { 
353
        REGS_SPI0->dlen = count;    
354

355
        // Receive - start dma transfer
356
        dma_transfer_conbk(BCM283X_PRIV(dev)->dma_chan_out, (volatile struct dma_ctrl_blk *)outbuf);
357
        // Transmit - start dma transfer
358
        dma_transfer_conbk(BCM283X_PRIV(dev)->dma_chan_in, (volatile struct dma_ctrl_blk *)inbuf);
359
        // Activate SPI
360
        REGS_SPI0->cs |= SPI0_CS_ADCS | SPI0_CS_CLEAR( SPI0_tx_fifo | SPI0_rx_fifo ) | SPI0_CS_TA; // clear FIFO and Assert
361
    } else { 
362
        // Poll mode - bytes send, bytes receive
363
        REGS_SPI0->cs |= SPI0_CS_CLEAR( SPI0_tx_fifo | SPI0_rx_fifo ) | SPI0_CS_TA; // clear FIFO and Assert
364

365
        /* because we need to write all tx data before transfer competed. */
366
        REGS_SPI0->dlen = DLEN_NO_DMA_VALUE;
367

368
        bcm283x_spi0_do_transfer(dev, inbuf, outbuf, count, count);
369
        REGS_SPI0->cs &= ~SPI0_CS_TA; // De-assert
370
    }
371
    return 0;
372
}
373

374
struct spi_ops bcm283x_spi0_ops = {
375
    .select   = bcm283x_spi0_select,
376
    .transfer = bcm283x_spi0_transfer,
377
};
378

379
PERIPH_MEMORY_DEFINE(bcm283x_spi0, PBASE, sizeof(struct bcm283x_spi_regs));
380

381
static struct bcm283x_spi_dev bcm283x_spi_dev = {
382
		.regs = REGS_SPI0,
383
		.init_dma_block_spi_in = bcm283x_init_dma_block_spi_in,
384
		.init_dma_block_spi_out = bcm283x_init_dma_block_spi_out
385
};
386

387
SPI_DEV_DEF("spi0", &bcm283x_spi0_ops, &bcm283x_spi_dev, 0);
388

389
EMBOX_UNIT_INIT(bcm283x_spi0_init);
390

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.