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