1 /**************************************************************************//**
2 *
3 * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Change Logs:
8 * Date Author Notes
9 * 2020-5-19 YHKuo First version
10 *
11 ******************************************************************************/
12 #include <rtconfig.h>
13
14 #if defined(BSP_USING_QSPI)
15
16 #define LOG_TAG "drv.qspi"
17 #define DBG_ENABLE
18 #define DBG_SECTION_NAME LOG_TAG
19 #define DBG_LEVEL DBG_INFO
20 #define DBG_COLOR
21 #include <rtdbg.h>
22
23 #include <rthw.h>
24 #include <rtdef.h>
25
26 #include <drv_spi.h>
27
28 /* Private define ---------------------------------------------------------------*/
29 enum
30 {
31 QSPI_START = -1,
32 #if defined(BSP_USING_QSPI0)
33 QSPI0_IDX,
34 #endif
35 #if defined(BSP_USING_QSPI1)
36 QSPI1_IDX,
37 #endif
38 QSPI_CNT
39 };
40
41 /* Private typedef --------------------------------------------------------------*/
42
43 /* Private functions ------------------------------------------------------------*/
44 static rt_err_t nu_qspi_bus_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration);
45 static rt_ssize_t nu_qspi_bus_xfer(struct rt_spi_device *device, struct rt_spi_message *message);
46 static int nu_qspi_register_bus(struct nu_spi *qspi_bus, const char *name);
47
48 /* Public functions -------------------------------------------------------------*/
49
50 /* Private variables ------------------------------------------------------------*/
51 static struct rt_spi_ops nu_qspi_poll_ops =
52 {
53 .configure = nu_qspi_bus_configure,
54 .xfer = nu_qspi_bus_xfer,
55 };
56
57 static struct nu_spi nu_qspi_arr [] =
58 {
59 #if defined(BSP_USING_QSPI0)
60 {
61 .name = "qspi0",
62 .spi_base = (SPI_T *)QSPI0,
63 .rstidx = QSPI0_RST,
64 #if defined(BSP_USING_SPI_PDMA)
65 #if defined(BSP_USING_QSPI0_PDMA)
66 .pdma_perp_tx = PDMA_QSPI0_TX,
67 .pdma_perp_rx = PDMA_QSPI0_RX,
68 #else
69 .pdma_perp_tx = NU_PDMA_UNUSED,
70 .pdma_perp_rx = NU_PDMA_UNUSED,
71 #endif
72 #endif
73 },
74 #endif
75 #if defined(BSP_USING_QSPI1)
76 {
77 .name = "qspi1",
78 .spi_base = (SPI_T *)QSPI1,
79 .rstidx = QSPI1_RST,
80 #if defined(BSP_USING_SPI_PDMA)
81 #if defined(BSP_USING_QSPI1_PDMA)
82 .pdma_perp_tx = PDMA_QSPI1_TX,
83 .pdma_perp_rx = PDMA_QSPI1_RX,
84 #else
85 .pdma_perp_tx = NU_PDMA_UNUSED,
86 .pdma_perp_rx = NU_PDMA_UNUSED,
87 #endif
88 #endif
89 },
90 #endif
91 }; /* qspi nu_qspi */
92
nu_qspi_bus_configure(struct rt_spi_device * device,struct rt_spi_configuration * configuration)93 static rt_err_t nu_qspi_bus_configure(struct rt_spi_device *device,
94 struct rt_spi_configuration *configuration)
95 {
96 struct nu_spi *spi_bus;
97 rt_uint32_t u32SPIMode;
98 rt_uint32_t u32BusClock;
99 rt_err_t ret = RT_EOK;
100
101 RT_ASSERT(device != RT_NULL);
102 RT_ASSERT(configuration != RT_NULL);
103
104 spi_bus = (struct nu_spi *) device->bus;
105
106 /* Check mode */
107 switch (configuration->mode & RT_SPI_MODE_3)
108 {
109 case RT_SPI_MODE_0:
110 u32SPIMode = SPI_MODE_0;
111 break;
112 case RT_SPI_MODE_1:
113 u32SPIMode = SPI_MODE_1;
114 break;
115 case RT_SPI_MODE_2:
116 u32SPIMode = SPI_MODE_2;
117 break;
118 case RT_SPI_MODE_3:
119 u32SPIMode = SPI_MODE_3;
120 break;
121 default:
122 ret = -RT_EIO;
123 goto exit_nu_qspi_bus_configure;
124 }
125
126 /* Check data width */
127 if (!(configuration->data_width == 8 ||
128 configuration->data_width == 16 ||
129 configuration->data_width == 24 ||
130 configuration->data_width == 32))
131 {
132 ret = -RT_EINVAL;
133 goto exit_nu_qspi_bus_configure;
134 }
135
136 /* Try to set clock and get actual spi bus clock */
137 u32BusClock = QSPI_SetBusClock((QSPI_T *)spi_bus->spi_base, configuration->max_hz);
138 if (configuration->max_hz > u32BusClock)
139 {
140 LOG_W("%s clock max frequency is %dHz (!= %dHz)\n", spi_bus->name, u32BusClock, configuration->max_hz);
141 configuration->max_hz = u32BusClock;
142 }
143
144 /* Need to initialize new configuration? */
145 if (rt_memcmp(configuration, &spi_bus->configuration, sizeof(struct rt_spi_configuration)) != 0)
146 {
147 rt_memcpy(&spi_bus->configuration, configuration, sizeof(struct rt_spi_configuration));
148
149 QSPI_Open((QSPI_T *)spi_bus->spi_base, SPI_MASTER, u32SPIMode, configuration->data_width, u32BusClock);
150
151 if (configuration->mode & RT_SPI_CS_HIGH)
152 {
153 /* Set CS pin to LOW */
154 SPI_SET_SS_LOW(spi_bus->spi_base);
155 }
156 else
157 {
158 /* Set CS pin to HIGH */
159 SPI_SET_SS_HIGH(spi_bus->spi_base);
160 }
161
162 if (configuration->mode & RT_SPI_MSB)
163 {
164 /* Set sequence to MSB first */
165 SPI_SET_MSB_FIRST(spi_bus->spi_base);
166 }
167 else
168 {
169 /* Set sequence to LSB first */
170 SPI_SET_LSB_FIRST(spi_bus->spi_base);
171 }
172 }
173
174 /* Clear SPI RX FIFO */
175 nu_spi_drain_rxfifo(spi_bus->spi_base);
176
177 exit_nu_qspi_bus_configure:
178
179 return -(ret);
180 }
181
nu_qspi_mode_config(struct nu_spi * qspi_bus,rt_uint8_t * tx,rt_uint8_t * rx,int qspi_lines)182 static int nu_qspi_mode_config(struct nu_spi *qspi_bus, rt_uint8_t *tx, rt_uint8_t *rx, int qspi_lines)
183 {
184 QSPI_T *qspi_base = (QSPI_T *)qspi_bus->spi_base;
185 #if defined(RT_SFUD_USING_QSPI)
186 if (qspi_lines > 1)
187 {
188 if (tx)
189 {
190 switch (qspi_lines)
191 {
192 case 2:
193 QSPI_ENABLE_DUAL_OUTPUT_MODE(qspi_base);
194 break;
195 case 4:
196 QSPI_ENABLE_QUAD_OUTPUT_MODE(qspi_base);
197 break;
198 default:
199 LOG_E("Data line is not supported.\n");
200 break;
201 }
202 }
203 else
204 {
205 switch (qspi_lines)
206 {
207 case 2:
208 QSPI_ENABLE_DUAL_INPUT_MODE(qspi_base);
209 break;
210 case 4:
211 QSPI_ENABLE_QUAD_INPUT_MODE(qspi_base);
212 break;
213 default:
214 LOG_E("Data line is not supported.\n");
215 break;
216 }
217 }
218 }
219 else
220 #endif
221 {
222 QSPI_DISABLE_DUAL_MODE(qspi_base);
223 QSPI_DISABLE_QUAD_MODE(qspi_base);
224 }
225 return qspi_lines;
226 }
227
nu_qspi_bus_xfer(struct rt_spi_device * device,struct rt_spi_message * message)228 static rt_ssize_t nu_qspi_bus_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
229 {
230 struct nu_spi *qspi_bus;
231 struct rt_qspi_configuration *qspi_configuration;
232 struct rt_qspi_message *qspi_message;
233 rt_uint8_t u8last = 1;
234 rt_uint8_t bytes_per_word;
235 QSPI_T *qspi_base;
236 rt_ssize_t u32len = 0;
237
238 RT_ASSERT(device != RT_NULL);
239 RT_ASSERT(message != RT_NULL);
240
241 qspi_bus = (struct nu_spi *) device->bus;
242 qspi_base = (QSPI_T *)qspi_bus->spi_base;
243 qspi_configuration = &qspi_bus->configuration;
244
245 bytes_per_word = qspi_configuration->parent.data_width / 8;
246
247 if (message->cs_take && !(qspi_configuration->parent.mode & RT_SPI_NO_CS))
248 {
249 if (qspi_configuration->parent.mode & RT_SPI_CS_HIGH)
250 {
251 QSPI_SET_SS_HIGH(qspi_base);
252 }
253 else
254 {
255 QSPI_SET_SS_LOW(qspi_base);
256 }
257 }
258
259 qspi_message = (struct rt_qspi_message *)message;
260
261 /* Command + Address + Dummy + Data */
262 /* Command stage */
263 if (qspi_message->instruction.content != 0)
264 {
265 u8last = nu_qspi_mode_config(qspi_bus, (rt_uint8_t *) &qspi_message->instruction.content, RT_NULL, qspi_message->instruction.qspi_lines);
266 nu_spi_transfer((struct nu_spi *)qspi_bus,
267 (rt_uint8_t *) &qspi_message->instruction.content,
268 RT_NULL,
269 1,
270 1);
271 }
272
273 /* Address stage */
274 if (qspi_message->address.size > 0)
275 {
276 rt_uint32_t u32ReversedAddr = 0;
277 rt_uint32_t u32AddrNumOfByte = qspi_message->address.size / 8;
278 switch (u32AddrNumOfByte)
279 {
280 case 1:
281 u32ReversedAddr = (qspi_message->address.content & 0xff);
282 break;
283 case 2:
284 nu_set16_be((rt_uint8_t *)&u32ReversedAddr, qspi_message->address.content);
285 break;
286 case 3:
287 nu_set24_be((rt_uint8_t *)&u32ReversedAddr, qspi_message->address.content);
288 break;
289 case 4:
290 nu_set32_be((rt_uint8_t *)&u32ReversedAddr, qspi_message->address.content);
291 break;
292 default:
293 RT_ASSERT(0);
294 break;
295 }
296 u8last = nu_qspi_mode_config(qspi_bus, (rt_uint8_t *)&u32ReversedAddr, RT_NULL, qspi_message->address.qspi_lines);
297 nu_spi_transfer((struct nu_spi *)qspi_bus,
298 (rt_uint8_t *) &u32ReversedAddr,
299 RT_NULL,
300 u32AddrNumOfByte,
301 1);
302 }
303
304 /* alternate_bytes stage */
305 if ((qspi_message->alternate_bytes.size > 0) && (qspi_message->alternate_bytes.size <= 4))
306 {
307 rt_uint32_t u32AlternateByte = 0;
308 rt_uint32_t u32NumOfByte = qspi_message->alternate_bytes.size / 8;
309 switch (u32NumOfByte)
310 {
311 case 1:
312 u32AlternateByte = (qspi_message->alternate_bytes.content & 0xff);
313 break;
314 case 2:
315 nu_set16_be((rt_uint8_t *)&u32AlternateByte, qspi_message->alternate_bytes.content);
316 break;
317 case 3:
318 nu_set24_be((rt_uint8_t *)&u32AlternateByte, qspi_message->alternate_bytes.content);
319 break;
320 case 4:
321 nu_set32_be((rt_uint8_t *)&u32AlternateByte, qspi_message->alternate_bytes.content);
322 break;
323 default:
324 RT_ASSERT(0);
325 break;
326 }
327 u8last = nu_qspi_mode_config(qspi_bus, (rt_uint8_t *)&u32AlternateByte, RT_NULL, qspi_message->alternate_bytes.qspi_lines);
328 nu_spi_transfer((struct nu_spi *)qspi_bus,
329 (rt_uint8_t *) &u32AlternateByte,
330 RT_NULL,
331 u32NumOfByte,
332 1);
333 }
334
335 /* Dummy_cycles stage */
336 if (qspi_message->dummy_cycles > 0)
337 {
338 qspi_bus->dummy = 0x00;
339
340 u8last = nu_qspi_mode_config(qspi_bus, (rt_uint8_t *) &qspi_bus->dummy, RT_NULL, u8last);
341 nu_spi_transfer((struct nu_spi *)qspi_bus,
342 (rt_uint8_t *) &qspi_bus->dummy,
343 RT_NULL,
344 qspi_message->dummy_cycles / (8 / u8last),
345 1);
346 }
347
348 if (message->length > 0)
349 {
350 /* Data stage */
351 nu_qspi_mode_config(qspi_bus, (rt_uint8_t *) message->send_buf, (rt_uint8_t *) message->recv_buf, qspi_message->qspi_data_lines);
352 nu_spi_transfer((struct nu_spi *)qspi_bus,
353 (rt_uint8_t *) message->send_buf,
354 (rt_uint8_t *) message->recv_buf,
355 message->length,
356 bytes_per_word);
357 u32len = message->length;
358 }
359 else
360 {
361 u32len = 1;
362 }
363
364 if (message->cs_release && !(qspi_configuration->parent.mode & RT_SPI_NO_CS))
365 {
366 if (qspi_configuration->parent.mode & RT_SPI_CS_HIGH)
367 {
368 QSPI_SET_SS_LOW(qspi_base);
369 }
370 else
371 {
372 QSPI_SET_SS_HIGH(qspi_base);
373 }
374 }
375
376 return u32len;
377 }
378
nu_qspi_register_bus(struct nu_spi * qspi_bus,const char * name)379 static int nu_qspi_register_bus(struct nu_spi *qspi_bus, const char *name)
380 {
381 return rt_qspi_bus_register(&qspi_bus->dev, name, &nu_qspi_poll_ops);
382 }
383
384 /**
385 * Hardware SPI Initial
386 */
rt_hw_qspi_init(void)387 static int rt_hw_qspi_init(void)
388 {
389 rt_uint8_t i;
390
391 for (i = (QSPI_START + 1); i < QSPI_CNT; i++)
392 {
393 SYS_ResetModule(nu_qspi_arr[i].rstidx);
394
395 nu_qspi_register_bus(&nu_qspi_arr[i], nu_qspi_arr[i].name);
396 #if defined(BSP_USING_SPI_PDMA)
397 nu_qspi_arr[i].pdma_chanid_tx = -1;
398 nu_qspi_arr[i].pdma_chanid_rx = -1;
399 #endif
400 #if defined(BSP_USING_QSPI_PDMA)
401 if ((nu_qspi_arr[i].pdma_perp_tx != NU_PDMA_UNUSED) && (nu_qspi_arr[i].pdma_perp_rx != NU_PDMA_UNUSED))
402 {
403 if (nu_hw_spi_pdma_allocate(&nu_qspi_arr[i]) != RT_EOK)
404 {
405 LOG_E("Failed to allocate DMA channels for %s. We will use poll-mode for this bus.\n", nu_qspi_arr[i].name);
406 }
407 }
408 #endif
409 }
410
411 return 0;
412 }
413 INIT_DEVICE_EXPORT(rt_hw_qspi_init);
414
nu_qspi_bus_attach_device(const char * bus_name,const char * device_name,rt_uint8_t data_line_width,void (* enter_qspi_mode)(),void (* exit_qspi_mode)())415 rt_err_t nu_qspi_bus_attach_device(const char *bus_name, const char *device_name, rt_uint8_t data_line_width, void (*enter_qspi_mode)(), void (*exit_qspi_mode)())
416 {
417 struct rt_qspi_device *qspi_device = RT_NULL;
418 rt_err_t result = RT_EOK;
419
420 RT_ASSERT(bus_name != RT_NULL);
421 RT_ASSERT(device_name != RT_NULL);
422 RT_ASSERT(data_line_width == 1 || data_line_width == 2 || data_line_width == 4);
423
424 qspi_device = (struct rt_qspi_device *)rt_malloc(sizeof(struct rt_qspi_device));
425 if (qspi_device == RT_NULL)
426 {
427 LOG_E("no memory, qspi bus attach device failed!\n");
428 result = -RT_ENOMEM;
429 goto __exit;
430 }
431
432 qspi_device->enter_qspi_mode = enter_qspi_mode;
433 qspi_device->exit_qspi_mode = exit_qspi_mode;
434 qspi_device->config.qspi_dl_width = data_line_width;
435
436 result = rt_spi_bus_attach_device(&qspi_device->parent, device_name, bus_name, RT_NULL);
437
438 __exit:
439 if (result != RT_EOK)
440 {
441 if (qspi_device)
442 {
443 rt_free(qspi_device);
444 }
445 }
446
447 return result;
448 }
449
450 #endif //#if defined(BSP_USING_QSPI)
451