1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Email: opensource_embedded@phytium.com.cn
7 *
8 * Change Logs:
9 * Date Author Notes
10 * 2023-03-20 zhangyan first version
11 * 2023-05-31 zhangyan improve functions
12 *
13 */
14 #include "rtconfig.h"
15 #include "rtdevice.h"
16 #define LOG_TAG "qspi_drv"
17 #include "drv_log.h"
18 #include <rtthread.h>
19 #ifdef RT_USING_SMART
20 #include <ioremap.h>
21 #include "tlb.h"
22 #endif
23 #include "drv_qspi.h"
24 #include "fqspi_flash.h"
25 #include "fiopad.h"
26 #include "fqspi_hw.h"
27 #include "fio_mux.h"
28 #include <string.h>
29
30 #define QSPI_ALIGNED_BYTE 4
31
FQspiInit(phytium_qspi_bus * phytium_qspi_bus)32 static rt_err_t FQspiInit(phytium_qspi_bus *phytium_qspi_bus)
33 {
34 FError ret = FT_SUCCESS;
35 rt_uint32_t qspi_id = phytium_qspi_bus->fqspi_id;
36
37 FIOPadSetQspiMux(qspi_id, FQSPI_CS_0);
38 FIOPadSetQspiMux(qspi_id, FQSPI_CS_1);
39
40 FQspiDeInitialize(&(phytium_qspi_bus->fqspi));
41
42 FQspiConfig pconfig = *FQspiLookupConfig(qspi_id);
43
44 #ifdef RT_USING_SMART
45 pconfig.base_addr = (uintptr)rt_ioremap((void *)pconfig.base_addr, 0x1000);
46 #endif
47
48 /* Norflash init, include reset and read flash_size */
49 ret = FQspiCfgInitialize(&(phytium_qspi_bus->fqspi), &pconfig);
50 if (FT_SUCCESS != ret)
51 {
52 LOG_E("Qspi init failed.\n");
53 return -RT_ERROR;
54 }
55 else
56 {
57 LOG_D("Qspi init successfully.\n");
58 }
59
60 /* Detect connected flash infomation */
61 ret = FQspiFlashDetect(&(phytium_qspi_bus->fqspi));
62 if (FT_SUCCESS != ret)
63 {
64 LOG_E("Qspi flash detect failed.\n");
65 return -RT_ERROR;
66 }
67 else
68 {
69 LOG_D("Qspi flash detect successfully.\n");
70 }
71
72 #ifdef USING_QSPI_CHANNEL0
73 phytium_qspi_bus->fqspi.config.channel = 0;
74 #elif defined USING_QSPI_CHANNEL1
75 phytium_qspi_bus->fqspi.config.channel = 1;
76 #endif
77 phytium_qspi_bus->init = RT_EOK;
78 return RT_EOK;
79 }
80
81 #define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
FtDumpHexByte(const u8 * ptr,u32 buflen)82 void FtDumpHexByte(const u8 *ptr, u32 buflen)
83 {
84 u8 *buf = (u8 *)ptr;
85 fsize_t i, j;
86
87 for (i = 0; i < buflen; i += 16)
88 {
89 rt_kprintf("%p: ", ptr + i);
90
91 for (j = 0; j < 16; j++)
92 if (i + j < buflen)
93 {
94 rt_kprintf("%02X ", buf[i + j]);
95 }
96 else
97 {
98 rt_kprintf(" ");
99 }
100 rt_kprintf(" ");
101
102 for (j = 0; j < 16; j++)
103 if (i + j < buflen)
104 {
105 rt_kprintf("%c", (char)(__is_print(buf[i + j]) ? buf[i + j] : '.'));
106 }
107 rt_kprintf("\r\n");
108 }
109 }
110
RTQspiFlashWriteData(FQspiCtrl * pctrl,uintptr addr,const u8 * buf,size_t len)111 FError RTQspiFlashWriteData(FQspiCtrl *pctrl, uintptr addr, const u8 *buf, size_t len)
112 {
113 FASSERT(pctrl && buf);
114 FError ret = FQSPI_SUCCESS;
115 u32 loop = 0;
116 const u32 mask = (u32)GENMASK(1, 0);
117 u32 reg_val = 0;
118 u32 val = 0;
119 u32 aligned_bit = 0;
120 u8 tmp[QSPI_ALIGNED_BYTE] = {0xff, 0xff, 0xff, 0xff};
121 uintptr base_addr = pctrl->config.base_addr;
122 if (FT_COMPONENT_IS_READY != pctrl->is_ready)
123 {
124 LOG_E("Nor flash not ready !!!");
125 return FQSPI_NOT_READY;
126 }
127
128 /* Flash write enable */
129 ret = FQspiFlashEnableWrite(pctrl);
130 if (ret != FT_SUCCESS)
131 {
132 LOG_E("FQspiFlashEnableWrite failed!");
133 return ret;
134 }
135
136 if (IS_ALIGNED(addr, QSPI_ALIGNED_BYTE)) /* if copy src is aligned by 4 bytes */
137 {
138 /* write alligned data into memory space */
139 for (loop = 0; loop < (len >> 2); loop++)
140 {
141 FQSPI_DAT_WRITE(addr + QSPI_ALIGNED_BYTE * loop, *(u32 *)(buf + QSPI_ALIGNED_BYTE * loop));
142 }
143 /* write not alligned data into memory space */
144 if (len & mask)
145 {
146 addr = addr + (len & ~mask);
147 memcpy(tmp, buf + (len & ~mask), len & mask);
148 FQSPI_DAT_WRITE(addr, *(u32 *)(tmp));
149 }
150 }
151 else
152 {
153 aligned_bit = (addr & mask);
154 addr = addr - aligned_bit;
155 reg_val = FQSPI_READ_REG32(addr, 0);
156
157 for (loop = 0; loop < (QSPI_ALIGNED_BYTE - aligned_bit); loop++)
158 {
159 val = (val << 8) | (buf[loop]);
160 reg_val &= (~(0xff << (loop * 8)));
161 }
162
163 reg_val |= val;
164 reg_val = __builtin_bswap32(reg_val);
165 FQSPI_DAT_WRITE(addr, reg_val);
166
167 buf = buf + loop;
168 len = len - loop;
169 addr = addr + QSPI_ALIGNED_BYTE;
170
171 LOG_D("addr=%p, buf=%p, len=%d, value=%#x\r\n", addr, buf, len, *(u32 *)(buf));
172
173 for (loop = 0; loop < (len >> 2); loop++)
174 {
175 FQSPI_DAT_WRITE(addr + QSPI_ALIGNED_BYTE * loop, *(u32 *)(buf + QSPI_ALIGNED_BYTE * loop));
176 }
177
178 if (!IS_ALIGNED(len, QSPI_ALIGNED_BYTE))
179 {
180 buf = buf + QSPI_ALIGNED_BYTE * loop;
181 len = len - QSPI_ALIGNED_BYTE * loop;
182 addr = addr + QSPI_ALIGNED_BYTE * loop;
183 memcpy(tmp, buf, len);
184 FQSPI_DAT_WRITE(addr, *(u32 *)(tmp));
185 }
186 }
187
188 /* flush buffer data to Flash */
189 FQspiWriteFlush(base_addr);
190
191 ret = FQspiFlashWaitForCmd(pctrl);
192
193 return ret;
194 }
195
RTQspiFlashReadData(FQspiCtrl * pctrl,uintptr addr,u8 * buf,size_t len)196 size_t RTQspiFlashReadData(FQspiCtrl *pctrl, uintptr addr, u8 *buf, size_t len)
197 {
198 /* addr of copy dst or src might be zero */
199 FASSERT(pctrl && buf);
200 size_t loop = 0;
201 const size_t cnt = len / QSPI_ALIGNED_BYTE; /* cnt number of 4-bytes need copy */
202 const size_t remain = len % QSPI_ALIGNED_BYTE; /* remain number of 1-byte not aligned */
203 u8 align_buf[QSPI_ALIGNED_BYTE];
204 size_t copy_len = 0;
205 intptr src_addr = (intptr)addr; /* conver to 32/64 bit addr */
206 intptr dst_addr = (intptr)buf;
207
208 if (FT_COMPONENT_IS_READY != pctrl->is_ready)
209 {
210 LOG_E("Nor flash not ready !!!");
211 return 0;
212 }
213 if (0 == pctrl->rd_cfg.rd_cmd)
214 {
215 LOG_E("Nor flash read command is not ready !!!");
216 return 0;
217 }
218
219 if (0 == len)
220 {
221 return 0;
222 }
223
224 if (IS_ALIGNED(src_addr, QSPI_ALIGNED_BYTE)) /* if copy src is aligned by 4 bytes */
225 {
226 /* read 4-bytes aligned buf part */
227 for (loop = 0; loop < cnt; loop++)
228 {
229 *(u32 *)dst_addr = *(volatile u32 *)(src_addr);
230 src_addr += QSPI_ALIGNED_BYTE;
231 dst_addr += QSPI_ALIGNED_BYTE;
232 }
233
234 copy_len += (loop << 2);
235
236 if (remain > 0)
237 {
238 *(u32 *)align_buf = *(volatile u32 *)(src_addr);
239 }
240
241 /* read remain un-aligned buf byte by byte */
242 for (loop = 0; loop < remain; loop++)
243 {
244 *(u8 *)dst_addr = align_buf[loop];
245 dst_addr += 1;
246 }
247
248 copy_len += loop;
249
250 }
251 else /* if copy src is not aligned */
252 {
253 /* read byte by byte */
254 for (loop = 0; loop < len; loop++)
255 {
256 *(u8 *)dst_addr = *(volatile u8 *)(src_addr);
257 dst_addr += 1;
258 src_addr += 1;
259 }
260 copy_len += loop;
261
262 }
263
264 return copy_len;
265 }
266
phytium_qspi_configure(struct rt_spi_device * device,struct rt_spi_configuration * configuration)267 static rt_err_t phytium_qspi_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration)
268 {
269 RT_ASSERT(device != RT_NULL);
270 RT_ASSERT(configuration != RT_NULL);
271 phytium_qspi_bus *qspi_bus;
272 qspi_bus = (phytium_qspi_bus *) device->bus->parent.user_data;
273 rt_err_t ret = RT_EOK;
274
275 ret = FQspiInit(qspi_bus);
276 if (RT_EOK != ret)
277 {
278 qspi_bus->init = RT_FALSE;
279 LOG_E("Qspi init failed!!!\n");
280 return -RT_ERROR;
281 }
282
283 return RT_EOK;
284 }
285
phytium_qspi_xfer(struct rt_spi_device * device,struct rt_spi_message * message)286 static rt_ssize_t phytium_qspi_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
287 {
288 RT_ASSERT(device != RT_NULL);
289 RT_ASSERT(message != RT_NULL);
290 FError ret = FT_SUCCESS;
291 phytium_qspi_bus *qspi_bus;
292 struct rt_qspi_message *qspi_message = (struct rt_qspi_message *)message;
293 rt_uint32_t cmd = qspi_message->instruction.content;
294 rt_uint32_t flash_addr = qspi_message->address.content;
295 rt_uint32_t len = message->length;
296 const void *rcvb = message->recv_buf;
297 const void *sndb = message->send_buf;
298 qspi_bus = (phytium_qspi_bus *) device->bus->parent.user_data;
299 uintptr addr = flash_addr;
300 for (u32 index = 0; index < qspi_bus->fqspi.config.channel; index++)
301 {
302 addr = qspi_bus->fqspi.flash_size[index];
303 }
304 /*Distinguish the write mode according to different commands*/
305 if (cmd == FQSPI_FLASH_CMD_PP || cmd == FQSPI_FLASH_CMD_QPP || cmd == FQSPI_FLASH_CMD_4PP || cmd == FQSPI_FLASH_CMD_4QPP)
306 {
307 ret = FQspiFlashErase(&(qspi_bus->fqspi), FQSPI_FLASH_CMD_SE, flash_addr);
308 if (FT_SUCCESS != ret)
309 {
310 LOG_E("Failed to erase mem, test result 0x%x.\r\n", ret);
311 return -RT_ERROR;
312 }
313
314 ret = FQspiFlashWriteDataConfig(&(qspi_bus->fqspi), cmd);
315 if (FQSPI_SUCCESS != ret)
316 {
317 LOG_E("Failed to config write, test result 0x%x.\r\n", ret);
318 return -RT_ERROR;
319 } /* write norflash data */
320 #ifdef RT_USING_SMART
321 addr = (uintptr)rt_ioremap((void *)addr, len);
322 #endif
323 ret = RTQspiFlashWriteData(&(qspi_bus->fqspi), addr, (u8 *)message->send_buf, len);
324 #ifdef RT_USING_SMART
325 rt_iounmap(addr);
326 rt_hw_tlb_invalidate_all();
327 #endif
328 if (FT_SUCCESS != ret)
329 {
330 LOG_E("Failed to write mem, test result 0x%x.\r\n", ret);
331 return -RT_ERROR;
332 }
333 else
334 {
335 LOG_I("Write successfully!!!\r\n");
336 }
337
338 return RT_EOK;
339 }
340
341 /*Distinguish the read mode according to different commands*/
342 if (cmd == FQSPI_FLASH_CMD_READ || cmd == FQSPI_FLASH_CMD_4READ || cmd == FQSPI_FLASH_CMD_FAST_READ || cmd == FQSPI_FLASH_CMD_4FAST_READ ||
343 cmd == FQSPI_FLASH_CMD_DUAL_READ || cmd == FQSPI_FLASH_CMD_QIOR || cmd == FQSPI_FLASH_CMD_4QIOR)
344 {
345 ret |= FQspiFlashReadDataConfig(&(qspi_bus->fqspi), cmd);
346 if (FT_SUCCESS != ret)
347 {
348 LOG_E("Failed to config read, test result 0x%x.\r\n", ret);
349 return -RT_ERROR;
350 }
351 /* read norflash data */
352 #ifdef RT_USING_SMART
353 addr = (uintptr)rt_ioremap((void *)addr, len);
354 #endif
355 size_t read_len = RTQspiFlashReadData(&(qspi_bus->fqspi), addr, (u8 *)message->recv_buf, len);
356 #ifdef RT_USING_SMART
357 rt_iounmap(addr);
358 rt_hw_tlb_invalidate_all();
359 #endif
360 if (read_len != len)
361 {
362 LOG_E("Failed to read mem, read len = %d.\r\n", read_len);
363 return -RT_ERROR;
364 }
365 else
366 {
367 LOG_I("Read successfully!!!, read_len = %d\r\n", read_len);
368 }
369 FtDumpHexByte(message->recv_buf, read_len);
370
371 return read_len;
372 }
373
374 if (rcvb)
375 {
376 if (cmd == FQSPI_FLASH_CMD_RDID || cmd == FQSPI_FLASH_CMD_RDSR1 || cmd == FQSPI_FLASH_CMD_RDSR2 || cmd == FQSPI_FLASH_CMD_RDSR3)
377 {
378 ret |= FQspiFlashSpecialInstruction(&(qspi_bus->fqspi), cmd, (u8 *)rcvb, sizeof(rcvb));
379 if (FT_SUCCESS != ret)
380 {
381 LOG_E("Failed to read flash information.\n");
382 return -RT_ERROR;
383 }
384 }
385
386 return 1;
387 }
388
389 if (sndb)
390 {
391 ret |= FQspiFlashEnableWrite(&(qspi_bus->fqspi));
392 if (FT_SUCCESS != ret)
393 {
394 LOG_E("Failed to enable flash reg write.\n");
395 return -RT_ERROR;
396 }
397
398 ret |= FQspiFlashWriteReg(&(qspi_bus->fqspi), cmd, (u8 *)sndb, 1);
399 if (FT_SUCCESS != ret)
400 {
401 LOG_E("Failed to write flash reg.\n");
402 return -RT_ERROR;
403 }
404
405 return 1;
406 }
407
408 LOG_E("cmd not found!!!\r\n");
409 return -RT_ERROR;
410 }
411
412 static struct rt_spi_ops phytium_qspi_ops =
413 {
414 .configure = phytium_qspi_configure,
415 .xfer = phytium_qspi_xfer,
416 };
417
phytium_qspi_bus_attach_device(const char * bus_name,const char * device_name)418 rt_err_t phytium_qspi_bus_attach_device(const char *bus_name, const char *device_name)
419 {
420 struct rt_qspi_device *qspi_device;
421 rt_err_t result = RT_EOK;
422 RT_ASSERT(bus_name != RT_NULL);
423 RT_ASSERT(device_name != RT_NULL);
424
425 qspi_device = (struct rt_qspi_device *)rt_malloc(sizeof(struct rt_qspi_device));
426 if (qspi_device == RT_NULL)
427 {
428 LOG_E("Qspi bus attach device failed.");
429 result = RT_ENOMEM;
430 goto __exit;
431 }
432 result = rt_spi_bus_attach_device(&(qspi_device->parent), device_name, bus_name, RT_NULL);
433
434 __exit:
435 if (result != RT_EOK)
436 {
437 if (qspi_device)
438 {
439 rt_free(qspi_device);
440 }
441 }
442 return result;
443 }
444
rt_qspi_init(phytium_qspi_bus * phytium_qspi)445 static int rt_qspi_init(phytium_qspi_bus *phytium_qspi)
446 {
447 rt_err_t result = RT_EOK;
448
449 phytium_qspi->qspi_bus.parent.user_data = phytium_qspi;
450
451 if (rt_qspi_bus_register(&phytium_qspi->qspi_bus, phytium_qspi->name, &phytium_qspi_ops) == RT_EOK)
452 {
453 LOG_D("Qspi bus register successfully!!!\n");
454 }
455 else
456 {
457 LOG_E("Qspi bus register Failed!!!\n");
458 result = -RT_ERROR;
459 }
460
461 return result;
462 }
463
464 #if defined(RT_USING_QSPI0)
465 static phytium_qspi_bus phytium_qspi0_bus;
466 #endif
467
rt_hw_qspi_init(void)468 int rt_hw_qspi_init(void)
469 {
470 #if defined(RT_USING_QSPI0)
471 phytium_qspi0_bus.name = "QSPI0";
472 phytium_qspi0_bus.fqspi_id = FQSPI0_ID;
473 rt_qspi_init(&phytium_qspi0_bus);
474 FQspiInit(&phytium_qspi0_bus);
475 #endif
476 return 0;
477 }
478 INIT_BOARD_EXPORT(rt_hw_qspi_init);
479