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