1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * (C) Copyright 2014
3*4882a593Smuzhiyun * Heiko Schocher, DENX Software Engineering, hs@denx.de.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun #include <common.h>
8*4882a593Smuzhiyun #include <dm/device.h>
9*4882a593Smuzhiyun #include <dm/device-internal.h>
10*4882a593Smuzhiyun #include <dm/uclass-internal.h>
11*4882a593Smuzhiyun #include <jffs2/jffs2.h> /* LEGACY */
12*4882a593Smuzhiyun #include <linux/mtd/mtd.h>
13*4882a593Smuzhiyun #include <linux/mtd/partitions.h>
14*4882a593Smuzhiyun #include <mtd.h>
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #define MTD_NAME_MAX_LEN 20
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun void board_mtdparts_default(const char **mtdids, const char **mtdparts);
19*4882a593Smuzhiyun
get_mtdids(void)20*4882a593Smuzhiyun static const char *get_mtdids(void)
21*4882a593Smuzhiyun {
22*4882a593Smuzhiyun __maybe_unused const char *mtdparts = NULL;
23*4882a593Smuzhiyun const char *mtdids = env_get("mtdids");
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun if (mtdids)
26*4882a593Smuzhiyun return mtdids;
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun #if defined(CONFIG_SYS_MTDPARTS_RUNTIME)
29*4882a593Smuzhiyun board_mtdparts_default(&mtdids, &mtdparts);
30*4882a593Smuzhiyun #elif defined(MTDIDS_DEFAULT)
31*4882a593Smuzhiyun mtdids = MTDIDS_DEFAULT;
32*4882a593Smuzhiyun #elif defined(CONFIG_MTDIDS_DEFAULT)
33*4882a593Smuzhiyun mtdids = CONFIG_MTDIDS_DEFAULT;
34*4882a593Smuzhiyun #endif
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun if (mtdids)
37*4882a593Smuzhiyun env_set("mtdids", mtdids);
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun return mtdids;
40*4882a593Smuzhiyun }
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun /**
43*4882a593Smuzhiyun * mtd_search_alternate_name - Search an alternate name for @mtdname thanks to
44*4882a593Smuzhiyun * the mtdids legacy environment variable.
45*4882a593Smuzhiyun *
46*4882a593Smuzhiyun * The mtdids string is a list of comma-separated 'dev_id=mtd_id' tupples.
47*4882a593Smuzhiyun * Check if one of the mtd_id matches mtdname, in this case save dev_id in
48*4882a593Smuzhiyun * altname.
49*4882a593Smuzhiyun *
50*4882a593Smuzhiyun * @mtdname: Current MTD device name
51*4882a593Smuzhiyun * @altname: Alternate name to return
52*4882a593Smuzhiyun * @max_len: Length of the alternate name buffer
53*4882a593Smuzhiyun *
54*4882a593Smuzhiyun * @return 0 on success, an error otherwise.
55*4882a593Smuzhiyun */
mtd_search_alternate_name(const char * mtdname,char * altname,unsigned int max_len)56*4882a593Smuzhiyun int mtd_search_alternate_name(const char *mtdname, char *altname,
57*4882a593Smuzhiyun unsigned int max_len)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun const char *mtdids, *equal, *comma, *dev_id, *mtd_id;
60*4882a593Smuzhiyun int dev_id_len, mtd_id_len;
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun mtdids = get_mtdids();
63*4882a593Smuzhiyun if (!mtdids)
64*4882a593Smuzhiyun return -EINVAL;
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun do {
67*4882a593Smuzhiyun /* Find the '=' sign */
68*4882a593Smuzhiyun dev_id = mtdids;
69*4882a593Smuzhiyun equal = strchr(dev_id, '=');
70*4882a593Smuzhiyun if (!equal)
71*4882a593Smuzhiyun break;
72*4882a593Smuzhiyun dev_id_len = equal - mtdids;
73*4882a593Smuzhiyun mtd_id = equal + 1;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun /* Find the end of the tupple */
76*4882a593Smuzhiyun comma = strchr(mtdids, ',');
77*4882a593Smuzhiyun if (comma)
78*4882a593Smuzhiyun mtd_id_len = comma - mtd_id;
79*4882a593Smuzhiyun else
80*4882a593Smuzhiyun mtd_id_len = &mtdids[strlen(mtdids)] - mtd_id + 1;
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun if (!dev_id_len || !mtd_id_len)
83*4882a593Smuzhiyun return -EINVAL;
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun if (dev_id_len + 1 > max_len)
86*4882a593Smuzhiyun continue;
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun /* Compare the name we search with the current mtd_id */
89*4882a593Smuzhiyun if (!strncmp(mtdname, mtd_id, mtd_id_len)) {
90*4882a593Smuzhiyun strncpy(altname, dev_id, dev_id_len);
91*4882a593Smuzhiyun altname[dev_id_len] = 0;
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun return 0;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun /* Go to the next tupple */
97*4882a593Smuzhiyun mtdids = comma + 1;
98*4882a593Smuzhiyun } while (comma);
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun return -EINVAL;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_MTD)
mtd_probe_uclass_mtd_devs(void)104*4882a593Smuzhiyun static void mtd_probe_uclass_mtd_devs(void)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun struct udevice *dev;
107*4882a593Smuzhiyun int idx = 0;
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun /* Probe devices with DM compliant drivers */
110*4882a593Smuzhiyun while (!uclass_find_device(UCLASS_MTD, idx, &dev) && dev) {
111*4882a593Smuzhiyun mtd_probe(dev);
112*4882a593Smuzhiyun idx++;
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun #else
mtd_probe_uclass_mtd_devs(void)116*4882a593Smuzhiyun static void mtd_probe_uclass_mtd_devs(void) { }
117*4882a593Smuzhiyun #endif
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_DM_SPI_FLASH) && IS_ENABLED(CONFIG_SPI_FLASH_MTD)
mtd_probe_uclass_spi_nor_devs(void)120*4882a593Smuzhiyun static void __maybe_unused mtd_probe_uclass_spi_nor_devs(void)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun struct udevice *dev;
123*4882a593Smuzhiyun int idx = 0;
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun /* Probe devices with DM compliant drivers */
126*4882a593Smuzhiyun while (!uclass_find_device(UCLASS_SPI_FLASH, idx, &dev) && dev) {
127*4882a593Smuzhiyun device_probe(dev);
128*4882a593Smuzhiyun idx++;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun #else
mtd_probe_uclass_spi_nor_devs(void)132*4882a593Smuzhiyun static void __maybe_unused mtd_probe_uclass_spi_nor_devs(void) { }
133*4882a593Smuzhiyun #endif
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun #if defined(CONFIG_MTD_PARTITIONS)
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun #define MTDPARTS_MAXLEN 512
138*4882a593Smuzhiyun
get_mtdparts(void)139*4882a593Smuzhiyun static const char *get_mtdparts(void)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun __maybe_unused const char *mtdids = NULL;
142*4882a593Smuzhiyun static char tmp_parts[MTDPARTS_MAXLEN];
143*4882a593Smuzhiyun const char *mtdparts = NULL;
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun if (gd->flags & GD_FLG_ENV_READY)
146*4882a593Smuzhiyun mtdparts = env_get("mtdparts");
147*4882a593Smuzhiyun else if (env_get_f("mtdparts", tmp_parts, sizeof(tmp_parts)) != -1)
148*4882a593Smuzhiyun mtdparts = tmp_parts;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun if (mtdparts)
151*4882a593Smuzhiyun return mtdparts;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun #if defined(CONFIG_SYS_MTDPARTS_RUNTIME)
154*4882a593Smuzhiyun board_mtdparts_default(&mtdids, &mtdparts);
155*4882a593Smuzhiyun #elif defined(MTDPARTS_DEFAULT)
156*4882a593Smuzhiyun mtdparts = MTDPARTS_DEFAULT;
157*4882a593Smuzhiyun #elif defined(CONFIG_MTDPARTS_DEFAULT)
158*4882a593Smuzhiyun mtdparts = CONFIG_MTDPARTS_DEFAULT;
159*4882a593Smuzhiyun #endif
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun if (mtdparts)
162*4882a593Smuzhiyun env_set("mtdparts", mtdparts);
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun return mtdparts;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun
mtd_del_parts(struct mtd_info * mtd,bool quiet)167*4882a593Smuzhiyun static int mtd_del_parts(struct mtd_info *mtd, bool quiet)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun int ret;
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun if (!mtd_has_partitions(mtd))
172*4882a593Smuzhiyun return 0;
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun /* do not delete partitions if they are in use. */
175*4882a593Smuzhiyun if (mtd_partitions_used(mtd)) {
176*4882a593Smuzhiyun if (!quiet)
177*4882a593Smuzhiyun printf("\"%s\" partitions still in use, can't delete them\n",
178*4882a593Smuzhiyun mtd->name);
179*4882a593Smuzhiyun return -EACCES;
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun ret = del_mtd_partitions(mtd);
183*4882a593Smuzhiyun if (ret)
184*4882a593Smuzhiyun return ret;
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun return 1;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun static bool mtd_del_all_parts_failed;
190*4882a593Smuzhiyun
mtd_del_all_parts(void)191*4882a593Smuzhiyun static void mtd_del_all_parts(void)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun struct mtd_info *mtd;
194*4882a593Smuzhiyun int ret = 0;
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun mtd_del_all_parts_failed = false;
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun /*
199*4882a593Smuzhiyun * It is not safe to remove entries from the mtd_for_each_device loop
200*4882a593Smuzhiyun * as it uses idr indexes and the partitions removal is done in bulk
201*4882a593Smuzhiyun * (all partitions of one device at the same time), so break and
202*4882a593Smuzhiyun * iterate from start each time a new partition is found and deleted.
203*4882a593Smuzhiyun */
204*4882a593Smuzhiyun do {
205*4882a593Smuzhiyun mtd_for_each_device(mtd) {
206*4882a593Smuzhiyun ret = mtd_del_parts(mtd, false);
207*4882a593Smuzhiyun if (ret > 0)
208*4882a593Smuzhiyun break;
209*4882a593Smuzhiyun else if (ret < 0)
210*4882a593Smuzhiyun mtd_del_all_parts_failed = true;
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun } while (ret > 0);
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
mtd_probe_devices(void)215*4882a593Smuzhiyun int mtd_probe_devices(void)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun static char *old_mtdparts;
218*4882a593Smuzhiyun static char *old_mtdids;
219*4882a593Smuzhiyun const char *mtdparts = get_mtdparts();
220*4882a593Smuzhiyun const char *mtdids = get_mtdids();
221*4882a593Smuzhiyun const char *mtdparts_next = mtdparts;
222*4882a593Smuzhiyun struct mtd_info *mtd;
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun mtd_probe_uclass_mtd_devs();
225*4882a593Smuzhiyun mtd_probe_uclass_spi_nor_devs();
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun /*
228*4882a593Smuzhiyun * Check if mtdparts/mtdids changed, if the MTD dev list was updated
229*4882a593Smuzhiyun * or if our previous attempt to delete existing partititions failed.
230*4882a593Smuzhiyun * In any of these cases we want to update the partitions, otherwise,
231*4882a593Smuzhiyun * everything is up-to-date and we can return 0 directly.
232*4882a593Smuzhiyun */
233*4882a593Smuzhiyun if ((!mtdparts && !old_mtdparts && !mtdids && !old_mtdids) ||
234*4882a593Smuzhiyun (mtdparts && old_mtdparts && mtdids && old_mtdids &&
235*4882a593Smuzhiyun !mtd_dev_list_updated() && !mtd_del_all_parts_failed &&
236*4882a593Smuzhiyun !strcmp(mtdparts, old_mtdparts) &&
237*4882a593Smuzhiyun !strcmp(mtdids, old_mtdids)))
238*4882a593Smuzhiyun return 0;
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun /* Update the local copy of mtdparts */
241*4882a593Smuzhiyun free(old_mtdparts);
242*4882a593Smuzhiyun free(old_mtdids);
243*4882a593Smuzhiyun old_mtdparts = strdup(mtdparts);
244*4882a593Smuzhiyun old_mtdids = strdup(mtdids);
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun /*
247*4882a593Smuzhiyun * Remove all old parts. Note that partition removal can fail in case
248*4882a593Smuzhiyun * one of the partition is still being used by an MTD user, so this
249*4882a593Smuzhiyun * does not guarantee that all old partitions are gone.
250*4882a593Smuzhiyun */
251*4882a593Smuzhiyun mtd_del_all_parts();
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun /*
254*4882a593Smuzhiyun * Call mtd_dev_list_updated() to clear updates generated by our own
255*4882a593Smuzhiyun * parts removal loop.
256*4882a593Smuzhiyun */
257*4882a593Smuzhiyun mtd_dev_list_updated();
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun /* If either mtdparts or mtdids is empty, then exit */
260*4882a593Smuzhiyun if (!mtdparts || !mtdids)
261*4882a593Smuzhiyun return 0;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun /* Start the parsing by ignoring the extra 'mtdparts=' prefix, if any */
264*4882a593Smuzhiyun if (!strncmp(mtdparts, "mtdparts=", sizeof("mtdparts=") - 1))
265*4882a593Smuzhiyun mtdparts += 9;
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun /* For each MTD device in mtdparts */
268*4882a593Smuzhiyun for (; mtdparts[0] != '\0'; mtdparts = mtdparts_next) {
269*4882a593Smuzhiyun char mtd_name[MTD_NAME_MAX_LEN], *colon;
270*4882a593Smuzhiyun struct mtd_partition *parts;
271*4882a593Smuzhiyun unsigned int mtd_name_len;
272*4882a593Smuzhiyun int nparts, ret;
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun mtdparts_next = strchr(mtdparts, ';');
275*4882a593Smuzhiyun if (!mtdparts_next)
276*4882a593Smuzhiyun mtdparts_next = mtdparts + strlen(mtdparts);
277*4882a593Smuzhiyun else
278*4882a593Smuzhiyun mtdparts_next++;
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun colon = strchr(mtdparts, ':');
281*4882a593Smuzhiyun if (colon > mtdparts_next)
282*4882a593Smuzhiyun colon = NULL;
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun if (!colon) {
285*4882a593Smuzhiyun printf("Wrong mtdparts: %s\n", mtdparts);
286*4882a593Smuzhiyun return -EINVAL;
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun mtd_name_len = (unsigned int)(colon - mtdparts);
290*4882a593Smuzhiyun if (mtd_name_len + 1 > sizeof(mtd_name)) {
291*4882a593Smuzhiyun printf("MTD name too long: %s\n", mtdparts);
292*4882a593Smuzhiyun return -EINVAL;
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun strncpy(mtd_name, mtdparts, mtd_name_len);
296*4882a593Smuzhiyun mtd_name[mtd_name_len] = '\0';
297*4882a593Smuzhiyun /* Move the pointer forward (including the ':') */
298*4882a593Smuzhiyun mtdparts += mtd_name_len + 1;
299*4882a593Smuzhiyun mtd = get_mtd_device_nm(mtd_name);
300*4882a593Smuzhiyun if (IS_ERR_OR_NULL(mtd)) {
301*4882a593Smuzhiyun char linux_name[MTD_NAME_MAX_LEN];
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun /*
304*4882a593Smuzhiyun * The MTD device named "mtd_name" does not exist. Try
305*4882a593Smuzhiyun * to find a correspondance with an MTD device having
306*4882a593Smuzhiyun * the same type and number as defined in the mtdids.
307*4882a593Smuzhiyun */
308*4882a593Smuzhiyun debug("No device named %s\n", mtd_name);
309*4882a593Smuzhiyun ret = mtd_search_alternate_name(mtd_name, linux_name,
310*4882a593Smuzhiyun MTD_NAME_MAX_LEN);
311*4882a593Smuzhiyun if (!ret)
312*4882a593Smuzhiyun mtd = get_mtd_device_nm(linux_name);
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun /*
315*4882a593Smuzhiyun * If no device could be found, move the mtdparts
316*4882a593Smuzhiyun * pointer forward until the next set of partitions.
317*4882a593Smuzhiyun */
318*4882a593Smuzhiyun if (ret || IS_ERR_OR_NULL(mtd)) {
319*4882a593Smuzhiyun printf("Could not find a valid device for %s\n",
320*4882a593Smuzhiyun mtd_name);
321*4882a593Smuzhiyun mtdparts = mtdparts_next;
322*4882a593Smuzhiyun continue;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun /*
327*4882a593Smuzhiyun * Call mtd_del_parts() again, even if it's already been called
328*4882a593Smuzhiyun * in mtd_del_all_parts(). We need to know if old partitions are
329*4882a593Smuzhiyun * still around (because they are still being used by someone),
330*4882a593Smuzhiyun * and if they are, we shouldn't create new partitions, so just
331*4882a593Smuzhiyun * skip this MTD device and try the next one.
332*4882a593Smuzhiyun */
333*4882a593Smuzhiyun ret = mtd_del_parts(mtd, true);
334*4882a593Smuzhiyun if (ret < 0)
335*4882a593Smuzhiyun continue;
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun /*
338*4882a593Smuzhiyun * Parse the MTD device partitions. It will update the mtdparts
339*4882a593Smuzhiyun * pointer, create an array of parts (that must be freed), and
340*4882a593Smuzhiyun * return the number of partition structures in the array.
341*4882a593Smuzhiyun */
342*4882a593Smuzhiyun ret = mtd_parse_partitions(mtd, &mtdparts, &parts, &nparts);
343*4882a593Smuzhiyun if (ret) {
344*4882a593Smuzhiyun printf("Could not parse device %s\n", mtd->name);
345*4882a593Smuzhiyun put_mtd_device(mtd);
346*4882a593Smuzhiyun return -EINVAL;
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun if (!nparts)
350*4882a593Smuzhiyun continue;
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun /* Create the new MTD partitions */
353*4882a593Smuzhiyun add_mtd_partitions(mtd, parts, nparts);
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun /* Free the structures allocated during the parsing */
356*4882a593Smuzhiyun mtd_free_parsed_partitions(parts, nparts);
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun put_mtd_device(mtd);
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun /*
362*4882a593Smuzhiyun * Call mtd_dev_list_updated() to clear updates generated by our own
363*4882a593Smuzhiyun * parts registration loop.
364*4882a593Smuzhiyun */
365*4882a593Smuzhiyun mtd_dev_list_updated();
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun return 0;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun #else
mtd_probe_devices(void)370*4882a593Smuzhiyun int mtd_probe_devices(void)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun mtd_probe_uclass_mtd_devs();
373*4882a593Smuzhiyun mtd_probe_uclass_spi_nor_devs();
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun return 0;
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun #endif /* defined(CONFIG_MTD_PARTITIONS) */
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun /* Legacy */
380*4882a593Smuzhiyun
get_part(const char * partname,int * idx,loff_t * off,loff_t * size,loff_t * maxsize,int devtype)381*4882a593Smuzhiyun static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size,
382*4882a593Smuzhiyun loff_t *maxsize, int devtype)
383*4882a593Smuzhiyun {
384*4882a593Smuzhiyun #ifdef CONFIG_CMD_MTDPARTS
385*4882a593Smuzhiyun struct mtd_device *dev;
386*4882a593Smuzhiyun struct part_info *part;
387*4882a593Smuzhiyun u8 pnum;
388*4882a593Smuzhiyun int ret;
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun ret = mtdparts_init();
391*4882a593Smuzhiyun if (ret)
392*4882a593Smuzhiyun return ret;
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun ret = find_dev_and_part(partname, &dev, &pnum, &part);
395*4882a593Smuzhiyun if (ret)
396*4882a593Smuzhiyun return ret;
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun if (dev->id->type != devtype) {
399*4882a593Smuzhiyun printf("not same typ %d != %d\n", dev->id->type, devtype);
400*4882a593Smuzhiyun return -1;
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun *off = part->offset;
404*4882a593Smuzhiyun *size = part->size;
405*4882a593Smuzhiyun *maxsize = part->size;
406*4882a593Smuzhiyun *idx = dev->id->num;
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun return 0;
409*4882a593Smuzhiyun #else
410*4882a593Smuzhiyun puts("mtdparts support missing.\n");
411*4882a593Smuzhiyun return -1;
412*4882a593Smuzhiyun #endif
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun
mtd_arg_off(const char * arg,int * idx,loff_t * off,loff_t * size,loff_t * maxsize,int devtype,uint64_t chipsize)415*4882a593Smuzhiyun int mtd_arg_off(const char *arg, int *idx, loff_t *off, loff_t *size,
416*4882a593Smuzhiyun loff_t *maxsize, int devtype, uint64_t chipsize)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun if (!str2off(arg, off))
419*4882a593Smuzhiyun return get_part(arg, idx, off, size, maxsize, devtype);
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun if (*off >= chipsize) {
422*4882a593Smuzhiyun puts("Offset exceeds device limit\n");
423*4882a593Smuzhiyun return -1;
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun *maxsize = chipsize - *off;
427*4882a593Smuzhiyun *size = *maxsize;
428*4882a593Smuzhiyun return 0;
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun
mtd_arg_off_size(int argc,char * const argv[],int * idx,loff_t * off,loff_t * size,loff_t * maxsize,int devtype,uint64_t chipsize)431*4882a593Smuzhiyun int mtd_arg_off_size(int argc, char *const argv[], int *idx, loff_t *off,
432*4882a593Smuzhiyun loff_t *size, loff_t *maxsize, int devtype,
433*4882a593Smuzhiyun uint64_t chipsize)
434*4882a593Smuzhiyun {
435*4882a593Smuzhiyun int ret;
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun if (argc == 0) {
438*4882a593Smuzhiyun *off = 0;
439*4882a593Smuzhiyun *size = chipsize;
440*4882a593Smuzhiyun *maxsize = *size;
441*4882a593Smuzhiyun goto print;
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun ret = mtd_arg_off(argv[0], idx, off, size, maxsize, devtype,
445*4882a593Smuzhiyun chipsize);
446*4882a593Smuzhiyun if (ret)
447*4882a593Smuzhiyun return ret;
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun if (argc == 1)
450*4882a593Smuzhiyun goto print;
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun if (!str2off(argv[1], size)) {
453*4882a593Smuzhiyun printf("'%s' is not a number\n", argv[1]);
454*4882a593Smuzhiyun return -1;
455*4882a593Smuzhiyun }
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun if (*size > *maxsize) {
458*4882a593Smuzhiyun puts("Size exceeds partition or device limit\n");
459*4882a593Smuzhiyun return -1;
460*4882a593Smuzhiyun }
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun print:
463*4882a593Smuzhiyun printf("device %d ", *idx);
464*4882a593Smuzhiyun if (*size == chipsize)
465*4882a593Smuzhiyun puts("whole chip\n");
466*4882a593Smuzhiyun else
467*4882a593Smuzhiyun printf("offset 0x%llx, size 0x%llx\n",
468*4882a593Smuzhiyun (unsigned long long)*off, (unsigned long long)*size);
469*4882a593Smuzhiyun return 0;
470*4882a593Smuzhiyun }
471