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