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> 809c32807SHeiko Schocher #include <linux/mtd/mtd.h> 9*50466819SMiquel Raynal #include <jffs2/jffs2.h> /* Legacy */ 10*50466819SMiquel Raynal 11*50466819SMiquel Raynal /** 12*50466819SMiquel Raynal * mtd_search_alternate_name - Search an alternate name for @mtdname thanks to 13*50466819SMiquel Raynal * the mtdids legacy environment variable. 14*50466819SMiquel Raynal * 15*50466819SMiquel Raynal * The mtdids string is a list of comma-separated 'dev_id=mtd_id' tupples. 16*50466819SMiquel Raynal * Check if one of the mtd_id matches mtdname, in this case save dev_id in 17*50466819SMiquel Raynal * altname. 18*50466819SMiquel Raynal * 19*50466819SMiquel Raynal * @mtdname: Current MTD device name 20*50466819SMiquel Raynal * @altname: Alternate name to return 21*50466819SMiquel Raynal * @max_len: Length of the alternate name buffer 22*50466819SMiquel Raynal * 23*50466819SMiquel Raynal * @return 0 on success, an error otherwise. 24*50466819SMiquel Raynal */ 25*50466819SMiquel Raynal int mtd_search_alternate_name(const char *mtdname, char *altname, 26*50466819SMiquel Raynal unsigned int max_len) 27*50466819SMiquel Raynal { 28*50466819SMiquel Raynal const char *mtdids, *equal, *comma, *dev_id, *mtd_id; 29*50466819SMiquel Raynal int dev_id_len, mtd_id_len; 30*50466819SMiquel Raynal 31*50466819SMiquel Raynal mtdids = env_get("mtdids"); 32*50466819SMiquel Raynal if (!mtdids) 33*50466819SMiquel Raynal return -EINVAL; 34*50466819SMiquel Raynal 35*50466819SMiquel Raynal do { 36*50466819SMiquel Raynal /* Find the '=' sign */ 37*50466819SMiquel Raynal dev_id = mtdids; 38*50466819SMiquel Raynal equal = strchr(dev_id, '='); 39*50466819SMiquel Raynal if (!equal) 40*50466819SMiquel Raynal break; 41*50466819SMiquel Raynal dev_id_len = equal - mtdids; 42*50466819SMiquel Raynal mtd_id = equal + 1; 43*50466819SMiquel Raynal 44*50466819SMiquel Raynal /* Find the end of the tupple */ 45*50466819SMiquel Raynal comma = strchr(mtdids, ','); 46*50466819SMiquel Raynal if (comma) 47*50466819SMiquel Raynal mtd_id_len = comma - mtd_id; 48*50466819SMiquel Raynal else 49*50466819SMiquel Raynal mtd_id_len = &mtdids[strlen(mtdids)] - mtd_id + 1; 50*50466819SMiquel Raynal 51*50466819SMiquel Raynal if (!dev_id_len || !mtd_id_len) 52*50466819SMiquel Raynal return -EINVAL; 53*50466819SMiquel Raynal 54*50466819SMiquel Raynal if (dev_id_len + 1 > max_len) 55*50466819SMiquel Raynal continue; 56*50466819SMiquel Raynal 57*50466819SMiquel Raynal /* Compare the name we search with the current mtd_id */ 58*50466819SMiquel Raynal if (!strncmp(mtdname, mtd_id, mtd_id_len)) { 59*50466819SMiquel Raynal strncpy(altname, dev_id, dev_id_len); 60*50466819SMiquel Raynal altname[dev_id_len] = 0; 61*50466819SMiquel Raynal 62*50466819SMiquel Raynal return 0; 63*50466819SMiquel Raynal } 64*50466819SMiquel Raynal 65*50466819SMiquel Raynal /* Go to the next tupple */ 66*50466819SMiquel Raynal mtdids = comma + 1; 67*50466819SMiquel Raynal } while (comma); 68*50466819SMiquel Raynal 69*50466819SMiquel Raynal return -EINVAL; 70*50466819SMiquel Raynal } 71*50466819SMiquel Raynal 72*50466819SMiquel Raynal /* Legacy */ 7309c32807SHeiko Schocher 7409c32807SHeiko Schocher static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size, 7509c32807SHeiko Schocher loff_t *maxsize, int devtype) 7609c32807SHeiko Schocher { 7709c32807SHeiko Schocher #ifdef CONFIG_CMD_MTDPARTS 7809c32807SHeiko Schocher struct mtd_device *dev; 7909c32807SHeiko Schocher struct part_info *part; 8009c32807SHeiko Schocher u8 pnum; 8109c32807SHeiko Schocher int ret; 8209c32807SHeiko Schocher 8309c32807SHeiko Schocher ret = mtdparts_init(); 8409c32807SHeiko Schocher if (ret) 8509c32807SHeiko Schocher return ret; 8609c32807SHeiko Schocher 8709c32807SHeiko Schocher ret = find_dev_and_part(partname, &dev, &pnum, &part); 8809c32807SHeiko Schocher if (ret) 8909c32807SHeiko Schocher return ret; 9009c32807SHeiko Schocher 9109c32807SHeiko Schocher if (dev->id->type != devtype) { 9209c32807SHeiko Schocher printf("not same typ %d != %d\n", dev->id->type, devtype); 9309c32807SHeiko Schocher return -1; 9409c32807SHeiko Schocher } 9509c32807SHeiko Schocher 9609c32807SHeiko Schocher *off = part->offset; 9709c32807SHeiko Schocher *size = part->size; 9809c32807SHeiko Schocher *maxsize = part->size; 9909c32807SHeiko Schocher *idx = dev->id->num; 10009c32807SHeiko Schocher 10109c32807SHeiko Schocher return 0; 10209c32807SHeiko Schocher #else 10310b69712SMaxime Ripard puts("mtdparts support missing.\n"); 10409c32807SHeiko Schocher return -1; 10509c32807SHeiko Schocher #endif 10609c32807SHeiko Schocher } 10709c32807SHeiko Schocher 10809c32807SHeiko Schocher int mtd_arg_off(const char *arg, int *idx, loff_t *off, loff_t *size, 109f18d1116SMasahiro Yamada loff_t *maxsize, int devtype, uint64_t chipsize) 11009c32807SHeiko Schocher { 11109c32807SHeiko Schocher if (!str2off(arg, off)) 11209c32807SHeiko Schocher return get_part(arg, idx, off, size, maxsize, devtype); 11309c32807SHeiko Schocher 11409c32807SHeiko Schocher if (*off >= chipsize) { 11509c32807SHeiko Schocher puts("Offset exceeds device limit\n"); 11609c32807SHeiko Schocher return -1; 11709c32807SHeiko Schocher } 11809c32807SHeiko Schocher 11909c32807SHeiko Schocher *maxsize = chipsize - *off; 12009c32807SHeiko Schocher *size = *maxsize; 12109c32807SHeiko Schocher return 0; 12209c32807SHeiko Schocher } 12309c32807SHeiko Schocher 12409c32807SHeiko Schocher int mtd_arg_off_size(int argc, char *const argv[], int *idx, loff_t *off, 125f18d1116SMasahiro Yamada loff_t *size, loff_t *maxsize, int devtype, 126f18d1116SMasahiro Yamada uint64_t chipsize) 12709c32807SHeiko Schocher { 12809c32807SHeiko Schocher int ret; 12909c32807SHeiko Schocher 13009c32807SHeiko Schocher if (argc == 0) { 13109c32807SHeiko Schocher *off = 0; 13209c32807SHeiko Schocher *size = chipsize; 13309c32807SHeiko Schocher *maxsize = *size; 13409c32807SHeiko Schocher goto print; 13509c32807SHeiko Schocher } 13609c32807SHeiko Schocher 13709c32807SHeiko Schocher ret = mtd_arg_off(argv[0], idx, off, size, maxsize, devtype, 13809c32807SHeiko Schocher chipsize); 13909c32807SHeiko Schocher if (ret) 14009c32807SHeiko Schocher return ret; 14109c32807SHeiko Schocher 14209c32807SHeiko Schocher if (argc == 1) 14309c32807SHeiko Schocher goto print; 14409c32807SHeiko Schocher 14509c32807SHeiko Schocher if (!str2off(argv[1], size)) { 14609c32807SHeiko Schocher printf("'%s' is not a number\n", argv[1]); 14709c32807SHeiko Schocher return -1; 14809c32807SHeiko Schocher } 14909c32807SHeiko Schocher 15009c32807SHeiko Schocher if (*size > *maxsize) { 15109c32807SHeiko Schocher puts("Size exceeds partition or device limit\n"); 15209c32807SHeiko Schocher return -1; 15309c32807SHeiko Schocher } 15409c32807SHeiko Schocher 15509c32807SHeiko Schocher print: 15609c32807SHeiko Schocher printf("device %d ", *idx); 15709c32807SHeiko Schocher if (*size == chipsize) 15809c32807SHeiko Schocher puts("whole chip\n"); 15909c32807SHeiko Schocher else 16009c32807SHeiko Schocher printf("offset 0x%llx, size 0x%llx\n", 16109c32807SHeiko Schocher (unsigned long long)*off, (unsigned long long)*size); 16209c32807SHeiko Schocher return 0; 16309c32807SHeiko Schocher } 164