1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2016-09-28     armink       first version.
9  */
10 
11 #include <stdint.h>
12 #include <string.h>
13 #include <rtdevice.h>
14 #include "dev_spi_flash.h"
15 #include "dev_spi_flash_sfud.h"
16 
17 #ifdef RT_USING_SFUD
18 
19 #ifndef RT_SFUD_DEFAULT_SPI_CFG
20 
21 #ifndef RT_SFUD_SPI_MAX_HZ
22 #define RT_SFUD_SPI_MAX_HZ 50000000
23 #endif
24 
25 /* read the JEDEC SFDP command must run at 50 MHz or less */
26 #define RT_SFUD_DEFAULT_SPI_CFG                  \
27 {                                                \
28     .mode = RT_SPI_MODE_0 | RT_SPI_MSB,          \
29     .data_width = 8,                             \
30     .max_hz = RT_SFUD_SPI_MAX_HZ,                \
31 }
32 #endif /* RT_SFUD_DEFAULT_SPI_CFG */
33 
34 #ifdef SFUD_USING_QSPI
35 #define RT_SFUD_DEFAULT_QSPI_CFG                 \
36 {                                                \
37     RT_SFUD_DEFAULT_SPI_CFG,                     \
38     .medium_size = 0x800000,                     \
39     .ddr_mode = 0,                               \
40     .qspi_dl_width = 4,                          \
41 }
42 #endif /* SFUD_USING_QSPI */
43 
rt_sfud_control(rt_device_t dev,int cmd,void * args)44 static rt_err_t rt_sfud_control(rt_device_t dev, int cmd, void *args) {
45     RT_ASSERT(dev);
46 
47     switch (cmd) {
48     case RT_DEVICE_CTRL_BLK_GETGEOME: {
49         struct rt_device_blk_geometry *geometry = (struct rt_device_blk_geometry *) args;
50         struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (dev->user_data);
51 
52         if (rtt_dev == RT_NULL || geometry == RT_NULL) {
53             return -RT_ERROR;
54         }
55 
56         geometry->bytes_per_sector = rtt_dev->geometry.bytes_per_sector;
57         geometry->sector_count = rtt_dev->geometry.sector_count;
58         geometry->block_size = rtt_dev->geometry.block_size;
59         break;
60     }
61     case RT_DEVICE_CTRL_BLK_ERASE: {
62         rt_uint32_t *addrs = (rt_uint32_t *) args, start_addr = addrs[0], end_addr = addrs[1], phy_start_addr;
63         struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (dev->user_data);
64         sfud_flash *sfud_dev = (sfud_flash *) (rtt_dev->user_data);
65         rt_size_t phy_size;
66 
67         if (addrs == RT_NULL || start_addr > end_addr || rtt_dev == RT_NULL || sfud_dev == RT_NULL) {
68             return -RT_ERROR;
69         }
70 
71         if (end_addr == start_addr) {
72             end_addr ++;
73         }
74 
75         phy_start_addr = start_addr * rtt_dev->geometry.bytes_per_sector;
76         phy_size = (end_addr - start_addr) * rtt_dev->geometry.bytes_per_sector;
77 
78         if (sfud_erase(sfud_dev, phy_start_addr, phy_size) != SFUD_SUCCESS) {
79             return -RT_ERROR;
80         }
81         break;
82     }
83     }
84 
85     return RT_EOK;
86 }
87 
88 
rt_sfud_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)89 static rt_ssize_t rt_sfud_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) {
90     struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (dev->user_data);
91     sfud_flash *sfud_dev = (sfud_flash *) (rtt_dev->user_data);
92 
93     RT_ASSERT(dev);
94     RT_ASSERT(rtt_dev);
95     RT_ASSERT(sfud_dev);
96     /* change the block device's logic address to physical address */
97     rt_off_t phy_pos = pos * rtt_dev->geometry.bytes_per_sector;
98     rt_size_t phy_size = size * rtt_dev->geometry.bytes_per_sector;
99 
100     if (sfud_read(sfud_dev, phy_pos, phy_size, buffer) != SFUD_SUCCESS) {
101         return 0;
102     } else {
103         return size;
104     }
105 }
106 
rt_sfud_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)107 static rt_ssize_t rt_sfud_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size) {
108     struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (dev->user_data);
109     sfud_flash *sfud_dev = (sfud_flash *) (rtt_dev->user_data);
110 
111     RT_ASSERT(dev);
112     RT_ASSERT(rtt_dev);
113     RT_ASSERT(sfud_dev);
114     /* change the block device's logic address to physical address */
115     rt_off_t phy_pos = pos * rtt_dev->geometry.bytes_per_sector;
116     rt_size_t phy_size = size * rtt_dev->geometry.bytes_per_sector;
117 
118     if (sfud_erase_write(sfud_dev, phy_pos, phy_size, buffer) != SFUD_SUCCESS) {
119         return 0;
120     } else {
121         return size;
122     }
123 }
124 
125 /**
126  * SPI write data then read data
127  */
spi_write_read(const sfud_spi * spi,const uint8_t * write_buf,size_t write_size,uint8_t * read_buf,size_t read_size)128 static sfud_err spi_write_read(const sfud_spi *spi, const uint8_t *write_buf, size_t write_size, uint8_t *read_buf,
129         size_t read_size) {
130     sfud_err result = SFUD_SUCCESS;
131     sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
132     struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
133 
134     RT_ASSERT(spi);
135     RT_ASSERT(sfud_dev);
136     RT_ASSERT(rtt_dev);
137 #ifdef SFUD_USING_QSPI
138     struct rt_qspi_device *qspi_dev = RT_NULL;
139 #endif
140     if (write_size) {
141         RT_ASSERT(write_buf);
142     }
143     if (read_size) {
144         RT_ASSERT(read_buf);
145     }
146 #ifdef SFUD_USING_QSPI
147     if(rtt_dev->rt_spi_device->bus->mode & RT_SPI_BUS_MODE_QSPI) {
148         qspi_dev = (struct rt_qspi_device *) (rtt_dev->rt_spi_device);
149         if (write_size && read_size) {
150             if (rt_qspi_send_then_recv(qspi_dev, write_buf, write_size, read_buf, read_size) <= 0) {
151                 result = SFUD_ERR_TIMEOUT;
152             }
153         } else if (write_size) {
154             if (rt_qspi_send(qspi_dev, write_buf, write_size) <= 0) {
155                 result = SFUD_ERR_TIMEOUT;
156             }
157         }
158     }
159     else
160 #endif
161     {
162         if (write_size && read_size) {
163             if (rt_spi_send_then_recv(rtt_dev->rt_spi_device, write_buf, write_size, read_buf, read_size) != RT_EOK) {
164                 result = SFUD_ERR_TIMEOUT;
165             }
166         } else if (write_size) {
167             if (rt_spi_send(rtt_dev->rt_spi_device, write_buf, write_size) <= 0) {
168                 result = SFUD_ERR_TIMEOUT;
169             }
170         } else {
171             if (rt_spi_recv(rtt_dev->rt_spi_device, read_buf, read_size) <= 0) {
172                 result = SFUD_ERR_TIMEOUT;
173             }
174         }
175     }
176 
177     return result;
178 }
179 
180 #ifdef SFUD_USING_QSPI
181 /**
182  * QSPI fast read data
183  */
qspi_read(const struct __sfud_spi * spi,uint32_t addr,sfud_qspi_read_cmd_format * qspi_read_cmd_format,uint8_t * read_buf,size_t read_size)184 static sfud_err qspi_read(const struct __sfud_spi *spi, uint32_t addr, sfud_qspi_read_cmd_format *qspi_read_cmd_format, uint8_t *read_buf, size_t read_size) {
185     struct rt_qspi_message message;
186     sfud_err result = SFUD_SUCCESS;
187 
188     sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
189     struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
190     struct rt_qspi_device *qspi_dev = (struct rt_qspi_device *) (rtt_dev->rt_spi_device);
191 
192     RT_ASSERT(spi);
193     RT_ASSERT(sfud_dev);
194     RT_ASSERT(rtt_dev);
195     RT_ASSERT(qspi_dev);
196 
197     /* set message struct */
198     message.instruction.content = qspi_read_cmd_format->instruction;
199     message.instruction.qspi_lines = qspi_read_cmd_format->instruction_lines;
200 
201     message.address.content = addr;
202     message.address.size = qspi_read_cmd_format->address_size;
203     message.address.qspi_lines = qspi_read_cmd_format->address_lines;
204 
205     message.alternate_bytes.content = 0;
206     message.alternate_bytes.size = 0;
207     message.alternate_bytes.qspi_lines = 0;
208 
209     message.dummy_cycles = qspi_read_cmd_format->dummy_cycles;
210 
211     message.parent.send_buf = RT_NULL;
212     message.parent.recv_buf = read_buf;
213     message.parent.length = read_size;
214     message.parent.cs_release = 1;
215     message.parent.cs_take = 1;
216     message.qspi_data_lines = qspi_read_cmd_format->data_lines;
217     /* set next */
218     /* Ensure correct QSPI message chaining by setting next pointer to NULL, preventing unintended data transmission issues.*/
219     message.parent.next = RT_NULL;
220     if (rt_qspi_transfer_message(qspi_dev, &message) != read_size) {
221         result = SFUD_ERR_TIMEOUT;
222     }
223 
224     return result;
225 }
226 #endif
227 
spi_lock(const sfud_spi * spi)228 static void spi_lock(const sfud_spi *spi) {
229     sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
230     struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
231 
232     RT_ASSERT(spi);
233     RT_ASSERT(sfud_dev);
234     RT_ASSERT(rtt_dev);
235 
236     rt_mutex_take(&(rtt_dev->lock), RT_WAITING_FOREVER);
237 }
238 
spi_unlock(const sfud_spi * spi)239 static void spi_unlock(const sfud_spi *spi) {
240     sfud_flash *sfud_dev = (sfud_flash *) (spi->user_data);
241     struct spi_flash_device *rtt_dev = (struct spi_flash_device *) (sfud_dev->user_data);
242 
243     RT_ASSERT(spi);
244     RT_ASSERT(sfud_dev);
245     RT_ASSERT(rtt_dev);
246 
247     rt_mutex_release(&(rtt_dev->lock));
248 }
249 
retry_delay_100us(void)250 static void retry_delay_100us(void) {
251     /* 100 microsecond delay */
252     rt_thread_delay((RT_TICK_PER_SECOND * 1 + 9999) / 10000);
253 }
254 
sfud_spi_port_init(sfud_flash * flash)255 sfud_err sfud_spi_port_init(sfud_flash *flash) {
256     sfud_err result = SFUD_SUCCESS;
257 
258     RT_ASSERT(flash);
259 
260     /* port SPI device interface */
261     flash->spi.wr = spi_write_read;
262 #ifdef SFUD_USING_QSPI
263     flash->spi.qspi_read = qspi_read;
264 #endif
265     flash->spi.lock = spi_lock;
266     flash->spi.unlock = spi_unlock;
267     flash->spi.user_data = flash;
268     if (RT_TICK_PER_SECOND < 1000) {
269         LOG_W("[SFUD] Warning: The OS tick(%d) is less than 1000. So the flash write will take more time.", RT_TICK_PER_SECOND);
270     }
271     /* 100 microsecond delay */
272     flash->retry.delay = retry_delay_100us;
273     /* 60 seconds timeout */
274     flash->retry.times = 60 * 10000;
275 
276     return result;
277 }
278 
279 #ifdef RT_USING_DEVICE_OPS
280 const static struct rt_device_ops flash_device_ops =
281 {
282     RT_NULL,
283     RT_NULL,
284     RT_NULL,
285     rt_sfud_read,
286     rt_sfud_write,
287     rt_sfud_control
288 };
289 #endif
290 
291 /**
292  * Probe SPI flash by SFUD (Serial Flash Universal Driver) driver library and though SPI device by specified configuration.
293  *
294  * @param spi_flash_dev_name the name which will create SPI flash device
295  * @param spi_dev_name using SPI device name
296  * @param spi_cfg SPI device configuration
297  * @param qspi_cfg QSPI device configuration
298  *
299  * @return probed SPI flash device, probe failed will return RT_NULL
300  */
rt_sfud_flash_probe_ex(const char * spi_flash_dev_name,const char * spi_dev_name,struct rt_spi_configuration * spi_cfg,struct rt_qspi_configuration * qspi_cfg)301 rt_spi_flash_device_t rt_sfud_flash_probe_ex(const char *spi_flash_dev_name, const char *spi_dev_name,
302         struct rt_spi_configuration *spi_cfg, struct rt_qspi_configuration *qspi_cfg)
303 {
304     rt_spi_flash_device_t rtt_dev = RT_NULL;
305     sfud_flash *sfud_dev = RT_NULL;
306     char *spi_flash_dev_name_bak = RT_NULL, *spi_dev_name_bak = RT_NULL;
307     extern sfud_err sfud_device_init(sfud_flash *flash);
308 #ifdef SFUD_USING_QSPI
309     struct rt_qspi_device *qspi_dev = RT_NULL;
310 #endif
311 
312     RT_ASSERT(spi_flash_dev_name);
313     RT_ASSERT(spi_dev_name);
314 
315     rtt_dev = (rt_spi_flash_device_t) rt_malloc(sizeof(struct spi_flash_device));
316     sfud_dev = (sfud_flash_t) rt_malloc(sizeof(sfud_flash));
317     spi_flash_dev_name_bak = (char *) rt_malloc(rt_strlen(spi_flash_dev_name) + 1);
318     spi_dev_name_bak = (char *) rt_malloc(rt_strlen(spi_dev_name) + 1);
319 
320     if (rtt_dev) {
321         rt_memset(rtt_dev, 0, sizeof(struct spi_flash_device));
322         /* initialize lock */
323         rt_mutex_init(&(rtt_dev->lock), spi_flash_dev_name, RT_IPC_FLAG_PRIO);
324     }
325 
326     if (rtt_dev && sfud_dev && spi_flash_dev_name_bak && spi_dev_name_bak) {
327         rt_memset(sfud_dev, 0, sizeof(sfud_flash));
328         rt_strncpy(spi_flash_dev_name_bak, spi_flash_dev_name, rt_strlen(spi_flash_dev_name));
329         rt_strncpy(spi_dev_name_bak, spi_dev_name, rt_strlen(spi_dev_name));
330         /* make string end sign */
331         spi_flash_dev_name_bak[rt_strlen(spi_flash_dev_name)] = '\0';
332         spi_dev_name_bak[rt_strlen(spi_dev_name)] = '\0';
333         /* SPI configure */
334         {
335             /* RT-Thread SPI device initialize */
336             rtt_dev->rt_spi_device = (struct rt_spi_device *) rt_device_find(spi_dev_name);
337             if (rtt_dev->rt_spi_device == RT_NULL || rtt_dev->rt_spi_device->parent.type != RT_Device_Class_SPIDevice) {
338                 LOG_E("ERROR: SPI device %s not found!", spi_dev_name);
339                 goto error;
340             }
341             sfud_dev->spi.name = spi_dev_name_bak;
342 
343 #ifdef SFUD_USING_QSPI
344             /* set the qspi line number and configure the QSPI bus */
345             if(rtt_dev->rt_spi_device->bus->mode &RT_SPI_BUS_MODE_QSPI) {
346                 qspi_dev = (struct rt_qspi_device *)rtt_dev->rt_spi_device;
347                 qspi_cfg->qspi_dl_width = qspi_dev->config.qspi_dl_width;
348                 rt_qspi_configure(qspi_dev, qspi_cfg);
349             }
350             else
351 #endif
352                 rt_spi_configure(rtt_dev->rt_spi_device, spi_cfg);
353         }
354         /* SFUD flash device initialize */
355         {
356             sfud_dev->name = spi_flash_dev_name_bak;
357             /* accessed each other */
358             rtt_dev->user_data = sfud_dev;
359             rtt_dev->rt_spi_device->user_data = rtt_dev;
360             rtt_dev->flash_device.user_data = rtt_dev;
361             sfud_dev->user_data = rtt_dev;
362             /* initialize SFUD device */
363             if (sfud_device_init(sfud_dev) != SFUD_SUCCESS) {
364                 LOG_E("ERROR: SPI flash probe failed by SPI device %s.", spi_dev_name);
365                 goto error;
366             }
367             /* when initialize success, then copy SFUD flash device's geometry to RT-Thread SPI flash device */
368             rtt_dev->geometry.sector_count = sfud_dev->chip.capacity / sfud_dev->chip.erase_gran;
369             rtt_dev->geometry.bytes_per_sector = sfud_dev->chip.erase_gran;
370             rtt_dev->geometry.block_size = sfud_dev->chip.erase_gran;
371 #ifdef SFUD_USING_QSPI
372             /* reconfigure the QSPI bus for medium size */
373             if(rtt_dev->rt_spi_device->bus->mode &RT_SPI_BUS_MODE_QSPI) {
374                 qspi_cfg->medium_size = sfud_dev->chip.capacity;
375                 rt_qspi_configure(qspi_dev, qspi_cfg);
376                 if(qspi_dev->enter_qspi_mode != RT_NULL)
377                     qspi_dev->enter_qspi_mode(qspi_dev);
378 
379                 /* set data lines width */
380                 sfud_qspi_fast_read_enable(sfud_dev, qspi_dev->config.qspi_dl_width);
381             }
382 #endif /* SFUD_USING_QSPI */
383         }
384 
385         /* register device */
386         rtt_dev->flash_device.type = RT_Device_Class_Block;
387 #ifdef RT_USING_DEVICE_OPS
388         rtt_dev->flash_device.ops  = &flash_device_ops;
389 #else
390         rtt_dev->flash_device.init = RT_NULL;
391         rtt_dev->flash_device.open = RT_NULL;
392         rtt_dev->flash_device.close = RT_NULL;
393         rtt_dev->flash_device.read = rt_sfud_read;
394         rtt_dev->flash_device.write = rt_sfud_write;
395         rtt_dev->flash_device.control = rt_sfud_control;
396 #endif
397 
398         rt_device_register(&(rtt_dev->flash_device), spi_flash_dev_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
399 
400         LOG_I("Probe SPI flash %s by SPI device %s success.",spi_flash_dev_name, spi_dev_name);
401         return rtt_dev;
402     } else {
403         LOG_E("ERROR: Low memory.");
404         goto error;
405     }
406 
407 error:
408 
409     if (rtt_dev) {
410         rt_mutex_detach(&(rtt_dev->lock));
411     }
412     /* may be one of objects memory was malloc success, so need free all */
413     rt_free(rtt_dev);
414     rt_free(sfud_dev);
415     rt_free(spi_flash_dev_name_bak);
416     rt_free(spi_dev_name_bak);
417 
418     return RT_NULL;
419 }
420 
421 /**
422  * Probe SPI flash by SFUD(Serial Flash Universal Driver) driver library and though SPI device.
423  *
424  * @param spi_flash_dev_name the name which will create SPI flash device
425  * @param spi_dev_name using SPI device name
426  *
427  * @return probed SPI flash device, probe failed will return RT_NULL
428  */
rt_sfud_flash_probe(const char * spi_flash_dev_name,const char * spi_dev_name)429 rt_spi_flash_device_t rt_sfud_flash_probe(const char *spi_flash_dev_name, const char *spi_dev_name)
430 {
431     struct rt_spi_configuration cfg = RT_SFUD_DEFAULT_SPI_CFG;
432 #ifndef SFUD_USING_QSPI
433     return rt_sfud_flash_probe_ex(spi_flash_dev_name, spi_dev_name, &cfg, RT_NULL);
434 #else
435     struct rt_qspi_configuration qspi_cfg = RT_SFUD_DEFAULT_QSPI_CFG;
436 
437     return rt_sfud_flash_probe_ex(spi_flash_dev_name, spi_dev_name, &cfg, &qspi_cfg);
438 #endif
439 }
440 
441 /**
442  * Delete SPI flash device
443  *
444  * @param spi_flash_dev SPI flash device
445  *
446  * @return the operation status, RT_EOK on successful
447  */
rt_sfud_flash_delete(rt_spi_flash_device_t spi_flash_dev)448 rt_err_t rt_sfud_flash_delete(rt_spi_flash_device_t spi_flash_dev) {
449     sfud_flash *sfud_flash_dev = (sfud_flash *) (spi_flash_dev->user_data);
450 
451     RT_ASSERT(spi_flash_dev);
452     RT_ASSERT(sfud_flash_dev);
453 
454     rt_device_unregister(&(spi_flash_dev->flash_device));
455 
456     rt_mutex_detach(&(spi_flash_dev->lock));
457 
458     rt_free(sfud_flash_dev->spi.name);
459     rt_free(sfud_flash_dev->name);
460     rt_free(sfud_flash_dev);
461     rt_free(spi_flash_dev);
462 
463     return RT_EOK;
464 }
465 
rt_sfud_flash_find(const char * spi_dev_name)466 sfud_flash_t rt_sfud_flash_find(const char *spi_dev_name)
467 {
468     rt_spi_flash_device_t  rtt_dev       = RT_NULL;
469     struct rt_spi_device  *rt_spi_device = RT_NULL;
470     sfud_flash_t           sfud_dev      = RT_NULL;
471 
472     rt_spi_device = (struct rt_spi_device *) rt_device_find(spi_dev_name);
473     if (rt_spi_device == RT_NULL || rt_spi_device->parent.type != RT_Device_Class_SPIDevice) {
474         LOG_E("ERROR: SPI device %s not found!", spi_dev_name);
475         goto __error;
476     }
477 
478     rtt_dev = (rt_spi_flash_device_t) (rt_spi_device->user_data);
479     if (rtt_dev && rtt_dev->user_data) {
480         sfud_dev = (sfud_flash_t) (rtt_dev->user_data);
481         return sfud_dev;
482     } else {
483         LOG_E("ERROR: SFUD flash device not found!");
484         goto __error;
485     }
486 
487 __error:
488     return RT_NULL;
489 }
490 
rt_sfud_flash_find_by_dev_name(const char * flash_dev_name)491 sfud_flash_t rt_sfud_flash_find_by_dev_name(const char *flash_dev_name)
492 {
493     rt_spi_flash_device_t  rtt_dev       = RT_NULL;
494     sfud_flash_t           sfud_dev      = RT_NULL;
495 
496     rtt_dev = (rt_spi_flash_device_t) rt_device_find(flash_dev_name);
497     if (rtt_dev == RT_NULL || rtt_dev->flash_device.type != RT_Device_Class_Block) {
498         LOG_E("ERROR: Flash device %s not found!", flash_dev_name);
499         goto __error;
500     }
501 
502     if (rtt_dev->user_data) {
503         sfud_dev = (sfud_flash_t) (rtt_dev->user_data);
504         return sfud_dev;
505     } else {
506         LOG_E("ERROR: SFUD flash device not found!");
507         goto __error;
508     }
509 
510 __error:
511     return RT_NULL;
512 }
513 
514 #if defined(RT_USING_FINSH)
515 
516 #include <finsh.h>
517 
sf(uint8_t argc,char ** argv)518 static void sf(uint8_t argc, char **argv) {
519 
520 #define __is_print(ch)                ((unsigned int)((ch) - ' ') < 127u - ' ')
521 #define HEXDUMP_WIDTH                 16
522 #define CMD_PROBE_INDEX               0
523 #define CMD_READ_INDEX                1
524 #define CMD_WRITE_INDEX               2
525 #define CMD_ERASE_INDEX               3
526 #define CMD_RW_STATUS_INDEX           4
527 #define CMD_BENCH_INDEX               5
528 
529     sfud_err result = SFUD_SUCCESS;
530     static const sfud_flash *sfud_dev = NULL;
531     static rt_spi_flash_device_t rtt_dev = NULL, rtt_dev_bak = NULL;
532     size_t i = 0, j = 0;
533 
534     const char* sf_help_info[] = {
535             [CMD_PROBE_INDEX]     = "sf probe [spi_device]           - probe and init SPI flash by given 'spi_device'",
536             [CMD_READ_INDEX]      = "sf read addr size               - read 'size' bytes starting at 'addr'",
537             [CMD_WRITE_INDEX]     = "sf write addr data1 ... dataN   - write some bytes 'data' to flash starting at 'addr'",
538             [CMD_ERASE_INDEX]     = "sf erase addr size              - erase 'size' bytes starting at 'addr'",
539             [CMD_RW_STATUS_INDEX] = "sf status [<volatile> <status>] - read or write '1:volatile|0:non-volatile' 'status'",
540             [CMD_BENCH_INDEX]     = "sf bench                        - full chip benchmark. DANGER: It will erase full chip!",
541     };
542 
543     if (argc < 2) {
544         rt_kprintf("Usage:\n");
545         for (i = 0; i < sizeof(sf_help_info) / sizeof(char*); i++) {
546             rt_kprintf("%s\n", sf_help_info[i]);
547         }
548         rt_kprintf("\n");
549     } else {
550         const char *operator = argv[1];
551         uint32_t addr, size;
552 
553         if (!strcmp(operator, "probe")) {
554             if (argc < 3) {
555                 rt_kprintf("Usage: %s.\n", sf_help_info[CMD_PROBE_INDEX]);
556             } else {
557                 char *spi_dev_name = argv[2];
558                 rtt_dev_bak = rtt_dev;
559 
560                 /* delete the old SPI flash device */
561                 if(rtt_dev_bak) {
562                     rt_sfud_flash_delete(rtt_dev_bak);
563                 }
564 
565                 rtt_dev = rt_sfud_flash_probe("sf_cmd", spi_dev_name);
566                 if (!rtt_dev) {
567                     return;
568                 }
569 
570                 sfud_dev = (sfud_flash_t)rtt_dev->user_data;
571                 if (sfud_dev->chip.capacity < 1024 * 1024) {
572                     rt_kprintf("%d KB %s is current selected device.\n", sfud_dev->chip.capacity / 1024, sfud_dev->name);
573                 } else {
574                     rt_kprintf("%d MB %s is current selected device.\n", sfud_dev->chip.capacity / 1024 / 1024,
575                             sfud_dev->name);
576                 }
577             }
578         } else {
579             if (!sfud_dev) {
580                 rt_kprintf("No flash device selected. Please run 'sf probe'.\n");
581                 return;
582             }
583             if (!rt_strcmp(operator, "read")) {
584                 if (argc < 4) {
585                     rt_kprintf("Usage: %s.\n", sf_help_info[CMD_READ_INDEX]);
586                     return;
587                 } else {
588                     addr = strtol(argv[2], NULL, 0);
589                     size = strtol(argv[3], NULL, 0);
590                     uint8_t *data = rt_malloc(size);
591                     if (data) {
592                         result = sfud_read(sfud_dev, addr, size, data);
593                         if (result == SFUD_SUCCESS) {
594                             rt_kprintf("Read the %s flash data success. Start from 0x%08X, size is %ld. The data is:\n",
595                                     sfud_dev->name, addr, size);
596                             rt_kprintf("Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
597                             for (i = 0; i < size; i += HEXDUMP_WIDTH)
598                             {
599                                 rt_kprintf("[%08X] ", addr + i);
600                                 /* dump hex */
601                                 for (j = 0; j < HEXDUMP_WIDTH; j++) {
602                                     if (i + j < size) {
603                                         rt_kprintf("%02X ", data[i + j]);
604                                     } else {
605                                         rt_kprintf("   ");
606                                     }
607                                 }
608                                 /* dump char for hex */
609                                 for (j = 0; j < HEXDUMP_WIDTH; j++) {
610                                     if (i + j < size) {
611                                         rt_kprintf("%c", __is_print(data[i + j]) ? data[i + j] : '.');
612                                     }
613                                 }
614                                 rt_kprintf("\n");
615                             }
616                             rt_kprintf("\n");
617                         }
618                         rt_free(data);
619                     } else {
620                         rt_kprintf("Low memory!\n");
621                     }
622                 }
623             } else if (!rt_strcmp(operator, "write")) {
624                 if (argc < 4) {
625                     rt_kprintf("Usage: %s.\n", sf_help_info[CMD_WRITE_INDEX]);
626                     return;
627                 } else {
628                     addr = strtol(argv[2], NULL, 0);
629                     size = argc - 3;
630                     uint8_t *data = rt_malloc(size);
631                     if (data) {
632                         for (i = 0; i < size; i++) {
633                             data[i] = strtol(argv[3 + i], NULL, 0);
634                         }
635                         result = sfud_write(sfud_dev, addr, size, data);
636                         if (result == SFUD_SUCCESS) {
637                             rt_kprintf("Write the %s flash data success. Start from 0x%08X, size is %ld.\n",
638                                     sfud_dev->name, addr, size);
639                             rt_kprintf("Write data: ");
640                             for (i = 0; i < size; i++) {
641                                 rt_kprintf("%d ", data[i]);
642                             }
643                             rt_kprintf(".\n");
644                         }
645                         rt_free(data);
646                     } else {
647                         rt_kprintf("Low memory!\n");
648                     }
649                 }
650             } else if (!rt_strcmp(operator, "erase")) {
651                 if (argc < 4) {
652                     rt_kprintf("Usage: %s.\n", sf_help_info[CMD_ERASE_INDEX]);
653                     return;
654                 } else {
655                     addr = strtol(argv[2], NULL, 0);
656                     size = strtol(argv[3], NULL, 0);
657                     result = sfud_erase(sfud_dev, addr, size);
658                     if (result == SFUD_SUCCESS) {
659                         rt_kprintf("Erase the %s flash data success. Start from 0x%08X, size is %ld.\n", sfud_dev->name,
660                                 addr, size);
661                     }
662                 }
663             } else if (!rt_strcmp(operator, "status")) {
664                 if (argc < 3) {
665                     uint8_t status;
666                     result = sfud_read_status(sfud_dev, &status);
667                     if (result == SFUD_SUCCESS) {
668                         rt_kprintf("The %s flash status register current value is 0x%02X.\n", sfud_dev->name, status);
669                     }
670                 } else if (argc == 4) {
671                     bool is_volatile = strtol(argv[2], NULL, 0);
672                     uint8_t status = strtol(argv[3], NULL, 0);
673                     result = sfud_write_status(sfud_dev, is_volatile, status);
674                     if (result == SFUD_SUCCESS) {
675                         rt_kprintf("Write the %s flash status register to 0x%02X success.\n", sfud_dev->name, status);
676                     }
677                 } else {
678                     rt_kprintf("Usage: %s.\n", sf_help_info[CMD_RW_STATUS_INDEX]);
679                     return;
680                 }
681             } else if (!rt_strcmp(operator, "bench")) {
682                 if ((argc > 2 && rt_strcmp(argv[2], "yes")) || argc < 3) {
683                     rt_kprintf("DANGER: It will erase full chip! Please run 'sf bench yes'.\n");
684                     return;
685                 }
686                 /* full chip benchmark test */
687                 addr = 0;
688                 size = sfud_dev->chip.capacity;
689                 uint32_t start_time, time_cast;
690                 size_t write_size = SFUD_WRITE_MAX_PAGE_SIZE, read_size = SFUD_WRITE_MAX_PAGE_SIZE, cur_op_size;
691                 uint8_t *write_data = rt_malloc(write_size), *read_data = rt_malloc(read_size);
692 
693                 if (write_data && read_data) {
694                     for (i = 0; i < write_size; i ++) {
695                         write_data[i] = i & 0xFF;
696                     }
697                     /* benchmark testing */
698                     rt_kprintf("Erasing the %s %ld bytes data, waiting...\n", sfud_dev->name, size);
699                     start_time = rt_tick_get();
700                     result = sfud_erase(sfud_dev, addr, size);
701                     if (result == SFUD_SUCCESS) {
702                         time_cast = rt_tick_get() - start_time;
703                         rt_kprintf("Erase benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
704                                 time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
705                     } else {
706                         rt_kprintf("Erase benchmark has an error. Error code: %d.\n", result);
707                     }
708                     /* write test */
709                     rt_kprintf("Writing the %s %ld bytes data, waiting...\n", sfud_dev->name, size);
710                     start_time = rt_tick_get();
711                     for (i = 0; i < size; i += write_size) {
712                         if (i + write_size <= size) {
713                             cur_op_size = write_size;
714                         } else {
715                             cur_op_size = size - i;
716                         }
717                         result = sfud_write(sfud_dev, addr + i, cur_op_size, write_data);
718                         if (result != SFUD_SUCCESS) {
719                             rt_kprintf("Writing %s failed, already wr for %lu bytes, write %d each time\n", sfud_dev->name, i, write_size);
720                             break;
721                         }
722                     }
723                     if (result == SFUD_SUCCESS) {
724                         time_cast = rt_tick_get() - start_time;
725                         rt_kprintf("Write benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
726                                 time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
727                     } else {
728                         rt_kprintf("Write benchmark has an error. Error code: %d.\n", result);
729                     }
730                     /* read test */
731                     rt_kprintf("Reading the %s %ld bytes data, waiting...\n", sfud_dev->name, size);
732                     start_time = rt_tick_get();
733                     for (i = 0; i < size; i += read_size) {
734                         if (i + read_size <= size) {
735                             cur_op_size = read_size;
736                         } else {
737                             cur_op_size = size - i;
738                         }
739                         result = sfud_read(sfud_dev, addr + i, cur_op_size, read_data);
740                         /* data check */
741                         if (memcmp(write_data, read_data, cur_op_size))
742                         {
743                             rt_kprintf("Data check ERROR! Please check you flash by other command.\n");
744                             result = SFUD_ERR_READ;
745                         }
746 
747                         if (result != SFUD_SUCCESS) {
748                             rt_kprintf("Read %s failed, already rd for %lu bytes, read %d each time\n", sfud_dev->name, i, read_size);
749                             break;
750                         }
751                     }
752                     if (result == SFUD_SUCCESS) {
753                         time_cast = rt_tick_get() - start_time;
754                         rt_kprintf("Read benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
755                                 time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
756                     } else {
757                         rt_kprintf("Read benchmark has an error. Error code: %d.\n", result);
758                     }
759                 } else {
760                     rt_kprintf("Low memory!\n");
761                 }
762                 rt_free(write_data);
763                 rt_free(read_data);
764             } else {
765                 rt_kprintf("Usage:\n");
766                 for (i = 0; i < sizeof(sf_help_info) / sizeof(char*); i++) {
767                     rt_kprintf("%s\n", sf_help_info[i]);
768                 }
769                 rt_kprintf("\n");
770                 return;
771             }
772             if (result != SFUD_SUCCESS) {
773                 rt_kprintf("This flash operate has an error. Error code: %d.\n", result);
774             }
775         }
776     }
777 }
778 MSH_CMD_EXPORT(sf, SPI Flash operate.);
779 #endif /* defined(RT_USING_FINSH) */
780 
781 #endif /* RT_USING_SFUD */
782