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