xref: /OK3568_Linux_fs/u-boot/cmd/jffs2.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * (C) Copyright 2002
3*4882a593Smuzhiyun  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * (C) Copyright 2002
6*4882a593Smuzhiyun  * Robert Schwebel, Pengutronix, <r.schwebel@pengutronix.de>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * (C) Copyright 2003
9*4882a593Smuzhiyun  * Kai-Uwe Bloem, Auerswald GmbH & Co KG, <linux-development@auerswald.de>
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * (C) Copyright 2005
12*4882a593Smuzhiyun  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  *   Added support for reading flash partition table from environment.
15*4882a593Smuzhiyun  *   Parsing routines are based on driver/mtd/cmdline.c from the linux 2.4
16*4882a593Smuzhiyun  *   kernel tree.
17*4882a593Smuzhiyun  *
18*4882a593Smuzhiyun  *   $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $
19*4882a593Smuzhiyun  *   Copyright 2002 SYSGO Real-Time Solutions GmbH
20*4882a593Smuzhiyun  *
21*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
22*4882a593Smuzhiyun  */
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun /*
25*4882a593Smuzhiyun  * Three environment variables are used by the parsing routines:
26*4882a593Smuzhiyun  *
27*4882a593Smuzhiyun  * 'partition' - keeps current partition identifier
28*4882a593Smuzhiyun  *
29*4882a593Smuzhiyun  * partition  := <part-id>
30*4882a593Smuzhiyun  * <part-id>  := <dev-id>,part_num
31*4882a593Smuzhiyun  *
32*4882a593Smuzhiyun  *
33*4882a593Smuzhiyun  * 'mtdids' - linux kernel mtd device id <-> u-boot device id mapping
34*4882a593Smuzhiyun  *
35*4882a593Smuzhiyun  * mtdids=<idmap>[,<idmap>,...]
36*4882a593Smuzhiyun  *
37*4882a593Smuzhiyun  * <idmap>    := <dev-id>=<mtd-id>
38*4882a593Smuzhiyun  * <dev-id>   := 'nand'|'nor'|'onenand'<dev-num>
39*4882a593Smuzhiyun  * <dev-num>  := mtd device number, 0...
40*4882a593Smuzhiyun  * <mtd-id>   := unique device tag used by linux kernel to find mtd device (mtd->name)
41*4882a593Smuzhiyun  *
42*4882a593Smuzhiyun  *
43*4882a593Smuzhiyun  * 'mtdparts' - partition list
44*4882a593Smuzhiyun  *
45*4882a593Smuzhiyun  * mtdparts=mtdparts=<mtd-def>[;<mtd-def>...]
46*4882a593Smuzhiyun  *
47*4882a593Smuzhiyun  * <mtd-def>  := <mtd-id>:<part-def>[,<part-def>...]
48*4882a593Smuzhiyun  * <mtd-id>   := unique device tag used by linux kernel to find mtd device (mtd->name)
49*4882a593Smuzhiyun  * <part-def> := <size>[@<offset>][<name>][<ro-flag>]
50*4882a593Smuzhiyun  * <size>     := standard linux memsize OR '-' to denote all remaining space
51*4882a593Smuzhiyun  * <offset>   := partition start offset within the device
52*4882a593Smuzhiyun  * <name>     := '(' NAME ')'
53*4882a593Smuzhiyun  * <ro-flag>  := when set to 'ro' makes partition read-only (not used, passed to kernel)
54*4882a593Smuzhiyun  *
55*4882a593Smuzhiyun  * Notes:
56*4882a593Smuzhiyun  * - each <mtd-id> used in mtdparts must albo exist in 'mtddis' mapping
57*4882a593Smuzhiyun  * - if the above variables are not set defaults for a given target are used
58*4882a593Smuzhiyun  *
59*4882a593Smuzhiyun  * Examples:
60*4882a593Smuzhiyun  *
61*4882a593Smuzhiyun  * 1 NOR Flash, with 1 single writable partition:
62*4882a593Smuzhiyun  * mtdids=nor0=edb7312-nor
63*4882a593Smuzhiyun  * mtdparts=mtdparts=edb7312-nor:-
64*4882a593Smuzhiyun  *
65*4882a593Smuzhiyun  * 1 NOR Flash with 2 partitions, 1 NAND with one
66*4882a593Smuzhiyun  * mtdids=nor0=edb7312-nor,nand0=edb7312-nand
67*4882a593Smuzhiyun  * mtdparts=mtdparts=edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
68*4882a593Smuzhiyun  *
69*4882a593Smuzhiyun  */
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun /*
72*4882a593Smuzhiyun  * JFFS2/CRAMFS support
73*4882a593Smuzhiyun  */
74*4882a593Smuzhiyun #include <common.h>
75*4882a593Smuzhiyun #include <command.h>
76*4882a593Smuzhiyun #include <malloc.h>
77*4882a593Smuzhiyun #include <jffs2/jffs2.h>
78*4882a593Smuzhiyun #include <linux/list.h>
79*4882a593Smuzhiyun #include <linux/ctype.h>
80*4882a593Smuzhiyun #include <cramfs/cramfs_fs.h>
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun #if defined(CONFIG_CMD_NAND)
83*4882a593Smuzhiyun #include <linux/mtd/rawnand.h>
84*4882a593Smuzhiyun #include <nand.h>
85*4882a593Smuzhiyun #endif
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun #if defined(CONFIG_CMD_ONENAND)
88*4882a593Smuzhiyun #include <linux/mtd/mtd.h>
89*4882a593Smuzhiyun #include <linux/mtd/onenand.h>
90*4882a593Smuzhiyun #include <onenand_uboot.h>
91*4882a593Smuzhiyun #endif
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun /* enable/disable debugging messages */
94*4882a593Smuzhiyun #define	DEBUG_JFFS
95*4882a593Smuzhiyun #undef	DEBUG_JFFS
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun #ifdef  DEBUG_JFFS
98*4882a593Smuzhiyun # define DEBUGF(fmt, args...)	printf(fmt ,##args)
99*4882a593Smuzhiyun #else
100*4882a593Smuzhiyun # define DEBUGF(fmt, args...)
101*4882a593Smuzhiyun #endif
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun /* special size referring to all the remaining space in a partition */
104*4882a593Smuzhiyun #define SIZE_REMAINING		0xFFFFFFFF
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun /* special offset value, it is used when not provided by user
107*4882a593Smuzhiyun  *
108*4882a593Smuzhiyun  * this value is used temporarily during parsing, later such offests
109*4882a593Smuzhiyun  * are recalculated */
110*4882a593Smuzhiyun #define OFFSET_NOT_SPECIFIED	0xFFFFFFFF
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun /* minimum partition size */
113*4882a593Smuzhiyun #define MIN_PART_SIZE		4096
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun /* this flag needs to be set in part_info struct mask_flags
116*4882a593Smuzhiyun  * field for read-only partitions */
117*4882a593Smuzhiyun #define MTD_WRITEABLE_CMD		1
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun /* current active device and partition number */
120*4882a593Smuzhiyun #ifdef CONFIG_CMD_MTDPARTS
121*4882a593Smuzhiyun /* Use the ones declared in cmd_mtdparts.c */
122*4882a593Smuzhiyun extern struct mtd_device *current_mtd_dev;
123*4882a593Smuzhiyun extern u8 current_mtd_partnum;
124*4882a593Smuzhiyun #else
125*4882a593Smuzhiyun /* Use local ones */
126*4882a593Smuzhiyun struct mtd_device *current_mtd_dev = NULL;
127*4882a593Smuzhiyun u8 current_mtd_partnum = 0;
128*4882a593Smuzhiyun #endif
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun #if defined(CONFIG_CMD_CRAMFS)
131*4882a593Smuzhiyun extern int cramfs_check (struct part_info *info);
132*4882a593Smuzhiyun extern int cramfs_load (char *loadoffset, struct part_info *info, char *filename);
133*4882a593Smuzhiyun extern int cramfs_ls (struct part_info *info, char *filename);
134*4882a593Smuzhiyun extern int cramfs_info (struct part_info *info);
135*4882a593Smuzhiyun #else
136*4882a593Smuzhiyun /* defining empty macros for function names is ugly but avoids ifdef clutter
137*4882a593Smuzhiyun  * all over the code */
138*4882a593Smuzhiyun #define cramfs_check(x)		(0)
139*4882a593Smuzhiyun #define cramfs_load(x,y,z)	(-1)
140*4882a593Smuzhiyun #define cramfs_ls(x,y)		(0)
141*4882a593Smuzhiyun #define cramfs_info(x)		(0)
142*4882a593Smuzhiyun #endif
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun #ifndef CONFIG_CMD_MTDPARTS
145*4882a593Smuzhiyun /**
146*4882a593Smuzhiyun  * Check device number to be within valid range for given device type.
147*4882a593Smuzhiyun  *
148*4882a593Smuzhiyun  * @param dev device to validate
149*4882a593Smuzhiyun  * @return 0 if device is valid, 1 otherwise
150*4882a593Smuzhiyun  */
mtd_device_validate(u8 type,u8 num,u32 * size)151*4882a593Smuzhiyun static int mtd_device_validate(u8 type, u8 num, u32 *size)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun 	if (type == MTD_DEV_TYPE_NOR) {
154*4882a593Smuzhiyun #if defined(CONFIG_CMD_FLASH)
155*4882a593Smuzhiyun 		if (num < CONFIG_SYS_MAX_FLASH_BANKS) {
156*4882a593Smuzhiyun 			extern flash_info_t flash_info[];
157*4882a593Smuzhiyun 			*size = flash_info[num].size;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 			return 0;
160*4882a593Smuzhiyun 		}
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 		printf("no such FLASH device: %s%d (valid range 0 ... %d\n",
163*4882a593Smuzhiyun 				MTD_DEV_TYPE(type), num, CONFIG_SYS_MAX_FLASH_BANKS - 1);
164*4882a593Smuzhiyun #else
165*4882a593Smuzhiyun 		printf("support for FLASH devices not present\n");
166*4882a593Smuzhiyun #endif
167*4882a593Smuzhiyun 	} else if (type == MTD_DEV_TYPE_NAND) {
168*4882a593Smuzhiyun #if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND)
169*4882a593Smuzhiyun 		struct mtd_info *mtd = get_nand_dev_by_index(num);
170*4882a593Smuzhiyun 		if (mtd) {
171*4882a593Smuzhiyun 			*size = mtd->size;
172*4882a593Smuzhiyun 			return 0;
173*4882a593Smuzhiyun 		}
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 		printf("no such NAND device: %s%d (valid range 0 ... %d)\n",
176*4882a593Smuzhiyun 				MTD_DEV_TYPE(type), num, CONFIG_SYS_MAX_NAND_DEVICE - 1);
177*4882a593Smuzhiyun #else
178*4882a593Smuzhiyun 		printf("support for NAND devices not present\n");
179*4882a593Smuzhiyun #endif
180*4882a593Smuzhiyun 	} else if (type == MTD_DEV_TYPE_ONENAND) {
181*4882a593Smuzhiyun #if defined(CONFIG_CMD_ONENAND)
182*4882a593Smuzhiyun 		*size = onenand_mtd.size;
183*4882a593Smuzhiyun 		return 0;
184*4882a593Smuzhiyun #else
185*4882a593Smuzhiyun 		printf("support for OneNAND devices not present\n");
186*4882a593Smuzhiyun #endif
187*4882a593Smuzhiyun 	} else
188*4882a593Smuzhiyun 		printf("Unknown defice type %d\n", type);
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	return 1;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun /**
194*4882a593Smuzhiyun  * Parse device id string <dev-id> := 'nand'|'nor'|'onenand'<dev-num>,
195*4882a593Smuzhiyun  * return device type and number.
196*4882a593Smuzhiyun  *
197*4882a593Smuzhiyun  * @param id string describing device id
198*4882a593Smuzhiyun  * @param ret_id output pointer to next char after parse completes (output)
199*4882a593Smuzhiyun  * @param dev_type parsed device type (output)
200*4882a593Smuzhiyun  * @param dev_num parsed device number (output)
201*4882a593Smuzhiyun  * @return 0 on success, 1 otherwise
202*4882a593Smuzhiyun  */
mtd_id_parse(const char * id,const char ** ret_id,u8 * dev_type,u8 * dev_num)203*4882a593Smuzhiyun static int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num)
204*4882a593Smuzhiyun {
205*4882a593Smuzhiyun 	const char *p = id;
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	*dev_type = 0;
208*4882a593Smuzhiyun 	if (strncmp(p, "nand", 4) == 0) {
209*4882a593Smuzhiyun 		*dev_type = MTD_DEV_TYPE_NAND;
210*4882a593Smuzhiyun 		p += 4;
211*4882a593Smuzhiyun 	} else if (strncmp(p, "nor", 3) == 0) {
212*4882a593Smuzhiyun 		*dev_type = MTD_DEV_TYPE_NOR;
213*4882a593Smuzhiyun 		p += 3;
214*4882a593Smuzhiyun 	} else if (strncmp(p, "onenand", 7) == 0) {
215*4882a593Smuzhiyun 		*dev_type = MTD_DEV_TYPE_ONENAND;
216*4882a593Smuzhiyun 		p += 7;
217*4882a593Smuzhiyun 	} else {
218*4882a593Smuzhiyun 		printf("incorrect device type in %s\n", id);
219*4882a593Smuzhiyun 		return 1;
220*4882a593Smuzhiyun 	}
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	if (!isdigit(*p)) {
223*4882a593Smuzhiyun 		printf("incorrect device number in %s\n", id);
224*4882a593Smuzhiyun 		return 1;
225*4882a593Smuzhiyun 	}
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	*dev_num = simple_strtoul(p, (char **)&p, 0);
228*4882a593Smuzhiyun 	if (ret_id)
229*4882a593Smuzhiyun 		*ret_id = p;
230*4882a593Smuzhiyun 	return 0;
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun /*
234*4882a593Smuzhiyun  * 'Static' version of command line mtdparts_init() routine. Single partition on
235*4882a593Smuzhiyun  * a single device configuration.
236*4882a593Smuzhiyun  */
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun /**
239*4882a593Smuzhiyun  * Calculate sector size.
240*4882a593Smuzhiyun  *
241*4882a593Smuzhiyun  * @return sector size
242*4882a593Smuzhiyun  */
get_part_sector_size_nand(struct mtdids * id)243*4882a593Smuzhiyun static inline u32 get_part_sector_size_nand(struct mtdids *id)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun #if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND)
246*4882a593Smuzhiyun 	struct mtd_info *mtd;
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	mtd = get_nand_dev_by_index(id->num);
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	return mtd->erasesize;
251*4882a593Smuzhiyun #else
252*4882a593Smuzhiyun 	BUG();
253*4882a593Smuzhiyun 	return 0;
254*4882a593Smuzhiyun #endif
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun 
get_part_sector_size_nor(struct mtdids * id,struct part_info * part)257*4882a593Smuzhiyun static inline u32 get_part_sector_size_nor(struct mtdids *id, struct part_info *part)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun #if defined(CONFIG_CMD_FLASH)
260*4882a593Smuzhiyun 	extern flash_info_t flash_info[];
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	u32 end_phys, start_phys, sector_size = 0, size = 0;
263*4882a593Smuzhiyun 	int i;
264*4882a593Smuzhiyun 	flash_info_t *flash;
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	flash = &flash_info[id->num];
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	start_phys = flash->start[0] + part->offset;
269*4882a593Smuzhiyun 	end_phys = start_phys + part->size - 1;
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	for (i = 0; i < flash->sector_count; i++) {
272*4882a593Smuzhiyun 		if (flash->start[i] >= end_phys)
273*4882a593Smuzhiyun 			break;
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 		if (flash->start[i] >= start_phys) {
276*4882a593Smuzhiyun 			if (i == flash->sector_count - 1) {
277*4882a593Smuzhiyun 				size = flash->start[0] + flash->size - flash->start[i];
278*4882a593Smuzhiyun 			} else {
279*4882a593Smuzhiyun 				size = flash->start[i+1] - flash->start[i];
280*4882a593Smuzhiyun 			}
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 			if (sector_size < size)
283*4882a593Smuzhiyun 				sector_size = size;
284*4882a593Smuzhiyun 		}
285*4882a593Smuzhiyun 	}
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	return sector_size;
288*4882a593Smuzhiyun #else
289*4882a593Smuzhiyun 	BUG();
290*4882a593Smuzhiyun 	return 0;
291*4882a593Smuzhiyun #endif
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun 
get_part_sector_size_onenand(void)294*4882a593Smuzhiyun static inline u32 get_part_sector_size_onenand(void)
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun #if defined(CONFIG_CMD_ONENAND)
297*4882a593Smuzhiyun 	struct mtd_info *mtd;
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	mtd = &onenand_mtd;
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	return mtd->erasesize;
302*4882a593Smuzhiyun #else
303*4882a593Smuzhiyun 	BUG();
304*4882a593Smuzhiyun 	return 0;
305*4882a593Smuzhiyun #endif
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun 
get_part_sector_size(struct mtdids * id,struct part_info * part)308*4882a593Smuzhiyun static inline u32 get_part_sector_size(struct mtdids *id, struct part_info *part)
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun 	if (id->type == MTD_DEV_TYPE_NAND)
311*4882a593Smuzhiyun 		return get_part_sector_size_nand(id);
312*4882a593Smuzhiyun 	else if (id->type == MTD_DEV_TYPE_NOR)
313*4882a593Smuzhiyun 		return get_part_sector_size_nor(id, part);
314*4882a593Smuzhiyun 	else if (id->type == MTD_DEV_TYPE_ONENAND)
315*4882a593Smuzhiyun 		return get_part_sector_size_onenand();
316*4882a593Smuzhiyun 	else
317*4882a593Smuzhiyun 		DEBUGF("Error: Unknown device type.\n");
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	return 0;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun /**
323*4882a593Smuzhiyun  * Parse and initialize global mtdids mapping and create global
324*4882a593Smuzhiyun  * device/partition list.
325*4882a593Smuzhiyun  *
326*4882a593Smuzhiyun  * 'Static' version of command line mtdparts_init() routine. Single partition on
327*4882a593Smuzhiyun  * a single device configuration.
328*4882a593Smuzhiyun  *
329*4882a593Smuzhiyun  * @return 0 on success, 1 otherwise
330*4882a593Smuzhiyun  */
mtdparts_init(void)331*4882a593Smuzhiyun int mtdparts_init(void)
332*4882a593Smuzhiyun {
333*4882a593Smuzhiyun 	static int initialized = 0;
334*4882a593Smuzhiyun 	u32 size;
335*4882a593Smuzhiyun 	char *dev_name;
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	DEBUGF("\n---mtdparts_init---\n");
338*4882a593Smuzhiyun 	if (!initialized) {
339*4882a593Smuzhiyun 		struct mtdids *id;
340*4882a593Smuzhiyun 		struct part_info *part;
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 		initialized = 1;
343*4882a593Smuzhiyun 		current_mtd_dev = (struct mtd_device *)
344*4882a593Smuzhiyun 			malloc(sizeof(struct mtd_device) +
345*4882a593Smuzhiyun 					sizeof(struct part_info) +
346*4882a593Smuzhiyun 					sizeof(struct mtdids));
347*4882a593Smuzhiyun 		if (!current_mtd_dev) {
348*4882a593Smuzhiyun 			printf("out of memory\n");
349*4882a593Smuzhiyun 			return 1;
350*4882a593Smuzhiyun 		}
351*4882a593Smuzhiyun 		memset(current_mtd_dev, 0, sizeof(struct mtd_device) +
352*4882a593Smuzhiyun 		       sizeof(struct part_info) + sizeof(struct mtdids));
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 		id = (struct mtdids *)(current_mtd_dev + 1);
355*4882a593Smuzhiyun 		part = (struct part_info *)(id + 1);
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 		/* id */
358*4882a593Smuzhiyun 		id->mtd_id = "single part";
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun #if defined(CONFIG_JFFS2_DEV)
361*4882a593Smuzhiyun 		dev_name = CONFIG_JFFS2_DEV;
362*4882a593Smuzhiyun #else
363*4882a593Smuzhiyun 		dev_name = "nor0";
364*4882a593Smuzhiyun #endif
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 		if ((mtd_id_parse(dev_name, NULL, &id->type, &id->num) != 0) ||
367*4882a593Smuzhiyun 				(mtd_device_validate(id->type, id->num, &size) != 0)) {
368*4882a593Smuzhiyun 			printf("incorrect device: %s%d\n", MTD_DEV_TYPE(id->type), id->num);
369*4882a593Smuzhiyun 			free(current_mtd_dev);
370*4882a593Smuzhiyun 			return 1;
371*4882a593Smuzhiyun 		}
372*4882a593Smuzhiyun 		id->size = size;
373*4882a593Smuzhiyun 		INIT_LIST_HEAD(&id->link);
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 		DEBUGF("dev id: type = %d, num = %d, size = 0x%08lx, mtd_id = %s\n",
376*4882a593Smuzhiyun 				id->type, id->num, id->size, id->mtd_id);
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 		/* partition */
379*4882a593Smuzhiyun 		part->name = "static";
380*4882a593Smuzhiyun 		part->auto_name = 0;
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun #if defined(CONFIG_JFFS2_PART_SIZE)
383*4882a593Smuzhiyun 		part->size = CONFIG_JFFS2_PART_SIZE;
384*4882a593Smuzhiyun #else
385*4882a593Smuzhiyun 		part->size = SIZE_REMAINING;
386*4882a593Smuzhiyun #endif
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun #if defined(CONFIG_JFFS2_PART_OFFSET)
389*4882a593Smuzhiyun 		part->offset = CONFIG_JFFS2_PART_OFFSET;
390*4882a593Smuzhiyun #else
391*4882a593Smuzhiyun 		part->offset = 0x00000000;
392*4882a593Smuzhiyun #endif
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 		part->dev = current_mtd_dev;
395*4882a593Smuzhiyun 		INIT_LIST_HEAD(&part->link);
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 		/* recalculate size if needed */
398*4882a593Smuzhiyun 		if (part->size == SIZE_REMAINING)
399*4882a593Smuzhiyun 			part->size = id->size - part->offset;
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 		part->sector_size = get_part_sector_size(id, part);
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 		DEBUGF("part  : name = %s, size = 0x%08lx, offset = 0x%08lx\n",
404*4882a593Smuzhiyun 				part->name, part->size, part->offset);
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 		/* device */
407*4882a593Smuzhiyun 		current_mtd_dev->id = id;
408*4882a593Smuzhiyun 		INIT_LIST_HEAD(&current_mtd_dev->link);
409*4882a593Smuzhiyun 		current_mtd_dev->num_parts = 1;
410*4882a593Smuzhiyun 		INIT_LIST_HEAD(&current_mtd_dev->parts);
411*4882a593Smuzhiyun 		list_add(&part->link, &current_mtd_dev->parts);
412*4882a593Smuzhiyun 	}
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	return 0;
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun #endif /* #ifndef CONFIG_CMD_MTDPARTS */
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun /**
419*4882a593Smuzhiyun  * Return pointer to the partition of a requested number from a requested
420*4882a593Smuzhiyun  * device.
421*4882a593Smuzhiyun  *
422*4882a593Smuzhiyun  * @param dev device that is to be searched for a partition
423*4882a593Smuzhiyun  * @param part_num requested partition number
424*4882a593Smuzhiyun  * @return pointer to the part_info, NULL otherwise
425*4882a593Smuzhiyun  */
jffs2_part_info(struct mtd_device * dev,unsigned int part_num)426*4882a593Smuzhiyun static struct part_info* jffs2_part_info(struct mtd_device *dev, unsigned int part_num)
427*4882a593Smuzhiyun {
428*4882a593Smuzhiyun 	struct list_head *entry;
429*4882a593Smuzhiyun 	struct part_info *part;
430*4882a593Smuzhiyun 	int num;
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	if (!dev)
433*4882a593Smuzhiyun 		return NULL;
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	DEBUGF("\n--- jffs2_part_info: partition number %d for device %s%d (%s)\n",
436*4882a593Smuzhiyun 			part_num, MTD_DEV_TYPE(dev->id->type),
437*4882a593Smuzhiyun 			dev->id->num, dev->id->mtd_id);
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	if (part_num >= dev->num_parts) {
440*4882a593Smuzhiyun 		printf("invalid partition number %d for device %s%d (%s)\n",
441*4882a593Smuzhiyun 				part_num, MTD_DEV_TYPE(dev->id->type),
442*4882a593Smuzhiyun 				dev->id->num, dev->id->mtd_id);
443*4882a593Smuzhiyun 		return NULL;
444*4882a593Smuzhiyun 	}
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	/* locate partition number, return it */
447*4882a593Smuzhiyun 	num = 0;
448*4882a593Smuzhiyun 	list_for_each(entry, &dev->parts) {
449*4882a593Smuzhiyun 		part = list_entry(entry, struct part_info, link);
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 		if (part_num == num++) {
452*4882a593Smuzhiyun 			return part;
453*4882a593Smuzhiyun 		}
454*4882a593Smuzhiyun 	}
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	return NULL;
457*4882a593Smuzhiyun }
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun /***************************************************/
460*4882a593Smuzhiyun /* U-Boot commands				   */
461*4882a593Smuzhiyun /***************************************************/
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun /**
464*4882a593Smuzhiyun  * Routine implementing fsload u-boot command. This routine tries to load
465*4882a593Smuzhiyun  * a requested file from jffs2/cramfs filesystem on a current partition.
466*4882a593Smuzhiyun  *
467*4882a593Smuzhiyun  * @param cmdtp command internal data
468*4882a593Smuzhiyun  * @param flag command flag
469*4882a593Smuzhiyun  * @param argc number of arguments supplied to the command
470*4882a593Smuzhiyun  * @param argv arguments list
471*4882a593Smuzhiyun  * @return 0 on success, 1 otherwise
472*4882a593Smuzhiyun  */
do_jffs2_fsload(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])473*4882a593Smuzhiyun int do_jffs2_fsload(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun 	char *fsname;
476*4882a593Smuzhiyun 	char *filename;
477*4882a593Smuzhiyun 	int size;
478*4882a593Smuzhiyun 	struct part_info *part;
479*4882a593Smuzhiyun 	ulong offset = load_addr;
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 	/* pre-set Boot file name */
482*4882a593Smuzhiyun 	filename = env_get("bootfile");
483*4882a593Smuzhiyun 	if (!filename)
484*4882a593Smuzhiyun 		filename = "uImage";
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	if (argc == 2) {
487*4882a593Smuzhiyun 		filename = argv[1];
488*4882a593Smuzhiyun 	}
489*4882a593Smuzhiyun 	if (argc == 3) {
490*4882a593Smuzhiyun 		offset = simple_strtoul(argv[1], NULL, 16);
491*4882a593Smuzhiyun 		load_addr = offset;
492*4882a593Smuzhiyun 		filename = argv[2];
493*4882a593Smuzhiyun 	}
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 	/* make sure we are in sync with env variables */
496*4882a593Smuzhiyun 	if (mtdparts_init() !=0)
497*4882a593Smuzhiyun 		return 1;
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 	if ((part = jffs2_part_info(current_mtd_dev, current_mtd_partnum))){
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun 		/* check partition type for cramfs */
502*4882a593Smuzhiyun 		fsname = (cramfs_check(part) ? "CRAMFS" : "JFFS2");
503*4882a593Smuzhiyun 		printf("### %s loading '%s' to 0x%lx\n", fsname, filename, offset);
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 		if (cramfs_check(part)) {
506*4882a593Smuzhiyun 			size = cramfs_load ((char *) offset, part, filename);
507*4882a593Smuzhiyun 		} else {
508*4882a593Smuzhiyun 			/* if this is not cramfs assume jffs2 */
509*4882a593Smuzhiyun 			size = jffs2_1pass_load((char *)offset, part, filename);
510*4882a593Smuzhiyun 		}
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 		if (size > 0) {
513*4882a593Smuzhiyun 			printf("### %s load complete: %d bytes loaded to 0x%lx\n",
514*4882a593Smuzhiyun 				fsname, size, offset);
515*4882a593Smuzhiyun 			env_set_hex("filesize", size);
516*4882a593Smuzhiyun 		} else {
517*4882a593Smuzhiyun 			printf("### %s LOAD ERROR<%x> for %s!\n", fsname, size, filename);
518*4882a593Smuzhiyun 		}
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 		return !(size > 0);
521*4882a593Smuzhiyun 	}
522*4882a593Smuzhiyun 	return 1;
523*4882a593Smuzhiyun }
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun /**
526*4882a593Smuzhiyun  * Routine implementing u-boot ls command which lists content of a given
527*4882a593Smuzhiyun  * directory on a current partition.
528*4882a593Smuzhiyun  *
529*4882a593Smuzhiyun  * @param cmdtp command internal data
530*4882a593Smuzhiyun  * @param flag command flag
531*4882a593Smuzhiyun  * @param argc number of arguments supplied to the command
532*4882a593Smuzhiyun  * @param argv arguments list
533*4882a593Smuzhiyun  * @return 0 on success, 1 otherwise
534*4882a593Smuzhiyun  */
do_jffs2_ls(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])535*4882a593Smuzhiyun int do_jffs2_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
536*4882a593Smuzhiyun {
537*4882a593Smuzhiyun 	char *filename = "/";
538*4882a593Smuzhiyun 	int ret;
539*4882a593Smuzhiyun 	struct part_info *part;
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	if (argc == 2)
542*4882a593Smuzhiyun 		filename = argv[1];
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 	/* make sure we are in sync with env variables */
545*4882a593Smuzhiyun 	if (mtdparts_init() !=0)
546*4882a593Smuzhiyun 		return 1;
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun 	if ((part = jffs2_part_info(current_mtd_dev, current_mtd_partnum))){
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 		/* check partition type for cramfs */
551*4882a593Smuzhiyun 		if (cramfs_check(part)) {
552*4882a593Smuzhiyun 			ret = cramfs_ls (part, filename);
553*4882a593Smuzhiyun 		} else {
554*4882a593Smuzhiyun 			/* if this is not cramfs assume jffs2 */
555*4882a593Smuzhiyun 			ret = jffs2_1pass_ls(part, filename);
556*4882a593Smuzhiyun 		}
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun 		return ret ? 0 : 1;
559*4882a593Smuzhiyun 	}
560*4882a593Smuzhiyun 	return 1;
561*4882a593Smuzhiyun }
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun /**
564*4882a593Smuzhiyun  * Routine implementing u-boot fsinfo command. This routine prints out
565*4882a593Smuzhiyun  * miscellaneous filesystem informations/statistics.
566*4882a593Smuzhiyun  *
567*4882a593Smuzhiyun  * @param cmdtp command internal data
568*4882a593Smuzhiyun  * @param flag command flag
569*4882a593Smuzhiyun  * @param argc number of arguments supplied to the command
570*4882a593Smuzhiyun  * @param argv arguments list
571*4882a593Smuzhiyun  * @return 0 on success, 1 otherwise
572*4882a593Smuzhiyun  */
do_jffs2_fsinfo(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])573*4882a593Smuzhiyun int do_jffs2_fsinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
574*4882a593Smuzhiyun {
575*4882a593Smuzhiyun 	struct part_info *part;
576*4882a593Smuzhiyun 	char *fsname;
577*4882a593Smuzhiyun 	int ret;
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	/* make sure we are in sync with env variables */
580*4882a593Smuzhiyun 	if (mtdparts_init() !=0)
581*4882a593Smuzhiyun 		return 1;
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 	if ((part = jffs2_part_info(current_mtd_dev, current_mtd_partnum))){
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 		/* check partition type for cramfs */
586*4882a593Smuzhiyun 		fsname = (cramfs_check(part) ? "CRAMFS" : "JFFS2");
587*4882a593Smuzhiyun 		printf("### filesystem type is %s\n", fsname);
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 		if (cramfs_check(part)) {
590*4882a593Smuzhiyun 			ret = cramfs_info (part);
591*4882a593Smuzhiyun 		} else {
592*4882a593Smuzhiyun 			/* if this is not cramfs assume jffs2 */
593*4882a593Smuzhiyun 			ret = jffs2_1pass_info(part);
594*4882a593Smuzhiyun 		}
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 		return ret ? 0 : 1;
597*4882a593Smuzhiyun 	}
598*4882a593Smuzhiyun 	return 1;
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun /***************************************************/
602*4882a593Smuzhiyun U_BOOT_CMD(
603*4882a593Smuzhiyun 	fsload,	3,	0,	do_jffs2_fsload,
604*4882a593Smuzhiyun 	"load binary file from a filesystem image",
605*4882a593Smuzhiyun 	"[ off ] [ filename ]\n"
606*4882a593Smuzhiyun 	"    - load binary file from flash bank\n"
607*4882a593Smuzhiyun 	"      with offset 'off'"
608*4882a593Smuzhiyun );
609*4882a593Smuzhiyun U_BOOT_CMD(
610*4882a593Smuzhiyun 	fsls,	2,	1,	do_jffs2_ls,
611*4882a593Smuzhiyun 	"list files in a directory (default /)",
612*4882a593Smuzhiyun 	"[ directory ]"
613*4882a593Smuzhiyun );
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun U_BOOT_CMD(
616*4882a593Smuzhiyun 	fsinfo,	1,	1,	do_jffs2_fsinfo,
617*4882a593Smuzhiyun 	"print information about filesystems",
618*4882a593Smuzhiyun 	""
619*4882a593Smuzhiyun );
620*4882a593Smuzhiyun /***************************************************/
621