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-11-11      Wayne            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_err_t ret = RT_EOK;
99 
100     RT_ASSERT(device != RT_NULL);
101     RT_ASSERT(configuration != RT_NULL);
102 
103     spi_bus = (struct nu_spi *) device->bus;
104 
105     /* Check mode */
106     switch (configuration->mode & RT_SPI_MODE_3)
107     {
108     case RT_SPI_MODE_0:
109         u32SPIMode = SPI_MODE_0;
110         break;
111     case RT_SPI_MODE_1:
112         u32SPIMode = SPI_MODE_1;
113         break;
114     case RT_SPI_MODE_2:
115         u32SPIMode = SPI_MODE_2;
116         break;
117     case RT_SPI_MODE_3:
118         u32SPIMode = SPI_MODE_3;
119         break;
120     default:
121         ret = -RT_EIO;
122         goto exit_nu_qspi_bus_configure;
123     }
124 
125     /* Check data width */
126     if (!(configuration->data_width == 8  ||
127             configuration->data_width == 16 ||
128             configuration->data_width == 24 ||
129             configuration->data_width == 32))
130     {
131         ret = -RT_EINVAL;
132         goto exit_nu_qspi_bus_configure;
133     }
134 
135     /* Need to initialize new configuration? */
136     if (rt_memcmp(configuration, &spi_bus->configuration, sizeof(struct rt_spi_configuration)) != 0)
137     {
138         uint32_t u32ActualClk;
139         rt_memcpy(&spi_bus->configuration, configuration, sizeof(struct rt_spi_configuration));
140 
141         u32ActualClk = QSPI_Open((QSPI_T *)spi_bus->spi_base, SPI_MASTER, u32SPIMode, configuration->data_width, configuration->max_hz);
142         LOG_I("[%s] Preferred clock:%d, Actually:%d", spi_bus->name, configuration->max_hz, u32ActualClk);
143 
144         if (configuration->mode & RT_SPI_CS_HIGH)
145         {
146             /* Set CS pin to LOW */
147             SPI_SET_SS_LOW(spi_bus->spi_base);
148         }
149         else
150         {
151             /* Set CS pin to HIGH */
152             SPI_SET_SS_HIGH(spi_bus->spi_base);
153         }
154 
155         if (configuration->mode & RT_SPI_MSB)
156         {
157             /* Set sequence to MSB first */
158             SPI_SET_MSB_FIRST(spi_bus->spi_base);
159         }
160         else
161         {
162             /* Set sequence to LSB first */
163             SPI_SET_LSB_FIRST(spi_bus->spi_base);
164         }
165     }
166 
167     /* Clear SPI RX FIFO */
168     nu_spi_drain_rxfifo(spi_bus->spi_base);
169 
170 exit_nu_qspi_bus_configure:
171 
172     return -(ret);
173 }
174 
nu_qspi_mode_config(struct nu_spi * qspi_bus,rt_uint8_t * tx,rt_uint8_t * rx,int qspi_lines)175 static int nu_qspi_mode_config(struct nu_spi *qspi_bus, rt_uint8_t *tx, rt_uint8_t *rx, int qspi_lines)
176 {
177     QSPI_T *qspi_base = (QSPI_T *)qspi_bus->spi_base;
178     if (qspi_lines > 1)
179     {
180         if (tx)
181         {
182             switch (qspi_lines)
183             {
184             case 2:
185                 QSPI_ENABLE_DUAL_OUTPUT_MODE(qspi_base);
186                 break;
187             case 4:
188                 QSPI_ENABLE_QUAD_OUTPUT_MODE(qspi_base);
189                 break;
190             default:
191                 LOG_E("Data line is not supported.\n");
192                 break;
193             }
194         }
195         else
196         {
197             switch (qspi_lines)
198             {
199             case 2:
200                 QSPI_ENABLE_DUAL_INPUT_MODE(qspi_base);
201                 break;
202             case 4:
203                 QSPI_ENABLE_QUAD_INPUT_MODE(qspi_base);
204                 break;
205             default:
206                 LOG_E("Data line is not supported.\n");
207                 break;
208             }
209         }
210     }
211     else
212     {
213         QSPI_DISABLE_DUAL_MODE(qspi_base);
214         QSPI_DISABLE_QUAD_MODE(qspi_base);
215     }
216     return qspi_lines;
217 }
218 
nu_qspi_bus_xfer(struct rt_spi_device * device,struct rt_spi_message * message)219 static rt_ssize_t nu_qspi_bus_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
220 {
221     struct nu_spi *qspi_bus;
222     struct rt_qspi_configuration *qspi_configuration;
223     struct rt_qspi_message *qspi_message;
224     rt_uint8_t u8last = 1;
225     rt_uint8_t bytes_per_word;
226     QSPI_T *qspi_base;
227     rt_ssize_t u32len = 0;
228 
229     RT_ASSERT(device != RT_NULL);
230     RT_ASSERT(message != RT_NULL);
231 
232     qspi_bus = (struct nu_spi *) device->bus;
233     qspi_base = (QSPI_T *)qspi_bus->spi_base;
234     qspi_configuration = &qspi_bus->configuration;
235 
236     bytes_per_word = qspi_configuration->parent.data_width / 8;
237 
238     if (message->cs_take && !(qspi_configuration->parent.mode & RT_SPI_NO_CS))
239     {
240         if (qspi_configuration->parent.mode & RT_SPI_CS_HIGH)
241         {
242             QSPI_SET_SS_HIGH(qspi_base);
243         }
244         else
245         {
246             QSPI_SET_SS_LOW(qspi_base);
247         }
248     }
249 
250     qspi_message = (struct rt_qspi_message *)message;
251 
252     /* Command + Address + Dummy + Data */
253     /* Command stage */
254     if (qspi_message->instruction.content != 0)
255     {
256         u8last = nu_qspi_mode_config(qspi_bus, (rt_uint8_t *) &qspi_message->instruction.content, RT_NULL, qspi_message->instruction.qspi_lines);
257         nu_spi_transfer((struct nu_spi *)qspi_bus,
258                         (rt_uint8_t *) &qspi_message->instruction.content,
259                         RT_NULL,
260                         1,
261                         1);
262     }
263 
264     /* Address stage */
265     if (qspi_message->address.size > 0)
266     {
267         rt_uint32_t u32ReversedAddr = 0;
268         rt_uint32_t u32AddrNumOfByte = qspi_message->address.size / 8;
269         switch (u32AddrNumOfByte)
270         {
271         case 1:
272             u32ReversedAddr = (qspi_message->address.content & 0xff);
273             break;
274         case 2:
275             nu_set16_be((rt_uint8_t *)&u32ReversedAddr, qspi_message->address.content);
276             break;
277         case 3:
278             nu_set24_be((rt_uint8_t *)&u32ReversedAddr, qspi_message->address.content);
279             break;
280         case 4:
281             nu_set32_be((rt_uint8_t *)&u32ReversedAddr, qspi_message->address.content);
282             break;
283         default:
284             RT_ASSERT(0);
285             break;
286         }
287         u8last = nu_qspi_mode_config(qspi_bus, (rt_uint8_t *)&u32ReversedAddr, RT_NULL, qspi_message->address.qspi_lines);
288         nu_spi_transfer((struct nu_spi *)qspi_bus,
289                         (rt_uint8_t *) &u32ReversedAddr,
290                         RT_NULL,
291                         u32AddrNumOfByte,
292                         1);
293     }
294 
295     /* alternate_bytes stage */
296     if ((qspi_message->alternate_bytes.size > 0) && (qspi_message->alternate_bytes.size <= 4))
297     {
298         rt_uint32_t u32AlternateByte = 0;
299         rt_uint32_t u32NumOfByte = qspi_message->alternate_bytes.size / 8;
300         switch (u32NumOfByte)
301         {
302         case 1:
303             u32AlternateByte = (qspi_message->alternate_bytes.content & 0xff);
304             break;
305         case 2:
306             nu_set16_be((rt_uint8_t *)&u32AlternateByte, qspi_message->alternate_bytes.content);
307             break;
308         case 3:
309             nu_set24_be((rt_uint8_t *)&u32AlternateByte, qspi_message->alternate_bytes.content);
310             break;
311         case 4:
312             nu_set32_be((rt_uint8_t *)&u32AlternateByte, qspi_message->alternate_bytes.content);
313             break;
314         default:
315             RT_ASSERT(0);
316             break;
317         }
318         u8last = nu_qspi_mode_config(qspi_bus, (rt_uint8_t *)&u32AlternateByte, RT_NULL, qspi_message->alternate_bytes.qspi_lines);
319         nu_spi_transfer((struct nu_spi *)qspi_bus,
320                         (rt_uint8_t *) &u32AlternateByte,
321                         RT_NULL,
322                         u32NumOfByte,
323                         1);
324     }
325 
326     /* Dummy_cycles stage */
327     if (qspi_message->dummy_cycles > 0)
328     {
329         qspi_bus->dummy = 0x00;
330 
331         u8last = nu_qspi_mode_config(qspi_bus, (rt_uint8_t *) &qspi_bus->dummy, RT_NULL, u8last);
332         nu_spi_transfer((struct nu_spi *)qspi_bus,
333                         (rt_uint8_t *) &qspi_bus->dummy,
334                         RT_NULL,
335                         qspi_message->dummy_cycles / (8 / u8last),
336                         1);
337     }
338 
339     if (message->length > 0)
340     {
341         /* Data stage */
342         nu_qspi_mode_config(qspi_bus, (rt_uint8_t *) message->send_buf, (rt_uint8_t *) message->recv_buf, qspi_message->qspi_data_lines);
343         nu_spi_transfer((struct nu_spi *)qspi_bus,
344                         (rt_uint8_t *) message->send_buf,
345                         (rt_uint8_t *) message->recv_buf,
346                         message->length,
347                         bytes_per_word);
348         u32len = message->length;
349     }
350     else
351     {
352         u32len = 1;
353     }
354 
355     if (message->cs_release && !(qspi_configuration->parent.mode & RT_SPI_NO_CS))
356     {
357         if (qspi_configuration->parent.mode & RT_SPI_CS_HIGH)
358         {
359             QSPI_SET_SS_LOW(qspi_base);
360         }
361         else
362         {
363             QSPI_SET_SS_HIGH(qspi_base);
364         }
365     }
366 
367     return u32len;
368 }
369 
nu_qspi_register_bus(struct nu_spi * qspi_bus,const char * name)370 static int nu_qspi_register_bus(struct nu_spi *qspi_bus, const char *name)
371 {
372     return rt_qspi_bus_register(&qspi_bus->dev, name, &nu_qspi_poll_ops);
373 }
374 
375 /**
376  * Hardware SPI Initial
377  */
rt_hw_qspi_init(void)378 static int rt_hw_qspi_init(void)
379 {
380     rt_uint8_t i;
381 
382     for (i = (QSPI_START + 1); i < QSPI_CNT; i++)
383     {
384         nu_sys_ip_reset(nu_qspi_arr[i].rstidx);
385 
386         nu_qspi_register_bus(&nu_qspi_arr[i], nu_qspi_arr[i].name);
387 #if defined(BSP_USING_SPI_PDMA)
388         nu_qspi_arr[i].pdma_chanid_tx = -1;
389         nu_qspi_arr[i].pdma_chanid_rx = -1;
390 #endif
391 #if defined(BSP_USING_QSPI_PDMA)
392         if ((nu_qspi_arr[i].pdma_perp_tx != NU_PDMA_UNUSED) && (nu_qspi_arr[i].pdma_perp_rx != NU_PDMA_UNUSED))
393         {
394             if (nu_hw_spi_pdma_allocate(&nu_qspi_arr[i]) != RT_EOK)
395             {
396                 LOG_E("Failed to allocate DMA channels for %s. We will use poll-mode for this bus.\n", nu_qspi_arr[i].name);
397             }
398         }
399 #endif
400     }
401 
402     return 0;
403 }
404 INIT_PREV_EXPORT(rt_hw_qspi_init);
405 
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)())406 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)())
407 {
408     struct rt_qspi_device *qspi_device = RT_NULL;
409     rt_err_t result = RT_EOK;
410 
411     RT_ASSERT(bus_name != RT_NULL);
412     RT_ASSERT(device_name != RT_NULL);
413     RT_ASSERT(data_line_width == 1 || data_line_width == 2 || data_line_width == 4);
414 
415     qspi_device = (struct rt_qspi_device *)rt_malloc(sizeof(struct rt_qspi_device));
416     if (qspi_device == RT_NULL)
417     {
418         LOG_E("no memory, qspi bus attach device failed!\n");
419         result = -RT_ENOMEM;
420         goto __exit;
421     }
422 
423     qspi_device->enter_qspi_mode = enter_qspi_mode;
424     qspi_device->exit_qspi_mode = exit_qspi_mode;
425     qspi_device->config.qspi_dl_width = data_line_width;
426 
427     result = rt_spi_bus_attach_device(&qspi_device->parent, device_name, bus_name, RT_NULL);
428 
429 __exit:
430     if (result != RT_EOK)
431     {
432         if (qspi_device)
433         {
434             rt_free(qspi_device);
435         }
436     }
437 
438     return  result;
439 }
440 
441 #endif //#if defined(BSP_USING_QSPI)
442