1 /***************************************************************************//**
2 * Copyright 2019-2020 Microchip FPGA Embedded Systems Solutions.
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 * PolarFire SoC Microprocessor Subsystem SPI bare metal software driver
7 * implementation.
8 */
9
10 #include <string.h>
11 #include "mpfs_hal/mss_hal.h"
12 #include "mss_spi.h"
13
14 #ifdef __cplusplus
15 extern "C" {
16 #endif
17
18 /***************************************************************************//**
19 * Mask of transfer protocol and SPO, SPH bits within control register.
20 */
21 #define PROTOCOL_MODE_MASK ((uint32_t) 0x0300000Cu)
22
23 /***************************************************************************//**
24 * Mask of the frame count bits within the SPI control register.
25 */
26 #define TXRXDFCOUNT_MASK ((uint32_t) 0x00FFFF00u)
27 #define TXRXDFCOUNT_SHIFT ((uint32_t) 8u)
28 #define BYTESUPPER_MASK ((uint32_t) 0xFFFF0000u)
29 /***************************************************************************//**
30 * SPI hardware FIFO depth.
31 */
32 #define RX_FIFO_SIZE 4u
33 #define BIG_FIFO_SIZE 32u
34
35 /***************************************************************************//**
36 * CONTROL register bit masks
37 */
38 #define CTRL_ENABLE_MASK 0x00000001u
39 #define CTRL_MASTER_MASK 0x00000002u
40
41 /***************************************************************************//**
42 Registers bit masks
43 */
44 /* CONTROL register. */
45 #define MASTER_MODE_MASK 0x00000002u
46 #define CTRL_RX_IRQ_EN_MASK 0x00000010u
47 #define CTRL_TX_IRQ_EN_MASK 0x00000020u
48 #define CTRL_OVFLOW_IRQ_EN_MASK 0x00000040u
49 #define CTRL_URUN_IRQ_EN_MASK 0x00000080u
50 #define CTRL_REG_RESET_MASK 0x80000000u
51 #define BIGFIFO_MASK 0x20000000u
52 #define CTRL_CLKMODE_MASK 0x10000000u
53 #define SPS_MASK 0x04000000u
54
55 /* CONTROL2 register */
56 #define C2_ENABLE_CMD_IRQ_MASK 0x00000010u
57 #define C2_ENABLE_SSEND_IRQ_MASK 0x00000020u
58
59 /* STATUS register */
60 #define TX_DONE_MASK 0x00000001u
61 #define RX_DATA_READY_MASK 0x00000002u
62 #define RX_OVERFLOW_MASK 0x00000004u
63 #define RX_FIFO_EMPTY_MASK 0x00000040u
64 #define TX_FIFO_FULL_MASK 0x00000100u
65 #define TX_FIFO_EMPTY_MASK 0x00000400u
66
67 /* MIS register. */
68 #define TXDONE_IRQ_MASK 0x00000001u
69 #define RXDONE_IRQ_MASK 0x00000002u
70 #define RXOVFLOW_IRQ_MASK 0x00000004u
71 #define TXURUN_IRQ_MASK 0x00000008u
72 #define CMD_IRQ_MASK 0x00000010u
73 #define SSEND_IRQ_MASK 0x00000020u
74
75 /* COMMAND register */
76 #define AUTOFILL_MASK 0x00000001u
77 #define TX_FIFO_RESET_MASK 0x00000008u
78 #define RX_FIFO_RESET_MASK 0x00000004u
79
80 /***************************************************************************//**
81 *
82 */
83 #define RX_IRQ_THRESHOLD (BIG_FIFO_SIZE / 2u)
84
85 /***************************************************************************//**
86 Marker used to detect that the configuration has not been selected for a
87 specific slave when operating as a master.
88 */
89 #define NOT_CONFIGURED 0xFFFFFFFFu
90
91 /***************************************************************************//**
92 Maximum frame length
93 */
94 #define MAX_FRAME_LENGTH 32u
95
96 /***************************************************************************//**
97 * SPI instance data structures for SPI0 and SPI1. A pointer to these data
98 * structures must be used as first parameter to any of the SPI driver functions
99 * to identify the SPI hardware block that will perform the requested operation.
100 */
101 mss_spi_instance_t g_mss_spi0_lo;
102 mss_spi_instance_t g_mss_spi1_lo;
103
104 mss_spi_instance_t g_mss_spi0_hi;
105 mss_spi_instance_t g_mss_spi1_hi;
106
107 /***************************************************************************//*
108 * This peripheral tracks if the SPI peripheral is located on S5 or S6 on AXI
109 * switch. This will be used to determine which SPI instance is to be passed
110 * to SPI interrupt handler. Value 0 = S5(SPI_LO) value 1 = S6(SPI_HI).
111 * Bit positions
112 * 0 -> SPI0
113 * 1 -> SPI1
114 */
115 static uint8_t g_spi_axi_pos = 0u;
116
117 /***************************************************************************//**
118 local functions
119 */
120 static void recover_from_rx_overflow(mss_spi_instance_t * this_spi);
121 static void fill_slave_tx_fifo(mss_spi_instance_t * this_spi);
122 static void read_slave_rx_fifo(mss_spi_instance_t * this_spi);
123 static void mss_spi_isr(mss_spi_instance_t * this_spi);
124
125 /***************************************************************************//**
126 * MSS_SPI_init()
127 * See "mss_spi.h" for details of how to use this function.
128 */
MSS_SPI_init(mss_spi_instance_t * this_spi)129 void MSS_SPI_init
130 (
131 mss_spi_instance_t * this_spi
132 )
133 {
134 uint16_t slave;
135
136 ASSERT((this_spi == &g_mss_spi0_lo) || (this_spi == &g_mss_spi1_lo));
137
138 /* Initialize SPI driver instance data. Relies on the majority
139 * of data requiring 0 for initial state so we just need to fill
140 * with 0s and finish off with a small number of non zero values.
141 * Shut down interrupts from the MSS SPI while we do this */
142 PLIC_DisableIRQ( this_spi->irqn );
143
144 memset(this_spi, 0, sizeof(mss_spi_instance_t));
145
146 this_spi->cmd_done = 1u;
147
148 for (slave = 0u; slave < (uint16_t)MSS_SPI_MAX_NB_OF_SLAVES; slave++)
149 {
150 this_spi->slaves_cfg[slave].ctrl_reg = NOT_CONFIGURED;
151 }
152
153 if (&g_mss_spi0_lo == this_spi)
154 {
155 this_spi->hw_reg = MSS_SPI0_LO_BASE;
156 this_spi->irqn = SPI0_PLIC;
157 g_spi_axi_pos &= ~0x01u;
158 }
159 else if (&g_mss_spi1_lo == this_spi)
160 {
161 this_spi->hw_reg = MSS_SPI1_LO_BASE;
162 this_spi->irqn = SPI1_PLIC;
163 g_spi_axi_pos &= ~0x02u;
164 }
165 else if (&g_mss_spi0_hi == this_spi)
166 {
167 this_spi->hw_reg = MSS_SPI0_HI_BASE;
168 this_spi->irqn = SPI0_PLIC;
169 g_spi_axi_pos |= 0x01u;
170 }
171 else if (&g_mss_spi1_hi == this_spi)
172 {
173 this_spi->hw_reg = MSS_SPI1_HI_BASE;
174 this_spi->irqn = SPI1_PLIC;
175 g_spi_axi_pos |= 0x02u;
176 }
177 else
178 {
179 ASSERT(0);
180 }
181
182 /* De-assert reset bit. */
183 this_spi->hw_reg->CONTROL &= ~CTRL_REG_RESET_MASK;
184 }
185
186 /***************************************************************************//**
187 * MSS_SPI_configure_slave_mode()
188 * See "mss_spi.h" for details of how to use this function.
189 */
MSS_SPI_configure_slave_mode(mss_spi_instance_t * this_spi,mss_spi_protocol_mode_t protocol_mode,uint8_t frame_bit_length,mss_spi_oveflow_handler_t recieve_buffer_overflow_handler)190 void MSS_SPI_configure_slave_mode
191 (
192 mss_spi_instance_t * this_spi,
193 mss_spi_protocol_mode_t protocol_mode,
194 uint8_t frame_bit_length,
195 mss_spi_oveflow_handler_t recieve_buffer_overflow_handler
196 )
197 {
198 ASSERT((this_spi == &g_mss_spi0_lo) || (this_spi == &g_mss_spi0_hi)
199 || (this_spi == &g_mss_spi1_lo) || (this_spi == &g_mss_spi1_hi));
200 ASSERT(frame_bit_length <= MAX_FRAME_LENGTH);
201
202 /* Shut down interrupts from the MSS SPI while we do this */
203 PLIC_DisableIRQ(this_spi->irqn);
204
205 /* Registering MSS SPI overflow handler to the SPI instance */
206 this_spi->buffer_overflow_handler = recieve_buffer_overflow_handler;
207
208 /* Don't yet know what slave transfer mode will be used */
209 this_spi->slave_xfer_mode = MSS_SPI_SLAVE_XFER_NONE;
210
211 /* Set the mode. */
212 this_spi->hw_reg->CONTROL &= ~(uint32_t)CTRL_MASTER_MASK;
213
214 /* Set the protocol mode */
215 this_spi->hw_reg->CONTROL &= ~(uint32_t)CTRL_ENABLE_MASK;
216 this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~PROTOCOL_MODE_MASK)
217 | (uint32_t)protocol_mode | BIGFIFO_MASK;
218
219 /* Set number of data frames to 1 by default */
220 this_spi->hw_reg->FRAMESUP = 0u;
221 this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~TXRXDFCOUNT_MASK)
222 | ((uint32_t)1 << TXRXDFCOUNT_SHIFT);
223
224 this_spi->hw_reg->FRAMESIZE = frame_bit_length;
225 this_spi->hw_reg->CONTROL |= CTRL_ENABLE_MASK;
226
227 /* Re-enable interrupts */
228 PLIC_EnableIRQ(this_spi->irqn);
229 }
230
231 /***************************************************************************//**
232 * MSS_SPI_configure_master_mode()
233 * See "mss_spi.h" for details of how to use this function.
234 */
MSS_SPI_configure_master_mode(mss_spi_instance_t * this_spi,mss_spi_slave_t slave,mss_spi_protocol_mode_t protocol_mode,uint32_t clk_div,uint8_t frame_bit_length,mss_spi_oveflow_handler_t recieve_buffer_overflow_handler)235 void MSS_SPI_configure_master_mode
236 (
237 mss_spi_instance_t * this_spi,
238 mss_spi_slave_t slave,
239 mss_spi_protocol_mode_t protocol_mode,
240 uint32_t clk_div,
241 uint8_t frame_bit_length,
242 mss_spi_oveflow_handler_t recieve_buffer_overflow_handler
243 )
244 {
245 ASSERT((this_spi == &g_mss_spi0_lo) || (this_spi == &g_mss_spi0_hi)
246 || (this_spi == &g_mss_spi1_lo) || (this_spi == &g_mss_spi1_hi));
247 ASSERT(slave < MSS_SPI_MAX_NB_OF_SLAVES);
248 ASSERT(frame_bit_length <= MAX_FRAME_LENGTH);
249
250 /* Check that the requested clock divider is within range and even number */
251 ASSERT(clk_div >= 2u);
252 ASSERT(clk_div <= 512u);
253 ASSERT(0u == (clk_div & 0x00000001U));
254
255 /* Shut down interrupts from the MSS SPI while we do this */
256 PLIC_DisableIRQ( this_spi->irqn );
257
258 /* Registering MSS SPI overflow handler to the SPI instance */
259 this_spi->buffer_overflow_handler = recieve_buffer_overflow_handler;
260
261 /* Reset slave transfer mode to unknown to wipe slate clean */
262 this_spi->slave_xfer_mode = MSS_SPI_SLAVE_XFER_NONE;
263
264 /* Set the mode. */
265 this_spi->hw_reg->CONTROL &= ~(uint32_t)CTRL_ENABLE_MASK;
266 this_spi->hw_reg->CONTROL |= CTRL_MASTER_MASK;
267 this_spi->hw_reg->CONTROL |= CTRL_ENABLE_MASK;
268
269 /* Keep track of the required register configuration for this slave. These
270 * values will be used by the MSS_SPI_set_slave_select() function to
271 * configure the master to match the slave being selected. */
272 if (slave < MSS_SPI_MAX_NB_OF_SLAVES)
273 {
274 uint32_t clk_gen;
275
276 /* Setting the SPS bit ensures the slave select remains asserted even
277 * if we don't keep the TX FIFO filled in block mode. We only do it for
278 * Motorola modes and if you need the slave selected deselected between
279 * frames in modes 0 or 2 then remove SPS_MASK from below. */
280 if ((MSS_SPI_MODE0 == protocol_mode) ||
281 (MSS_SPI_MODE1 == protocol_mode) ||
282 (MSS_SPI_MODE2 == protocol_mode) ||
283 (MSS_SPI_MODE3 == protocol_mode))
284 {
285 this_spi->slaves_cfg[slave].ctrl_reg = MASTER_MODE_MASK | SPS_MASK |
286 BIGFIFO_MASK | CTRL_CLKMODE_MASK |
287 (uint32_t)protocol_mode |
288 ((uint32_t)1 << TXRXDFCOUNT_SHIFT);
289 }
290 else
291 {
292 this_spi->slaves_cfg[slave].ctrl_reg = MASTER_MODE_MASK |
293 BIGFIFO_MASK | CTRL_CLKMODE_MASK |
294 (uint32_t)protocol_mode |
295 ((uint32_t)1 << TXRXDFCOUNT_SHIFT);
296 }
297 this_spi->slaves_cfg[slave].txrxdf_size_reg = frame_bit_length;
298
299 clk_gen = (clk_div / 2u) - (uint32_t)1u;
300 this_spi->slaves_cfg[slave].clk_gen = (uint8_t)clk_gen;
301 }
302
303 /* Re enable interrupts */
304 PLIC_EnableIRQ( this_spi->irqn );
305 }
306
307 /***************************************************************************//**
308 * MSS_SPI_set_slave_select()
309 * See "mss_spi.h" for details of how to use this function.
310 */
MSS_SPI_set_slave_select(mss_spi_instance_t * this_spi,mss_spi_slave_t slave)311 void MSS_SPI_set_slave_select
312 (
313 mss_spi_instance_t * this_spi,
314 mss_spi_slave_t slave
315 )
316 {
317 uint32_t rx_overflow;
318 ASSERT((this_spi == &g_mss_spi0_lo) || (this_spi == &g_mss_spi0_hi)
319 || (this_spi == &g_mss_spi1_lo) || (this_spi == &g_mss_spi1_hi));
320
321 /* This function is only intended to be used with an SPI master. */
322 ASSERT((this_spi->hw_reg->CONTROL & CTRL_MASTER_MASK)
323 == CTRL_MASTER_MASK);
324
325 ASSERT(this_spi->slaves_cfg[slave].ctrl_reg != NOT_CONFIGURED);
326
327 /* Shut down interrupts from the MSS SPI while we do this */
328 PLIC_DisableIRQ( this_spi->irqn );
329
330 /* Recover from receive overflow. */
331 rx_overflow = this_spi->hw_reg->STATUS & RX_OVERFLOW_MASK;
332 if (rx_overflow > 0U)
333 {
334 recover_from_rx_overflow(this_spi);
335 }
336
337 /* Set the clock rate. */
338 this_spi->hw_reg->CONTROL &= ~(uint32_t)CTRL_ENABLE_MASK;
339 this_spi->hw_reg->CONTROL = this_spi->slaves_cfg[slave].ctrl_reg;
340 this_spi->hw_reg->CLK_GEN = (uint32_t)(this_spi->slaves_cfg[slave].clk_gen);
341 this_spi->hw_reg->FRAMESIZE =
342 (uint32_t)(this_spi->slaves_cfg[slave].txrxdf_size_reg);
343
344 this_spi->hw_reg->CONTROL |= CTRL_ENABLE_MASK;
345
346 /* Set slave select */
347 this_spi->hw_reg->SLAVE_SELECT |= ((uint32_t)1 << (uint32_t)slave);
348
349 /* Re enable interrupts */
350 PLIC_EnableIRQ(this_spi->irqn);
351 }
352
353 /***************************************************************************//**
354 * MSS_SPI_clear_slave_select()
355 * See "mss_spi.h" for details of how to use this function.
356 */
MSS_SPI_clear_slave_select(mss_spi_instance_t * this_spi,mss_spi_slave_t slave)357 void MSS_SPI_clear_slave_select
358 (
359 mss_spi_instance_t * this_spi,
360 mss_spi_slave_t slave
361 )
362 {
363 uint32_t rx_overflow;
364 ASSERT((this_spi == &g_mss_spi0_lo) || (this_spi == &g_mss_spi0_hi)
365 || (this_spi == &g_mss_spi1_lo) || (this_spi == &g_mss_spi1_hi));
366
367 /* This function is only intended to be used with an SPI master. */
368 ASSERT((this_spi->hw_reg->CONTROL & CTRL_MASTER_MASK)
369 == CTRL_MASTER_MASK);
370
371 /* Shut down interrupts from the MSS SPI while we do this */
372 PLIC_DisableIRQ( this_spi->irqn );
373
374 /* Recover from receive overflow. */
375 rx_overflow = this_spi->hw_reg->STATUS & RX_OVERFLOW_MASK;
376 if (rx_overflow > 0U)
377 {
378 recover_from_rx_overflow(this_spi);
379 }
380 this_spi->hw_reg->SLAVE_SELECT &= ~((uint32_t)1 << (uint32_t)slave);
381
382 /* Re enable interrupts */
383 PLIC_EnableIRQ( this_spi->irqn );
384 }
385
386 /***************************************************************************//**
387 * MSS_SPI_transfer_frame()
388 * See "mss_spi.h" for details of how to use this function.
389 */
MSS_SPI_transfer_frame(mss_spi_instance_t * this_spi,uint32_t tx_bits)390 uint32_t MSS_SPI_transfer_frame
391 (
392 mss_spi_instance_t * this_spi,
393 uint32_t tx_bits
394 )
395 {
396 uint32_t rx_ready;
397 uint32_t tx_done;
398 ASSERT((this_spi == &g_mss_spi0_lo) || (this_spi == &g_mss_spi0_hi)
399 || (this_spi == &g_mss_spi1_lo) || (this_spi == &g_mss_spi1_hi));
400
401 /* This function is only intended to be used with an SPI master. */
402 ASSERT((this_spi->hw_reg->CONTROL & CTRL_MASTER_MASK)
403 == CTRL_MASTER_MASK);
404
405 /* Ensure single frame transfer selected so interrupts work correctly */
406 this_spi->hw_reg->FRAMESUP = 0u;
407 this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~TXRXDFCOUNT_MASK)
408 | ((uint32_t)1u << TXRXDFCOUNT_SHIFT);
409
410 /* Flush the Tx and Rx FIFOs. */
411 this_spi->hw_reg->COMMAND |= ((uint32_t)TX_FIFO_RESET_MASK |
412 (uint32_t)RX_FIFO_RESET_MASK);
413
414 /* Send frame. */
415 this_spi->hw_reg->TX_DATA = tx_bits;
416
417 /* Wait for frame Tx to complete. */
418 tx_done = this_spi->hw_reg->STATUS & TX_DONE_MASK;
419 while (0u == tx_done)
420 {
421 tx_done = this_spi->hw_reg->STATUS & TX_DONE_MASK;
422 }
423
424 /* Read received frame. */
425 /* Wait for Rx complete. */
426 rx_ready = this_spi->hw_reg->STATUS & RX_DATA_READY_MASK;
427 while (0u == rx_ready)
428 {
429 rx_ready = this_spi->hw_reg->STATUS & RX_DATA_READY_MASK;
430 }
431
432 /* Return Rx data. */
433 return( this_spi->hw_reg->RX_DATA );
434 }
435
436 /***************************************************************************//**
437 * MSS_SPI_transfer_block()
438 * See "mss_spi.h" for details of how to use this function.
439 */
MSS_SPI_transfer_block(mss_spi_instance_t * this_spi,const uint8_t cmd_buffer[],uint32_t cmd_byte_size,uint8_t rd_buffer[],uint32_t rd_byte_size)440 void MSS_SPI_transfer_block
441 (
442 mss_spi_instance_t * this_spi,
443 const uint8_t cmd_buffer[],
444 uint32_t cmd_byte_size,
445 uint8_t rd_buffer[],
446 uint32_t rd_byte_size
447 )
448 {
449 uint32_t transfer_idx = 0u;
450 uint32_t tx_idx;
451 uint32_t rx_idx;
452 uint32_t frame_count;
453 volatile uint32_t rx_raw;
454 uint32_t transit = 0u;
455 uint32_t tx_fifo_full;
456 uint32_t rx_overflow;
457 uint32_t rx_fifo_empty;
458
459 uint32_t transfer_size; /* Total number of bytes transferred. */
460
461 ASSERT((this_spi == &g_mss_spi0_lo) || (this_spi == &g_mss_spi0_hi)
462 || (this_spi == &g_mss_spi1_lo) || (this_spi == &g_mss_spi1_hi));
463
464 /* This function is only intended to be used with an SPI master. */
465 ASSERT((this_spi->hw_reg->CONTROL & CTRL_MASTER_MASK)
466 == CTRL_MASTER_MASK);
467
468 /* Compute number of bytes to transfer. */
469 transfer_size = cmd_byte_size + rd_byte_size;
470
471 /* Adjust to 1 byte transfer to cater for DMA transfers. */
472 if (0u == transfer_size)
473 {
474 frame_count = 1u;
475 }
476 else
477 {
478 frame_count = transfer_size;
479 }
480
481 /* Flush the Tx and Rx FIFOs. */
482 this_spi->hw_reg->COMMAND |= ((uint32_t)TX_FIFO_RESET_MASK |
483 (uint32_t)RX_FIFO_RESET_MASK);
484
485 /* Recover from receive overflow. */
486 rx_overflow = this_spi->hw_reg->STATUS & RX_OVERFLOW_MASK;
487 if (rx_overflow > 0U)
488 {
489 recover_from_rx_overflow(this_spi);
490 }
491
492 /* Set frame size to 8 bits and the frame count to the transfer size. */
493 this_spi->hw_reg->CONTROL &= ~(uint32_t)CTRL_ENABLE_MASK;
494 this_spi->hw_reg->FRAMESUP = frame_count & BYTESUPPER_MASK;
495 this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~TXRXDFCOUNT_MASK) |
496 ((frame_count << TXRXDFCOUNT_SHIFT)
497 & TXRXDFCOUNT_MASK);
498
499 this_spi->hw_reg->FRAMESIZE = MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE;
500 this_spi->hw_reg->CONTROL |= CTRL_ENABLE_MASK;
501
502 /* Flush the receive FIFO. */
503 rx_fifo_empty = this_spi->hw_reg->STATUS & RX_FIFO_EMPTY_MASK;
504 while (0u == rx_fifo_empty)
505 {
506 rx_raw = this_spi->hw_reg->RX_DATA;
507 rx_fifo_empty = this_spi->hw_reg->STATUS & RX_FIFO_EMPTY_MASK;
508 }
509 tx_idx = 0u;
510 rx_idx = 0u;
511 if (tx_idx < cmd_byte_size)
512 {
513 this_spi->hw_reg->TX_DATA = cmd_buffer[tx_idx];
514 ++tx_idx;
515 ++transit;
516 }
517 else
518 {
519 if (tx_idx < transfer_size)
520 {
521 this_spi->hw_reg->TX_DATA = 0x00u;
522 ++tx_idx;
523 ++transit;
524 }
525 }
526
527 /* Perform the remainder of the transfer by sending a byte every time a byte
528 * has been received. This should ensure that no Rx overflow can happen in
529 * case of an interrupt occurs during this function. */
530 while (transfer_idx < transfer_size)
531 {
532 rx_fifo_empty = this_spi->hw_reg->STATUS & RX_FIFO_EMPTY_MASK;
533 if (0u == rx_fifo_empty)
534 {
535 /* Process received byte. */
536 rx_raw = this_spi->hw_reg->RX_DATA;
537 if (transfer_idx >= cmd_byte_size)
538 {
539 if (rx_idx < rd_byte_size)
540 {
541 rd_buffer[rx_idx] = (uint8_t)rx_raw;
542 }
543 ++rx_idx;
544 }
545 ++transfer_idx;
546 --transit;
547 }
548 tx_fifo_full = this_spi->hw_reg->STATUS & TX_FIFO_FULL_MASK;
549 if (0u == tx_fifo_full)
550 {
551 if (transit < RX_FIFO_SIZE)
552 {
553 /* Send another byte. */
554 if (tx_idx < cmd_byte_size)
555 {
556 this_spi->hw_reg->TX_DATA = cmd_buffer[tx_idx];
557 ++tx_idx;
558 ++transit;
559 }
560 else
561 {
562 if (tx_idx < transfer_size)
563 {
564 this_spi->hw_reg->TX_DATA = 0x00u;
565 ++tx_idx;
566 ++transit;
567 }
568 }
569 }
570 }
571 }
572 }
573
574 /***************************************************************************//**
575 * MSS_SPI_set_frame_rx_handler()
576 * See "mss_spi.h" for details of how to use this function.
577 */
MSS_SPI_set_frame_rx_handler(mss_spi_instance_t * this_spi,mss_spi_frame_rx_handler_t rx_handler)578 void MSS_SPI_set_frame_rx_handler
579 (
580 mss_spi_instance_t * this_spi,
581 mss_spi_frame_rx_handler_t rx_handler
582 )
583 {
584 uint32_t tx_fifo_empty;
585 ASSERT((this_spi == &g_mss_spi0_lo) || (this_spi == &g_mss_spi0_hi)
586 || (this_spi == &g_mss_spi1_lo) || (this_spi == &g_mss_spi1_hi));
587
588 /* This function is only intended to be used with an SPI slave. */
589 ASSERT((this_spi->hw_reg->CONTROL & CTRL_MASTER_MASK)
590 != CTRL_MASTER_MASK);
591
592 /* Shut down interrupts from the MSS SPI while we do this */
593 PLIC_DisableIRQ( this_spi->irqn );
594
595 /* Disable block Rx handlers as they are mutually exclusive. */
596 this_spi->block_rx_handler = 0u;
597 this_spi->cmd_handler = 0u;
598
599 /* Keep a copy of the pointer to the rx handler function. */
600 this_spi->frame_rx_handler = rx_handler;
601
602 /* Make sure correct mode is selected */
603 this_spi->slave_xfer_mode = MSS_SPI_SLAVE_XFER_FRAME;
604
605 /* Automatically fill the TX FIFO with zeroes if no slave tx frame set.*/
606 tx_fifo_empty = this_spi->hw_reg->STATUS & TX_FIFO_EMPTY_MASK;
607 if (tx_fifo_empty > 0U)
608 {
609 this_spi->hw_reg->COMMAND |= AUTOFILL_MASK;
610 }
611
612 /* Ensure single frame transfer selected so interrupts work correctly */
613 this_spi->hw_reg->FRAMESUP = 0u;
614 this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~TXRXDFCOUNT_MASK)
615 | ((uint32_t)1u << TXRXDFCOUNT_SHIFT);
616
617 /* Disable block specific interrupts */
618 this_spi->hw_reg->CONTROL2 &= ~(uint32_t)C2_ENABLE_CMD_IRQ_MASK;
619 this_spi->hw_reg->CONTROL2 &= ~(uint32_t)C2_ENABLE_SSEND_IRQ_MASK;
620
621 /* Clear down interrupts to avoid stale interrupts triggering when we
622 * enable them below */
623 this_spi->hw_reg->INT_CLEAR = ((uint32_t)TXURUN_IRQ_MASK |
624 (uint32_t)RXOVFLOW_IRQ_MASK |
625 (uint32_t)RXDONE_IRQ_MASK);
626
627 /* Enable TX under run and RX overflow interrupts to improve error
628 * recovery and the Rx interrupt.*/
629 this_spi->hw_reg->CONTROL |= ((uint32_t)CTRL_URUN_IRQ_EN_MASK |
630 (uint32_t)CTRL_OVFLOW_IRQ_EN_MASK |
631 (uint32_t)CTRL_RX_IRQ_EN_MASK);
632
633 PLIC_EnableIRQ(this_spi->irqn);
634 }
635
636 /***************************************************************************//**
637 * MSS_SPI_set_slave_tx_frame()
638 * See "mss_spi.h" for details of how to use this function.
639 */
MSS_SPI_set_slave_tx_frame(mss_spi_instance_t * this_spi,uint32_t frame_value)640 void MSS_SPI_set_slave_tx_frame
641 (
642 mss_spi_instance_t * this_spi,
643 uint32_t frame_value
644 )
645 {
646 ASSERT((this_spi == &g_mss_spi0_lo) || (this_spi == &g_mss_spi0_hi)
647 || (this_spi == &g_mss_spi1_lo) || (this_spi == &g_mss_spi1_hi));
648
649 /* This function is only intended to be used with an SPI slave. */
650 ASSERT((this_spi->hw_reg->CONTROL & CTRL_MASTER_MASK)
651 != CTRL_MASTER_MASK);
652
653 /* Shut down interrupts from the MSS SPI while we do this */
654 PLIC_DisableIRQ(this_spi->irqn);
655
656 /* Make sure correct mode is selected */
657 this_spi->slave_xfer_mode = MSS_SPI_SLAVE_XFER_FRAME;
658
659 /* Disable block Rx handlers as they are mutually exclusive. */
660 this_spi->block_rx_handler = 0u;
661 this_spi->cmd_handler = 0u;
662
663 /* Disable slave block tx buffer as it is mutually exclusive with frame
664 * level handling. */
665 this_spi->slave_tx_buffer = 0u;
666 this_spi->slave_tx_size = 0u;
667 this_spi->slave_tx_idx = 0u;
668
669 /* Keep a copy of the slave tx frame value. */
670 this_spi->slave_tx_frame = frame_value;
671
672 /* Disable automatic fill of the TX FIFO with zeroes.*/
673 this_spi->hw_reg->COMMAND &= ~(uint32_t)AUTOFILL_MASK;
674 this_spi->hw_reg->COMMAND |= TX_FIFO_RESET_MASK;
675
676 /* Ensure single frame transfer selected so interrupts work correctly
677 *
678 * IMPORTANT: Note this must be done before writing to the TX_DATA register
679 * as it seems that doing these in the opposite order causes the receive
680 * and transmit interrupts to be disabled.*/
681 this_spi->hw_reg->FRAMESUP = 0u;
682 this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~TXRXDFCOUNT_MASK)
683 | ((uint32_t)1u << TXRXDFCOUNT_SHIFT);
684
685 /* Load frame into Tx data register. */
686 this_spi->hw_reg->TX_DATA = this_spi->slave_tx_frame;
687
688 /* Disable block specific interrupts */
689 this_spi->hw_reg->CONTROL2 &= ~(uint32_t)C2_ENABLE_CMD_IRQ_MASK;
690 this_spi->hw_reg->CONTROL2 &= ~(uint32_t)C2_ENABLE_SSEND_IRQ_MASK;
691
692 /* Clear down interrupts to avoid stale interrupts triggering when we
693 * enable them below */
694 this_spi->hw_reg->INT_CLEAR = ((uint32_t)TXURUN_IRQ_MASK |
695 (uint32_t)RXOVFLOW_IRQ_MASK |
696 (uint32_t)RXDONE_IRQ_MASK);
697
698 /* Enable Tx Done interrupt in order to reload the slave Tx frame after each
699 * time it has been sent.
700 *
701 * Enable TX under run and RX overflow interrupts to improve error
702 * recovery.
703 */
704 this_spi->hw_reg->CONTROL |= ((uint32_t)CTRL_URUN_IRQ_EN_MASK |
705 (uint32_t)CTRL_OVFLOW_IRQ_EN_MASK |
706 (uint32_t)CTRL_RX_IRQ_EN_MASK);
707
708 PLIC_EnableIRQ(this_spi->irqn);
709 }
710
711 /***************************************************************************//**
712 * MSS_SPI_set_slave_block_buffers()
713 * See "mss_spi.h" for details of how to use this function.
714 */
MSS_SPI_set_slave_block_buffers(mss_spi_instance_t * this_spi,const uint8_t * tx_buffer,uint32_t tx_buff_size,uint8_t * rx_buffer,uint32_t rx_buff_size,mss_spi_block_rx_handler_t block_rx_handler)715 void MSS_SPI_set_slave_block_buffers
716 (
717 mss_spi_instance_t * this_spi,
718 const uint8_t * tx_buffer,
719 uint32_t tx_buff_size,
720 uint8_t * rx_buffer,
721 uint32_t rx_buff_size,
722 mss_spi_block_rx_handler_t block_rx_handler
723 )
724 {
725 uint32_t frame_count;
726 uint32_t done = 0u;
727 ASSERT((this_spi == &g_mss_spi0_lo) || (this_spi == &g_mss_spi0_hi)
728 || (this_spi == &g_mss_spi1_lo) || (this_spi == &g_mss_spi1_hi));
729
730 /* This function is only intended to be used with an SPI slave. */
731 ASSERT((this_spi->hw_reg->CONTROL & CTRL_MASTER_MASK) != CTRL_MASTER_MASK);
732
733 /* Shut down interrupts from the MSS SPI while we do this */
734 PLIC_DisableIRQ(this_spi->irqn);
735
736 /* Make sure correct mode is selected */
737 this_spi->slave_xfer_mode = MSS_SPI_SLAVE_XFER_BLOCK;
738
739 /* Set cmd_done correctly to ensure 0 padding works. */
740 if ((mss_spi_block_rx_handler_t)0 == this_spi->cmd_handler)
741 {
742 this_spi->cmd_done = 1u;
743 }
744 else
745 {
746 this_spi->cmd_done = 0u;
747 }
748
749 /* Disable Rx frame handler as it is mutually exclusive with block rx
750 handler.*/
751 this_spi->frame_rx_handler = 0u;
752
753 /* Keep a copy of the pointer to the block rx handler function. */
754 this_spi->block_rx_handler = block_rx_handler;
755
756 this_spi->slave_rx_buffer = rx_buffer;
757 this_spi->slave_rx_size = rx_buff_size;
758 this_spi->slave_rx_idx = 0u;
759
760 /* Initialize the transmit state data. */
761 this_spi->slave_tx_buffer = tx_buffer;
762 this_spi->slave_tx_size = tx_buff_size;
763 this_spi->slave_tx_idx = 0u;
764
765 /* Flush the Tx and Rx FIFOs.
766 * Please note this does not have any effect on A2F200. */
767 this_spi->hw_reg->COMMAND |= ((uint32_t)TX_FIFO_RESET_MASK
768 | (uint32_t)RX_FIFO_RESET_MASK);
769
770 /* Recover from receive overflow if needs be */
771 if (0u != (this_spi->hw_reg->STATUS & RX_OVERFLOW_MASK))
772 {
773 recover_from_rx_overflow(this_spi);
774 }
775
776 /* Flush Rx FIFO in case we are executing on A2F200. */
777 while (0u == (this_spi->hw_reg->STATUS & RX_FIFO_EMPTY_MASK))
778 {
779 volatile uint32_t dummy;
780 dummy = this_spi->hw_reg->RX_DATA;
781 }
782
783 /* Use the frame counter to control how often receive interrupts are
784 * generated */
785 frame_count = RX_IRQ_THRESHOLD;
786
787 this_spi->hw_reg->CONTROL &= ~(uint32_t)CTRL_ENABLE_MASK;
788 this_spi->hw_reg->FRAMESUP = frame_count & BYTESUPPER_MASK;
789 this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~TXRXDFCOUNT_MASK)
790 | (frame_count << TXRXDFCOUNT_SHIFT);
791 this_spi->hw_reg->FRAMESIZE = MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE;
792 this_spi->hw_reg->CONTROL |= CTRL_ENABLE_MASK;
793
794 /* Load the transmit FIFO. */
795 while ((0u == (this_spi->hw_reg->STATUS & TX_FIFO_FULL_MASK))
796 && (0u == done))
797 {
798 if (this_spi->slave_tx_idx < this_spi->slave_tx_size)
799 {
800 this_spi->hw_reg->TX_DATA =
801 (uint32_t)(this_spi->slave_tx_buffer[this_spi->slave_tx_idx]);
802 }
803 else if (0u != this_spi->cmd_done)
804 {
805 /* Fill with 0s if no need to insert command response */
806 this_spi->hw_reg->TX_DATA = 0x00u;
807 }
808 else
809 {
810 /* Exit loop early as command response needs to be inserted next */
811 done = 1u;
812 }
813 ++this_spi->slave_tx_idx;
814 }
815
816 if (tx_buff_size > 0u)
817 {
818 /* Clear and enable TX interrupt. Also disable auto fill */
819 this_spi->hw_reg->COMMAND &= ~(uint32_t)AUTOFILL_MASK;
820 this_spi->hw_reg->INT_CLEAR = TXDONE_IRQ_MASK;
821 this_spi->hw_reg->CONTROL |= CTRL_TX_IRQ_EN_MASK;
822 }
823 else
824 {
825 this_spi->hw_reg->COMMAND |= AUTOFILL_MASK;
826 }
827 /* Ensure command interrupt disabled if no handler */
828 if ((mss_spi_block_rx_handler_t)0 == this_spi->cmd_handler)
829 {
830 this_spi->hw_reg->CONTROL2 &= ~(uint32_t)C2_ENABLE_CMD_IRQ_MASK;
831 }
832
833 /* Enable slave select release interrupt. The SSEND interrupt is used to
834 * complete reading of the receive FIFO and prepare the transmit FIFO for
835 * the next transaction.
836 * Make sure to clear any pending send interrupts otherwise we will trigger
837 * an immediate interrupt. */
838 this_spi->hw_reg->INT_CLEAR = SSEND_IRQ_MASK;
839 this_spi->hw_reg->CONTROL2 |= C2_ENABLE_SSEND_IRQ_MASK;
840
841 /* Clear down interrupts to avoid stale interrupts triggering when we
842 * enable them below */
843 this_spi->hw_reg->INT_CLEAR = ((uint32_t)TXURUN_IRQ_MASK |
844 (uint32_t)RXOVFLOW_IRQ_MASK |
845 (uint32_t)RXDONE_IRQ_MASK);
846
847 /* Enable TX under run and RX overflow interrupts to improve error
848 * recovery. */
849 this_spi->hw_reg->CONTROL |= ((uint32_t)CTRL_URUN_IRQ_EN_MASK |
850 (uint32_t)CTRL_OVFLOW_IRQ_EN_MASK |
851 (uint32_t)CTRL_RX_IRQ_EN_MASK);
852
853 PLIC_EnableIRQ(this_spi->irqn);
854 }
855
856 /***************************************************************************//**
857 * MSS_SPI_set_cmd_handler()
858 * See "mss_spi.h" for details of how to use this function.
859 */
MSS_SPI_set_cmd_handler(mss_spi_instance_t * this_spi,mss_spi_block_rx_handler_t cmd_handler,uint32_t cmd_size)860 void MSS_SPI_set_cmd_handler
861 (
862 mss_spi_instance_t * this_spi,
863 mss_spi_block_rx_handler_t cmd_handler,
864 uint32_t cmd_size
865 )
866 {
867 /* Shut down interrupts from the MSS SPI while we do this */
868 PLIC_DisableIRQ(this_spi->irqn);
869
870 /* Make sure response state is cleared down */
871 this_spi->resp_tx_buffer = 0u;
872 this_spi->resp_buff_size = 0u;
873 this_spi->resp_buff_tx_idx = 0u;
874
875 if ((mss_spi_block_rx_handler_t)0 == cmd_handler)
876 {
877 /* Set this flag so zero padding is enabled */
878 this_spi->cmd_done = 1u;
879
880 /* Ensure command interrupt disabled if no handler
881 * and handler pointer is wiped clean. */
882 this_spi->cmd_handler = 0u;
883 this_spi->hw_reg->CMDSIZE = 0u;
884 this_spi->hw_reg->CONTROL2 &= ~(uint32_t)C2_ENABLE_CMD_IRQ_MASK;
885 }
886 else
887 {
888 /* Clear this flag so zero padding is disabled until command response
889 * has been taken care of. */
890 this_spi->cmd_done = 0u;
891 this_spi->cmd_handler = cmd_handler;
892 this_spi->hw_reg->CMDSIZE = cmd_size;
893
894 /* Flush the Tx FIFO. Please note this does not have any effect on
895 * A2F200. */
896 this_spi->hw_reg->COMMAND |= ((uint32_t)TX_FIFO_RESET_MASK |
897 (uint32_t)RX_FIFO_RESET_MASK);
898
899 /* Reload TX FIFO as MSS_SPI_set_slave_block_buffers() may have zero
900 * filled the FIFO if command handler was not in place when it was
901 * called and so the first frame sent could be wrong. */
902 this_spi->slave_tx_idx = 0u;
903 fill_slave_tx_fifo(this_spi);
904
905 /* Make sure to clear any pending command interrupts otherwise we will
906 * trigger an immediate interrupt. */
907 this_spi->hw_reg->INT_CLEAR = CMD_IRQ_MASK;
908 this_spi->hw_reg->CONTROL2 |= C2_ENABLE_CMD_IRQ_MASK;
909 }
910
911 PLIC_EnableIRQ(this_spi->irqn); /* Safe to allow interrupts again */
912 }
913
914 /***************************************************************************//**
915 * MSS_SPI_set_cmd_response()
916 * See "mss_spi.h" for details of how to use this function.
917 */
MSS_SPI_set_cmd_response(mss_spi_instance_t * this_spi,const uint8_t * resp_tx_buffer,uint32_t resp_buff_size)918 void MSS_SPI_set_cmd_response
919 (
920 mss_spi_instance_t * this_spi,
921 const uint8_t * resp_tx_buffer,
922 uint32_t resp_buff_size
923 )
924 {
925 this_spi->resp_tx_buffer = resp_tx_buffer;
926 this_spi->resp_buff_size = resp_buff_size;
927 this_spi->resp_buff_tx_idx = 0u;
928
929 /* Note that we have provided response and start getting it into the FIFO */
930 this_spi->cmd_done = 1u;
931 fill_slave_tx_fifo(this_spi);
932 }
933
934 /***************************************************************************//**
935 * MSS_SPI_enable()
936 * See "mss_spi.h" for details of how to use this function.
937 */
MSS_SPI_enable(mss_spi_instance_t * this_spi)938 void MSS_SPI_enable
939 (
940 mss_spi_instance_t * this_spi
941 )
942 {
943 /* Shut down interrupts from the MSS SPI while we do this */
944 PLIC_DisableIRQ(this_spi->irqn);
945
946 this_spi->hw_reg->CONTROL |= CTRL_ENABLE_MASK;
947
948 /* Re enable interrupts */
949 PLIC_EnableIRQ(this_spi->irqn);
950 }
951
952 /***************************************************************************//**
953 * MSS_SPI_disable()
954 * See "mss_spi.h" for details of how to use this function.
955 */
MSS_SPI_disable(mss_spi_instance_t * this_spi)956 void MSS_SPI_disable
957 (
958 mss_spi_instance_t * this_spi
959 )
960 {
961 /* Shut down interrupts from the MSS SPI while we do this */
962 PLIC_DisableIRQ(this_spi->irqn);
963
964 this_spi->hw_reg->CONTROL &= ~(uint32_t)CTRL_ENABLE_MASK;
965
966 /* Re-enable interrupts */
967 PLIC_EnableIRQ(this_spi->irqn);
968 }
969
970 /***************************************************************************//**
971 * MSS_SPI_tx_done()
972 * See "mss_spi.h" for details of how to use this function.
973 */
MSS_SPI_tx_done(mss_spi_instance_t * this_spi)974 uint32_t MSS_SPI_tx_done
975 (
976 mss_spi_instance_t * this_spi
977 )
978 {
979 uint32_t tx_done;
980
981 tx_done = this_spi->hw_reg->STATUS & TX_DONE_MASK;
982
983 return tx_done;
984 }
985
986 /***************************************************************************//**
987 * Fill the transmit FIFO(used for slave block transfers).
988 */
fill_slave_tx_fifo(mss_spi_instance_t * this_spi)989 static void fill_slave_tx_fifo
990 (
991 mss_spi_instance_t * this_spi
992 )
993 {
994 uint32_t guard = 0u;
995
996 while ((0u == (this_spi->hw_reg->STATUS & TX_FIFO_FULL_MASK)) &&
997 (this_spi->slave_tx_idx < this_spi->slave_tx_size))
998 {
999 /* Sending from primary slave transmit buffer */
1000 this_spi->hw_reg->TX_DATA =
1001 (uint32_t)(this_spi->slave_tx_buffer[this_spi->slave_tx_idx]);
1002 ++this_spi->slave_tx_idx;
1003 }
1004
1005 if (this_spi->slave_tx_idx >= this_spi->slave_tx_size)
1006 {
1007 while ((0u == (this_spi->hw_reg->STATUS & TX_FIFO_FULL_MASK)) &&
1008 (this_spi->resp_buff_tx_idx < this_spi->resp_buff_size))
1009 {
1010 /* Sending from command response buffer */
1011 this_spi->hw_reg->TX_DATA =
1012 (uint32_t)(this_spi->resp_tx_buffer[this_spi->resp_buff_tx_idx]);
1013 ++this_spi->resp_buff_tx_idx;
1014 }
1015 }
1016
1017 if ((0u != this_spi->cmd_done) &&
1018 (this_spi->slave_tx_idx >= this_spi->slave_tx_size) &&
1019 (this_spi->resp_buff_tx_idx >= this_spi->resp_buff_size))
1020 {
1021 while ((0u == (this_spi->hw_reg->STATUS & TX_FIFO_FULL_MASK)) &&
1022 (guard < BIG_FIFO_SIZE))
1023 {
1024 /* Nothing left so pad with 0s for consistency */
1025 this_spi->hw_reg->TX_DATA = 0x00u;
1026
1027 /* We use the guard count to cover the unlikely event that we are
1028 * never seeing the TX FIFO full because the data is being pulled
1029 * out as fast as we can stuff it in. In this event we never spend
1030 * more than a full FIFOs worth of time spinning here. */
1031 guard++;
1032 }
1033 }
1034 }
1035
1036 /***************************************************************************//**
1037 *
1038 */
read_slave_rx_fifo(mss_spi_instance_t * this_spi)1039 static void read_slave_rx_fifo
1040 (
1041 mss_spi_instance_t * this_spi
1042 )
1043 {
1044 volatile uint32_t rx_frame;
1045
1046 if (MSS_SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode)
1047 {
1048 while (0u == (this_spi->hw_reg->STATUS & RX_FIFO_EMPTY_MASK))
1049 {
1050 /* Single frame handling mode. */
1051 rx_frame = this_spi->hw_reg->RX_DATA;
1052 if ((mss_spi_frame_rx_handler_t)0 != this_spi->frame_rx_handler)
1053 {
1054 this_spi->frame_rx_handler( rx_frame );
1055 }
1056 }
1057 }
1058 else if (MSS_SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode)
1059 {
1060 /* Block handling mode.
1061 * Something needs to be read from FIFO */
1062 while (0u == (this_spi->hw_reg->STATUS & RX_FIFO_EMPTY_MASK))
1063 {
1064 rx_frame = this_spi->hw_reg->RX_DATA;
1065 if (this_spi->slave_rx_idx < this_spi->slave_rx_size)
1066 {
1067 this_spi->slave_rx_buffer[this_spi->slave_rx_idx] =
1068 (uint8_t)rx_frame;
1069 }
1070 ++this_spi->slave_rx_idx;
1071 }
1072 }
1073 else
1074 {
1075 /* Should not happen... Just purge FIFO */
1076 while (0u == (this_spi->hw_reg->STATUS & RX_FIFO_EMPTY_MASK))
1077 {
1078 rx_frame = this_spi->hw_reg->RX_DATA;
1079 }
1080 }
1081 }
1082
1083 /***************************************************************************//**
1084 * SPI interrupt service routine.
1085 */
mss_spi_isr(mss_spi_instance_t * this_spi)1086 static void mss_spi_isr
1087 (
1088 mss_spi_instance_t * this_spi
1089 )
1090 {
1091 volatile uint32_t rx_frame;
1092 volatile uint32_t *this_mis = &this_spi->hw_reg->MIS;
1093
1094 ASSERT((this_spi == &g_mss_spi0_lo) || (this_spi == &g_mss_spi0_hi)
1095 || (this_spi == &g_mss_spi1_lo) || (this_spi == &g_mss_spi1_hi));
1096
1097 if (0u != (*this_mis & RXDONE_IRQ_MASK))
1098 {
1099 if (MSS_SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode)
1100 {
1101 /* Single frame handling mode. */
1102 while (0u == (this_spi->hw_reg->STATUS & RX_FIFO_EMPTY_MASK))
1103 {
1104 rx_frame = this_spi->hw_reg->RX_DATA;
1105 if ((mss_spi_frame_rx_handler_t)0 != this_spi->frame_rx_handler)
1106 {
1107 this_spi->frame_rx_handler(rx_frame);
1108 }
1109 }
1110 }
1111 else if (MSS_SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode)
1112 {
1113 /* Block handling mode.
1114 * Something needs to be read from FIFO */
1115 while (0u == (this_spi->hw_reg->STATUS & RX_FIFO_EMPTY_MASK))
1116 {
1117 /* Read from FIFO irrespective */
1118 rx_frame = this_spi->hw_reg->RX_DATA;
1119 /* Write to array if required */
1120 if (this_spi->slave_rx_idx < this_spi->slave_rx_size)
1121 {
1122 this_spi->slave_rx_buffer[this_spi->slave_rx_idx] =
1123 (uint8_t)rx_frame;
1124 }
1125 ++this_spi->slave_rx_idx;
1126 }
1127 }
1128 else
1129 {
1130 /* No slave handling in place so just purge FIFO */
1131 while (0u == (this_spi->hw_reg->STATUS & RX_FIFO_EMPTY_MASK))
1132 {
1133 rx_frame = this_spi->hw_reg->RX_DATA;
1134 }
1135 }
1136 this_spi->hw_reg->INT_CLEAR = RXDONE_IRQ_MASK;
1137 }
1138
1139 /* Handle transmit. */
1140 if (0u != (*this_mis & TXDONE_IRQ_MASK))
1141 {
1142 if (MSS_SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode)
1143 {
1144 /* Reload slave tx frame into Tx data register. */
1145 this_spi->hw_reg->TX_DATA = this_spi->slave_tx_frame;
1146 }
1147 else /* Must be block mode so load FIFO to the max */
1148 {
1149 fill_slave_tx_fifo (this_spi);
1150 }
1151
1152 this_spi->hw_reg->INT_CLEAR = TXDONE_IRQ_MASK;
1153 }
1154
1155 /* Handle command interrupt. */
1156 if (0u != (*this_mis & CMD_IRQ_MASK))
1157 {
1158 read_slave_rx_fifo (this_spi);
1159
1160 /* Call the command handler if one exists. */
1161 if ((mss_spi_block_rx_handler_t)0 != this_spi->cmd_handler)
1162 {
1163 (*this_spi->cmd_handler)(this_spi->slave_rx_buffer,
1164 this_spi->slave_rx_idx);
1165
1166 fill_slave_tx_fifo(this_spi);
1167 }
1168
1169 /* Set cmd_done to indicate it is now safe to 0 fill TX FIFO */
1170 this_spi->cmd_done = 1u;
1171
1172 /* Disable command interrupt until slave select becomes de-asserted to
1173 * avoid retriggering. */
1174 this_spi->hw_reg->CONTROL2 &= ~(uint32_t)C2_ENABLE_CMD_IRQ_MASK;
1175 this_spi->hw_reg->INT_CLEAR = CMD_IRQ_MASK;
1176 }
1177
1178 if (0u != (*this_mis & RXOVFLOW_IRQ_MASK))
1179 {
1180 /* Receive overflow, not a lot we can do for this. Reset the receive
1181 * FIFO, clear the interrupt and hope it doesn't happen again... */
1182 this_spi->hw_reg->COMMAND |= RX_FIFO_RESET_MASK;
1183 recover_from_rx_overflow(this_spi);
1184
1185 this_spi->hw_reg->INT_CLEAR = RXOVFLOW_IRQ_MASK;
1186 }
1187
1188 /* Transmit under-run, try and recover by reapplying the current
1189 * slave TX FIFO data setup (if there is one).
1190 * In block mode this will probably not be very successful as we will
1191 * be out of sync with the master but the reset on SSEND will hopefully
1192 * take care of that for the next transfer. */
1193 if (0u != (*this_mis & TXURUN_IRQ_MASK))
1194 {
1195 this_spi->hw_reg->COMMAND |= TX_FIFO_RESET_MASK;
1196 if ( MSS_SPI_SLAVE_XFER_FRAME == this_spi->slave_xfer_mode )
1197 {
1198 this_spi->hw_reg->FRAMESUP = 0u;
1199 this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL
1200 & ~TXRXDFCOUNT_MASK)
1201 | ((uint32_t)1u << TXRXDFCOUNT_SHIFT);
1202
1203 /* Reload slave tx frame into Tx data register. */
1204 this_spi->hw_reg->TX_DATA = this_spi->slave_tx_frame;
1205 }
1206 else if (MSS_SPI_SLAVE_XFER_BLOCK == this_spi->slave_xfer_mode)
1207 {
1208 /* Block mode so reload FIFO to the max */
1209 this_spi->slave_tx_idx = 0u;
1210 fill_slave_tx_fifo(this_spi);
1211 }
1212 else
1213 {
1214 /* Not frame or block mode? Can't do anything here... */
1215 }
1216 this_spi->hw_reg->INT_CLEAR = TXURUN_IRQ_MASK;
1217 }
1218
1219 /* Handle slave select becoming de-asserted. Only enables if
1220 * we are operating in block mode, in frame mode we do everything
1221 * in the receive and transmit interrupt handlers. */
1222 if (0u != (*this_mis & SSEND_IRQ_MASK))
1223 {
1224 uint32_t rx_size;
1225
1226 read_slave_rx_fifo(this_spi);
1227 rx_size = this_spi->slave_rx_idx;
1228
1229 /* Re-enable command interrupt if required and clear all the response
1230 * buffer state in readiness for next response. This must be done
1231 * before reloading the TX FIFO. */
1232 if (0 != this_spi->cmd_handler)
1233 {
1234 this_spi->cmd_done = 0u;
1235 this_spi->resp_tx_buffer = 0u;
1236 this_spi->resp_buff_size = 0u;
1237 this_spi->resp_buff_tx_idx = 0u;
1238 this_spi->hw_reg->INT_CLEAR = CMD_IRQ_MASK;
1239 this_spi->hw_reg->CONTROL2 |= C2_ENABLE_CMD_IRQ_MASK;
1240 }
1241
1242 /* Reset the transmit index to 0 to restart transmit at the start of the
1243 * transmit buffer in the next transaction. This also requires flushing
1244 * the Tx FIFO and refilling it with the start of Tx data buffer. */
1245 this_spi->slave_tx_idx = 0u;
1246 this_spi->hw_reg->COMMAND |= ((uint32_t)TX_FIFO_RESET_MASK |
1247 (uint32_t)RX_FIFO_RESET_MASK);
1248
1249 fill_slave_tx_fifo(this_spi);
1250
1251 /* Prepare to receive next packet. */
1252 this_spi->slave_rx_idx = 0u;
1253
1254 /* Call the receive handler if one exists. */
1255 if ((mss_spi_block_rx_handler_t)0 != this_spi->block_rx_handler)
1256 {
1257 (*this_spi->block_rx_handler)(this_spi->slave_rx_buffer, rx_size);
1258 }
1259 this_spi->hw_reg->INT_CLEAR = SSEND_IRQ_MASK;
1260 }
1261 }
1262 /************************************************************************//***
1263 This is the local function to recover from rx overflow. This function performs
1264 set of operations which includes storing the current state of MSS SPI
1265 registers, reset the SPI core, restore the registers.
1266 Resetting the SPI core is performed by call back function which user must
1267 implement. Driver sends information about the SPI instance in use and the
1268 handler function resets particular SPI core.
1269
1270 Note: while configuring the SPI in master mode, user must provide the overflow
1271 handler function as one of the arguments.
1272
1273 @param this_spi
1274 The this_spi parameter is a pointer to an mss_spi_instance_t structure
1275 identifying the MSS SPI hardware block to be configured. There are two such
1276 data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and
1277 MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0
1278 or g_mss_spi1 global data structure defined within the SPI driver.
1279 */
recover_from_rx_overflow(mss_spi_instance_t * this_spi)1280 static void recover_from_rx_overflow
1281 (
1282 mss_spi_instance_t * this_spi
1283 )
1284 {
1285 uint32_t control_reg;
1286 uint32_t clk_gen;
1287 uint32_t frame_size;
1288 uint32_t control2;
1289 uint32_t packet_size;
1290 uint32_t cmd_size;
1291 uint32_t slave_select;
1292
1293 /* Read current SPI hardware block configuration. */
1294 control_reg = this_spi->hw_reg->CONTROL;
1295 clk_gen = this_spi->hw_reg->CLK_GEN;
1296 frame_size = this_spi->hw_reg->FRAMESIZE;
1297 control2 = this_spi->hw_reg->CONTROL2;
1298 packet_size = this_spi->hw_reg->PKTSIZE;
1299 cmd_size = this_spi->hw_reg->CMDSIZE;
1300 slave_select = this_spi->hw_reg->SLAVE_SELECT;
1301
1302 /* Reset the SPI hardware block. */
1303 if (this_spi == &g_mss_spi0_lo)
1304 {
1305 this_spi->hw_reg = MSS_SPI0_LO_BASE;
1306 this_spi->irqn = SPI0_PLIC;
1307
1308 /* reset SPI0 */
1309 this_spi->buffer_overflow_handler(0U);
1310 this_spi->hw_reg->CONTROL &= ~CTRL_REG_RESET_MASK;
1311 }
1312 else if (this_spi == &g_mss_spi1_lo)
1313 {
1314 this_spi->hw_reg = MSS_SPI1_LO_BASE;
1315 this_spi->irqn = SPI1_PLIC;
1316
1317 /* reset SPI1 */
1318 this_spi->buffer_overflow_handler(1u);
1319 this_spi->hw_reg->CONTROL &= ~CTRL_REG_RESET_MASK;
1320 }
1321 else if (this_spi == &g_mss_spi0_hi)
1322 {
1323 this_spi->hw_reg = MSS_SPI0_HI_BASE;
1324 this_spi->irqn = SPI0_PLIC;
1325
1326 /* reset SPI0 */
1327 this_spi->buffer_overflow_handler(0u);
1328 this_spi->hw_reg->CONTROL &= ~CTRL_REG_RESET_MASK;
1329 }
1330 else if (this_spi == &g_mss_spi1_hi)
1331 {
1332 this_spi->hw_reg = MSS_SPI1_HI_BASE;
1333 this_spi->irqn = SPI1_PLIC;
1334
1335 /* reset SPI1 */
1336 this_spi->buffer_overflow_handler(1u);
1337 this_spi->hw_reg->CONTROL &= ~CTRL_REG_RESET_MASK;
1338 }
1339 else
1340 {
1341 ASSERT(0);
1342 }
1343
1344 /* Restore SPI hardware block configuration. */
1345 control_reg &= ~(uint32_t)CTRL_ENABLE_MASK;
1346 this_spi->hw_reg->CONTROL = control_reg;
1347 this_spi->hw_reg->CLK_GEN = clk_gen;
1348 this_spi->hw_reg->FRAMESIZE = frame_size;
1349 this_spi->hw_reg->CONTROL |= CTRL_ENABLE_MASK;
1350 this_spi->hw_reg->CONTROL2 = control2;
1351 this_spi->hw_reg->PKTSIZE = packet_size;
1352 this_spi->hw_reg->CMDSIZE = cmd_size;
1353 this_spi->hw_reg->SLAVE_SELECT = slave_select;
1354 }
1355
1356 /***************************************************************************//**
1357 * SPI0 interrupt service routine.
1358 * Please note that the name of this ISR is defined as part of the MPFS HAL
1359 * start-up code.
1360 */
spi0_plic_IRQHandler(void)1361 uint8_t spi0_plic_IRQHandler(void)
1362 {
1363 if (g_spi_axi_pos & 0x01u)
1364 {
1365 mss_spi_isr(&g_mss_spi0_hi);
1366 }
1367 else
1368 {
1369 mss_spi_isr(&g_mss_spi0_lo);
1370 }
1371
1372 return (uint8_t)EXT_IRQ_KEEP_ENABLED;
1373 }
1374
1375 /***************************************************************************//**
1376 * SPI1 interrupt service routine.
1377 * Please note that the name of this ISR is defined as part of the MPFS HAL
1378 * startup code.
1379 */
spi1_plic_IRQHandler(void)1380 uint8_t spi1_plic_IRQHandler(void)
1381 {
1382 if (g_spi_axi_pos & 0x02u)
1383 {
1384 mss_spi_isr(&g_mss_spi1_hi);
1385 }
1386 else
1387 {
1388 mss_spi_isr(&g_mss_spi1_lo);
1389 }
1390
1391 return (uint8_t)EXT_IRQ_KEEP_ENABLED;
1392 }
1393
1394 #ifdef __cplusplus
1395 }
1396 #endif