109c32807SHeiko Schocher /* 209c32807SHeiko Schocher * (C) Copyright 2014 309c32807SHeiko Schocher * Heiko Schocher, DENX Software Engineering, hs@denx.de. 409c32807SHeiko Schocher * 509c32807SHeiko Schocher * SPDX-License-Identifier: GPL-2.0+ 609c32807SHeiko Schocher */ 709c32807SHeiko Schocher #include <common.h> 8f87151b3SMiquel Raynal #include <dm/device.h> 9f87151b3SMiquel Raynal #include <dm/uclass-internal.h> 10f87151b3SMiquel Raynal #include <jffs2/jffs2.h> /* LEGACY */ 1109c32807SHeiko Schocher #include <linux/mtd/mtd.h> 12f87151b3SMiquel Raynal #include <linux/mtd/partitions.h> 13f87151b3SMiquel Raynal #include <mtd.h> 14f87151b3SMiquel Raynal 15f87151b3SMiquel Raynal #define MTD_NAME_MAX_LEN 20 16f87151b3SMiquel Raynal 174ac4e964SBoris Brezillon void board_mtdparts_default(const char **mtdids, const char **mtdparts); 184ac4e964SBoris Brezillon 194ac4e964SBoris Brezillon static const char *get_mtdids(void) 204ac4e964SBoris Brezillon { 214ac4e964SBoris Brezillon __maybe_unused const char *mtdparts = NULL; 224ac4e964SBoris Brezillon const char *mtdids = env_get("mtdids"); 234ac4e964SBoris Brezillon 244ac4e964SBoris Brezillon if (mtdids) 254ac4e964SBoris Brezillon return mtdids; 264ac4e964SBoris Brezillon 274ac4e964SBoris Brezillon #if defined(CONFIG_SYS_MTDPARTS_RUNTIME) 284ac4e964SBoris Brezillon board_mtdparts_default(&mtdids, &mtdparts); 294ac4e964SBoris Brezillon #elif defined(MTDIDS_DEFAULT) 304ac4e964SBoris Brezillon mtdids = MTDIDS_DEFAULT; 314ac4e964SBoris Brezillon #elif defined(CONFIG_MTDIDS_DEFAULT) 324ac4e964SBoris Brezillon mtdids = CONFIG_MTDIDS_DEFAULT; 334ac4e964SBoris Brezillon #endif 344ac4e964SBoris Brezillon 354ac4e964SBoris Brezillon if (mtdids) 364ac4e964SBoris Brezillon env_set("mtdids", mtdids); 374ac4e964SBoris Brezillon 384ac4e964SBoris Brezillon return mtdids; 394ac4e964SBoris Brezillon } 4050466819SMiquel Raynal 4150466819SMiquel Raynal /** 4250466819SMiquel Raynal * mtd_search_alternate_name - Search an alternate name for @mtdname thanks to 4350466819SMiquel Raynal * the mtdids legacy environment variable. 4450466819SMiquel Raynal * 4550466819SMiquel Raynal * The mtdids string is a list of comma-separated 'dev_id=mtd_id' tupples. 4650466819SMiquel Raynal * Check if one of the mtd_id matches mtdname, in this case save dev_id in 4750466819SMiquel Raynal * altname. 4850466819SMiquel Raynal * 4950466819SMiquel Raynal * @mtdname: Current MTD device name 5050466819SMiquel Raynal * @altname: Alternate name to return 5150466819SMiquel Raynal * @max_len: Length of the alternate name buffer 5250466819SMiquel Raynal * 5350466819SMiquel Raynal * @return 0 on success, an error otherwise. 5450466819SMiquel Raynal */ 5550466819SMiquel Raynal int mtd_search_alternate_name(const char *mtdname, char *altname, 5650466819SMiquel Raynal unsigned int max_len) 5750466819SMiquel Raynal { 5850466819SMiquel Raynal const char *mtdids, *equal, *comma, *dev_id, *mtd_id; 5950466819SMiquel Raynal int dev_id_len, mtd_id_len; 6050466819SMiquel Raynal 614ac4e964SBoris Brezillon mtdids = get_mtdids(); 6250466819SMiquel Raynal if (!mtdids) 6350466819SMiquel Raynal return -EINVAL; 6450466819SMiquel Raynal 6550466819SMiquel Raynal do { 6650466819SMiquel Raynal /* Find the '=' sign */ 6750466819SMiquel Raynal dev_id = mtdids; 6850466819SMiquel Raynal equal = strchr(dev_id, '='); 6950466819SMiquel Raynal if (!equal) 7050466819SMiquel Raynal break; 7150466819SMiquel Raynal dev_id_len = equal - mtdids; 7250466819SMiquel Raynal mtd_id = equal + 1; 7350466819SMiquel Raynal 7450466819SMiquel Raynal /* Find the end of the tupple */ 7550466819SMiquel Raynal comma = strchr(mtdids, ','); 7650466819SMiquel Raynal if (comma) 7750466819SMiquel Raynal mtd_id_len = comma - mtd_id; 7850466819SMiquel Raynal else 7950466819SMiquel Raynal mtd_id_len = &mtdids[strlen(mtdids)] - mtd_id + 1; 8050466819SMiquel Raynal 8150466819SMiquel Raynal if (!dev_id_len || !mtd_id_len) 8250466819SMiquel Raynal return -EINVAL; 8350466819SMiquel Raynal 8450466819SMiquel Raynal if (dev_id_len + 1 > max_len) 8550466819SMiquel Raynal continue; 8650466819SMiquel Raynal 8750466819SMiquel Raynal /* Compare the name we search with the current mtd_id */ 8850466819SMiquel Raynal if (!strncmp(mtdname, mtd_id, mtd_id_len)) { 8950466819SMiquel Raynal strncpy(altname, dev_id, dev_id_len); 9050466819SMiquel Raynal altname[dev_id_len] = 0; 9150466819SMiquel Raynal 9250466819SMiquel Raynal return 0; 9350466819SMiquel Raynal } 9450466819SMiquel Raynal 9550466819SMiquel Raynal /* Go to the next tupple */ 9650466819SMiquel Raynal mtdids = comma + 1; 9750466819SMiquel Raynal } while (comma); 9850466819SMiquel Raynal 9950466819SMiquel Raynal return -EINVAL; 10050466819SMiquel Raynal } 10150466819SMiquel Raynal 102f87151b3SMiquel Raynal #if IS_ENABLED(CONFIG_MTD) 103f87151b3SMiquel Raynal static void mtd_probe_uclass_mtd_devs(void) 104f87151b3SMiquel Raynal { 105f87151b3SMiquel Raynal struct udevice *dev; 106f87151b3SMiquel Raynal int idx = 0; 107f87151b3SMiquel Raynal 108f87151b3SMiquel Raynal /* Probe devices with DM compliant drivers */ 109f87151b3SMiquel Raynal while (!uclass_find_device(UCLASS_MTD, idx, &dev) && dev) { 110f87151b3SMiquel Raynal mtd_probe(dev); 111f87151b3SMiquel Raynal idx++; 112f87151b3SMiquel Raynal } 113f87151b3SMiquel Raynal } 114f87151b3SMiquel Raynal #else 115f87151b3SMiquel Raynal static void mtd_probe_uclass_mtd_devs(void) { } 116f87151b3SMiquel Raynal #endif 117f87151b3SMiquel Raynal 118f87151b3SMiquel Raynal #if defined(CONFIG_MTD_PARTITIONS) 119b95c8f6cSBoris Brezillon 120b95c8f6cSBoris Brezillon #define MTDPARTS_MAXLEN 512 121b95c8f6cSBoris Brezillon 122b95c8f6cSBoris Brezillon static const char *get_mtdparts(void) 123b95c8f6cSBoris Brezillon { 124b95c8f6cSBoris Brezillon __maybe_unused const char *mtdids = NULL; 125b95c8f6cSBoris Brezillon static char tmp_parts[MTDPARTS_MAXLEN]; 126b95c8f6cSBoris Brezillon const char *mtdparts = NULL; 127b95c8f6cSBoris Brezillon 128b95c8f6cSBoris Brezillon if (gd->flags & GD_FLG_ENV_READY) 129b95c8f6cSBoris Brezillon mtdparts = env_get("mtdparts"); 130b95c8f6cSBoris Brezillon else if (env_get_f("mtdparts", tmp_parts, sizeof(tmp_parts)) != -1) 131b95c8f6cSBoris Brezillon mtdparts = tmp_parts; 132b95c8f6cSBoris Brezillon 133*a62211b4SPatrice Chotard if (mtdparts) 134b95c8f6cSBoris Brezillon return mtdparts; 135b95c8f6cSBoris Brezillon 136b95c8f6cSBoris Brezillon #if defined(CONFIG_SYS_MTDPARTS_RUNTIME) 137b95c8f6cSBoris Brezillon board_mtdparts_default(&mtdids, &mtdparts); 138b95c8f6cSBoris Brezillon #elif defined(MTDPARTS_DEFAULT) 139b95c8f6cSBoris Brezillon mtdparts = MTDPARTS_DEFAULT; 140b95c8f6cSBoris Brezillon #elif defined(CONFIG_MTDPARTS_DEFAULT) 141b95c8f6cSBoris Brezillon mtdparts = CONFIG_MTDPARTS_DEFAULT; 142b95c8f6cSBoris Brezillon #endif 143b95c8f6cSBoris Brezillon 144b95c8f6cSBoris Brezillon if (mtdparts) 145b95c8f6cSBoris Brezillon env_set("mtdparts", mtdparts); 146b95c8f6cSBoris Brezillon 147b95c8f6cSBoris Brezillon return mtdparts; 148b95c8f6cSBoris Brezillon } 149b95c8f6cSBoris Brezillon 150ef964b01SBoris Brezillon static int mtd_del_parts(struct mtd_info *mtd, bool quiet) 151ef964b01SBoris Brezillon { 152ef964b01SBoris Brezillon int ret; 153ef964b01SBoris Brezillon 154ef964b01SBoris Brezillon if (!mtd_has_partitions(mtd)) 155ef964b01SBoris Brezillon return 0; 156ef964b01SBoris Brezillon 157ef964b01SBoris Brezillon /* do not delete partitions if they are in use. */ 158ef964b01SBoris Brezillon if (mtd_partitions_used(mtd)) { 159ef964b01SBoris Brezillon if (!quiet) 160ef964b01SBoris Brezillon printf("\"%s\" partitions still in use, can't delete them\n", 161ef964b01SBoris Brezillon mtd->name); 162ef964b01SBoris Brezillon return -EACCES; 163ef964b01SBoris Brezillon } 164ef964b01SBoris Brezillon 165ef964b01SBoris Brezillon ret = del_mtd_partitions(mtd); 166ef964b01SBoris Brezillon if (ret) 167ef964b01SBoris Brezillon return ret; 168ef964b01SBoris Brezillon 169ef964b01SBoris Brezillon return 1; 170ef964b01SBoris Brezillon } 171ef964b01SBoris Brezillon 172ef964b01SBoris Brezillon static bool mtd_del_all_parts_failed; 173ef964b01SBoris Brezillon 174ef964b01SBoris Brezillon static void mtd_del_all_parts(void) 175ef964b01SBoris Brezillon { 176ef964b01SBoris Brezillon struct mtd_info *mtd; 177ef964b01SBoris Brezillon int ret = 0; 178ef964b01SBoris Brezillon 179ef964b01SBoris Brezillon mtd_del_all_parts_failed = false; 180ef964b01SBoris Brezillon 181ef964b01SBoris Brezillon /* 182ef964b01SBoris Brezillon * It is not safe to remove entries from the mtd_for_each_device loop 183ef964b01SBoris Brezillon * as it uses idr indexes and the partitions removal is done in bulk 184ef964b01SBoris Brezillon * (all partitions of one device at the same time), so break and 185ef964b01SBoris Brezillon * iterate from start each time a new partition is found and deleted. 186ef964b01SBoris Brezillon */ 187ef964b01SBoris Brezillon do { 188ef964b01SBoris Brezillon mtd_for_each_device(mtd) { 189ef964b01SBoris Brezillon ret = mtd_del_parts(mtd, false); 190ef964b01SBoris Brezillon if (ret > 0) 191ef964b01SBoris Brezillon break; 192ef964b01SBoris Brezillon else if (ret < 0) 193ef964b01SBoris Brezillon mtd_del_all_parts_failed = true; 194ef964b01SBoris Brezillon } 195ef964b01SBoris Brezillon } while (ret > 0); 196ef964b01SBoris Brezillon } 197ef964b01SBoris Brezillon 198f87151b3SMiquel Raynal int mtd_probe_devices(void) 199f87151b3SMiquel Raynal { 200f87151b3SMiquel Raynal static char *old_mtdparts; 201f87151b3SMiquel Raynal static char *old_mtdids; 202b95c8f6cSBoris Brezillon const char *mtdparts = get_mtdparts(); 203b95c8f6cSBoris Brezillon const char *mtdids = get_mtdids(); 204a38bf0a9SBoris Brezillon const char *mtdparts_next = mtdparts; 205f87151b3SMiquel Raynal struct mtd_info *mtd; 206f87151b3SMiquel Raynal 207f87151b3SMiquel Raynal mtd_probe_uclass_mtd_devs(); 208f87151b3SMiquel Raynal 2094c33ae3bSBoris Brezillon /* 210ef964b01SBoris Brezillon * Check if mtdparts/mtdids changed, if the MTD dev list was updated 211ef964b01SBoris Brezillon * or if our previous attempt to delete existing partititions failed. 212ef964b01SBoris Brezillon * In any of these cases we want to update the partitions, otherwise, 213ef964b01SBoris Brezillon * everything is up-to-date and we can return 0 directly. 2144c33ae3bSBoris Brezillon */ 2154696f08fSAdam Ford if ((!mtdparts && !old_mtdparts && !mtdids && !old_mtdids) || 2164696f08fSAdam Ford (mtdparts && old_mtdparts && mtdids && old_mtdids && 217ef964b01SBoris Brezillon !mtd_dev_list_updated() && !mtd_del_all_parts_failed && 2184696f08fSAdam Ford !strcmp(mtdparts, old_mtdparts) && 2194696f08fSAdam Ford !strcmp(mtdids, old_mtdids))) 220f87151b3SMiquel Raynal return 0; 221f87151b3SMiquel Raynal 222f87151b3SMiquel Raynal /* Update the local copy of mtdparts */ 223f87151b3SMiquel Raynal free(old_mtdparts); 224f87151b3SMiquel Raynal free(old_mtdids); 225f87151b3SMiquel Raynal old_mtdparts = strdup(mtdparts); 226f87151b3SMiquel Raynal old_mtdids = strdup(mtdids); 227f87151b3SMiquel Raynal 228f87151b3SMiquel Raynal /* 229ef964b01SBoris Brezillon * Remove all old parts. Note that partition removal can fail in case 230ef964b01SBoris Brezillon * one of the partition is still being used by an MTD user, so this 231ef964b01SBoris Brezillon * does not guarantee that all old partitions are gone. 232f87151b3SMiquel Raynal */ 233ef964b01SBoris Brezillon mtd_del_all_parts(); 234f87151b3SMiquel Raynal 2354c33ae3bSBoris Brezillon /* 2364c33ae3bSBoris Brezillon * Call mtd_dev_list_updated() to clear updates generated by our own 2374c33ae3bSBoris Brezillon * parts removal loop. 2384c33ae3bSBoris Brezillon */ 2394c33ae3bSBoris Brezillon mtd_dev_list_updated(); 2404c33ae3bSBoris Brezillon 2414696f08fSAdam Ford /* If either mtdparts or mtdids is empty, then exit */ 2424696f08fSAdam Ford if (!mtdparts || !mtdids) 2434696f08fSAdam Ford return 0; 2444696f08fSAdam Ford 245f87151b3SMiquel Raynal /* Start the parsing by ignoring the extra 'mtdparts=' prefix, if any */ 246e3112a2cSBoris Brezillon if (!strncmp(mtdparts, "mtdparts=", sizeof("mtdparts=") - 1)) 247f87151b3SMiquel Raynal mtdparts += 9; 248f87151b3SMiquel Raynal 249f87151b3SMiquel Raynal /* For each MTD device in mtdparts */ 250a38bf0a9SBoris Brezillon for (; mtdparts[0] != '\0'; mtdparts = mtdparts_next) { 251f87151b3SMiquel Raynal char mtd_name[MTD_NAME_MAX_LEN], *colon; 252f87151b3SMiquel Raynal struct mtd_partition *parts; 2537a13c786SBoris Brezillon unsigned int mtd_name_len; 2547a13c786SBoris Brezillon int nparts, ret; 255f87151b3SMiquel Raynal 256a38bf0a9SBoris Brezillon mtdparts_next = strchr(mtdparts, ';'); 257a38bf0a9SBoris Brezillon if (!mtdparts_next) 258a38bf0a9SBoris Brezillon mtdparts_next = mtdparts + strlen(mtdparts); 259a38bf0a9SBoris Brezillon else 260a38bf0a9SBoris Brezillon mtdparts_next++; 261a38bf0a9SBoris Brezillon 262f87151b3SMiquel Raynal colon = strchr(mtdparts, ':'); 263a38bf0a9SBoris Brezillon if (colon > mtdparts_next) 264a38bf0a9SBoris Brezillon colon = NULL; 265a38bf0a9SBoris Brezillon 266f87151b3SMiquel Raynal if (!colon) { 267f87151b3SMiquel Raynal printf("Wrong mtdparts: %s\n", mtdparts); 268f87151b3SMiquel Raynal return -EINVAL; 269f87151b3SMiquel Raynal } 270f87151b3SMiquel Raynal 2717a13c786SBoris Brezillon mtd_name_len = (unsigned int)(colon - mtdparts); 2727a13c786SBoris Brezillon if (mtd_name_len + 1 > sizeof(mtd_name)) { 2737a13c786SBoris Brezillon printf("MTD name too long: %s\n", mtdparts); 2747a13c786SBoris Brezillon return -EINVAL; 2757a13c786SBoris Brezillon } 2767a13c786SBoris Brezillon 277f87151b3SMiquel Raynal strncpy(mtd_name, mtdparts, mtd_name_len); 278f87151b3SMiquel Raynal mtd_name[mtd_name_len] = '\0'; 279f87151b3SMiquel Raynal /* Move the pointer forward (including the ':') */ 280f87151b3SMiquel Raynal mtdparts += mtd_name_len + 1; 281f87151b3SMiquel Raynal mtd = get_mtd_device_nm(mtd_name); 282f87151b3SMiquel Raynal if (IS_ERR_OR_NULL(mtd)) { 283f87151b3SMiquel Raynal char linux_name[MTD_NAME_MAX_LEN]; 284f87151b3SMiquel Raynal 285f87151b3SMiquel Raynal /* 286f87151b3SMiquel Raynal * The MTD device named "mtd_name" does not exist. Try 287f87151b3SMiquel Raynal * to find a correspondance with an MTD device having 288f87151b3SMiquel Raynal * the same type and number as defined in the mtdids. 289f87151b3SMiquel Raynal */ 290f87151b3SMiquel Raynal debug("No device named %s\n", mtd_name); 291f87151b3SMiquel Raynal ret = mtd_search_alternate_name(mtd_name, linux_name, 292f87151b3SMiquel Raynal MTD_NAME_MAX_LEN); 293f87151b3SMiquel Raynal if (!ret) 294f87151b3SMiquel Raynal mtd = get_mtd_device_nm(linux_name); 295f87151b3SMiquel Raynal 296f87151b3SMiquel Raynal /* 297f87151b3SMiquel Raynal * If no device could be found, move the mtdparts 298f87151b3SMiquel Raynal * pointer forward until the next set of partitions. 299f87151b3SMiquel Raynal */ 300f87151b3SMiquel Raynal if (ret || IS_ERR_OR_NULL(mtd)) { 301f87151b3SMiquel Raynal printf("Could not find a valid device for %s\n", 302f87151b3SMiquel Raynal mtd_name); 303a38bf0a9SBoris Brezillon mtdparts = mtdparts_next; 304f87151b3SMiquel Raynal continue; 305f87151b3SMiquel Raynal } 306f87151b3SMiquel Raynal } 307f87151b3SMiquel Raynal 308f87151b3SMiquel Raynal /* 309ef964b01SBoris Brezillon * Call mtd_del_parts() again, even if it's already been called 310ef964b01SBoris Brezillon * in mtd_del_all_parts(). We need to know if old partitions are 311ef964b01SBoris Brezillon * still around (because they are still being used by someone), 312ef964b01SBoris Brezillon * and if they are, we shouldn't create new partitions, so just 313ef964b01SBoris Brezillon * skip this MTD device and try the next one. 314ef964b01SBoris Brezillon */ 315ef964b01SBoris Brezillon ret = mtd_del_parts(mtd, true); 316ef964b01SBoris Brezillon if (ret < 0) 317ef964b01SBoris Brezillon continue; 318ef964b01SBoris Brezillon 319ef964b01SBoris Brezillon /* 320f87151b3SMiquel Raynal * Parse the MTD device partitions. It will update the mtdparts 321f87151b3SMiquel Raynal * pointer, create an array of parts (that must be freed), and 322f87151b3SMiquel Raynal * return the number of partition structures in the array. 323f87151b3SMiquel Raynal */ 324f87151b3SMiquel Raynal ret = mtd_parse_partitions(mtd, &mtdparts, &parts, &nparts); 325f87151b3SMiquel Raynal if (ret) { 326f87151b3SMiquel Raynal printf("Could not parse device %s\n", mtd->name); 327f87151b3SMiquel Raynal put_mtd_device(mtd); 328f87151b3SMiquel Raynal return -EINVAL; 329f87151b3SMiquel Raynal } 330f87151b3SMiquel Raynal 331f87151b3SMiquel Raynal if (!nparts) 332f87151b3SMiquel Raynal continue; 333f87151b3SMiquel Raynal 334f87151b3SMiquel Raynal /* Create the new MTD partitions */ 335f87151b3SMiquel Raynal add_mtd_partitions(mtd, parts, nparts); 336f87151b3SMiquel Raynal 337f87151b3SMiquel Raynal /* Free the structures allocated during the parsing */ 338f87151b3SMiquel Raynal mtd_free_parsed_partitions(parts, nparts); 339f87151b3SMiquel Raynal 340f87151b3SMiquel Raynal put_mtd_device(mtd); 341f87151b3SMiquel Raynal } 342f87151b3SMiquel Raynal 3434c33ae3bSBoris Brezillon /* 3444c33ae3bSBoris Brezillon * Call mtd_dev_list_updated() to clear updates generated by our own 3454c33ae3bSBoris Brezillon * parts registration loop. 3464c33ae3bSBoris Brezillon */ 3474c33ae3bSBoris Brezillon mtd_dev_list_updated(); 3484c33ae3bSBoris Brezillon 349f87151b3SMiquel Raynal return 0; 350f87151b3SMiquel Raynal } 351f87151b3SMiquel Raynal #else 352f87151b3SMiquel Raynal int mtd_probe_devices(void) 353f87151b3SMiquel Raynal { 354f87151b3SMiquel Raynal mtd_probe_uclass_mtd_devs(); 355f87151b3SMiquel Raynal 356f87151b3SMiquel Raynal return 0; 357f87151b3SMiquel Raynal } 358f87151b3SMiquel Raynal #endif /* defined(CONFIG_MTD_PARTITIONS) */ 359f87151b3SMiquel Raynal 36050466819SMiquel Raynal /* Legacy */ 36109c32807SHeiko Schocher 36209c32807SHeiko Schocher static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size, 36309c32807SHeiko Schocher loff_t *maxsize, int devtype) 36409c32807SHeiko Schocher { 36509c32807SHeiko Schocher #ifdef CONFIG_CMD_MTDPARTS 36609c32807SHeiko Schocher struct mtd_device *dev; 36709c32807SHeiko Schocher struct part_info *part; 36809c32807SHeiko Schocher u8 pnum; 36909c32807SHeiko Schocher int ret; 37009c32807SHeiko Schocher 37109c32807SHeiko Schocher ret = mtdparts_init(); 37209c32807SHeiko Schocher if (ret) 37309c32807SHeiko Schocher return ret; 37409c32807SHeiko Schocher 37509c32807SHeiko Schocher ret = find_dev_and_part(partname, &dev, &pnum, &part); 37609c32807SHeiko Schocher if (ret) 37709c32807SHeiko Schocher return ret; 37809c32807SHeiko Schocher 37909c32807SHeiko Schocher if (dev->id->type != devtype) { 38009c32807SHeiko Schocher printf("not same typ %d != %d\n", dev->id->type, devtype); 38109c32807SHeiko Schocher return -1; 38209c32807SHeiko Schocher } 38309c32807SHeiko Schocher 38409c32807SHeiko Schocher *off = part->offset; 38509c32807SHeiko Schocher *size = part->size; 38609c32807SHeiko Schocher *maxsize = part->size; 38709c32807SHeiko Schocher *idx = dev->id->num; 38809c32807SHeiko Schocher 38909c32807SHeiko Schocher return 0; 39009c32807SHeiko Schocher #else 39110b69712SMaxime Ripard puts("mtdparts support missing.\n"); 39209c32807SHeiko Schocher return -1; 39309c32807SHeiko Schocher #endif 39409c32807SHeiko Schocher } 39509c32807SHeiko Schocher 39609c32807SHeiko Schocher int mtd_arg_off(const char *arg, int *idx, loff_t *off, loff_t *size, 397f18d1116SMasahiro Yamada loff_t *maxsize, int devtype, uint64_t chipsize) 39809c32807SHeiko Schocher { 39909c32807SHeiko Schocher if (!str2off(arg, off)) 40009c32807SHeiko Schocher return get_part(arg, idx, off, size, maxsize, devtype); 40109c32807SHeiko Schocher 40209c32807SHeiko Schocher if (*off >= chipsize) { 40309c32807SHeiko Schocher puts("Offset exceeds device limit\n"); 40409c32807SHeiko Schocher return -1; 40509c32807SHeiko Schocher } 40609c32807SHeiko Schocher 40709c32807SHeiko Schocher *maxsize = chipsize - *off; 40809c32807SHeiko Schocher *size = *maxsize; 40909c32807SHeiko Schocher return 0; 41009c32807SHeiko Schocher } 41109c32807SHeiko Schocher 41209c32807SHeiko Schocher int mtd_arg_off_size(int argc, char *const argv[], int *idx, loff_t *off, 413f18d1116SMasahiro Yamada loff_t *size, loff_t *maxsize, int devtype, 414f18d1116SMasahiro Yamada uint64_t chipsize) 41509c32807SHeiko Schocher { 41609c32807SHeiko Schocher int ret; 41709c32807SHeiko Schocher 41809c32807SHeiko Schocher if (argc == 0) { 41909c32807SHeiko Schocher *off = 0; 42009c32807SHeiko Schocher *size = chipsize; 42109c32807SHeiko Schocher *maxsize = *size; 42209c32807SHeiko Schocher goto print; 42309c32807SHeiko Schocher } 42409c32807SHeiko Schocher 42509c32807SHeiko Schocher ret = mtd_arg_off(argv[0], idx, off, size, maxsize, devtype, 42609c32807SHeiko Schocher chipsize); 42709c32807SHeiko Schocher if (ret) 42809c32807SHeiko Schocher return ret; 42909c32807SHeiko Schocher 43009c32807SHeiko Schocher if (argc == 1) 43109c32807SHeiko Schocher goto print; 43209c32807SHeiko Schocher 43309c32807SHeiko Schocher if (!str2off(argv[1], size)) { 43409c32807SHeiko Schocher printf("'%s' is not a number\n", argv[1]); 43509c32807SHeiko Schocher return -1; 43609c32807SHeiko Schocher } 43709c32807SHeiko Schocher 43809c32807SHeiko Schocher if (*size > *maxsize) { 43909c32807SHeiko Schocher puts("Size exceeds partition or device limit\n"); 44009c32807SHeiko Schocher return -1; 44109c32807SHeiko Schocher } 44209c32807SHeiko Schocher 44309c32807SHeiko Schocher print: 44409c32807SHeiko Schocher printf("device %d ", *idx); 44509c32807SHeiko Schocher if (*size == chipsize) 44609c32807SHeiko Schocher puts("whole chip\n"); 44709c32807SHeiko Schocher else 44809c32807SHeiko Schocher printf("offset 0x%llx, size 0x%llx\n", 44909c32807SHeiko Schocher (unsigned long long)*off, (unsigned long long)*size); 45009c32807SHeiko Schocher return 0; 45109c32807SHeiko Schocher } 452