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