1 /*
2 * Copyright (c) 2017-2023 Nordic Semiconductor ASA
3 * Copyright (c) 2018 Intel Corporation
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <stdbool.h>
9 #include <stddef.h>
10 #include <stdint.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14 #include <zephyr/kernel.h>
15 #include <zephyr/devicetree.h>
16 #include <zephyr/drivers/flash.h>
17 #include <zephyr/shell/shell.h>
18 #include <zephyr/sys/util.h>
19
20 /* Buffer is only needed for bytes that follow command and offset */
21 #define BUF_ARRAY_CNT (CONFIG_SHELL_ARGC_MAX - 2)
22
23 #define FLASH_LOAD_BUF_MAX 256
24
25 static const struct device *flash_load_dev;
26 static uint32_t flash_load_buf_size;
27 static uint32_t flash_load_addr;
28 static uint32_t flash_load_total;
29 static uint32_t flash_load_written;
30 static uint32_t flash_load_chunk;
31
32 static uint32_t flash_load_boff;
33 static uint8_t flash_load_buf[FLASH_LOAD_BUF_MAX];
34
35 /* This only issues compilation error when it would not be possible
36 * to extract at least one byte from command line arguments, yet
37 * it does not warrant successful writes if BUF_ARRAY_CNT
38 * is smaller than flash write alignment.
39 */
40 BUILD_ASSERT(BUF_ARRAY_CNT >= 1);
41
42 static const struct device *const zephyr_flash_controller =
43 DEVICE_DT_GET_OR_NULL(DT_CHOSEN(zephyr_flash_controller));
44
45 static uint8_t __aligned(4) test_arr[CONFIG_FLASH_SHELL_BUFFER_SIZE];
46
parse_helper(const struct shell * sh,size_t * argc,char ** argv[],const struct device ** flash_dev,uint32_t * addr)47 static int parse_helper(const struct shell *sh, size_t *argc,
48 char **argv[], const struct device * *flash_dev,
49 uint32_t *addr)
50 {
51 char *endptr;
52
53 *addr = strtoul((*argv)[1], &endptr, 16);
54
55 if (*endptr != '\0') {
56 /* flash controller from user input */
57 *flash_dev = shell_device_get_binding((*argv)[1]);
58 if (!*flash_dev) {
59 shell_error(sh, "Given flash device was not found");
60 return -ENODEV;
61 }
62 } else if (zephyr_flash_controller != NULL) {
63 /* default to zephyr,flash-controller */
64 if (!device_is_ready(zephyr_flash_controller)) {
65 shell_error(sh, "Default flash driver not ready");
66 return -ENODEV;
67 }
68 *flash_dev = zephyr_flash_controller;
69 } else {
70 /* no flash controller given, no default available */
71 shell_error(sh, "No flash device specified (required)");
72 return -ENODEV;
73 }
74
75 if (*endptr == '\0') {
76 return 0;
77 }
78 if (*argc < 3) {
79 shell_error(sh, "Missing address.");
80 return -EINVAL;
81 }
82 *addr = strtoul((*argv)[2], &endptr, 16);
83 (*argc)--;
84 (*argv)++;
85 return 0;
86 }
87
cmd_erase(const struct shell * sh,size_t argc,char * argv[])88 static int cmd_erase(const struct shell *sh, size_t argc, char *argv[])
89 {
90 int result = -ENOTSUP;
91
92 #if defined(CONFIG_FLASH_HAS_EXPLICIT_ERASE)
93 const struct device *flash_dev;
94 uint32_t page_addr;
95 uint32_t size;
96
97 result = parse_helper(sh, &argc, &argv, &flash_dev, &page_addr);
98 if (result) {
99 return result;
100 }
101 if (argc > 2) {
102 size = strtoul(argv[2], NULL, 16);
103 } else {
104 struct flash_pages_info info;
105
106 result = flash_get_page_info_by_offs(flash_dev, page_addr,
107 &info);
108
109 if (result != 0) {
110 shell_error(sh, "Could not determine page size, "
111 "code %d.", result);
112 return -EINVAL;
113 }
114
115 size = info.size;
116 }
117
118 result = flash_erase(flash_dev, page_addr, size);
119
120 if (result) {
121 shell_error(sh, "Erase Failed, code %d.", result);
122 } else {
123 shell_print(sh, "Erase success.");
124 }
125 #endif
126
127 return result;
128 }
129
cmd_write(const struct shell * sh,size_t argc,char * argv[])130 static int cmd_write(const struct shell *sh, size_t argc, char *argv[])
131 {
132 uint32_t __aligned(4) check_array[BUF_ARRAY_CNT];
133 uint32_t __aligned(4) buf_array[BUF_ARRAY_CNT];
134 const struct device *flash_dev;
135 uint32_t w_addr;
136 int ret;
137 size_t op_size;
138
139 ret = parse_helper(sh, &argc, &argv, &flash_dev, &w_addr);
140 if (ret) {
141 return ret;
142 }
143
144 if (argc <= 2) {
145 shell_error(sh, "Missing data to be written.");
146 return -EINVAL;
147 }
148
149 op_size = 0;
150
151 for (int i = 2; i < argc; i++) {
152 int j = i - 2;
153
154 buf_array[j] = strtoul(argv[i], NULL, 16);
155 check_array[j] = ~buf_array[j];
156
157 op_size += sizeof(buf_array[0]);
158 }
159
160 if (flash_write(flash_dev, w_addr, buf_array, op_size) != 0) {
161 shell_error(sh, "Write internal ERROR!");
162 return -EIO;
163 }
164
165 shell_print(sh, "Write OK.");
166
167 if (flash_read(flash_dev, w_addr, check_array, op_size) < 0) {
168 shell_print(sh, "Verification read ERROR!");
169 return -EIO;
170 }
171
172 if (memcmp(buf_array, check_array, op_size) == 0) {
173 shell_print(sh, "Verified.");
174 } else {
175 shell_error(sh, "Verification ERROR!");
176 return -EIO;
177 }
178
179 return 0;
180 }
181
cmd_copy(const struct shell * sh,size_t argc,char * argv[])182 static int cmd_copy(const struct shell *sh, size_t argc, char *argv[])
183 {
184 int ret;
185 uint32_t size = 0;
186 uint32_t src_offset = 0;
187 uint32_t dst_offset = 0;
188 const struct device *src_dev = NULL;
189 const struct device *dst_dev = NULL;
190
191 if (argc < 5) {
192 shell_error(sh, "missing parameters");
193 return -EINVAL;
194 }
195
196 src_dev = shell_device_get_binding(argv[1]);
197 dst_dev = shell_device_get_binding(argv[2]);
198 src_offset = strtoul(argv[3], NULL, 0);
199 dst_offset = strtoul(argv[4], NULL, 0);
200 /* size will be padded to write_size bytes */
201 size = strtoul(argv[5], NULL, 0);
202
203 ret = flash_copy(src_dev, src_offset, dst_dev, dst_offset, size, flash_load_buf,
204 sizeof(flash_load_buf));
205 if (ret < 0) {
206 shell_error(sh, "%s failed: %d", "flash_copy()", ret);
207 return -EIO;
208 }
209
210 shell_print(sh, "Copied %u bytes from %s:%x to %s:%x", size, argv[1], src_offset, argv[2],
211 dst_offset);
212
213 return 0;
214 }
215
cmd_read(const struct shell * sh,size_t argc,char * argv[])216 static int cmd_read(const struct shell *sh, size_t argc, char *argv[])
217 {
218 const struct device *flash_dev;
219 uint32_t addr;
220 int todo;
221 int upto;
222 int cnt;
223 int ret;
224
225 ret = parse_helper(sh, &argc, &argv, &flash_dev, &addr);
226 if (ret) {
227 return ret;
228 }
229
230 if (argc > 2) {
231 cnt = strtoul(argv[2], NULL, 16);
232 } else {
233 cnt = 1;
234 }
235
236 for (upto = 0; upto < cnt; upto += todo) {
237 uint8_t data[SHELL_HEXDUMP_BYTES_IN_LINE];
238
239 todo = MIN(cnt - upto, SHELL_HEXDUMP_BYTES_IN_LINE);
240 ret = flash_read(flash_dev, addr, data, todo);
241 if (ret != 0) {
242 shell_error(sh, "Read ERROR!");
243 return -EIO;
244 }
245 shell_hexdump_line(sh, addr, data, todo);
246 addr += todo;
247 }
248
249 shell_print(sh, "");
250
251 return 0;
252 }
253
cmd_test(const struct shell * sh,size_t argc,char * argv[])254 static int cmd_test(const struct shell *sh, size_t argc, char *argv[])
255 {
256 const struct device *flash_dev;
257 uint32_t repeat;
258 int result;
259 uint32_t addr;
260 uint32_t size;
261
262 static uint8_t __aligned(4) check_arr[CONFIG_FLASH_SHELL_BUFFER_SIZE];
263
264 result = parse_helper(sh, &argc, &argv, &flash_dev, &addr);
265 if (result) {
266 return result;
267 }
268
269 size = strtoul(argv[2], NULL, 16);
270 repeat = strtoul(argv[3], NULL, 16);
271 if (size > CONFIG_FLASH_SHELL_BUFFER_SIZE) {
272 shell_error(sh, "<size> must be at most 0x%x.",
273 CONFIG_FLASH_SHELL_BUFFER_SIZE);
274 return -EINVAL;
275 }
276
277 if (repeat == 0) {
278 repeat = 1;
279 }
280
281 for (uint32_t i = 0; i < size; i++) {
282 test_arr[i] = (uint8_t)i;
283 }
284
285 result = 0;
286
287 while (repeat--) {
288 result = flash_erase(flash_dev, addr, size);
289
290 if (result) {
291 shell_error(sh, "Erase Failed, code %d.", result);
292 break;
293 }
294
295 shell_print(sh, "Erase OK.");
296
297 result = flash_write(flash_dev, addr, test_arr, size);
298
299 if (result) {
300 shell_error(sh, "Write failed, code %d", result);
301 break;
302 }
303
304 shell_print(sh, "Write OK.");
305
306 result = flash_read(flash_dev, addr, check_arr, size);
307
308 if (result < 0) {
309 shell_print(sh, "Verification read failed, code: %d", result);
310 break;
311 }
312
313 if (memcmp(test_arr, check_arr, size) != 0) {
314 shell_error(sh, "Verification ERROR!");
315 break;
316 }
317
318 shell_print(sh, "Verified OK.");
319 }
320
321 if (result == 0) {
322 shell_print(sh, "Erase-Write-Verify test done.");
323 }
324
325 return result;
326 }
327
328 #ifdef CONFIG_FLASH_SHELL_TEST_COMMANDS
329 const static uint8_t speed_types[][4] = { "B", "KiB", "MiB", "GiB" };
330 const static uint32_t speed_divisor = 1024;
331
read_write_erase_validate(const struct shell * sh,size_t argc,char * argv[],uint32_t * size,uint32_t * repeat)332 static int read_write_erase_validate(const struct shell *sh, size_t argc, char *argv[],
333 uint32_t *size, uint32_t *repeat)
334 {
335 if (argc < 4) {
336 shell_error(sh, "Missing parameters: <device> <offset> <size> <repeat>");
337 return -EINVAL;
338 }
339
340 *size = strtoul(argv[2], NULL, 0);
341 *repeat = strtoul(argv[3], NULL, 0);
342
343 if (*size == 0 || *size > CONFIG_FLASH_SHELL_BUFFER_SIZE) {
344 shell_error(sh, "<size> must be between 0x1 and 0x%x.",
345 CONFIG_FLASH_SHELL_BUFFER_SIZE);
346 return -EINVAL;
347 }
348
349 if (*repeat == 0 || *repeat > 10) {
350 shell_error(sh, "<repeat> must be between 1 and 10.");
351 return -EINVAL;
352 }
353
354 return 0;
355 }
356
speed_output(const struct shell * sh,uint64_t total_time,double loops,double size)357 static void speed_output(const struct shell *sh, uint64_t total_time, double loops, double size)
358 {
359 double time_per_loop = (double)total_time / loops;
360 double throughput = size;
361 uint8_t speed_index = 0;
362
363 if (time_per_loop > 0) {
364 throughput /= (time_per_loop / 1000.0);
365 }
366
367 while (throughput >= (double)speed_divisor && speed_index < ARRAY_SIZE(speed_types)) {
368 throughput /= (double)speed_divisor;
369 ++speed_index;
370 }
371
372 shell_print(sh, "Total: %llums, Per loop: ~%.0fms, Speed: ~%.1f%sps",
373 total_time, time_per_loop, throughput, speed_types[speed_index]);
374 }
375
cmd_read_test(const struct shell * sh,size_t argc,char * argv[])376 static int cmd_read_test(const struct shell *sh, size_t argc, char *argv[])
377 {
378
379 const struct device *flash_dev;
380 uint32_t repeat;
381 int result;
382 uint32_t addr;
383 uint32_t size;
384 uint64_t start_time;
385 uint64_t loop_time;
386 uint64_t total_time = 0;
387 uint32_t loops = 0;
388
389 result = parse_helper(sh, &argc, &argv, &flash_dev, &addr);
390 if (result) {
391 return result;
392 }
393
394 result = read_write_erase_validate(sh, argc, argv, &size, &repeat);
395 if (result) {
396 return result;
397 }
398
399 while (repeat--) {
400 start_time = k_uptime_get();
401 result = flash_read(flash_dev, addr, test_arr, size);
402 loop_time = k_uptime_delta(&start_time);
403
404 if (result) {
405 shell_error(sh, "Read failed: %d", result);
406 break;
407 }
408
409 ++loops;
410 total_time += loop_time;
411 shell_print(sh, "Loop #%u done in %llums.", loops, loop_time);
412 }
413
414 if (result == 0) {
415 speed_output(sh, total_time, (double)loops, (double)size);
416 }
417
418 return result;
419 }
420
cmd_write_test(const struct shell * sh,size_t argc,char * argv[])421 static int cmd_write_test(const struct shell *sh, size_t argc, char *argv[])
422 {
423 const struct device *flash_dev;
424 uint32_t repeat;
425 int result;
426 uint32_t addr;
427 uint32_t size;
428 uint64_t start_time;
429 uint64_t loop_time;
430 uint64_t total_time = 0;
431 uint32_t loops = 0;
432
433 result = parse_helper(sh, &argc, &argv, &flash_dev, &addr);
434 if (result) {
435 return result;
436 }
437
438 result = read_write_erase_validate(sh, argc, argv, &size, &repeat);
439 if (result) {
440 return result;
441 }
442
443 for (uint32_t i = 0; i < size; i++) {
444 test_arr[i] = (uint8_t)i;
445 }
446
447 while (repeat--) {
448 start_time = k_uptime_get();
449 result = flash_write(flash_dev, addr, test_arr, size);
450 loop_time = k_uptime_delta(&start_time);
451
452 if (result) {
453 shell_error(sh, "Write failed: %d", result);
454 break;
455 }
456
457 ++loops;
458 total_time += loop_time;
459 shell_print(sh, "Loop #%u done in %llu ticks.", loops, loop_time);
460 }
461
462 if (result == 0) {
463 speed_output(sh, total_time, (double)loops, (double)size);
464 }
465
466 return result;
467 }
468
cmd_erase_test(const struct shell * sh,size_t argc,char * argv[])469 static int cmd_erase_test(const struct shell *sh, size_t argc, char *argv[])
470 {
471 const struct device *flash_dev;
472 uint32_t repeat;
473 int result;
474 uint32_t addr;
475 uint32_t size;
476 uint64_t start_time;
477 uint64_t loop_time;
478 uint64_t total_time = 0;
479 uint32_t loops = 0;
480
481 result = parse_helper(sh, &argc, &argv, &flash_dev, &addr);
482 if (result) {
483 return result;
484 }
485
486 result = read_write_erase_validate(sh, argc, argv, &size, &repeat);
487 if (result) {
488 return result;
489 }
490
491 for (uint32_t i = 0; i < size; i++) {
492 test_arr[i] = (uint8_t)i;
493 }
494
495 while (repeat--) {
496 start_time = k_uptime_get();
497 result = flash_erase(flash_dev, addr, size);
498 loop_time = k_uptime_delta(&start_time);
499
500 if (result) {
501 shell_error(sh, "Erase failed: %d", result);
502 break;
503 }
504
505 ++loops;
506 total_time += loop_time;
507 shell_print(sh, "Loop #%u done in %llums.", loops, loop_time);
508 }
509
510 if (result == 0) {
511 speed_output(sh, total_time, (double)loops, (double)size);
512 }
513
514 return result;
515 }
516
cmd_erase_write_test(const struct shell * sh,size_t argc,char * argv[])517 static int cmd_erase_write_test(const struct shell *sh, size_t argc, char *argv[])
518 {
519 const struct device *flash_dev;
520 uint32_t repeat;
521 int result_erase = 0;
522 int result_write = 0;
523 uint32_t addr;
524 uint32_t size;
525 uint64_t start_time;
526 uint64_t loop_time;
527 uint64_t total_time = 0;
528 uint32_t loops = 0;
529
530 result_erase = parse_helper(sh, &argc, &argv, &flash_dev, &addr);
531 if (result_erase) {
532 return result_erase;
533 }
534
535 result_erase = read_write_erase_validate(sh, argc, argv, &size, &repeat);
536 if (result_erase) {
537 return result_erase;
538 }
539
540 for (uint32_t i = 0; i < size; i++) {
541 test_arr[i] = (uint8_t)i;
542 }
543
544 while (repeat--) {
545 start_time = k_uptime_get();
546 result_erase = flash_erase(flash_dev, addr, size);
547 result_write = flash_write(flash_dev, addr, test_arr, size);
548 loop_time = k_uptime_delta(&start_time);
549
550 if (result_erase) {
551 shell_error(sh, "Erase failed: %d", result_erase);
552 break;
553 }
554
555 if (result_write) {
556 shell_error(sh, "Write failed: %d", result_write);
557 break;
558 }
559
560 ++loops;
561 total_time += loop_time;
562 shell_print(sh, "Loop #%u done in %llums.", loops, loop_time);
563 }
564
565 if (result_erase == 0 && result_write == 0) {
566 speed_output(sh, total_time, (double)loops, (double)size);
567 }
568
569 return (result_erase != 0 ? result_erase : result_write);
570 }
571 #endif
572
set_bypass(const struct shell * sh,shell_bypass_cb_t bypass)573 static int set_bypass(const struct shell *sh, shell_bypass_cb_t bypass)
574 {
575 static bool in_use;
576
577 if (bypass && in_use) {
578 shell_error(sh, "flash load supports setting bypass on a single instance.");
579
580 return -EBUSY;
581 }
582
583 /* Mark that we have set or unset the bypass function */
584 in_use = bypass != NULL;
585
586 if (in_use) {
587 shell_print(sh, "Loading...");
588 }
589
590 shell_set_bypass(sh, bypass);
591
592 return 0;
593 }
594
bypass_cb(const struct shell * sh,uint8_t * recv,size_t len)595 static void bypass_cb(const struct shell *sh, uint8_t *recv, size_t len)
596 {
597 uint32_t left_to_read = flash_load_total - flash_load_written - flash_load_boff;
598 uint32_t to_copy = MIN(len, left_to_read);
599 uint32_t copied = 0;
600
601 while (copied < to_copy) {
602
603 uint32_t buf_copy = MIN(to_copy, flash_load_buf_size - flash_load_boff);
604
605 memcpy(flash_load_buf + flash_load_boff, recv + copied, buf_copy);
606
607 flash_load_boff += buf_copy;
608 copied += buf_copy;
609
610 /* Buffer is full. Write data to memory. */
611 if (flash_load_boff == flash_load_buf_size) {
612 uint32_t addr = flash_load_addr + flash_load_written;
613 int rc = flash_write(flash_load_dev, addr, flash_load_buf,
614 flash_load_buf_size);
615
616 if (rc != 0) {
617 shell_error(sh, "Write to addr %x on dev %p ERROR!",
618 addr, flash_load_dev);
619 }
620
621 shell_print(sh, "Written chunk %d", flash_load_chunk);
622
623 flash_load_written += flash_load_buf_size;
624 flash_load_chunk++;
625 flash_load_boff = 0;
626 }
627 }
628
629 /* When data is not aligned to flash_load_buf_size there may be partial write
630 * at the end.
631 */
632 if (flash_load_written < flash_load_total &&
633 flash_load_written + flash_load_boff >= flash_load_total) {
634
635 uint32_t addr = flash_load_addr + flash_load_written;
636 int rc = flash_write(flash_load_dev, addr, flash_load_buf, flash_load_boff);
637
638 if (rc != 0) {
639 set_bypass(sh, NULL);
640 shell_error(sh, "Write to addr %x on dev %p ERROR!",
641 addr, flash_load_dev);
642 return;
643 }
644
645 shell_print(sh, "Written chunk %d", flash_load_chunk);
646 flash_load_written += flash_load_boff;
647 flash_load_chunk++;
648 }
649
650 if (flash_load_written >= flash_load_total) {
651 set_bypass(sh, NULL);
652 shell_print(sh, "Read all");
653 }
654 }
655
cmd_load(const struct shell * sh,size_t argc,char * argv[])656 static int cmd_load(const struct shell *sh, size_t argc, char *argv[])
657 {
658 const struct device *flash_dev;
659 int result;
660 uint32_t addr;
661 uint32_t size;
662 ssize_t write_block_size;
663
664 result = parse_helper(sh, &argc, &argv, &flash_dev, &addr);
665 if (result) {
666 return result;
667 }
668
669 size = strtoul(argv[2], NULL, 0);
670
671 write_block_size = flash_get_write_block_size(flash_dev);
672
673 /* Check if size is aligned */
674 if (size % write_block_size != 0) {
675 shell_error(sh, "Size must be %zu bytes aligned", write_block_size);
676 return -EIO;
677 }
678
679 /* Align buffer size to write_block_size */
680 flash_load_buf_size = FLASH_LOAD_BUF_MAX;
681
682 if (flash_load_buf_size < write_block_size) {
683 shell_error(sh, "Size of buffer is too small to be aligned to %zu.",
684 write_block_size);
685 return -ENOSPC;
686 }
687
688 /* If buffer size is not aligned then change its size. */
689 if (flash_load_buf_size % write_block_size != 0) {
690 flash_load_buf_size -= flash_load_buf_size % write_block_size;
691
692 shell_warn(sh, "Load buffer was not aligned to %zu.", write_block_size);
693 shell_warn(sh, "Effective load buffer size was set from %d to %d",
694 FLASH_LOAD_BUF_MAX, flash_load_buf_size);
695 }
696
697 /* Prepare data for callback. */
698 flash_load_dev = flash_dev;
699 flash_load_addr = addr;
700 flash_load_total = size;
701 flash_load_written = 0;
702 flash_load_boff = 0;
703 flash_load_chunk = 0;
704
705 shell_print(sh, "Send %d bytes to complete flash load command", size);
706
707 set_bypass(sh, bypass_cb);
708 return 0;
709 }
710
cmd_page_info(const struct shell * sh,size_t argc,char * argv[])711 static int cmd_page_info(const struct shell *sh, size_t argc, char *argv[])
712 {
713 const struct device *flash_dev;
714 struct flash_pages_info info;
715 int result;
716 uint32_t addr;
717
718 result = parse_helper(sh, &argc, &argv, &flash_dev, &addr);
719 if (result) {
720 return result;
721 }
722
723 result = flash_get_page_info_by_offs(flash_dev, addr, &info);
724
725 if (result != 0) {
726 shell_error(sh, "Could not determine page size, error code %d.", result);
727 return -EINVAL;
728 }
729
730 shell_print(sh, "Page for address 0x%x:\nstart offset: 0x%lx\nsize: %zu\nindex: %d",
731 addr, info.start_offset, info.size, info.index);
732 return 0;
733 }
734
735 static void device_name_get(size_t idx, struct shell_static_entry *entry);
736
737 SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get);
738
device_name_get(size_t idx,struct shell_static_entry * entry)739 static void device_name_get(size_t idx, struct shell_static_entry *entry)
740 {
741 const struct device *dev = shell_device_lookup(idx, NULL);
742
743 entry->syntax = (dev != NULL) ? dev->name : NULL;
744 entry->handler = NULL;
745 entry->help = NULL;
746 entry->subcmd = &dsub_device_name;
747 }
748
749 SHELL_STATIC_SUBCMD_SET_CREATE(flash_cmds,
750 SHELL_CMD_ARG(copy, &dsub_device_name,
751 "<src_device> <dst_device> <src_offset> <dst_offset> <size>",
752 cmd_copy, 5, 5),
753 SHELL_CMD_ARG(erase, &dsub_device_name,
754 "[<device>] <page address> [<size>]",
755 cmd_erase, 2, 2),
756 SHELL_CMD_ARG(read, &dsub_device_name,
757 "[<device>] <address> [<Dword count>]",
758 cmd_read, 2, 2),
759 SHELL_CMD_ARG(test, &dsub_device_name,
760 "[<device>] <address> <size> <repeat count>",
761 cmd_test, 4, 1),
762 SHELL_CMD_ARG(write, &dsub_device_name,
763 "[<device>] <address> <dword> [<dword>...]",
764 cmd_write, 3, BUF_ARRAY_CNT),
765 SHELL_CMD_ARG(load, &dsub_device_name,
766 "[<device>] <address> <size>",
767 cmd_load, 3, 1),
768 SHELL_CMD_ARG(page_info, &dsub_device_name,
769 "[<device>] <address>",
770 cmd_page_info, 2, 1),
771
772 #ifdef CONFIG_FLASH_SHELL_TEST_COMMANDS
773 SHELL_CMD_ARG(read_test, &dsub_device_name,
774 "[<device>] <address> <size> <repeat count>",
775 cmd_read_test, 4, 1),
776 SHELL_CMD_ARG(write_test, &dsub_device_name,
777 "[<device>] <address> <size> <repeat count>",
778 cmd_write_test, 4, 1),
779 SHELL_CMD_ARG(erase_test, &dsub_device_name,
780 "[<device>] <address> <size> <repeat count>",
781 cmd_erase_test, 4, 1),
782 SHELL_CMD_ARG(erase_write_test, &dsub_device_name,
783 "[<device>] <address> <size> <repeat count>",
784 cmd_erase_write_test, 4, 1),
785 #endif
786
787 SHELL_SUBCMD_SET_END
788 );
789
cmd_flash(const struct shell * sh,size_t argc,char ** argv)790 static int cmd_flash(const struct shell *sh, size_t argc, char **argv)
791 {
792 shell_error(sh, "%s:unknown parameter: %s", argv[0], argv[1]);
793 return -EINVAL;
794 }
795
796 SHELL_CMD_ARG_REGISTER(flash, &flash_cmds, "Flash shell commands",
797 cmd_flash, 2, 0);
798