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 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 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 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 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 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 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 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() */ 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 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 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 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