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 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 */ 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) 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 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) 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 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 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 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 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 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 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 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 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 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