Commit 5db66b3aee6f2c057706d8715f7e5c472e82f047

Authored by Miquel Raynal
Committed by Jagan Teki
1 parent 2a74930da5

cmd: mtd: add 'mtd' command

There should not be a 'nand' command, a 'sf' command and certainly not
a new 'spi-nand' command. Write a 'mtd' command instead to manage all
MTD devices/partitions at once. This should be the preferred way to
access any MTD device.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Acked-by: Jagan Teki <jagan@openedev.com>
Reviewed-by: Stefan Roese <sr@denx.de>
Reviewed-by: Boris Brezillon <boris.brezillon@bootlin.com>

Showing 6 changed files with 644 additions and 4 deletions Side-by-side Diff

... ... @@ -864,6 +864,12 @@
864 864 Enable support for the "mmc swrite" command to write Android sparse
865 865 images to eMMC.
866 866  
  867 +config CMD_MTD
  868 + bool "mtd"
  869 + select MTD_PARTITIONS
  870 + help
  871 + MTD commands support.
  872 +
867 873 config CMD_NAND
868 874 bool "nand"
869 875 default y if NAND_SUNXI
870 876  
... ... @@ -1697,14 +1703,14 @@
1697 1703  
1698 1704 config MTDIDS_DEFAULT
1699 1705 string "Default MTD IDs"
1700   - depends on CMD_MTDPARTS || CMD_NAND || CMD_FLASH
  1706 + depends on CMD_MTD || CMD_MTDPARTS || CMD_NAND || CMD_FLASH
1701 1707 help
1702 1708 Defines a default MTD IDs list for use with MTD partitions in the
1703 1709 Linux MTD command line partitions format.
1704 1710  
1705 1711 config MTDPARTS_DEFAULT
1706 1712 string "Default MTD partition scheme"
1707   - depends on CMD_MTDPARTS || CMD_NAND || CMD_FLASH
  1713 + depends on CMD_MTD || CMD_MTDPARTS || CMD_NAND || CMD_FLASH
1708 1714 help
1709 1715 Defines a default MTD partitioning scheme in the Linux MTD command
1710 1716 line partitions format
... ... @@ -92,6 +92,7 @@
92 92 obj-$(CONFIG_CMD_MMC) += mmc.o
93 93 obj-$(CONFIG_CMD_MMC_SPI) += mmc_spi.o
94 94 obj-$(CONFIG_MP) += mp.o
  95 +obj-$(CONFIG_CMD_MTD) += mtd.o
95 96 obj-$(CONFIG_CMD_MTDPARTS) += mtdparts.o
96 97 obj-$(CONFIG_CMD_NAND) += nand.o
97 98 obj-$(CONFIG_CMD_NET) += net.o
  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);
drivers/mtd/Makefile
... ... @@ -3,7 +3,7 @@
3 3 # (C) Copyright 2000-2007
4 4 # Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5 5  
6   -ifneq (,$(findstring y,$(CONFIG_MTD_DEVICE)$(CONFIG_CMD_NAND)$(CONFIG_CMD_ONENAND)$(CONFIG_CMD_SF)))
  6 +ifneq (,$(findstring y,$(CONFIG_MTD_DEVICE)$(CONFIG_CMD_NAND)$(CONFIG_CMD_ONENAND)$(CONFIG_CMD_SF)$(CONFIG_CMD_MTD)))
7 7 obj-y += mtdcore.o mtd_uboot.o
8 8 endif
9 9 obj-$(CONFIG_MTD) += mtd-uclass.o
drivers/mtd/mtd_uboot.c
... ... @@ -4,9 +4,16 @@
4 4 * Heiko Schocher, DENX Software Engineering, hs@denx.de.
5 5 */
6 6 #include <common.h>
  7 +#include <dm/device.h>
  8 +#include <dm/uclass-internal.h>
  9 +#include <jffs2/jffs2.h> /* LEGACY */
7 10 #include <linux/mtd/mtd.h>
8   -#include <jffs2/jffs2.h> /* Legacy */
  11 +#include <linux/mtd/partitions.h>
  12 +#include <mtd.h>
9 13  
  14 +#define MTD_NAME_MAX_LEN 20
  15 +
  16 +
10 17 /**
11 18 * mtd_search_alternate_name - Search an alternate name for @mtdname thanks to
12 19 * the mtdids legacy environment variable.
... ... @@ -67,6 +74,158 @@
67 74  
68 75 return -EINVAL;
69 76 }
  77 +
  78 +#if IS_ENABLED(CONFIG_MTD)
  79 +static void mtd_probe_uclass_mtd_devs(void)
  80 +{
  81 + struct udevice *dev;
  82 + int idx = 0;
  83 +
  84 + /* Probe devices with DM compliant drivers */
  85 + while (!uclass_find_device(UCLASS_MTD, idx, &dev) && dev) {
  86 + mtd_probe(dev);
  87 + idx++;
  88 + }
  89 +}
  90 +#else
  91 +static void mtd_probe_uclass_mtd_devs(void) { }
  92 +#endif
  93 +
  94 +#if defined(CONFIG_MTD_PARTITIONS)
  95 +int mtd_probe_devices(void)
  96 +{
  97 + static char *old_mtdparts;
  98 + static char *old_mtdids;
  99 + const char *mtdparts = env_get("mtdparts");
  100 + const char *mtdids = env_get("mtdids");
  101 + bool remaining_partitions = true;
  102 + struct mtd_info *mtd;
  103 +
  104 + mtd_probe_uclass_mtd_devs();
  105 +
  106 + /* Check if mtdparts/mtdids changed since last call, otherwise: exit */
  107 + if (!strcmp(mtdparts, old_mtdparts) && !strcmp(mtdids, old_mtdids))
  108 + return 0;
  109 +
  110 + /* Update the local copy of mtdparts */
  111 + free(old_mtdparts);
  112 + free(old_mtdids);
  113 + old_mtdparts = strdup(mtdparts);
  114 + old_mtdids = strdup(mtdids);
  115 +
  116 + /* If at least one partition is still in use, do not delete anything */
  117 + mtd_for_each_device(mtd) {
  118 + if (mtd->usecount) {
  119 + printf("Partition \"%s\" already in use, aborting\n",
  120 + mtd->name);
  121 + return -EACCES;
  122 + }
  123 + }
  124 +
  125 + /*
  126 + * Everything looks clear, remove all partitions. It is not safe to
  127 + * remove entries from the mtd_for_each_device loop as it uses idr
  128 + * indexes and the partitions removal is done in bulk (all partitions of
  129 + * one device at the same time), so break and iterate from start each
  130 + * time a new partition is found and deleted.
  131 + */
  132 + while (remaining_partitions) {
  133 + remaining_partitions = false;
  134 + mtd_for_each_device(mtd) {
  135 + if (!mtd_is_partition(mtd) && mtd_has_partitions(mtd)) {
  136 + del_mtd_partitions(mtd);
  137 + remaining_partitions = true;
  138 + break;
  139 + }
  140 + }
  141 + }
  142 +
  143 + /* Start the parsing by ignoring the extra 'mtdparts=' prefix, if any */
  144 + if (strstr(mtdparts, "mtdparts="))
  145 + mtdparts += 9;
  146 +
  147 + /* For each MTD device in mtdparts */
  148 + while (mtdparts[0] != '\0') {
  149 + char mtd_name[MTD_NAME_MAX_LEN], *colon;
  150 + struct mtd_partition *parts;
  151 + int mtd_name_len, nparts;
  152 + int ret;
  153 +
  154 + colon = strchr(mtdparts, ':');
  155 + if (!colon) {
  156 + printf("Wrong mtdparts: %s\n", mtdparts);
  157 + return -EINVAL;
  158 + }
  159 +
  160 + mtd_name_len = colon - mtdparts;
  161 + strncpy(mtd_name, mtdparts, mtd_name_len);
  162 + mtd_name[mtd_name_len] = '\0';
  163 + /* Move the pointer forward (including the ':') */
  164 + mtdparts += mtd_name_len + 1;
  165 + mtd = get_mtd_device_nm(mtd_name);
  166 + if (IS_ERR_OR_NULL(mtd)) {
  167 + char linux_name[MTD_NAME_MAX_LEN];
  168 +
  169 + /*
  170 + * The MTD device named "mtd_name" does not exist. Try
  171 + * to find a correspondance with an MTD device having
  172 + * the same type and number as defined in the mtdids.
  173 + */
  174 + debug("No device named %s\n", mtd_name);
  175 + ret = mtd_search_alternate_name(mtd_name, linux_name,
  176 + MTD_NAME_MAX_LEN);
  177 + if (!ret)
  178 + mtd = get_mtd_device_nm(linux_name);
  179 +
  180 + /*
  181 + * If no device could be found, move the mtdparts
  182 + * pointer forward until the next set of partitions.
  183 + */
  184 + if (ret || IS_ERR_OR_NULL(mtd)) {
  185 + printf("Could not find a valid device for %s\n",
  186 + mtd_name);
  187 + mtdparts = strchr(mtdparts, ';');
  188 + if (mtdparts)
  189 + mtdparts++;
  190 +
  191 + continue;
  192 + }
  193 + }
  194 +
  195 + /*
  196 + * Parse the MTD device partitions. It will update the mtdparts
  197 + * pointer, create an array of parts (that must be freed), and
  198 + * return the number of partition structures in the array.
  199 + */
  200 + ret = mtd_parse_partitions(mtd, &mtdparts, &parts, &nparts);
  201 + if (ret) {
  202 + printf("Could not parse device %s\n", mtd->name);
  203 + put_mtd_device(mtd);
  204 + return -EINVAL;
  205 + }
  206 +
  207 + if (!nparts)
  208 + continue;
  209 +
  210 + /* Create the new MTD partitions */
  211 + add_mtd_partitions(mtd, parts, nparts);
  212 +
  213 + /* Free the structures allocated during the parsing */
  214 + mtd_free_parsed_partitions(parts, nparts);
  215 +
  216 + put_mtd_device(mtd);
  217 + }
  218 +
  219 + return 0;
  220 +}
  221 +#else
  222 +int mtd_probe_devices(void)
  223 +{
  224 + mtd_probe_uclass_mtd_devs();
  225 +
  226 + return 0;
  227 +}
  228 +#endif /* defined(CONFIG_MTD_PARTITIONS) */
70 229  
71 230 /* Legacy */
72 231  
... ... @@ -9,6 +9,7 @@
9 9 #include <linux/mtd/mtd.h>
10 10  
11 11 int mtd_probe(struct udevice *dev);
  12 +int mtd_probe_devices(void);
12 13  
13 14 #endif /* _MTD_H_ */