1 /***************************************************************************//**
2  * Copyright 2019-2020 Microchip FPGA Embedded Systems Solutions.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * PolarFire SoC (MPFS) Microprocessor SubSystem QSPI bare metal software driver
7  * implementation.
8  *
9  */
10 
11 #include "mpfs_hal/mss_hal.h"
12 #include "mss_qspi.h"
13 
14 #ifdef __cplusplus
15 extern "C" {
16 #endif
17 
18 #define QSPI_BYTESUPPER_MASK     ((uint32_t)0xFFFF0000u)
19 
20 static void default_status_hanlder(uint32_t value);
21 static volatile uint32_t g_irq_rd_byte_size = 0u;
22 static volatile uint8_t g_rx_complete = 0u;
23 static void * g_rd_buffer;
24 static volatile mss_qspi_status_handler_t g_handler;
25 
26 /***************************************************************************//**
27  * See mss_qspi.h for details of how to use this function.
28  */
MSS_QSPI_init(void)29 void MSS_QSPI_init
30 (
31     void
32 )
33 {
34     g_handler = default_status_hanlder;
35 
36     QSPI->CONTROL = CTRL_EN_MASK |
37                     CTRL_SAMPLE_SCK |
38                     (0x1u << CTRL_CLKRATE) | CTRL_CLKIDL_MASK ;
39 
40     QSPI->INTENABLE = 0x0u;
41 }
42 
43 /***************************************************************************//**
44  * See mss_qspi.h for details of how to use this function.
45  */
MSS_QSPI_configure(const mss_qspi_config_t * config)46 void MSS_QSPI_configure
47 (
48     const mss_qspi_config_t* config
49 )
50 {
51     QSPI->CONTROL = (uint32_t)(config->sample << CTRL_SAMPLE)    |
52                     (uint32_t)(config->io_format << CTRL_QMODE0) |
53                     (uint32_t)(config->clk_div << CTRL_CLKRATE)  |
54                     (uint32_t)(config->xip << CTRL_XIP)          |
55                     (uint32_t)(config->xip_addr << CTRL_XIPADDR) |
56                     (uint32_t)(config->spi_mode << CTRL_CLKIDL)  |
57                     CTRL_EN_MASK;
58 }
59 
60 /***************************************************************************//**
61  * See mss_qspi.h for details of how to use this function.
62  */
MSS_QSPI_get_config(mss_qspi_config_t * config)63 void MSS_QSPI_get_config
64 (
65     mss_qspi_config_t* config
66 )
67 {
68    volatile uint32_t reg =0;
69 
70    reg = QSPI->CONTROL;
71 
72    config->spi_mode = ((reg & CTRL_CLKIDL_MASK) >> CTRL_CLKIDL);
73    reg = reg & (uint32_t )((uint32_t )CTRL_QMODE12_MASK | (uint32_t )CTRL_QMODE0_MASK);
74    reg = reg >> CTRL_QMODE0;
75 
76    config->io_format = (mss_qspi_io_format)reg;
77 
78    config->clk_div = (mss_qspi_clk_div)((reg & CTRL_CLKRATE_MASK)
79                                                                >> CTRL_CLKRATE);
80    config->xip = (uint8_t)((reg & CTRL_XIP_MASK) >> CTRL_XIP);
81    config->xip_addr = (uint8_t)((reg & CTRL_XIPADDR_MASK) >> CTRL_XIPADDR);
82    config->sample = (uint8_t)((reg & CTRL_SAMPLE_MASK) >> CTRL_SAMPLE);
83 }
84 
85 /***************************************************************************//**
86  * See mss_qspi.h for details of how to use this function.
87  */
MSS_QSPI_polled_transfer_block(uint8_t num_addr_bytes,const void * const tx_buffer,uint32_t tx_byte_size,const void * const rd_buffer,uint32_t rd_byte_size,uint8_t num_idle_cycles)88 void MSS_QSPI_polled_transfer_block
89 (
90     uint8_t num_addr_bytes,
91     const void * const tx_buffer,
92     uint32_t tx_byte_size,
93     const void * const rd_buffer,
94     uint32_t rd_byte_size,
95     uint8_t num_idle_cycles
96 )
97 {
98     uint32_t idx;
99     uint8_t* buf8 = (uint8_t*)tx_buffer;
100     uint32_t* buf32 = (uint32_t*)tx_buffer;
101     volatile uint32_t skips;
102     uint32_t cbytes;
103     uint32_t total_byte_cnt;
104     uint32_t words = 0u;
105 
106     cbytes = 1u + tx_byte_size + num_addr_bytes;
107     total_byte_cnt = 1u + tx_byte_size + num_addr_bytes + rd_byte_size;
108 
109     QSPI->INTENABLE = 0u;
110 
111     while ((QSPI->STATUS & STTS_READY_MASK) == 0u){};
112 
113     /*bit16 to 31 define the number of Upper bytes when count is >65535
114     Write to lower 16 bit is ignored*/
115     QSPI->FRAMESUP = total_byte_cnt & QSPI_BYTESUPPER_MASK;
116 
117     num_idle_cycles = (num_idle_cycles << 3u);
118 
119     skips  = (total_byte_cnt & 0x0000FFFFu);
120     skips |= (cbytes << FRMS_CBYTES);
121     skips |= (((QSPI->CONTROL & CTRL_QMODE12_MASK)? 1u:0u) << FRMS_QSPI);
122     skips |= ((uint32_t)num_idle_cycles) << 23u;
123     skips |= FRMS_FWORD_MASK;
124 
125     QSPI->FRAMES = (uint32_t)skips;
126 
127     QSPI->CONTROL |= CTRL_FLAGSX4_MASK;
128 
129     words = cbytes / (uint32_t)4u;
130 
131     for (idx = 0u; idx < words; ++idx)
132     {
133         while (QSPI->STATUS & STTS_TFFULL_MASK){};
134 
135         QSPI->TXDATAX4 = (uint32_t)buf32[idx];
136     }
137 
138     QSPI->CONTROL &= ~CTRL_FLAGSX4_MASK;
139 
140     for (idx = (cbytes - (cbytes % 4u)); idx < cbytes; ++idx)
141     {
142         while (QSPI->STATUS & STTS_TFFULL_MASK){};
143 
144         QSPI->TXDATAX1 = (uint8_t)buf8[idx];
145     }
146 
147     buf32 = (uint32_t*)rd_buffer;
148     buf8 = (uint8_t*)rd_buffer;
149 
150     if (rd_byte_size)
151     {
152         words = rd_byte_size / 4u;
153 
154         QSPI->CONTROL |= CTRL_FLAGSX4_MASK;
155 
156         for (idx = 0u; idx < words; ++idx)
157         {
158             while (QSPI->STATUS & STTS_RFEMPTY_MASK){};
159             buf32[idx] = QSPI->RXDATAX4;
160         }
161 
162         QSPI->CONTROL &= ~CTRL_FLAGSX4_MASK;
163 
164         for (idx = (rd_byte_size - (rd_byte_size % 4u));
165                                                       idx < rd_byte_size; ++idx)
166         {
167             while (QSPI->STATUS & STTS_RFEMPTY_MASK){};
168             buf8[idx] = QSPI->RXDATAX1;
169         }
170 
171         while (0u == (QSPI->STATUS & STTS_RDONE_MASK))
172         {
173             skips = (uint64_t)((QSPI->STATUS & STTS_FLAGSX4_MASK) ?
174                                                QSPI->RXDATAX4 : QSPI->RXDATAX1);
175         }
176      }
177 }
178 
179 /***************************************************************************//**
180  * See mss_qspi.h for details of how to use this function.
181  */
MSS_QSPI_irq_transfer_block(uint8_t num_addr_bytes,const void * const tx_buffer,uint32_t tx_byte_size,const void * const rd_buffer,uint32_t rd_byte_size,uint8_t num_idle_cycles)182 uint8_t MSS_QSPI_irq_transfer_block
183 (
184     uint8_t num_addr_bytes,
185     const void * const tx_buffer,
186     uint32_t tx_byte_size,
187     const void * const rd_buffer,
188     uint32_t rd_byte_size,
189     uint8_t num_idle_cycles
190 )
191 {
192     uint32_t idx;
193     uint32_t cbytes;
194     uint32_t total_byte_cnt;
195     const uint8_t* buf8 = tx_buffer;
196     const uint32_t* buf32 = tx_buffer;
197 
198     uint8_t returnval = 0u;
199 
200 
201     g_rd_buffer = (uint32_t*)rd_buffer;
202     cbytes = 1u + tx_byte_size + num_addr_bytes;
203     total_byte_cnt = 1u + tx_byte_size + num_addr_bytes + rd_byte_size;
204 
205     if ((QSPI->STATUS & STTS_READY_MASK) == 0u)
206     {
207         returnval = 1u;
208     }
209     else
210     {
211         volatile uint32_t skips=0;
212         uint32_t enable = 0u;
213 
214         enable = INTE_TDONE_MASK;
215 
216         /*bit16 to 31 define the number of Upper bytes when count is >65535
217          Write to lower 16 bit is ignored*/
218         QSPI->FRAMESUP = total_byte_cnt & QSPI_BYTESUPPER_MASK;
219         num_idle_cycles = (num_idle_cycles << 3u);
220 
221         skips  = (total_byte_cnt & 0x0000FFFFu);
222         skips |= (cbytes << FRMS_CBYTES);
223         skips |= (((QSPI->CONTROL & CTRL_QMODE12_MASK)? 1u:0u) << FRMS_QSPI);
224         skips |= ((uint32_t)num_idle_cycles) << 23u;
225         skips |= FRMS_FWORD_MASK;
226 
227         QSPI->FRAMES = skips;
228 
229         QSPI->CONTROL |= CTRL_FLAGSX4_MASK;
230 
231         if (rd_byte_size)
232         {
233             g_rx_complete = 0u;
234             g_irq_rd_byte_size = rd_byte_size;
235 
236             QSPI->CONTROL |= CTRL_FLAGSX4_MASK;
237 
238             enable |= (uint32_t )((uint32_t )INTE_RDONE_MASK | (uint32_t )INTE_RAVLB_MASK);
239         }
240 
241         uint32_t words = 0u;
242         words = cbytes / (uint32_t)4u;
243 
244         for (idx = 0u; idx < words; ++idx)
245         {
246             while (QSPI->STATUS & STTS_TFFULL_MASK){};
247 
248             QSPI->TXDATAX4 = (uint32_t)buf32[idx];
249         }
250 
251         QSPI->CONTROL &= ~CTRL_FLAGSX4_MASK;
252 
253         for (idx = (cbytes - (cbytes % 4u)); idx < cbytes; ++idx)
254         {
255             while (QSPI->STATUS & STTS_TFFULL_MASK){};
256 
257             QSPI->TXDATAX1 = (uint8_t)buf8[idx];
258         }
259 
260         QSPI->INTENABLE = enable;
261         returnval = 0u;
262     }
263 
264     return(returnval);
265 }
266 
267 /***************************************************************************//**
268  * See mss_qspi.h for details of how to use this function.
269  */
MSS_QSPI_set_status_handler(mss_qspi_status_handler_t handler)270 void MSS_QSPI_set_status_handler
271 (
272    mss_qspi_status_handler_t handler
273 )
274 {
275     if ((mss_qspi_status_handler_t)0 != handler)
276     {
277         g_handler = handler;
278     }
279 }
280 
qspi_isr(void)281 static void qspi_isr(void)
282 {
283     uint32_t idx;
284     static uint32_t empty = 0u;
285     static uint32_t tx_fifo_full = 0u;
286     uint32_t status;
287 
288     status = QSPI->STATUS;
289 
290     if (STTS_TDONE_MASK == (uint32_t)(status & STTS_TDONE_MASK))
291     {
292         g_handler(STTS_TDONE_MASK);
293         QSPI->STATUS |= STTS_TDONE_MASK;
294     }
295 
296     if (STTS_RAVLB_MASK == (uint32_t)(status & STTS_RAVLB_MASK))
297     {
298         if (0u == g_rx_complete)
299         {
300             uint8_t* buf8 = g_rd_buffer;
301             uint32_t* buf32 = g_rd_buffer;
302             uint32_t words = 0u;
303 
304             words = g_irq_rd_byte_size / 4u;
305 
306             QSPI->CONTROL |= CTRL_FLAGSX4_MASK;
307 
308             for (idx = 0u; idx < words; ++idx)
309             {
310                 while (status & STTS_RFEMPTY_MASK){};
311 
312                 buf32[idx] = QSPI->RXDATAX4;
313             }
314 
315             QSPI->CONTROL &= ~CTRL_FLAGSX4_MASK;
316 
317             for (idx = (g_irq_rd_byte_size - (g_irq_rd_byte_size % 4u));
318                                                 idx < g_irq_rd_byte_size; ++idx)
319             {
320                 while (status & STTS_RFEMPTY_MASK){};
321 
322                 buf8[idx] = QSPI->RXDATAX1;
323             }
324 
325             uint32_t skips = 0;
326 
327             while (0u == (QSPI->STATUS & STTS_RFEMPTY_MASK))
328             {
329                 /*Make sure that the Receive FIFO is empty and any
330                   remaining data is read from it after desired bytes
331                   have been received.*/
332                 skips = (uint32_t)((QSPI->STATUS & STTS_FLAGSX4_MASK) ?
333                                             QSPI->RXDATAX4 : QSPI->RXDATAX1);
334             }
335         }
336     }
337 
338     if (STTS_RDONE_MASK == (uint32_t)(status & STTS_RDONE_MASK))
339     {
340         g_rx_complete = 1u;
341 
342         /*This means receive transfer is now complete. invoke the callback
343          * function*/
344         g_handler(STTS_RDONE_MASK);
345 
346         /*disable RXDONE, RXEMPTY, RXAVLBL interrupt*/
347         QSPI->INTENABLE &= ~(INTE_RDONE_MASK | INTE_RAVLB_MASK);
348         QSPI->STATUS |= STTS_RDONE_MASK;
349     }
350 }
351 
default_status_hanlder(uint32_t value)352 static void default_status_hanlder(uint32_t value)
353 {
354     /*Take some default interrupt handling action here*/
355 }
356 
357 /*QSPI interrupt handler function*/
qspi_plic_IRQHandler(void)358 uint8_t qspi_plic_IRQHandler(void)
359 {
360     qspi_isr();
361     return (uint8_t)EXT_IRQ_KEEP_ENABLED;
362 }
363 
364 #ifdef __cplusplus
365 }
366 #endif
367