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