xref: /OK3568_Linux_fs/u-boot/drivers/mtd/mtd_uboot.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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