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