1 // SPDX-License-Identifier: GPL-2.0+
4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
7 * Robert Schwebel, Pengutronix, <r.schwebel@pengutronix.de>
10 * Kai-Uwe Bloem, Auerswald GmbH & Co KG, <linux-development@auerswald.de>
13 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
15 * Added support for reading flash partition table from environment.
16 * Parsing routines are based on driver/mtd/cmdline.c from the linux 2.4
19 * $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $
20 * Copyright 2002 SYSGO Real-Time Solutions GmbH
24 * Three environment variables are used by the parsing routines:
26 * 'partition' - keeps current partition identifier
28 * partition := <part-id>
29 * <part-id> := <dev-id>,part_num
32 * 'mtdids' - linux kernel mtd device id <-> u-boot device id mapping
34 * mtdids=<idmap>[,<idmap>,...]
36 * <idmap> := <dev-id>=<mtd-id>
37 * <dev-id> := 'nand'|'nor'|'onenand'<dev-num>
38 * <dev-num> := mtd device number, 0...
39 * <mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name)
42 * 'mtdparts' - partition list
44 * mtdparts=mtdparts=<mtd-def>[;<mtd-def>...]
46 * <mtd-def> := <mtd-id>:<part-def>[,<part-def>...]
47 * <mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name)
48 * <part-def> := <size>[@<offset>][<name>][<ro-flag>]
49 * <size> := standard linux memsize OR '-' to denote all remaining space
50 * <offset> := partition start offset within the device
51 * <name> := '(' NAME ')'
52 * <ro-flag> := when set to 'ro' makes partition read-only (not used, passed to kernel)
55 * - each <mtd-id> used in mtdparts must albo exist in 'mtddis' mapping
56 * - if the above variables are not set defaults for a given target are used
60 * 1 NOR Flash, with 1 single writable partition:
61 * mtdids=nor0=edb7312-nor
62 * mtdparts=mtdparts=edb7312-nor:-
64 * 1 NOR Flash with 2 partitions, 1 NAND with one
65 * mtdids=nor0=edb7312-nor,nand0=edb7312-nand
66 * mtdparts=mtdparts=edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
71 * JFFS2/CRAMFS support
79 #include <jffs2/jffs2.h>
80 #include <linux/list.h>
81 #include <linux/ctype.h>
82 #include <cramfs/cramfs_fs.h>
84 #if defined(CONFIG_CMD_NAND)
85 #include <linux/mtd/rawnand.h>
89 #if defined(CONFIG_CMD_ONENAND)
90 #include <linux/mtd/mtd.h>
91 #include <linux/mtd/onenand.h>
92 #include <onenand_uboot.h>
95 /* enable/disable debugging messages */
100 # define DEBUGF(fmt, args...) printf(fmt ,##args)
102 # define DEBUGF(fmt, args...)
105 /* special size referring to all the remaining space in a partition */
106 #define SIZE_REMAINING 0xFFFFFFFF
108 /* special offset value, it is used when not provided by user
110 * this value is used temporarily during parsing, later such offests
111 * are recalculated */
112 #define OFFSET_NOT_SPECIFIED 0xFFFFFFFF
114 /* minimum partition size */
115 #define MIN_PART_SIZE 4096
117 /* this flag needs to be set in part_info struct mask_flags
118 * field for read-only partitions */
119 #define MTD_WRITEABLE_CMD 1
121 /* current active device and partition number */
122 #ifdef CONFIG_CMD_MTDPARTS
123 /* Use the ones declared in cmd_mtdparts.c */
124 extern struct mtd_device
*current_mtd_dev
;
125 extern u8 current_mtd_partnum
;
128 struct mtd_device
*current_mtd_dev
= NULL
;
129 u8 current_mtd_partnum
= 0;
132 #if defined(CONFIG_CMD_CRAMFS)
133 extern int cramfs_check (struct part_info
*info
);
134 extern int cramfs_load (char *loadoffset
, struct part_info
*info
, char *filename
);
135 extern int cramfs_ls (struct part_info
*info
, char *filename
);
136 extern int cramfs_info (struct part_info
*info
);
138 /* defining empty macros for function names is ugly but avoids ifdef clutter
139 * all over the code */
140 #define cramfs_check(x) (0)
141 #define cramfs_load(x,y,z) (-1)
142 #define cramfs_ls(x,y) (0)
143 #define cramfs_info(x) (0)
146 #ifndef CONFIG_CMD_MTDPARTS
148 * Check device number to be within valid range for given device type.
150 * @param dev device to validate
151 * @return 0 if device is valid, 1 otherwise
153 static int mtd_device_validate(u8 type
, u8 num
, u32
*size
)
155 if (type
== MTD_DEV_TYPE_NOR
) {
156 #if defined(CONFIG_CMD_FLASH)
157 if (num
< CONFIG_SYS_MAX_FLASH_BANKS
) {
158 extern flash_info_t flash_info
[];
159 *size
= flash_info
[num
].size
;
164 printf("no such FLASH device: %s%d (valid range 0 ... %d\n",
165 MTD_DEV_TYPE(type
), num
, CONFIG_SYS_MAX_FLASH_BANKS
- 1);
167 printf("support for FLASH devices not present\n");
169 } else if (type
== MTD_DEV_TYPE_NAND
) {
170 #if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND)
171 struct mtd_info
*mtd
= get_nand_dev_by_index(num
);
177 printf("no such NAND device: %s%d (valid range 0 ... %d)\n",
178 MTD_DEV_TYPE(type
), num
, CONFIG_SYS_MAX_NAND_DEVICE
- 1);
180 printf("support for NAND devices not present\n");
182 } else if (type
== MTD_DEV_TYPE_ONENAND
) {
183 #if defined(CONFIG_CMD_ONENAND)
184 *size
= onenand_mtd
.size
;
187 printf("support for OneNAND devices not present\n");
190 printf("Unknown defice type %d\n", type
);
196 * Parse device id string <dev-id> := 'nand'|'nor'|'onenand'<dev-num>,
197 * return device type and number.
199 * @param id string describing device id
200 * @param ret_id output pointer to next char after parse completes (output)
201 * @param dev_type parsed device type (output)
202 * @param dev_num parsed device number (output)
203 * @return 0 on success, 1 otherwise
205 static int mtd_id_parse(const char *id
, const char **ret_id
, u8
*dev_type
, u8
*dev_num
)
210 if (strncmp(p
, "nand", 4) == 0) {
211 *dev_type
= MTD_DEV_TYPE_NAND
;
213 } else if (strncmp(p
, "nor", 3) == 0) {
214 *dev_type
= MTD_DEV_TYPE_NOR
;
216 } else if (strncmp(p
, "onenand", 7) == 0) {
217 *dev_type
= MTD_DEV_TYPE_ONENAND
;
220 printf("incorrect device type in %s\n", id
);
225 printf("incorrect device number in %s\n", id
);
229 *dev_num
= simple_strtoul(p
, (char **)&p
, 0);
236 * 'Static' version of command line mtdparts_init() routine. Single partition on
237 * a single device configuration.
241 * Calculate sector size.
243 * @return sector size
245 static inline u32
get_part_sector_size_nand(struct mtdids
*id
)
247 #if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND)
248 struct mtd_info
*mtd
;
250 mtd
= get_nand_dev_by_index(id
->num
);
252 return mtd
->erasesize
;
259 static inline u32
get_part_sector_size_nor(struct mtdids
*id
, struct part_info
*part
)
261 #if defined(CONFIG_CMD_FLASH)
262 extern flash_info_t flash_info
[];
264 u32 end_phys
, start_phys
, sector_size
= 0, size
= 0;
268 flash
= &flash_info
[id
->num
];
270 start_phys
= flash
->start
[0] + part
->offset
;
271 end_phys
= start_phys
+ part
->size
- 1;
273 for (i
= 0; i
< flash
->sector_count
; i
++) {
274 if (flash
->start
[i
] >= end_phys
)
277 if (flash
->start
[i
] >= start_phys
) {
278 if (i
== flash
->sector_count
- 1) {
279 size
= flash
->start
[0] + flash
->size
- flash
->start
[i
];
281 size
= flash
->start
[i
+1] - flash
->start
[i
];
284 if (sector_size
< size
)
296 static inline u32
get_part_sector_size_onenand(void)
298 #if defined(CONFIG_CMD_ONENAND)
299 struct mtd_info
*mtd
;
303 return mtd
->erasesize
;
310 static inline u32
get_part_sector_size(struct mtdids
*id
, struct part_info
*part
)
312 if (id
->type
== MTD_DEV_TYPE_NAND
)
313 return get_part_sector_size_nand(id
);
314 else if (id
->type
== MTD_DEV_TYPE_NOR
)
315 return get_part_sector_size_nor(id
, part
);
316 else if (id
->type
== MTD_DEV_TYPE_ONENAND
)
317 return get_part_sector_size_onenand();
319 DEBUGF("Error: Unknown device type.\n");
325 * Parse and initialize global mtdids mapping and create global
326 * device/partition list.
328 * 'Static' version of command line mtdparts_init() routine. Single partition on
329 * a single device configuration.
331 * @return 0 on success, 1 otherwise
333 int mtdparts_init(void)
335 static int initialized
= 0;
339 DEBUGF("\n---mtdparts_init---\n");
342 struct part_info
*part
;
345 current_mtd_dev
= (struct mtd_device
*)
346 malloc(sizeof(struct mtd_device
) +
347 sizeof(struct part_info
) +
348 sizeof(struct mtdids
));
349 if (!current_mtd_dev
) {
350 printf("out of memory\n");
353 memset(current_mtd_dev
, 0, sizeof(struct mtd_device
) +
354 sizeof(struct part_info
) + sizeof(struct mtdids
));
356 id
= (struct mtdids
*)(current_mtd_dev
+ 1);
357 part
= (struct part_info
*)(id
+ 1);
360 id
->mtd_id
= "single part";
362 #if defined(CONFIG_JFFS2_DEV)
363 dev_name
= CONFIG_JFFS2_DEV
;
368 if ((mtd_id_parse(dev_name
, NULL
, &id
->type
, &id
->num
) != 0) ||
369 (mtd_device_validate(id
->type
, id
->num
, &size
) != 0)) {
370 printf("incorrect device: %s%d\n", MTD_DEV_TYPE(id
->type
), id
->num
);
371 free(current_mtd_dev
);
375 INIT_LIST_HEAD(&id
->link
);
377 DEBUGF("dev id: type = %d, num = %d, size = 0x%08lx, mtd_id = %s\n",
378 id
->type
, id
->num
, id
->size
, id
->mtd_id
);
381 part
->name
= "static";
384 #if defined(CONFIG_JFFS2_PART_SIZE)
385 part
->size
= CONFIG_JFFS2_PART_SIZE
;
387 part
->size
= SIZE_REMAINING
;
390 #if defined(CONFIG_JFFS2_PART_OFFSET)
391 part
->offset
= CONFIG_JFFS2_PART_OFFSET
;
393 part
->offset
= 0x00000000;
396 part
->dev
= current_mtd_dev
;
397 INIT_LIST_HEAD(&part
->link
);
399 /* recalculate size if needed */
400 if (part
->size
== SIZE_REMAINING
)
401 part
->size
= id
->size
- part
->offset
;
403 part
->sector_size
= get_part_sector_size(id
, part
);
405 DEBUGF("part : name = %s, size = 0x%08lx, offset = 0x%08lx\n",
406 part
->name
, part
->size
, part
->offset
);
409 current_mtd_dev
->id
= id
;
410 INIT_LIST_HEAD(¤t_mtd_dev
->link
);
411 current_mtd_dev
->num_parts
= 1;
412 INIT_LIST_HEAD(¤t_mtd_dev
->parts
);
413 list_add(&part
->link
, ¤t_mtd_dev
->parts
);
418 #endif /* #ifndef CONFIG_CMD_MTDPARTS */
421 * Return pointer to the partition of a requested number from a requested
424 * @param dev device that is to be searched for a partition
425 * @param part_num requested partition number
426 * @return pointer to the part_info, NULL otherwise
428 static struct part_info
* jffs2_part_info(struct mtd_device
*dev
, unsigned int part_num
)
430 struct list_head
*entry
;
431 struct part_info
*part
;
437 DEBUGF("\n--- jffs2_part_info: partition number %d for device %s%d (%s)\n",
438 part_num
, MTD_DEV_TYPE(dev
->id
->type
),
439 dev
->id
->num
, dev
->id
->mtd_id
);
441 if (part_num
>= dev
->num_parts
) {
442 printf("invalid partition number %d for device %s%d (%s)\n",
443 part_num
, MTD_DEV_TYPE(dev
->id
->type
),
444 dev
->id
->num
, dev
->id
->mtd_id
);
448 /* locate partition number, return it */
450 list_for_each(entry
, &dev
->parts
) {
451 part
= list_entry(entry
, struct part_info
, link
);
453 if (part_num
== num
++) {
461 /***************************************************/
462 /* U-Boot commands */
463 /***************************************************/
466 * Routine implementing fsload u-boot command. This routine tries to load
467 * a requested file from jffs2/cramfs filesystem on a current partition.
469 * @param cmdtp command internal data
470 * @param flag command flag
471 * @param argc number of arguments supplied to the command
472 * @param argv arguments list
473 * @return 0 on success, 1 otherwise
475 int do_jffs2_fsload(cmd_tbl_t
*cmdtp
, int flag
, int argc
, char * const argv
[])
480 struct part_info
*part
;
481 ulong offset
= image_load_addr
;
483 /* pre-set Boot file name */
484 filename
= env_get("bootfile");
492 offset
= simple_strtoul(argv
[1], NULL
, 16);
493 image_load_addr
= offset
;
497 /* make sure we are in sync with env variables */
498 if (mtdparts_init() !=0)
501 if ((part
= jffs2_part_info(current_mtd_dev
, current_mtd_partnum
))){
503 /* check partition type for cramfs */
504 fsname
= (cramfs_check(part
) ? "CRAMFS" : "JFFS2");
505 printf("### %s loading '%s' to 0x%lx\n", fsname
, filename
, offset
);
507 if (cramfs_check(part
)) {
508 size
= cramfs_load ((char *) offset
, part
, filename
);
510 /* if this is not cramfs assume jffs2 */
511 size
= jffs2_1pass_load((char *)offset
, part
, filename
);
515 printf("### %s load complete: %d bytes loaded to 0x%lx\n",
516 fsname
, size
, offset
);
517 env_set_hex("filesize", size
);
519 printf("### %s LOAD ERROR<%x> for %s!\n", fsname
, size
, filename
);
528 * Routine implementing u-boot ls command which lists content of a given
529 * directory on a current partition.
531 * @param cmdtp command internal data
532 * @param flag command flag
533 * @param argc number of arguments supplied to the command
534 * @param argv arguments list
535 * @return 0 on success, 1 otherwise
537 int do_jffs2_ls(cmd_tbl_t
*cmdtp
, int flag
, int argc
, char * const argv
[])
539 char *filename
= "/";
541 struct part_info
*part
;
546 /* make sure we are in sync with env variables */
547 if (mtdparts_init() !=0)
550 if ((part
= jffs2_part_info(current_mtd_dev
, current_mtd_partnum
))){
552 /* check partition type for cramfs */
553 if (cramfs_check(part
)) {
554 ret
= cramfs_ls (part
, filename
);
556 /* if this is not cramfs assume jffs2 */
557 ret
= jffs2_1pass_ls(part
, filename
);
566 * Routine implementing u-boot fsinfo command. This routine prints out
567 * miscellaneous filesystem informations/statistics.
569 * @param cmdtp command internal data
570 * @param flag command flag
571 * @param argc number of arguments supplied to the command
572 * @param argv arguments list
573 * @return 0 on success, 1 otherwise
575 int do_jffs2_fsinfo(cmd_tbl_t
*cmdtp
, int flag
, int argc
, char * const argv
[])
577 struct part_info
*part
;
581 /* make sure we are in sync with env variables */
582 if (mtdparts_init() !=0)
585 if ((part
= jffs2_part_info(current_mtd_dev
, current_mtd_partnum
))){
587 /* check partition type for cramfs */
588 fsname
= (cramfs_check(part
) ? "CRAMFS" : "JFFS2");
589 printf("### filesystem type is %s\n", fsname
);
591 if (cramfs_check(part
)) {
592 ret
= cramfs_info (part
);
594 /* if this is not cramfs assume jffs2 */
595 ret
= jffs2_1pass_info(part
);
603 /***************************************************/
605 fsload
, 3, 0, do_jffs2_fsload
,
606 "load binary file from a filesystem image",
607 "[ off ] [ filename ]\n"
608 " - load binary file from flash bank\n"
612 fsls
, 2, 1, do_jffs2_ls
,
613 "list files in a directory (default /)",
618 fsinfo
, 1, 1, do_jffs2_fsinfo
,
619 "print information about filesystems",
622 /***************************************************/