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