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