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