]>
git.ipfire.org Git - thirdparty/u-boot.git/blob - drivers/mtd/mtd_uboot.c
1 // SPDX-License-Identifier: GPL-2.0+
4 * Heiko Schocher, DENX Software Engineering, hs@denx.de.
8 #include <dm/uclass-internal.h>
9 #include <jffs2/jffs2.h> /* LEGACY */
10 #include <linux/mtd/mtd.h>
11 #include <linux/mtd/partitions.h>
14 #define MTD_NAME_MAX_LEN 20
16 void board_mtdparts_default(const char **mtdids
, const char **mtdparts
);
18 static const char *get_mtdids(void)
20 __maybe_unused
const char *mtdparts
= NULL
;
21 const char *mtdids
= env_get("mtdids");
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
;
35 env_set("mtdids", mtdids
);
41 * mtd_search_alternate_name - Search an alternate name for @mtdname thanks to
42 * the mtdids legacy environment variable.
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
48 * @mtdname: Current MTD device name
49 * @altname: Alternate name to return
50 * @max_len: Length of the alternate name buffer
52 * @return 0 on success, an error otherwise.
54 int mtd_search_alternate_name(const char *mtdname
, char *altname
,
57 const char *mtdids
, *equal
, *comma
, *dev_id
, *mtd_id
;
58 int dev_id_len
, mtd_id_len
;
60 mtdids
= get_mtdids();
65 /* Find the '=' sign */
67 equal
= strchr(dev_id
, '=');
70 dev_id_len
= equal
- mtdids
;
73 /* Find the end of the tupple */
74 comma
= strchr(mtdids
, ',');
76 mtd_id_len
= comma
- mtd_id
;
78 mtd_id_len
= &mtdids
[strlen(mtdids
)] - mtd_id
+ 1;
80 if (!dev_id_len
|| !mtd_id_len
)
83 if (dev_id_len
+ 1 > max_len
)
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;
94 /* Go to the next tupple */
101 #if IS_ENABLED(CONFIG_MTD)
102 static void mtd_probe_uclass_mtd_devs(void)
107 /* Probe devices with DM compliant drivers */
108 while (!uclass_find_device(UCLASS_MTD
, idx
, &dev
) && dev
) {
114 static void mtd_probe_uclass_mtd_devs(void) { }
117 #if defined(CONFIG_MTD_PARTITIONS)
119 #define MTDPARTS_MAXLEN 512
121 static const char *get_mtdparts(void)
123 __maybe_unused
const char *mtdids
= NULL
;
124 static char tmp_parts
[MTDPARTS_MAXLEN
];
125 static bool use_defaults
= true;
126 const char *mtdparts
= NULL
;
128 if (gd
->flags
& GD_FLG_ENV_READY
)
129 mtdparts
= env_get("mtdparts");
130 else if (env_get_f("mtdparts", tmp_parts
, sizeof(tmp_parts
)) != -1)
131 mtdparts
= tmp_parts
;
133 if (mtdparts
|| !use_defaults
)
136 #if defined(CONFIG_SYS_MTDPARTS_RUNTIME)
137 board_mtdparts_default(&mtdids
, &mtdparts
);
138 #elif defined(MTDPARTS_DEFAULT)
139 mtdparts
= MTDPARTS_DEFAULT
;
140 #elif defined(CONFIG_MTDPARTS_DEFAULT)
141 mtdparts
= CONFIG_MTDPARTS_DEFAULT
;
145 env_set("mtdparts", mtdparts
);
147 use_defaults
= false;
152 int mtd_probe_devices(void)
154 static char *old_mtdparts
;
155 static char *old_mtdids
;
156 const char *mtdparts
= get_mtdparts();
157 const char *mtdids
= get_mtdids();
158 bool remaining_partitions
= true;
159 struct mtd_info
*mtd
;
161 mtd_probe_uclass_mtd_devs();
164 * Check if mtdparts/mtdids changed or if the MTD dev list was updated
165 * since last call, otherwise: exit
167 if ((!mtdparts
&& !old_mtdparts
&& !mtdids
&& !old_mtdids
) ||
168 (mtdparts
&& old_mtdparts
&& mtdids
&& old_mtdids
&&
169 !mtd_dev_list_updated() &&
170 !strcmp(mtdparts
, old_mtdparts
) &&
171 !strcmp(mtdids
, old_mtdids
)))
174 /* Update the local copy of mtdparts */
177 old_mtdparts
= strdup(mtdparts
);
178 old_mtdids
= strdup(mtdids
);
180 /* If at least one partition is still in use, do not delete anything */
181 mtd_for_each_device(mtd
) {
183 printf("Partition \"%s\" already in use, aborting\n",
190 * Everything looks clear, remove all partitions. It is not safe to
191 * remove entries from the mtd_for_each_device loop as it uses idr
192 * indexes and the partitions removal is done in bulk (all partitions of
193 * one device at the same time), so break and iterate from start each
194 * time a new partition is found and deleted.
196 while (remaining_partitions
) {
197 remaining_partitions
= false;
198 mtd_for_each_device(mtd
) {
199 if (!mtd_is_partition(mtd
) && mtd_has_partitions(mtd
)) {
200 del_mtd_partitions(mtd
);
201 remaining_partitions
= true;
208 * Call mtd_dev_list_updated() to clear updates generated by our own
209 * parts removal loop.
211 mtd_dev_list_updated();
213 /* If either mtdparts or mtdids is empty, then exit */
214 if (!mtdparts
|| !mtdids
)
217 /* Start the parsing by ignoring the extra 'mtdparts=' prefix, if any */
218 if (!strncmp(mtdparts
, "mtdparts=", sizeof("mtdparts=") - 1))
221 /* For each MTD device in mtdparts */
222 while (mtdparts
[0] != '\0') {
223 char mtd_name
[MTD_NAME_MAX_LEN
], *colon
;
224 struct mtd_partition
*parts
;
225 unsigned int mtd_name_len
;
228 colon
= strchr(mtdparts
, ':');
230 printf("Wrong mtdparts: %s\n", mtdparts
);
234 mtd_name_len
= (unsigned int)(colon
- mtdparts
);
235 if (mtd_name_len
+ 1 > sizeof(mtd_name
)) {
236 printf("MTD name too long: %s\n", mtdparts
);
240 strncpy(mtd_name
, mtdparts
, mtd_name_len
);
241 mtd_name
[mtd_name_len
] = '\0';
242 /* Move the pointer forward (including the ':') */
243 mtdparts
+= mtd_name_len
+ 1;
244 mtd
= get_mtd_device_nm(mtd_name
);
245 if (IS_ERR_OR_NULL(mtd
)) {
246 char linux_name
[MTD_NAME_MAX_LEN
];
249 * The MTD device named "mtd_name" does not exist. Try
250 * to find a correspondance with an MTD device having
251 * the same type and number as defined in the mtdids.
253 debug("No device named %s\n", mtd_name
);
254 ret
= mtd_search_alternate_name(mtd_name
, linux_name
,
257 mtd
= get_mtd_device_nm(linux_name
);
260 * If no device could be found, move the mtdparts
261 * pointer forward until the next set of partitions.
263 if (ret
|| IS_ERR_OR_NULL(mtd
)) {
264 printf("Could not find a valid device for %s\n",
266 mtdparts
= strchr(mtdparts
, ';');
275 * Parse the MTD device partitions. It will update the mtdparts
276 * pointer, create an array of parts (that must be freed), and
277 * return the number of partition structures in the array.
279 ret
= mtd_parse_partitions(mtd
, &mtdparts
, &parts
, &nparts
);
281 printf("Could not parse device %s\n", mtd
->name
);
289 /* Create the new MTD partitions */
290 add_mtd_partitions(mtd
, parts
, nparts
);
292 /* Free the structures allocated during the parsing */
293 mtd_free_parsed_partitions(parts
, nparts
);
299 * Call mtd_dev_list_updated() to clear updates generated by our own
300 * parts registration loop.
302 mtd_dev_list_updated();
307 int mtd_probe_devices(void)
309 mtd_probe_uclass_mtd_devs();
313 #endif /* defined(CONFIG_MTD_PARTITIONS) */
317 static int get_part(const char *partname
, int *idx
, loff_t
*off
, loff_t
*size
,
318 loff_t
*maxsize
, int devtype
)
320 #ifdef CONFIG_CMD_MTDPARTS
321 struct mtd_device
*dev
;
322 struct part_info
*part
;
326 ret
= mtdparts_init();
330 ret
= find_dev_and_part(partname
, &dev
, &pnum
, &part
);
334 if (dev
->id
->type
!= devtype
) {
335 printf("not same typ %d != %d\n", dev
->id
->type
, devtype
);
341 *maxsize
= part
->size
;
346 puts("mtdparts support missing.\n");
351 int mtd_arg_off(const char *arg
, int *idx
, loff_t
*off
, loff_t
*size
,
352 loff_t
*maxsize
, int devtype
, uint64_t chipsize
)
354 if (!str2off(arg
, off
))
355 return get_part(arg
, idx
, off
, size
, maxsize
, devtype
);
357 if (*off
>= chipsize
) {
358 puts("Offset exceeds device limit\n");
362 *maxsize
= chipsize
- *off
;
367 int mtd_arg_off_size(int argc
, char *const argv
[], int *idx
, loff_t
*off
,
368 loff_t
*size
, loff_t
*maxsize
, int devtype
,
380 ret
= mtd_arg_off(argv
[0], idx
, off
, size
, maxsize
, devtype
,
388 if (!str2off(argv
[1], size
)) {
389 printf("'%s' is not a number\n", argv
[1]);
393 if (*size
> *maxsize
) {
394 puts("Size exceeds partition or device limit\n");
399 printf("device %d ", *idx
);
400 if (*size
== chipsize
)
401 puts("whole chip\n");
403 printf("offset 0x%llx, size 0x%llx\n",
404 (unsigned long long)*off
, (unsigned long long)*size
);