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