183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+ 22e192b24SSimon Glass /* 32e192b24SSimon Glass * (C) Copyright 2002 42e192b24SSimon Glass * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 52e192b24SSimon Glass * 62e192b24SSimon Glass * (C) Copyright 2002 72e192b24SSimon Glass * Robert Schwebel, Pengutronix, <r.schwebel@pengutronix.de> 82e192b24SSimon Glass * 92e192b24SSimon Glass * (C) Copyright 2003 102e192b24SSimon Glass * Kai-Uwe Bloem, Auerswald GmbH & Co KG, <linux-development@auerswald.de> 112e192b24SSimon Glass * 122e192b24SSimon Glass * (C) Copyright 2005 132e192b24SSimon Glass * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 142e192b24SSimon Glass * 152e192b24SSimon Glass * Added support for reading flash partition table from environment. 162e192b24SSimon Glass * Parsing routines are based on driver/mtd/cmdline.c from the linux 2.4 172e192b24SSimon Glass * kernel tree. 182e192b24SSimon Glass * 192e192b24SSimon Glass * (C) Copyright 2008 202e192b24SSimon Glass * Harald Welte, OpenMoko, Inc., Harald Welte <laforge@openmoko.org> 212e192b24SSimon Glass * 222e192b24SSimon Glass * $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $ 232e192b24SSimon Glass * Copyright 2002 SYSGO Real-Time Solutions GmbH 242e192b24SSimon Glass */ 252e192b24SSimon Glass 262e192b24SSimon Glass /* 272e192b24SSimon Glass * Three environment variables are used by the parsing routines: 282e192b24SSimon Glass * 292e192b24SSimon Glass * 'partition' - keeps current partition identifier 302e192b24SSimon Glass * 312e192b24SSimon Glass * partition := <part-id> 322e192b24SSimon Glass * <part-id> := <dev-id>,part_num 332e192b24SSimon Glass * 342e192b24SSimon Glass * 352e192b24SSimon Glass * 'mtdids' - linux kernel mtd device id <-> u-boot device id mapping 362e192b24SSimon Glass * 372e192b24SSimon Glass * mtdids=<idmap>[,<idmap>,...] 382e192b24SSimon Glass * 392e192b24SSimon Glass * <idmap> := <dev-id>=<mtd-id> 4000ac922dSMiquel Raynal * <dev-id> := 'nand'|'nor'|'onenand'|'spi-nand'<dev-num> 412e192b24SSimon Glass * <dev-num> := mtd device number, 0... 422e192b24SSimon Glass * <mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name) 432e192b24SSimon Glass * 442e192b24SSimon Glass * 452e192b24SSimon Glass * 'mtdparts' - partition list 462e192b24SSimon Glass * 47*d60aea94SMiquel Raynal * mtdparts=[mtdparts=]<mtd-def>[;<mtd-def>...] 482e192b24SSimon Glass * 492e192b24SSimon Glass * <mtd-def> := <mtd-id>:<part-def>[,<part-def>...] 502e192b24SSimon Glass * <mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name) 512e192b24SSimon Glass * <part-def> := <size>[@<offset>][<name>][<ro-flag>] 522e192b24SSimon Glass * <size> := standard linux memsize OR '-' to denote all remaining space 532e192b24SSimon Glass * <offset> := partition start offset within the device 542e192b24SSimon Glass * <name> := '(' NAME ')' 552e192b24SSimon Glass * <ro-flag> := when set to 'ro' makes partition read-only (not used, passed to kernel) 562e192b24SSimon Glass * 572e192b24SSimon Glass * Notes: 582e192b24SSimon Glass * - each <mtd-id> used in mtdparts must albo exist in 'mtddis' mapping 592e192b24SSimon Glass * - if the above variables are not set defaults for a given target are used 602e192b24SSimon Glass * 612e192b24SSimon Glass * Examples: 622e192b24SSimon Glass * 632e192b24SSimon Glass * 1 NOR Flash, with 1 single writable partition: 642e192b24SSimon Glass * mtdids=nor0=edb7312-nor 65*d60aea94SMiquel Raynal * mtdparts=[mtdparts=]edb7312-nor:- 662e192b24SSimon Glass * 672e192b24SSimon Glass * 1 NOR Flash with 2 partitions, 1 NAND with one 682e192b24SSimon Glass * mtdids=nor0=edb7312-nor,nand0=edb7312-nand 69*d60aea94SMiquel Raynal * mtdparts=[mtdparts=]edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home) 702e192b24SSimon Glass * 712e192b24SSimon Glass */ 722e192b24SSimon Glass 732e192b24SSimon Glass #include <common.h> 742e192b24SSimon Glass #include <command.h> 752e192b24SSimon Glass #include <malloc.h> 762e192b24SSimon Glass #include <jffs2/load_kernel.h> 772e192b24SSimon Glass #include <linux/list.h> 782e192b24SSimon Glass #include <linux/ctype.h> 792e192b24SSimon Glass #include <linux/err.h> 802e192b24SSimon Glass #include <linux/mtd/mtd.h> 812e192b24SSimon Glass 822e192b24SSimon Glass #if defined(CONFIG_CMD_NAND) 836ae3900aSMasahiro Yamada #include <linux/mtd/rawnand.h> 842e192b24SSimon Glass #include <nand.h> 852e192b24SSimon Glass #endif 862e192b24SSimon Glass 872e192b24SSimon Glass #if defined(CONFIG_CMD_ONENAND) 882e192b24SSimon Glass #include <linux/mtd/onenand.h> 892e192b24SSimon Glass #include <onenand_uboot.h> 902e192b24SSimon Glass #endif 912e192b24SSimon Glass 922e192b24SSimon Glass DECLARE_GLOBAL_DATA_PTR; 932e192b24SSimon Glass 942e192b24SSimon Glass /* special size referring to all the remaining space in a partition */ 952e192b24SSimon Glass #define SIZE_REMAINING (~0llu) 962e192b24SSimon Glass 972e192b24SSimon Glass /* special offset value, it is used when not provided by user 982e192b24SSimon Glass * 992e192b24SSimon Glass * this value is used temporarily during parsing, later such offests 1002e192b24SSimon Glass * are recalculated */ 1012e192b24SSimon Glass #define OFFSET_NOT_SPECIFIED (~0llu) 1022e192b24SSimon Glass 1032e192b24SSimon Glass /* minimum partition size */ 1042e192b24SSimon Glass #define MIN_PART_SIZE 4096 1052e192b24SSimon Glass 1062e192b24SSimon Glass /* this flag needs to be set in part_info struct mask_flags 1072e192b24SSimon Glass * field for read-only partitions */ 1082e192b24SSimon Glass #define MTD_WRITEABLE_CMD 1 1092e192b24SSimon Glass 1102e192b24SSimon Glass /* default values for mtdids and mtdparts variables */ 111af324436SLadislav Michl #if !defined(MTDIDS_DEFAULT) 1120269dfaeSMaxime Ripard #ifdef CONFIG_MTDIDS_DEFAULT 1130269dfaeSMaxime Ripard #define MTDIDS_DEFAULT CONFIG_MTDIDS_DEFAULT 1140269dfaeSMaxime Ripard #else 115af324436SLadislav Michl #define MTDIDS_DEFAULT NULL 1162e192b24SSimon Glass #endif 1170269dfaeSMaxime Ripard #endif 118af324436SLadislav Michl #if !defined(MTDPARTS_DEFAULT) 1190269dfaeSMaxime Ripard #ifdef CONFIG_MTDPARTS_DEFAULT 1200269dfaeSMaxime Ripard #define MTDPARTS_DEFAULT CONFIG_MTDPARTS_DEFAULT 1210269dfaeSMaxime Ripard #else 122af324436SLadislav Michl #define MTDPARTS_DEFAULT NULL 1232e192b24SSimon Glass #endif 1240269dfaeSMaxime Ripard #endif 125af324436SLadislav Michl #if defined(CONFIG_SYS_MTDPARTS_RUNTIME) 126af324436SLadislav Michl extern void board_mtdparts_default(const char **mtdids, const char **mtdparts); 127af324436SLadislav Michl #endif 128af324436SLadislav Michl static const char *mtdids_default = MTDIDS_DEFAULT; 129af324436SLadislav Michl static const char *mtdparts_default = MTDPARTS_DEFAULT; 1302e192b24SSimon Glass 1312e192b24SSimon Glass /* copies of last seen 'mtdids', 'mtdparts' and 'partition' env variables */ 1322e192b24SSimon Glass #define MTDIDS_MAXLEN 128 1332e192b24SSimon Glass #define MTDPARTS_MAXLEN 512 1342e192b24SSimon Glass #define PARTITION_MAXLEN 16 13554f1792cSTom Rini static char last_ids[MTDIDS_MAXLEN + 1]; 13654f1792cSTom Rini static char last_parts[MTDPARTS_MAXLEN + 1]; 13754f1792cSTom Rini static char last_partition[PARTITION_MAXLEN + 1]; 1382e192b24SSimon Glass 1392e192b24SSimon Glass /* low level jffs2 cache cleaning routine */ 1402e192b24SSimon Glass extern void jffs2_free_cache(struct part_info *part); 1412e192b24SSimon Glass 1422e192b24SSimon Glass /* mtdids mapping list, filled by parse_ids() */ 1432e192b24SSimon Glass static struct list_head mtdids; 1442e192b24SSimon Glass 1452e192b24SSimon Glass /* device/partition list, parse_cmdline() parses into here */ 1462e192b24SSimon Glass static struct list_head devices; 1472e192b24SSimon Glass 1482e192b24SSimon Glass /* current active device and partition number */ 1492e192b24SSimon Glass struct mtd_device *current_mtd_dev = NULL; 1502e192b24SSimon Glass u8 current_mtd_partnum = 0; 1512e192b24SSimon Glass 152f8f744a3SLadislav Michl u8 use_defaults; 153f8f744a3SLadislav Michl 1542e192b24SSimon Glass static struct part_info* mtd_part_info(struct mtd_device *dev, unsigned int part_num); 1552e192b24SSimon Glass 1562e192b24SSimon Glass /* command line only routines */ 1572e192b24SSimon Glass static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_len); 1582e192b24SSimon Glass static int device_del(struct mtd_device *dev); 1592e192b24SSimon Glass 1602e192b24SSimon Glass /** 1612e192b24SSimon Glass * Parses a string into a number. The number stored at ptr is 1622e192b24SSimon Glass * potentially suffixed with K (for kilobytes, or 1024 bytes), 1632e192b24SSimon Glass * M (for megabytes, or 1048576 bytes), or G (for gigabytes, or 1642e192b24SSimon Glass * 1073741824). If the number is suffixed with K, M, or G, then 1652e192b24SSimon Glass * the return value is the number multiplied by one kilobyte, one 1662e192b24SSimon Glass * megabyte, or one gigabyte, respectively. 1672e192b24SSimon Glass * 1682e192b24SSimon Glass * @param ptr where parse begins 1692e192b24SSimon Glass * @param retptr output pointer to next char after parse completes (output) 1702e192b24SSimon Glass * @return resulting unsigned int 1712e192b24SSimon Glass */ 1722e192b24SSimon Glass static u64 memsize_parse (const char *const ptr, const char **retptr) 1732e192b24SSimon Glass { 1742e192b24SSimon Glass u64 ret = simple_strtoull(ptr, (char **)retptr, 0); 1752e192b24SSimon Glass 1762e192b24SSimon Glass switch (**retptr) { 1772e192b24SSimon Glass case 'G': 1782e192b24SSimon Glass case 'g': 1792e192b24SSimon Glass ret <<= 10; 1802b9ace55SMiquel Raynal /* Fallthrough */ 1812e192b24SSimon Glass case 'M': 1822e192b24SSimon Glass case 'm': 1832e192b24SSimon Glass ret <<= 10; 1842b9ace55SMiquel Raynal /* Fallthrough */ 1852e192b24SSimon Glass case 'K': 1862e192b24SSimon Glass case 'k': 1872e192b24SSimon Glass ret <<= 10; 1882e192b24SSimon Glass (*retptr)++; 1892b9ace55SMiquel Raynal /* Fallthrough */ 1902e192b24SSimon Glass default: 1912e192b24SSimon Glass break; 1922e192b24SSimon Glass } 1932e192b24SSimon Glass 1942e192b24SSimon Glass return ret; 1952e192b24SSimon Glass } 1962e192b24SSimon Glass 1972e192b24SSimon Glass /** 1982e192b24SSimon Glass * Format string describing supplied size. This routine does the opposite job 1992e192b24SSimon Glass * to memsize_parse(). Size in bytes is converted to string and if possible 2002e192b24SSimon Glass * shortened by using k (kilobytes), m (megabytes) or g (gigabytes) suffix. 2012e192b24SSimon Glass * 2022e192b24SSimon Glass * Note, that this routine does not check for buffer overflow, it's the caller 2032e192b24SSimon Glass * who must assure enough space. 2042e192b24SSimon Glass * 2052e192b24SSimon Glass * @param buf output buffer 2062e192b24SSimon Glass * @param size size to be converted to string 2072e192b24SSimon Glass */ 2082e192b24SSimon Glass static void memsize_format(char *buf, u64 size) 2092e192b24SSimon Glass { 2102e192b24SSimon Glass #define SIZE_GB ((u32)1024*1024*1024) 2112e192b24SSimon Glass #define SIZE_MB ((u32)1024*1024) 2122e192b24SSimon Glass #define SIZE_KB ((u32)1024) 2132e192b24SSimon Glass 2142e192b24SSimon Glass if ((size % SIZE_GB) == 0) 2152e192b24SSimon Glass sprintf(buf, "%llug", size/SIZE_GB); 2162e192b24SSimon Glass else if ((size % SIZE_MB) == 0) 2172e192b24SSimon Glass sprintf(buf, "%llum", size/SIZE_MB); 2182e192b24SSimon Glass else if (size % SIZE_KB == 0) 2192e192b24SSimon Glass sprintf(buf, "%lluk", size/SIZE_KB); 2202e192b24SSimon Glass else 2212e192b24SSimon Glass sprintf(buf, "%llu", size); 2222e192b24SSimon Glass } 2232e192b24SSimon Glass 2242e192b24SSimon Glass /** 2252e192b24SSimon Glass * This routine does global indexing of all partitions. Resulting index for 2262e192b24SSimon Glass * current partition is saved in 'mtddevnum'. Current partition name in 2272e192b24SSimon Glass * 'mtddevname'. 2282e192b24SSimon Glass */ 2292e192b24SSimon Glass static void index_partitions(void) 2302e192b24SSimon Glass { 2312e192b24SSimon Glass u16 mtddevnum; 2322e192b24SSimon Glass struct part_info *part; 2332e192b24SSimon Glass struct list_head *dentry; 2342e192b24SSimon Glass struct mtd_device *dev; 2352e192b24SSimon Glass 2362e192b24SSimon Glass debug("--- index partitions ---\n"); 2372e192b24SSimon Glass 2382e192b24SSimon Glass if (current_mtd_dev) { 2392e192b24SSimon Glass mtddevnum = 0; 2402e192b24SSimon Glass list_for_each(dentry, &devices) { 2412e192b24SSimon Glass dev = list_entry(dentry, struct mtd_device, link); 2422e192b24SSimon Glass if (dev == current_mtd_dev) { 2432e192b24SSimon Glass mtddevnum += current_mtd_partnum; 244018f5303SSimon Glass env_set_ulong("mtddevnum", mtddevnum); 24554f1792cSTom Rini debug("=> mtddevnum %d,\n", mtddevnum); 2462e192b24SSimon Glass break; 2472e192b24SSimon Glass } 2482e192b24SSimon Glass mtddevnum += dev->num_parts; 2492e192b24SSimon Glass } 2502e192b24SSimon Glass 2512e192b24SSimon Glass part = mtd_part_info(current_mtd_dev, current_mtd_partnum); 25254f1792cSTom Rini if (part) { 253382bee57SSimon Glass env_set("mtddevname", part->name); 2542e192b24SSimon Glass 25554f1792cSTom Rini debug("=> mtddevname %s\n", part->name); 25654f1792cSTom Rini } else { 25754f1792cSTom Rini env_set("mtddevname", NULL); 25854f1792cSTom Rini 25954f1792cSTom Rini debug("=> mtddevname NULL\n"); 26054f1792cSTom Rini } 2612e192b24SSimon Glass } else { 262382bee57SSimon Glass env_set("mtddevnum", NULL); 263382bee57SSimon Glass env_set("mtddevname", NULL); 2642e192b24SSimon Glass 2652e192b24SSimon Glass debug("=> mtddevnum NULL\n=> mtddevname NULL\n"); 2662e192b24SSimon Glass } 2672e192b24SSimon Glass } 2682e192b24SSimon Glass 2692e192b24SSimon Glass /** 2702e192b24SSimon Glass * Save current device and partition in environment variable 'partition'. 2712e192b24SSimon Glass */ 2722e192b24SSimon Glass static void current_save(void) 2732e192b24SSimon Glass { 2742e192b24SSimon Glass char buf[16]; 2752e192b24SSimon Glass 2762e192b24SSimon Glass debug("--- current_save ---\n"); 2772e192b24SSimon Glass 2782e192b24SSimon Glass if (current_mtd_dev) { 2792e192b24SSimon Glass sprintf(buf, "%s%d,%d", MTD_DEV_TYPE(current_mtd_dev->id->type), 2802e192b24SSimon Glass current_mtd_dev->id->num, current_mtd_partnum); 2812e192b24SSimon Glass 282382bee57SSimon Glass env_set("partition", buf); 2832e192b24SSimon Glass strncpy(last_partition, buf, 16); 2842e192b24SSimon Glass 2852e192b24SSimon Glass debug("=> partition %s\n", buf); 2862e192b24SSimon Glass } else { 287382bee57SSimon Glass env_set("partition", NULL); 2882e192b24SSimon Glass last_partition[0] = '\0'; 2892e192b24SSimon Glass 2902e192b24SSimon Glass debug("=> partition NULL\n"); 2912e192b24SSimon Glass } 2922e192b24SSimon Glass index_partitions(); 2932e192b24SSimon Glass } 2942e192b24SSimon Glass 2952e192b24SSimon Glass 2962e192b24SSimon Glass /** 2972e192b24SSimon Glass * Produce a mtd_info given a type and num. 2982e192b24SSimon Glass * 2992e192b24SSimon Glass * @param type mtd type 3002e192b24SSimon Glass * @param num mtd number 3012e192b24SSimon Glass * @param mtd a pointer to an mtd_info instance (output) 3022e192b24SSimon Glass * @return 0 if device is valid, 1 otherwise 3032e192b24SSimon Glass */ 3042e192b24SSimon Glass static int get_mtd_info(u8 type, u8 num, struct mtd_info **mtd) 3052e192b24SSimon Glass { 3062e192b24SSimon Glass char mtd_dev[16]; 3072e192b24SSimon Glass 3082e192b24SSimon Glass sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(type), num); 3092e192b24SSimon Glass *mtd = get_mtd_device_nm(mtd_dev); 3102e192b24SSimon Glass if (IS_ERR(*mtd)) { 3112e192b24SSimon Glass printf("Device %s not found!\n", mtd_dev); 3122e192b24SSimon Glass return 1; 3132e192b24SSimon Glass } 3142e192b24SSimon Glass put_mtd_device(*mtd); 3152e192b24SSimon Glass 3162e192b24SSimon Glass return 0; 3172e192b24SSimon Glass } 3182e192b24SSimon Glass 3192e192b24SSimon Glass /** 3202e192b24SSimon Glass * Performs sanity check for supplied flash partition. 3212e192b24SSimon Glass * Table of existing MTD flash devices is searched and partition device 3222e192b24SSimon Glass * is located. Alignment with the granularity of nand erasesize is verified. 3232e192b24SSimon Glass * 3242e192b24SSimon Glass * @param id of the parent device 3252e192b24SSimon Glass * @param part partition to validate 3262e192b24SSimon Glass * @return 0 if partition is valid, 1 otherwise 3272e192b24SSimon Glass */ 3282e192b24SSimon Glass static int part_validate_eraseblock(struct mtdids *id, struct part_info *part) 3292e192b24SSimon Glass { 3302e192b24SSimon Glass struct mtd_info *mtd = NULL; 3312e192b24SSimon Glass int i, j; 3322e192b24SSimon Glass ulong start; 3332e192b24SSimon Glass u64 offset, size; 3342e192b24SSimon Glass 3352e192b24SSimon Glass if (get_mtd_info(id->type, id->num, &mtd)) 3362e192b24SSimon Glass return 1; 3372e192b24SSimon Glass 3382e192b24SSimon Glass part->sector_size = mtd->erasesize; 3392e192b24SSimon Glass 3402e192b24SSimon Glass if (!mtd->numeraseregions) { 3412e192b24SSimon Glass /* 34200ac922dSMiquel Raynal * Only one eraseregion (NAND, SPI-NAND, OneNAND or uniform NOR), 3432e192b24SSimon Glass * checking for alignment is easy here 3442e192b24SSimon Glass */ 3452e192b24SSimon Glass offset = part->offset; 3462e192b24SSimon Glass if (do_div(offset, mtd->erasesize)) { 3472e192b24SSimon Glass printf("%s%d: partition (%s) start offset" 3482e192b24SSimon Glass "alignment incorrect\n", 3492e192b24SSimon Glass MTD_DEV_TYPE(id->type), id->num, part->name); 3502e192b24SSimon Glass return 1; 3512e192b24SSimon Glass } 3522e192b24SSimon Glass 3532e192b24SSimon Glass size = part->size; 3542e192b24SSimon Glass if (do_div(size, mtd->erasesize)) { 3552e192b24SSimon Glass printf("%s%d: partition (%s) size alignment incorrect\n", 3562e192b24SSimon Glass MTD_DEV_TYPE(id->type), id->num, part->name); 3572e192b24SSimon Glass return 1; 3582e192b24SSimon Glass } 3592e192b24SSimon Glass } else { 3602e192b24SSimon Glass /* 3612e192b24SSimon Glass * Multiple eraseregions (non-uniform NOR), 3622e192b24SSimon Glass * checking for alignment is more complex here 3632e192b24SSimon Glass */ 3642e192b24SSimon Glass 3652e192b24SSimon Glass /* Check start alignment */ 3662e192b24SSimon Glass for (i = 0; i < mtd->numeraseregions; i++) { 3672e192b24SSimon Glass start = mtd->eraseregions[i].offset; 3682e192b24SSimon Glass for (j = 0; j < mtd->eraseregions[i].numblocks; j++) { 3692e192b24SSimon Glass if (part->offset == start) 3702e192b24SSimon Glass goto start_ok; 3712e192b24SSimon Glass start += mtd->eraseregions[i].erasesize; 3722e192b24SSimon Glass } 3732e192b24SSimon Glass } 3742e192b24SSimon Glass 3752e192b24SSimon Glass printf("%s%d: partition (%s) start offset alignment incorrect\n", 3762e192b24SSimon Glass MTD_DEV_TYPE(id->type), id->num, part->name); 3772e192b24SSimon Glass return 1; 3782e192b24SSimon Glass 3792e192b24SSimon Glass start_ok: 3802e192b24SSimon Glass 3812e192b24SSimon Glass /* Check end/size alignment */ 3822e192b24SSimon Glass for (i = 0; i < mtd->numeraseregions; i++) { 3832e192b24SSimon Glass start = mtd->eraseregions[i].offset; 3842e192b24SSimon Glass for (j = 0; j < mtd->eraseregions[i].numblocks; j++) { 3852e192b24SSimon Glass if ((part->offset + part->size) == start) 3862e192b24SSimon Glass goto end_ok; 3872e192b24SSimon Glass start += mtd->eraseregions[i].erasesize; 3882e192b24SSimon Glass } 3892e192b24SSimon Glass } 3902e192b24SSimon Glass /* Check last sector alignment */ 3912e192b24SSimon Glass if ((part->offset + part->size) == start) 3922e192b24SSimon Glass goto end_ok; 3932e192b24SSimon Glass 3942e192b24SSimon Glass printf("%s%d: partition (%s) size alignment incorrect\n", 3952e192b24SSimon Glass MTD_DEV_TYPE(id->type), id->num, part->name); 3962e192b24SSimon Glass return 1; 3972e192b24SSimon Glass 3982e192b24SSimon Glass end_ok: 3992e192b24SSimon Glass return 0; 4002e192b24SSimon Glass } 4012e192b24SSimon Glass 4022e192b24SSimon Glass return 0; 4032e192b24SSimon Glass } 4042e192b24SSimon Glass 4052e192b24SSimon Glass 4062e192b24SSimon Glass /** 4072e192b24SSimon Glass * Performs sanity check for supplied partition. Offset and size are 4082e192b24SSimon Glass * verified to be within valid range. Partition type is checked and 4092e192b24SSimon Glass * part_validate_eraseblock() is called with the argument of part. 4102e192b24SSimon Glass * 4112e192b24SSimon Glass * @param id of the parent device 4122e192b24SSimon Glass * @param part partition to validate 4132e192b24SSimon Glass * @return 0 if partition is valid, 1 otherwise 4142e192b24SSimon Glass */ 4152e192b24SSimon Glass static int part_validate(struct mtdids *id, struct part_info *part) 4162e192b24SSimon Glass { 4172e192b24SSimon Glass if (part->size == SIZE_REMAINING) 4182e192b24SSimon Glass part->size = id->size - part->offset; 4192e192b24SSimon Glass 4202e192b24SSimon Glass if (part->offset > id->size) { 4212e192b24SSimon Glass printf("%s: offset %08llx beyond flash size %08llx\n", 4222e192b24SSimon Glass id->mtd_id, part->offset, id->size); 4232e192b24SSimon Glass return 1; 4242e192b24SSimon Glass } 4252e192b24SSimon Glass 4262e192b24SSimon Glass if ((part->offset + part->size) <= part->offset) { 4272e192b24SSimon Glass printf("%s%d: partition (%s) size too big\n", 4282e192b24SSimon Glass MTD_DEV_TYPE(id->type), id->num, part->name); 4292e192b24SSimon Glass return 1; 4302e192b24SSimon Glass } 4312e192b24SSimon Glass 4322e192b24SSimon Glass if (part->offset + part->size > id->size) { 4332e192b24SSimon Glass printf("%s: partitioning exceeds flash size\n", id->mtd_id); 4342e192b24SSimon Glass return 1; 4352e192b24SSimon Glass } 4362e192b24SSimon Glass 4372e192b24SSimon Glass /* 4382e192b24SSimon Glass * Now we need to check if the partition starts and ends on 4392e192b24SSimon Glass * sector (eraseblock) regions 4402e192b24SSimon Glass */ 4412e192b24SSimon Glass return part_validate_eraseblock(id, part); 4422e192b24SSimon Glass } 4432e192b24SSimon Glass 4442e192b24SSimon Glass /** 4452e192b24SSimon Glass * Delete selected partition from the partition list of the specified device. 4462e192b24SSimon Glass * 4472e192b24SSimon Glass * @param dev device to delete partition from 4482e192b24SSimon Glass * @param part partition to delete 4492e192b24SSimon Glass * @return 0 on success, 1 otherwise 4502e192b24SSimon Glass */ 4512e192b24SSimon Glass static int part_del(struct mtd_device *dev, struct part_info *part) 4522e192b24SSimon Glass { 4532e192b24SSimon Glass u8 current_save_needed = 0; 4542e192b24SSimon Glass 4552e192b24SSimon Glass /* if there is only one partition, remove whole device */ 4562e192b24SSimon Glass if (dev->num_parts == 1) 4572e192b24SSimon Glass return device_del(dev); 4582e192b24SSimon Glass 4592e192b24SSimon Glass /* otherwise just delete this partition */ 4602e192b24SSimon Glass 4612e192b24SSimon Glass if (dev == current_mtd_dev) { 4622e192b24SSimon Glass /* we are modyfing partitions for the current device, 4632e192b24SSimon Glass * update current */ 4642e192b24SSimon Glass struct part_info *curr_pi; 4652e192b24SSimon Glass curr_pi = mtd_part_info(current_mtd_dev, current_mtd_partnum); 4662e192b24SSimon Glass 4672e192b24SSimon Glass if (curr_pi) { 4682e192b24SSimon Glass if (curr_pi == part) { 4692e192b24SSimon Glass printf("current partition deleted, resetting current to 0\n"); 4702e192b24SSimon Glass current_mtd_partnum = 0; 4712e192b24SSimon Glass } else if (part->offset <= curr_pi->offset) { 4722e192b24SSimon Glass current_mtd_partnum--; 4732e192b24SSimon Glass } 4742e192b24SSimon Glass current_save_needed = 1; 4752e192b24SSimon Glass } 4762e192b24SSimon Glass } 4772e192b24SSimon Glass 4782e192b24SSimon Glass list_del(&part->link); 4792e192b24SSimon Glass free(part); 4802e192b24SSimon Glass dev->num_parts--; 4812e192b24SSimon Glass 4822e192b24SSimon Glass if (current_save_needed > 0) 4832e192b24SSimon Glass current_save(); 4842e192b24SSimon Glass else 4852e192b24SSimon Glass index_partitions(); 4862e192b24SSimon Glass 4872e192b24SSimon Glass return 0; 4882e192b24SSimon Glass } 4892e192b24SSimon Glass 4902e192b24SSimon Glass /** 4912e192b24SSimon Glass * Delete all partitions from parts head list, free memory. 4922e192b24SSimon Glass * 4932e192b24SSimon Glass * @param head list of partitions to delete 4942e192b24SSimon Glass */ 4952e192b24SSimon Glass static void part_delall(struct list_head *head) 4962e192b24SSimon Glass { 4972e192b24SSimon Glass struct list_head *entry, *n; 4982e192b24SSimon Glass struct part_info *part_tmp; 4992e192b24SSimon Glass 5002e192b24SSimon Glass /* clean tmp_list and free allocated memory */ 5012e192b24SSimon Glass list_for_each_safe(entry, n, head) { 5022e192b24SSimon Glass part_tmp = list_entry(entry, struct part_info, link); 5032e192b24SSimon Glass 5042e192b24SSimon Glass list_del(entry); 5052e192b24SSimon Glass free(part_tmp); 5062e192b24SSimon Glass } 5072e192b24SSimon Glass } 5082e192b24SSimon Glass 5092e192b24SSimon Glass /** 5102e192b24SSimon Glass * Add new partition to the supplied partition list. Make sure partitions are 5112e192b24SSimon Glass * sorted by offset in ascending order. 5122e192b24SSimon Glass * 5132e192b24SSimon Glass * @param head list this partition is to be added to 5142e192b24SSimon Glass * @param new partition to be added 5152e192b24SSimon Glass */ 5162e192b24SSimon Glass static int part_sort_add(struct mtd_device *dev, struct part_info *part) 5172e192b24SSimon Glass { 5182e192b24SSimon Glass struct list_head *entry; 5192e192b24SSimon Glass struct part_info *new_pi, *curr_pi; 5202e192b24SSimon Glass 5212e192b24SSimon Glass /* link partition to parrent dev */ 5222e192b24SSimon Glass part->dev = dev; 5232e192b24SSimon Glass 5242e192b24SSimon Glass if (list_empty(&dev->parts)) { 5252e192b24SSimon Glass debug("part_sort_add: list empty\n"); 5262e192b24SSimon Glass list_add(&part->link, &dev->parts); 5272e192b24SSimon Glass dev->num_parts++; 5282e192b24SSimon Glass index_partitions(); 5292e192b24SSimon Glass return 0; 5302e192b24SSimon Glass } 5312e192b24SSimon Glass 5322e192b24SSimon Glass new_pi = list_entry(&part->link, struct part_info, link); 5332e192b24SSimon Glass 5342e192b24SSimon Glass /* get current partition info if we are updating current device */ 5352e192b24SSimon Glass curr_pi = NULL; 5362e192b24SSimon Glass if (dev == current_mtd_dev) 5372e192b24SSimon Glass curr_pi = mtd_part_info(current_mtd_dev, current_mtd_partnum); 5382e192b24SSimon Glass 5392e192b24SSimon Glass list_for_each(entry, &dev->parts) { 5402e192b24SSimon Glass struct part_info *pi; 5412e192b24SSimon Glass 5422e192b24SSimon Glass pi = list_entry(entry, struct part_info, link); 5432e192b24SSimon Glass 5442e192b24SSimon Glass /* be compliant with kernel cmdline, allow only one partition at offset zero */ 5452e192b24SSimon Glass if ((new_pi->offset == pi->offset) && (pi->offset == 0)) { 5462e192b24SSimon Glass printf("cannot add second partition at offset 0\n"); 5472e192b24SSimon Glass return 1; 5482e192b24SSimon Glass } 5492e192b24SSimon Glass 5502e192b24SSimon Glass if (new_pi->offset <= pi->offset) { 5512e192b24SSimon Glass list_add_tail(&part->link, entry); 5522e192b24SSimon Glass dev->num_parts++; 5532e192b24SSimon Glass 5542e192b24SSimon Glass if (curr_pi && (pi->offset <= curr_pi->offset)) { 5552e192b24SSimon Glass /* we are modyfing partitions for the current 5562e192b24SSimon Glass * device, update current */ 5572e192b24SSimon Glass current_mtd_partnum++; 5582e192b24SSimon Glass current_save(); 5592e192b24SSimon Glass } else { 5602e192b24SSimon Glass index_partitions(); 5612e192b24SSimon Glass } 5622e192b24SSimon Glass return 0; 5632e192b24SSimon Glass } 5642e192b24SSimon Glass } 5652e192b24SSimon Glass 5662e192b24SSimon Glass list_add_tail(&part->link, &dev->parts); 5672e192b24SSimon Glass dev->num_parts++; 5682e192b24SSimon Glass index_partitions(); 5692e192b24SSimon Glass return 0; 5702e192b24SSimon Glass } 5712e192b24SSimon Glass 5722e192b24SSimon Glass /** 5732e192b24SSimon Glass * Add provided partition to the partition list of a given device. 5742e192b24SSimon Glass * 5752e192b24SSimon Glass * @param dev device to which partition is added 5762e192b24SSimon Glass * @param part partition to be added 5772e192b24SSimon Glass * @return 0 on success, 1 otherwise 5782e192b24SSimon Glass */ 5792e192b24SSimon Glass static int part_add(struct mtd_device *dev, struct part_info *part) 5802e192b24SSimon Glass { 5812e192b24SSimon Glass /* verify alignment and size */ 5822e192b24SSimon Glass if (part_validate(dev->id, part) != 0) 5832e192b24SSimon Glass return 1; 5842e192b24SSimon Glass 5852e192b24SSimon Glass /* partition is ok, add it to the list */ 5862e192b24SSimon Glass if (part_sort_add(dev, part) != 0) 5872e192b24SSimon Glass return 1; 5882e192b24SSimon Glass 5892e192b24SSimon Glass return 0; 5902e192b24SSimon Glass } 5912e192b24SSimon Glass 5922e192b24SSimon Glass /** 5932e192b24SSimon Glass * Parse one partition definition, allocate memory and return pointer to this 5942e192b24SSimon Glass * location in retpart. 5952e192b24SSimon Glass * 5962e192b24SSimon Glass * @param partdef pointer to the partition definition string i.e. <part-def> 5972e192b24SSimon Glass * @param ret output pointer to next char after parse completes (output) 5982e192b24SSimon Glass * @param retpart pointer to the allocated partition (output) 5992e192b24SSimon Glass * @return 0 on success, 1 otherwise 6002e192b24SSimon Glass */ 6012e192b24SSimon Glass static int part_parse(const char *const partdef, const char **ret, struct part_info **retpart) 6022e192b24SSimon Glass { 6032e192b24SSimon Glass struct part_info *part; 6042e192b24SSimon Glass u64 size; 6052e192b24SSimon Glass u64 offset; 6062e192b24SSimon Glass const char *name; 6072e192b24SSimon Glass int name_len; 6082e192b24SSimon Glass unsigned int mask_flags; 6092e192b24SSimon Glass const char *p; 6102e192b24SSimon Glass 6112e192b24SSimon Glass p = partdef; 6122e192b24SSimon Glass *retpart = NULL; 6132e192b24SSimon Glass *ret = NULL; 6142e192b24SSimon Glass 6152e192b24SSimon Glass /* fetch the partition size */ 6162e192b24SSimon Glass if (*p == '-') { 6172e192b24SSimon Glass /* assign all remaining space to this partition */ 6182e192b24SSimon Glass debug("'-': remaining size assigned\n"); 6192e192b24SSimon Glass size = SIZE_REMAINING; 6202e192b24SSimon Glass p++; 6212e192b24SSimon Glass } else { 6222e192b24SSimon Glass size = memsize_parse(p, &p); 6232e192b24SSimon Glass if (size < MIN_PART_SIZE) { 6242e192b24SSimon Glass printf("partition size too small (%llx)\n", size); 6252e192b24SSimon Glass return 1; 6262e192b24SSimon Glass } 6272e192b24SSimon Glass } 6282e192b24SSimon Glass 6292e192b24SSimon Glass /* check for offset */ 6302e192b24SSimon Glass offset = OFFSET_NOT_SPECIFIED; 6312e192b24SSimon Glass if (*p == '@') { 6322e192b24SSimon Glass p++; 6332e192b24SSimon Glass offset = memsize_parse(p, &p); 6342e192b24SSimon Glass } 6352e192b24SSimon Glass 6362e192b24SSimon Glass /* now look for the name */ 6372e192b24SSimon Glass if (*p == '(') { 6382e192b24SSimon Glass name = ++p; 6392e192b24SSimon Glass if ((p = strchr(name, ')')) == NULL) { 6402e192b24SSimon Glass printf("no closing ) found in partition name\n"); 6412e192b24SSimon Glass return 1; 6422e192b24SSimon Glass } 6432e192b24SSimon Glass name_len = p - name + 1; 6442e192b24SSimon Glass if ((name_len - 1) == 0) { 6452e192b24SSimon Glass printf("empty partition name\n"); 6462e192b24SSimon Glass return 1; 6472e192b24SSimon Glass } 6482e192b24SSimon Glass p++; 6492e192b24SSimon Glass } else { 6502e192b24SSimon Glass /* 0x00000000@0x00000000 */ 6512e192b24SSimon Glass name_len = 22; 6522e192b24SSimon Glass name = NULL; 6532e192b24SSimon Glass } 6542e192b24SSimon Glass 6552e192b24SSimon Glass /* test for options */ 6562e192b24SSimon Glass mask_flags = 0; 6572e192b24SSimon Glass if (strncmp(p, "ro", 2) == 0) { 6582e192b24SSimon Glass mask_flags |= MTD_WRITEABLE_CMD; 6592e192b24SSimon Glass p += 2; 6602e192b24SSimon Glass } 6612e192b24SSimon Glass 6622e192b24SSimon Glass /* check for next partition definition */ 6632e192b24SSimon Glass if (*p == ',') { 6642e192b24SSimon Glass if (size == SIZE_REMAINING) { 6652e192b24SSimon Glass *ret = NULL; 6662e192b24SSimon Glass printf("no partitions allowed after a fill-up partition\n"); 6672e192b24SSimon Glass return 1; 6682e192b24SSimon Glass } 6692e192b24SSimon Glass *ret = ++p; 6702e192b24SSimon Glass } else if ((*p == ';') || (*p == '\0')) { 6712e192b24SSimon Glass *ret = p; 6722e192b24SSimon Glass } else { 6732e192b24SSimon Glass printf("unexpected character '%c' at the end of partition\n", *p); 6742e192b24SSimon Glass *ret = NULL; 6752e192b24SSimon Glass return 1; 6762e192b24SSimon Glass } 6772e192b24SSimon Glass 6782e192b24SSimon Glass /* allocate memory */ 6792e192b24SSimon Glass part = (struct part_info *)malloc(sizeof(struct part_info) + name_len); 6802e192b24SSimon Glass if (!part) { 6812e192b24SSimon Glass printf("out of memory\n"); 6822e192b24SSimon Glass return 1; 6832e192b24SSimon Glass } 6842e192b24SSimon Glass memset(part, 0, sizeof(struct part_info) + name_len); 6852e192b24SSimon Glass part->size = size; 6862e192b24SSimon Glass part->offset = offset; 6872e192b24SSimon Glass part->mask_flags = mask_flags; 6882e192b24SSimon Glass part->name = (char *)(part + 1); 6892e192b24SSimon Glass 6902e192b24SSimon Glass if (name) { 6912e192b24SSimon Glass /* copy user provided name */ 6922e192b24SSimon Glass strncpy(part->name, name, name_len - 1); 6932e192b24SSimon Glass part->auto_name = 0; 6942e192b24SSimon Glass } else { 6952e192b24SSimon Glass /* auto generated name in form of size@offset */ 696149c21b0SKay Potthoff snprintf(part->name, name_len, "0x%08llx@0x%08llx", size, offset); 6972e192b24SSimon Glass part->auto_name = 1; 6982e192b24SSimon Glass } 6992e192b24SSimon Glass 7002e192b24SSimon Glass part->name[name_len - 1] = '\0'; 7012e192b24SSimon Glass INIT_LIST_HEAD(&part->link); 7022e192b24SSimon Glass 7032e192b24SSimon Glass debug("+ partition: name %-22s size 0x%08llx offset 0x%08llx mask flags %d\n", 7042e192b24SSimon Glass part->name, part->size, 7052e192b24SSimon Glass part->offset, part->mask_flags); 7062e192b24SSimon Glass 7072e192b24SSimon Glass *retpart = part; 7082e192b24SSimon Glass return 0; 7092e192b24SSimon Glass } 7102e192b24SSimon Glass 7112e192b24SSimon Glass /** 7122e192b24SSimon Glass * Check device number to be within valid range for given device type. 7132e192b24SSimon Glass * 7142e192b24SSimon Glass * @param type mtd type 7152e192b24SSimon Glass * @param num mtd number 7162e192b24SSimon Glass * @param size a pointer to the size of the mtd device (output) 7172e192b24SSimon Glass * @return 0 if device is valid, 1 otherwise 7182e192b24SSimon Glass */ 7192e192b24SSimon Glass static int mtd_device_validate(u8 type, u8 num, u64 *size) 7202e192b24SSimon Glass { 7212e192b24SSimon Glass struct mtd_info *mtd = NULL; 7222e192b24SSimon Glass 7232e192b24SSimon Glass if (get_mtd_info(type, num, &mtd)) 7242e192b24SSimon Glass return 1; 7252e192b24SSimon Glass 7262e192b24SSimon Glass *size = mtd->size; 7272e192b24SSimon Glass 7282e192b24SSimon Glass return 0; 7292e192b24SSimon Glass } 7302e192b24SSimon Glass 7312e192b24SSimon Glass /** 7322e192b24SSimon Glass * Delete all mtd devices from a supplied devices list, free memory allocated for 7332e192b24SSimon Glass * each device and delete all device partitions. 7342e192b24SSimon Glass * 7352e192b24SSimon Glass * @return 0 on success, 1 otherwise 7362e192b24SSimon Glass */ 7372e192b24SSimon Glass static int device_delall(struct list_head *head) 7382e192b24SSimon Glass { 7392e192b24SSimon Glass struct list_head *entry, *n; 7402e192b24SSimon Glass struct mtd_device *dev_tmp; 7412e192b24SSimon Glass 7422e192b24SSimon Glass /* clean devices list */ 7432e192b24SSimon Glass list_for_each_safe(entry, n, head) { 7442e192b24SSimon Glass dev_tmp = list_entry(entry, struct mtd_device, link); 7452e192b24SSimon Glass list_del(entry); 7462e192b24SSimon Glass part_delall(&dev_tmp->parts); 7472e192b24SSimon Glass free(dev_tmp); 7482e192b24SSimon Glass } 7492e192b24SSimon Glass INIT_LIST_HEAD(&devices); 7502e192b24SSimon Glass 7512e192b24SSimon Glass return 0; 7522e192b24SSimon Glass } 7532e192b24SSimon Glass 7542e192b24SSimon Glass /** 7552e192b24SSimon Glass * If provided device exists it's partitions are deleted, device is removed 7562e192b24SSimon Glass * from device list and device memory is freed. 7572e192b24SSimon Glass * 7582e192b24SSimon Glass * @param dev device to be deleted 7592e192b24SSimon Glass * @return 0 on success, 1 otherwise 7602e192b24SSimon Glass */ 7612e192b24SSimon Glass static int device_del(struct mtd_device *dev) 7622e192b24SSimon Glass { 7632e192b24SSimon Glass part_delall(&dev->parts); 7642e192b24SSimon Glass list_del(&dev->link); 7652e192b24SSimon Glass free(dev); 7662e192b24SSimon Glass 7672e192b24SSimon Glass if (dev == current_mtd_dev) { 7682e192b24SSimon Glass /* we just deleted current device */ 7692e192b24SSimon Glass if (list_empty(&devices)) { 7702e192b24SSimon Glass current_mtd_dev = NULL; 7712e192b24SSimon Glass } else { 7722e192b24SSimon Glass /* reset first partition from first dev from the 7732e192b24SSimon Glass * devices list as current */ 7742e192b24SSimon Glass current_mtd_dev = list_entry(devices.next, struct mtd_device, link); 7752e192b24SSimon Glass current_mtd_partnum = 0; 7762e192b24SSimon Glass } 7772e192b24SSimon Glass current_save(); 7782e192b24SSimon Glass return 0; 7792e192b24SSimon Glass } 7802e192b24SSimon Glass 7812e192b24SSimon Glass index_partitions(); 7822e192b24SSimon Glass return 0; 7832e192b24SSimon Glass } 7842e192b24SSimon Glass 7852e192b24SSimon Glass /** 7862e192b24SSimon Glass * Search global device list and return pointer to the device of type and num 7872e192b24SSimon Glass * specified. 7882e192b24SSimon Glass * 7892e192b24SSimon Glass * @param type device type 7902e192b24SSimon Glass * @param num device number 7912e192b24SSimon Glass * @return NULL if requested device does not exist 7922e192b24SSimon Glass */ 7932e192b24SSimon Glass struct mtd_device *device_find(u8 type, u8 num) 7942e192b24SSimon Glass { 7952e192b24SSimon Glass struct list_head *entry; 7962e192b24SSimon Glass struct mtd_device *dev_tmp; 7972e192b24SSimon Glass 7982e192b24SSimon Glass list_for_each(entry, &devices) { 7992e192b24SSimon Glass dev_tmp = list_entry(entry, struct mtd_device, link); 8002e192b24SSimon Glass 8012e192b24SSimon Glass if ((dev_tmp->id->type == type) && (dev_tmp->id->num == num)) 8022e192b24SSimon Glass return dev_tmp; 8032e192b24SSimon Glass } 8042e192b24SSimon Glass 8052e192b24SSimon Glass return NULL; 8062e192b24SSimon Glass } 8072e192b24SSimon Glass 8082e192b24SSimon Glass /** 8092e192b24SSimon Glass * Add specified device to the global device list. 8102e192b24SSimon Glass * 8112e192b24SSimon Glass * @param dev device to be added 8122e192b24SSimon Glass */ 8132e192b24SSimon Glass static void device_add(struct mtd_device *dev) 8142e192b24SSimon Glass { 8152e192b24SSimon Glass u8 current_save_needed = 0; 8162e192b24SSimon Glass 8172e192b24SSimon Glass if (list_empty(&devices)) { 8182e192b24SSimon Glass current_mtd_dev = dev; 8192e192b24SSimon Glass current_mtd_partnum = 0; 8202e192b24SSimon Glass current_save_needed = 1; 8212e192b24SSimon Glass } 8222e192b24SSimon Glass 8232e192b24SSimon Glass list_add_tail(&dev->link, &devices); 8242e192b24SSimon Glass 8252e192b24SSimon Glass if (current_save_needed > 0) 8262e192b24SSimon Glass current_save(); 8272e192b24SSimon Glass else 8282e192b24SSimon Glass index_partitions(); 8292e192b24SSimon Glass } 8302e192b24SSimon Glass 8312e192b24SSimon Glass /** 8322e192b24SSimon Glass * Parse device type, name and mtd-id. If syntax is ok allocate memory and 8332e192b24SSimon Glass * return pointer to the device structure. 8342e192b24SSimon Glass * 8352e192b24SSimon Glass * @param mtd_dev pointer to the device definition string i.e. <mtd-dev> 8362e192b24SSimon Glass * @param ret output pointer to next char after parse completes (output) 8372e192b24SSimon Glass * @param retdev pointer to the allocated device (output) 8382e192b24SSimon Glass * @return 0 on success, 1 otherwise 8392e192b24SSimon Glass */ 8402e192b24SSimon Glass static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_device **retdev) 8412e192b24SSimon Glass { 8422e192b24SSimon Glass struct mtd_device *dev; 8432e192b24SSimon Glass struct part_info *part; 8442e192b24SSimon Glass struct mtdids *id; 8452e192b24SSimon Glass const char *mtd_id; 8462e192b24SSimon Glass unsigned int mtd_id_len; 8472e192b24SSimon Glass const char *p; 8482e192b24SSimon Glass const char *pend; 8492e192b24SSimon Glass LIST_HEAD(tmp_list); 8502e192b24SSimon Glass struct list_head *entry, *n; 8512e192b24SSimon Glass u16 num_parts; 8522e192b24SSimon Glass u64 offset; 8532e192b24SSimon Glass int err = 1; 8542e192b24SSimon Glass 8552e192b24SSimon Glass debug("===device_parse===\n"); 8562e192b24SSimon Glass 8572e192b24SSimon Glass assert(retdev); 8582e192b24SSimon Glass *retdev = NULL; 8592e192b24SSimon Glass 8602e192b24SSimon Glass if (ret) 8612e192b24SSimon Glass *ret = NULL; 8622e192b24SSimon Glass 8632e192b24SSimon Glass /* fetch <mtd-id> */ 8642e192b24SSimon Glass mtd_id = p = mtd_dev; 8652e192b24SSimon Glass if (!(p = strchr(mtd_id, ':'))) { 8662e192b24SSimon Glass printf("no <mtd-id> identifier\n"); 8672e192b24SSimon Glass return 1; 8682e192b24SSimon Glass } 8692e192b24SSimon Glass mtd_id_len = p - mtd_id + 1; 8702e192b24SSimon Glass p++; 8712e192b24SSimon Glass 8722e192b24SSimon Glass /* verify if we have a valid device specified */ 8732e192b24SSimon Glass if ((id = id_find_by_mtd_id(mtd_id, mtd_id_len - 1)) == NULL) { 8742e192b24SSimon Glass printf("invalid mtd device '%.*s'\n", mtd_id_len - 1, mtd_id); 8752e192b24SSimon Glass return 1; 8762e192b24SSimon Glass } 8772e192b24SSimon Glass 8782e192b24SSimon Glass pend = strchr(p, ';'); 8792e192b24SSimon Glass debug("dev type = %d (%s), dev num = %d, mtd-id = %s\n", 8802e192b24SSimon Glass id->type, MTD_DEV_TYPE(id->type), 8812e192b24SSimon Glass id->num, id->mtd_id); 8822e192b24SSimon Glass debug("parsing partitions %.*s\n", (int)(pend ? pend - p : strlen(p)), p); 8832e192b24SSimon Glass 8842e192b24SSimon Glass /* parse partitions */ 8852e192b24SSimon Glass num_parts = 0; 8862e192b24SSimon Glass 8872e192b24SSimon Glass offset = 0; 8882e192b24SSimon Glass if ((dev = device_find(id->type, id->num)) != NULL) { 8892e192b24SSimon Glass /* if device already exists start at the end of the last partition */ 8902e192b24SSimon Glass part = list_entry(dev->parts.prev, struct part_info, link); 8912e192b24SSimon Glass offset = part->offset + part->size; 8922e192b24SSimon Glass } 8932e192b24SSimon Glass 8942e192b24SSimon Glass while (p && (*p != '\0') && (*p != ';')) { 8952e192b24SSimon Glass err = 1; 8962e192b24SSimon Glass if ((part_parse(p, &p, &part) != 0) || (!part)) 8972e192b24SSimon Glass break; 8982e192b24SSimon Glass 8992e192b24SSimon Glass /* calculate offset when not specified */ 9002e192b24SSimon Glass if (part->offset == OFFSET_NOT_SPECIFIED) 9012e192b24SSimon Glass part->offset = offset; 9022e192b24SSimon Glass else 9032e192b24SSimon Glass offset = part->offset; 9042e192b24SSimon Glass 9052e192b24SSimon Glass /* verify alignment and size */ 9062e192b24SSimon Glass if (part_validate(id, part) != 0) 9072e192b24SSimon Glass break; 9082e192b24SSimon Glass 9092e192b24SSimon Glass offset += part->size; 9102e192b24SSimon Glass 9112e192b24SSimon Glass /* partition is ok, add it to the list */ 9122e192b24SSimon Glass list_add_tail(&part->link, &tmp_list); 9132e192b24SSimon Glass num_parts++; 9142e192b24SSimon Glass err = 0; 9152e192b24SSimon Glass } 9162e192b24SSimon Glass if (err == 1) { 9172e192b24SSimon Glass part_delall(&tmp_list); 9182e192b24SSimon Glass return 1; 9192e192b24SSimon Glass } 9202e192b24SSimon Glass 9212e192b24SSimon Glass debug("\ntotal partitions: %d\n", num_parts); 9222e192b24SSimon Glass 9232e192b24SSimon Glass /* check for next device presence */ 9242e192b24SSimon Glass if (p) { 9252e192b24SSimon Glass if (*p == ';') { 9262e192b24SSimon Glass if (ret) 9272e192b24SSimon Glass *ret = ++p; 9282e192b24SSimon Glass } else if (*p == '\0') { 9292e192b24SSimon Glass if (ret) 9302e192b24SSimon Glass *ret = p; 9312e192b24SSimon Glass } else { 9322e192b24SSimon Glass printf("unexpected character '%c' at the end of device\n", *p); 9332e192b24SSimon Glass if (ret) 9342e192b24SSimon Glass *ret = NULL; 9352e192b24SSimon Glass return 1; 9362e192b24SSimon Glass } 9372e192b24SSimon Glass } 9382e192b24SSimon Glass 9392e192b24SSimon Glass /* allocate memory for mtd_device structure */ 9402e192b24SSimon Glass if ((dev = (struct mtd_device *)malloc(sizeof(struct mtd_device))) == NULL) { 9412e192b24SSimon Glass printf("out of memory\n"); 9422e192b24SSimon Glass return 1; 9432e192b24SSimon Glass } 9442e192b24SSimon Glass memset(dev, 0, sizeof(struct mtd_device)); 9452e192b24SSimon Glass dev->id = id; 9462e192b24SSimon Glass dev->num_parts = 0; /* part_sort_add increments num_parts */ 9472e192b24SSimon Glass INIT_LIST_HEAD(&dev->parts); 9482e192b24SSimon Glass INIT_LIST_HEAD(&dev->link); 9492e192b24SSimon Glass 9502e192b24SSimon Glass /* move partitions from tmp_list to dev->parts */ 9512e192b24SSimon Glass list_for_each_safe(entry, n, &tmp_list) { 9522e192b24SSimon Glass part = list_entry(entry, struct part_info, link); 9532e192b24SSimon Glass list_del(entry); 9542e192b24SSimon Glass if (part_sort_add(dev, part) != 0) { 9552e192b24SSimon Glass device_del(dev); 9562e192b24SSimon Glass return 1; 9572e192b24SSimon Glass } 9582e192b24SSimon Glass } 9592e192b24SSimon Glass 9602e192b24SSimon Glass *retdev = dev; 9612e192b24SSimon Glass 9622e192b24SSimon Glass debug("===\n\n"); 9632e192b24SSimon Glass return 0; 9642e192b24SSimon Glass } 9652e192b24SSimon Glass 9662e192b24SSimon Glass /** 9672e192b24SSimon Glass * Initialize global device list. 9682e192b24SSimon Glass * 9692e192b24SSimon Glass * @return 0 on success, 1 otherwise 9702e192b24SSimon Glass */ 9712e192b24SSimon Glass static int mtd_devices_init(void) 9722e192b24SSimon Glass { 9732e192b24SSimon Glass last_parts[0] = '\0'; 9742e192b24SSimon Glass current_mtd_dev = NULL; 9752e192b24SSimon Glass current_save(); 9762e192b24SSimon Glass 9772e192b24SSimon Glass return device_delall(&devices); 9782e192b24SSimon Glass } 9792e192b24SSimon Glass 9802e192b24SSimon Glass /* 9812e192b24SSimon Glass * Search global mtdids list and find id of requested type and number. 9822e192b24SSimon Glass * 9832e192b24SSimon Glass * @return pointer to the id if it exists, NULL otherwise 9842e192b24SSimon Glass */ 9852e192b24SSimon Glass static struct mtdids* id_find(u8 type, u8 num) 9862e192b24SSimon Glass { 9872e192b24SSimon Glass struct list_head *entry; 9882e192b24SSimon Glass struct mtdids *id; 9892e192b24SSimon Glass 9902e192b24SSimon Glass list_for_each(entry, &mtdids) { 9912e192b24SSimon Glass id = list_entry(entry, struct mtdids, link); 9922e192b24SSimon Glass 9932e192b24SSimon Glass if ((id->type == type) && (id->num == num)) 9942e192b24SSimon Glass return id; 9952e192b24SSimon Glass } 9962e192b24SSimon Glass 9972e192b24SSimon Glass return NULL; 9982e192b24SSimon Glass } 9992e192b24SSimon Glass 10002e192b24SSimon Glass /** 10012e192b24SSimon Glass * Search global mtdids list and find id of a requested mtd_id. 10022e192b24SSimon Glass * 10032e192b24SSimon Glass * Note: first argument is not null terminated. 10042e192b24SSimon Glass * 10052e192b24SSimon Glass * @param mtd_id string containing requested mtd_id 10062e192b24SSimon Glass * @param mtd_id_len length of supplied mtd_id 10072e192b24SSimon Glass * @return pointer to the id if it exists, NULL otherwise 10082e192b24SSimon Glass */ 10092e192b24SSimon Glass static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_len) 10102e192b24SSimon Glass { 10112e192b24SSimon Glass struct list_head *entry; 10122e192b24SSimon Glass struct mtdids *id; 10132e192b24SSimon Glass 10142e192b24SSimon Glass debug("--- id_find_by_mtd_id: '%.*s' (len = %d)\n", 10152e192b24SSimon Glass mtd_id_len, mtd_id, mtd_id_len); 10162e192b24SSimon Glass 10172e192b24SSimon Glass list_for_each(entry, &mtdids) { 10182e192b24SSimon Glass id = list_entry(entry, struct mtdids, link); 10192e192b24SSimon Glass 10202e192b24SSimon Glass debug("entry: '%s' (len = %zu)\n", 10212e192b24SSimon Glass id->mtd_id, strlen(id->mtd_id)); 10222e192b24SSimon Glass 10232e192b24SSimon Glass if (mtd_id_len != strlen(id->mtd_id)) 10242e192b24SSimon Glass continue; 10252e192b24SSimon Glass if (strncmp(id->mtd_id, mtd_id, mtd_id_len) == 0) 10262e192b24SSimon Glass return id; 10272e192b24SSimon Glass } 10282e192b24SSimon Glass 10292e192b24SSimon Glass return NULL; 10302e192b24SSimon Glass } 10312e192b24SSimon Glass 10322e192b24SSimon Glass /** 103300ac922dSMiquel Raynal * Parse device id string <dev-id> := 'nand'|'nor'|'onenand'|'spi-nand'<dev-num>, 10342e192b24SSimon Glass * return device type and number. 10352e192b24SSimon Glass * 10362e192b24SSimon Glass * @param id string describing device id 10372e192b24SSimon Glass * @param ret_id output pointer to next char after parse completes (output) 10382e192b24SSimon Glass * @param dev_type parsed device type (output) 10392e192b24SSimon Glass * @param dev_num parsed device number (output) 10402e192b24SSimon Glass * @return 0 on success, 1 otherwise 10412e192b24SSimon Glass */ 10422e192b24SSimon Glass int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type, 10432e192b24SSimon Glass u8 *dev_num) 10442e192b24SSimon Glass { 10452e192b24SSimon Glass const char *p = id; 10462e192b24SSimon Glass 10472e192b24SSimon Glass *dev_type = 0; 10482e192b24SSimon Glass if (strncmp(p, "nand", 4) == 0) { 10492e192b24SSimon Glass *dev_type = MTD_DEV_TYPE_NAND; 10502e192b24SSimon Glass p += 4; 10512e192b24SSimon Glass } else if (strncmp(p, "nor", 3) == 0) { 10522e192b24SSimon Glass *dev_type = MTD_DEV_TYPE_NOR; 10532e192b24SSimon Glass p += 3; 10542e192b24SSimon Glass } else if (strncmp(p, "onenand", 7) == 0) { 10552e192b24SSimon Glass *dev_type = MTD_DEV_TYPE_ONENAND; 10562e192b24SSimon Glass p += 7; 105700ac922dSMiquel Raynal } else if (strncmp(p, "spi-nand", 8) == 0) { 105800ac922dSMiquel Raynal *dev_type = MTD_DEV_TYPE_SPINAND; 105900ac922dSMiquel Raynal p += 8; 10602e192b24SSimon Glass } else { 10612e192b24SSimon Glass printf("incorrect device type in %s\n", id); 10622e192b24SSimon Glass return 1; 10632e192b24SSimon Glass } 10642e192b24SSimon Glass 10652e192b24SSimon Glass if (!isdigit(*p)) { 10662e192b24SSimon Glass printf("incorrect device number in %s\n", id); 10672e192b24SSimon Glass return 1; 10682e192b24SSimon Glass } 10692e192b24SSimon Glass 10702e192b24SSimon Glass *dev_num = simple_strtoul(p, (char **)&p, 0); 10712e192b24SSimon Glass if (ret_id) 10722e192b24SSimon Glass *ret_id = p; 10732e192b24SSimon Glass return 0; 10742e192b24SSimon Glass } 10752e192b24SSimon Glass 10762e192b24SSimon Glass /** 10772e192b24SSimon Glass * Process all devices and generate corresponding mtdparts string describing 10782e192b24SSimon Glass * all partitions on all devices. 10792e192b24SSimon Glass * 10802e192b24SSimon Glass * @param buf output buffer holding generated mtdparts string (output) 10812e192b24SSimon Glass * @param buflen buffer size 10822e192b24SSimon Glass * @return 0 on success, 1 otherwise 10832e192b24SSimon Glass */ 10842e192b24SSimon Glass static int generate_mtdparts(char *buf, u32 buflen) 10852e192b24SSimon Glass { 10862e192b24SSimon Glass struct list_head *pentry, *dentry; 10872e192b24SSimon Glass struct mtd_device *dev; 10882e192b24SSimon Glass struct part_info *part, *prev_part; 10892e192b24SSimon Glass char *p = buf; 10902e192b24SSimon Glass char tmpbuf[32]; 10912e192b24SSimon Glass u64 size, offset; 10922e192b24SSimon Glass u32 len, part_cnt; 10932e192b24SSimon Glass u32 maxlen = buflen - 1; 10942e192b24SSimon Glass 10952e192b24SSimon Glass debug("--- generate_mtdparts ---\n"); 10962e192b24SSimon Glass 10972e192b24SSimon Glass if (list_empty(&devices)) { 10982e192b24SSimon Glass buf[0] = '\0'; 10992e192b24SSimon Glass return 0; 11002e192b24SSimon Glass } 11012e192b24SSimon Glass 11022e192b24SSimon Glass list_for_each(dentry, &devices) { 11032e192b24SSimon Glass dev = list_entry(dentry, struct mtd_device, link); 11042e192b24SSimon Glass 11052e192b24SSimon Glass /* copy mtd_id */ 11062e192b24SSimon Glass len = strlen(dev->id->mtd_id) + 1; 11072e192b24SSimon Glass if (len > maxlen) 11082e192b24SSimon Glass goto cleanup; 11092e192b24SSimon Glass memcpy(p, dev->id->mtd_id, len - 1); 11102e192b24SSimon Glass p += len - 1; 11112e192b24SSimon Glass *(p++) = ':'; 11122e192b24SSimon Glass maxlen -= len; 11132e192b24SSimon Glass 11142e192b24SSimon Glass /* format partitions */ 11152e192b24SSimon Glass prev_part = NULL; 11162e192b24SSimon Glass part_cnt = 0; 11172e192b24SSimon Glass list_for_each(pentry, &dev->parts) { 11182e192b24SSimon Glass part = list_entry(pentry, struct part_info, link); 11192e192b24SSimon Glass size = part->size; 11202e192b24SSimon Glass offset = part->offset; 11212e192b24SSimon Glass part_cnt++; 11222e192b24SSimon Glass 11232e192b24SSimon Glass /* partition size */ 11242e192b24SSimon Glass memsize_format(tmpbuf, size); 11252e192b24SSimon Glass len = strlen(tmpbuf); 11262e192b24SSimon Glass if (len > maxlen) 11272e192b24SSimon Glass goto cleanup; 11282e192b24SSimon Glass memcpy(p, tmpbuf, len); 11292e192b24SSimon Glass p += len; 11302e192b24SSimon Glass maxlen -= len; 11312e192b24SSimon Glass 11322e192b24SSimon Glass 11332e192b24SSimon Glass /* add offset only when there is a gap between 11342e192b24SSimon Glass * partitions */ 11352e192b24SSimon Glass if ((!prev_part && (offset != 0)) || 11362e192b24SSimon Glass (prev_part && ((prev_part->offset + prev_part->size) != part->offset))) { 11372e192b24SSimon Glass 11382e192b24SSimon Glass memsize_format(tmpbuf, offset); 11392e192b24SSimon Glass len = strlen(tmpbuf) + 1; 11402e192b24SSimon Glass if (len > maxlen) 11412e192b24SSimon Glass goto cleanup; 11422e192b24SSimon Glass *(p++) = '@'; 11432e192b24SSimon Glass memcpy(p, tmpbuf, len - 1); 11442e192b24SSimon Glass p += len - 1; 11452e192b24SSimon Glass maxlen -= len; 11462e192b24SSimon Glass } 11472e192b24SSimon Glass 11482e192b24SSimon Glass /* copy name only if user supplied */ 11492e192b24SSimon Glass if(!part->auto_name) { 11502e192b24SSimon Glass len = strlen(part->name) + 2; 11512e192b24SSimon Glass if (len > maxlen) 11522e192b24SSimon Glass goto cleanup; 11532e192b24SSimon Glass 11542e192b24SSimon Glass *(p++) = '('; 11552e192b24SSimon Glass memcpy(p, part->name, len - 2); 11562e192b24SSimon Glass p += len - 2; 11572e192b24SSimon Glass *(p++) = ')'; 11582e192b24SSimon Glass maxlen -= len; 11592e192b24SSimon Glass } 11602e192b24SSimon Glass 11612e192b24SSimon Glass /* ro mask flag */ 11622e192b24SSimon Glass if (part->mask_flags && MTD_WRITEABLE_CMD) { 11632e192b24SSimon Glass len = 2; 11642e192b24SSimon Glass if (len > maxlen) 11652e192b24SSimon Glass goto cleanup; 11662e192b24SSimon Glass *(p++) = 'r'; 11672e192b24SSimon Glass *(p++) = 'o'; 11682e192b24SSimon Glass maxlen -= 2; 11692e192b24SSimon Glass } 11702e192b24SSimon Glass 11712e192b24SSimon Glass /* print ',' separator if there are other partitions 11722e192b24SSimon Glass * following */ 11732e192b24SSimon Glass if (dev->num_parts > part_cnt) { 11742e192b24SSimon Glass if (1 > maxlen) 11752e192b24SSimon Glass goto cleanup; 11762e192b24SSimon Glass *(p++) = ','; 11772e192b24SSimon Glass maxlen--; 11782e192b24SSimon Glass } 11792e192b24SSimon Glass prev_part = part; 11802e192b24SSimon Glass } 11812e192b24SSimon Glass /* print ';' separator if there are other devices following */ 11822e192b24SSimon Glass if (dentry->next != &devices) { 11832e192b24SSimon Glass if (1 > maxlen) 11842e192b24SSimon Glass goto cleanup; 11852e192b24SSimon Glass *(p++) = ';'; 11862e192b24SSimon Glass maxlen--; 11872e192b24SSimon Glass } 11882e192b24SSimon Glass } 11892e192b24SSimon Glass 11902e192b24SSimon Glass /* we still have at least one char left, as we decremented maxlen at 11912e192b24SSimon Glass * the begining */ 11922e192b24SSimon Glass *p = '\0'; 11932e192b24SSimon Glass 11942e192b24SSimon Glass return 0; 11952e192b24SSimon Glass 11962e192b24SSimon Glass cleanup: 11972e192b24SSimon Glass last_parts[0] = '\0'; 11982e192b24SSimon Glass return 1; 11992e192b24SSimon Glass } 12002e192b24SSimon Glass 12012e192b24SSimon Glass /** 12022e192b24SSimon Glass * Call generate_mtdparts to process all devices and generate corresponding 12032e192b24SSimon Glass * mtdparts string, save it in mtdparts environment variable. 12042e192b24SSimon Glass * 12052e192b24SSimon Glass * @param buf output buffer holding generated mtdparts string (output) 12062e192b24SSimon Glass * @param buflen buffer size 12072e192b24SSimon Glass * @return 0 on success, 1 otherwise 12082e192b24SSimon Glass */ 12092e192b24SSimon Glass static int generate_mtdparts_save(char *buf, u32 buflen) 12102e192b24SSimon Glass { 12112e192b24SSimon Glass int ret; 12122e192b24SSimon Glass 12132e192b24SSimon Glass ret = generate_mtdparts(buf, buflen); 12142e192b24SSimon Glass 12152e192b24SSimon Glass if ((buf[0] != '\0') && (ret == 0)) 1216382bee57SSimon Glass env_set("mtdparts", buf); 12172e192b24SSimon Glass else 1218382bee57SSimon Glass env_set("mtdparts", NULL); 12192e192b24SSimon Glass 12202e192b24SSimon Glass return ret; 12212e192b24SSimon Glass } 12222e192b24SSimon Glass 12232e192b24SSimon Glass #if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) 12242e192b24SSimon Glass /** 12252e192b24SSimon Glass * Get the net size (w/o bad blocks) of the given partition. 12262e192b24SSimon Glass * 12272e192b24SSimon Glass * @param mtd the mtd info 12282e192b24SSimon Glass * @param part the partition 12292e192b24SSimon Glass * @return the calculated net size of this partition 12302e192b24SSimon Glass */ 12312e192b24SSimon Glass static uint64_t net_part_size(struct mtd_info *mtd, struct part_info *part) 12322e192b24SSimon Glass { 12332e192b24SSimon Glass uint64_t i, net_size = 0; 12342e192b24SSimon Glass 12352e192b24SSimon Glass if (!mtd->block_isbad) 12362e192b24SSimon Glass return part->size; 12372e192b24SSimon Glass 12382e192b24SSimon Glass for (i = 0; i < part->size; i += mtd->erasesize) { 12392e192b24SSimon Glass if (!mtd->block_isbad(mtd, part->offset + i)) 12402e192b24SSimon Glass net_size += mtd->erasesize; 12412e192b24SSimon Glass } 12422e192b24SSimon Glass 12432e192b24SSimon Glass return net_size; 12442e192b24SSimon Glass } 12452e192b24SSimon Glass #endif 12462e192b24SSimon Glass 12472e192b24SSimon Glass static void print_partition_table(void) 12482e192b24SSimon Glass { 12492e192b24SSimon Glass struct list_head *dentry, *pentry; 12502e192b24SSimon Glass struct part_info *part; 12512e192b24SSimon Glass struct mtd_device *dev; 12522e192b24SSimon Glass int part_num; 12532e192b24SSimon Glass 12542e192b24SSimon Glass list_for_each(dentry, &devices) { 12552e192b24SSimon Glass dev = list_entry(dentry, struct mtd_device, link); 12562e192b24SSimon Glass /* list partitions for given device */ 12572e192b24SSimon Glass part_num = 0; 12582e192b24SSimon Glass #if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) 12592e192b24SSimon Glass struct mtd_info *mtd; 12602e192b24SSimon Glass 12612e192b24SSimon Glass if (get_mtd_info(dev->id->type, dev->id->num, &mtd)) 12622e192b24SSimon Glass return; 12632e192b24SSimon Glass 12642e192b24SSimon Glass printf("\ndevice %s%d <%s>, # parts = %d\n", 12652e192b24SSimon Glass MTD_DEV_TYPE(dev->id->type), dev->id->num, 12662e192b24SSimon Glass dev->id->mtd_id, dev->num_parts); 12672e192b24SSimon Glass printf(" #: name\t\tsize\t\tnet size\toffset\t\tmask_flags\n"); 12682e192b24SSimon Glass 12692e192b24SSimon Glass list_for_each(pentry, &dev->parts) { 12702e192b24SSimon Glass u32 net_size; 12712e192b24SSimon Glass char *size_note; 12722e192b24SSimon Glass 12732e192b24SSimon Glass part = list_entry(pentry, struct part_info, link); 12742e192b24SSimon Glass net_size = net_part_size(mtd, part); 12752e192b24SSimon Glass size_note = part->size == net_size ? " " : " (!)"; 12762e192b24SSimon Glass printf("%2d: %-20s0x%08x\t0x%08x%s\t0x%08x\t%d\n", 12772e192b24SSimon Glass part_num, part->name, part->size, 12782e192b24SSimon Glass net_size, size_note, part->offset, 12792e192b24SSimon Glass part->mask_flags); 12802e192b24SSimon Glass #else /* !defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */ 12812e192b24SSimon Glass printf("\ndevice %s%d <%s>, # parts = %d\n", 12822e192b24SSimon Glass MTD_DEV_TYPE(dev->id->type), dev->id->num, 12832e192b24SSimon Glass dev->id->mtd_id, dev->num_parts); 12842e192b24SSimon Glass printf(" #: name\t\tsize\t\toffset\t\tmask_flags\n"); 12852e192b24SSimon Glass 12862e192b24SSimon Glass list_for_each(pentry, &dev->parts) { 12872e192b24SSimon Glass part = list_entry(pentry, struct part_info, link); 12882e192b24SSimon Glass printf("%2d: %-20s0x%08llx\t0x%08llx\t%d\n", 12892e192b24SSimon Glass part_num, part->name, part->size, 12902e192b24SSimon Glass part->offset, part->mask_flags); 12912e192b24SSimon Glass #endif /* defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */ 12922e192b24SSimon Glass part_num++; 12932e192b24SSimon Glass } 12942e192b24SSimon Glass } 12952e192b24SSimon Glass 12962e192b24SSimon Glass if (list_empty(&devices)) 12972e192b24SSimon Glass printf("no partitions defined\n"); 12982e192b24SSimon Glass } 12992e192b24SSimon Glass 13002e192b24SSimon Glass /** 13012e192b24SSimon Glass * Format and print out a partition list for each device from global device 13022e192b24SSimon Glass * list. 13032e192b24SSimon Glass */ 13042e192b24SSimon Glass static void list_partitions(void) 13052e192b24SSimon Glass { 13062e192b24SSimon Glass struct part_info *part; 13072e192b24SSimon Glass 13082e192b24SSimon Glass debug("\n---list_partitions---\n"); 13092e192b24SSimon Glass print_partition_table(); 13102e192b24SSimon Glass 13112e192b24SSimon Glass /* current_mtd_dev is not NULL only when we have non empty device list */ 13122e192b24SSimon Glass if (current_mtd_dev) { 13132e192b24SSimon Glass part = mtd_part_info(current_mtd_dev, current_mtd_partnum); 13142e192b24SSimon Glass if (part) { 13152e192b24SSimon Glass printf("\nactive partition: %s%d,%d - (%s) 0x%08llx @ 0x%08llx\n", 13162e192b24SSimon Glass MTD_DEV_TYPE(current_mtd_dev->id->type), 13172e192b24SSimon Glass current_mtd_dev->id->num, current_mtd_partnum, 13182e192b24SSimon Glass part->name, part->size, part->offset); 13192e192b24SSimon Glass } else { 13202e192b24SSimon Glass printf("could not get current partition info\n\n"); 13212e192b24SSimon Glass } 13222e192b24SSimon Glass } 13232e192b24SSimon Glass 13242e192b24SSimon Glass printf("\ndefaults:\n"); 13252e192b24SSimon Glass printf("mtdids : %s\n", 13262e192b24SSimon Glass mtdids_default ? mtdids_default : "none"); 13272e192b24SSimon Glass /* 13282e192b24SSimon Glass * Using printf() here results in printbuffer overflow 13292e192b24SSimon Glass * if default mtdparts string is greater than console 13302e192b24SSimon Glass * printbuffer. Use puts() to prevent system crashes. 13312e192b24SSimon Glass */ 13322e192b24SSimon Glass puts("mtdparts: "); 13332e192b24SSimon Glass puts(mtdparts_default ? mtdparts_default : "none"); 13342e192b24SSimon Glass puts("\n"); 13352e192b24SSimon Glass } 13362e192b24SSimon Glass 13372e192b24SSimon Glass /** 13382e192b24SSimon Glass * Given partition identifier in form of <dev_type><dev_num>,<part_num> find 13392e192b24SSimon Glass * corresponding device and verify partition number. 13402e192b24SSimon Glass * 13412e192b24SSimon Glass * @param id string describing device and partition or partition name 13422e192b24SSimon Glass * @param dev pointer to the requested device (output) 13432e192b24SSimon Glass * @param part_num verified partition number (output) 13442e192b24SSimon Glass * @param part pointer to requested partition (output) 13452e192b24SSimon Glass * @return 0 on success, 1 otherwise 13462e192b24SSimon Glass */ 13472e192b24SSimon Glass int find_dev_and_part(const char *id, struct mtd_device **dev, 13482e192b24SSimon Glass u8 *part_num, struct part_info **part) 13492e192b24SSimon Glass { 13502e192b24SSimon Glass struct list_head *dentry, *pentry; 13512e192b24SSimon Glass u8 type, dnum, pnum; 13522e192b24SSimon Glass const char *p; 13532e192b24SSimon Glass 13542e192b24SSimon Glass debug("--- find_dev_and_part ---\nid = %s\n", id); 13552e192b24SSimon Glass 13562e192b24SSimon Glass list_for_each(dentry, &devices) { 13572e192b24SSimon Glass *part_num = 0; 13582e192b24SSimon Glass *dev = list_entry(dentry, struct mtd_device, link); 13592e192b24SSimon Glass list_for_each(pentry, &(*dev)->parts) { 13602e192b24SSimon Glass *part = list_entry(pentry, struct part_info, link); 13612e192b24SSimon Glass if (strcmp((*part)->name, id) == 0) 13622e192b24SSimon Glass return 0; 13632e192b24SSimon Glass (*part_num)++; 13642e192b24SSimon Glass } 13652e192b24SSimon Glass } 13662e192b24SSimon Glass 13672e192b24SSimon Glass p = id; 13682e192b24SSimon Glass *dev = NULL; 13692e192b24SSimon Glass *part = NULL; 13702e192b24SSimon Glass *part_num = 0; 13712e192b24SSimon Glass 13722e192b24SSimon Glass if (mtd_id_parse(p, &p, &type, &dnum) != 0) 13732e192b24SSimon Glass return 1; 13742e192b24SSimon Glass 13752e192b24SSimon Glass if ((*p++ != ',') || (*p == '\0')) { 13762e192b24SSimon Glass printf("no partition number specified\n"); 13772e192b24SSimon Glass return 1; 13782e192b24SSimon Glass } 13792e192b24SSimon Glass pnum = simple_strtoul(p, (char **)&p, 0); 13802e192b24SSimon Glass if (*p != '\0') { 13812e192b24SSimon Glass printf("unexpected trailing character '%c'\n", *p); 13822e192b24SSimon Glass return 1; 13832e192b24SSimon Glass } 13842e192b24SSimon Glass 13852e192b24SSimon Glass if ((*dev = device_find(type, dnum)) == NULL) { 13862e192b24SSimon Glass printf("no such device %s%d\n", MTD_DEV_TYPE(type), dnum); 13872e192b24SSimon Glass return 1; 13882e192b24SSimon Glass } 13892e192b24SSimon Glass 13902e192b24SSimon Glass if ((*part = mtd_part_info(*dev, pnum)) == NULL) { 13912e192b24SSimon Glass printf("no such partition\n"); 13922e192b24SSimon Glass *dev = NULL; 13932e192b24SSimon Glass return 1; 13942e192b24SSimon Glass } 13952e192b24SSimon Glass 13962e192b24SSimon Glass *part_num = pnum; 13972e192b24SSimon Glass 13982e192b24SSimon Glass return 0; 13992e192b24SSimon Glass } 14002e192b24SSimon Glass 14012e192b24SSimon Glass /** 14022e192b24SSimon Glass * Find and delete partition. For partition id format see find_dev_and_part(). 14032e192b24SSimon Glass * 14042e192b24SSimon Glass * @param id string describing device and partition 14052e192b24SSimon Glass * @return 0 on success, 1 otherwise 14062e192b24SSimon Glass */ 14072e192b24SSimon Glass static int delete_partition(const char *id) 14082e192b24SSimon Glass { 14092e192b24SSimon Glass u8 pnum; 14102e192b24SSimon Glass struct mtd_device *dev; 14112e192b24SSimon Glass struct part_info *part; 14122e192b24SSimon Glass 14132e192b24SSimon Glass if (find_dev_and_part(id, &dev, &pnum, &part) == 0) { 14142e192b24SSimon Glass 14152e192b24SSimon Glass debug("delete_partition: device = %s%d, partition %d = (%s) 0x%08llx@0x%08llx\n", 14162e192b24SSimon Glass MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum, 14172e192b24SSimon Glass part->name, part->size, part->offset); 14182e192b24SSimon Glass 14192e192b24SSimon Glass if (part_del(dev, part) != 0) 14202e192b24SSimon Glass return 1; 14212e192b24SSimon Glass 14222e192b24SSimon Glass if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) { 14232e192b24SSimon Glass printf("generated mtdparts too long, resetting to null\n"); 14242e192b24SSimon Glass return 1; 14252e192b24SSimon Glass } 14262e192b24SSimon Glass return 0; 14272e192b24SSimon Glass } 14282e192b24SSimon Glass 14292e192b24SSimon Glass printf("partition %s not found\n", id); 14302e192b24SSimon Glass return 1; 14312e192b24SSimon Glass } 14322e192b24SSimon Glass 14332e192b24SSimon Glass #if defined(CONFIG_CMD_MTDPARTS_SPREAD) 14342e192b24SSimon Glass /** 14352e192b24SSimon Glass * Increase the size of the given partition so that it's net size is at least 14362e192b24SSimon Glass * as large as the size member and such that the next partition would start on a 14372e192b24SSimon Glass * good block if it were adjacent to this partition. 14382e192b24SSimon Glass * 14392e192b24SSimon Glass * @param mtd the mtd device 14402e192b24SSimon Glass * @param part the partition 14412e192b24SSimon Glass * @param next_offset pointer to the offset of the next partition after this 14422e192b24SSimon Glass * partition's size has been modified (output) 14432e192b24SSimon Glass */ 14442e192b24SSimon Glass static void spread_partition(struct mtd_info *mtd, struct part_info *part, 14452e192b24SSimon Glass uint64_t *next_offset) 14462e192b24SSimon Glass { 14472e192b24SSimon Glass uint64_t net_size, padding_size = 0; 14482e192b24SSimon Glass int truncated; 14492e192b24SSimon Glass 14502e192b24SSimon Glass mtd_get_len_incl_bad(mtd, part->offset, part->size, &net_size, 14512e192b24SSimon Glass &truncated); 14522e192b24SSimon Glass 14532e192b24SSimon Glass /* 14542e192b24SSimon Glass * Absorb bad blocks immediately following this 14552e192b24SSimon Glass * partition also into the partition, such that 14562e192b24SSimon Glass * the next partition starts with a good block. 14572e192b24SSimon Glass */ 14582e192b24SSimon Glass if (!truncated) { 14592e192b24SSimon Glass mtd_get_len_incl_bad(mtd, part->offset + net_size, 14602e192b24SSimon Glass mtd->erasesize, &padding_size, &truncated); 14612e192b24SSimon Glass if (truncated) 14622e192b24SSimon Glass padding_size = 0; 14632e192b24SSimon Glass else 14642e192b24SSimon Glass padding_size -= mtd->erasesize; 14652e192b24SSimon Glass } 14662e192b24SSimon Glass 14672e192b24SSimon Glass if (truncated) { 14682e192b24SSimon Glass printf("truncated partition %s to %lld bytes\n", part->name, 14692e192b24SSimon Glass (uint64_t) net_size + padding_size); 14702e192b24SSimon Glass } 14712e192b24SSimon Glass 14722e192b24SSimon Glass part->size = net_size + padding_size; 14732e192b24SSimon Glass *next_offset = part->offset + part->size; 14742e192b24SSimon Glass } 14752e192b24SSimon Glass 14762e192b24SSimon Glass /** 14772e192b24SSimon Glass * Adjust all of the partition sizes, such that all partitions are at least 14782e192b24SSimon Glass * as big as their mtdparts environment variable sizes and they each start 14792e192b24SSimon Glass * on a good block. 14802e192b24SSimon Glass * 14812e192b24SSimon Glass * @return 0 on success, 1 otherwise 14822e192b24SSimon Glass */ 14832e192b24SSimon Glass static int spread_partitions(void) 14842e192b24SSimon Glass { 14852e192b24SSimon Glass struct list_head *dentry, *pentry; 14862e192b24SSimon Glass struct mtd_device *dev; 14872e192b24SSimon Glass struct part_info *part; 14882e192b24SSimon Glass struct mtd_info *mtd; 14892e192b24SSimon Glass int part_num; 14902e192b24SSimon Glass uint64_t cur_offs; 14912e192b24SSimon Glass 14922e192b24SSimon Glass list_for_each(dentry, &devices) { 14932e192b24SSimon Glass dev = list_entry(dentry, struct mtd_device, link); 14942e192b24SSimon Glass 14952e192b24SSimon Glass if (get_mtd_info(dev->id->type, dev->id->num, &mtd)) 14962e192b24SSimon Glass return 1; 14972e192b24SSimon Glass 14982e192b24SSimon Glass part_num = 0; 14992e192b24SSimon Glass cur_offs = 0; 15002e192b24SSimon Glass list_for_each(pentry, &dev->parts) { 15012e192b24SSimon Glass part = list_entry(pentry, struct part_info, link); 15022e192b24SSimon Glass 15032e192b24SSimon Glass debug("spread_partitions: device = %s%d, partition %d =" 150459441ac3SSteve Rae " (%s) 0x%08llx@0x%08llx\n", 15052e192b24SSimon Glass MTD_DEV_TYPE(dev->id->type), dev->id->num, 15062e192b24SSimon Glass part_num, part->name, part->size, 15072e192b24SSimon Glass part->offset); 15082e192b24SSimon Glass 15092e192b24SSimon Glass if (cur_offs > part->offset) 15102e192b24SSimon Glass part->offset = cur_offs; 15112e192b24SSimon Glass 15122e192b24SSimon Glass spread_partition(mtd, part, &cur_offs); 15132e192b24SSimon Glass 15142e192b24SSimon Glass part_num++; 15152e192b24SSimon Glass } 15162e192b24SSimon Glass } 15172e192b24SSimon Glass 15182e192b24SSimon Glass index_partitions(); 15192e192b24SSimon Glass 15202e192b24SSimon Glass if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) { 15212e192b24SSimon Glass printf("generated mtdparts too long, resetting to null\n"); 15222e192b24SSimon Glass return 1; 15232e192b24SSimon Glass } 15242e192b24SSimon Glass return 0; 15252e192b24SSimon Glass } 15262e192b24SSimon Glass #endif /* CONFIG_CMD_MTDPARTS_SPREAD */ 15272e192b24SSimon Glass 15282e192b24SSimon Glass /** 15291c2a262aSLadislav Michl * The mtdparts variable tends to be long. If we need to access it 15301c2a262aSLadislav Michl * before the env is relocated, then we need to use our own stack 15311c2a262aSLadislav Michl * buffer. gd->env_buf will be too small. 15321c2a262aSLadislav Michl * 15331c2a262aSLadislav Michl * @param buf temporary buffer pointer MTDPARTS_MAXLEN long 15341c2a262aSLadislav Michl * @return mtdparts variable string, NULL if not found 15351c2a262aSLadislav Michl */ 1536723806ccSSimon Glass static const char *env_get_mtdparts(char *buf) 15371c2a262aSLadislav Michl { 15381c2a262aSLadislav Michl if (gd->flags & GD_FLG_ENV_READY) 153900caae6dSSimon Glass return env_get("mtdparts"); 154000caae6dSSimon Glass if (env_get_f("mtdparts", buf, MTDPARTS_MAXLEN) != -1) 15411c2a262aSLadislav Michl return buf; 15421c2a262aSLadislav Michl return NULL; 15431c2a262aSLadislav Michl } 15441c2a262aSLadislav Michl 15451c2a262aSLadislav Michl /** 15462e192b24SSimon Glass * Accept character string describing mtd partitions and call device_parse() 15472e192b24SSimon Glass * for each entry. Add created devices to the global devices list. 15482e192b24SSimon Glass * 15492e192b24SSimon Glass * @param mtdparts string specifing mtd partitions 15502e192b24SSimon Glass * @return 0 on success, 1 otherwise 15512e192b24SSimon Glass */ 15522e192b24SSimon Glass static int parse_mtdparts(const char *const mtdparts) 15532e192b24SSimon Glass { 155406a040a3SLadislav Michl const char *p; 15552e192b24SSimon Glass struct mtd_device *dev; 15562e192b24SSimon Glass int err = 1; 15572e192b24SSimon Glass char tmp_parts[MTDPARTS_MAXLEN]; 15582e192b24SSimon Glass 15591aca4d5aSLothar Waßmann debug("\n---parse_mtdparts---\nmtdparts = %s\n\n", mtdparts); 15602e192b24SSimon Glass 15612e192b24SSimon Glass /* delete all devices and partitions */ 15622e192b24SSimon Glass if (mtd_devices_init() != 0) { 15632e192b24SSimon Glass printf("could not initialise device list\n"); 15642e192b24SSimon Glass return err; 15652e192b24SSimon Glass } 15662e192b24SSimon Glass 15672e192b24SSimon Glass /* re-read 'mtdparts' variable, mtd_devices_init may be updating env */ 1568723806ccSSimon Glass p = env_get_mtdparts(tmp_parts); 156906a040a3SLadislav Michl if (!p) 157006a040a3SLadislav Michl p = mtdparts; 157106a040a3SLadislav Michl 1572*d60aea94SMiquel Raynal /* Skip the useless prefix, if any */ 1573*d60aea94SMiquel Raynal if (strncmp(p, "mtdparts=", 9) == 0) 15742e192b24SSimon Glass p += 9; 15752e192b24SSimon Glass 157606a040a3SLadislav Michl while (*p != '\0') { 15772e192b24SSimon Glass err = 1; 15782e192b24SSimon Glass if ((device_parse(p, &p, &dev) != 0) || (!dev)) 15792e192b24SSimon Glass break; 15802e192b24SSimon Glass 15812e192b24SSimon Glass debug("+ device: %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type), 15822e192b24SSimon Glass dev->id->num, dev->id->mtd_id); 15832e192b24SSimon Glass 15842e192b24SSimon Glass /* check if parsed device is already on the list */ 15852e192b24SSimon Glass if (device_find(dev->id->type, dev->id->num) != NULL) { 15862e192b24SSimon Glass printf("device %s%d redefined, please correct mtdparts variable\n", 15872e192b24SSimon Glass MTD_DEV_TYPE(dev->id->type), dev->id->num); 15882e192b24SSimon Glass break; 15892e192b24SSimon Glass } 15902e192b24SSimon Glass 15912e192b24SSimon Glass list_add_tail(&dev->link, &devices); 15922e192b24SSimon Glass err = 0; 15932e192b24SSimon Glass } 159454f1792cSTom Rini if (err == 1) { 159554f1792cSTom Rini free(dev); 15962e192b24SSimon Glass device_delall(&devices); 159754f1792cSTom Rini } 15982e192b24SSimon Glass 159906a040a3SLadislav Michl return err; 16002e192b24SSimon Glass } 16012e192b24SSimon Glass 16022e192b24SSimon Glass /** 16032e192b24SSimon Glass * Parse provided string describing mtdids mapping (see file header for mtdids 16042e192b24SSimon Glass * variable format). Allocate memory for each entry and add all found entries 16052e192b24SSimon Glass * to the global mtdids list. 16062e192b24SSimon Glass * 16072e192b24SSimon Glass * @param ids mapping string 16082e192b24SSimon Glass * @return 0 on success, 1 otherwise 16092e192b24SSimon Glass */ 16102e192b24SSimon Glass static int parse_mtdids(const char *const ids) 16112e192b24SSimon Glass { 16122e192b24SSimon Glass const char *p = ids; 16132e192b24SSimon Glass const char *mtd_id; 16142e192b24SSimon Glass int mtd_id_len; 16152e192b24SSimon Glass struct mtdids *id; 16162e192b24SSimon Glass struct list_head *entry, *n; 16172e192b24SSimon Glass struct mtdids *id_tmp; 16182e192b24SSimon Glass u8 type, num; 16192e192b24SSimon Glass u64 size; 16202e192b24SSimon Glass int ret = 1; 16212e192b24SSimon Glass 16222e192b24SSimon Glass debug("\n---parse_mtdids---\nmtdids = %s\n\n", ids); 16232e192b24SSimon Glass 16242e192b24SSimon Glass /* clean global mtdids list */ 16252e192b24SSimon Glass list_for_each_safe(entry, n, &mtdids) { 16262e192b24SSimon Glass id_tmp = list_entry(entry, struct mtdids, link); 16272e192b24SSimon Glass debug("mtdids del: %d %d\n", id_tmp->type, id_tmp->num); 16282e192b24SSimon Glass list_del(entry); 16292e192b24SSimon Glass free(id_tmp); 16302e192b24SSimon Glass } 16312e192b24SSimon Glass last_ids[0] = '\0'; 16322e192b24SSimon Glass INIT_LIST_HEAD(&mtdids); 16332e192b24SSimon Glass 16342e192b24SSimon Glass while(p && (*p != '\0')) { 16352e192b24SSimon Glass 16362e192b24SSimon Glass ret = 1; 163700ac922dSMiquel Raynal /* parse 'nor'|'nand'|'onenand'|'spi-nand'<dev-num> */ 16382e192b24SSimon Glass if (mtd_id_parse(p, &p, &type, &num) != 0) 16392e192b24SSimon Glass break; 16402e192b24SSimon Glass 16412e192b24SSimon Glass if (*p != '=') { 16422e192b24SSimon Glass printf("mtdids: incorrect <dev-num>\n"); 16432e192b24SSimon Glass break; 16442e192b24SSimon Glass } 16452e192b24SSimon Glass p++; 16462e192b24SSimon Glass 16472e192b24SSimon Glass /* check if requested device exists */ 16482e192b24SSimon Glass if (mtd_device_validate(type, num, &size) != 0) 16492e192b24SSimon Glass return 1; 16502e192b24SSimon Glass 16512e192b24SSimon Glass /* locate <mtd-id> */ 16522e192b24SSimon Glass mtd_id = p; 16532e192b24SSimon Glass if ((p = strchr(mtd_id, ',')) != NULL) { 16542e192b24SSimon Glass mtd_id_len = p - mtd_id + 1; 16552e192b24SSimon Glass p++; 16562e192b24SSimon Glass } else { 16572e192b24SSimon Glass mtd_id_len = strlen(mtd_id) + 1; 16582e192b24SSimon Glass } 16592e192b24SSimon Glass if (mtd_id_len == 0) { 16602e192b24SSimon Glass printf("mtdids: no <mtd-id> identifier\n"); 16612e192b24SSimon Glass break; 16622e192b24SSimon Glass } 16632e192b24SSimon Glass 16642e192b24SSimon Glass /* check if this id is already on the list */ 16652e192b24SSimon Glass int double_entry = 0; 16662e192b24SSimon Glass list_for_each(entry, &mtdids) { 16672e192b24SSimon Glass id_tmp = list_entry(entry, struct mtdids, link); 16682e192b24SSimon Glass if ((id_tmp->type == type) && (id_tmp->num == num)) { 16692e192b24SSimon Glass double_entry = 1; 16702e192b24SSimon Glass break; 16712e192b24SSimon Glass } 16722e192b24SSimon Glass } 16732e192b24SSimon Glass if (double_entry) { 16742e192b24SSimon Glass printf("device id %s%d redefined, please correct mtdids variable\n", 16752e192b24SSimon Glass MTD_DEV_TYPE(type), num); 16762e192b24SSimon Glass break; 16772e192b24SSimon Glass } 16782e192b24SSimon Glass 16792e192b24SSimon Glass /* allocate mtdids structure */ 16802e192b24SSimon Glass if (!(id = (struct mtdids *)malloc(sizeof(struct mtdids) + mtd_id_len))) { 16812e192b24SSimon Glass printf("out of memory\n"); 16822e192b24SSimon Glass break; 16832e192b24SSimon Glass } 16842e192b24SSimon Glass memset(id, 0, sizeof(struct mtdids) + mtd_id_len); 16852e192b24SSimon Glass id->num = num; 16862e192b24SSimon Glass id->type = type; 16872e192b24SSimon Glass id->size = size; 16882e192b24SSimon Glass id->mtd_id = (char *)(id + 1); 16892e192b24SSimon Glass strncpy(id->mtd_id, mtd_id, mtd_id_len - 1); 16902e192b24SSimon Glass id->mtd_id[mtd_id_len - 1] = '\0'; 16912e192b24SSimon Glass INIT_LIST_HEAD(&id->link); 16922e192b24SSimon Glass 16932e192b24SSimon Glass debug("+ id %s%d\t%16lld bytes\t%s\n", 16942e192b24SSimon Glass MTD_DEV_TYPE(id->type), id->num, 16952e192b24SSimon Glass id->size, id->mtd_id); 16962e192b24SSimon Glass 16972e192b24SSimon Glass list_add_tail(&id->link, &mtdids); 16982e192b24SSimon Glass ret = 0; 16992e192b24SSimon Glass } 17002e192b24SSimon Glass if (ret == 1) { 17012e192b24SSimon Glass /* clean mtdids list and free allocated memory */ 17022e192b24SSimon Glass list_for_each_safe(entry, n, &mtdids) { 17032e192b24SSimon Glass id_tmp = list_entry(entry, struct mtdids, link); 17042e192b24SSimon Glass list_del(entry); 17052e192b24SSimon Glass free(id_tmp); 17062e192b24SSimon Glass } 17072e192b24SSimon Glass return 1; 17082e192b24SSimon Glass } 17092e192b24SSimon Glass 17102e192b24SSimon Glass return 0; 17112e192b24SSimon Glass } 17122e192b24SSimon Glass 17131c2a262aSLadislav Michl 17142e192b24SSimon Glass /** 17152e192b24SSimon Glass * Parse and initialize global mtdids mapping and create global 17162e192b24SSimon Glass * device/partition list. 17172e192b24SSimon Glass * 17182e192b24SSimon Glass * @return 0 on success, 1 otherwise 17192e192b24SSimon Glass */ 17202e192b24SSimon Glass int mtdparts_init(void) 17212e192b24SSimon Glass { 17222e192b24SSimon Glass static int initialized = 0; 17232e192b24SSimon Glass const char *ids, *parts; 17242e192b24SSimon Glass const char *current_partition; 17252e192b24SSimon Glass int ids_changed; 1726bc028345STom Rini char tmp_ep[PARTITION_MAXLEN + 1]; 17272e192b24SSimon Glass char tmp_parts[MTDPARTS_MAXLEN]; 17282e192b24SSimon Glass 17292e192b24SSimon Glass debug("\n---mtdparts_init---\n"); 17302e192b24SSimon Glass if (!initialized) { 17312e192b24SSimon Glass INIT_LIST_HEAD(&mtdids); 17322e192b24SSimon Glass INIT_LIST_HEAD(&devices); 173354f1792cSTom Rini memset(last_ids, 0, sizeof(last_ids)); 173454f1792cSTom Rini memset(last_parts, 0, sizeof(last_parts)); 173554f1792cSTom Rini memset(last_partition, 0, sizeof(last_partition)); 1736af324436SLadislav Michl #if defined(CONFIG_SYS_MTDPARTS_RUNTIME) 1737af324436SLadislav Michl board_mtdparts_default(&mtdids_default, &mtdparts_default); 1738af324436SLadislav Michl #endif 1739f8f744a3SLadislav Michl use_defaults = 1; 17402e192b24SSimon Glass initialized = 1; 17412e192b24SSimon Glass } 17422e192b24SSimon Glass 17432e192b24SSimon Glass /* get variables */ 174400caae6dSSimon Glass ids = env_get("mtdids"); 1745723806ccSSimon Glass parts = env_get_mtdparts(tmp_parts); 174600caae6dSSimon Glass current_partition = env_get("partition"); 17472e192b24SSimon Glass 17482e192b24SSimon Glass /* save it for later parsing, cannot rely on current partition pointer 17492e192b24SSimon Glass * as 'partition' variable may be updated during init */ 1750bc028345STom Rini memset(tmp_parts, 0, sizeof(tmp_parts)); 17518b3cec7dSTom Rini memset(tmp_ep, 0, sizeof(tmp_ep)); 17522e192b24SSimon Glass if (current_partition) 17532e192b24SSimon Glass strncpy(tmp_ep, current_partition, PARTITION_MAXLEN); 17542e192b24SSimon Glass 17552e192b24SSimon Glass debug("last_ids : %s\n", last_ids); 17562e192b24SSimon Glass debug("env_ids : %s\n", ids); 17572e192b24SSimon Glass debug("last_parts: %s\n", last_parts); 17582e192b24SSimon Glass debug("env_parts : %s\n\n", parts); 17592e192b24SSimon Glass 17602e192b24SSimon Glass debug("last_partition : %s\n", last_partition); 17612e192b24SSimon Glass debug("env_partition : %s\n", current_partition); 17622e192b24SSimon Glass 17631cc0a9f4SRobert P. J. Day /* if mtdids variable is empty try to use defaults */ 17642e192b24SSimon Glass if (!ids) { 17652e192b24SSimon Glass if (mtdids_default) { 17662e192b24SSimon Glass debug("mtdids variable not defined, using default\n"); 17672e192b24SSimon Glass ids = mtdids_default; 1768382bee57SSimon Glass env_set("mtdids", (char *)ids); 17692e192b24SSimon Glass } else { 17702e192b24SSimon Glass printf("mtdids not defined, no default present\n"); 17712e192b24SSimon Glass return 1; 17722e192b24SSimon Glass } 17732e192b24SSimon Glass } 17742e192b24SSimon Glass if (strlen(ids) > MTDIDS_MAXLEN - 1) { 17752e192b24SSimon Glass printf("mtdids too long (> %d)\n", MTDIDS_MAXLEN); 17762e192b24SSimon Glass return 1; 17772e192b24SSimon Glass } 17782e192b24SSimon Glass 1779f8f744a3SLadislav Michl /* use defaults when mtdparts variable is not defined 1780f8f744a3SLadislav Michl * once mtdparts is saved environment, drop use_defaults flag */ 1781f8f744a3SLadislav Michl if (!parts) { 1782f8f744a3SLadislav Michl if (mtdparts_default && use_defaults) { 1783f8f744a3SLadislav Michl parts = mtdparts_default; 1784382bee57SSimon Glass if (env_set("mtdparts", (char *)parts) == 0) 1785f8f744a3SLadislav Michl use_defaults = 0; 1786f8f744a3SLadislav Michl } else 17872e192b24SSimon Glass printf("mtdparts variable not set, see 'help mtdparts'\n"); 1788f8f744a3SLadislav Michl } 17892e192b24SSimon Glass 17902e192b24SSimon Glass if (parts && (strlen(parts) > MTDPARTS_MAXLEN - 1)) { 17912e192b24SSimon Glass printf("mtdparts too long (> %d)\n", MTDPARTS_MAXLEN); 17922e192b24SSimon Glass return 1; 17932e192b24SSimon Glass } 17942e192b24SSimon Glass 17952e192b24SSimon Glass /* check if we have already parsed those mtdids */ 17962e192b24SSimon Glass if ((last_ids[0] != '\0') && (strcmp(last_ids, ids) == 0)) { 17972e192b24SSimon Glass ids_changed = 0; 17982e192b24SSimon Glass } else { 17992e192b24SSimon Glass ids_changed = 1; 18002e192b24SSimon Glass 18012e192b24SSimon Glass if (parse_mtdids(ids) != 0) { 18022e192b24SSimon Glass mtd_devices_init(); 18032e192b24SSimon Glass return 1; 18042e192b24SSimon Glass } 18052e192b24SSimon Glass 18062e192b24SSimon Glass /* ok it's good, save new ids */ 18072e192b24SSimon Glass strncpy(last_ids, ids, MTDIDS_MAXLEN); 18082e192b24SSimon Glass } 18092e192b24SSimon Glass 18102e192b24SSimon Glass /* parse partitions if either mtdparts or mtdids were updated */ 18112e192b24SSimon Glass if (parts && ((last_parts[0] == '\0') || ((strcmp(last_parts, parts) != 0)) || ids_changed)) { 18122e192b24SSimon Glass if (parse_mtdparts(parts) != 0) 18132e192b24SSimon Glass return 1; 18142e192b24SSimon Glass 18152e192b24SSimon Glass if (list_empty(&devices)) { 18162e192b24SSimon Glass printf("mtdparts_init: no valid partitions\n"); 18172e192b24SSimon Glass return 1; 18182e192b24SSimon Glass } 18192e192b24SSimon Glass 18202e192b24SSimon Glass /* ok it's good, save new parts */ 18212e192b24SSimon Glass strncpy(last_parts, parts, MTDPARTS_MAXLEN); 18222e192b24SSimon Glass 18232e192b24SSimon Glass /* reset first partition from first dev from the list as current */ 18242e192b24SSimon Glass current_mtd_dev = list_entry(devices.next, struct mtd_device, link); 18252e192b24SSimon Glass current_mtd_partnum = 0; 18262e192b24SSimon Glass current_save(); 18272e192b24SSimon Glass 18282e192b24SSimon Glass debug("mtdparts_init: current_mtd_dev = %s%d, current_mtd_partnum = %d\n", 18292e192b24SSimon Glass MTD_DEV_TYPE(current_mtd_dev->id->type), 18302e192b24SSimon Glass current_mtd_dev->id->num, current_mtd_partnum); 18312e192b24SSimon Glass } 18322e192b24SSimon Glass 18332e192b24SSimon Glass /* mtdparts variable was reset to NULL, delete all devices/partitions */ 18342e192b24SSimon Glass if (!parts && (last_parts[0] != '\0')) 18352e192b24SSimon Glass return mtd_devices_init(); 18362e192b24SSimon Glass 18372e192b24SSimon Glass /* do not process current partition if mtdparts variable is null */ 18382e192b24SSimon Glass if (!parts) 18392e192b24SSimon Glass return 0; 18402e192b24SSimon Glass 18412e192b24SSimon Glass /* is current partition set in environment? if so, use it */ 18422e192b24SSimon Glass if ((tmp_ep[0] != '\0') && (strcmp(tmp_ep, last_partition) != 0)) { 18432e192b24SSimon Glass struct part_info *p; 18442e192b24SSimon Glass struct mtd_device *cdev; 18452e192b24SSimon Glass u8 pnum; 18462e192b24SSimon Glass 18472e192b24SSimon Glass debug("--- getting current partition: %s\n", tmp_ep); 18482e192b24SSimon Glass 18492e192b24SSimon Glass if (find_dev_and_part(tmp_ep, &cdev, &pnum, &p) == 0) { 18502e192b24SSimon Glass current_mtd_dev = cdev; 18512e192b24SSimon Glass current_mtd_partnum = pnum; 18522e192b24SSimon Glass current_save(); 18532e192b24SSimon Glass } 185400caae6dSSimon Glass } else if (env_get("partition") == NULL) { 18552e192b24SSimon Glass debug("no partition variable set, setting...\n"); 18562e192b24SSimon Glass current_save(); 18572e192b24SSimon Glass } 18582e192b24SSimon Glass 18592e192b24SSimon Glass return 0; 18602e192b24SSimon Glass } 18612e192b24SSimon Glass 18622e192b24SSimon Glass /** 18632e192b24SSimon Glass * Return pointer to the partition of a requested number from a requested 18642e192b24SSimon Glass * device. 18652e192b24SSimon Glass * 18662e192b24SSimon Glass * @param dev device that is to be searched for a partition 18672e192b24SSimon Glass * @param part_num requested partition number 18682e192b24SSimon Glass * @return pointer to the part_info, NULL otherwise 18692e192b24SSimon Glass */ 18702e192b24SSimon Glass static struct part_info* mtd_part_info(struct mtd_device *dev, unsigned int part_num) 18712e192b24SSimon Glass { 18722e192b24SSimon Glass struct list_head *entry; 18732e192b24SSimon Glass struct part_info *part; 18742e192b24SSimon Glass int num; 18752e192b24SSimon Glass 18762e192b24SSimon Glass if (!dev) 18772e192b24SSimon Glass return NULL; 18782e192b24SSimon Glass 18792e192b24SSimon Glass debug("\n--- mtd_part_info: partition number %d for device %s%d (%s)\n", 18802e192b24SSimon Glass part_num, MTD_DEV_TYPE(dev->id->type), 18812e192b24SSimon Glass dev->id->num, dev->id->mtd_id); 18822e192b24SSimon Glass 18832e192b24SSimon Glass if (part_num >= dev->num_parts) { 18842e192b24SSimon Glass printf("invalid partition number %d for device %s%d (%s)\n", 18852e192b24SSimon Glass part_num, MTD_DEV_TYPE(dev->id->type), 18862e192b24SSimon Glass dev->id->num, dev->id->mtd_id); 18872e192b24SSimon Glass return NULL; 18882e192b24SSimon Glass } 18892e192b24SSimon Glass 18902e192b24SSimon Glass /* locate partition number, return it */ 18912e192b24SSimon Glass num = 0; 18922e192b24SSimon Glass list_for_each(entry, &dev->parts) { 18932e192b24SSimon Glass part = list_entry(entry, struct part_info, link); 18942e192b24SSimon Glass 18952e192b24SSimon Glass if (part_num == num++) { 18962e192b24SSimon Glass return part; 18972e192b24SSimon Glass } 18982e192b24SSimon Glass } 18992e192b24SSimon Glass 19002e192b24SSimon Glass return NULL; 19012e192b24SSimon Glass } 19022e192b24SSimon Glass 19032e192b24SSimon Glass /***************************************************/ 1904a187559eSBin Meng /* U-Boot commands */ 19052e192b24SSimon Glass /***************************************************/ 19062e192b24SSimon Glass /* command line only */ 19072e192b24SSimon Glass /** 19082e192b24SSimon Glass * Routine implementing u-boot chpart command. Sets new current partition based 19092e192b24SSimon Glass * on the user supplied partition id. For partition id format see find_dev_and_part(). 19102e192b24SSimon Glass * 19112e192b24SSimon Glass * @param cmdtp command internal data 19122e192b24SSimon Glass * @param flag command flag 19132e192b24SSimon Glass * @param argc number of arguments supplied to the command 19142e192b24SSimon Glass * @param argv arguments list 19152e192b24SSimon Glass * @return 0 on success, 1 otherwise 19162e192b24SSimon Glass */ 19172e192b24SSimon Glass static int do_chpart(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 19182e192b24SSimon Glass { 19192e192b24SSimon Glass /* command line only */ 19202e192b24SSimon Glass struct mtd_device *dev; 19212e192b24SSimon Glass struct part_info *part; 19222e192b24SSimon Glass u8 pnum; 19232e192b24SSimon Glass 19242e192b24SSimon Glass if (mtdparts_init() !=0) 19252e192b24SSimon Glass return 1; 19262e192b24SSimon Glass 19272e192b24SSimon Glass if (argc < 2) { 19282e192b24SSimon Glass printf("no partition id specified\n"); 19292e192b24SSimon Glass return 1; 19302e192b24SSimon Glass } 19312e192b24SSimon Glass 19322e192b24SSimon Glass if (find_dev_and_part(argv[1], &dev, &pnum, &part) != 0) 19332e192b24SSimon Glass return 1; 19342e192b24SSimon Glass 19352e192b24SSimon Glass current_mtd_dev = dev; 19362e192b24SSimon Glass current_mtd_partnum = pnum; 19372e192b24SSimon Glass current_save(); 19382e192b24SSimon Glass 19392e192b24SSimon Glass printf("partition changed to %s%d,%d\n", 19402e192b24SSimon Glass MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum); 19412e192b24SSimon Glass 19422e192b24SSimon Glass return 0; 19432e192b24SSimon Glass } 19442e192b24SSimon Glass 19452e192b24SSimon Glass /** 19462e192b24SSimon Glass * Routine implementing u-boot mtdparts command. Initialize/update default global 19472e192b24SSimon Glass * partition list and process user partition request (list, add, del). 19482e192b24SSimon Glass * 19492e192b24SSimon Glass * @param cmdtp command internal data 19502e192b24SSimon Glass * @param flag command flag 19512e192b24SSimon Glass * @param argc number of arguments supplied to the command 19522e192b24SSimon Glass * @param argv arguments list 19532e192b24SSimon Glass * @return 0 on success, 1 otherwise 19542e192b24SSimon Glass */ 19552e192b24SSimon Glass static int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, 19562e192b24SSimon Glass char * const argv[]) 19572e192b24SSimon Glass { 19582e192b24SSimon Glass if (argc == 2) { 19592e192b24SSimon Glass if (strcmp(argv[1], "default") == 0) { 1960382bee57SSimon Glass env_set("mtdids", NULL); 1961382bee57SSimon Glass env_set("mtdparts", NULL); 1962382bee57SSimon Glass env_set("partition", NULL); 1963f8f744a3SLadislav Michl use_defaults = 1; 19642e192b24SSimon Glass 19652e192b24SSimon Glass mtdparts_init(); 19662e192b24SSimon Glass return 0; 19672e192b24SSimon Glass } else if (strcmp(argv[1], "delall") == 0) { 19682e192b24SSimon Glass /* this may be the first run, initialize lists if needed */ 19692e192b24SSimon Glass mtdparts_init(); 19702e192b24SSimon Glass 1971382bee57SSimon Glass env_set("mtdparts", NULL); 19722e192b24SSimon Glass 19732e192b24SSimon Glass /* mtd_devices_init() calls current_save() */ 19742e192b24SSimon Glass return mtd_devices_init(); 19752e192b24SSimon Glass } 19762e192b24SSimon Glass } 19772e192b24SSimon Glass 19782e192b24SSimon Glass /* make sure we are in sync with env variables */ 19792e192b24SSimon Glass if (mtdparts_init() != 0) 19802e192b24SSimon Glass return 1; 19812e192b24SSimon Glass 19822e192b24SSimon Glass if (argc == 1) { 19832e192b24SSimon Glass list_partitions(); 19842e192b24SSimon Glass return 0; 19852e192b24SSimon Glass } 19862e192b24SSimon Glass 19872e192b24SSimon Glass /* mtdparts add <mtd-dev> <size>[@<offset>] <name> [ro] */ 19882e192b24SSimon Glass if (((argc == 5) || (argc == 6)) && (strncmp(argv[1], "add", 3) == 0)) { 19892e192b24SSimon Glass #define PART_ADD_DESC_MAXLEN 64 19902e192b24SSimon Glass char tmpbuf[PART_ADD_DESC_MAXLEN]; 19912e192b24SSimon Glass #if defined(CONFIG_CMD_MTDPARTS_SPREAD) 19922e192b24SSimon Glass struct mtd_info *mtd; 19932e192b24SSimon Glass uint64_t next_offset; 19942e192b24SSimon Glass #endif 19952e192b24SSimon Glass u8 type, num, len; 19962e192b24SSimon Glass struct mtd_device *dev; 19972e192b24SSimon Glass struct mtd_device *dev_tmp; 19982e192b24SSimon Glass struct mtdids *id; 19992e192b24SSimon Glass struct part_info *p; 20002e192b24SSimon Glass 20012e192b24SSimon Glass if (mtd_id_parse(argv[2], NULL, &type, &num) != 0) 20022e192b24SSimon Glass return 1; 20032e192b24SSimon Glass 20042e192b24SSimon Glass if ((id = id_find(type, num)) == NULL) { 20052e192b24SSimon Glass printf("no such device %s defined in mtdids variable\n", argv[2]); 20062e192b24SSimon Glass return 1; 20072e192b24SSimon Glass } 20082e192b24SSimon Glass 20092e192b24SSimon Glass len = strlen(id->mtd_id) + 1; /* 'mtd_id:' */ 20102e192b24SSimon Glass len += strlen(argv[3]); /* size@offset */ 20112e192b24SSimon Glass len += strlen(argv[4]) + 2; /* '(' name ')' */ 20122e192b24SSimon Glass if (argv[5] && (strlen(argv[5]) == 2)) 20132e192b24SSimon Glass len += 2; /* 'ro' */ 20142e192b24SSimon Glass 20152e192b24SSimon Glass if (len >= PART_ADD_DESC_MAXLEN) { 20162e192b24SSimon Glass printf("too long partition description\n"); 20172e192b24SSimon Glass return 1; 20182e192b24SSimon Glass } 20192e192b24SSimon Glass sprintf(tmpbuf, "%s:%s(%s)%s", 20202e192b24SSimon Glass id->mtd_id, argv[3], argv[4], argv[5] ? argv[5] : ""); 20212e192b24SSimon Glass debug("add tmpbuf: %s\n", tmpbuf); 20222e192b24SSimon Glass 20232e192b24SSimon Glass if ((device_parse(tmpbuf, NULL, &dev) != 0) || (!dev)) 20242e192b24SSimon Glass return 1; 20252e192b24SSimon Glass 20262e192b24SSimon Glass debug("+ %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type), 20272e192b24SSimon Glass dev->id->num, dev->id->mtd_id); 20282e192b24SSimon Glass 20292e192b24SSimon Glass p = list_entry(dev->parts.next, struct part_info, link); 20302e192b24SSimon Glass 20312e192b24SSimon Glass #if defined(CONFIG_CMD_MTDPARTS_SPREAD) 20322e192b24SSimon Glass if (get_mtd_info(dev->id->type, dev->id->num, &mtd)) 20332e192b24SSimon Glass return 1; 20342e192b24SSimon Glass 20352e192b24SSimon Glass if (!strcmp(&argv[1][3], ".spread")) { 20362e192b24SSimon Glass spread_partition(mtd, p, &next_offset); 203759441ac3SSteve Rae debug("increased %s to %llu bytes\n", p->name, p->size); 20382e192b24SSimon Glass } 20392e192b24SSimon Glass #endif 20402e192b24SSimon Glass 20412e192b24SSimon Glass dev_tmp = device_find(dev->id->type, dev->id->num); 20422e192b24SSimon Glass if (dev_tmp == NULL) { 20432e192b24SSimon Glass device_add(dev); 20442e192b24SSimon Glass } else if (part_add(dev_tmp, p) != 0) { 20452e192b24SSimon Glass /* merge new partition with existing ones*/ 20462e192b24SSimon Glass device_del(dev); 20472e192b24SSimon Glass return 1; 20482e192b24SSimon Glass } 20492e192b24SSimon Glass 20502e192b24SSimon Glass if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) { 20512e192b24SSimon Glass printf("generated mtdparts too long, resetting to null\n"); 20522e192b24SSimon Glass return 1; 20532e192b24SSimon Glass } 20542e192b24SSimon Glass 20552e192b24SSimon Glass return 0; 20562e192b24SSimon Glass } 20572e192b24SSimon Glass 20582e192b24SSimon Glass /* mtdparts del part-id */ 20592e192b24SSimon Glass if ((argc == 3) && (strcmp(argv[1], "del") == 0)) { 20602e192b24SSimon Glass debug("del: part-id = %s\n", argv[2]); 20612e192b24SSimon Glass 20622e192b24SSimon Glass return delete_partition(argv[2]); 20632e192b24SSimon Glass } 20642e192b24SSimon Glass 20652e192b24SSimon Glass #if defined(CONFIG_CMD_MTDPARTS_SPREAD) 20662e192b24SSimon Glass if ((argc == 2) && (strcmp(argv[1], "spread") == 0)) 20672e192b24SSimon Glass return spread_partitions(); 20682e192b24SSimon Glass #endif /* CONFIG_CMD_MTDPARTS_SPREAD */ 20692e192b24SSimon Glass 20702e192b24SSimon Glass return CMD_RET_USAGE; 20712e192b24SSimon Glass } 20722e192b24SSimon Glass 20732e192b24SSimon Glass /***************************************************/ 20742e192b24SSimon Glass U_BOOT_CMD( 20752e192b24SSimon Glass chpart, 2, 0, do_chpart, 20762e192b24SSimon Glass "change active partition", 20772e192b24SSimon Glass "part-id\n" 20782e192b24SSimon Glass " - change active partition (e.g. part-id = nand0,1)" 20792e192b24SSimon Glass ); 20802e192b24SSimon Glass 20812e192b24SSimon Glass #ifdef CONFIG_SYS_LONGHELP 20822e192b24SSimon Glass static char mtdparts_help_text[] = 20832e192b24SSimon Glass "\n" 20842e192b24SSimon Glass " - list partition table\n" 20852e192b24SSimon Glass "mtdparts delall\n" 20862e192b24SSimon Glass " - delete all partitions\n" 20872e192b24SSimon Glass "mtdparts del part-id\n" 20882e192b24SSimon Glass " - delete partition (e.g. part-id = nand0,1)\n" 20892e192b24SSimon Glass "mtdparts add <mtd-dev> <size>[@<offset>] [<name>] [ro]\n" 20902e192b24SSimon Glass " - add partition\n" 20912e192b24SSimon Glass #if defined(CONFIG_CMD_MTDPARTS_SPREAD) 20922e192b24SSimon Glass "mtdparts add.spread <mtd-dev> <size>[@<offset>] [<name>] [ro]\n" 20932e192b24SSimon Glass " - add partition, padding size by skipping bad blocks\n" 20942e192b24SSimon Glass #endif 20952e192b24SSimon Glass "mtdparts default\n" 20962e192b24SSimon Glass " - reset partition table to defaults\n" 20972e192b24SSimon Glass #if defined(CONFIG_CMD_MTDPARTS_SPREAD) 20982e192b24SSimon Glass "mtdparts spread\n" 20992e192b24SSimon Glass " - adjust the sizes of the partitions so they are\n" 21002e192b24SSimon Glass " at least as big as the mtdparts variable specifies\n" 21012e192b24SSimon Glass " and they each start on a good block\n\n" 21022e192b24SSimon Glass #else 21032e192b24SSimon Glass "\n" 21042e192b24SSimon Glass #endif /* CONFIG_CMD_MTDPARTS_SPREAD */ 21052e192b24SSimon Glass "-----\n\n" 21062e192b24SSimon Glass "this command uses three environment variables:\n\n" 21072e192b24SSimon Glass "'partition' - keeps current partition identifier\n\n" 21082e192b24SSimon Glass "partition := <part-id>\n" 21092e192b24SSimon Glass "<part-id> := <dev-id>,part_num\n\n" 21102e192b24SSimon Glass "'mtdids' - linux kernel mtd device id <-> u-boot device id mapping\n\n" 21112e192b24SSimon Glass "mtdids=<idmap>[,<idmap>,...]\n\n" 21122e192b24SSimon Glass "<idmap> := <dev-id>=<mtd-id>\n" 211300ac922dSMiquel Raynal "<dev-id> := 'nand'|'nor'|'onenand'|'spi-nand'<dev-num>\n" 21142e192b24SSimon Glass "<dev-num> := mtd device number, 0...\n" 21152e192b24SSimon Glass "<mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name)\n\n" 21162e192b24SSimon Glass "'mtdparts' - partition list\n\n" 21172e192b24SSimon Glass "mtdparts=mtdparts=<mtd-def>[;<mtd-def>...]\n\n" 21182e192b24SSimon Glass "<mtd-def> := <mtd-id>:<part-def>[,<part-def>...]\n" 21192e192b24SSimon Glass "<mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name)\n" 21202e192b24SSimon Glass "<part-def> := <size>[@<offset>][<name>][<ro-flag>]\n" 21212e192b24SSimon Glass "<size> := standard linux memsize OR '-' to denote all remaining space\n" 21222e192b24SSimon Glass "<offset> := partition start offset within the device\n" 21232e192b24SSimon Glass "<name> := '(' NAME ')'\n" 21242e192b24SSimon Glass "<ro-flag> := when set to 'ro' makes partition read-only (not used, passed to kernel)"; 21252e192b24SSimon Glass #endif 21262e192b24SSimon Glass 21272e192b24SSimon Glass U_BOOT_CMD( 21282e192b24SSimon Glass mtdparts, 6, 0, do_mtdparts, 21292e192b24SSimon Glass "define flash/nand partitions", mtdparts_help_text 21302e192b24SSimon Glass ); 21312e192b24SSimon Glass /***************************************************/ 2132