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