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