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