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