1 // SPDX-License-Identifier:  GPL-2.0+
2 /*
3  * mtd.c
4  *
5  * Generic command to handle basic operations on any memory device.
6  *
7  * Copyright: Bootlin, 2018
8  * Author: Miquèl Raynal <miquel.raynal@bootlin.com>
9  */
10 
11 #include <command.h>
12 #include <common.h>
13 #include <console.h>
14 #include <malloc.h>
15 #include <mapmem.h>
16 #include <mtd.h>
17 #include <dm/devres.h>
18 #include <linux/err.h>
19 
20 #include <linux/ctype.h>
21 
get_mtd_by_name(const char * name)22 static struct mtd_info *get_mtd_by_name(const char *name)
23 {
24 	struct mtd_info *mtd;
25 
26 	mtd_probe_devices();
27 
28 	mtd = get_mtd_device_nm(name);
29 	if (IS_ERR_OR_NULL(mtd))
30 		printf("MTD device %s not found, ret %ld\n", name,
31 		       PTR_ERR(mtd));
32 
33 	return mtd;
34 }
35 
mtd_len_to_pages(struct mtd_info * mtd,u64 len)36 static uint mtd_len_to_pages(struct mtd_info *mtd, u64 len)
37 {
38 	do_div(len, mtd->writesize);
39 
40 	return len;
41 }
42 
mtd_is_aligned_with_min_io_size(struct mtd_info * mtd,u64 size)43 static bool mtd_is_aligned_with_min_io_size(struct mtd_info *mtd, u64 size)
44 {
45 	return !do_div(size, mtd->writesize);
46 }
47 
mtd_is_aligned_with_block_size(struct mtd_info * mtd,u64 size)48 static bool mtd_is_aligned_with_block_size(struct mtd_info *mtd, u64 size)
49 {
50 	return !do_div(size, mtd->erasesize);
51 }
52 
mtd_dump_buf(const u8 * buf,uint len,uint offset)53 static void mtd_dump_buf(const u8 *buf, uint len, uint offset)
54 {
55 	int i, j;
56 
57 	for (i = 0; i < len; ) {
58 		printf("0x%08x:\t", offset + i);
59 		for (j = 0; j < 8; j++)
60 			printf("%02x ", buf[i + j]);
61 		printf(" ");
62 		i += 8;
63 		for (j = 0; j < 8; j++)
64 			printf("%02x ", buf[i + j]);
65 		printf("\n");
66 		i += 8;
67 	}
68 }
69 
mtd_dump_device_buf(struct mtd_info * mtd,u64 start_off,const u8 * buf,u64 len,bool woob)70 static void mtd_dump_device_buf(struct mtd_info *mtd, u64 start_off,
71 				const u8 *buf, u64 len, bool woob)
72 {
73 	bool has_pages = mtd->type == MTD_NANDFLASH ||
74 		mtd->type == MTD_MLCNANDFLASH;
75 	int npages = mtd_len_to_pages(mtd, len);
76 	uint page;
77 
78 	if (has_pages) {
79 		for (page = 0; page < npages; page++) {
80 			u64 data_off = page * mtd->writesize;
81 
82 			printf("\nDump %d data bytes from 0x%08llx:\n",
83 			       mtd->writesize, start_off + data_off);
84 			mtd_dump_buf(&buf[data_off],
85 				     mtd->writesize, start_off + data_off);
86 
87 			if (woob) {
88 				u64 oob_off = page * mtd->oobsize;
89 
90 				printf("Dump %d OOB bytes from page at 0x%08llx:\n",
91 				       mtd->oobsize, start_off + data_off);
92 				mtd_dump_buf(&buf[len + oob_off],
93 					     mtd->oobsize, 0);
94 			}
95 		}
96 	} else {
97 		printf("\nDump %lld data bytes from 0x%llx:\n",
98 		       len, start_off);
99 		mtd_dump_buf(buf, len, start_off);
100 	}
101 }
102 
mtd_show_parts(struct mtd_info * mtd,int level)103 static void mtd_show_parts(struct mtd_info *mtd, int level)
104 {
105 	struct mtd_info *part;
106 	int i;
107 
108 	list_for_each_entry(part, &mtd->partitions, node) {
109 		for (i = 0; i < level; i++)
110 			printf("\t");
111 		printf("  - 0x%012llx-0x%012llx : \"%s\"\n",
112 		       part->offset, part->offset + part->size, part->name);
113 
114 		mtd_show_parts(part, level + 1);
115 	}
116 }
117 
mtd_show_device(struct mtd_info * mtd)118 static void mtd_show_device(struct mtd_info *mtd)
119 {
120 	/* Device */
121 	printf("* %s\n", mtd->name);
122 #if defined(CONFIG_DM)
123 	if (mtd->dev) {
124 		printf("  - device: %s\n", mtd->dev->name);
125 		printf("  - parent: %s\n", mtd->dev->parent->name);
126 		printf("  - driver: %s\n", mtd->dev->driver->name);
127 	}
128 #endif
129 	if (IS_ENABLED(CONFIG_OF_CONTROL) && mtd->dev) {
130 		char buf[256];
131 		int res;
132 
133 		res = ofnode_get_path(mtd_get_ofnode(mtd), buf, 256);
134 		printf("  - path: %s\n", res == 0 ? buf : "unavailable");
135 	}
136 
137 	/* MTD device information */
138 	printf("  - type: ");
139 	switch (mtd->type) {
140 	case MTD_RAM:
141 		printf("RAM\n");
142 		break;
143 	case MTD_ROM:
144 		printf("ROM\n");
145 		break;
146 	case MTD_NORFLASH:
147 		printf("NOR flash\n");
148 		break;
149 	case MTD_NANDFLASH:
150 		printf("NAND flash\n");
151 		break;
152 	case MTD_DATAFLASH:
153 		printf("Data flash\n");
154 		break;
155 	case MTD_UBIVOLUME:
156 		printf("UBI volume\n");
157 		break;
158 	case MTD_MLCNANDFLASH:
159 		printf("MLC NAND flash\n");
160 		break;
161 	case MTD_ABSENT:
162 	default:
163 		printf("Unknown\n");
164 		break;
165 	}
166 
167 	printf("  - block size: 0x%x bytes\n", mtd->erasesize);
168 	printf("  - min I/O: 0x%x bytes\n", mtd->writesize);
169 
170 	if (mtd->oobsize) {
171 		printf("  - OOB size: %u bytes\n", mtd->oobsize);
172 		printf("  - OOB available: %u bytes\n", mtd->oobavail);
173 	}
174 
175 	if (mtd->ecc_strength) {
176 		printf("  - ECC strength: %u bits\n", mtd->ecc_strength);
177 		printf("  - ECC step size: %u bytes\n", mtd->ecc_step_size);
178 		printf("  - bitflip threshold: %u bits\n",
179 		       mtd->bitflip_threshold);
180 	}
181 
182 	printf("  - 0x%012llx-0x%012llx : \"%s\"\n",
183 	       mtd->offset, mtd->offset + mtd->size, mtd->name);
184 
185 	/* MTD partitions, if any */
186 	mtd_show_parts(mtd, 1);
187 }
188 
189 /* Logic taken from fs/ubifs/recovery.c:is_empty() */
mtd_oob_write_is_empty(struct mtd_oob_ops * op)190 static bool mtd_oob_write_is_empty(struct mtd_oob_ops *op)
191 {
192 	int i;
193 
194 	for (i = 0; i < op->len; i++)
195 		if (op->datbuf[i] != 0xff)
196 			return false;
197 
198 	for (i = 0; i < op->ooblen; i++)
199 		if (op->oobbuf[i] != 0xff)
200 			return false;
201 
202 	return true;
203 }
204 
do_mtd_list(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])205 static int do_mtd_list(struct cmd_tbl *cmdtp, int flag, int argc,
206 		       char *const argv[])
207 {
208 	struct mtd_info *mtd;
209 	int dev_nb = 0;
210 
211 	/* Ensure all devices (and their partitions) are probed */
212 	mtd_probe_devices();
213 
214 	printf("List of MTD devices:\n");
215 	mtd_for_each_device(mtd) {
216 		if (!mtd_is_partition(mtd))
217 			mtd_show_device(mtd);
218 
219 		dev_nb++;
220 	}
221 
222 	if (!dev_nb) {
223 		printf("No MTD device found\n");
224 		return CMD_RET_FAILURE;
225 	}
226 
227 	return CMD_RET_SUCCESS;
228 }
229 
mtd_special_write_oob(struct mtd_info * mtd,u64 off,struct mtd_oob_ops * io_op,bool write_empty_pages,bool woob)230 static int mtd_special_write_oob(struct mtd_info *mtd, u64 off,
231 				 struct mtd_oob_ops *io_op,
232 				 bool write_empty_pages, bool woob)
233 {
234 	int ret = 0;
235 
236 	/*
237 	 * By default, do not write an empty page.
238 	 * Skip it by simulating a successful write.
239 	 */
240 	if (!write_empty_pages && mtd_oob_write_is_empty(io_op)) {
241 		io_op->retlen = mtd->writesize;
242 		io_op->oobretlen = woob ? mtd->oobsize : 0;
243 	} else {
244 		ret = mtd_write_oob(mtd, off, io_op);
245 	}
246 
247 	return ret;
248 }
249 
do_mtd_io(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])250 static int do_mtd_io(struct cmd_tbl *cmdtp, int flag, int argc,
251 		     char *const argv[])
252 {
253 	bool dump, read, raw, woob, write_empty_pages, has_pages = false;
254 	u64 start_off, off, len, remaining, default_len;
255 	struct mtd_oob_ops io_op = {};
256 	uint user_addr = 0, npages;
257 	const char *cmd = argv[0];
258 	struct mtd_info *mtd;
259 	u32 oob_len;
260 	u8 *buf;
261 	int ret;
262 
263 	if (argc < 2)
264 		return CMD_RET_USAGE;
265 
266 	mtd = get_mtd_by_name(argv[1]);
267 	if (IS_ERR_OR_NULL(mtd))
268 		return CMD_RET_FAILURE;
269 
270 	if (mtd->type == MTD_NANDFLASH || mtd->type == MTD_MLCNANDFLASH)
271 		has_pages = true;
272 
273 	dump = !strncmp(cmd, "dump", 4);
274 	read = dump || !strncmp(cmd, "read", 4);
275 	raw = strstr(cmd, ".raw");
276 	woob = strstr(cmd, ".oob");
277 	write_empty_pages = !has_pages || strstr(cmd, ".dontskipff");
278 
279 	argc -= 2;
280 	argv += 2;
281 
282 	if (!dump) {
283 		if (!argc) {
284 			ret = CMD_RET_USAGE;
285 			goto out_put_mtd;
286 		}
287 
288 		user_addr = hextoul(argv[0], NULL);
289 		argc--;
290 		argv++;
291 	}
292 
293 	start_off = argc > 0 ? hextoul(argv[0], NULL) : 0;
294 	if (!mtd_is_aligned_with_min_io_size(mtd, start_off)) {
295 		printf("Offset not aligned with a page (0x%x)\n",
296 		       mtd->writesize);
297 		ret = CMD_RET_FAILURE;
298 		goto out_put_mtd;
299 	}
300 
301 	default_len = dump ? mtd->writesize : mtd->size;
302 	len = argc > 1 ? hextoul(argv[1], NULL) : default_len;
303 	if (!mtd_is_aligned_with_min_io_size(mtd, len)) {
304 		len = round_up(len, mtd->writesize);
305 		printf("Size not on a page boundary (0x%x), rounding to 0x%llx\n",
306 		       mtd->writesize, len);
307 	}
308 
309 	remaining = len;
310 	npages = mtd_len_to_pages(mtd, len);
311 	oob_len = woob ? npages * mtd->oobsize : 0;
312 
313 	if (dump)
314 		buf = kmalloc(len + oob_len, GFP_KERNEL);
315 	else
316 		buf = map_sysmem(user_addr, 0);
317 
318 	if (!buf) {
319 		printf("Could not map/allocate the user buffer\n");
320 		ret = CMD_RET_FAILURE;
321 		goto out_put_mtd;
322 	}
323 
324 	if (has_pages)
325 		printf("%s %lld byte(s) (%d page(s)) at offset 0x%08llx%s%s%s\n",
326 		       read ? "Reading" : "Writing", len, npages, start_off,
327 		       raw ? " [raw]" : "", woob ? " [oob]" : "",
328 		       !read && write_empty_pages ? " [dontskipff]" : "");
329 	else
330 		printf("%s %lld byte(s) at offset 0x%08llx\n",
331 		       read ? "Reading" : "Writing", len, start_off);
332 
333 	io_op.mode = raw ? MTD_OPS_RAW : MTD_OPS_AUTO_OOB;
334 	io_op.len = has_pages ? mtd->writesize : len;
335 	io_op.ooblen = woob ? mtd->oobsize : 0;
336 	io_op.datbuf = buf;
337 	io_op.oobbuf = woob ? &buf[len] : NULL;
338 
339 	/* Search for the first good block after the given offset */
340 	off = start_off;
341 	while (mtd_block_isbad(mtd, off))
342 		off += mtd->erasesize;
343 
344 	/* Loop over the pages to do the actual read/write */
345 	while (remaining) {
346 		/* Skip the block if it is bad */
347 		if (mtd_is_aligned_with_block_size(mtd, off) &&
348 		    mtd_block_isbad(mtd, off)) {
349 			off += mtd->erasesize;
350 			continue;
351 		}
352 
353 		if (read)
354 			ret = mtd_read_oob(mtd, off, &io_op);
355 		else
356 			ret = mtd_special_write_oob(mtd, off, &io_op,
357 						    write_empty_pages, woob);
358 
359 		if (ret) {
360 			printf("Failure while %s at offset 0x%llx\n",
361 			       read ? "reading" : "writing", off);
362 			break;
363 		}
364 
365 		off += io_op.retlen;
366 		remaining -= io_op.retlen;
367 		io_op.datbuf += io_op.retlen;
368 		io_op.oobbuf += io_op.oobretlen;
369 	}
370 
371 	if (!ret && dump)
372 		mtd_dump_device_buf(mtd, start_off, buf, len, woob);
373 
374 	if (dump)
375 		kfree(buf);
376 	else
377 		unmap_sysmem(buf);
378 
379 	if (ret) {
380 		printf("%s on %s failed with error %d\n",
381 		       read ? "Read" : "Write", mtd->name, ret);
382 		ret = CMD_RET_FAILURE;
383 	} else {
384 		ret = CMD_RET_SUCCESS;
385 	}
386 
387 out_put_mtd:
388 	put_mtd_device(mtd);
389 
390 	return ret;
391 }
392 
do_mtd_erase(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])393 static int do_mtd_erase(struct cmd_tbl *cmdtp, int flag, int argc,
394 			char *const argv[])
395 {
396 	struct erase_info erase_op = {};
397 	struct mtd_info *mtd;
398 	u64 off, len;
399 	bool scrub;
400 	int ret = 0;
401 
402 	if (argc < 2)
403 		return CMD_RET_USAGE;
404 
405 	mtd = get_mtd_by_name(argv[1]);
406 	if (IS_ERR_OR_NULL(mtd))
407 		return CMD_RET_FAILURE;
408 
409 	scrub = strstr(argv[0], ".dontskipbad");
410 
411 	argc -= 2;
412 	argv += 2;
413 
414 	off = argc > 0 ? hextoul(argv[0], NULL) : 0;
415 	len = argc > 1 ? hextoul(argv[1], NULL) : mtd->size;
416 
417 	if (!mtd_is_aligned_with_block_size(mtd, off)) {
418 		printf("Offset not aligned with a block (0x%x)\n",
419 		       mtd->erasesize);
420 		ret = CMD_RET_FAILURE;
421 		goto out_put_mtd;
422 	}
423 
424 	if (!mtd_is_aligned_with_block_size(mtd, len)) {
425 		printf("Size not a multiple of a block (0x%x)\n",
426 		       mtd->erasesize);
427 		ret = CMD_RET_FAILURE;
428 		goto out_put_mtd;
429 	}
430 
431 	printf("Erasing 0x%08llx ... 0x%08llx (%d eraseblock(s))\n",
432 	       off, off + len - 1, mtd_div_by_eb(len, mtd));
433 
434 	erase_op.mtd = mtd;
435 	erase_op.addr = off;
436 	erase_op.len = mtd->erasesize;
437 	erase_op.scrub = scrub;
438 
439 	while (len) {
440 		ret = mtd_erase(mtd, &erase_op);
441 
442 		if (ret) {
443 			/* Abort if its not a bad block error */
444 			if (ret != -EIO)
445 				break;
446 			printf("Skipping bad block at 0x%08llx\n",
447 			       erase_op.addr);
448 		}
449 
450 		len -= mtd->erasesize;
451 		erase_op.addr += mtd->erasesize;
452 	}
453 
454 	if (ret && ret != -EIO)
455 		ret = CMD_RET_FAILURE;
456 	else
457 		ret = CMD_RET_SUCCESS;
458 
459 out_put_mtd:
460 	put_mtd_device(mtd);
461 
462 	return ret;
463 }
464 
do_mtd_bad(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])465 static int do_mtd_bad(struct cmd_tbl *cmdtp, int flag, int argc,
466 		      char *const argv[])
467 {
468 	struct mtd_info *mtd;
469 	loff_t off;
470 
471 	if (argc < 2)
472 		return CMD_RET_USAGE;
473 
474 	mtd = get_mtd_by_name(argv[1]);
475 	if (IS_ERR_OR_NULL(mtd))
476 		return CMD_RET_FAILURE;
477 
478 	if (!mtd_can_have_bb(mtd)) {
479 		printf("Only NAND-based devices can have bad blocks\n");
480 		goto out_put_mtd;
481 	}
482 
483 	printf("MTD device %s bad blocks list:\n", mtd->name);
484 	for (off = 0; off < mtd->size; off += mtd->erasesize) {
485 		if (mtd_block_isbad(mtd, off))
486 			printf("\t0x%08llx\n", off);
487 	}
488 
489 out_put_mtd:
490 	put_mtd_device(mtd);
491 
492 	return CMD_RET_SUCCESS;
493 }
494 
495 #ifdef CONFIG_AUTO_COMPLETE
mtd_name_complete(int argc,char * const argv[],char last_char,int maxv,char * cmdv[])496 static int mtd_name_complete(int argc, char *const argv[], char last_char,
497 			     int maxv, char *cmdv[])
498 {
499 	int len = 0, n_found = 0;
500 	struct mtd_info *mtd;
501 
502 	argc--;
503 	argv++;
504 
505 	if (argc > 1 ||
506 	    (argc == 1 && (last_char == '\0' || isblank(last_char))))
507 		return 0;
508 
509 	if (argc)
510 		len = strlen(argv[0]);
511 
512 	mtd_for_each_device(mtd) {
513 		if (argc &&
514 		    (len > strlen(mtd->name) ||
515 		     strncmp(argv[0], mtd->name, len)))
516 			continue;
517 
518 		if (n_found >= maxv - 2) {
519 			cmdv[n_found++] = "...";
520 			break;
521 		}
522 
523 		cmdv[n_found++] = mtd->name;
524 	}
525 
526 	cmdv[n_found] = NULL;
527 
528 	return n_found;
529 }
530 #endif /* CONFIG_AUTO_COMPLETE */
531 
532 #ifdef CONFIG_SYS_LONGHELP
533 static char mtd_help_text[] =
534 	"- generic operations on memory technology devices\n\n"
535 	"mtd list\n"
536 	"mtd read[.raw][.oob]                  <name> <addr> [<off> [<size>]]\n"
537 	"mtd dump[.raw][.oob]                  <name>        [<off> [<size>]]\n"
538 	"mtd write[.raw][.oob][.dontskipff]    <name> <addr> [<off> [<size>]]\n"
539 	"mtd erase[.dontskipbad]               <name>        [<off> [<size>]]\n"
540 	"\n"
541 	"Specific functions:\n"
542 	"mtd bad                               <name>\n"
543 	"\n"
544 	"With:\n"
545 	"\t<name>: NAND partition/chip name (or corresponding DM device name or OF path)\n"
546 	"\t<addr>: user address from/to which data will be retrieved/stored\n"
547 	"\t<off>: offset in <name> in bytes (default: start of the part)\n"
548 	"\t\t* must be block-aligned for erase\n"
549 	"\t\t* must be page-aligned otherwise\n"
550 	"\t<size>: length of the operation in bytes (default: the entire device)\n"
551 	"\t\t* must be a multiple of a block for erase\n"
552 	"\t\t* must be a multiple of a page otherwise (special case: default is a page with dump)\n"
553 	"\n"
554 	"The .dontskipff option forces writing empty pages, don't use it if unsure.\n";
555 #endif
556 
557 U_BOOT_CMD_WITH_SUBCMDS(mtd, "MTD utils", mtd_help_text,
558 		U_BOOT_SUBCMD_MKENT(list, 1, 1, do_mtd_list),
559 		U_BOOT_SUBCMD_MKENT_COMPLETE(read, 5, 0, do_mtd_io,
560 					     mtd_name_complete),
561 		U_BOOT_SUBCMD_MKENT_COMPLETE(write, 5, 0, do_mtd_io,
562 					     mtd_name_complete),
563 		U_BOOT_SUBCMD_MKENT_COMPLETE(dump, 4, 0, do_mtd_io,
564 					     mtd_name_complete),
565 		U_BOOT_SUBCMD_MKENT_COMPLETE(erase, 4, 0, do_mtd_erase,
566 					     mtd_name_complete),
567 		U_BOOT_SUBCMD_MKENT_COMPLETE(bad, 2, 1, do_mtd_bad,
568 					     mtd_name_complete));
569