Commit d9831893ab2efd3dd36f948da898c83f33c4992c

Authored by Wolfgang Denk

Merge with /home/sr/git/u-boot/nand-ladis

Showing 8 changed files Inline Diff

board/netstar/netstar.c
1 /* 1 /*
2 * (C) Copyright 2005 2N TELEKOMUNIKACE, Ladislav Michl 2 * (C) Copyright 2005 2N TELEKOMUNIKACE, Ladislav Michl
3 * 3 *
4 * See file CREDITS for list of people who contributed to this 4 * See file CREDITS for list of people who contributed to this
5 * project. 5 * project.
6 * 6 *
7 * This program is free software; you can redistribute it and/or 7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as 8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of 9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version. 10 * the License, or (at your option) any later version.
11 * 11 *
12 * This program is distributed in the hope that it will be useful, 12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details. 15 * GNU General Public License for more details.
16 * 16 *
17 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 * MA 02111-1307 USA 20 * MA 02111-1307 USA
21 */ 21 */
22 22
23 #include <common.h> 23 #include <common.h>
24 24
25 DECLARE_GLOBAL_DATA_PTR; 25 DECLARE_GLOBAL_DATA_PTR;
26 26
27 int board_init(void) 27 int board_init(void)
28 { 28 {
29 /* arch number of NetStar board */ 29 /* arch number of NetStar board */
30 gd->bd->bi_arch_number = 692; 30 gd->bd->bi_arch_number = MACH_TYPE_NETSTAR;
31 31
32 /* adress of boot parameters */ 32 /* adress of boot parameters */
33 gd->bd->bi_boot_params = 0x10000100; 33 gd->bd->bi_boot_params = 0x10000100;
34 34
35 return 0; 35 return 0;
36 } 36 }
37 37
38 int dram_init(void) 38 int dram_init(void)
39 { 39 {
40 gd->bd->bi_dram[0].start = PHYS_SDRAM_1; 40 gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
41 gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE; 41 gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
42 42
43 /* Take the Ethernet controller out of reset and wait 43 /* Take the Ethernet controller out of reset and wait
44 * for the EEPROM load to complete. */ 44 * for the EEPROM load to complete. */
45 *((volatile unsigned short *) GPIO_DATA_OUTPUT_REG) |= 0x80; 45 *((volatile unsigned short *) GPIO_DATA_OUTPUT_REG) |= 0x80;
46 udelay(10); /* doesn't work before interrupt_init call */ 46 udelay(10); /* doesn't work before interrupt_init call */
47 *((volatile unsigned short *) GPIO_DATA_OUTPUT_REG) &= ~0x80; 47 *((volatile unsigned short *) GPIO_DATA_OUTPUT_REG) &= ~0x80;
48 udelay(500); 48 udelay(500);
49 49
50 return 0; 50 return 0;
51 } 51 }
52 52
53 int misc_init_r(void) 53 int misc_init_r(void)
54 { 54 {
55 return 0; 55 return 0;
56 } 56 }
57 57
58 int board_late_init(void) 58 int board_late_init(void)
59 { 59 {
60 return 0; 60 return 0;
61 } 61 }
62 62
board/voiceblue/voiceblue.c
1 /* 1 /*
2 * (C) Copyright 2005 2N TELEKOMUNIKACE, Ladislav Michl 2 * (C) Copyright 2005 2N TELEKOMUNIKACE, Ladislav Michl
3 * 3 *
4 * See file CREDITS for list of people who contributed to this 4 * See file CREDITS for list of people who contributed to this
5 * project. 5 * project.
6 * 6 *
7 * This program is free software; you can redistribute it and/or 7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License 8 * modify it under the terms of the GNU General Public License
9 * version 2 as published by the Free Software Foundation. 9 * version 2 as published by the Free Software Foundation.
10 * 10 *
11 * This program is distributed in the hope that it will be useful, 11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details. 14 * GNU General Public License for more details.
15 * 15 *
16 * You should have received a copy of the GNU General Public License 16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software 17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
19 * MA 02111-1307 USA 19 * MA 02111-1307 USA
20 */ 20 */
21 21
22 #include <common.h> 22 #include <common.h>
23 23
24 DECLARE_GLOBAL_DATA_PTR; 24 DECLARE_GLOBAL_DATA_PTR;
25 25
26 int board_init(void) 26 int board_init(void)
27 { 27 {
28 *((volatile unsigned char *) VOICEBLUE_LED_REG) = 0xaa; 28 *((volatile unsigned char *) VOICEBLUE_LED_REG) = 0xaa;
29 29
30 /* arch number of VoiceBlue board */ 30 /* arch number of VoiceBlue board */
31 /* TODO: use define from asm/mach-types.h */ 31 gd->bd->bi_arch_number = MACH_TYPE_VOICEBLUE;
32 gd->bd->bi_arch_number = 218;
33 32
34 /* adress of boot parameters */ 33 /* adress of boot parameters */
35 gd->bd->bi_boot_params = 0x10000100; 34 gd->bd->bi_boot_params = 0x10000100;
36 35
37 return 0; 36 return 0;
38 } 37 }
39 38
40 int dram_init(void) 39 int dram_init(void)
41 { 40 {
42 *((volatile unsigned short *) VOICEBLUE_LED_REG) = 0xff; 41 *((volatile unsigned short *) VOICEBLUE_LED_REG) = 0xff;
43 42
44 /* Take the Ethernet controller out of reset and wait 43 /* Take the Ethernet controller out of reset and wait
45 * for the EEPROM load to complete. */ 44 * for the EEPROM load to complete. */
46 *((volatile unsigned short *) GPIO_DATA_OUTPUT_REG) |= 0x80; 45 *((volatile unsigned short *) GPIO_DATA_OUTPUT_REG) |= 0x80;
47 udelay(10); /* doesn't work before interrupt_init call */ 46 udelay(10); /* doesn't work before interrupt_init call */
48 *((volatile unsigned short *) GPIO_DATA_OUTPUT_REG) &= ~0x80; 47 *((volatile unsigned short *) GPIO_DATA_OUTPUT_REG) &= ~0x80;
49 udelay(500); 48 udelay(500);
50 49
51 gd->bd->bi_dram[0].start = PHYS_SDRAM_1; 50 gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
52 gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE; 51 gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
53 52
54 return 0; 53 return 0;
55 } 54 }
56 55
57 int misc_init_r(void) 56 int misc_init_r(void)
58 { 57 {
59 *((volatile unsigned short *) VOICEBLUE_LED_REG) = 0x55; 58 *((volatile unsigned short *) VOICEBLUE_LED_REG) = 0x55;
60 59
61 return 0; 60 return 0;
62 } 61 }
63 62
64 int board_late_init(void) 63 int board_late_init(void)
65 { 64 {
66 *((volatile unsigned char *) VOICEBLUE_LED_REG) = 0x00; 65 *((volatile unsigned char *) VOICEBLUE_LED_REG) = 0x00;
67 66
68 return 0; 67 return 0;
69 } 68 }
70 69
1 /* 1 /*
2 * (C) Copyright 2002 2 * (C) Copyright 2002
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 * 4 *
5 * (C) Copyright 2002 5 * (C) Copyright 2002
6 * Robert Schwebel, Pengutronix, <r.schwebel@pengutronix.de> 6 * Robert Schwebel, Pengutronix, <r.schwebel@pengutronix.de>
7 * 7 *
8 * (C) Copyright 2003 8 * (C) Copyright 2003
9 * Kai-Uwe Bloem, Auerswald GmbH & Co KG, <linux-development@auerswald.de> 9 * Kai-Uwe Bloem, Auerswald GmbH & Co KG, <linux-development@auerswald.de>
10 * 10 *
11 * (C) Copyright 2005 11 * (C) Copyright 2005
12 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 12 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
13 * 13 *
14 * Added support for reading flash partition table from environment. 14 * Added support for reading flash partition table from environment.
15 * Parsing routines are based on driver/mtd/cmdline.c from the linux 2.4 15 * Parsing routines are based on driver/mtd/cmdline.c from the linux 2.4
16 * kernel tree. 16 * kernel tree.
17 * 17 *
18 * $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $ 18 * $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $
19 * Copyright 2002 SYSGO Real-Time Solutions GmbH 19 * Copyright 2002 SYSGO Real-Time Solutions GmbH
20 * 20 *
21 * See file CREDITS for list of people who contributed to this 21 * See file CREDITS for list of people who contributed to this
22 * project. 22 * project.
23 * 23 *
24 * This program is free software; you can redistribute it and/or 24 * This program is free software; you can redistribute it and/or
25 * modify it under the terms of the GNU General Public License as 25 * modify it under the terms of the GNU General Public License as
26 * published by the Free Software Foundation; either version 2 of 26 * published by the Free Software Foundation; either version 2 of
27 * the License, or (at your option) any later version. 27 * the License, or (at your option) any later version.
28 * 28 *
29 * This program is distributed in the hope that it will be useful, 29 * This program is distributed in the hope that it will be useful,
30 * but WITHOUT ANY WARRANTY; without even the implied warranty of 30 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 * GNU General Public License for more details. 32 * GNU General Public License for more details.
33 * 33 *
34 * You should have received a copy of the GNU General Public License 34 * You should have received a copy of the GNU General Public License
35 * along with this program; if not, write to the Free Software 35 * along with this program; if not, write to the Free Software
36 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 36 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
37 * MA 02111-1307 USA 37 * MA 02111-1307 USA
38 */ 38 */
39 39
40 /* 40 /*
41 * Three environment variables are used by the parsing routines: 41 * Three environment variables are used by the parsing routines:
42 * 42 *
43 * 'partition' - keeps current partition identifier 43 * 'partition' - keeps current partition identifier
44 * 44 *
45 * partition := <part-id> 45 * partition := <part-id>
46 * <part-id> := <dev-id>,part_num 46 * <part-id> := <dev-id>,part_num
47 * 47 *
48 * 48 *
49 * 'mtdids' - linux kernel mtd device id <-> u-boot device id mapping 49 * 'mtdids' - linux kernel mtd device id <-> u-boot device id mapping
50 * 50 *
51 * mtdids=<idmap>[,<idmap>,...] 51 * mtdids=<idmap>[,<idmap>,...]
52 * 52 *
53 * <idmap> := <dev-id>=<mtd-id> 53 * <idmap> := <dev-id>=<mtd-id>
54 * <dev-id> := 'nand'|'nor'<dev-num> 54 * <dev-id> := 'nand'|'nor'<dev-num>
55 * <dev-num> := mtd device number, 0... 55 * <dev-num> := mtd device number, 0...
56 * <mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name) 56 * <mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name)
57 * 57 *
58 * 58 *
59 * 'mtdparts' - partition list 59 * 'mtdparts' - partition list
60 * 60 *
61 * mtdparts=mtdparts=<mtd-def>[;<mtd-def>...] 61 * mtdparts=mtdparts=<mtd-def>[;<mtd-def>...]
62 * 62 *
63 * <mtd-def> := <mtd-id>:<part-def>[,<part-def>...] 63 * <mtd-def> := <mtd-id>:<part-def>[,<part-def>...]
64 * <mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name) 64 * <mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name)
65 * <part-def> := <size>[@<offset>][<name>][<ro-flag>] 65 * <part-def> := <size>[@<offset>][<name>][<ro-flag>]
66 * <size> := standard linux memsize OR '-' to denote all remaining space 66 * <size> := standard linux memsize OR '-' to denote all remaining space
67 * <offset> := partition start offset within the device 67 * <offset> := partition start offset within the device
68 * <name> := '(' NAME ')' 68 * <name> := '(' NAME ')'
69 * <ro-flag> := when set to 'ro' makes partition read-only (not used, passed to kernel) 69 * <ro-flag> := when set to 'ro' makes partition read-only (not used, passed to kernel)
70 * 70 *
71 * Notes: 71 * Notes:
72 * - each <mtd-id> used in mtdparts must albo exist in 'mtddis' mapping 72 * - each <mtd-id> used in mtdparts must albo exist in 'mtddis' mapping
73 * - if the above variables are not set defaults for a given target are used 73 * - if the above variables are not set defaults for a given target are used
74 * 74 *
75 * Examples: 75 * Examples:
76 * 76 *
77 * 1 NOR Flash, with 1 single writable partition: 77 * 1 NOR Flash, with 1 single writable partition:
78 * mtdids=nor0=edb7312-nor 78 * mtdids=nor0=edb7312-nor
79 * mtdparts=mtdparts=edb7312-nor:- 79 * mtdparts=mtdparts=edb7312-nor:-
80 * 80 *
81 * 1 NOR Flash with 2 partitions, 1 NAND with one 81 * 1 NOR Flash with 2 partitions, 1 NAND with one
82 * mtdids=nor0=edb7312-nor,nand0=edb7312-nand 82 * mtdids=nor0=edb7312-nor,nand0=edb7312-nand
83 * mtdparts=mtdparts=edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home) 83 * mtdparts=mtdparts=edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
84 * 84 *
85 */ 85 */
86 86
87 /* 87 /*
88 * JFFS2/CRAMFS support 88 * JFFS2/CRAMFS support
89 */ 89 */
90 #include <common.h> 90 #include <common.h>
91 #include <command.h> 91 #include <command.h>
92 #include <malloc.h> 92 #include <malloc.h>
93 #include <jffs2/jffs2.h> 93 #include <jffs2/jffs2.h>
94 #include <linux/list.h> 94 #include <linux/list.h>
95 #include <linux/ctype.h> 95 #include <linux/ctype.h>
96 96
97 #if (CONFIG_COMMANDS & CFG_CMD_JFFS2) 97 #if (CONFIG_COMMANDS & CFG_CMD_JFFS2)
98 98
99 #include <cramfs/cramfs_fs.h> 99 #include <cramfs/cramfs_fs.h>
100 100
101 #if (CONFIG_COMMANDS & CFG_CMD_NAND) 101 #if (CONFIG_COMMANDS & CFG_CMD_NAND)
102 #ifdef CFG_NAND_LEGACY 102 #ifdef CFG_NAND_LEGACY
103 #include <linux/mtd/nand_legacy.h> 103 #include <linux/mtd/nand_legacy.h>
104 #else /* !CFG_NAND_LEGACY */ 104 #else /* !CFG_NAND_LEGACY */
105 #include <linux/mtd/nand.h> 105 #include <linux/mtd/nand.h>
106 #include <nand.h> 106 #include <nand.h>
107 #endif /* !CFG_NAND_LEGACY */ 107 #endif /* !CFG_NAND_LEGACY */
108 #endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */ 108 #endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */
109 /* enable/disable debugging messages */ 109 /* enable/disable debugging messages */
110 #define DEBUG_JFFS 110 #define DEBUG_JFFS
111 #undef DEBUG_JFFS 111 #undef DEBUG_JFFS
112 112
113 #ifdef DEBUG_JFFS 113 #ifdef DEBUG_JFFS
114 # define DEBUGF(fmt, args...) printf(fmt ,##args) 114 # define DEBUGF(fmt, args...) printf(fmt ,##args)
115 #else 115 #else
116 # define DEBUGF(fmt, args...) 116 # define DEBUGF(fmt, args...)
117 #endif 117 #endif
118 118
119 /* special size referring to all the remaining space in a partition */ 119 /* special size referring to all the remaining space in a partition */
120 #define SIZE_REMAINING 0xFFFFFFFF 120 #define SIZE_REMAINING 0xFFFFFFFF
121 121
122 /* special offset value, it is used when not provided by user 122 /* special offset value, it is used when not provided by user
123 * 123 *
124 * this value is used temporarily during parsing, later such offests 124 * this value is used temporarily during parsing, later such offests
125 * are recalculated */ 125 * are recalculated */
126 #define OFFSET_NOT_SPECIFIED 0xFFFFFFFF 126 #define OFFSET_NOT_SPECIFIED 0xFFFFFFFF
127 127
128 /* minimum partition size */ 128 /* minimum partition size */
129 #define MIN_PART_SIZE 4096 129 #define MIN_PART_SIZE 4096
130 130
131 /* this flag needs to be set in part_info struct mask_flags 131 /* this flag needs to be set in part_info struct mask_flags
132 * field for read-only partitions */ 132 * field for read-only partitions */
133 #define MTD_WRITEABLE_CMD 1 133 #define MTD_WRITEABLE_CMD 1
134 134
135 #ifdef CONFIG_JFFS2_CMDLINE 135 #ifdef CONFIG_JFFS2_CMDLINE
136 /* default values for mtdids and mtdparts variables */ 136 /* default values for mtdids and mtdparts variables */
137 #if defined(MTDIDS_DEFAULT) 137 #if defined(MTDIDS_DEFAULT)
138 static const char *const mtdids_default = MTDIDS_DEFAULT; 138 static const char *const mtdids_default = MTDIDS_DEFAULT;
139 #else 139 #else
140 #warning "MTDIDS_DEFAULT not defined!" 140 #warning "MTDIDS_DEFAULT not defined!"
141 static const char *const mtdids_default = NULL; 141 static const char *const mtdids_default = NULL;
142 #endif 142 #endif
143 143
144 #if defined(MTDPARTS_DEFAULT) 144 #if defined(MTDPARTS_DEFAULT)
145 static const char *const mtdparts_default = MTDPARTS_DEFAULT; 145 static const char *const mtdparts_default = MTDPARTS_DEFAULT;
146 #else 146 #else
147 #warning "MTDPARTS_DEFAULT not defined!" 147 #warning "MTDPARTS_DEFAULT not defined!"
148 static const char *const mtdparts_default = NULL; 148 static const char *const mtdparts_default = NULL;
149 #endif 149 #endif
150 150
151 /* copies of last seen 'mtdids', 'mtdparts' and 'partition' env variables */ 151 /* copies of last seen 'mtdids', 'mtdparts' and 'partition' env variables */
152 #define MTDIDS_MAXLEN 128 152 #define MTDIDS_MAXLEN 128
153 #define MTDPARTS_MAXLEN 512 153 #define MTDPARTS_MAXLEN 512
154 #define PARTITION_MAXLEN 16 154 #define PARTITION_MAXLEN 16
155 static char last_ids[MTDIDS_MAXLEN]; 155 static char last_ids[MTDIDS_MAXLEN];
156 static char last_parts[MTDPARTS_MAXLEN]; 156 static char last_parts[MTDPARTS_MAXLEN];
157 static char last_partition[PARTITION_MAXLEN]; 157 static char last_partition[PARTITION_MAXLEN];
158 158
159 /* low level jffs2 cache cleaning routine */ 159 /* low level jffs2 cache cleaning routine */
160 extern void jffs2_free_cache(struct part_info *part); 160 extern void jffs2_free_cache(struct part_info *part);
161 161
162 /* mtdids mapping list, filled by parse_ids() */ 162 /* mtdids mapping list, filled by parse_ids() */
163 struct list_head mtdids; 163 struct list_head mtdids;
164 164
165 /* device/partition list, parse_cmdline() parses into here */ 165 /* device/partition list, parse_cmdline() parses into here */
166 struct list_head devices; 166 struct list_head devices;
167 #endif /* #ifdef CONFIG_JFFS2_CMDLINE */ 167 #endif /* #ifdef CONFIG_JFFS2_CMDLINE */
168 168
169 /* current active device and partition number */ 169 /* current active device and partition number */
170 static struct mtd_device *current_dev = NULL; 170 static struct mtd_device *current_dev = NULL;
171 static u8 current_partnum = 0; 171 static u8 current_partnum = 0;
172 172
173 extern int cramfs_check (struct part_info *info); 173 extern int cramfs_check (struct part_info *info);
174 extern int cramfs_load (char *loadoffset, struct part_info *info, char *filename); 174 extern int cramfs_load (char *loadoffset, struct part_info *info, char *filename);
175 extern int cramfs_ls (struct part_info *info, char *filename); 175 extern int cramfs_ls (struct part_info *info, char *filename);
176 extern int cramfs_info (struct part_info *info); 176 extern int cramfs_info (struct part_info *info);
177 177
178 static struct part_info* jffs2_part_info(struct mtd_device *dev, unsigned int part_num); 178 static struct part_info* jffs2_part_info(struct mtd_device *dev, unsigned int part_num);
179 179
180 /* command line only routines */ 180 /* command line only routines */
181 #ifdef CONFIG_JFFS2_CMDLINE 181 #ifdef CONFIG_JFFS2_CMDLINE
182 182
183 static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_len); 183 static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_len);
184 static int device_del(struct mtd_device *dev); 184 static int device_del(struct mtd_device *dev);
185 185
186 /** 186 /**
187 * Parses a string into a number. The number stored at ptr is 187 * Parses a string into a number. The number stored at ptr is
188 * potentially suffixed with K (for kilobytes, or 1024 bytes), 188 * potentially suffixed with K (for kilobytes, or 1024 bytes),
189 * M (for megabytes, or 1048576 bytes), or G (for gigabytes, or 189 * M (for megabytes, or 1048576 bytes), or G (for gigabytes, or
190 * 1073741824). If the number is suffixed with K, M, or G, then 190 * 1073741824). If the number is suffixed with K, M, or G, then
191 * the return value is the number multiplied by one kilobyte, one 191 * the return value is the number multiplied by one kilobyte, one
192 * megabyte, or one gigabyte, respectively. 192 * megabyte, or one gigabyte, respectively.
193 * 193 *
194 * @param ptr where parse begins 194 * @param ptr where parse begins
195 * @param retptr output pointer to next char after parse completes (output) 195 * @param retptr output pointer to next char after parse completes (output)
196 * @return resulting unsigned int 196 * @return resulting unsigned int
197 */ 197 */
198 static unsigned long memsize_parse (const char *const ptr, const char **retptr) 198 static unsigned long memsize_parse (const char *const ptr, const char **retptr)
199 { 199 {
200 unsigned long ret = simple_strtoul(ptr, (char **)retptr, 0); 200 unsigned long ret = simple_strtoul(ptr, (char **)retptr, 0);
201 201
202 switch (**retptr) { 202 switch (**retptr) {
203 case 'G': 203 case 'G':
204 case 'g': 204 case 'g':
205 ret <<= 10; 205 ret <<= 10;
206 case 'M': 206 case 'M':
207 case 'm': 207 case 'm':
208 ret <<= 10; 208 ret <<= 10;
209 case 'K': 209 case 'K':
210 case 'k': 210 case 'k':
211 ret <<= 10; 211 ret <<= 10;
212 (*retptr)++; 212 (*retptr)++;
213 default: 213 default:
214 break; 214 break;
215 } 215 }
216 216
217 return ret; 217 return ret;
218 } 218 }
219 219
220 /** 220 /**
221 * Format string describing supplied size. This routine does the opposite job 221 * Format string describing supplied size. This routine does the opposite job
222 * to memsize_parse(). Size in bytes is converted to string and if possible 222 * to memsize_parse(). Size in bytes is converted to string and if possible
223 * shortened by using k (kilobytes), m (megabytes) or g (gigabytes) suffix. 223 * shortened by using k (kilobytes), m (megabytes) or g (gigabytes) suffix.
224 * 224 *
225 * Note, that this routine does not check for buffer overflow, it's the caller 225 * Note, that this routine does not check for buffer overflow, it's the caller
226 * who must assure enough space. 226 * who must assure enough space.
227 * 227 *
228 * @param buf output buffer 228 * @param buf output buffer
229 * @param size size to be converted to string 229 * @param size size to be converted to string
230 */ 230 */
231 static void memsize_format(char *buf, u32 size) 231 static void memsize_format(char *buf, u32 size)
232 { 232 {
233 #define SIZE_GB ((u32)1024*1024*1024) 233 #define SIZE_GB ((u32)1024*1024*1024)
234 #define SIZE_MB ((u32)1024*1024) 234 #define SIZE_MB ((u32)1024*1024)
235 #define SIZE_KB ((u32)1024) 235 #define SIZE_KB ((u32)1024)
236 236
237 if ((size % SIZE_GB) == 0) 237 if ((size % SIZE_GB) == 0)
238 sprintf(buf, "%lug", size/SIZE_GB); 238 sprintf(buf, "%lug", size/SIZE_GB);
239 else if ((size % SIZE_MB) == 0) 239 else if ((size % SIZE_MB) == 0)
240 sprintf(buf, "%lum", size/SIZE_MB); 240 sprintf(buf, "%lum", size/SIZE_MB);
241 else if (size % SIZE_KB == 0) 241 else if (size % SIZE_KB == 0)
242 sprintf(buf, "%luk", size/SIZE_KB); 242 sprintf(buf, "%luk", size/SIZE_KB);
243 else 243 else
244 sprintf(buf, "%lu", size); 244 sprintf(buf, "%lu", size);
245 } 245 }
246 246
247 /** 247 /**
248 * This routine does global indexing of all partitions. Resulting index for 248 * This routine does global indexing of all partitions. Resulting index for
249 * current partition is saved in 'mtddevnum'. Current partition name in 249 * current partition is saved in 'mtddevnum'. Current partition name in
250 * 'mtddevname'. 250 * 'mtddevname'.
251 */ 251 */
252 static void index_partitions(void) 252 static void index_partitions(void)
253 { 253 {
254 char buf[16]; 254 char buf[16];
255 u16 mtddevnum; 255 u16 mtddevnum;
256 struct part_info *part; 256 struct part_info *part;
257 struct list_head *dentry; 257 struct list_head *dentry;
258 struct mtd_device *dev; 258 struct mtd_device *dev;
259 259
260 DEBUGF("--- index partitions ---\n"); 260 DEBUGF("--- index partitions ---\n");
261 261
262 if (current_dev) { 262 if (current_dev) {
263 mtddevnum = 0; 263 mtddevnum = 0;
264 list_for_each(dentry, &devices) { 264 list_for_each(dentry, &devices) {
265 dev = list_entry(dentry, struct mtd_device, link); 265 dev = list_entry(dentry, struct mtd_device, link);
266 if (dev == current_dev) { 266 if (dev == current_dev) {
267 mtddevnum += current_partnum; 267 mtddevnum += current_partnum;
268 sprintf(buf, "%d", mtddevnum); 268 sprintf(buf, "%d", mtddevnum);
269 setenv("mtddevnum", buf); 269 setenv("mtddevnum", buf);
270 break; 270 break;
271 } 271 }
272 mtddevnum += dev->num_parts; 272 mtddevnum += dev->num_parts;
273 } 273 }
274 274
275 part = jffs2_part_info(current_dev, current_partnum); 275 part = jffs2_part_info(current_dev, current_partnum);
276 setenv("mtddevname", part->name); 276 setenv("mtddevname", part->name);
277 277
278 DEBUGF("=> mtddevnum %d,\n=> mtddevname %s\n", mtddevnum, part->name); 278 DEBUGF("=> mtddevnum %d,\n=> mtddevname %s\n", mtddevnum, part->name);
279 } else { 279 } else {
280 setenv("mtddevnum", NULL); 280 setenv("mtddevnum", NULL);
281 setenv("mtddevname", NULL); 281 setenv("mtddevname", NULL);
282 282
283 DEBUGF("=> mtddevnum NULL\n=> mtddevname NULL\n"); 283 DEBUGF("=> mtddevnum NULL\n=> mtddevname NULL\n");
284 } 284 }
285 } 285 }
286 286
287 /** 287 /**
288 * Save current device and partition in environment variable 'partition'. 288 * Save current device and partition in environment variable 'partition'.
289 */ 289 */
290 static void current_save(void) 290 static void current_save(void)
291 { 291 {
292 char buf[16]; 292 char buf[16];
293 293
294 DEBUGF("--- current_save ---\n"); 294 DEBUGF("--- current_save ---\n");
295 295
296 if (current_dev) { 296 if (current_dev) {
297 sprintf(buf, "%s%d,%d", MTD_DEV_TYPE(current_dev->id->type), 297 sprintf(buf, "%s%d,%d", MTD_DEV_TYPE(current_dev->id->type),
298 current_dev->id->num, current_partnum); 298 current_dev->id->num, current_partnum);
299 299
300 setenv("partition", buf); 300 setenv("partition", buf);
301 strncpy(last_partition, buf, 16); 301 strncpy(last_partition, buf, 16);
302 302
303 DEBUGF("=> partition %s\n", buf); 303 DEBUGF("=> partition %s\n", buf);
304 } else { 304 } else {
305 setenv("partition", NULL); 305 setenv("partition", NULL);
306 last_partition[0] = '\0'; 306 last_partition[0] = '\0';
307 307
308 DEBUGF("=> partition NULL\n"); 308 DEBUGF("=> partition NULL\n");
309 } 309 }
310 index_partitions(); 310 index_partitions();
311 } 311 }
312 312
313 /** 313 /**
314 * Performs sanity check for supplied NOR flash partition. Table of existing 314 * Performs sanity check for supplied NOR flash partition. Table of existing
315 * NOR flash devices is searched and partition device is located. Alignment 315 * NOR flash devices is searched and partition device is located. Alignment
316 * with the granularity of NOR flash sectors is verified. 316 * with the granularity of NOR flash sectors is verified.
317 * 317 *
318 * @param id of the parent device 318 * @param id of the parent device
319 * @param part partition to validate 319 * @param part partition to validate
320 * @return 0 if partition is valid, 1 otherwise 320 * @return 0 if partition is valid, 1 otherwise
321 */ 321 */
322 static int part_validate_nor(struct mtdids *id, struct part_info *part) 322 static int part_validate_nor(struct mtdids *id, struct part_info *part)
323 { 323 {
324 #if (CONFIG_COMMANDS & CFG_CMD_FLASH) 324 #if (CONFIG_COMMANDS & CFG_CMD_FLASH)
325 /* info for FLASH chips */ 325 /* info for FLASH chips */
326 extern flash_info_t flash_info[]; 326 extern flash_info_t flash_info[];
327 flash_info_t *flash; 327 flash_info_t *flash;
328 int offset_aligned; 328 int offset_aligned;
329 u32 end_offset; 329 u32 end_offset;
330 int i; 330 int i;
331 331
332 flash = &flash_info[id->num]; 332 flash = &flash_info[id->num];
333 333
334 offset_aligned = 0; 334 offset_aligned = 0;
335 for (i = 0; i < flash->sector_count; i++) { 335 for (i = 0; i < flash->sector_count; i++) {
336 if ((flash->start[i] - flash->start[0]) == part->offset) { 336 if ((flash->start[i] - flash->start[0]) == part->offset) {
337 offset_aligned = 1; 337 offset_aligned = 1;
338 break; 338 break;
339 } 339 }
340 } 340 }
341 if (offset_aligned == 0) { 341 if (offset_aligned == 0) {
342 printf("%s%d: partition (%s) start offset alignment incorrect\n", 342 printf("%s%d: partition (%s) start offset alignment incorrect\n",
343 MTD_DEV_TYPE(id->type), id->num, part->name); 343 MTD_DEV_TYPE(id->type), id->num, part->name);
344 return 1; 344 return 1;
345 } 345 }
346 346
347 end_offset = part->offset + part->size; 347 end_offset = part->offset + part->size;
348 for (i = 0; i < flash->sector_count; i++) { 348 for (i = 0; i < flash->sector_count; i++) {
349 if ((flash->start[i] - flash->start[0]) == end_offset) 349 if ((flash->start[i] - flash->start[0]) == end_offset)
350 return 0; 350 return 0;
351 } 351 }
352 352
353 if (flash->size == end_offset) 353 if (flash->size == end_offset)
354 return 0; 354 return 0;
355 355
356 printf("%s%d: partition (%s) size alignment incorrect\n", 356 printf("%s%d: partition (%s) size alignment incorrect\n",
357 MTD_DEV_TYPE(id->type), id->num, part->name); 357 MTD_DEV_TYPE(id->type), id->num, part->name);
358 #endif 358 #endif
359 return 1; 359 return 1;
360 } 360 }
361 361
362 /** 362 /**
363 * Performs sanity check for supplied NAND flash partition. Table of existing 363 * Performs sanity check for supplied NAND flash partition. Table of existing
364 * NAND flash devices is searched and partition device is located. Alignment 364 * NAND flash devices is searched and partition device is located. Alignment
365 * with the granularity of nand erasesize is verified. 365 * with the granularity of nand erasesize is verified.
366 * 366 *
367 * @param id of the parent device 367 * @param id of the parent device
368 * @param part partition to validate 368 * @param part partition to validate
369 * @return 0 if partition is valid, 1 otherwise 369 * @return 0 if partition is valid, 1 otherwise
370 */ 370 */
371 static int part_validate_nand(struct mtdids *id, struct part_info *part) 371 static int part_validate_nand(struct mtdids *id, struct part_info *part)
372 { 372 {
373 #if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) 373 #if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND)
374 /* info for NAND chips */ 374 /* info for NAND chips */
375 nand_info_t *nand; 375 nand_info_t *nand;
376 376
377 nand = &nand_info[id->num]; 377 nand = &nand_info[id->num];
378 378
379 if ((unsigned long)(part->offset) % nand->erasesize) { 379 if ((unsigned long)(part->offset) % nand->erasesize) {
380 printf("%s%d: partition (%s) start offset alignment incorrect\n", 380 printf("%s%d: partition (%s) start offset alignment incorrect\n",
381 MTD_DEV_TYPE(id->type), id->num, part->name); 381 MTD_DEV_TYPE(id->type), id->num, part->name);
382 return 1; 382 return 1;
383 } 383 }
384 384
385 if (part->size % nand->erasesize) { 385 if (part->size % nand->erasesize) {
386 printf("%s%d: partition (%s) size alignment incorrect\n", 386 printf("%s%d: partition (%s) size alignment incorrect\n",
387 MTD_DEV_TYPE(id->type), id->num, part->name); 387 MTD_DEV_TYPE(id->type), id->num, part->name);
388 return 1; 388 return 1;
389 } 389 }
390 390
391 return 0; 391 return 0;
392 #else 392 #else
393 return 1; 393 return 1;
394 #endif 394 #endif
395 } 395 }
396 396
397 /** 397 /**
398 * Performs sanity check for supplied partition. Offset and size are verified 398 * Performs sanity check for supplied partition. Offset and size are verified
399 * to be within valid range. Partition type is checked and either 399 * to be within valid range. Partition type is checked and either
400 * parts_validate_nor() or parts_validate_nand() is called with the argument 400 * parts_validate_nor() or parts_validate_nand() is called with the argument
401 * of part. 401 * of part.
402 * 402 *
403 * @param id of the parent device 403 * @param id of the parent device
404 * @param part partition to validate 404 * @param part partition to validate
405 * @return 0 if partition is valid, 1 otherwise 405 * @return 0 if partition is valid, 1 otherwise
406 */ 406 */
407 static int part_validate(struct mtdids *id, struct part_info *part) 407 static int part_validate(struct mtdids *id, struct part_info *part)
408 { 408 {
409 if (part->size == SIZE_REMAINING) 409 if (part->size == SIZE_REMAINING)
410 part->size = id->size - part->offset; 410 part->size = id->size - part->offset;
411 411
412 if (part->offset > id->size) { 412 if (part->offset > id->size) {
413 printf("%s: offset %08lx beyond flash size %08lx\n", 413 printf("%s: offset %08lx beyond flash size %08lx\n",
414 id->mtd_id, part->offset, id->size); 414 id->mtd_id, part->offset, id->size);
415 return 1; 415 return 1;
416 } 416 }
417 417
418 if ((part->offset + part->size) <= part->offset) { 418 if ((part->offset + part->size) <= part->offset) {
419 printf("%s%d: partition (%s) size too big\n", 419 printf("%s%d: partition (%s) size too big\n",
420 MTD_DEV_TYPE(id->type), id->num, part->name); 420 MTD_DEV_TYPE(id->type), id->num, part->name);
421 return 1; 421 return 1;
422 } 422 }
423 423
424 if (part->offset + part->size > id->size) { 424 if (part->offset + part->size > id->size) {
425 printf("%s: partitioning exceeds flash size\n", id->mtd_id); 425 printf("%s: partitioning exceeds flash size\n", id->mtd_id);
426 return 1; 426 return 1;
427 } 427 }
428 428
429 if (id->type == MTD_DEV_TYPE_NAND) 429 if (id->type == MTD_DEV_TYPE_NAND)
430 return part_validate_nand(id, part); 430 return part_validate_nand(id, part);
431 else if (id->type == MTD_DEV_TYPE_NOR) 431 else if (id->type == MTD_DEV_TYPE_NOR)
432 return part_validate_nor(id, part); 432 return part_validate_nor(id, part);
433 else 433 else
434 DEBUGF("part_validate: invalid dev type\n"); 434 DEBUGF("part_validate: invalid dev type\n");
435 435
436 return 1; 436 return 1;
437 } 437 }
438 438
439 /** 439 /**
440 * Delete selected partition from the partion list of the specified device. 440 * Delete selected partition from the partion list of the specified device.
441 * 441 *
442 * @param dev device to delete partition from 442 * @param dev device to delete partition from
443 * @param part partition to delete 443 * @param part partition to delete
444 * @return 0 on success, 1 otherwise 444 * @return 0 on success, 1 otherwise
445 */ 445 */
446 static int part_del(struct mtd_device *dev, struct part_info *part) 446 static int part_del(struct mtd_device *dev, struct part_info *part)
447 { 447 {
448 u8 current_save_needed = 0; 448 u8 current_save_needed = 0;
449 449
450 /* if there is only one partition, remove whole device */ 450 /* if there is only one partition, remove whole device */
451 if (dev->num_parts == 1) 451 if (dev->num_parts == 1)
452 return device_del(dev); 452 return device_del(dev);
453 453
454 /* otherwise just delete this partition */ 454 /* otherwise just delete this partition */
455 455
456 if (dev == current_dev) { 456 if (dev == current_dev) {
457 /* we are modyfing partitions for the current device, 457 /* we are modyfing partitions for the current device,
458 * update current */ 458 * update current */
459 struct part_info *curr_pi; 459 struct part_info *curr_pi;
460 curr_pi = jffs2_part_info(current_dev, current_partnum); 460 curr_pi = jffs2_part_info(current_dev, current_partnum);
461 461
462 if (curr_pi) { 462 if (curr_pi) {
463 if (curr_pi == part) { 463 if (curr_pi == part) {
464 printf("current partition deleted, resetting current to 0\n"); 464 printf("current partition deleted, resetting current to 0\n");
465 current_partnum = 0; 465 current_partnum = 0;
466 } else if (part->offset <= curr_pi->offset) { 466 } else if (part->offset <= curr_pi->offset) {
467 current_partnum--; 467 current_partnum--;
468 } 468 }
469 current_save_needed = 1; 469 current_save_needed = 1;
470 } 470 }
471 } 471 }
472 472
473 #ifdef CFG_NAND_LEGACY 473 #ifdef CFG_NAND_LEGACY
474 jffs2_free_cache(part); 474 jffs2_free_cache(part);
475 #endif 475 #endif
476 list_del(&part->link); 476 list_del(&part->link);
477 free(part); 477 free(part);
478 dev->num_parts--; 478 dev->num_parts--;
479 479
480 if (current_save_needed > 0) 480 if (current_save_needed > 0)
481 current_save(); 481 current_save();
482 else 482 else
483 index_partitions(); 483 index_partitions();
484 484
485 return 0; 485 return 0;
486 } 486 }
487 487
488 /** 488 /**
489 * Delete all partitions from parts head list, free memory. 489 * Delete all partitions from parts head list, free memory.
490 * 490 *
491 * @param head list of partitions to delete 491 * @param head list of partitions to delete
492 */ 492 */
493 static void part_delall(struct list_head *head) 493 static void part_delall(struct list_head *head)
494 { 494 {
495 struct list_head *entry, *n; 495 struct list_head *entry, *n;
496 struct part_info *part_tmp; 496 struct part_info *part_tmp;
497 497
498 /* clean tmp_list and free allocated memory */ 498 /* clean tmp_list and free allocated memory */
499 list_for_each_safe(entry, n, head) { 499 list_for_each_safe(entry, n, head) {
500 part_tmp = list_entry(entry, struct part_info, link); 500 part_tmp = list_entry(entry, struct part_info, link);
501 501
502 #ifdef CFG_NAND_LEGACY 502 #ifdef CFG_NAND_LEGACY
503 jffs2_free_cache(part_tmp); 503 jffs2_free_cache(part_tmp);
504 #endif 504 #endif
505 list_del(entry); 505 list_del(entry);
506 free(part_tmp); 506 free(part_tmp);
507 } 507 }
508 } 508 }
509 509
510 /** 510 /**
511 * Add new partition to the supplied partition list. Make sure partitions are 511 * Add new partition to the supplied partition list. Make sure partitions are
512 * sorted by offset in ascending order. 512 * sorted by offset in ascending order.
513 * 513 *
514 * @param head list this partition is to be added to 514 * @param head list this partition is to be added to
515 * @param new partition to be added 515 * @param new partition to be added
516 */ 516 */
517 static int part_sort_add(struct mtd_device *dev, struct part_info *part) 517 static int part_sort_add(struct mtd_device *dev, struct part_info *part)
518 { 518 {
519 struct list_head *entry; 519 struct list_head *entry;
520 struct part_info *new_pi, *curr_pi; 520 struct part_info *new_pi, *curr_pi;
521 521
522 /* link partition to parrent dev */ 522 /* link partition to parrent dev */
523 part->dev = dev; 523 part->dev = dev;
524 524
525 if (list_empty(&dev->parts)) { 525 if (list_empty(&dev->parts)) {
526 DEBUGF("part_sort_add: list empty\n"); 526 DEBUGF("part_sort_add: list empty\n");
527 list_add(&part->link, &dev->parts); 527 list_add(&part->link, &dev->parts);
528 dev->num_parts++; 528 dev->num_parts++;
529 index_partitions(); 529 index_partitions();
530 return 0; 530 return 0;
531 } 531 }
532 532
533 new_pi = list_entry(&part->link, struct part_info, link); 533 new_pi = list_entry(&part->link, struct part_info, link);
534 534
535 /* get current partition info if we are updating current device */ 535 /* get current partition info if we are updating current device */
536 curr_pi = NULL; 536 curr_pi = NULL;
537 if (dev == current_dev) 537 if (dev == current_dev)
538 curr_pi = jffs2_part_info(current_dev, current_partnum); 538 curr_pi = jffs2_part_info(current_dev, current_partnum);
539 539
540 list_for_each(entry, &dev->parts) { 540 list_for_each(entry, &dev->parts) {
541 struct part_info *pi; 541 struct part_info *pi;
542 542
543 pi = list_entry(entry, struct part_info, link); 543 pi = list_entry(entry, struct part_info, link);
544 544
545 /* be compliant with kernel cmdline, allow only one partition at offset zero */ 545 /* be compliant with kernel cmdline, allow only one partition at offset zero */
546 if ((new_pi->offset == pi->offset) && (pi->offset == 0)) { 546 if ((new_pi->offset == pi->offset) && (pi->offset == 0)) {
547 printf("cannot add second partition at offset 0\n"); 547 printf("cannot add second partition at offset 0\n");
548 return 1; 548 return 1;
549 } 549 }
550 550
551 if (new_pi->offset <= pi->offset) { 551 if (new_pi->offset <= pi->offset) {
552 list_add_tail(&part->link, entry); 552 list_add_tail(&part->link, entry);
553 dev->num_parts++; 553 dev->num_parts++;
554 554
555 if (curr_pi && (pi->offset <= curr_pi->offset)) { 555 if (curr_pi && (pi->offset <= curr_pi->offset)) {
556 /* we are modyfing partitions for the current 556 /* we are modyfing partitions for the current
557 * device, update current */ 557 * device, update current */
558 current_partnum++; 558 current_partnum++;
559 current_save(); 559 current_save();
560 } else { 560 } else {
561 index_partitions(); 561 index_partitions();
562 } 562 }
563 return 0; 563 return 0;
564 } 564 }
565 } 565 }
566 566
567 list_add_tail(&part->link, &dev->parts); 567 list_add_tail(&part->link, &dev->parts);
568 dev->num_parts++; 568 dev->num_parts++;
569 index_partitions(); 569 index_partitions();
570 return 0; 570 return 0;
571 } 571 }
572 572
573 /** 573 /**
574 * Add provided partition to the partition list of a given device. 574 * Add provided partition to the partition list of a given device.
575 * 575 *
576 * @param dev device to which partition is added 576 * @param dev device to which partition is added
577 * @param part partition to be added 577 * @param part partition to be added
578 * @return 0 on success, 1 otherwise 578 * @return 0 on success, 1 otherwise
579 */ 579 */
580 static int part_add(struct mtd_device *dev, struct part_info *part) 580 static int part_add(struct mtd_device *dev, struct part_info *part)
581 { 581 {
582 /* verify alignment and size */ 582 /* verify alignment and size */
583 if (part_validate(dev->id, part) != 0) 583 if (part_validate(dev->id, part) != 0)
584 return 1; 584 return 1;
585 585
586 /* partition is ok, add it to the list */ 586 /* partition is ok, add it to the list */
587 if (part_sort_add(dev, part) != 0) 587 if (part_sort_add(dev, part) != 0)
588 return 1; 588 return 1;
589 589
590 return 0; 590 return 0;
591 } 591 }
592 592
593 /** 593 /**
594 * Parse one partition definition, allocate memory and return pointer to this 594 * Parse one partition definition, allocate memory and return pointer to this
595 * location in retpart. 595 * location in retpart.
596 * 596 *
597 * @param partdef pointer to the partition definition string i.e. <part-def> 597 * @param partdef pointer to the partition definition string i.e. <part-def>
598 * @param ret output pointer to next char after parse completes (output) 598 * @param ret output pointer to next char after parse completes (output)
599 * @param retpart pointer to the allocated partition (output) 599 * @param retpart pointer to the allocated partition (output)
600 * @return 0 on success, 1 otherwise 600 * @return 0 on success, 1 otherwise
601 */ 601 */
602 static int part_parse(const char *const partdef, const char **ret, struct part_info **retpart) 602 static int part_parse(const char *const partdef, const char **ret, struct part_info **retpart)
603 { 603 {
604 struct part_info *part; 604 struct part_info *part;
605 unsigned long size; 605 unsigned long size;
606 unsigned long offset; 606 unsigned long offset;
607 const char *name; 607 const char *name;
608 int name_len; 608 int name_len;
609 unsigned int mask_flags; 609 unsigned int mask_flags;
610 const char *p; 610 const char *p;
611 611
612 p = partdef; 612 p = partdef;
613 *retpart = NULL; 613 *retpart = NULL;
614 *ret = NULL; 614 *ret = NULL;
615 615
616 /* fetch the partition size */ 616 /* fetch the partition size */
617 if (*p == '-') { 617 if (*p == '-') {
618 /* assign all remaining space to this partition */ 618 /* assign all remaining space to this partition */
619 DEBUGF("'-': remaining size assigned\n"); 619 DEBUGF("'-': remaining size assigned\n");
620 size = SIZE_REMAINING; 620 size = SIZE_REMAINING;
621 p++; 621 p++;
622 } else { 622 } else {
623 size = memsize_parse(p, &p); 623 size = memsize_parse(p, &p);
624 if (size < MIN_PART_SIZE) { 624 if (size < MIN_PART_SIZE) {
625 printf("partition size too small (%lx)\n", size); 625 printf("partition size too small (%lx)\n", size);
626 return 1; 626 return 1;
627 } 627 }
628 } 628 }
629 629
630 /* check for offset */ 630 /* check for offset */
631 offset = OFFSET_NOT_SPECIFIED; 631 offset = OFFSET_NOT_SPECIFIED;
632 if (*p == '@') { 632 if (*p == '@') {
633 p++; 633 p++;
634 offset = memsize_parse(p, &p); 634 offset = memsize_parse(p, &p);
635 } 635 }
636 636
637 /* now look for the name */ 637 /* now look for the name */
638 if (*p == '(') { 638 if (*p == '(') {
639 name = ++p; 639 name = ++p;
640 if ((p = strchr(name, ')')) == NULL) { 640 if ((p = strchr(name, ')')) == NULL) {
641 printf("no closing ) found in partition name\n"); 641 printf("no closing ) found in partition name\n");
642 return 1; 642 return 1;
643 } 643 }
644 name_len = p - name + 1; 644 name_len = p - name + 1;
645 if ((name_len - 1) == 0) { 645 if ((name_len - 1) == 0) {
646 printf("empty partition name\n"); 646 printf("empty partition name\n");
647 return 1; 647 return 1;
648 } 648 }
649 p++; 649 p++;
650 } else { 650 } else {
651 /* 0x00000000@0x00000000 */ 651 /* 0x00000000@0x00000000 */
652 name_len = 22; 652 name_len = 22;
653 name = NULL; 653 name = NULL;
654 } 654 }
655 655
656 /* test for options */ 656 /* test for options */
657 mask_flags = 0; 657 mask_flags = 0;
658 if (strncmp(p, "ro", 2) == 0) { 658 if (strncmp(p, "ro", 2) == 0) {
659 mask_flags |= MTD_WRITEABLE_CMD; 659 mask_flags |= MTD_WRITEABLE_CMD;
660 p += 2; 660 p += 2;
661 } 661 }
662 662
663 /* check for next partition definition */ 663 /* check for next partition definition */
664 if (*p == ',') { 664 if (*p == ',') {
665 if (size == SIZE_REMAINING) { 665 if (size == SIZE_REMAINING) {
666 *ret = NULL; 666 *ret = NULL;
667 printf("no partitions allowed after a fill-up partition\n"); 667 printf("no partitions allowed after a fill-up partition\n");
668 return 1; 668 return 1;
669 } 669 }
670 *ret = ++p; 670 *ret = ++p;
671 } else if ((*p == ';') || (*p == '\0')) { 671 } else if ((*p == ';') || (*p == '\0')) {
672 *ret = p; 672 *ret = p;
673 } else { 673 } else {
674 printf("unexpected character '%c' at the end of partition\n", *p); 674 printf("unexpected character '%c' at the end of partition\n", *p);
675 *ret = NULL; 675 *ret = NULL;
676 return 1; 676 return 1;
677 } 677 }
678 678
679 /* allocate memory */ 679 /* allocate memory */
680 part = (struct part_info *)malloc(sizeof(struct part_info) + name_len); 680 part = (struct part_info *)malloc(sizeof(struct part_info) + name_len);
681 if (!part) { 681 if (!part) {
682 printf("out of memory\n"); 682 printf("out of memory\n");
683 return 1; 683 return 1;
684 } 684 }
685 memset(part, 0, sizeof(struct part_info) + name_len); 685 memset(part, 0, sizeof(struct part_info) + name_len);
686 part->size = size; 686 part->size = size;
687 part->offset = offset; 687 part->offset = offset;
688 part->mask_flags = mask_flags; 688 part->mask_flags = mask_flags;
689 part->name = (char *)(part + 1); 689 part->name = (char *)(part + 1);
690 690
691 if (name) { 691 if (name) {
692 /* copy user provided name */ 692 /* copy user provided name */
693 strncpy(part->name, name, name_len - 1); 693 strncpy(part->name, name, name_len - 1);
694 part->auto_name = 0; 694 part->auto_name = 0;
695 } else { 695 } else {
696 /* auto generated name in form of size@offset */ 696 /* auto generated name in form of size@offset */
697 sprintf(part->name, "0x%08lx@0x%08lx", size, offset); 697 sprintf(part->name, "0x%08lx@0x%08lx", size, offset);
698 part->auto_name = 1; 698 part->auto_name = 1;
699 } 699 }
700 700
701 part->name[name_len - 1] = '\0'; 701 part->name[name_len - 1] = '\0';
702 INIT_LIST_HEAD(&part->link); 702 INIT_LIST_HEAD(&part->link);
703 703
704 DEBUGF("+ partition: name %-22s size 0x%08x offset 0x%08x mask flags %d\n", 704 DEBUGF("+ partition: name %-22s size 0x%08x offset 0x%08x mask flags %d\n",
705 part->name, part->size, 705 part->name, part->size,
706 part->offset, part->mask_flags); 706 part->offset, part->mask_flags);
707 707
708 *retpart = part; 708 *retpart = part;
709 return 0; 709 return 0;
710 } 710 }
711 #endif/* #ifdef CONFIG_JFFS2_CMDLINE */ 711 #endif/* #ifdef CONFIG_JFFS2_CMDLINE */
712 712
713 /** 713 /**
714 * Check device number to be within valid range for given device type. 714 * Check device number to be within valid range for given device type.
715 * 715 *
716 * @param dev device to validate 716 * @param dev device to validate
717 * @return 0 if device is valid, 1 otherwise 717 * @return 0 if device is valid, 1 otherwise
718 */ 718 */
719 static int device_validate(u8 type, u8 num, u32 *size) 719 static int device_validate(u8 type, u8 num, u32 *size)
720 { 720 {
721 if (type == MTD_DEV_TYPE_NOR) { 721 if (type == MTD_DEV_TYPE_NOR) {
722 #if (CONFIG_COMMANDS & CFG_CMD_FLASH) 722 #if (CONFIG_COMMANDS & CFG_CMD_FLASH)
723 if (num < CFG_MAX_FLASH_BANKS) { 723 if (num < CFG_MAX_FLASH_BANKS) {
724 extern flash_info_t flash_info[]; 724 extern flash_info_t flash_info[];
725 *size = flash_info[num].size; 725 *size = flash_info[num].size;
726 726
727 return 0; 727 return 0;
728 } 728 }
729 729
730 printf("no such FLASH device: %s%d (valid range 0 ... %d\n", 730 printf("no such FLASH device: %s%d (valid range 0 ... %d\n",
731 MTD_DEV_TYPE(type), num, CFG_MAX_FLASH_BANKS - 1); 731 MTD_DEV_TYPE(type), num, CFG_MAX_FLASH_BANKS - 1);
732 #else 732 #else
733 printf("support for FLASH devices not present\n"); 733 printf("support for FLASH devices not present\n");
734 #endif 734 #endif
735 } else if (type == MTD_DEV_TYPE_NAND) { 735 } else if (type == MTD_DEV_TYPE_NAND) {
736 #if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) 736 #if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND)
737 if (num < CFG_MAX_NAND_DEVICE) { 737 if (num < CFG_MAX_NAND_DEVICE) {
738 #ifndef CFG_NAND_LEGACY 738 #ifndef CFG_NAND_LEGACY
739 *size = nand_info[num].size; 739 *size = nand_info[num].size;
740 #else 740 #else
741 extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE]; 741 extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
742 *size = nand_dev_desc[num].totlen; 742 *size = nand_dev_desc[num].totlen;
743 #endif 743 #endif
744 return 0; 744 return 0;
745 } 745 }
746 746
747 printf("no such NAND device: %s%d (valid range 0 ... %d)\n", 747 printf("no such NAND device: %s%d (valid range 0 ... %d)\n",
748 MTD_DEV_TYPE(type), num, CFG_MAX_NAND_DEVICE - 1); 748 MTD_DEV_TYPE(type), num, CFG_MAX_NAND_DEVICE - 1);
749 #else 749 #else
750 printf("support for NAND devices not present\n"); 750 printf("support for NAND devices not present\n");
751 #endif 751 #endif
752 } 752 }
753 753
754 return 1; 754 return 1;
755 } 755 }
756 756
757 #ifdef CONFIG_JFFS2_CMDLINE 757 #ifdef CONFIG_JFFS2_CMDLINE
758 /** 758 /**
759 * Delete all mtd devices from a supplied devices list, free memory allocated for 759 * Delete all mtd devices from a supplied devices list, free memory allocated for
760 * each device and delete all device partitions. 760 * each device and delete all device partitions.
761 * 761 *
762 * @return 0 on success, 1 otherwise 762 * @return 0 on success, 1 otherwise
763 */ 763 */
764 static int device_delall(struct list_head *head) 764 static int device_delall(struct list_head *head)
765 { 765 {
766 struct list_head *entry, *n; 766 struct list_head *entry, *n;
767 struct mtd_device *dev_tmp; 767 struct mtd_device *dev_tmp;
768 768
769 /* clean devices list */ 769 /* clean devices list */
770 list_for_each_safe(entry, n, head) { 770 list_for_each_safe(entry, n, head) {
771 dev_tmp = list_entry(entry, struct mtd_device, link); 771 dev_tmp = list_entry(entry, struct mtd_device, link);
772 list_del(entry); 772 list_del(entry);
773 part_delall(&dev_tmp->parts); 773 part_delall(&dev_tmp->parts);
774 free(dev_tmp); 774 free(dev_tmp);
775 } 775 }
776 INIT_LIST_HEAD(&devices); 776 INIT_LIST_HEAD(&devices);
777 777
778 return 0; 778 return 0;
779 } 779 }
780 780
781 /** 781 /**
782 * If provided device exists it's partitions are deleted, device is removed 782 * If provided device exists it's partitions are deleted, device is removed
783 * from device list and device memory is freed. 783 * from device list and device memory is freed.
784 * 784 *
785 * @param dev device to be deleted 785 * @param dev device to be deleted
786 * @return 0 on success, 1 otherwise 786 * @return 0 on success, 1 otherwise
787 */ 787 */
788 static int device_del(struct mtd_device *dev) 788 static int device_del(struct mtd_device *dev)
789 { 789 {
790 part_delall(&dev->parts); 790 part_delall(&dev->parts);
791 list_del(&dev->link); 791 list_del(&dev->link);
792 free(dev); 792 free(dev);
793 793
794 if (dev == current_dev) { 794 if (dev == current_dev) {
795 /* we just deleted current device */ 795 /* we just deleted current device */
796 if (list_empty(&devices)) { 796 if (list_empty(&devices)) {
797 current_dev = NULL; 797 current_dev = NULL;
798 } else { 798 } else {
799 /* reset first partition from first dev from the 799 /* reset first partition from first dev from the
800 * devices list as current */ 800 * devices list as current */
801 current_dev = list_entry(devices.next, struct mtd_device, link); 801 current_dev = list_entry(devices.next, struct mtd_device, link);
802 current_partnum = 0; 802 current_partnum = 0;
803 } 803 }
804 current_save(); 804 current_save();
805 return 0; 805 return 0;
806 } 806 }
807 807
808 index_partitions(); 808 index_partitions();
809 return 0; 809 return 0;
810 } 810 }
811 811
812 /** 812 /**
813 * Search global device list and return pointer to the device of type and num 813 * Search global device list and return pointer to the device of type and num
814 * specified. 814 * specified.
815 * 815 *
816 * @param type device type 816 * @param type device type
817 * @param num device number 817 * @param num device number
818 * @return NULL if requested device does not exist 818 * @return NULL if requested device does not exist
819 */ 819 */
820 static struct mtd_device* device_find(u8 type, u8 num) 820 static struct mtd_device* device_find(u8 type, u8 num)
821 { 821 {
822 struct list_head *entry; 822 struct list_head *entry;
823 struct mtd_device *dev_tmp; 823 struct mtd_device *dev_tmp;
824 824
825 list_for_each(entry, &devices) { 825 list_for_each(entry, &devices) {
826 dev_tmp = list_entry(entry, struct mtd_device, link); 826 dev_tmp = list_entry(entry, struct mtd_device, link);
827 827
828 if ((dev_tmp->id->type == type) && (dev_tmp->id->num == num)) 828 if ((dev_tmp->id->type == type) && (dev_tmp->id->num == num))
829 return dev_tmp; 829 return dev_tmp;
830 } 830 }
831 831
832 return NULL; 832 return NULL;
833 } 833 }
834 834
835 /** 835 /**
836 * Add specified device to the global device list. 836 * Add specified device to the global device list.
837 * 837 *
838 * @param dev device to be added 838 * @param dev device to be added
839 */ 839 */
840 static void device_add(struct mtd_device *dev) 840 static void device_add(struct mtd_device *dev)
841 { 841 {
842 u8 current_save_needed = 0; 842 u8 current_save_needed = 0;
843 843
844 if (list_empty(&devices)) { 844 if (list_empty(&devices)) {
845 current_dev = dev; 845 current_dev = dev;
846 current_partnum = 0; 846 current_partnum = 0;
847 current_save_needed = 1; 847 current_save_needed = 1;
848 } 848 }
849 849
850 list_add_tail(&dev->link, &devices); 850 list_add_tail(&dev->link, &devices);
851 851
852 if (current_save_needed > 0) 852 if (current_save_needed > 0)
853 current_save(); 853 current_save();
854 else 854 else
855 index_partitions(); 855 index_partitions();
856 } 856 }
857 857
858 /** 858 /**
859 * Parse device type, name and mtd-id. If syntax is ok allocate memory and 859 * Parse device type, name and mtd-id. If syntax is ok allocate memory and
860 * return pointer to the device structure. 860 * return pointer to the device structure.
861 * 861 *
862 * @param mtd_dev pointer to the device definition string i.e. <mtd-dev> 862 * @param mtd_dev pointer to the device definition string i.e. <mtd-dev>
863 * @param ret output pointer to next char after parse completes (output) 863 * @param ret output pointer to next char after parse completes (output)
864 * @param retdev pointer to the allocated device (output) 864 * @param retdev pointer to the allocated device (output)
865 * @return 0 on success, 1 otherwise 865 * @return 0 on success, 1 otherwise
866 */ 866 */
867 static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_device **retdev) 867 static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_device **retdev)
868 { 868 {
869 struct mtd_device *dev; 869 struct mtd_device *dev;
870 struct part_info *part; 870 struct part_info *part;
871 struct mtdids *id; 871 struct mtdids *id;
872 const char *mtd_id; 872 const char *mtd_id;
873 unsigned int mtd_id_len; 873 unsigned int mtd_id_len;
874 const char *p, *pend; 874 const char *p, *pend;
875 LIST_HEAD(tmp_list); 875 LIST_HEAD(tmp_list);
876 struct list_head *entry, *n; 876 struct list_head *entry, *n;
877 u16 num_parts; 877 u16 num_parts;
878 u32 offset; 878 u32 offset;
879 int err = 1; 879 int err = 1;
880 880
881 p = mtd_dev; 881 p = mtd_dev;
882 *retdev = NULL; 882 *retdev = NULL;
883 *ret = NULL; 883 *ret = NULL;
884 884
885 DEBUGF("===device_parse===\n"); 885 DEBUGF("===device_parse===\n");
886 886
887 /* fetch <mtd-id> */ 887 /* fetch <mtd-id> */
888 mtd_id = p; 888 mtd_id = p;
889 if (!(p = strchr(mtd_id, ':'))) { 889 if (!(p = strchr(mtd_id, ':'))) {
890 printf("no <mtd-id> identifier\n"); 890 printf("no <mtd-id> identifier\n");
891 return 1; 891 return 1;
892 } 892 }
893 mtd_id_len = p - mtd_id + 1; 893 mtd_id_len = p - mtd_id + 1;
894 p++; 894 p++;
895 895
896 /* verify if we have a valid device specified */ 896 /* verify if we have a valid device specified */
897 if ((id = id_find_by_mtd_id(mtd_id, mtd_id_len - 1)) == NULL) { 897 if ((id = id_find_by_mtd_id(mtd_id, mtd_id_len - 1)) == NULL) {
898 printf("invalid mtd device '%.*s'\n", mtd_id_len - 1, mtd_id); 898 printf("invalid mtd device '%.*s'\n", mtd_id_len - 1, mtd_id);
899 return 1; 899 return 1;
900 } 900 }
901 901
902 DEBUGF("dev type = %d (%s), dev num = %d, mtd-id = %s\n", 902 DEBUGF("dev type = %d (%s), dev num = %d, mtd-id = %s\n",
903 id->type, MTD_DEV_TYPE(id->type), 903 id->type, MTD_DEV_TYPE(id->type),
904 id->num, id->mtd_id); 904 id->num, id->mtd_id);
905 pend = strchr(p, ';'); 905 pend = strchr(p, ';');
906 DEBUGF("parsing partitions %.*s\n", (pend ? pend - p : strlen(p)), p); 906 DEBUGF("parsing partitions %.*s\n", (pend ? pend - p : strlen(p)), p);
907 907
908 908
909 /* parse partitions */ 909 /* parse partitions */
910 num_parts = 0; 910 num_parts = 0;
911 911
912 offset = 0; 912 offset = 0;
913 if ((dev = device_find(id->type, id->num)) != NULL) { 913 if ((dev = device_find(id->type, id->num)) != NULL) {
914 /* if device already exists start at the end of the last partition */ 914 /* if device already exists start at the end of the last partition */
915 part = list_entry(dev->parts.prev, struct part_info, link); 915 part = list_entry(dev->parts.prev, struct part_info, link);
916 offset = part->offset + part->size; 916 offset = part->offset + part->size;
917 } 917 }
918 918
919 while (p && (*p != '\0') && (*p != ';')) { 919 while (p && (*p != '\0') && (*p != ';')) {
920 err = 1; 920 err = 1;
921 if ((part_parse(p, &p, &part) != 0) || (!part)) 921 if ((part_parse(p, &p, &part) != 0) || (!part))
922 break; 922 break;
923 923
924 /* calculate offset when not specified */ 924 /* calculate offset when not specified */
925 if (part->offset == OFFSET_NOT_SPECIFIED) 925 if (part->offset == OFFSET_NOT_SPECIFIED)
926 part->offset = offset; 926 part->offset = offset;
927 else 927 else
928 offset = part->offset; 928 offset = part->offset;
929 929
930 /* verify alignment and size */ 930 /* verify alignment and size */
931 if (part_validate(id, part) != 0) 931 if (part_validate(id, part) != 0)
932 break; 932 break;
933 933
934 offset += part->size; 934 offset += part->size;
935 935
936 /* partition is ok, add it to the list */ 936 /* partition is ok, add it to the list */
937 list_add_tail(&part->link, &tmp_list); 937 list_add_tail(&part->link, &tmp_list);
938 num_parts++; 938 num_parts++;
939 err = 0; 939 err = 0;
940 } 940 }
941 if (err == 1) { 941 if (err == 1) {
942 part_delall(&tmp_list); 942 part_delall(&tmp_list);
943 return 1; 943 return 1;
944 } 944 }
945 945
946 if (num_parts == 0) { 946 if (num_parts == 0) {
947 printf("no partitions for device %s%d (%s)\n", 947 printf("no partitions for device %s%d (%s)\n",
948 MTD_DEV_TYPE(id->type), id->num, id->mtd_id); 948 MTD_DEV_TYPE(id->type), id->num, id->mtd_id);
949 return 1; 949 return 1;
950 } 950 }
951 951
952 DEBUGF("\ntotal partitions: %d\n", num_parts); 952 DEBUGF("\ntotal partitions: %d\n", num_parts);
953 953
954 /* check for next device presence */ 954 /* check for next device presence */
955 if (p) { 955 if (p) {
956 if (*p == ';') { 956 if (*p == ';') {
957 *ret = ++p; 957 *ret = ++p;
958 } else if (*p == '\0') { 958 } else if (*p == '\0') {
959 *ret = p; 959 *ret = p;
960 } else { 960 } else {
961 printf("unexpected character '%c' at the end of device\n", *p); 961 printf("unexpected character '%c' at the end of device\n", *p);
962 *ret = NULL; 962 *ret = NULL;
963 return 1; 963 return 1;
964 } 964 }
965 } 965 }
966 966
967 /* allocate memory for mtd_device structure */ 967 /* allocate memory for mtd_device structure */
968 if ((dev = (struct mtd_device *)malloc(sizeof(struct mtd_device))) == NULL) { 968 if ((dev = (struct mtd_device *)malloc(sizeof(struct mtd_device))) == NULL) {
969 printf("out of memory\n"); 969 printf("out of memory\n");
970 return 1; 970 return 1;
971 } 971 }
972 memset(dev, 0, sizeof(struct mtd_device)); 972 memset(dev, 0, sizeof(struct mtd_device));
973 dev->id = id; 973 dev->id = id;
974 dev->num_parts = 0; /* part_sort_add increments num_parts */ 974 dev->num_parts = 0; /* part_sort_add increments num_parts */
975 INIT_LIST_HEAD(&dev->parts); 975 INIT_LIST_HEAD(&dev->parts);
976 INIT_LIST_HEAD(&dev->link); 976 INIT_LIST_HEAD(&dev->link);
977 977
978 /* move partitions from tmp_list to dev->parts */ 978 /* move partitions from tmp_list to dev->parts */
979 list_for_each_safe(entry, n, &tmp_list) { 979 list_for_each_safe(entry, n, &tmp_list) {
980 part = list_entry(entry, struct part_info, link); 980 part = list_entry(entry, struct part_info, link);
981 list_del(entry); 981 list_del(entry);
982 if (part_sort_add(dev, part) != 0) { 982 if (part_sort_add(dev, part) != 0) {
983 device_del(dev); 983 device_del(dev);
984 return 1; 984 return 1;
985 } 985 }
986 } 986 }
987 987
988 *retdev = dev; 988 *retdev = dev;
989 989
990 DEBUGF("===\n\n"); 990 DEBUGF("===\n\n");
991 return 0; 991 return 0;
992 } 992 }
993 993
994 /** 994 /**
995 * Initialize global device list. 995 * Initialize global device list.
996 * 996 *
997 * @return 0 on success, 1 otherwise 997 * @return 0 on success, 1 otherwise
998 */ 998 */
999 static int devices_init(void) 999 static int devices_init(void)
1000 { 1000 {
1001 last_parts[0] = '\0'; 1001 last_parts[0] = '\0';
1002 current_dev = NULL; 1002 current_dev = NULL;
1003 current_save(); 1003 current_save();
1004 1004
1005 return device_delall(&devices); 1005 return device_delall(&devices);
1006 } 1006 }
1007 1007
1008 /* 1008 /*
1009 * Search global mtdids list and find id of requested type and number. 1009 * Search global mtdids list and find id of requested type and number.
1010 * 1010 *
1011 * @return pointer to the id if it exists, NULL otherwise 1011 * @return pointer to the id if it exists, NULL otherwise
1012 */ 1012 */
1013 static struct mtdids* id_find(u8 type, u8 num) 1013 static struct mtdids* id_find(u8 type, u8 num)
1014 { 1014 {
1015 struct list_head *entry; 1015 struct list_head *entry;
1016 struct mtdids *id; 1016 struct mtdids *id;
1017 1017
1018 list_for_each(entry, &mtdids) { 1018 list_for_each(entry, &mtdids) {
1019 id = list_entry(entry, struct mtdids, link); 1019 id = list_entry(entry, struct mtdids, link);
1020 1020
1021 if ((id->type == type) && (id->num == num)) 1021 if ((id->type == type) && (id->num == num))
1022 return id; 1022 return id;
1023 } 1023 }
1024 1024
1025 return NULL; 1025 return NULL;
1026 } 1026 }
1027 1027
1028 /** 1028 /**
1029 * Search global mtdids list and find id of a requested mtd_id. 1029 * Search global mtdids list and find id of a requested mtd_id.
1030 * 1030 *
1031 * Note: first argument is not null terminated. 1031 * Note: first argument is not null terminated.
1032 * 1032 *
1033 * @param mtd_id string containing requested mtd_id 1033 * @param mtd_id string containing requested mtd_id
1034 * @param mtd_id_len length of supplied mtd_id 1034 * @param mtd_id_len length of supplied mtd_id
1035 * @return pointer to the id if it exists, NULL otherwise 1035 * @return pointer to the id if it exists, NULL otherwise
1036 */ 1036 */
1037 static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_len) 1037 static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_len)
1038 { 1038 {
1039 struct list_head *entry; 1039 struct list_head *entry;
1040 struct mtdids *id; 1040 struct mtdids *id;
1041 1041
1042 DEBUGF("--- id_find_by_mtd_id: '%.*s' (len = %d)\n", 1042 DEBUGF("--- id_find_by_mtd_id: '%.*s' (len = %d)\n",
1043 mtd_id_len, mtd_id, mtd_id_len); 1043 mtd_id_len, mtd_id, mtd_id_len);
1044 1044
1045 list_for_each(entry, &mtdids) { 1045 list_for_each(entry, &mtdids) {
1046 id = list_entry(entry, struct mtdids, link); 1046 id = list_entry(entry, struct mtdids, link);
1047 1047
1048 DEBUGF("entry: '%s' (len = %d)\n", 1048 DEBUGF("entry: '%s' (len = %d)\n",
1049 id->mtd_id, strlen(id->mtd_id)); 1049 id->mtd_id, strlen(id->mtd_id));
1050 1050
1051 if (mtd_id_len != strlen(id->mtd_id)) 1051 if (mtd_id_len != strlen(id->mtd_id))
1052 continue; 1052 continue;
1053 if (strncmp(id->mtd_id, mtd_id, mtd_id_len) == 0) 1053 if (strncmp(id->mtd_id, mtd_id, mtd_id_len) == 0)
1054 return id; 1054 return id;
1055 } 1055 }
1056 1056
1057 return NULL; 1057 return NULL;
1058 } 1058 }
1059 #endif /* #ifdef CONFIG_JFFS2_CMDLINE */ 1059 #endif /* #ifdef CONFIG_JFFS2_CMDLINE */
1060 1060
1061 /** 1061 /**
1062 * Parse device id string <dev-id> := 'nand'|'nor'<dev-num>, return device 1062 * Parse device id string <dev-id> := 'nand'|'nor'<dev-num>, return device
1063 * type and number. 1063 * type and number.
1064 * 1064 *
1065 * @param id string describing device id 1065 * @param id string describing device id
1066 * @param ret_id output pointer to next char after parse completes (output) 1066 * @param ret_id output pointer to next char after parse completes (output)
1067 * @param dev_type parsed device type (output) 1067 * @param dev_type parsed device type (output)
1068 * @param dev_num parsed device number (output) 1068 * @param dev_num parsed device number (output)
1069 * @return 0 on success, 1 otherwise 1069 * @return 0 on success, 1 otherwise
1070 */ 1070 */
1071 int id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num) 1071 int id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num)
1072 { 1072 {
1073 const char *p = id; 1073 const char *p = id;
1074 1074
1075 *dev_type = 0; 1075 *dev_type = 0;
1076 if (strncmp(p, "nand", 4) == 0) { 1076 if (strncmp(p, "nand", 4) == 0) {
1077 *dev_type = MTD_DEV_TYPE_NAND; 1077 *dev_type = MTD_DEV_TYPE_NAND;
1078 p += 4; 1078 p += 4;
1079 } else if (strncmp(p, "nor", 3) == 0) { 1079 } else if (strncmp(p, "nor", 3) == 0) {
1080 *dev_type = MTD_DEV_TYPE_NOR; 1080 *dev_type = MTD_DEV_TYPE_NOR;
1081 p += 3; 1081 p += 3;
1082 } else { 1082 } else {
1083 printf("incorrect device type in %s\n", id); 1083 printf("incorrect device type in %s\n", id);
1084 return 1; 1084 return 1;
1085 } 1085 }
1086 1086
1087 if (!isdigit(*p)) { 1087 if (!isdigit(*p)) {
1088 printf("incorrect device number in %s\n", id); 1088 printf("incorrect device number in %s\n", id);
1089 return 1; 1089 return 1;
1090 } 1090 }
1091 1091
1092 *dev_num = simple_strtoul(p, (char **)&p, 0); 1092 *dev_num = simple_strtoul(p, (char **)&p, 0);
1093 if (ret_id) 1093 if (ret_id)
1094 *ret_id = p; 1094 *ret_id = p;
1095 return 0; 1095 return 0;
1096 } 1096 }
1097 1097
1098 #ifdef CONFIG_JFFS2_CMDLINE 1098 #ifdef CONFIG_JFFS2_CMDLINE
1099 /** 1099 /**
1100 * Process all devices and generate corresponding mtdparts string describing 1100 * Process all devices and generate corresponding mtdparts string describing
1101 * all partitions on all devices. 1101 * all partitions on all devices.
1102 * 1102 *
1103 * @param buf output buffer holding generated mtdparts string (output) 1103 * @param buf output buffer holding generated mtdparts string (output)
1104 * @param buflen buffer size 1104 * @param buflen buffer size
1105 * @return 0 on success, 1 otherwise 1105 * @return 0 on success, 1 otherwise
1106 */ 1106 */
1107 static int generate_mtdparts(char *buf, u32 buflen) 1107 static int generate_mtdparts(char *buf, u32 buflen)
1108 { 1108 {
1109 struct list_head *pentry, *dentry; 1109 struct list_head *pentry, *dentry;
1110 struct mtd_device *dev; 1110 struct mtd_device *dev;
1111 struct part_info *part, *prev_part; 1111 struct part_info *part, *prev_part;
1112 char *p = buf; 1112 char *p = buf;
1113 char tmpbuf[32]; 1113 char tmpbuf[32];
1114 u32 size, offset, len, part_cnt; 1114 u32 size, offset, len, part_cnt;
1115 u32 maxlen = buflen - 1; 1115 u32 maxlen = buflen - 1;
1116 1116
1117 DEBUGF("--- generate_mtdparts ---\n"); 1117 DEBUGF("--- generate_mtdparts ---\n");
1118 1118
1119 if (list_empty(&devices)) { 1119 if (list_empty(&devices)) {
1120 buf[0] = '\0'; 1120 buf[0] = '\0';
1121 return 0; 1121 return 0;
1122 } 1122 }
1123 1123
1124 sprintf(p, "mtdparts="); 1124 sprintf(p, "mtdparts=");
1125 p += 9; 1125 p += 9;
1126 1126
1127 list_for_each(dentry, &devices) { 1127 list_for_each(dentry, &devices) {
1128 dev = list_entry(dentry, struct mtd_device, link); 1128 dev = list_entry(dentry, struct mtd_device, link);
1129 1129
1130 /* copy mtd_id */ 1130 /* copy mtd_id */
1131 len = strlen(dev->id->mtd_id) + 1; 1131 len = strlen(dev->id->mtd_id) + 1;
1132 if (len > maxlen) 1132 if (len > maxlen)
1133 goto cleanup; 1133 goto cleanup;
1134 memcpy(p, dev->id->mtd_id, len - 1); 1134 memcpy(p, dev->id->mtd_id, len - 1);
1135 p += len - 1; 1135 p += len - 1;
1136 *(p++) = ':'; 1136 *(p++) = ':';
1137 maxlen -= len; 1137 maxlen -= len;
1138 1138
1139 /* format partitions */ 1139 /* format partitions */
1140 prev_part = NULL; 1140 prev_part = NULL;
1141 part_cnt = 0; 1141 part_cnt = 0;
1142 list_for_each(pentry, &dev->parts) { 1142 list_for_each(pentry, &dev->parts) {
1143 part = list_entry(pentry, struct part_info, link); 1143 part = list_entry(pentry, struct part_info, link);
1144 size = part->size; 1144 size = part->size;
1145 offset = part->offset; 1145 offset = part->offset;
1146 part_cnt++; 1146 part_cnt++;
1147 1147
1148 /* partition size */ 1148 /* partition size */
1149 memsize_format(tmpbuf, size); 1149 memsize_format(tmpbuf, size);
1150 len = strlen(tmpbuf); 1150 len = strlen(tmpbuf);
1151 if (len > maxlen) 1151 if (len > maxlen)
1152 goto cleanup; 1152 goto cleanup;
1153 memcpy(p, tmpbuf, len); 1153 memcpy(p, tmpbuf, len);
1154 p += len; 1154 p += len;
1155 maxlen -= len; 1155 maxlen -= len;
1156 1156
1157 1157
1158 /* add offset only when there is a gap between 1158 /* add offset only when there is a gap between
1159 * partitions */ 1159 * partitions */
1160 if ((!prev_part && (offset != 0)) || 1160 if ((!prev_part && (offset != 0)) ||
1161 (prev_part && ((prev_part->offset + prev_part->size) != part->offset))) { 1161 (prev_part && ((prev_part->offset + prev_part->size) != part->offset))) {
1162 1162
1163 memsize_format(tmpbuf, offset); 1163 memsize_format(tmpbuf, offset);
1164 len = strlen(tmpbuf) + 1; 1164 len = strlen(tmpbuf) + 1;
1165 if (len > maxlen) 1165 if (len > maxlen)
1166 goto cleanup; 1166 goto cleanup;
1167 *(p++) = '@'; 1167 *(p++) = '@';
1168 memcpy(p, tmpbuf, len - 1); 1168 memcpy(p, tmpbuf, len - 1);
1169 p += len - 1; 1169 p += len - 1;
1170 maxlen -= len; 1170 maxlen -= len;
1171 } 1171 }
1172 1172
1173 /* copy name only if user supplied */ 1173 /* copy name only if user supplied */
1174 if(!part->auto_name) { 1174 if(!part->auto_name) {
1175 len = strlen(part->name) + 2; 1175 len = strlen(part->name) + 2;
1176 if (len > maxlen) 1176 if (len > maxlen)
1177 goto cleanup; 1177 goto cleanup;
1178 1178
1179 *(p++) = '('; 1179 *(p++) = '(';
1180 memcpy(p, part->name, len - 2); 1180 memcpy(p, part->name, len - 2);
1181 p += len - 2; 1181 p += len - 2;
1182 *(p++) = ')'; 1182 *(p++) = ')';
1183 maxlen -= len; 1183 maxlen -= len;
1184 } 1184 }
1185 1185
1186 /* ro mask flag */ 1186 /* ro mask flag */
1187 if (part->mask_flags && MTD_WRITEABLE_CMD) { 1187 if (part->mask_flags && MTD_WRITEABLE_CMD) {
1188 len = 2; 1188 len = 2;
1189 if (len > maxlen) 1189 if (len > maxlen)
1190 goto cleanup; 1190 goto cleanup;
1191 *(p++) = 'r'; 1191 *(p++) = 'r';
1192 *(p++) = 'o'; 1192 *(p++) = 'o';
1193 maxlen -= 2; 1193 maxlen -= 2;
1194 } 1194 }
1195 1195
1196 /* print ',' separator if there are other partitions 1196 /* print ',' separator if there are other partitions
1197 * following */ 1197 * following */
1198 if (dev->num_parts > part_cnt) { 1198 if (dev->num_parts > part_cnt) {
1199 if (1 > maxlen) 1199 if (1 > maxlen)
1200 goto cleanup; 1200 goto cleanup;
1201 *(p++) = ','; 1201 *(p++) = ',';
1202 maxlen--; 1202 maxlen--;
1203 } 1203 }
1204 prev_part = part; 1204 prev_part = part;
1205 } 1205 }
1206 /* print ';' separator if there are other devices following */ 1206 /* print ';' separator if there are other devices following */
1207 if (dentry->next != &devices) { 1207 if (dentry->next != &devices) {
1208 if (1 > maxlen) 1208 if (1 > maxlen)
1209 goto cleanup; 1209 goto cleanup;
1210 *(p++) = ';'; 1210 *(p++) = ';';
1211 maxlen--; 1211 maxlen--;
1212 } 1212 }
1213 } 1213 }
1214 1214
1215 /* we still have at least one char left, as we decremented maxlen at 1215 /* we still have at least one char left, as we decremented maxlen at
1216 * the begining */ 1216 * the begining */
1217 *p = '\0'; 1217 *p = '\0';
1218 1218
1219 return 0; 1219 return 0;
1220 1220
1221 cleanup: 1221 cleanup:
1222 last_parts[0] = '\0'; 1222 last_parts[0] = '\0';
1223 return 1; 1223 return 1;
1224 } 1224 }
1225 1225
1226 /** 1226 /**
1227 * Call generate_mtdparts to process all devices and generate corresponding 1227 * Call generate_mtdparts to process all devices and generate corresponding
1228 * mtdparts string, save it in mtdparts environment variable. 1228 * mtdparts string, save it in mtdparts environment variable.
1229 * 1229 *
1230 * @param buf output buffer holding generated mtdparts string (output) 1230 * @param buf output buffer holding generated mtdparts string (output)
1231 * @param buflen buffer size 1231 * @param buflen buffer size
1232 * @return 0 on success, 1 otherwise 1232 * @return 0 on success, 1 otherwise
1233 */ 1233 */
1234 static int generate_mtdparts_save(char *buf, u32 buflen) 1234 static int generate_mtdparts_save(char *buf, u32 buflen)
1235 { 1235 {
1236 int ret; 1236 int ret;
1237 1237
1238 ret = generate_mtdparts(buf, buflen); 1238 ret = generate_mtdparts(buf, buflen);
1239 1239
1240 if ((buf[0] != '\0') && (ret == 0)) 1240 if ((buf[0] != '\0') && (ret == 0))
1241 setenv("mtdparts", buf); 1241 setenv("mtdparts", buf);
1242 else 1242 else
1243 setenv("mtdparts", NULL); 1243 setenv("mtdparts", NULL);
1244 1244
1245 return ret; 1245 return ret;
1246 } 1246 }
1247 1247
1248 /** 1248 /**
1249 * Format and print out a partition list for each device from global device 1249 * Format and print out a partition list for each device from global device
1250 * list. 1250 * list.
1251 */ 1251 */
1252 static void list_partitions(void) 1252 static void list_partitions(void)
1253 { 1253 {
1254 struct list_head *dentry, *pentry; 1254 struct list_head *dentry, *pentry;
1255 struct part_info *part; 1255 struct part_info *part;
1256 struct mtd_device *dev; 1256 struct mtd_device *dev;
1257 int part_num; 1257 int part_num;
1258 1258
1259 DEBUGF("\n---list_partitions---\n"); 1259 DEBUGF("\n---list_partitions---\n");
1260 list_for_each(dentry, &devices) { 1260 list_for_each(dentry, &devices) {
1261 dev = list_entry(dentry, struct mtd_device, link); 1261 dev = list_entry(dentry, struct mtd_device, link);
1262 printf("\ndevice %s%d <%s>, # parts = %d\n", 1262 printf("\ndevice %s%d <%s>, # parts = %d\n",
1263 MTD_DEV_TYPE(dev->id->type), dev->id->num, 1263 MTD_DEV_TYPE(dev->id->type), dev->id->num,
1264 dev->id->mtd_id, dev->num_parts); 1264 dev->id->mtd_id, dev->num_parts);
1265 printf(" #: name\t\t\tsize\t\toffset\t\tmask_flags\n"); 1265 printf(" #: name\t\t\tsize\t\toffset\t\tmask_flags\n");
1266 1266
1267 /* list partitions for given device */ 1267 /* list partitions for given device */
1268 part_num = 0; 1268 part_num = 0;
1269 list_for_each(pentry, &dev->parts) { 1269 list_for_each(pentry, &dev->parts) {
1270 part = list_entry(pentry, struct part_info, link); 1270 part = list_entry(pentry, struct part_info, link);
1271 printf("%2d: %-20s0x%08x\t0x%08x\t%d\n", 1271 printf("%2d: %-20s0x%08x\t0x%08x\t%d\n",
1272 part_num, part->name, part->size, 1272 part_num, part->name, part->size,
1273 part->offset, part->mask_flags); 1273 part->offset, part->mask_flags);
1274 1274
1275 part_num++; 1275 part_num++;
1276 } 1276 }
1277 } 1277 }
1278 if (list_empty(&devices)) 1278 if (list_empty(&devices))
1279 printf("no partitions defined\n"); 1279 printf("no partitions defined\n");
1280 1280
1281 /* current_dev is not NULL only when we have non empty device list */ 1281 /* current_dev is not NULL only when we have non empty device list */
1282 if (current_dev) { 1282 if (current_dev) {
1283 part = jffs2_part_info(current_dev, current_partnum); 1283 part = jffs2_part_info(current_dev, current_partnum);
1284 if (part) { 1284 if (part) {
1285 printf("\nactive partition: %s%d,%d - (%s) 0x%08lx @ 0x%08lx\n", 1285 printf("\nactive partition: %s%d,%d - (%s) 0x%08lx @ 0x%08lx\n",
1286 MTD_DEV_TYPE(current_dev->id->type), 1286 MTD_DEV_TYPE(current_dev->id->type),
1287 current_dev->id->num, current_partnum, 1287 current_dev->id->num, current_partnum,
1288 part->name, part->size, part->offset); 1288 part->name, part->size, part->offset);
1289 } else { 1289 } else {
1290 printf("could not get current partition info\n\n"); 1290 printf("could not get current partition info\n\n");
1291 } 1291 }
1292 } 1292 }
1293 1293
1294 printf("\ndefaults:\n"); 1294 printf("\ndefaults:\n");
1295 printf("mtdids : %s\n", mtdids_default); 1295 printf("mtdids : %s\n", mtdids_default);
1296 printf("mtdparts: %s\n", mtdparts_default); 1296 printf("mtdparts: %s\n", mtdparts_default);
1297 } 1297 }
1298 1298
1299 /** 1299 /**
1300 * Given partition identifier in form of <dev_type><dev_num>,<part_num> find 1300 * Given partition identifier in form of <dev_type><dev_num>,<part_num> find
1301 * corresponding device and verify partition number. 1301 * corresponding device and verify partition number.
1302 * 1302 *
1303 * @param id string describing device and partition 1303 * @param id string describing device and partition or partition name
1304 * @param dev pointer to the requested device (output) 1304 * @param dev pointer to the requested device (output)
1305 * @param part_num verified partition number (output) 1305 * @param part_num verified partition number (output)
1306 * @param part pointer to requested partition (output) 1306 * @param part pointer to requested partition (output)
1307 * @return 0 on success, 1 otherwise 1307 * @return 0 on success, 1 otherwise
1308 */ 1308 */
1309 int find_dev_and_part(const char *id, struct mtd_device **dev, 1309 int find_dev_and_part(const char *id, struct mtd_device **dev,
1310 u8 *part_num, struct part_info **part) 1310 u8 *part_num, struct part_info **part)
1311 { 1311 {
1312 struct list_head *dentry, *pentry;
1312 u8 type, dnum, pnum; 1313 u8 type, dnum, pnum;
1313 const char *p; 1314 const char *p;
1314 1315
1315 DEBUGF("--- find_dev_and_part ---\nid = %s\n", id); 1316 DEBUGF("--- find_dev_and_part ---\nid = %s\n", id);
1317
1318 list_for_each(dentry, &devices) {
1319 *part_num = 0;
1320 *dev = list_entry(dentry, struct mtd_device, link);
1321 list_for_each(pentry, &(*dev)->parts) {
1322 *part = list_entry(pentry, struct part_info, link);
1323 if (strcmp((*part)->name, id) == 0)
1324 return 0;
1325 (*part_num)++;
1326 }
1327 }
1316 1328
1317 p = id; 1329 p = id;
1318 *dev = NULL; 1330 *dev = NULL;
1319 *part = NULL; 1331 *part = NULL;
1320 *part_num = 0; 1332 *part_num = 0;
1321 1333
1322 if (id_parse(p, &p, &type, &dnum) != 0) 1334 if (id_parse(p, &p, &type, &dnum) != 0)
1323 return 1; 1335 return 1;
1324 1336
1325 if ((*p++ != ',') || (*p == '\0')) { 1337 if ((*p++ != ',') || (*p == '\0')) {
1326 printf("no partition number specified\n"); 1338 printf("no partition number specified\n");
1327 return 1; 1339 return 1;
1328 } 1340 }
1329 pnum = simple_strtoul(p, (char **)&p, 0); 1341 pnum = simple_strtoul(p, (char **)&p, 0);
1330 if (*p != '\0') { 1342 if (*p != '\0') {
1331 printf("unexpected trailing character '%c'\n", *p); 1343 printf("unexpected trailing character '%c'\n", *p);
1332 return 1; 1344 return 1;
1333 } 1345 }
1334 1346
1335 if ((*dev = device_find(type, dnum)) == NULL) { 1347 if ((*dev = device_find(type, dnum)) == NULL) {
1336 printf("no such device %s%d\n", MTD_DEV_TYPE(type), dnum); 1348 printf("no such device %s%d\n", MTD_DEV_TYPE(type), dnum);
1337 return 1; 1349 return 1;
1338 } 1350 }
1339 1351
1340 if ((*part = jffs2_part_info(*dev, pnum)) == NULL) { 1352 if ((*part = jffs2_part_info(*dev, pnum)) == NULL) {
1341 printf("no such partition\n"); 1353 printf("no such partition\n");
1342 *dev = NULL; 1354 *dev = NULL;
1343 return 1; 1355 return 1;
1344 } 1356 }
1345 1357
1346 *part_num = pnum; 1358 *part_num = pnum;
1347 1359
1348 return 0; 1360 return 0;
1349 } 1361 }
1350 1362
1351 /** 1363 /**
1352 * Find and delete partition. For partition id format see find_dev_and_part(). 1364 * Find and delete partition. For partition id format see find_dev_and_part().
1353 * 1365 *
1354 * @param id string describing device and partition 1366 * @param id string describing device and partition
1355 * @return 0 on success, 1 otherwise 1367 * @return 0 on success, 1 otherwise
1356 */ 1368 */
1357 static int delete_partition(const char *id) 1369 static int delete_partition(const char *id)
1358 { 1370 {
1359 u8 pnum; 1371 u8 pnum;
1360 struct mtd_device *dev; 1372 struct mtd_device *dev;
1361 struct part_info *part; 1373 struct part_info *part;
1362 1374
1363 if (find_dev_and_part(id, &dev, &pnum, &part) == 0) { 1375 if (find_dev_and_part(id, &dev, &pnum, &part) == 0) {
1364 1376
1365 DEBUGF("delete_partition: device = %s%d, partition %d = (%s) 0x%08lx@0x%08lx\n", 1377 DEBUGF("delete_partition: device = %s%d, partition %d = (%s) 0x%08lx@0x%08lx\n",
1366 MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum, 1378 MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum,
1367 part->name, part->size, part->offset); 1379 part->name, part->size, part->offset);
1368 1380
1369 if (part_del(dev, part) != 0) 1381 if (part_del(dev, part) != 0)
1370 return 1; 1382 return 1;
1371 1383
1372 if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) { 1384 if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) {
1373 printf("generated mtdparts too long, reseting to null\n"); 1385 printf("generated mtdparts too long, reseting to null\n");
1374 return 1; 1386 return 1;
1375 } 1387 }
1376 return 0; 1388 return 0;
1377 } 1389 }
1378 1390
1379 printf("partition %s not found\n", id); 1391 printf("partition %s not found\n", id);
1380 return 1; 1392 return 1;
1381 } 1393 }
1382 1394
1383 /** 1395 /**
1384 * Accept character string describing mtd partitions and call device_parse() 1396 * Accept character string describing mtd partitions and call device_parse()
1385 * for each entry. Add created devices to the global devices list. 1397 * for each entry. Add created devices to the global devices list.
1386 * 1398 *
1387 * @param mtdparts string specifing mtd partitions 1399 * @param mtdparts string specifing mtd partitions
1388 * @return 0 on success, 1 otherwise 1400 * @return 0 on success, 1 otherwise
1389 */ 1401 */
1390 static int parse_mtdparts(const char *const mtdparts) 1402 static int parse_mtdparts(const char *const mtdparts)
1391 { 1403 {
1392 const char *p = mtdparts; 1404 const char *p = mtdparts;
1393 struct mtd_device *dev; 1405 struct mtd_device *dev;
1394 int err = 1; 1406 int err = 1;
1395 1407
1396 DEBUGF("\n---parse_mtdparts---\nmtdparts = %s\n\n", p); 1408 DEBUGF("\n---parse_mtdparts---\nmtdparts = %s\n\n", p);
1397 1409
1398 /* delete all devices and partitions */ 1410 /* delete all devices and partitions */
1399 if (devices_init() != 0) { 1411 if (devices_init() != 0) {
1400 printf("could not initialise device list\n"); 1412 printf("could not initialise device list\n");
1401 return err; 1413 return err;
1402 } 1414 }
1403 1415
1404 /* re-read 'mtdparts' variable, devices_init may be updating env */ 1416 /* re-read 'mtdparts' variable, devices_init may be updating env */
1405 p = getenv("mtdparts"); 1417 p = getenv("mtdparts");
1406 1418
1407 if (strncmp(p, "mtdparts=", 9) != 0) { 1419 if (strncmp(p, "mtdparts=", 9) != 0) {
1408 printf("mtdparts variable doesn't start with 'mtdparts='\n"); 1420 printf("mtdparts variable doesn't start with 'mtdparts='\n");
1409 return err; 1421 return err;
1410 } 1422 }
1411 p += 9; 1423 p += 9;
1412 1424
1413 while (p && (*p != '\0')) { 1425 while (p && (*p != '\0')) {
1414 err = 1; 1426 err = 1;
1415 if ((device_parse(p, &p, &dev) != 0) || (!dev)) 1427 if ((device_parse(p, &p, &dev) != 0) || (!dev))
1416 break; 1428 break;
1417 1429
1418 DEBUGF("+ device: %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type), 1430 DEBUGF("+ device: %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type),
1419 dev->id->num, dev->id->mtd_id); 1431 dev->id->num, dev->id->mtd_id);
1420 1432
1421 /* check if parsed device is already on the list */ 1433 /* check if parsed device is already on the list */
1422 if (device_find(dev->id->type, dev->id->num) != NULL) { 1434 if (device_find(dev->id->type, dev->id->num) != NULL) {
1423 printf("device %s%d redefined, please correct mtdparts variable\n", 1435 printf("device %s%d redefined, please correct mtdparts variable\n",
1424 MTD_DEV_TYPE(dev->id->type), dev->id->num); 1436 MTD_DEV_TYPE(dev->id->type), dev->id->num);
1425 break; 1437 break;
1426 } 1438 }
1427 1439
1428 list_add_tail(&dev->link, &devices); 1440 list_add_tail(&dev->link, &devices);
1429 err = 0; 1441 err = 0;
1430 } 1442 }
1431 if (err == 1) { 1443 if (err == 1) {
1432 device_delall(&devices); 1444 device_delall(&devices);
1433 return 1; 1445 return 1;
1434 } 1446 }
1435 1447
1436 return 0; 1448 return 0;
1437 } 1449 }
1438 1450
1439 /** 1451 /**
1440 * Parse provided string describing mtdids mapping (see file header for mtdids 1452 * Parse provided string describing mtdids mapping (see file header for mtdids
1441 * variable format). Allocate memory for each entry and add all found entries 1453 * variable format). Allocate memory for each entry and add all found entries
1442 * to the global mtdids list. 1454 * to the global mtdids list.
1443 * 1455 *
1444 * @param ids mapping string 1456 * @param ids mapping string
1445 * @return 0 on success, 1 otherwise 1457 * @return 0 on success, 1 otherwise
1446 */ 1458 */
1447 static int parse_mtdids(const char *const ids) 1459 static int parse_mtdids(const char *const ids)
1448 { 1460 {
1449 const char *p = ids; 1461 const char *p = ids;
1450 const char *mtd_id; 1462 const char *mtd_id;
1451 int mtd_id_len; 1463 int mtd_id_len;
1452 struct mtdids *id; 1464 struct mtdids *id;
1453 struct list_head *entry, *n; 1465 struct list_head *entry, *n;
1454 struct mtdids *id_tmp; 1466 struct mtdids *id_tmp;
1455 u8 type, num; 1467 u8 type, num;
1456 u32 size; 1468 u32 size;
1457 int ret = 1; 1469 int ret = 1;
1458 1470
1459 DEBUGF("\n---parse_mtdids---\nmtdids = %s\n\n", ids); 1471 DEBUGF("\n---parse_mtdids---\nmtdids = %s\n\n", ids);
1460 1472
1461 /* clean global mtdids list */ 1473 /* clean global mtdids list */
1462 list_for_each_safe(entry, n, &mtdids) { 1474 list_for_each_safe(entry, n, &mtdids) {
1463 id_tmp = list_entry(entry, struct mtdids, link); 1475 id_tmp = list_entry(entry, struct mtdids, link);
1464 DEBUGF("mtdids del: %d %d\n", id_tmp->type, id_tmp->num); 1476 DEBUGF("mtdids del: %d %d\n", id_tmp->type, id_tmp->num);
1465 list_del(entry); 1477 list_del(entry);
1466 free(id_tmp); 1478 free(id_tmp);
1467 } 1479 }
1468 last_ids[0] = '\0'; 1480 last_ids[0] = '\0';
1469 INIT_LIST_HEAD(&mtdids); 1481 INIT_LIST_HEAD(&mtdids);
1470 1482
1471 while(p && (*p != '\0')) { 1483 while(p && (*p != '\0')) {
1472 1484
1473 ret = 1; 1485 ret = 1;
1474 /* parse 'nor'|'nand'<dev-num> */ 1486 /* parse 'nor'|'nand'<dev-num> */
1475 if (id_parse(p, &p, &type, &num) != 0) 1487 if (id_parse(p, &p, &type, &num) != 0)
1476 break; 1488 break;
1477 1489
1478 if (*p != '=') { 1490 if (*p != '=') {
1479 printf("mtdids: incorrect <dev-num>\n"); 1491 printf("mtdids: incorrect <dev-num>\n");
1480 break; 1492 break;
1481 } 1493 }
1482 p++; 1494 p++;
1483 1495
1484 /* check if requested device exists */ 1496 /* check if requested device exists */
1485 if (device_validate(type, num, &size) != 0) 1497 if (device_validate(type, num, &size) != 0)
1486 return 1; 1498 return 1;
1487 1499
1488 /* locate <mtd-id> */ 1500 /* locate <mtd-id> */
1489 mtd_id = p; 1501 mtd_id = p;
1490 if ((p = strchr(mtd_id, ',')) != NULL) { 1502 if ((p = strchr(mtd_id, ',')) != NULL) {
1491 mtd_id_len = p - mtd_id + 1; 1503 mtd_id_len = p - mtd_id + 1;
1492 p++; 1504 p++;
1493 } else { 1505 } else {
1494 mtd_id_len = strlen(mtd_id) + 1; 1506 mtd_id_len = strlen(mtd_id) + 1;
1495 } 1507 }
1496 if (mtd_id_len == 0) { 1508 if (mtd_id_len == 0) {
1497 printf("mtdids: no <mtd-id> identifier\n"); 1509 printf("mtdids: no <mtd-id> identifier\n");
1498 break; 1510 break;
1499 } 1511 }
1500 1512
1501 /* check if this id is already on the list */ 1513 /* check if this id is already on the list */
1502 int double_entry = 0; 1514 int double_entry = 0;
1503 list_for_each(entry, &mtdids) { 1515 list_for_each(entry, &mtdids) {
1504 id_tmp = list_entry(entry, struct mtdids, link); 1516 id_tmp = list_entry(entry, struct mtdids, link);
1505 if ((id_tmp->type == type) && (id_tmp->num == num)) { 1517 if ((id_tmp->type == type) && (id_tmp->num == num)) {
1506 double_entry = 1; 1518 double_entry = 1;
1507 break; 1519 break;
1508 } 1520 }
1509 } 1521 }
1510 if (double_entry) { 1522 if (double_entry) {
1511 printf("device id %s%d redefined, please correct mtdids variable\n", 1523 printf("device id %s%d redefined, please correct mtdids variable\n",
1512 MTD_DEV_TYPE(type), num); 1524 MTD_DEV_TYPE(type), num);
1513 break; 1525 break;
1514 } 1526 }
1515 1527
1516 /* allocate mtdids structure */ 1528 /* allocate mtdids structure */
1517 if (!(id = (struct mtdids *)malloc(sizeof(struct mtdids) + mtd_id_len))) { 1529 if (!(id = (struct mtdids *)malloc(sizeof(struct mtdids) + mtd_id_len))) {
1518 printf("out of memory\n"); 1530 printf("out of memory\n");
1519 break; 1531 break;
1520 } 1532 }
1521 memset(id, 0, sizeof(struct mtdids) + mtd_id_len); 1533 memset(id, 0, sizeof(struct mtdids) + mtd_id_len);
1522 id->num = num; 1534 id->num = num;
1523 id->type = type; 1535 id->type = type;
1524 id->size = size; 1536 id->size = size;
1525 id->mtd_id = (char *)(id + 1); 1537 id->mtd_id = (char *)(id + 1);
1526 strncpy(id->mtd_id, mtd_id, mtd_id_len - 1); 1538 strncpy(id->mtd_id, mtd_id, mtd_id_len - 1);
1527 id->mtd_id[mtd_id_len - 1] = '\0'; 1539 id->mtd_id[mtd_id_len - 1] = '\0';
1528 INIT_LIST_HEAD(&id->link); 1540 INIT_LIST_HEAD(&id->link);
1529 1541
1530 DEBUGF("+ id %s%d\t%16d bytes\t%s\n", 1542 DEBUGF("+ id %s%d\t%16d bytes\t%s\n",
1531 MTD_DEV_TYPE(id->type), id->num, 1543 MTD_DEV_TYPE(id->type), id->num,
1532 id->size, id->mtd_id); 1544 id->size, id->mtd_id);
1533 1545
1534 list_add_tail(&id->link, &mtdids); 1546 list_add_tail(&id->link, &mtdids);
1535 ret = 0; 1547 ret = 0;
1536 } 1548 }
1537 if (ret == 1) { 1549 if (ret == 1) {
1538 /* clean mtdids list and free allocated memory */ 1550 /* clean mtdids list and free allocated memory */
1539 list_for_each_safe(entry, n, &mtdids) { 1551 list_for_each_safe(entry, n, &mtdids) {
1540 id_tmp = list_entry(entry, struct mtdids, link); 1552 id_tmp = list_entry(entry, struct mtdids, link);
1541 list_del(entry); 1553 list_del(entry);
1542 free(id_tmp); 1554 free(id_tmp);
1543 } 1555 }
1544 return 1; 1556 return 1;
1545 } 1557 }
1546 1558
1547 return 0; 1559 return 0;
1548 } 1560 }
1549 1561
1550 /** 1562 /**
1551 * Parse and initialize global mtdids mapping and create global 1563 * Parse and initialize global mtdids mapping and create global
1552 * device/partition list. 1564 * device/partition list.
1553 * 1565 *
1554 * @return 0 on success, 1 otherwise 1566 * @return 0 on success, 1 otherwise
1555 */ 1567 */
1556 int mtdparts_init(void) 1568 int mtdparts_init(void)
1557 { 1569 {
1558 static int initialized = 0; 1570 static int initialized = 0;
1559 const char *ids, *parts; 1571 const char *ids, *parts;
1560 const char *current_partition; 1572 const char *current_partition;
1561 int ids_changed; 1573 int ids_changed;
1562 char tmp_ep[PARTITION_MAXLEN]; 1574 char tmp_ep[PARTITION_MAXLEN];
1563 1575
1564 DEBUGF("\n---mtdparts_init---\n"); 1576 DEBUGF("\n---mtdparts_init---\n");
1565 if (!initialized) { 1577 if (!initialized) {
1566 INIT_LIST_HEAD(&mtdids); 1578 INIT_LIST_HEAD(&mtdids);
1567 INIT_LIST_HEAD(&devices); 1579 INIT_LIST_HEAD(&devices);
1568 memset(last_ids, 0, MTDIDS_MAXLEN); 1580 memset(last_ids, 0, MTDIDS_MAXLEN);
1569 memset(last_parts, 0, MTDPARTS_MAXLEN); 1581 memset(last_parts, 0, MTDPARTS_MAXLEN);
1570 memset(last_partition, 0, PARTITION_MAXLEN); 1582 memset(last_partition, 0, PARTITION_MAXLEN);
1571 initialized = 1; 1583 initialized = 1;
1572 } 1584 }
1573 1585
1574 /* get variables */ 1586 /* get variables */
1575 ids = getenv("mtdids"); 1587 ids = getenv("mtdids");
1576 parts = getenv("mtdparts"); 1588 parts = getenv("mtdparts");
1577 current_partition = getenv("partition"); 1589 current_partition = getenv("partition");
1578 1590
1579 /* save it for later parsing, cannot rely on current partition pointer 1591 /* save it for later parsing, cannot rely on current partition pointer
1580 * as 'partition' variable may be updated during init */ 1592 * as 'partition' variable may be updated during init */
1581 tmp_ep[0] = '\0'; 1593 tmp_ep[0] = '\0';
1582 if (current_partition) 1594 if (current_partition)
1583 strncpy(tmp_ep, current_partition, PARTITION_MAXLEN); 1595 strncpy(tmp_ep, current_partition, PARTITION_MAXLEN);
1584 1596
1585 DEBUGF("last_ids : %s\n", last_ids); 1597 DEBUGF("last_ids : %s\n", last_ids);
1586 DEBUGF("env_ids : %s\n", ids); 1598 DEBUGF("env_ids : %s\n", ids);
1587 DEBUGF("last_parts: %s\n", last_parts); 1599 DEBUGF("last_parts: %s\n", last_parts);
1588 DEBUGF("env_parts : %s\n\n", parts); 1600 DEBUGF("env_parts : %s\n\n", parts);
1589 1601
1590 DEBUGF("last_partition : %s\n", last_partition); 1602 DEBUGF("last_partition : %s\n", last_partition);
1591 DEBUGF("env_partition : %s\n", current_partition); 1603 DEBUGF("env_partition : %s\n", current_partition);
1592 1604
1593 /* if mtdids varible is empty try to use defaults */ 1605 /* if mtdids varible is empty try to use defaults */
1594 if (!ids) { 1606 if (!ids) {
1595 if (mtdids_default) { 1607 if (mtdids_default) {
1596 DEBUGF("mtdids variable not defined, using default\n"); 1608 DEBUGF("mtdids variable not defined, using default\n");
1597 ids = mtdids_default; 1609 ids = mtdids_default;
1598 setenv("mtdids", (char *)ids); 1610 setenv("mtdids", (char *)ids);
1599 } else { 1611 } else {
1600 printf("mtdids not defined, no default present\n"); 1612 printf("mtdids not defined, no default present\n");
1601 return 1; 1613 return 1;
1602 } 1614 }
1603 } 1615 }
1604 if (strlen(ids) > MTDIDS_MAXLEN - 1) { 1616 if (strlen(ids) > MTDIDS_MAXLEN - 1) {
1605 printf("mtdids too long (> %d)\n", MTDIDS_MAXLEN); 1617 printf("mtdids too long (> %d)\n", MTDIDS_MAXLEN);
1606 return 1; 1618 return 1;
1607 } 1619 }
1608 1620
1609 /* do no try to use defaults when mtdparts variable is not defined, 1621 /* do no try to use defaults when mtdparts variable is not defined,
1610 * just check the length */ 1622 * just check the length */
1611 if (!parts) 1623 if (!parts)
1612 printf("mtdparts variable not set, see 'help mtdparts'\n"); 1624 printf("mtdparts variable not set, see 'help mtdparts'\n");
1613 1625
1614 if (parts && (strlen(parts) > MTDPARTS_MAXLEN - 1)) { 1626 if (parts && (strlen(parts) > MTDPARTS_MAXLEN - 1)) {
1615 printf("mtdparts too long (> %d)\n", MTDPARTS_MAXLEN); 1627 printf("mtdparts too long (> %d)\n", MTDPARTS_MAXLEN);
1616 return 1; 1628 return 1;
1617 } 1629 }
1618 1630
1619 /* check if we have already parsed those mtdids */ 1631 /* check if we have already parsed those mtdids */
1620 if ((last_ids[0] != '\0') && (strcmp(last_ids, ids) == 0)) { 1632 if ((last_ids[0] != '\0') && (strcmp(last_ids, ids) == 0)) {
1621 ids_changed = 0; 1633 ids_changed = 0;
1622 } else { 1634 } else {
1623 ids_changed = 1; 1635 ids_changed = 1;
1624 1636
1625 if (parse_mtdids(ids) != 0) { 1637 if (parse_mtdids(ids) != 0) {
1626 devices_init(); 1638 devices_init();
1627 return 1; 1639 return 1;
1628 } 1640 }
1629 1641
1630 /* ok it's good, save new ids */ 1642 /* ok it's good, save new ids */
1631 strncpy(last_ids, ids, MTDIDS_MAXLEN); 1643 strncpy(last_ids, ids, MTDIDS_MAXLEN);
1632 } 1644 }
1633 1645
1634 /* parse partitions if either mtdparts or mtdids were updated */ 1646 /* parse partitions if either mtdparts or mtdids were updated */
1635 if (parts && ((last_parts[0] == '\0') || ((strcmp(last_parts, parts) != 0)) || ids_changed)) { 1647 if (parts && ((last_parts[0] == '\0') || ((strcmp(last_parts, parts) != 0)) || ids_changed)) {
1636 if (parse_mtdparts(parts) != 0) 1648 if (parse_mtdparts(parts) != 0)
1637 return 1; 1649 return 1;
1638 1650
1639 if (list_empty(&devices)) { 1651 if (list_empty(&devices)) {
1640 printf("mtdparts_init: no valid partitions\n"); 1652 printf("mtdparts_init: no valid partitions\n");
1641 return 1; 1653 return 1;
1642 } 1654 }
1643 1655
1644 /* ok it's good, save new parts */ 1656 /* ok it's good, save new parts */
1645 strncpy(last_parts, parts, MTDPARTS_MAXLEN); 1657 strncpy(last_parts, parts, MTDPARTS_MAXLEN);
1646 1658
1647 /* reset first partition from first dev from the list as current */ 1659 /* reset first partition from first dev from the list as current */
1648 current_dev = list_entry(devices.next, struct mtd_device, link); 1660 current_dev = list_entry(devices.next, struct mtd_device, link);
1649 current_partnum = 0; 1661 current_partnum = 0;
1650 current_save(); 1662 current_save();
1651 1663
1652 DEBUGF("mtdparts_init: current_dev = %s%d, current_partnum = %d\n", 1664 DEBUGF("mtdparts_init: current_dev = %s%d, current_partnum = %d\n",
1653 MTD_DEV_TYPE(current_dev->id->type), 1665 MTD_DEV_TYPE(current_dev->id->type),
1654 current_dev->id->num, current_partnum); 1666 current_dev->id->num, current_partnum);
1655 } 1667 }
1656 1668
1657 /* mtdparts variable was reset to NULL, delete all devices/partitions */ 1669 /* mtdparts variable was reset to NULL, delete all devices/partitions */
1658 if (!parts && (last_parts[0] != '\0')) 1670 if (!parts && (last_parts[0] != '\0'))
1659 return devices_init(); 1671 return devices_init();
1660 1672
1661 /* do not process current partition if mtdparts variable is null */ 1673 /* do not process current partition if mtdparts variable is null */
1662 if (!parts) 1674 if (!parts)
1663 return 0; 1675 return 0;
1664 1676
1665 /* is current partition set in environment? if so, use it */ 1677 /* is current partition set in environment? if so, use it */
1666 if ((tmp_ep[0] != '\0') && (strcmp(tmp_ep, last_partition) != 0)) { 1678 if ((tmp_ep[0] != '\0') && (strcmp(tmp_ep, last_partition) != 0)) {
1667 struct part_info *p; 1679 struct part_info *p;
1668 struct mtd_device *cdev; 1680 struct mtd_device *cdev;
1669 u8 pnum; 1681 u8 pnum;
1670 1682
1671 DEBUGF("--- getting current partition: %s\n", tmp_ep); 1683 DEBUGF("--- getting current partition: %s\n", tmp_ep);
1672 1684
1673 if (find_dev_and_part(tmp_ep, &cdev, &pnum, &p) == 0) { 1685 if (find_dev_and_part(tmp_ep, &cdev, &pnum, &p) == 0) {
1674 current_dev = cdev; 1686 current_dev = cdev;
1675 current_partnum = pnum; 1687 current_partnum = pnum;
1676 current_save(); 1688 current_save();
1677 } 1689 }
1678 } else if (getenv("partition") == NULL) { 1690 } else if (getenv("partition") == NULL) {
1679 DEBUGF("no partition variable set, setting...\n"); 1691 DEBUGF("no partition variable set, setting...\n");
1680 current_save(); 1692 current_save();
1681 } 1693 }
1682 1694
1683 return 0; 1695 return 0;
1684 } 1696 }
1685 #else /* #ifdef CONFIG_JFFS2_CMDLINE */ 1697 #else /* #ifdef CONFIG_JFFS2_CMDLINE */
1686 /* 1698 /*
1687 * 'Static' version of command line mtdparts_init() routine. Single partition on 1699 * 'Static' version of command line mtdparts_init() routine. Single partition on
1688 * a single device configuration. 1700 * a single device configuration.
1689 */ 1701 */
1690 1702
1691 /** 1703 /**
1692 * Parse and initialize global mtdids mapping and create global 1704 * Parse and initialize global mtdids mapping and create global
1693 * device/partition list. 1705 * device/partition list.
1694 * 1706 *
1695 * @return 0 on success, 1 otherwise 1707 * @return 0 on success, 1 otherwise
1696 */ 1708 */
1697 int mtdparts_init(void) 1709 int mtdparts_init(void)
1698 { 1710 {
1699 static int initialized = 0; 1711 static int initialized = 0;
1700 u32 size; 1712 u32 size;
1701 char *dev_name; 1713 char *dev_name;
1702 1714
1703 DEBUGF("\n---mtdparts_init---\n"); 1715 DEBUGF("\n---mtdparts_init---\n");
1704 if (!initialized) { 1716 if (!initialized) {
1705 struct mtdids *id; 1717 struct mtdids *id;
1706 struct part_info *part; 1718 struct part_info *part;
1707 1719
1708 initialized = 1; 1720 initialized = 1;
1709 current_dev = (struct mtd_device *) 1721 current_dev = (struct mtd_device *)
1710 malloc(sizeof(struct mtd_device) + 1722 malloc(sizeof(struct mtd_device) +
1711 sizeof(struct part_info) + 1723 sizeof(struct part_info) +
1712 sizeof(struct mtdids)); 1724 sizeof(struct mtdids));
1713 if (!current_dev) { 1725 if (!current_dev) {
1714 printf("out of memory\n"); 1726 printf("out of memory\n");
1715 return 1; 1727 return 1;
1716 } 1728 }
1717 memset(current_dev, 0, sizeof(struct mtd_device) + 1729 memset(current_dev, 0, sizeof(struct mtd_device) +
1718 sizeof(struct part_info) + sizeof(struct mtdids)); 1730 sizeof(struct part_info) + sizeof(struct mtdids));
1719 1731
1720 id = (struct mtdids *)(current_dev + 1); 1732 id = (struct mtdids *)(current_dev + 1);
1721 part = (struct part_info *)(id + 1); 1733 part = (struct part_info *)(id + 1);
1722 1734
1723 /* id */ 1735 /* id */
1724 id->mtd_id = "single part"; 1736 id->mtd_id = "single part";
1725 1737
1726 #if defined(CONFIG_JFFS2_DEV) 1738 #if defined(CONFIG_JFFS2_DEV)
1727 dev_name = CONFIG_JFFS2_DEV; 1739 dev_name = CONFIG_JFFS2_DEV;
1728 #else 1740 #else
1729 dev_name = "nor0"; 1741 dev_name = "nor0";
1730 #endif 1742 #endif
1731 1743
1732 if ((id_parse(dev_name, NULL, &id->type, &id->num) != 0) || 1744 if ((id_parse(dev_name, NULL, &id->type, &id->num) != 0) ||
1733 (device_validate(id->type, id->num, &size) != 0)) { 1745 (device_validate(id->type, id->num, &size) != 0)) {
1734 printf("incorrect device: %s%d\n", MTD_DEV_TYPE(id->type), id->num); 1746 printf("incorrect device: %s%d\n", MTD_DEV_TYPE(id->type), id->num);
1735 free(current_dev); 1747 free(current_dev);
1736 return 1; 1748 return 1;
1737 } 1749 }
1738 id->size = size; 1750 id->size = size;
1739 INIT_LIST_HEAD(&id->link); 1751 INIT_LIST_HEAD(&id->link);
1740 1752
1741 DEBUGF("dev id: type = %d, num = %d, size = 0x%08lx, mtd_id = %s\n", 1753 DEBUGF("dev id: type = %d, num = %d, size = 0x%08lx, mtd_id = %s\n",
1742 id->type, id->num, id->size, id->mtd_id); 1754 id->type, id->num, id->size, id->mtd_id);
1743 1755
1744 /* partition */ 1756 /* partition */
1745 part->name = "static"; 1757 part->name = "static";
1746 part->auto_name = 0; 1758 part->auto_name = 0;
1747 1759
1748 #if defined(CONFIG_JFFS2_PART_SIZE) 1760 #if defined(CONFIG_JFFS2_PART_SIZE)
1749 part->size = CONFIG_JFFS2_PART_SIZE; 1761 part->size = CONFIG_JFFS2_PART_SIZE;
1750 #else 1762 #else
1751 part->size = SIZE_REMAINING; 1763 part->size = SIZE_REMAINING;
1752 #endif 1764 #endif
1753 1765
1754 #if defined(CONFIG_JFFS2_PART_OFFSET) 1766 #if defined(CONFIG_JFFS2_PART_OFFSET)
1755 part->offset = CONFIG_JFFS2_PART_OFFSET; 1767 part->offset = CONFIG_JFFS2_PART_OFFSET;
1756 #else 1768 #else
1757 part->offset = 0x00000000; 1769 part->offset = 0x00000000;
1758 #endif 1770 #endif
1759 1771
1760 part->dev = current_dev; 1772 part->dev = current_dev;
1761 INIT_LIST_HEAD(&part->link); 1773 INIT_LIST_HEAD(&part->link);
1762 1774
1763 /* recalculate size if needed */ 1775 /* recalculate size if needed */
1764 if (part->size == SIZE_REMAINING) 1776 if (part->size == SIZE_REMAINING)
1765 part->size = id->size - part->offset; 1777 part->size = id->size - part->offset;
1766 1778
1767 DEBUGF("part : name = %s, size = 0x%08lx, offset = 0x%08lx\n", 1779 DEBUGF("part : name = %s, size = 0x%08lx, offset = 0x%08lx\n",
1768 part->name, part->size, part->offset); 1780 part->name, part->size, part->offset);
1769 1781
1770 /* device */ 1782 /* device */
1771 current_dev->id = id; 1783 current_dev->id = id;
1772 INIT_LIST_HEAD(&current_dev->link); 1784 INIT_LIST_HEAD(&current_dev->link);
1773 current_dev->num_parts = 1; 1785 current_dev->num_parts = 1;
1774 INIT_LIST_HEAD(&current_dev->parts); 1786 INIT_LIST_HEAD(&current_dev->parts);
1775 list_add(&part->link, &current_dev->parts); 1787 list_add(&part->link, &current_dev->parts);
1776 } 1788 }
1777 1789
1778 return 0; 1790 return 0;
1779 } 1791 }
1780 #endif /* #ifdef CONFIG_JFFS2_CMDLINE */ 1792 #endif /* #ifdef CONFIG_JFFS2_CMDLINE */
1781 1793
1782 /** 1794 /**
1783 * Return pointer to the partition of a requested number from a requested 1795 * Return pointer to the partition of a requested number from a requested
1784 * device. 1796 * device.
1785 * 1797 *
1786 * @param dev device that is to be searched for a partition 1798 * @param dev device that is to be searched for a partition
1787 * @param part_num requested partition number 1799 * @param part_num requested partition number
1788 * @return pointer to the part_info, NULL otherwise 1800 * @return pointer to the part_info, NULL otherwise
1789 */ 1801 */
1790 static struct part_info* jffs2_part_info(struct mtd_device *dev, unsigned int part_num) 1802 static struct part_info* jffs2_part_info(struct mtd_device *dev, unsigned int part_num)
1791 { 1803 {
1792 struct list_head *entry; 1804 struct list_head *entry;
1793 struct part_info *part; 1805 struct part_info *part;
1794 int num; 1806 int num;
1795 1807
1796 if (!dev) 1808 if (!dev)
1797 return NULL; 1809 return NULL;
1798 1810
1799 DEBUGF("\n--- jffs2_part_info: partition number %d for device %s%d (%s)\n", 1811 DEBUGF("\n--- jffs2_part_info: partition number %d for device %s%d (%s)\n",
1800 part_num, MTD_DEV_TYPE(dev->id->type), 1812 part_num, MTD_DEV_TYPE(dev->id->type),
1801 dev->id->num, dev->id->mtd_id); 1813 dev->id->num, dev->id->mtd_id);
1802 1814
1803 if (part_num >= dev->num_parts) { 1815 if (part_num >= dev->num_parts) {
1804 printf("invalid partition number %d for device %s%d (%s)\n", 1816 printf("invalid partition number %d for device %s%d (%s)\n",
1805 part_num, MTD_DEV_TYPE(dev->id->type), 1817 part_num, MTD_DEV_TYPE(dev->id->type),
1806 dev->id->num, dev->id->mtd_id); 1818 dev->id->num, dev->id->mtd_id);
1807 return NULL; 1819 return NULL;
1808 } 1820 }
1809 1821
1810 /* locate partition number, return it */ 1822 /* locate partition number, return it */
1811 num = 0; 1823 num = 0;
1812 list_for_each(entry, &dev->parts) { 1824 list_for_each(entry, &dev->parts) {
1813 part = list_entry(entry, struct part_info, link); 1825 part = list_entry(entry, struct part_info, link);
1814 1826
1815 if (part_num == num++) { 1827 if (part_num == num++) {
1816 return part; 1828 return part;
1817 } 1829 }
1818 } 1830 }
1819 1831
1820 return NULL; 1832 return NULL;
1821 } 1833 }
1822 1834
1823 /***************************************************/ 1835 /***************************************************/
1824 /* U-boot commands */ 1836 /* U-boot commands */
1825 /***************************************************/ 1837 /***************************************************/
1826 1838
1827 /** 1839 /**
1828 * Routine implementing fsload u-boot command. This routine tries to load 1840 * Routine implementing fsload u-boot command. This routine tries to load
1829 * a requested file from jffs2/cramfs filesystem on a current partition. 1841 * a requested file from jffs2/cramfs filesystem on a current partition.
1830 * 1842 *
1831 * @param cmdtp command internal data 1843 * @param cmdtp command internal data
1832 * @param flag command flag 1844 * @param flag command flag
1833 * @param argc number of arguments supplied to the command 1845 * @param argc number of arguments supplied to the command
1834 * @param argv arguments list 1846 * @param argv arguments list
1835 * @return 0 on success, 1 otherwise 1847 * @return 0 on success, 1 otherwise
1836 */ 1848 */
1837 int do_jffs2_fsload(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) 1849 int do_jffs2_fsload(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
1838 { 1850 {
1839 char *fsname; 1851 char *fsname;
1840 char *filename; 1852 char *filename;
1841 int size; 1853 int size;
1842 struct part_info *part; 1854 struct part_info *part;
1843 ulong offset = load_addr; 1855 ulong offset = load_addr;
1844 1856
1845 /* pre-set Boot file name */ 1857 /* pre-set Boot file name */
1846 if ((filename = getenv("bootfile")) == NULL) { 1858 if ((filename = getenv("bootfile")) == NULL) {
1847 filename = "uImage"; 1859 filename = "uImage";
1848 } 1860 }
1849 1861
1850 if (argc == 2) { 1862 if (argc == 2) {
1851 filename = argv[1]; 1863 filename = argv[1];
1852 } 1864 }
1853 if (argc == 3) { 1865 if (argc == 3) {
1854 offset = simple_strtoul(argv[1], NULL, 16); 1866 offset = simple_strtoul(argv[1], NULL, 16);
1855 load_addr = offset; 1867 load_addr = offset;
1856 filename = argv[2]; 1868 filename = argv[2];
1857 } 1869 }
1858 1870
1859 /* make sure we are in sync with env variables */ 1871 /* make sure we are in sync with env variables */
1860 if (mtdparts_init() !=0) 1872 if (mtdparts_init() !=0)
1861 return 1; 1873 return 1;
1862 1874
1863 if ((part = jffs2_part_info(current_dev, current_partnum))){ 1875 if ((part = jffs2_part_info(current_dev, current_partnum))){
1864 1876
1865 /* check partition type for cramfs */ 1877 /* check partition type for cramfs */
1866 fsname = (cramfs_check(part) ? "CRAMFS" : "JFFS2"); 1878 fsname = (cramfs_check(part) ? "CRAMFS" : "JFFS2");
1867 printf("### %s loading '%s' to 0x%lx\n", fsname, filename, offset); 1879 printf("### %s loading '%s' to 0x%lx\n", fsname, filename, offset);
1868 1880
1869 if (cramfs_check(part)) { 1881 if (cramfs_check(part)) {
1870 size = cramfs_load ((char *) offset, part, filename); 1882 size = cramfs_load ((char *) offset, part, filename);
1871 } else { 1883 } else {
1872 /* if this is not cramfs assume jffs2 */ 1884 /* if this is not cramfs assume jffs2 */
1873 size = jffs2_1pass_load((char *)offset, part, filename); 1885 size = jffs2_1pass_load((char *)offset, part, filename);
1874 } 1886 }
1875 1887
1876 if (size > 0) { 1888 if (size > 0) {
1877 char buf[10]; 1889 char buf[10];
1878 printf("### %s load complete: %d bytes loaded to 0x%lx\n", 1890 printf("### %s load complete: %d bytes loaded to 0x%lx\n",
1879 fsname, size, offset); 1891 fsname, size, offset);
1880 sprintf(buf, "%x", size); 1892 sprintf(buf, "%x", size);
1881 setenv("filesize", buf); 1893 setenv("filesize", buf);
1882 } else { 1894 } else {
1883 printf("### %s LOAD ERROR<%x> for %s!\n", fsname, size, filename); 1895 printf("### %s LOAD ERROR<%x> for %s!\n", fsname, size, filename);
1884 } 1896 }
1885 1897
1886 return !(size > 0); 1898 return !(size > 0);
1887 } 1899 }
1888 return 1; 1900 return 1;
1889 } 1901 }
1890 1902
1891 /** 1903 /**
1892 * Routine implementing u-boot ls command which lists content of a given 1904 * Routine implementing u-boot ls command which lists content of a given
1893 * directory on a current partition. 1905 * directory on a current partition.
1894 * 1906 *
1895 * @param cmdtp command internal data 1907 * @param cmdtp command internal data
1896 * @param flag command flag 1908 * @param flag command flag
1897 * @param argc number of arguments supplied to the command 1909 * @param argc number of arguments supplied to the command
1898 * @param argv arguments list 1910 * @param argv arguments list
1899 * @return 0 on success, 1 otherwise 1911 * @return 0 on success, 1 otherwise
1900 */ 1912 */
1901 int do_jffs2_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) 1913 int do_jffs2_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
1902 { 1914 {
1903 char *filename = "/"; 1915 char *filename = "/";
1904 int ret; 1916 int ret;
1905 struct part_info *part; 1917 struct part_info *part;
1906 1918
1907 if (argc == 2) 1919 if (argc == 2)
1908 filename = argv[1]; 1920 filename = argv[1];
1909 1921
1910 /* make sure we are in sync with env variables */ 1922 /* make sure we are in sync with env variables */
1911 if (mtdparts_init() !=0) 1923 if (mtdparts_init() !=0)
1912 return 1; 1924 return 1;
1913 1925
1914 if ((part = jffs2_part_info(current_dev, current_partnum))){ 1926 if ((part = jffs2_part_info(current_dev, current_partnum))){
1915 1927
1916 /* check partition type for cramfs */ 1928 /* check partition type for cramfs */
1917 if (cramfs_check(part)) { 1929 if (cramfs_check(part)) {
1918 ret = cramfs_ls (part, filename); 1930 ret = cramfs_ls (part, filename);
1919 } else { 1931 } else {
1920 /* if this is not cramfs assume jffs2 */ 1932 /* if this is not cramfs assume jffs2 */
1921 ret = jffs2_1pass_ls(part, filename); 1933 ret = jffs2_1pass_ls(part, filename);
1922 } 1934 }
1923 1935
1924 return ret ? 0 : 1; 1936 return ret ? 0 : 1;
1925 } 1937 }
1926 return 1; 1938 return 1;
1927 } 1939 }
1928 1940
1929 /** 1941 /**
1930 * Routine implementing u-boot fsinfo command. This routine prints out 1942 * Routine implementing u-boot fsinfo command. This routine prints out
1931 * miscellaneous filesystem informations/statistics. 1943 * miscellaneous filesystem informations/statistics.
1932 * 1944 *
1933 * @param cmdtp command internal data 1945 * @param cmdtp command internal data
1934 * @param flag command flag 1946 * @param flag command flag
1935 * @param argc number of arguments supplied to the command 1947 * @param argc number of arguments supplied to the command
1936 * @param argv arguments list 1948 * @param argv arguments list
1937 * @return 0 on success, 1 otherwise 1949 * @return 0 on success, 1 otherwise
1938 */ 1950 */
1939 int do_jffs2_fsinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) 1951 int do_jffs2_fsinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
1940 { 1952 {
1941 struct part_info *part; 1953 struct part_info *part;
1942 char *fsname; 1954 char *fsname;
1943 int ret; 1955 int ret;
1944 1956
1945 /* make sure we are in sync with env variables */ 1957 /* make sure we are in sync with env variables */
1946 if (mtdparts_init() !=0) 1958 if (mtdparts_init() !=0)
1947 return 1; 1959 return 1;
1948 1960
1949 if ((part = jffs2_part_info(current_dev, current_partnum))){ 1961 if ((part = jffs2_part_info(current_dev, current_partnum))){
1950 1962
1951 /* check partition type for cramfs */ 1963 /* check partition type for cramfs */
1952 fsname = (cramfs_check(part) ? "CRAMFS" : "JFFS2"); 1964 fsname = (cramfs_check(part) ? "CRAMFS" : "JFFS2");
1953 printf("### filesystem type is %s\n", fsname); 1965 printf("### filesystem type is %s\n", fsname);
1954 1966
1955 if (cramfs_check(part)) { 1967 if (cramfs_check(part)) {
1956 ret = cramfs_info (part); 1968 ret = cramfs_info (part);
1957 } else { 1969 } else {
1958 /* if this is not cramfs assume jffs2 */ 1970 /* if this is not cramfs assume jffs2 */
1959 ret = jffs2_1pass_info(part); 1971 ret = jffs2_1pass_info(part);
1960 } 1972 }
1961 1973
1962 return ret ? 0 : 1; 1974 return ret ? 0 : 1;
1963 } 1975 }
1964 return 1; 1976 return 1;
1965 } 1977 }
1966 1978
1967 /* command line only */ 1979 /* command line only */
1968 #ifdef CONFIG_JFFS2_CMDLINE 1980 #ifdef CONFIG_JFFS2_CMDLINE
1969 /** 1981 /**
1970 * Routine implementing u-boot chpart command. Sets new current partition based 1982 * Routine implementing u-boot chpart command. Sets new current partition based
1971 * on the user supplied partition id. For partition id format see find_dev_and_part(). 1983 * on the user supplied partition id. For partition id format see find_dev_and_part().
1972 * 1984 *
1973 * @param cmdtp command internal data 1985 * @param cmdtp command internal data
1974 * @param flag command flag 1986 * @param flag command flag
1975 * @param argc number of arguments supplied to the command 1987 * @param argc number of arguments supplied to the command
1976 * @param argv arguments list 1988 * @param argv arguments list
1977 * @return 0 on success, 1 otherwise 1989 * @return 0 on success, 1 otherwise
1978 */ 1990 */
1979 int do_jffs2_chpart(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) 1991 int do_jffs2_chpart(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
1980 { 1992 {
1981 /* command line only */ 1993 /* command line only */
1982 struct mtd_device *dev; 1994 struct mtd_device *dev;
1983 struct part_info *part; 1995 struct part_info *part;
1984 u8 pnum; 1996 u8 pnum;
1985 1997
1986 if (mtdparts_init() !=0) 1998 if (mtdparts_init() !=0)
1987 return 1; 1999 return 1;
1988 2000
1989 if (argc < 2) { 2001 if (argc < 2) {
1990 printf("no partition id specified\n"); 2002 printf("no partition id specified\n");
1991 return 1; 2003 return 1;
1992 } 2004 }
1993 2005
1994 if (find_dev_and_part(argv[1], &dev, &pnum, &part) != 0) 2006 if (find_dev_and_part(argv[1], &dev, &pnum, &part) != 0)
1995 return 1; 2007 return 1;
1996 2008
1997 current_dev = dev; 2009 current_dev = dev;
1998 current_partnum = pnum; 2010 current_partnum = pnum;
1999 current_save(); 2011 current_save();
2000 2012
2001 printf("partition changed to %s%d,%d\n", 2013 printf("partition changed to %s%d,%d\n",
2002 MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum); 2014 MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum);
2003 2015
2004 return 0; 2016 return 0;
2005 } 2017 }
2006 2018
2007 /** 2019 /**
2008 * Routine implementing u-boot mtdparts command. Initialize/update default global 2020 * Routine implementing u-boot mtdparts command. Initialize/update default global
2009 * partition list and process user partition request (list, add, del). 2021 * partition list and process user partition request (list, add, del).
2010 * 2022 *
2011 * @param cmdtp command internal data 2023 * @param cmdtp command internal data
2012 * @param flag command flag 2024 * @param flag command flag
2013 * @param argc number of arguments supplied to the command 2025 * @param argc number of arguments supplied to the command
2014 * @param argv arguments list 2026 * @param argv arguments list
2015 * @return 0 on success, 1 otherwise 2027 * @return 0 on success, 1 otherwise
2016 */ 2028 */
2017 int do_jffs2_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) 2029 int do_jffs2_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
2018 { 2030 {
2019 if (argc == 2) { 2031 if (argc == 2) {
2020 if (strcmp(argv[1], "default") == 0) { 2032 if (strcmp(argv[1], "default") == 0) {
2021 setenv("mtdids", (char *)mtdids_default); 2033 setenv("mtdids", (char *)mtdids_default);
2022 setenv("mtdparts", (char *)mtdparts_default); 2034 setenv("mtdparts", (char *)mtdparts_default);
2023 setenv("partition", NULL); 2035 setenv("partition", NULL);
2024 2036
2025 mtdparts_init(); 2037 mtdparts_init();
2026 return 0; 2038 return 0;
2027 } else if (strcmp(argv[1], "delall") == 0) { 2039 } else if (strcmp(argv[1], "delall") == 0) {
2028 /* this may be the first run, initialize lists if needed */ 2040 /* this may be the first run, initialize lists if needed */
2029 mtdparts_init(); 2041 mtdparts_init();
2030 2042
2031 setenv("mtdparts", NULL); 2043 setenv("mtdparts", NULL);
2032 2044
2033 /* devices_init() calls current_save() */ 2045 /* devices_init() calls current_save() */
2034 return devices_init(); 2046 return devices_init();
2035 } 2047 }
2036 } 2048 }
2037 2049
2038 /* make sure we are in sync with env variables */ 2050 /* make sure we are in sync with env variables */
2039 if (mtdparts_init() != 0) 2051 if (mtdparts_init() != 0)
2040 return 1; 2052 return 1;
2041 2053
2042 if (argc == 1) { 2054 if (argc == 1) {
2043 list_partitions(); 2055 list_partitions();
2044 return 0; 2056 return 0;
2045 } 2057 }
2046 2058
2047 /* mtdparts add <mtd-dev> <size>[@<offset>] <name> [ro] */ 2059 /* mtdparts add <mtd-dev> <size>[@<offset>] <name> [ro] */
2048 if (((argc == 5) || (argc == 6)) && (strcmp(argv[1], "add") == 0)) { 2060 if (((argc == 5) || (argc == 6)) && (strcmp(argv[1], "add") == 0)) {
2049 #define PART_ADD_DESC_MAXLEN 64 2061 #define PART_ADD_DESC_MAXLEN 64
2050 char tmpbuf[PART_ADD_DESC_MAXLEN]; 2062 char tmpbuf[PART_ADD_DESC_MAXLEN];
2051 u8 type, num, len; 2063 u8 type, num, len;
2052 struct mtd_device *dev; 2064 struct mtd_device *dev;
2053 struct mtd_device *dev_tmp; 2065 struct mtd_device *dev_tmp;
2054 struct mtdids *id; 2066 struct mtdids *id;
2055 struct part_info *p; 2067 struct part_info *p;
2056 2068
2057 if (id_parse(argv[2], NULL, &type, &num) != 0) 2069 if (id_parse(argv[2], NULL, &type, &num) != 0)
2058 return 1; 2070 return 1;
2059 2071
2060 if ((id = id_find(type, num)) == NULL) { 2072 if ((id = id_find(type, num)) == NULL) {
2061 printf("no such device %s defined in mtdids variable\n", argv[2]); 2073 printf("no such device %s defined in mtdids variable\n", argv[2]);
2062 return 1; 2074 return 1;
2063 } 2075 }
2064 2076
2065 len = strlen(id->mtd_id) + 1; /* 'mtd_id:' */ 2077 len = strlen(id->mtd_id) + 1; /* 'mtd_id:' */
2066 len += strlen(argv[3]); /* size@offset */ 2078 len += strlen(argv[3]); /* size@offset */
2067 len += strlen(argv[4]) + 2; /* '(' name ')' */ 2079 len += strlen(argv[4]) + 2; /* '(' name ')' */
2068 if (argv[5] && (strlen(argv[5]) == 2)) 2080 if (argv[5] && (strlen(argv[5]) == 2))
2069 len += 2; /* 'ro' */ 2081 len += 2; /* 'ro' */
2070 2082
2071 if (len >= PART_ADD_DESC_MAXLEN) { 2083 if (len >= PART_ADD_DESC_MAXLEN) {
2072 printf("too long partition description\n"); 2084 printf("too long partition description\n");
2073 return 1; 2085 return 1;
2074 } 2086 }
2075 sprintf(tmpbuf, "%s:%s(%s)%s", 2087 sprintf(tmpbuf, "%s:%s(%s)%s",
2076 id->mtd_id, argv[3], argv[4], argv[5] ? argv[5] : ""); 2088 id->mtd_id, argv[3], argv[4], argv[5] ? argv[5] : "");
2077 DEBUGF("add tmpbuf: %s\n", tmpbuf); 2089 DEBUGF("add tmpbuf: %s\n", tmpbuf);
2078 2090
2079 if ((device_parse(tmpbuf, NULL, &dev) != 0) || (!dev)) 2091 if ((device_parse(tmpbuf, NULL, &dev) != 0) || (!dev))
2080 return 1; 2092 return 1;
2081 2093
2082 DEBUGF("+ %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type), 2094 DEBUGF("+ %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type),
2083 dev->id->num, dev->id->mtd_id); 2095 dev->id->num, dev->id->mtd_id);
2084 2096
2085 if ((dev_tmp = device_find(dev->id->type, dev->id->num)) == NULL) { 2097 if ((dev_tmp = device_find(dev->id->type, dev->id->num)) == NULL) {
2086 device_add(dev); 2098 device_add(dev);
2087 } else { 2099 } else {
2088 /* merge new partition with existing ones*/ 2100 /* merge new partition with existing ones*/
2089 p = list_entry(dev->parts.next, struct part_info, link); 2101 p = list_entry(dev->parts.next, struct part_info, link);
2090 if (part_add(dev_tmp, p) != 0) { 2102 if (part_add(dev_tmp, p) != 0) {
2091 device_del(dev); 2103 device_del(dev);
2092 return 1; 2104 return 1;
2093 } 2105 }
2094 } 2106 }
2095 2107
2096 if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) { 2108 if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) {
2097 printf("generated mtdparts too long, reseting to null\n"); 2109 printf("generated mtdparts too long, reseting to null\n");
2098 return 1; 2110 return 1;
2099 } 2111 }
2100 2112
2101 return 0; 2113 return 0;
2102 } 2114 }
2103 2115
2104 /* mtdparts del part-id */ 2116 /* mtdparts del part-id */
2105 if ((argc == 3) && (strcmp(argv[1], "del") == 0)) { 2117 if ((argc == 3) && (strcmp(argv[1], "del") == 0)) {
2106 DEBUGF("del: part-id = %s\n", argv[2]); 2118 DEBUGF("del: part-id = %s\n", argv[2]);
2107 2119
2108 return delete_partition(argv[2]); 2120 return delete_partition(argv[2]);
2109 } 2121 }
2110 2122
2111 printf ("Usage:\n%s\n", cmdtp->usage); 2123 printf ("Usage:\n%s\n", cmdtp->usage);
2112 return 1; 2124 return 1;
2113 } 2125 }
2114 #endif /* #ifdef CONFIG_JFFS2_CMDLINE */ 2126 #endif /* #ifdef CONFIG_JFFS2_CMDLINE */
2115 2127
2116 /***************************************************/ 2128 /***************************************************/
2117 U_BOOT_CMD( 2129 U_BOOT_CMD(
2118 fsload, 3, 0, do_jffs2_fsload, 2130 fsload, 3, 0, do_jffs2_fsload,
2119 "fsload\t- load binary file from a filesystem image\n", 2131 "fsload\t- load binary file from a filesystem image\n",
2120 "[ off ] [ filename ]\n" 2132 "[ off ] [ filename ]\n"
2121 " - load binary file from flash bank\n" 2133 " - load binary file from flash bank\n"
2122 " with offset 'off'\n" 2134 " with offset 'off'\n"
2123 ); 2135 );
2124 U_BOOT_CMD( 2136 U_BOOT_CMD(
2125 ls, 2, 1, do_jffs2_ls, 2137 ls, 2, 1, do_jffs2_ls,
2126 "ls\t- list files in a directory (default /)\n", 2138 "ls\t- list files in a directory (default /)\n",
2127 "[ directory ]\n" 2139 "[ directory ]\n"
2128 " - list files in a directory.\n" 2140 " - list files in a directory.\n"
2129 ); 2141 );
2130 2142
2131 U_BOOT_CMD( 2143 U_BOOT_CMD(
2132 fsinfo, 1, 1, do_jffs2_fsinfo, 2144 fsinfo, 1, 1, do_jffs2_fsinfo,
2133 "fsinfo\t- print information about filesystems\n", 2145 "fsinfo\t- print information about filesystems\n",
2134 " - print information about filesystems\n" 2146 " - print information about filesystems\n"
2135 ); 2147 );
2136 2148
2137 #ifdef CONFIG_JFFS2_CMDLINE 2149 #ifdef CONFIG_JFFS2_CMDLINE
2138 U_BOOT_CMD( 2150 U_BOOT_CMD(
2139 chpart, 2, 0, do_jffs2_chpart, 2151 chpart, 2, 0, do_jffs2_chpart,
2140 "chpart\t- change active partition\n", 2152 "chpart\t- change active partition\n",
2141 "part-id\n" 2153 "part-id\n"
2142 " - change active partition (e.g. part-id = nand0,1)\n" 2154 " - change active partition (e.g. part-id = nand0,1)\n"
2143 ); 2155 );
2144 2156
2145 U_BOOT_CMD( 2157 U_BOOT_CMD(
2146 mtdparts, 6, 0, do_jffs2_mtdparts, 2158 mtdparts, 6, 0, do_jffs2_mtdparts,
2147 "mtdparts- define flash/nand partitions\n", 2159 "mtdparts- define flash/nand partitions\n",
2148 "\n" 2160 "\n"
2149 " - list partition table\n" 2161 " - list partition table\n"
2150 "mtdparts delall\n" 2162 "mtdparts delall\n"
2151 " - delete all partitions\n" 2163 " - delete all partitions\n"
2152 "mtdparts del part-id\n" 2164 "mtdparts del part-id\n"
2153 " - delete partition (e.g. part-id = nand0,1)\n" 2165 " - delete partition (e.g. part-id = nand0,1)\n"
2154 "mtdparts add <mtd-dev> <size>[@<offset>] [<name>] [ro]\n" 2166 "mtdparts add <mtd-dev> <size>[@<offset>] [<name>] [ro]\n"
2155 " - add partition\n" 2167 " - add partition\n"
2156 "mtdparts default\n" 2168 "mtdparts default\n"
2157 " - reset partition table to defaults\n\n" 2169 " - reset partition table to defaults\n\n"
2158 "-----\n\n" 2170 "-----\n\n"
2159 "this command uses three environment variables:\n\n" 2171 "this command uses three environment variables:\n\n"
2160 "'partition' - keeps current partition identifier\n\n" 2172 "'partition' - keeps current partition identifier\n\n"
2161 "partition := <part-id>\n" 2173 "partition := <part-id>\n"
2162 "<part-id> := <dev-id>,part_num\n\n" 2174 "<part-id> := <dev-id>,part_num\n\n"
2163 "'mtdids' - linux kernel mtd device id <-> u-boot device id mapping\n\n" 2175 "'mtdids' - linux kernel mtd device id <-> u-boot device id mapping\n\n"
2164 "mtdids=<idmap>[,<idmap>,...]\n\n" 2176 "mtdids=<idmap>[,<idmap>,...]\n\n"
2165 "<idmap> := <dev-id>=<mtd-id>\n" 2177 "<idmap> := <dev-id>=<mtd-id>\n"
2166 "<dev-id> := 'nand'|'nor'<dev-num>\n" 2178 "<dev-id> := 'nand'|'nor'<dev-num>\n"
2167 "<dev-num> := mtd device number, 0...\n" 2179 "<dev-num> := mtd device number, 0...\n"
2168 "<mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name)\n\n" 2180 "<mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name)\n\n"
2169 "'mtdparts' - partition list\n\n" 2181 "'mtdparts' - partition list\n\n"
2170 "mtdparts=mtdparts=<mtd-def>[;<mtd-def>...]\n\n" 2182 "mtdparts=mtdparts=<mtd-def>[;<mtd-def>...]\n\n"
2171 "<mtd-def> := <mtd-id>:<part-def>[,<part-def>...]\n" 2183 "<mtd-def> := <mtd-id>:<part-def>[,<part-def>...]\n"
2172 "<mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name)\n" 2184 "<mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name)\n"
2173 "<part-def> := <size>[@<offset>][<name>][<ro-flag>]\n" 2185 "<part-def> := <size>[@<offset>][<name>][<ro-flag>]\n"
2174 "<size> := standard linux memsize OR '-' to denote all remaining space\n" 2186 "<size> := standard linux memsize OR '-' to denote all remaining space\n"
2175 "<offset> := partition start offset within the device\n" 2187 "<offset> := partition start offset within the device\n"
2176 "<name> := '(' NAME ')'\n" 2188 "<name> := '(' NAME ')'\n"
2177 "<ro-flag> := when set to 'ro' makes partition read-only (not used, passed to kernel)\n" 2189 "<ro-flag> := when set to 'ro' makes partition read-only (not used, passed to kernel)\n"
2178 ); 2190 );
2179 #endif /* #ifdef CONFIG_JFFS2_CMDLINE */ 2191 #endif /* #ifdef CONFIG_JFFS2_CMDLINE */
2180 2192
2181 /***************************************************/ 2193 /***************************************************/
2182 2194
2183 #endif /* CFG_CMD_JFFS2 */ 2195 #endif /* CFG_CMD_JFFS2 */
2184 2196
1 /* 1 /*
2 * Driver for NAND support, Rick Bronson 2 * Driver for NAND support, Rick Bronson
3 * borrowed heavily from: 3 * borrowed heavily from:
4 * (c) 1999 Machine Vision Holdings, Inc. 4 * (c) 1999 Machine Vision Holdings, Inc.
5 * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> 5 * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
6 * 6 *
7 * Added 16-bit nand support 7 * Added 16-bit nand support
8 * (C) 2004 Texas Instruments 8 * (C) 2004 Texas Instruments
9 */ 9 */
10 10
11 #include <common.h> 11 #include <common.h>
12 12
13 13
14 #ifndef CFG_NAND_LEGACY 14 #ifndef CFG_NAND_LEGACY
15 /* 15 /*
16 * 16 *
17 * New NAND support 17 * New NAND support
18 * 18 *
19 */ 19 */
20 #include <common.h> 20 #include <common.h>
21 21
22 #if (CONFIG_COMMANDS & CFG_CMD_NAND) 22 #if (CONFIG_COMMANDS & CFG_CMD_NAND)
23 23
24 #include <command.h> 24 #include <command.h>
25 #include <watchdog.h> 25 #include <watchdog.h>
26 #include <malloc.h> 26 #include <malloc.h>
27 #include <asm/byteorder.h> 27 #include <asm/byteorder.h>
28 28
29 #ifdef CONFIG_SHOW_BOOT_PROGRESS 29 #ifdef CONFIG_SHOW_BOOT_PROGRESS
30 # include <status_led.h> 30 # include <status_led.h>
31 # define SHOW_BOOT_PROGRESS(arg) show_boot_progress(arg) 31 # define SHOW_BOOT_PROGRESS(arg) show_boot_progress(arg)
32 #else 32 #else
33 # define SHOW_BOOT_PROGRESS(arg) 33 # define SHOW_BOOT_PROGRESS(arg)
34 #endif 34 #endif
35 35
36 #include <jffs2/jffs2.h> 36 #include <jffs2/jffs2.h>
37 #include <nand.h> 37 #include <nand.h>
38 38
39 #if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
40
41 /* parition handling routines */
42 int mtdparts_init(void);
43 int id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num);
44 int find_dev_and_part(const char *id, struct mtd_device **dev,
45 u8 *part_num, struct part_info **part);
46 #endif
47
39 extern nand_info_t nand_info[]; /* info for NAND chips */ 48 extern nand_info_t nand_info[]; /* info for NAND chips */
40 49
41 static int nand_dump_oob(nand_info_t *nand, ulong off) 50 static int nand_dump_oob(nand_info_t *nand, ulong off)
42 { 51 {
43 return 0; 52 return 0;
44 } 53 }
45 54
46 static int nand_dump(nand_info_t *nand, ulong off) 55 static int nand_dump(nand_info_t *nand, ulong off)
47 { 56 {
48 int i; 57 int i;
49 u_char *buf, *p; 58 u_char *buf, *p;
50 59
51 buf = malloc(nand->oobblock + nand->oobsize); 60 buf = malloc(nand->oobblock + nand->oobsize);
52 if (!buf) { 61 if (!buf) {
53 puts("No memory for page buffer\n"); 62 puts("No memory for page buffer\n");
54 return 1; 63 return 1;
55 } 64 }
56 off &= ~(nand->oobblock - 1); 65 off &= ~(nand->oobblock - 1);
57 i = nand_read_raw(nand, buf, off, nand->oobblock, nand->oobsize); 66 i = nand_read_raw(nand, buf, off, nand->oobblock, nand->oobsize);
58 if (i < 0) { 67 if (i < 0) {
59 printf("Error (%d) reading page %08x\n", i, off); 68 printf("Error (%d) reading page %08x\n", i, off);
60 free(buf); 69 free(buf);
61 return 1; 70 return 1;
62 } 71 }
63 printf("Page %08x dump:\n", off); 72 printf("Page %08x dump:\n", off);
64 i = nand->oobblock >> 4; p = buf; 73 i = nand->oobblock >> 4; p = buf;
65 while (i--) { 74 while (i--) {
66 printf( "\t%02x %02x %02x %02x %02x %02x %02x %02x" 75 printf( "\t%02x %02x %02x %02x %02x %02x %02x %02x"
67 " %02x %02x %02x %02x %02x %02x %02x %02x\n", 76 " %02x %02x %02x %02x %02x %02x %02x %02x\n",
68 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], 77 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
69 p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); 78 p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
70 p += 16; 79 p += 16;
71 } 80 }
72 puts("OOB:\n"); 81 puts("OOB:\n");
73 i = nand->oobsize >> 3; 82 i = nand->oobsize >> 3;
74 while (i--) { 83 while (i--) {
75 printf( "\t%02x %02x %02x %02x %02x %02x %02x %02x\n", 84 printf( "\t%02x %02x %02x %02x %02x %02x %02x %02x\n",
76 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); 85 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
77 p += 8; 86 p += 8;
78 } 87 }
79 free(buf); 88 free(buf);
80 89
81 return 0; 90 return 0;
82 } 91 }
83 92
84 /* ------------------------------------------------------------------------- */ 93 /* ------------------------------------------------------------------------- */
85 94
86 static void 95 static inline int str2long(char *p, ulong *num)
87 arg_off_size(int argc, char *argv[], ulong *off, ulong *size, ulong totsize)
88 { 96 {
89 *off = 0; 97 char *endptr;
90 *size = 0;
91 98
92 #if defined(CONFIG_JFFS2_NAND) && defined(CFG_JFFS_CUSTOM_PART) 99 *num = simple_strtoul(p, &endptr, 16);
93 if (argc >= 1 && strcmp(argv[0], "partition") == 0) { 100 return (*p != '\0' && *endptr == '\0') ? 1 : 0;
94 int part_num; 101 }
95 struct part_info *part;
96 const char *partstr;
97 102
98 if (argc >= 2) 103 static int
99 partstr = argv[1]; 104 arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off, ulong *size)
100 else 105 {
101 partstr = getenv("partition"); 106 int idx = nand_curr_device;
107 #if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
108 struct mtd_device *dev;
109 struct part_info *part;
110 u8 pnum;
102 111
103 if (partstr) 112 if (argc >= 1 && !(str2long(argv[0], off))) {
104 part_num = (int)simple_strtoul(partstr, NULL, 10); 113 if ((mtdparts_init() == 0) &&
105 else 114 (find_dev_and_part(argv[0], &dev, &pnum, &part) == 0)) {
106 part_num = 0; 115 if (dev->id->type != MTD_DEV_TYPE_NAND) {
107 116 puts("not a NAND device\n");
108 part = jffs2_part_info(part_num); 117 return -1;
109 if (part == NULL) { 118 }
110 printf("\nInvalid partition %d\n", part_num); 119 *off = part->offset;
111 return; 120 if (argc >= 2) {
121 if (!(str2long(argv[1], size))) {
122 printf("'%s' is not a number\n", argv[1]);
123 return -1;
124 }
125 if (*size > part->size)
126 *size = part->size;
127 } else {
128 *size = part->size;
129 }
130 idx = dev->id->num;
131 *nand = nand_info[idx];
132 goto out;
112 } 133 }
113 *size = part->size; 134 }
114 *off = (ulong)part->offset;
115 } else
116 #endif 135 #endif
117 {
118 if (argc >= 1)
119 *off = (ulong)simple_strtoul(argv[0], NULL, 16);
120 else
121 *off = 0;
122 136
123 if (argc >= 2) 137 if (argc >= 1) {
124 *size = (ulong)simple_strtoul(argv[1], NULL, 16); 138 if (!(str2long(argv[0], off))) {
125 else 139 printf("'%s' is not a number\n", argv[0]);
126 *size = totsize - *off; 140 return -1;
141 }
142 } else {
143 *off = 0;
144 }
127 145
146 if (argc >= 2) {
147 if (!(str2long(argv[1], size))) {
148 printf("'%s' is not a number\n", argv[1]);
149 return -1;
150 }
151 } else {
152 *size = nand->size - *off;
128 } 153 }
129 154
155 #if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
156 out:
157 #endif
158 printf("device %d ", idx);
159 if (*size == nand->size)
160 puts("whole chip\n");
161 else
162 printf("offset 0x%x, size 0x%x\n", *off, *size);
163 return 0;
130 } 164 }
131 165
132 int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) 166 int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
133 { 167 {
134 int i, dev, ret; 168 int i, dev, ret;
135 ulong addr, off, size; 169 ulong addr, off, size;
136 char *cmd, *s; 170 char *cmd, *s;
137 nand_info_t *nand; 171 nand_info_t *nand;
138 int quiet = 0; 172 int quiet = 0;
139 const char *quiet_str = getenv("quiet"); 173 const char *quiet_str = getenv("quiet");
140 174
141 /* at least two arguments please */ 175 /* at least two arguments please */
142 if (argc < 2) 176 if (argc < 2)
143 goto usage; 177 goto usage;
144 178
145 if (quiet_str) 179 if (quiet_str)
146 quiet = simple_strtoul(quiet_str, NULL, 0) != 0; 180 quiet = simple_strtoul(quiet_str, NULL, 0) != 0;
147 181
148 cmd = argv[1]; 182 cmd = argv[1];
149 183
150 if (strcmp(cmd, "info") == 0) { 184 if (strcmp(cmd, "info") == 0) {
151 185
152 putc('\n'); 186 putc('\n');
153 for (i = 0; i < CFG_MAX_NAND_DEVICE; i++) { 187 for (i = 0; i < CFG_MAX_NAND_DEVICE; i++) {
154 if (nand_info[i].name) 188 if (nand_info[i].name)
155 printf("Device %d: %s, sector size %lu KiB\n", 189 printf("Device %d: %s, sector size %lu KiB\n",
156 i, nand_info[i].name, 190 i, nand_info[i].name,
157 nand_info[i].erasesize >> 10); 191 nand_info[i].erasesize >> 10);
158 } 192 }
159 return 0; 193 return 0;
160 } 194 }
161 195
162 if (strcmp(cmd, "device") == 0) { 196 if (strcmp(cmd, "device") == 0) {
163 197
164 if (argc < 3) { 198 if (argc < 3) {
165 if ((nand_curr_device < 0) || 199 if ((nand_curr_device < 0) ||
166 (nand_curr_device >= CFG_MAX_NAND_DEVICE)) 200 (nand_curr_device >= CFG_MAX_NAND_DEVICE))
167 puts("\nno devices available\n"); 201 puts("\nno devices available\n");
168 else 202 else
169 printf("\nDevice %d: %s\n", nand_curr_device, 203 printf("\nDevice %d: %s\n", nand_curr_device,
170 nand_info[nand_curr_device].name); 204 nand_info[nand_curr_device].name);
171 return 0; 205 return 0;
172 } 206 }
173 dev = (int)simple_strtoul(argv[2], NULL, 10); 207 dev = (int)simple_strtoul(argv[2], NULL, 10);
174 if (dev < 0 || dev >= CFG_MAX_NAND_DEVICE || !nand_info[dev].name) { 208 if (dev < 0 || dev >= CFG_MAX_NAND_DEVICE || !nand_info[dev].name) {
175 puts("No such device\n"); 209 puts("No such device\n");
176 return 1; 210 return 1;
177 } 211 }
178 printf("Device %d: %s", dev, nand_info[dev].name); 212 printf("Device %d: %s", dev, nand_info[dev].name);
179 puts("... is now current device\n"); 213 puts("... is now current device\n");
180 nand_curr_device = dev; 214 nand_curr_device = dev;
181 215
182 #ifdef CFG_NAND_SELECT_DEVICE 216 #ifdef CFG_NAND_SELECT_DEVICE
183 /* 217 /*
184 * Select the chip in the board/cpu specific driver 218 * Select the chip in the board/cpu specific driver
185 */ 219 */
186 board_nand_select_device(nand_info[dev].priv, dev); 220 board_nand_select_device(nand_info[dev].priv, dev);
187 #endif 221 #endif
188 222
189 return 0; 223 return 0;
190 } 224 }
191 225
192 if (strcmp(cmd, "bad") != 0 && strcmp(cmd, "erase") != 0 && 226 if (strcmp(cmd, "bad") != 0 && strcmp(cmd, "erase") != 0 &&
193 strncmp(cmd, "dump", 4) != 0 && 227 strncmp(cmd, "dump", 4) != 0 &&
194 strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0 && 228 strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0 &&
195 strcmp(cmd, "scrub") != 0 && strcmp(cmd, "markbad") != 0 && 229 strcmp(cmd, "scrub") != 0 && strcmp(cmd, "markbad") != 0 &&
196 strcmp(cmd, "biterr") != 0 && 230 strcmp(cmd, "biterr") != 0 &&
197 strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0 ) 231 strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0 )
198 goto usage; 232 goto usage;
199 233
200 /* the following commands operate on the current device */ 234 /* the following commands operate on the current device */
201 if (nand_curr_device < 0 || nand_curr_device >= CFG_MAX_NAND_DEVICE || 235 if (nand_curr_device < 0 || nand_curr_device >= CFG_MAX_NAND_DEVICE ||
202 !nand_info[nand_curr_device].name) { 236 !nand_info[nand_curr_device].name) {
203 puts("\nno devices available\n"); 237 puts("\nno devices available\n");
204 return 1; 238 return 1;
205 } 239 }
206 nand = &nand_info[nand_curr_device]; 240 nand = &nand_info[nand_curr_device];
207 241
208 if (strcmp(cmd, "bad") == 0) { 242 if (strcmp(cmd, "bad") == 0) {
209 printf("\nDevice %d bad blocks:\n", nand_curr_device); 243 printf("\nDevice %d bad blocks:\n", nand_curr_device);
210 for (off = 0; off < nand->size; off += nand->erasesize) 244 for (off = 0; off < nand->size; off += nand->erasesize)
211 if (nand_block_isbad(nand, off)) 245 if (nand_block_isbad(nand, off))
212 printf(" %08x\n", off); 246 printf(" %08x\n", off);
213 return 0; 247 return 0;
214 } 248 }
215 249
250 /*
251 * Syntax is:
252 * 0 1 2 3 4
253 * nand erase [clean] [off size]
254 */
216 if (strcmp(cmd, "erase") == 0 || strcmp(cmd, "scrub") == 0) { 255 if (strcmp(cmd, "erase") == 0 || strcmp(cmd, "scrub") == 0) {
217 nand_erase_options_t opts; 256 nand_erase_options_t opts;
218 int clean = argc >= 3 && !strcmp("clean", argv[2]); 257 /* "clean" at index 2 means request to write cleanmarker */
219 int rest_argc = argc - 2; 258 int clean = argc > 2 && !strcmp("clean", argv[2]);
220 char **rest_argv = argv + 2; 259 int o = clean ? 3 : 2;
221 int scrub = !strcmp(cmd, "scrub"); 260 int scrub = !strcmp(cmd, "scrub");
222 261
223 if (clean) { 262 printf("\nNAND %s: ", scrub ? "scrub" : "erase");
224 rest_argc--; 263 /* skip first two or three arguments, look for offset and size */
225 rest_argv++; 264 if (arg_off_size(argc - o, argv + o, nand, &off, &size) != 0)
226 } 265 return 1;
227 266
228 if (rest_argc == 0) {
229
230 printf("\nNAND %s: device %d whole chip\n",
231 cmd,
232 nand_curr_device);
233
234 off = size = 0;
235 } else {
236 arg_off_size(rest_argc, rest_argv, &off, &size,
237 nand->size);
238
239 if (off == 0 && size == 0)
240 return 1;
241
242 printf("\nNAND %s: device %d offset 0x%x, size 0x%x\n",
243 cmd, nand_curr_device, off, size);
244 }
245
246 memset(&opts, 0, sizeof(opts)); 267 memset(&opts, 0, sizeof(opts));
247 opts.offset = off; 268 opts.offset = off;
248 opts.length = size; 269 opts.length = size;
249 opts.jffs2 = clean; 270 opts.jffs2 = clean;
250 opts.quiet = quiet; 271 opts.quiet = quiet;
251 272
252 if (scrub) { 273 if (scrub) {
253 printf("Warning: " 274 puts("Warning: "
254 "scrub option will erase all factory set " 275 "scrub option will erase all factory set "
255 "bad blocks!\n" 276 "bad blocks!\n"
256 " " 277 " "
257 "There is no reliable way to recover them.\n" 278 "There is no reliable way to recover them.\n"
258 " " 279 " "
259 "Use this command only for testing purposes " 280 "Use this command only for testing purposes "
260 "if you\n" 281 "if you\n"
261 " " 282 " "
262 "are sure of what you are doing!\n" 283 "are sure of what you are doing!\n"
263 "\nReally scrub this NAND flash? <y/N>\n" 284 "\nReally scrub this NAND flash? <y/N>\n");
264 );
265 285
266 if (getc() == 'y' && getc() == '\r') { 286 if (getc() == 'y' && getc() == '\r') {
267 opts.scrub = 1; 287 opts.scrub = 1;
268 } else { 288 } else {
269 printf("scrub aborted\n"); 289 puts("scrub aborted\n");
270 return -1; 290 return -1;
271 } 291 }
272 } 292 }
273 ret = nand_erase_opts(nand, &opts); 293 ret = nand_erase_opts(nand, &opts);
274 printf("%s\n", ret ? "ERROR" : "OK"); 294 printf("%s\n", ret ? "ERROR" : "OK");
275 295
276 return ret == 0 ? 0 : 1; 296 return ret == 0 ? 0 : 1;
277 } 297 }
278 298
279 if (strncmp(cmd, "dump", 4) == 0) { 299 if (strncmp(cmd, "dump", 4) == 0) {
280 if (argc < 3) 300 if (argc < 3)
281 goto usage; 301 goto usage;
282 302
283 s = strchr(cmd, '.'); 303 s = strchr(cmd, '.');
284 off = (int)simple_strtoul(argv[2], NULL, 16); 304 off = (int)simple_strtoul(argv[2], NULL, 16);
285 305
286 if (s != NULL && strcmp(s, ".oob") == 0) 306 if (s != NULL && strcmp(s, ".oob") == 0)
287 ret = nand_dump_oob(nand, off); 307 ret = nand_dump_oob(nand, off);
288 else 308 else
289 ret = nand_dump(nand, off); 309 ret = nand_dump(nand, off);
290 310
291 return ret == 0 ? 1 : 0; 311 return ret == 0 ? 1 : 0;
292 312
293 } 313 }
294 314
295 /* read write */ 315 /* read write */
296 if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) { 316 if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
297 int read; 317 int read;
298 318
299 if (argc < 4) 319 if (argc < 4)
300 goto usage; 320 goto usage;
301 321
302 addr = (ulong)simple_strtoul(argv[2], NULL, 16); 322 addr = (ulong)simple_strtoul(argv[2], NULL, 16);
303 323
304 arg_off_size(argc - 3, argv + 3, &off, &size, nand->size); 324 read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */
305 if (off == 0 && size == 0) 325 printf("\nNAND %s: ", read ? "read" : "write");
326 if (arg_off_size(argc - 3, argv + 3, nand, &off, &size) != 0)
306 return 1; 327 return 1;
307 328
308 read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */
309 printf("\nNAND %s: device %d offset %u, size %u ... ",
310 read ? "read" : "write", nand_curr_device, off, size);
311
312 s = strchr(cmd, '.'); 329 s = strchr(cmd, '.');
313 if (s != NULL && 330 if (s != NULL &&
314 (!strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i"))) { 331 (!strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i"))) {
315 if (read) { 332 if (read) {
316 /* read */ 333 /* read */
317 nand_read_options_t opts; 334 nand_read_options_t opts;
318 memset(&opts, 0, sizeof(opts)); 335 memset(&opts, 0, sizeof(opts));
319 opts.buffer = (u_char*) addr; 336 opts.buffer = (u_char*) addr;
320 opts.length = size; 337 opts.length = size;
321 opts.offset = off; 338 opts.offset = off;
322 opts.quiet = quiet; 339 opts.quiet = quiet;
323 ret = nand_read_opts(nand, &opts); 340 ret = nand_read_opts(nand, &opts);
324 } else { 341 } else {
325 /* write */ 342 /* write */
326 nand_write_options_t opts; 343 nand_write_options_t opts;
327 memset(&opts, 0, sizeof(opts)); 344 memset(&opts, 0, sizeof(opts));
328 opts.buffer = (u_char*) addr; 345 opts.buffer = (u_char*) addr;
329 opts.length = size; 346 opts.length = size;
330 opts.offset = off; 347 opts.offset = off;
331 /* opts.forcejffs2 = 1; */ 348 /* opts.forcejffs2 = 1; */
332 opts.pad = 1; 349 opts.pad = 1;
333 opts.blockalign = 1; 350 opts.blockalign = 1;
334 opts.quiet = quiet; 351 opts.quiet = quiet;
335 ret = nand_write_opts(nand, &opts); 352 ret = nand_write_opts(nand, &opts);
336 } 353 }
337 printf("%s\n", ret ? "ERROR" : "OK"); 354 } else {
338 return ret == 0 ? 0 : 1; 355 if (read)
356 ret = nand_read(nand, off, &size, (u_char *)addr);
357 else
358 ret = nand_write(nand, off, &size, (u_char *)addr);
339 } 359 }
340 360
341 if (read)
342 ret = nand_read(nand, off, &size, (u_char *)addr);
343 else
344 ret = nand_write(nand, off, &size, (u_char *)addr);
345
346 printf(" %d bytes %s: %s\n", size, 361 printf(" %d bytes %s: %s\n", size,
347 read ? "read" : "written", ret ? "ERROR" : "OK"); 362 read ? "read" : "written", ret ? "ERROR" : "OK");
348 363
349 return ret == 0 ? 0 : 1; 364 return ret == 0 ? 0 : 1;
350 } 365 }
351 366
352 if (strcmp(cmd, "markbad") == 0) { 367 if (strcmp(cmd, "markbad") == 0) {
353 addr = (ulong)simple_strtoul(argv[2], NULL, 16); 368 addr = (ulong)simple_strtoul(argv[2], NULL, 16);
354 369
355 int ret = nand->block_markbad(nand, addr); 370 int ret = nand->block_markbad(nand, addr);
356 if (ret == 0) { 371 if (ret == 0) {
357 printf("block 0x%08lx successfully marked as bad\n", 372 printf("block 0x%08lx successfully marked as bad\n",
358 (ulong) addr); 373 (ulong) addr);
359 return 0; 374 return 0;
360 } else { 375 } else {
361 printf("block 0x%08lx NOT marked as bad! ERROR %d\n", 376 printf("block 0x%08lx NOT marked as bad! ERROR %d\n",
362 (ulong) addr, ret); 377 (ulong) addr, ret);
363 } 378 }
364 return 1; 379 return 1;
365 } 380 }
366 if (strcmp(cmd, "biterr") == 0) { 381 if (strcmp(cmd, "biterr") == 0) {
367 /* todo */ 382 /* todo */
368 return 1; 383 return 1;
369 } 384 }
370 385
371 if (strcmp(cmd, "lock") == 0) { 386 if (strcmp(cmd, "lock") == 0) {
372 int tight = 0; 387 int tight = 0;
373 int status = 0; 388 int status = 0;
374 if (argc == 3) { 389 if (argc == 3) {
375 if (!strcmp("tight", argv[2])) 390 if (!strcmp("tight", argv[2]))
376 tight = 1; 391 tight = 1;
377 if (!strcmp("status", argv[2])) 392 if (!strcmp("status", argv[2]))
378 status = 1; 393 status = 1;
379 } 394 }
380 395
381 if (status) { 396 if (status) {
382 ulong block_start = 0; 397 ulong block_start = 0;
383 ulong off; 398 ulong off;
384 int last_status = -1; 399 int last_status = -1;
385 400
386 struct nand_chip *nand_chip = nand->priv; 401 struct nand_chip *nand_chip = nand->priv;
387 /* check the WP bit */ 402 /* check the WP bit */
388 nand_chip->cmdfunc (nand, NAND_CMD_STATUS, -1, -1); 403 nand_chip->cmdfunc (nand, NAND_CMD_STATUS, -1, -1);
389 printf("device is %swrite protected\n", 404 printf("device is %swrite protected\n",
390 (nand_chip->read_byte(nand) & 0x80 ? 405 (nand_chip->read_byte(nand) & 0x80 ?
391 "NOT " : "" ) ); 406 "NOT " : "" ) );
392 407
393 for (off = 0; off < nand->size; off += nand->oobblock) { 408 for (off = 0; off < nand->size; off += nand->oobblock) {
394 int s = nand_get_lock_status(nand, off); 409 int s = nand_get_lock_status(nand, off);
395 410
396 /* print message only if status has changed 411 /* print message only if status has changed
397 * or at end of chip 412 * or at end of chip
398 */ 413 */
399 if (off == nand->size - nand->oobblock 414 if (off == nand->size - nand->oobblock
400 || (s != last_status && off != 0)) { 415 || (s != last_status && off != 0)) {
401 416
402 printf("%08x - %08x: %8d pages %s%s%s\n", 417 printf("%08x - %08x: %8d pages %s%s%s\n",
403 block_start, 418 block_start,
404 off-1, 419 off-1,
405 (off-block_start)/nand->oobblock, 420 (off-block_start)/nand->oobblock,
406 ((last_status & NAND_LOCK_STATUS_TIGHT) ? "TIGHT " : ""), 421 ((last_status & NAND_LOCK_STATUS_TIGHT) ? "TIGHT " : ""),
407 ((last_status & NAND_LOCK_STATUS_LOCK) ? "LOCK " : ""), 422 ((last_status & NAND_LOCK_STATUS_LOCK) ? "LOCK " : ""),
408 ((last_status & NAND_LOCK_STATUS_UNLOCK) ? "UNLOCK " : "")); 423 ((last_status & NAND_LOCK_STATUS_UNLOCK) ? "UNLOCK " : ""));
409 } 424 }
410 425
411 last_status = s; 426 last_status = s;
412 } 427 }
413 } else { 428 } else {
414 if (!nand_lock(nand, tight)) { 429 if (!nand_lock(nand, tight)) {
415 printf ("NAND flash successfully locked\n"); 430 puts("NAND flash successfully locked\n");
416 } else { 431 } else {
417 printf ("Error locking NAND flash. \n"); 432 puts("Error locking NAND flash\n");
418 return 1; 433 return 1;
419 } 434 }
420 } 435 }
421 return 0; 436 return 0;
422 } 437 }
423 438
424 if (strcmp(cmd, "unlock") == 0) { 439 if (strcmp(cmd, "unlock") == 0) {
425 if (argc == 2) { 440 if (arg_off_size(argc - 2, argv + 2, nand, &off, &size) < 0)
426 off = 0; 441 return 1;
427 size = nand->size;
428 } else {
429 arg_off_size(argc - 2, argv + 2, &off, &size,
430 nand->size);
431 }
432 442
433 if (!nand_unlock(nand, off, size)) { 443 if (!nand_unlock(nand, off, size)) {
434 printf("NAND flash successfully unlocked\n"); 444 puts("NAND flash successfully unlocked\n");
435 } else { 445 } else {
436 printf("Error unlocking NAND flash. " 446 puts("Error unlocking NAND flash, "
437 "Write and erase will probably fail\n"); 447 "write and erase will probably fail\n");
438 return 1; 448 return 1;
439 } 449 }
440 return 0; 450 return 0;
441 } 451 }
442 452
443 usage: 453 usage:
444 printf("Usage:\n%s\n", cmdtp->usage); 454 printf("Usage:\n%s\n", cmdtp->usage);
445 return 1; 455 return 1;
446 } 456 }
447 457
448 U_BOOT_CMD(nand, 5, 1, do_nand, 458 U_BOOT_CMD(nand, 5, 1, do_nand,
449 "nand - NAND sub-system\n", 459 "nand - NAND sub-system\n",
450 "info - show available NAND devices\n" 460 "info - show available NAND devices\n"
451 "nand device [dev] - show or set current device\n" 461 "nand device [dev] - show or set current device\n"
452 "nand read[.jffs2] - addr off size\n" 462 "nand read[.jffs2] - addr off|partition size\n"
453 "nand write[.jffs2] - addr off size - read/write `size' bytes starting\n" 463 "nand write[.jffs2] - addr off|partiton size - read/write `size' bytes starting\n"
454 " at offset `off' to/from memory address `addr'\n" 464 " at offset `off' to/from memory address `addr'\n"
455 "nand erase [clean] [off size] - erase `size' bytes from\n" 465 "nand erase [clean] [off size] - erase `size' bytes from\n"
456 " offset `off' (entire device if not specified)\n" 466 " offset `off' (entire device if not specified)\n"
457 "nand bad - show bad blocks\n" 467 "nand bad - show bad blocks\n"
458 "nand dump[.oob] off - dump page\n" 468 "nand dump[.oob] off - dump page\n"
459 "nand scrub - really clean NAND erasing bad blocks (UNSAFE)\n" 469 "nand scrub - really clean NAND erasing bad blocks (UNSAFE)\n"
460 "nand markbad off - mark bad block at offset (UNSAFE)\n" 470 "nand markbad off - mark bad block at offset (UNSAFE)\n"
461 "nand biterr off - make a bit error at offset (UNSAFE)\n" 471 "nand biterr off - make a bit error at offset (UNSAFE)\n"
462 "nand lock [tight] [status] - bring nand to lock state or display locked pages\n" 472 "nand lock [tight] [status] - bring nand to lock state or display locked pages\n"
463 "nand unlock [offset] [size] - unlock section\n"); 473 "nand unlock [offset] [size] - unlock section\n");
464 474
465 int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) 475 static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand,
476 ulong offset, ulong addr, char *cmd)
466 { 477 {
467 char *boot_device = NULL;
468 char *ep;
469 int dev;
470 int r; 478 int r;
471 ulong addr, cnt, offset = 0; 479 char *ep;
480 ulong cnt;
472 image_header_t *hdr; 481 image_header_t *hdr;
473 nand_info_t *nand;
474 482
475 switch (argc) { 483 printf("\nLoading from %s, offset 0x%lx\n", nand->name, offset);
476 case 1:
477 addr = CFG_LOAD_ADDR;
478 boot_device = getenv("bootdevice");
479 break;
480 case 2:
481 addr = simple_strtoul(argv[1], NULL, 16);
482 boot_device = getenv("bootdevice");
483 break;
484 case 3:
485 addr = simple_strtoul(argv[1], NULL, 16);
486 boot_device = argv[2];
487 break;
488 case 4:
489 addr = simple_strtoul(argv[1], NULL, 16);
490 boot_device = argv[2];
491 offset = simple_strtoul(argv[3], NULL, 16);
492 break;
493 default:
494 printf("Usage:\n%s\n", cmdtp->usage);
495 SHOW_BOOT_PROGRESS(-1);
496 return 1;
497 }
498 484
499 if (!boot_device) {
500 puts("\n** No boot device **\n");
501 SHOW_BOOT_PROGRESS(-1);
502 return 1;
503 }
504
505 dev = simple_strtoul(boot_device, &ep, 16);
506
507 if (dev < 0 || dev >= CFG_MAX_NAND_DEVICE || !nand_info[dev].name) {
508 printf("\n** Device %d not available\n", dev);
509 SHOW_BOOT_PROGRESS(-1);
510 return 1;
511 }
512
513 nand = &nand_info[dev];
514 printf("\nLoading from device %d: %s (offset 0x%lx)\n",
515 dev, nand->name, offset);
516
517 cnt = nand->oobblock; 485 cnt = nand->oobblock;
518 r = nand_read(nand, offset, &cnt, (u_char *) addr); 486 r = nand_read(nand, offset, &cnt, (u_char *) addr);
519 if (r) { 487 if (r) {
520 printf("** Read error on %d\n", dev); 488 puts("** Read error\n");
521 SHOW_BOOT_PROGRESS(-1); 489 SHOW_BOOT_PROGRESS(-1);
522 return 1; 490 return 1;
523 } 491 }
524 492
525 hdr = (image_header_t *) addr; 493 hdr = (image_header_t *) addr;
526 494
527 if (ntohl(hdr->ih_magic) != IH_MAGIC) { 495 if (ntohl(hdr->ih_magic) != IH_MAGIC) {
528 printf("\n** Bad Magic Number 0x%x **\n", hdr->ih_magic); 496 printf("\n** Bad Magic Number 0x%x **\n", hdr->ih_magic);
529 SHOW_BOOT_PROGRESS(-1); 497 SHOW_BOOT_PROGRESS(-1);
530 return 1; 498 return 1;
531 } 499 }
532 500
533 print_image_hdr(hdr); 501 print_image_hdr(hdr);
534 502
535 cnt = (ntohl(hdr->ih_size) + sizeof (image_header_t)); 503 cnt = (ntohl(hdr->ih_size) + sizeof (image_header_t));
536 504
537 r = nand_read(nand, offset, &cnt, (u_char *) addr); 505 r = nand_read(nand, offset, &cnt, (u_char *) addr);
538 if (r) { 506 if (r) {
539 printf("** Read error on %d\n", dev); 507 puts("** Read error\n");
540 SHOW_BOOT_PROGRESS(-1); 508 SHOW_BOOT_PROGRESS(-1);
541 return 1; 509 return 1;
542 } 510 }
543 511
544 /* Loading ok, update default load address */ 512 /* Loading ok, update default load address */
545 513
546 load_addr = addr; 514 load_addr = addr;
547 515
548 /* Check if we should attempt an auto-start */ 516 /* Check if we should attempt an auto-start */
549 if (((ep = getenv("autostart")) != NULL) && (strcmp(ep, "yes") == 0)) { 517 if (((ep = getenv("autostart")) != NULL) && (strcmp(ep, "yes") == 0)) {
550 char *local_args[2]; 518 char *local_args[2];
551 extern int do_bootm(cmd_tbl_t *, int, int, char *[]); 519 extern int do_bootm(cmd_tbl_t *, int, int, char *[]);
552 520
553 local_args[0] = argv[0]; 521 local_args[0] = cmd;
554 local_args[1] = NULL; 522 local_args[1] = NULL;
555 523
556 printf("Automatic boot of image at addr 0x%08lx ...\n", addr); 524 printf("Automatic boot of image at addr 0x%08lx ...\n", addr);
557 525
558 do_bootm(cmdtp, 0, 1, local_args); 526 do_bootm(cmdtp, 0, 1, local_args);
559 return 1; 527 return 1;
560 } 528 }
561 return 0; 529 return 0;
562 } 530 }
563 531
564 U_BOOT_CMD(nboot, 4, 1, do_nandboot, 532 int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
565 "nboot - boot from NAND device\n", "loadAddr dev\n"); 533 {
534 char *boot_device = NULL;
535 int idx;
536 ulong addr, offset = 0;
537 #if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
538 struct mtd_device *dev;
539 struct part_info *part;
540 u8 pnum;
566 541
542 if (argc >= 2) {
543 char *p = (argc == 2) ? argv[1] : argv[2];
544 if (!(str2long(p, &addr)) && (mtdparts_init() == 0) &&
545 (find_dev_and_part(p, &dev, &pnum, &part) == 0)) {
546 if (dev->id->type != MTD_DEV_TYPE_NAND) {
547 puts("Not a NAND device\n");
548 return 1;
549 }
550 if (argc > 3)
551 goto usage;
552 if (argc == 3)
553 addr = simple_strtoul(argv[2], NULL, 16);
554 else
555 addr = CFG_LOAD_ADDR;
556 return nand_load_image(cmdtp, &nand_info[dev->id->num],
557 part->offset, addr, argv[0]);
558 }
559 }
560 #endif
561
562 switch (argc) {
563 case 1:
564 addr = CFG_LOAD_ADDR;
565 boot_device = getenv("bootdevice");
566 break;
567 case 2:
568 addr = simple_strtoul(argv[1], NULL, 16);
569 boot_device = getenv("bootdevice");
570 break;
571 case 3:
572 addr = simple_strtoul(argv[1], NULL, 16);
573 boot_device = argv[2];
574 break;
575 case 4:
576 addr = simple_strtoul(argv[1], NULL, 16);
577 boot_device = argv[2];
578 offset = simple_strtoul(argv[3], NULL, 16);
579 break;
580 default:
581 #if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
582 usage:
583 #endif
584 printf("Usage:\n%s\n", cmdtp->usage);
585 SHOW_BOOT_PROGRESS(-1);
586 return 1;
587 }
588
589 if (!boot_device) {
590 puts("\n** No boot device **\n");
591 SHOW_BOOT_PROGRESS(-1);
592 return 1;
593 }
594
595 idx = simple_strtoul(boot_device, NULL, 16);
596
597 if (idx < 0 || idx >= CFG_MAX_NAND_DEVICE || !nand_info[idx].name) {
598 printf("\n** Device %d not available\n", idx);
599 SHOW_BOOT_PROGRESS(-1);
600 return 1;
601 }
602
603 return nand_load_image(cmdtp, &nand_info[idx], offset, addr, argv[0]);
604 }
605
606 U_BOOT_CMD(nboot, 4, 1, do_nandboot,
607 "nboot - boot from NAND device\n",
608 "[partition] | [[[loadAddr] dev] offset]\n");
567 609
568 #endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */ 610 #endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */
569 611
570 #else /* CFG_NAND_LEGACY */ 612 #else /* CFG_NAND_LEGACY */
571 /* 613 /*
572 * 614 *
573 * Legacy NAND support - to be phased out 615 * Legacy NAND support - to be phased out
574 * 616 *
575 */ 617 */
576 #include <command.h> 618 #include <command.h>
577 #include <malloc.h> 619 #include <malloc.h>
578 #include <asm/io.h> 620 #include <asm/io.h>
579 #include <watchdog.h> 621 #include <watchdog.h>
580 622
581 #ifdef CONFIG_SHOW_BOOT_PROGRESS 623 #ifdef CONFIG_SHOW_BOOT_PROGRESS
582 # include <status_led.h> 624 # include <status_led.h>
583 # define SHOW_BOOT_PROGRESS(arg) show_boot_progress(arg) 625 # define SHOW_BOOT_PROGRESS(arg) show_boot_progress(arg)
584 #else 626 #else
585 # define SHOW_BOOT_PROGRESS(arg) 627 # define SHOW_BOOT_PROGRESS(arg)
586 #endif 628 #endif
587 629
588 #if (CONFIG_COMMANDS & CFG_CMD_NAND) 630 #if (CONFIG_COMMANDS & CFG_CMD_NAND)
589 #include <linux/mtd/nand_legacy.h> 631 #include <linux/mtd/nand_legacy.h>
590 #if 0 632 #if 0
591 #include <linux/mtd/nand_ids.h> 633 #include <linux/mtd/nand_ids.h>
592 #include <jffs2/jffs2.h> 634 #include <jffs2/jffs2.h>
593 #endif 635 #endif
594 636
595 #ifdef CONFIG_OMAP1510 637 #ifdef CONFIG_OMAP1510
596 void archflashwp(void *archdata, int wp); 638 void archflashwp(void *archdata, int wp);
597 #endif 639 #endif
598 640
599 #define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1))) 641 #define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1)))
600 642
601 #undef NAND_DEBUG 643 #undef NAND_DEBUG
602 #undef PSYCHO_DEBUG 644 #undef PSYCHO_DEBUG
603 645
604 /* ****************** WARNING ********************* 646 /* ****************** WARNING *********************
605 * When ALLOW_ERASE_BAD_DEBUG is non-zero the erase command will 647 * When ALLOW_ERASE_BAD_DEBUG is non-zero the erase command will
606 * erase (or at least attempt to erase) blocks that are marked 648 * erase (or at least attempt to erase) blocks that are marked
607 * bad. This can be very handy if you are _sure_ that the block 649 * bad. This can be very handy if you are _sure_ that the block
608 * is OK, say because you marked a good block bad to test bad 650 * is OK, say because you marked a good block bad to test bad
609 * block handling and you are done testing, or if you have 651 * block handling and you are done testing, or if you have
610 * accidentally marked blocks bad. 652 * accidentally marked blocks bad.
611 * 653 *
612 * Erasing factory marked bad blocks is a _bad_ idea. If the 654 * Erasing factory marked bad blocks is a _bad_ idea. If the
613 * erase succeeds there is no reliable way to find them again, 655 * erase succeeds there is no reliable way to find them again,
614 * and attempting to program or erase bad blocks can affect 656 * and attempting to program or erase bad blocks can affect
615 * the data in _other_ (good) blocks. 657 * the data in _other_ (good) blocks.
616 */ 658 */
617 #define ALLOW_ERASE_BAD_DEBUG 0 659 #define ALLOW_ERASE_BAD_DEBUG 0
618 660
619 #define CONFIG_MTD_NAND_ECC /* enable ECC */ 661 #define CONFIG_MTD_NAND_ECC /* enable ECC */
620 #define CONFIG_MTD_NAND_ECC_JFFS2 662 #define CONFIG_MTD_NAND_ECC_JFFS2
621 663
622 /* bits for nand_legacy_rw() `cmd'; or together as needed */ 664 /* bits for nand_legacy_rw() `cmd'; or together as needed */
623 #define NANDRW_READ 0x01 665 #define NANDRW_READ 0x01
624 #define NANDRW_WRITE 0x00 666 #define NANDRW_WRITE 0x00
625 #define NANDRW_JFFS2 0x02 667 #define NANDRW_JFFS2 0x02
626 #define NANDRW_JFFS2_SKIP 0x04 668 #define NANDRW_JFFS2_SKIP 0x04
627 669
628 /* 670 /*
629 * Imports from nand_legacy.c 671 * Imports from nand_legacy.c
630 */ 672 */
631 extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE]; 673 extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
632 extern int curr_device; 674 extern int curr_device;
633 extern int nand_legacy_erase(struct nand_chip *nand, size_t ofs, 675 extern int nand_legacy_erase(struct nand_chip *nand, size_t ofs,
634 size_t len, int clean); 676 size_t len, int clean);
635 extern int nand_legacy_rw(struct nand_chip *nand, int cmd, size_t start, 677 extern int nand_legacy_rw(struct nand_chip *nand, int cmd, size_t start,
636 size_t len, size_t *retlen, u_char *buf); 678 size_t len, size_t *retlen, u_char *buf);
637 extern void nand_print(struct nand_chip *nand); 679 extern void nand_print(struct nand_chip *nand);
638 extern void nand_print_bad(struct nand_chip *nand); 680 extern void nand_print_bad(struct nand_chip *nand);
639 extern int nand_read_oob(struct nand_chip *nand, size_t ofs, 681 extern int nand_read_oob(struct nand_chip *nand, size_t ofs,
640 size_t len, size_t *retlen, u_char *buf); 682 size_t len, size_t *retlen, u_char *buf);
641 extern int nand_write_oob(struct nand_chip *nand, size_t ofs, 683 extern int nand_write_oob(struct nand_chip *nand, size_t ofs,
642 size_t len, size_t *retlen, const u_char *buf); 684 size_t len, size_t *retlen, const u_char *buf);
643 685
644 686
645 int do_nand (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) 687 int do_nand (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
646 { 688 {
647 int rcode = 0; 689 int rcode = 0;
648 690
649 switch (argc) { 691 switch (argc) {
650 case 0: 692 case 0:
651 case 1: 693 case 1:
652 printf ("Usage:\n%s\n", cmdtp->usage); 694 printf ("Usage:\n%s\n", cmdtp->usage);
653 return 1; 695 return 1;
654 case 2: 696 case 2:
655 if (strcmp(argv[1],"info") == 0) { 697 if (strcmp(argv[1],"info") == 0) {
656 int i; 698 int i;
657 699
658 putc ('\n'); 700 putc ('\n');
659 701
660 for (i=0; i<CFG_MAX_NAND_DEVICE; ++i) { 702 for (i=0; i<CFG_MAX_NAND_DEVICE; ++i) {
661 if(nand_dev_desc[i].ChipID == NAND_ChipID_UNKNOWN) 703 if(nand_dev_desc[i].ChipID == NAND_ChipID_UNKNOWN)
662 continue; /* list only known devices */ 704 continue; /* list only known devices */
663 printf ("Device %d: ", i); 705 printf ("Device %d: ", i);
664 nand_print(&nand_dev_desc[i]); 706 nand_print(&nand_dev_desc[i]);
665 } 707 }
666 return 0; 708 return 0;
667 709
668 } else if (strcmp(argv[1],"device") == 0) { 710 } else if (strcmp(argv[1],"device") == 0) {
669 if ((curr_device < 0) || (curr_device >= CFG_MAX_NAND_DEVICE)) { 711 if ((curr_device < 0) || (curr_device >= CFG_MAX_NAND_DEVICE)) {
670 puts ("\nno devices available\n"); 712 puts ("\nno devices available\n");
671 return 1; 713 return 1;
672 } 714 }
673 printf ("\nDevice %d: ", curr_device); 715 printf ("\nDevice %d: ", curr_device);
674 nand_print(&nand_dev_desc[curr_device]); 716 nand_print(&nand_dev_desc[curr_device]);
675 return 0; 717 return 0;
676 718
677 } else if (strcmp(argv[1],"bad") == 0) { 719 } else if (strcmp(argv[1],"bad") == 0) {
678 if ((curr_device < 0) || (curr_device >= CFG_MAX_NAND_DEVICE)) { 720 if ((curr_device < 0) || (curr_device >= CFG_MAX_NAND_DEVICE)) {
679 puts ("\nno devices available\n"); 721 puts ("\nno devices available\n");
680 return 1; 722 return 1;
681 } 723 }
682 printf ("\nDevice %d bad blocks:\n", curr_device); 724 printf ("\nDevice %d bad blocks:\n", curr_device);
683 nand_print_bad(&nand_dev_desc[curr_device]); 725 nand_print_bad(&nand_dev_desc[curr_device]);
684 return 0; 726 return 0;
685 727
686 } 728 }
687 printf ("Usage:\n%s\n", cmdtp->usage); 729 printf ("Usage:\n%s\n", cmdtp->usage);
688 return 1; 730 return 1;
689 case 3: 731 case 3:
690 if (strcmp(argv[1],"device") == 0) { 732 if (strcmp(argv[1],"device") == 0) {
691 int dev = (int)simple_strtoul(argv[2], NULL, 10); 733 int dev = (int)simple_strtoul(argv[2], NULL, 10);
692 734
693 printf ("\nDevice %d: ", dev); 735 printf ("\nDevice %d: ", dev);
694 if (dev >= CFG_MAX_NAND_DEVICE) { 736 if (dev >= CFG_MAX_NAND_DEVICE) {
695 puts ("unknown device\n"); 737 puts ("unknown device\n");
696 return 1; 738 return 1;
697 } 739 }
698 nand_print(&nand_dev_desc[dev]); 740 nand_print(&nand_dev_desc[dev]);
699 /*nand_print (dev);*/ 741 /*nand_print (dev);*/
700 742
701 if (nand_dev_desc[dev].ChipID == NAND_ChipID_UNKNOWN) { 743 if (nand_dev_desc[dev].ChipID == NAND_ChipID_UNKNOWN) {
702 return 1; 744 return 1;
703 } 745 }
704 746
705 curr_device = dev; 747 curr_device = dev;
706 748
707 puts ("... is now current device\n"); 749 puts ("... is now current device\n");
708 750
709 return 0; 751 return 0;
710 } 752 }
711 else if (strcmp(argv[1],"erase") == 0 && strcmp(argv[2], "clean") == 0) { 753 else if (strcmp(argv[1],"erase") == 0 && strcmp(argv[2], "clean") == 0) {
712 struct nand_chip* nand = &nand_dev_desc[curr_device]; 754 struct nand_chip* nand = &nand_dev_desc[curr_device];
713 ulong off = 0; 755 ulong off = 0;
714 ulong size = nand->totlen; 756 ulong size = nand->totlen;
715 int ret; 757 int ret;
716 758
717 printf ("\nNAND erase: device %d offset %ld, size %ld ... ", 759 printf ("\nNAND erase: device %d offset %ld, size %ld ... ",
718 curr_device, off, size); 760 curr_device, off, size);
719 761
720 ret = nand_legacy_erase (nand, off, size, 1); 762 ret = nand_legacy_erase (nand, off, size, 1);
721 763
722 printf("%s\n", ret ? "ERROR" : "OK"); 764 printf("%s\n", ret ? "ERROR" : "OK");
723 765
724 return ret; 766 return ret;
725 } 767 }
726 768
727 printf ("Usage:\n%s\n", cmdtp->usage); 769 printf ("Usage:\n%s\n", cmdtp->usage);
728 return 1; 770 return 1;
729 default: 771 default:
730 /* at least 4 args */ 772 /* at least 4 args */
731 773
732 if (strncmp(argv[1], "read", 4) == 0 || 774 if (strncmp(argv[1], "read", 4) == 0 ||
733 strncmp(argv[1], "write", 5) == 0) { 775 strncmp(argv[1], "write", 5) == 0) {
734 ulong addr = simple_strtoul(argv[2], NULL, 16); 776 ulong addr = simple_strtoul(argv[2], NULL, 16);
735 ulong off = simple_strtoul(argv[3], NULL, 16); 777 ulong off = simple_strtoul(argv[3], NULL, 16);
736 ulong size = simple_strtoul(argv[4], NULL, 16); 778 ulong size = simple_strtoul(argv[4], NULL, 16);
737 int cmd = (strncmp(argv[1], "read", 4) == 0) ? 779 int cmd = (strncmp(argv[1], "read", 4) == 0) ?
738 NANDRW_READ : NANDRW_WRITE; 780 NANDRW_READ : NANDRW_WRITE;
739 int ret, total; 781 int ret, total;
740 char* cmdtail = strchr(argv[1], '.'); 782 char* cmdtail = strchr(argv[1], '.');
741 783
742 if (cmdtail && !strncmp(cmdtail, ".oob", 2)) { 784 if (cmdtail && !strncmp(cmdtail, ".oob", 2)) {
743 /* read out-of-band data */ 785 /* read out-of-band data */
744 if (cmd & NANDRW_READ) { 786 if (cmd & NANDRW_READ) {
745 ret = nand_read_oob(nand_dev_desc + curr_device, 787 ret = nand_read_oob(nand_dev_desc + curr_device,
746 off, size, (size_t *)&total, 788 off, size, (size_t *)&total,
747 (u_char*)addr); 789 (u_char*)addr);
748 } 790 }
749 else { 791 else {
750 ret = nand_write_oob(nand_dev_desc + curr_device, 792 ret = nand_write_oob(nand_dev_desc + curr_device,
751 off, size, (size_t *)&total, 793 off, size, (size_t *)&total,
752 (u_char*)addr); 794 (u_char*)addr);
753 } 795 }
754 return ret; 796 return ret;
755 } 797 }
756 else if (cmdtail && !strncmp(cmdtail, ".jffs2", 2)) 798 else if (cmdtail && !strncmp(cmdtail, ".jffs2", 2))
757 cmd |= NANDRW_JFFS2; /* skip bad blocks */ 799 cmd |= NANDRW_JFFS2; /* skip bad blocks */
758 else if (cmdtail && !strncmp(cmdtail, ".jffs2s", 2)) { 800 else if (cmdtail && !strncmp(cmdtail, ".jffs2s", 2)) {
759 cmd |= NANDRW_JFFS2; /* skip bad blocks (on read too) */ 801 cmd |= NANDRW_JFFS2; /* skip bad blocks (on read too) */
760 if (cmd & NANDRW_READ) 802 if (cmd & NANDRW_READ)
761 cmd |= NANDRW_JFFS2_SKIP; /* skip bad blocks (on read too) */ 803 cmd |= NANDRW_JFFS2_SKIP; /* skip bad blocks (on read too) */
762 } 804 }
763 #ifdef SXNI855T 805 #ifdef SXNI855T
764 /* need ".e" same as ".j" for compatibility with older units */ 806 /* need ".e" same as ".j" for compatibility with older units */
765 else if (cmdtail && !strcmp(cmdtail, ".e")) 807 else if (cmdtail && !strcmp(cmdtail, ".e"))
766 cmd |= NANDRW_JFFS2; /* skip bad blocks */ 808 cmd |= NANDRW_JFFS2; /* skip bad blocks */
767 #endif 809 #endif
768 #ifdef CFG_NAND_SKIP_BAD_DOT_I 810 #ifdef CFG_NAND_SKIP_BAD_DOT_I
769 /* need ".i" same as ".jffs2s" for compatibility with older units (esd) */ 811 /* need ".i" same as ".jffs2s" for compatibility with older units (esd) */
770 /* ".i" for image -> read skips bad block (no 0xff) */ 812 /* ".i" for image -> read skips bad block (no 0xff) */
771 else if (cmdtail && !strcmp(cmdtail, ".i")) { 813 else if (cmdtail && !strcmp(cmdtail, ".i")) {
772 cmd |= NANDRW_JFFS2; /* skip bad blocks (on read too) */ 814 cmd |= NANDRW_JFFS2; /* skip bad blocks (on read too) */
773 if (cmd & NANDRW_READ) 815 if (cmd & NANDRW_READ)
774 cmd |= NANDRW_JFFS2_SKIP; /* skip bad blocks (on read too) */ 816 cmd |= NANDRW_JFFS2_SKIP; /* skip bad blocks (on read too) */
775 } 817 }
776 #endif /* CFG_NAND_SKIP_BAD_DOT_I */ 818 #endif /* CFG_NAND_SKIP_BAD_DOT_I */
777 else if (cmdtail) { 819 else if (cmdtail) {
778 printf ("Usage:\n%s\n", cmdtp->usage); 820 printf ("Usage:\n%s\n", cmdtp->usage);
779 return 1; 821 return 1;
780 } 822 }
781 823
782 printf ("\nNAND %s: device %d offset %ld, size %ld ...\n", 824 printf ("\nNAND %s: device %d offset %ld, size %ld ...\n",
783 (cmd & NANDRW_READ) ? "read" : "write", 825 (cmd & NANDRW_READ) ? "read" : "write",
784 curr_device, off, size); 826 curr_device, off, size);
785 827
786 ret = nand_legacy_rw(nand_dev_desc + curr_device, cmd, off, size, 828 ret = nand_legacy_rw(nand_dev_desc + curr_device, cmd, off, size,
787 (size_t *)&total, (u_char*)addr); 829 (size_t *)&total, (u_char*)addr);
788 830
789 printf (" %d bytes %s: %s\n", total, 831 printf (" %d bytes %s: %s\n", total,
790 (cmd & NANDRW_READ) ? "read" : "written", 832 (cmd & NANDRW_READ) ? "read" : "written",
791 ret ? "ERROR" : "OK"); 833 ret ? "ERROR" : "OK");
792 834
793 return ret; 835 return ret;
794 } else if (strcmp(argv[1],"erase") == 0 && 836 } else if (strcmp(argv[1],"erase") == 0 &&
795 (argc == 4 || strcmp("clean", argv[2]) == 0)) { 837 (argc == 4 || strcmp("clean", argv[2]) == 0)) {
796 int clean = argc == 5; 838 int clean = argc == 5;
797 ulong off = simple_strtoul(argv[2 + clean], NULL, 16); 839 ulong off = simple_strtoul(argv[2 + clean], NULL, 16);
798 ulong size = simple_strtoul(argv[3 + clean], NULL, 16); 840 ulong size = simple_strtoul(argv[3 + clean], NULL, 16);
799 int ret; 841 int ret;
800 842
801 printf ("\nNAND erase: device %d offset %ld, size %ld ...\n", 843 printf ("\nNAND erase: device %d offset %ld, size %ld ...\n",
802 curr_device, off, size); 844 curr_device, off, size);
803 845
804 ret = nand_legacy_erase (nand_dev_desc + curr_device, 846 ret = nand_legacy_erase (nand_dev_desc + curr_device,
805 off, size, clean); 847 off, size, clean);
806 848
807 printf("%s\n", ret ? "ERROR" : "OK"); 849 printf("%s\n", ret ? "ERROR" : "OK");
808 850
809 return ret; 851 return ret;
810 } else { 852 } else {
811 printf ("Usage:\n%s\n", cmdtp->usage); 853 printf ("Usage:\n%s\n", cmdtp->usage);
812 rcode = 1; 854 rcode = 1;
813 } 855 }
814 856
815 return rcode; 857 return rcode;
816 } 858 }
817 } 859 }
818 860
819 U_BOOT_CMD( 861 U_BOOT_CMD(
820 nand, 5, 1, do_nand, 862 nand, 5, 1, do_nand,
821 "nand - legacy NAND sub-system\n", 863 "nand - legacy NAND sub-system\n",
822 "info - show available NAND devices\n" 864 "info - show available NAND devices\n"
823 "nand device [dev] - show or set current device\n" 865 "nand device [dev] - show or set current device\n"
824 "nand read[.jffs2[s]] addr off size\n" 866 "nand read[.jffs2[s]] addr off size\n"
825 "nand write[.jffs2] addr off size - read/write `size' bytes starting\n" 867 "nand write[.jffs2] addr off size - read/write `size' bytes starting\n"
826 " at offset `off' to/from memory address `addr'\n" 868 " at offset `off' to/from memory address `addr'\n"
827 "nand erase [clean] [off size] - erase `size' bytes from\n" 869 "nand erase [clean] [off size] - erase `size' bytes from\n"
828 " offset `off' (entire device if not specified)\n" 870 " offset `off' (entire device if not specified)\n"
829 "nand bad - show bad blocks\n" 871 "nand bad - show bad blocks\n"
830 "nand read.oob addr off size - read out-of-band data\n" 872 "nand read.oob addr off size - read out-of-band data\n"
831 "nand write.oob addr off size - read out-of-band data\n" 873 "nand write.oob addr off size - read out-of-band data\n"
832 ); 874 );
833 875
834 int do_nandboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) 876 int do_nandboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
835 { 877 {
836 char *boot_device = NULL; 878 char *boot_device = NULL;
837 char *ep; 879 char *ep;
838 int dev; 880 int dev;
839 ulong cnt; 881 ulong cnt;
840 ulong addr; 882 ulong addr;
841 ulong offset = 0; 883 ulong offset = 0;
842 image_header_t *hdr; 884 image_header_t *hdr;
843 int rcode = 0; 885 int rcode = 0;
844 switch (argc) { 886 switch (argc) {
845 case 1: 887 case 1:
846 addr = CFG_LOAD_ADDR; 888 addr = CFG_LOAD_ADDR;
847 boot_device = getenv ("bootdevice"); 889 boot_device = getenv ("bootdevice");
848 break; 890 break;
849 case 2: 891 case 2:
850 addr = simple_strtoul(argv[1], NULL, 16); 892 addr = simple_strtoul(argv[1], NULL, 16);
851 boot_device = getenv ("bootdevice"); 893 boot_device = getenv ("bootdevice");
852 break; 894 break;
853 case 3: 895 case 3:
854 addr = simple_strtoul(argv[1], NULL, 16); 896 addr = simple_strtoul(argv[1], NULL, 16);
855 boot_device = argv[2]; 897 boot_device = argv[2];
856 break; 898 break;
857 case 4: 899 case 4:
cpu/arm925t/omap925.c
1 /* 1 /*
2 * (C) Copyright 2003 2 * (C) Copyright 2003
3 * Texas Instruments <www.ti.com> 3 * Texas Instruments <www.ti.com>
4 * 4 *
5 * See file CREDITS for list of people who contributed to this 5 * See file CREDITS for list of people who contributed to this
6 * project. 6 * project.
7 * 7 *
8 * This program is free software; you can redistribute it and/or 8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as 9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of 10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version. 11 * the License, or (at your option) any later version.
12 * 12 *
13 * This program is distributed in the hope that it will be useful, 13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details. 16 * GNU General Public License for more details.
17 * 17 *
18 * You should have received a copy of the GNU General Public License 18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software 19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA 21 * MA 02111-1307 USA
22 */ 22 */
23 23
24 #include <common.h> 24 #include <common.h>
25 #include <command.h> 25 #include <command.h>
26 #include <arm925t.h> 26 #include <arm925t.h>
27 27
28 ushort gpioreserved;
29
30 void gpioreserve(ushort mask)
31 {
32 gpioreserved |= mask;
33 }
34
35 void gpiosetdir(ushort mask, ushort in)
36 {
37 *(ushort *)GPIO_DIR_CONTROL_REG = (*(ushort *)GPIO_DIR_CONTROL_REG & ~mask) | (in & mask);
38 }
39
40
41 void gpiosetout(ushort mask, ushort out)
42 {
43 ushort *r_ptr, r_val;
44
45 r_ptr = (ushort *)GPIO_DATA_OUTPUT_REG; /* set pointer */
46 r_val = *r_ptr & ~mask; /* get previous val, clear bits we want to change */
47 r_val |= (out & mask); /* set specified bits in value + plus origional ones */
48 *r_ptr = r_val; /* write it out */
49 /*
50 * gcc screwed this one up :(.
51 *
52 * *(ushort *)GPIO_DATA_OUTPUT_REG = (*(ushort *)GPIO_DATA_OUTPUT_REG & ~mask) | (out & mask);
53 */
54
55 }
56
57 void gpioinit(void)
58 {
59 }
60
61
62 #define MIF_CONFIG_REG 0xFFFECC0C 28 #define MIF_CONFIG_REG 0xFFFECC0C
63 #define FLASH_GLOBAL_CTRL_NWP 1 29 #define FLASH_GLOBAL_CTRL_NWP 1
64 30
65 void archflashwp (void *archdata, int wp) 31 void archflashwp (void *archdata, int wp)
66 { 32 {
67 ulong *fgc = (ulong *) MIF_CONFIG_REG; 33 ulong *fgc = (ulong *) MIF_CONFIG_REG;
68 34
69 if (wp == 1) 35 if (wp == 1)
70 *fgc &= ~FLASH_GLOBAL_CTRL_NWP; 36 *fgc &= ~FLASH_GLOBAL_CTRL_NWP;
71 else 37 else
72 *fgc |= FLASH_GLOBAL_CTRL_NWP; 38 *fgc |= FLASH_GLOBAL_CTRL_NWP;
73 } 39 }
74 40
1 NAND FLASH commands and notes 1 NAND FLASH commands and notes
2 2
3 See NOTE below!!! 3 See NOTE below!!!
4 4
5 # (C) Copyright 2003 5 # (C) Copyright 2003
6 # Dave Ellis, SIXNET, dge@sixnetio.com 6 # Dave Ellis, SIXNET, dge@sixnetio.com
7 # 7 #
8 # See file CREDITS for list of people who contributed to this 8 # See file CREDITS for list of people who contributed to this
9 # project. 9 # project.
10 # 10 #
11 # This program is free software; you can redistribute it and/or 11 # This program is free software; you can redistribute it and/or
12 # modify it under the terms of the GNU General Public License as 12 # modify it under the terms of the GNU General Public License as
13 # published by the Free Software Foundation; either version 2 of 13 # published by the Free Software Foundation; either version 2 of
14 # the License, or (at your option) any later version. 14 # the License, or (at your option) any later version.
15 # 15 #
16 # This program is distributed in the hope that it will be useful, 16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details. 19 # GNU General Public License for more details.
20 # 20 #
21 # You should have received a copy of the GNU General Public License 21 # You should have received a copy of the GNU General Public License
22 # along with this program; if not, write to the Free Software 22 # along with this program; if not, write to the Free Software
23 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, 23 # Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24 # MA 02111-1307 USA 24 # MA 02111-1307 USA
25 25
26 Commands: 26 Commands:
27 27
28 nand bad 28 nand bad
29 Print a list of all of the bad blocks in the current device. 29 Print a list of all of the bad blocks in the current device.
30 30
31 nand device 31 nand device
32 Print information about the current NAND device. 32 Print information about the current NAND device.
33 33
34 nand device num 34 nand device num
35 Make device `num' the current device and print information about it. 35 Make device `num' the current device and print information about it.
36 36
37 nand erase off size 37 nand erase off|partition size
38 nand erase clean [off size] 38 nand erase clean [off|partition size]
39 Erase `size' bytes starting at offset `off'. Only complete erase 39 Erase `size' bytes starting at offset `off'. Alternatively partition
40 blocks can be erased. 40 name can be specified, in this case size will be eventually limited
41 to not exceed partition size (this behaviour applies also to read
42 and write commands). Only complete erase blocks can be erased.
41 43
44 If `erase' is specified without an offset or size, the entire flash
45 is erased. If `erase' is specified with partition but without an
46 size, the entire partition is erased.
47
42 If `clean' is specified, a JFFS2-style clean marker is written to 48 If `clean' is specified, a JFFS2-style clean marker is written to
43 each block after it is erased. If `clean' is specified without an 49 each block after it is erased.
44 offset or size, the entire flash is erased.
45 50
46 This command will not erase blocks that are marked bad. There is 51 This command will not erase blocks that are marked bad. There is
47 a debug option in cmd_nand.c to allow bad blocks to be erased. 52 a debug option in cmd_nand.c to allow bad blocks to be erased.
48 Please read the warning there before using it, as blocks marked 53 Please read the warning there before using it, as blocks marked
49 bad by the manufacturer must _NEVER_ be erased. 54 bad by the manufacturer must _NEVER_ be erased.
50 55
51 nand info 56 nand info
52 Print information about all of the NAND devices found. 57 Print information about all of the NAND devices found.
53 58
54 nand read addr ofs size 59 nand read addr ofs|partition size
55 Read `size' bytes from `ofs' in NAND flash to `addr'. If a page 60 Read `size' bytes from `ofs' in NAND flash to `addr'. If a page
56 cannot be read because it is marked bad or an uncorrectable data 61 cannot be read because it is marked bad or an uncorrectable data
57 error is found the command stops with an error. 62 error is found the command stops with an error.
58 63
59 nand read.jffs2 addr ofs size 64 nand read.jffs2 addr ofs|partition size
60 Like `read', but the data for blocks that are marked bad is read as 65 Like `read', but the data for blocks that are marked bad is read as
61 0xff. This gives a readable JFFS2 image that can be processed by 66 0xff. This gives a readable JFFS2 image that can be processed by
62 the JFFS2 commands such as ls and fsload. 67 the JFFS2 commands such as ls and fsload.
63 68
64 nand read.oob addr ofs size 69 nand read.oob addr ofs|partition size
65 Read `size' bytes from the out-of-band data area corresponding to 70 Read `size' bytes from the out-of-band data area corresponding to
66 `ofs' in NAND flash to `addr'. This is limited to the 16 bytes of 71 `ofs' in NAND flash to `addr'. This is limited to the 16 bytes of
67 data for one 512-byte page or 2 256-byte pages. There is no check 72 data for one 512-byte page or 2 256-byte pages. There is no check
68 for bad blocks or ECC errors. 73 for bad blocks or ECC errors.
69 74
70 nand write addr ofs size 75 nand write addr ofs|partition size
71 Write `size' bytes from `addr' to `ofs' in NAND flash. If a page 76 Write `size' bytes from `addr' to `ofs' in NAND flash. If a page
72 cannot be written because it is marked bad or the write fails the 77 cannot be written because it is marked bad or the write fails the
73 command stops with an error. 78 command stops with an error.
74 79
75 nand write.jffs2 addr ofs size 80 nand write.jffs2 addr ofs|partition size
76 Like `write', but blocks that are marked bad are skipped and the 81 Like `write', but blocks that are marked bad are skipped and the
77 is written to the next block instead. This allows writing writing 82 is written to the next block instead. This allows writing writing
78 a JFFS2 image, as long as the image is short enough to fit even 83 a JFFS2 image, as long as the image is short enough to fit even
79 after skipping the bad blocks. Compact images, such as those 84 after skipping the bad blocks. Compact images, such as those
80 produced by mkfs.jffs2 should work well, but loading an image copied 85 produced by mkfs.jffs2 should work well, but loading an image copied
81 from another flash is going to be trouble if there are any bad blocks. 86 from another flash is going to be trouble if there are any bad blocks.
82 87
83 nand write.oob addr ofs size 88 nand write.oob addr ofs|partition size
84 Write `size' bytes from `addr' to the out-of-band data area 89 Write `size' bytes from `addr' to the out-of-band data area
85 corresponding to `ofs' in NAND flash. This is limited to the 16 bytes 90 corresponding to `ofs' in NAND flash. This is limited to the 16 bytes
86 of data for one 512-byte page or 2 256-byte pages. There is no check 91 of data for one 512-byte page or 2 256-byte pages. There is no check
87 for bad blocks. 92 for bad blocks.
88 93
89 Configuration Options: 94 Configuration Options:
90 95
91 CFG_CMD_NAND 96 CFG_CMD_NAND
92 A good one to add to CONFIG_COMMANDS since it enables NAND support. 97 A good one to add to CONFIG_COMMANDS since it enables NAND support.
93 98
94 CONFIG_MTD_NAND_ECC_JFFS2 99 CONFIG_MTD_NAND_ECC_JFFS2
95 Define this if you want the Error Correction Code information in 100 Define this if you want the Error Correction Code information in
96 the out-of-band data to be formatted to match the JFFS2 file system. 101 the out-of-band data to be formatted to match the JFFS2 file system.
97 CONFIG_MTD_NAND_ECC_YAFFS would be another useful choice for 102 CONFIG_MTD_NAND_ECC_YAFFS would be another useful choice for
98 someone to implement. 103 someone to implement.
99 104
100 CFG_MAX_NAND_DEVICE 105 CFG_MAX_NAND_DEVICE
101 The maximum number of NAND devices you want to support. 106 The maximum number of NAND devices you want to support.
102 107
103 NAND Interface: 108 NAND Interface:
104 109
105 #define NAND_WAIT_READY(nand) 110 #define NAND_WAIT_READY(nand)
106 Wait until the NAND flash is ready. Typically this would be a 111 Wait until the NAND flash is ready. Typically this would be a
107 loop waiting for the READY/BUSY line from the flash to indicate it 112 loop waiting for the READY/BUSY line from the flash to indicate it
108 it is ready. 113 it is ready.
109 114
110 #define WRITE_NAND_COMMAND(d, adr) 115 #define WRITE_NAND_COMMAND(d, adr)
111 Write the command byte `d' to the flash at `adr' with the 116 Write the command byte `d' to the flash at `adr' with the
112 CLE (command latch enable) line true. If your board uses writes to 117 CLE (command latch enable) line true. If your board uses writes to
113 different addresses to control CLE and ALE, you can modify `adr' 118 different addresses to control CLE and ALE, you can modify `adr'
114 to be the appropriate address here. If your board uses I/O registers 119 to be the appropriate address here. If your board uses I/O registers
115 to control them, it is probably better to let NAND_CTL_SETCLE() 120 to control them, it is probably better to let NAND_CTL_SETCLE()
116 and company do it. 121 and company do it.
117 122
118 #define WRITE_NAND_ADDRESS(d, adr) 123 #define WRITE_NAND_ADDRESS(d, adr)
119 Write the address byte `d' to the flash at `adr' with the 124 Write the address byte `d' to the flash at `adr' with the
120 ALE (address latch enable) line true. If your board uses writes to 125 ALE (address latch enable) line true. If your board uses writes to
121 different addresses to control CLE and ALE, you can modify `adr' 126 different addresses to control CLE and ALE, you can modify `adr'
122 to be the appropriate address here. If your board uses I/O registers 127 to be the appropriate address here. If your board uses I/O registers
123 to control them, it is probably better to let NAND_CTL_SETALE() 128 to control them, it is probably better to let NAND_CTL_SETALE()
124 and company do it. 129 and company do it.
125 130
126 #define WRITE_NAND(d, adr) 131 #define WRITE_NAND(d, adr)
127 Write the data byte `d' to the flash at `adr' with the 132 Write the data byte `d' to the flash at `adr' with the
128 ALE and CLE lines false. If your board uses writes to 133 ALE and CLE lines false. If your board uses writes to
129 different addresses to control CLE and ALE, you can modify `adr' 134 different addresses to control CLE and ALE, you can modify `adr'
130 to be the appropriate address here. If your board uses I/O registers 135 to be the appropriate address here. If your board uses I/O registers
131 to control them, it is probably better to let NAND_CTL_CLRALE() 136 to control them, it is probably better to let NAND_CTL_CLRALE()
132 and company do it. 137 and company do it.
133 138
134 #define READ_NAND(adr) 139 #define READ_NAND(adr)
135 Read a data byte from the flash at `adr' with the 140 Read a data byte from the flash at `adr' with the
136 ALE and CLE lines false. If your board uses reads from 141 ALE and CLE lines false. If your board uses reads from
137 different addresses to control CLE and ALE, you can modify `adr' 142 different addresses to control CLE and ALE, you can modify `adr'
138 to be the appropriate address here. If your board uses I/O registers 143 to be the appropriate address here. If your board uses I/O registers
139 to control them, it is probably better to let NAND_CTL_CLRALE() 144 to control them, it is probably better to let NAND_CTL_CLRALE()
140 and company do it. 145 and company do it.
141 146
142 #define NAND_DISABLE_CE(nand) 147 #define NAND_DISABLE_CE(nand)
143 Set CE (Chip Enable) low to enable the NAND flash. 148 Set CE (Chip Enable) low to enable the NAND flash.
144 149
145 #define NAND_ENABLE_CE(nand) 150 #define NAND_ENABLE_CE(nand)
146 Set CE (Chip Enable) high to disable the NAND flash. 151 Set CE (Chip Enable) high to disable the NAND flash.
147 152
148 #define NAND_CTL_CLRALE(nandptr) 153 #define NAND_CTL_CLRALE(nandptr)
149 Set ALE (address latch enable) low. If ALE control is handled by 154 Set ALE (address latch enable) low. If ALE control is handled by
150 WRITE_NAND_ADDRESS() this can be empty. 155 WRITE_NAND_ADDRESS() this can be empty.
151 156
152 #define NAND_CTL_SETALE(nandptr) 157 #define NAND_CTL_SETALE(nandptr)
153 Set ALE (address latch enable) high. If ALE control is handled by 158 Set ALE (address latch enable) high. If ALE control is handled by
154 WRITE_NAND_ADDRESS() this can be empty. 159 WRITE_NAND_ADDRESS() this can be empty.
155 160
156 #define NAND_CTL_CLRCLE(nandptr) 161 #define NAND_CTL_CLRCLE(nandptr)
157 Set CLE (command latch enable) low. If CLE control is handled by 162 Set CLE (command latch enable) low. If CLE control is handled by
158 WRITE_NAND_ADDRESS() this can be empty. 163 WRITE_NAND_ADDRESS() this can be empty.
159 164
160 #define NAND_CTL_SETCLE(nandptr) 165 #define NAND_CTL_SETCLE(nandptr)
161 Set CLE (command latch enable) high. If CLE control is handled by 166 Set CLE (command latch enable) high. If CLE control is handled by
162 WRITE_NAND_ADDRESS() this can be empty. 167 WRITE_NAND_ADDRESS() this can be empty.
163 168
164 More Definitions: 169 More Definitions:
165 170
166 These definitions are needed in the board configuration for now, but 171 These definitions are needed in the board configuration for now, but
167 may really belong in a header file. 172 may really belong in a header file.
168 TODO: Figure which ones are truly configuration settings and rename 173 TODO: Figure which ones are truly configuration settings and rename
169 them to CFG_NAND_... and move the rest somewhere appropriate. 174 them to CFG_NAND_... and move the rest somewhere appropriate.
170 175
171 #define SECTORSIZE 512 176 #define SECTORSIZE 512
172 #define ADDR_COLUMN 1 177 #define ADDR_COLUMN 1
173 #define ADDR_PAGE 2 178 #define ADDR_PAGE 2
174 #define ADDR_COLUMN_PAGE 3 179 #define ADDR_COLUMN_PAGE 3
175 #define NAND_ChipID_UNKNOWN 0x00 180 #define NAND_ChipID_UNKNOWN 0x00
176 #define NAND_MAX_FLOORS 1 181 #define NAND_MAX_FLOORS 1
177 #define NAND_MAX_CHIPS 1 182 #define NAND_MAX_CHIPS 1
178 183
179 184
180 NOTE: 185 NOTE:
181 ===== 186 =====
182 187
183 We now use a complete rewrite of the NAND code based on what is in 188 We now use a complete rewrite of the NAND code based on what is in
184 2.6.12 Linux kernel. 189 2.6.12 Linux kernel.
185 190
186 The old NAND handling code has been re-factored and is now confined 191 The old NAND handling code has been re-factored and is now confined
187 to only board-specific files and - unfortunately - to the DoC code 192 to only board-specific files and - unfortunately - to the DoC code
188 (see below). A new configuration variable has been introduced: 193 (see below). A new configuration variable has been introduced:
189 CFG_NAND_LEGACY, which has to be defined in the board config file if 194 CFG_NAND_LEGACY, which has to be defined in the board config file if
190 that board uses legacy code. If CFG_NAND_LEGACY is defined, the board 195 that board uses legacy code. If CFG_NAND_LEGACY is defined, the board
191 specific config.mk file should also have "BOARDLIBS = 196 specific config.mk file should also have "BOARDLIBS =
192 drivers/nand_legacy/libnand_legacy.a". For boards using the new NAND 197 drivers/nand_legacy/libnand_legacy.a". For boards using the new NAND
193 approach (PPChameleon and netstar at the moment) no variable is 198 approach (PPChameleon and netstar at the moment) no variable is
194 necessary, but the config.mk should have "BOARDLIBS = 199 necessary, but the config.mk should have "BOARDLIBS =
195 drivers/nand/libnand.a". 200 drivers/nand/libnand.a".
196 201
197 The necessary changes have been made to all affected boards, and no 202 The necessary changes have been made to all affected boards, and no
198 build breakage has been introduced, except for NETTA and NETTA_ISDN 203 build breakage has been introduced, except for NETTA and NETTA_ISDN
199 targets from MAKEALL. This is due to the fact that these two boards 204 targets from MAKEALL. This is due to the fact that these two boards
200 use JFFS, which has been adopted to use the new NAND, and at the same 205 use JFFS, which has been adopted to use the new NAND, and at the same
201 time use NAND in legacy mode. The breakage will disappear when the 206 time use NAND in legacy mode. The breakage will disappear when the
202 board-specific code is changed to the new NAND. 207 board-specific code is changed to the new NAND.
203 208
204 As mentioned above, the legacy code is still used by the DoC subsystem. 209 As mentioned above, the legacy code is still used by the DoC subsystem.
205 The consequence of this is that the legacy NAND can't be removed from 210 The consequence of this is that the legacy NAND can't be removed from
206 the tree until the DoC is ported to use the new NAND support (or boards 211 the tree until the DoC is ported to use the new NAND support (or boards
207 with DoC will break). 212 with DoC will break).
208 213
209 214
210 Additional improvements to the NAND subsystem by Guido Classen, 10-10-2006 215 Additional improvements to the NAND subsystem by Guido Classen, 10-10-2006
211 216
212 JFFS2 related commands: 217 JFFS2 related commands:
213 218
214 implement "nand erase clean" and old "nand erase" 219 implement "nand erase clean" and old "nand erase"
215 using both the new code which is able to skip bad blocks 220 using both the new code which is able to skip bad blocks
216 "nand erase clean" additionally writes JFFS2-cleanmarkers in the oob. 221 "nand erase clean" additionally writes JFFS2-cleanmarkers in the oob.
217 222
218 "nand write.jffs2" 223 "nand write.jffs2"
219 like "nand write" but skip found bad eraseblocks 224 like "nand write" but skip found bad eraseblocks
220 225
221 "nand read.jffs2" 226 "nand read.jffs2"
222 like "nand read" but skip found bad eraseblocks 227 like "nand read" but skip found bad eraseblocks
223 228
224 Miscellaneous and testing commands: 229 Miscellaneous and testing commands:
225 "markbad [offset]" 230 "markbad [offset]"
226 create an artificial bad block (for testing bad block handling) 231 create an artificial bad block (for testing bad block handling)
227 232
228 "scrub [offset length]" 233 "scrub [offset length]"
229 like "erase" but don't skip bad block. Instead erase them. 234 like "erase" but don't skip bad block. Instead erase them.
230 DANGEROUS!!! Factory set bad blocks will be lost. Use only 235 DANGEROUS!!! Factory set bad blocks will be lost. Use only
231 to remove artificial bad blocks created with the "markbad" command. 236 to remove artificial bad blocks created with the "markbad" command.
232 237
233 238
234 NAND locking command (for chips with active LOCKPRE pin) 239 NAND locking command (for chips with active LOCKPRE pin)
235 240
236 "nand lock" 241 "nand lock"
237 set NAND chip to lock state (all pages locked) 242 set NAND chip to lock state (all pages locked)
238 243
239 "nand lock tight" 244 "nand lock tight"
240 set NAND chip to lock tight state (software can't change locking anymore) 245 set NAND chip to lock tight state (software can't change locking anymore)
241 246
242 "nand lock status" 247 "nand lock status"
243 displays current locking status of all pages 248 displays current locking status of all pages
244 249
245 "nand unlock [offset] [size]" 250 "nand unlock [offset] [size]"
246 unlock consecutive area (can be called multiple times for different areas) 251 unlock consecutive area (can be called multiple times for different areas)
247 252
248 253
249 I have tested the code with board containing 128MiB NAND large page chips 254 I have tested the code with board containing 128MiB NAND large page chips
250 and 32MiB small page chips. 255 and 32MiB small page chips.
drivers/nand/nand_util.c
1 /* 1 /*
2 * drivers/nand/nand_util.c 2 * drivers/nand/nand_util.c
3 * 3 *
4 * Copyright (C) 2006 by Weiss-Electronic GmbH. 4 * Copyright (C) 2006 by Weiss-Electronic GmbH.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * @author: Guido Classen <clagix@gmail.com> 7 * @author: Guido Classen <clagix@gmail.com>
8 * @descr: NAND Flash support 8 * @descr: NAND Flash support
9 * @references: borrowed heavily from Linux mtd-utils code: 9 * @references: borrowed heavily from Linux mtd-utils code:
10 * flash_eraseall.c by Arcom Control System Ltd 10 * flash_eraseall.c by Arcom Control System Ltd
11 * nandwrite.c by Steven J. Hill (sjhill@realitydiluted.com) 11 * nandwrite.c by Steven J. Hill (sjhill@realitydiluted.com)
12 * and Thomas Gleixner (tglx@linutronix.de) 12 * and Thomas Gleixner (tglx@linutronix.de)
13 * 13 *
14 * See file CREDITS for list of people who contributed to this 14 * See file CREDITS for list of people who contributed to this
15 * project. 15 * project.
16 * 16 *
17 * This program is free software; you can redistribute it and/or 17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License version 18 * modify it under the terms of the GNU General Public License version
19 * 2 as published by the Free Software Foundation. 19 * 2 as published by the Free Software Foundation.
20 * 20 *
21 * This program is distributed in the hope that it will be useful, 21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details. 24 * GNU General Public License for more details.
25 * 25 *
26 * You should have received a copy of the GNU General Public License 26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software 27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
29 * MA 02111-1307 USA 29 * MA 02111-1307 USA
30 * 30 *
31 */ 31 */
32 32
33 #include <common.h> 33 #include <common.h>
34 34
35 #if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY) 35 #if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
36 36
37 #include <command.h> 37 #include <command.h>
38 #include <watchdog.h> 38 #include <watchdog.h>
39 #include <malloc.h> 39 #include <malloc.h>
40 40
41 #include <nand.h> 41 #include <nand.h>
42 #include <jffs2/jffs2.h> 42 #include <jffs2/jffs2.h>
43 43
44 typedef struct erase_info erase_info_t; 44 typedef struct erase_info erase_info_t;
45 typedef struct mtd_info mtd_info_t; 45 typedef struct mtd_info mtd_info_t;
46 46
47 /* support only for native endian JFFS2 */ 47 /* support only for native endian JFFS2 */
48 #define cpu_to_je16(x) (x) 48 #define cpu_to_je16(x) (x)
49 #define cpu_to_je32(x) (x) 49 #define cpu_to_je32(x) (x)
50 50
51 /*****************************************************************************/ 51 /*****************************************************************************/
52 static int nand_block_bad_scrub(struct mtd_info *mtd, loff_t ofs, int getchip) 52 static int nand_block_bad_scrub(struct mtd_info *mtd, loff_t ofs, int getchip)
53 { 53 {
54 return 0; 54 return 0;
55 } 55 }
56 56
57 /** 57 /**
58 * nand_erase_opts: - erase NAND flash with support for various options 58 * nand_erase_opts: - erase NAND flash with support for various options
59 * (jffs2 formating) 59 * (jffs2 formating)
60 * 60 *
61 * @param meminfo NAND device to erase 61 * @param meminfo NAND device to erase
62 * @param opts options, @see struct nand_erase_options 62 * @param opts options, @see struct nand_erase_options
63 * @return 0 in case of success 63 * @return 0 in case of success
64 * 64 *
65 * This code is ported from flash_eraseall.c from Linux mtd utils by 65 * This code is ported from flash_eraseall.c from Linux mtd utils by
66 * Arcom Control System Ltd. 66 * Arcom Control System Ltd.
67 */ 67 */
68 int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts) 68 int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
69 { 69 {
70 struct jffs2_unknown_node cleanmarker; 70 struct jffs2_unknown_node cleanmarker;
71 int clmpos = 0; 71 int clmpos = 0;
72 int clmlen = 8; 72 int clmlen = 8;
73 erase_info_t erase; 73 erase_info_t erase;
74 ulong erase_length; 74 ulong erase_length;
75 int isNAND; 75 int isNAND;
76 int bbtest = 1; 76 int bbtest = 1;
77 int result; 77 int result;
78 int percent_complete = -1; 78 int percent_complete = -1;
79 int (*nand_block_bad_old)(struct mtd_info *, loff_t, int) = NULL; 79 int (*nand_block_bad_old)(struct mtd_info *, loff_t, int) = NULL;
80 const char *mtd_device = meminfo->name; 80 const char *mtd_device = meminfo->name;
81 81
82 memset(&erase, 0, sizeof(erase)); 82 memset(&erase, 0, sizeof(erase));
83 83
84 erase.mtd = meminfo; 84 erase.mtd = meminfo;
85 erase.len = meminfo->erasesize; 85 erase.len = meminfo->erasesize;
86 if (opts->offset == 0 && opts->length == 0) { 86 erase.addr = opts->offset;
87 /* erase complete chip */ 87 erase_length = opts->length;
88 erase.addr = 0;
89 erase_length = meminfo->size;
90 } else {
91 /* erase specified region */
92 erase.addr = opts->offset;
93 erase_length = opts->length;
94 }
95 88
96 isNAND = meminfo->type == MTD_NANDFLASH ? 1 : 0; 89 isNAND = meminfo->type == MTD_NANDFLASH ? 1 : 0;
97 90
98 if (opts->jffs2) { 91 if (opts->jffs2) {
99 cleanmarker.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK); 92 cleanmarker.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
100 cleanmarker.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER); 93 cleanmarker.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER);
101 if (isNAND) { 94 if (isNAND) {
102 struct nand_oobinfo *oobinfo = &meminfo->oobinfo; 95 struct nand_oobinfo *oobinfo = &meminfo->oobinfo;
103 96
104 /* check for autoplacement */ 97 /* check for autoplacement */
105 if (oobinfo->useecc == MTD_NANDECC_AUTOPLACE) { 98 if (oobinfo->useecc == MTD_NANDECC_AUTOPLACE) {
106 /* get the position of the free bytes */ 99 /* get the position of the free bytes */
107 if (!oobinfo->oobfree[0][1]) { 100 if (!oobinfo->oobfree[0][1]) {
108 printf(" Eeep. Autoplacement selected " 101 printf(" Eeep. Autoplacement selected "
109 "and no empty space in oob\n"); 102 "and no empty space in oob\n");
110 return -1; 103 return -1;
111 } 104 }
112 clmpos = oobinfo->oobfree[0][0]; 105 clmpos = oobinfo->oobfree[0][0];
113 clmlen = oobinfo->oobfree[0][1]; 106 clmlen = oobinfo->oobfree[0][1];
114 if (clmlen > 8) 107 if (clmlen > 8)
115 clmlen = 8; 108 clmlen = 8;
116 } else { 109 } else {
117 /* legacy mode */ 110 /* legacy mode */
118 switch (meminfo->oobsize) { 111 switch (meminfo->oobsize) {
119 case 8: 112 case 8:
120 clmpos = 6; 113 clmpos = 6;
121 clmlen = 2; 114 clmlen = 2;
122 break; 115 break;
123 case 16: 116 case 16:
124 clmpos = 8; 117 clmpos = 8;
125 clmlen = 8; 118 clmlen = 8;
126 break; 119 break;
127 case 64: 120 case 64:
128 clmpos = 16; 121 clmpos = 16;
129 clmlen = 8; 122 clmlen = 8;
130 break; 123 break;
131 } 124 }
132 } 125 }
133 126
134 cleanmarker.totlen = cpu_to_je32(8); 127 cleanmarker.totlen = cpu_to_je32(8);
135 } else { 128 } else {
136 cleanmarker.totlen = 129 cleanmarker.totlen =
137 cpu_to_je32(sizeof(struct jffs2_unknown_node)); 130 cpu_to_je32(sizeof(struct jffs2_unknown_node));
138 } 131 }
139 cleanmarker.hdr_crc = cpu_to_je32( 132 cleanmarker.hdr_crc = cpu_to_je32(
140 crc32_no_comp(0, (unsigned char *) &cleanmarker, 133 crc32_no_comp(0, (unsigned char *) &cleanmarker,
141 sizeof(struct jffs2_unknown_node) - 4)); 134 sizeof(struct jffs2_unknown_node) - 4));
142 } 135 }
143 136
144 /* scrub option allows to erase badblock. To prevent internal 137 /* scrub option allows to erase badblock. To prevent internal
145 * check from erase() method, set block check method to dummy 138 * check from erase() method, set block check method to dummy
146 * and disable bad block table while erasing. 139 * and disable bad block table while erasing.
147 */ 140 */
148 if (opts->scrub) { 141 if (opts->scrub) {
149 struct nand_chip *priv_nand = meminfo->priv; 142 struct nand_chip *priv_nand = meminfo->priv;
150 143
151 nand_block_bad_old = priv_nand->block_bad; 144 nand_block_bad_old = priv_nand->block_bad;
152 priv_nand->block_bad = nand_block_bad_scrub; 145 priv_nand->block_bad = nand_block_bad_scrub;
153 /* we don't need the bad block table anymore... 146 /* we don't need the bad block table anymore...
154 * after scrub, there are no bad blocks left! 147 * after scrub, there are no bad blocks left!
155 */ 148 */
156 if (priv_nand->bbt) { 149 if (priv_nand->bbt) {
157 kfree(priv_nand->bbt); 150 kfree(priv_nand->bbt);
158 } 151 }
159 priv_nand->bbt = NULL; 152 priv_nand->bbt = NULL;
160 } 153 }
161 154
162 for (; 155 for (;
163 erase.addr < opts->offset + erase_length; 156 erase.addr < opts->offset + erase_length;
164 erase.addr += meminfo->erasesize) { 157 erase.addr += meminfo->erasesize) {
165 158
166 WATCHDOG_RESET (); 159 WATCHDOG_RESET ();
167 160
168 if (!opts->scrub && bbtest) { 161 if (!opts->scrub && bbtest) {
169 int ret = meminfo->block_isbad(meminfo, erase.addr); 162 int ret = meminfo->block_isbad(meminfo, erase.addr);
170 if (ret > 0) { 163 if (ret > 0) {
171 if (!opts->quiet) 164 if (!opts->quiet)
172 printf("\rSkipping bad block at " 165 printf("\rSkipping bad block at "
173 "0x%08x " 166 "0x%08x "
174 " \n", 167 " \n",
175 erase.addr); 168 erase.addr);
176 continue; 169 continue;
177 170
178 } else if (ret < 0) { 171 } else if (ret < 0) {
179 printf("\n%s: MTD get bad block failed: %d\n", 172 printf("\n%s: MTD get bad block failed: %d\n",
180 mtd_device, 173 mtd_device,
181 ret); 174 ret);
182 return -1; 175 return -1;
183 } 176 }
184 } 177 }
185 178
186 result = meminfo->erase(meminfo, &erase); 179 result = meminfo->erase(meminfo, &erase);
187 if (result != 0) { 180 if (result != 0) {
188 printf("\n%s: MTD Erase failure: %d\n", 181 printf("\n%s: MTD Erase failure: %d\n",
189 mtd_device, result); 182 mtd_device, result);
190 continue; 183 continue;
191 } 184 }
192 185
193 /* format for JFFS2 ? */ 186 /* format for JFFS2 ? */
194 if (opts->jffs2) { 187 if (opts->jffs2) {
195 188
196 /* write cleanmarker */ 189 /* write cleanmarker */
197 if (isNAND) { 190 if (isNAND) {
198 size_t written; 191 size_t written;
199 result = meminfo->write_oob(meminfo, 192 result = meminfo->write_oob(meminfo,
200 erase.addr + clmpos, 193 erase.addr + clmpos,
201 clmlen, 194 clmlen,
202 &written, 195 &written,
203 (unsigned char *) 196 (unsigned char *)
204 &cleanmarker); 197 &cleanmarker);
205 if (result != 0) { 198 if (result != 0) {
206 printf("\n%s: MTD writeoob failure: %d\n", 199 printf("\n%s: MTD writeoob failure: %d\n",
207 mtd_device, result); 200 mtd_device, result);
208 continue; 201 continue;
209 } 202 }
210 } else { 203 } else {
211 printf("\n%s: this erase routine only supports" 204 printf("\n%s: this erase routine only supports"
212 " NAND devices!\n", 205 " NAND devices!\n",
213 mtd_device); 206 mtd_device);
214 } 207 }
215 } 208 }
216 209
217 if (!opts->quiet) { 210 if (!opts->quiet) {
218 int percent = (int) 211 int percent = (int)
219 ((unsigned long long) 212 ((unsigned long long)
220 (erase.addr+meminfo->erasesize-opts->offset) 213 (erase.addr+meminfo->erasesize-opts->offset)
221 * 100 / erase_length); 214 * 100 / erase_length);
222 215
223 /* output progress message only at whole percent 216 /* output progress message only at whole percent
224 * steps to reduce the number of messages printed 217 * steps to reduce the number of messages printed
225 * on (slow) serial consoles 218 * on (slow) serial consoles
226 */ 219 */
227 if (percent != percent_complete) { 220 if (percent != percent_complete) {
228 percent_complete = percent; 221 percent_complete = percent;
229 222
230 printf("\rErasing at 0x%x -- %3d%% complete.", 223 printf("\rErasing at 0x%x -- %3d%% complete.",
231 erase.addr, percent); 224 erase.addr, percent);
232 225
233 if (opts->jffs2 && result == 0) 226 if (opts->jffs2 && result == 0)
234 printf(" Cleanmarker written at 0x%x.", 227 printf(" Cleanmarker written at 0x%x.",
235 erase.addr); 228 erase.addr);
236 } 229 }
237 } 230 }
238 } 231 }
239 if (!opts->quiet) 232 if (!opts->quiet)
240 printf("\n"); 233 printf("\n");
241 234
242 if (nand_block_bad_old) { 235 if (nand_block_bad_old) {
243 struct nand_chip *priv_nand = meminfo->priv; 236 struct nand_chip *priv_nand = meminfo->priv;
244 237
245 priv_nand->block_bad = nand_block_bad_old; 238 priv_nand->block_bad = nand_block_bad_old;
246 priv_nand->scan_bbt(meminfo); 239 priv_nand->scan_bbt(meminfo);
247 } 240 }
248 241
249 return 0; 242 return 0;
250 } 243 }
251 244
252 #define MAX_PAGE_SIZE 2048 245 #define MAX_PAGE_SIZE 2048
253 #define MAX_OOB_SIZE 64 246 #define MAX_OOB_SIZE 64
254 247
255 /* 248 /*
256 * buffer array used for writing data 249 * buffer array used for writing data
257 */ 250 */
258 static unsigned char data_buf[MAX_PAGE_SIZE]; 251 static unsigned char data_buf[MAX_PAGE_SIZE];
259 static unsigned char oob_buf[MAX_OOB_SIZE]; 252 static unsigned char oob_buf[MAX_OOB_SIZE];
260 253
261 /* OOB layouts to pass into the kernel as default */ 254 /* OOB layouts to pass into the kernel as default */
262 static struct nand_oobinfo none_oobinfo = { 255 static struct nand_oobinfo none_oobinfo = {
263 .useecc = MTD_NANDECC_OFF, 256 .useecc = MTD_NANDECC_OFF,
264 }; 257 };
265 258
266 static struct nand_oobinfo jffs2_oobinfo = { 259 static struct nand_oobinfo jffs2_oobinfo = {
267 .useecc = MTD_NANDECC_PLACE, 260 .useecc = MTD_NANDECC_PLACE,
268 .eccbytes = 6, 261 .eccbytes = 6,
269 .eccpos = { 0, 1, 2, 3, 6, 7 } 262 .eccpos = { 0, 1, 2, 3, 6, 7 }
270 }; 263 };
271 264
272 static struct nand_oobinfo yaffs_oobinfo = { 265 static struct nand_oobinfo yaffs_oobinfo = {
273 .useecc = MTD_NANDECC_PLACE, 266 .useecc = MTD_NANDECC_PLACE,
274 .eccbytes = 6, 267 .eccbytes = 6,
275 .eccpos = { 8, 9, 10, 13, 14, 15} 268 .eccpos = { 8, 9, 10, 13, 14, 15}
276 }; 269 };
277 270
278 static struct nand_oobinfo autoplace_oobinfo = { 271 static struct nand_oobinfo autoplace_oobinfo = {
279 .useecc = MTD_NANDECC_AUTOPLACE 272 .useecc = MTD_NANDECC_AUTOPLACE
280 }; 273 };
281 274
282 /** 275 /**
283 * nand_write_opts: - write image to NAND flash with support for various options 276 * nand_write_opts: - write image to NAND flash with support for various options
284 * 277 *
285 * @param meminfo NAND device to erase 278 * @param meminfo NAND device to erase
286 * @param opts write options (@see nand_write_options) 279 * @param opts write options (@see nand_write_options)
287 * @return 0 in case of success 280 * @return 0 in case of success
288 * 281 *
289 * This code is ported from nandwrite.c from Linux mtd utils by 282 * This code is ported from nandwrite.c from Linux mtd utils by
290 * Steven J. Hill and Thomas Gleixner. 283 * Steven J. Hill and Thomas Gleixner.
291 */ 284 */
292 int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts) 285 int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)
293 { 286 {
294 int imglen = 0; 287 int imglen = 0;
295 int pagelen; 288 int pagelen;
296 int baderaseblock; 289 int baderaseblock;
297 int blockstart = -1; 290 int blockstart = -1;
298 loff_t offs; 291 loff_t offs;
299 int readlen; 292 int readlen;
300 int oobinfochanged = 0; 293 int oobinfochanged = 0;
301 int percent_complete = -1; 294 int percent_complete = -1;
302 struct nand_oobinfo old_oobinfo; 295 struct nand_oobinfo old_oobinfo;
303 ulong mtdoffset = opts->offset; 296 ulong mtdoffset = opts->offset;
304 ulong erasesize_blockalign; 297 ulong erasesize_blockalign;
305 u_char *buffer = opts->buffer; 298 u_char *buffer = opts->buffer;
306 size_t written; 299 size_t written;
307 int result; 300 int result;
308 301
309 if (opts->pad && opts->writeoob) { 302 if (opts->pad && opts->writeoob) {
310 printf("Can't pad when oob data is present.\n"); 303 printf("Can't pad when oob data is present.\n");
311 return -1; 304 return -1;
312 } 305 }
313 306
314 /* set erasesize to specified number of blocks - to match 307 /* set erasesize to specified number of blocks - to match
315 * jffs2 (virtual) block size */ 308 * jffs2 (virtual) block size */
316 if (opts->blockalign == 0) { 309 if (opts->blockalign == 0) {
317 erasesize_blockalign = meminfo->erasesize; 310 erasesize_blockalign = meminfo->erasesize;
318 } else { 311 } else {
319 erasesize_blockalign = meminfo->erasesize * opts->blockalign; 312 erasesize_blockalign = meminfo->erasesize * opts->blockalign;
320 } 313 }
321 314
322 /* make sure device page sizes are valid */ 315 /* make sure device page sizes are valid */
323 if (!(meminfo->oobsize == 16 && meminfo->oobblock == 512) 316 if (!(meminfo->oobsize == 16 && meminfo->oobblock == 512)
324 && !(meminfo->oobsize == 8 && meminfo->oobblock == 256) 317 && !(meminfo->oobsize == 8 && meminfo->oobblock == 256)
325 && !(meminfo->oobsize == 64 && meminfo->oobblock == 2048)) { 318 && !(meminfo->oobsize == 64 && meminfo->oobblock == 2048)) {
326 printf("Unknown flash (not normal NAND)\n"); 319 printf("Unknown flash (not normal NAND)\n");
327 return -1; 320 return -1;
328 } 321 }
329 322
330 /* read the current oob info */ 323 /* read the current oob info */
331 memcpy(&old_oobinfo, &meminfo->oobinfo, sizeof(old_oobinfo)); 324 memcpy(&old_oobinfo, &meminfo->oobinfo, sizeof(old_oobinfo));
332 325
333 /* write without ecc? */ 326 /* write without ecc? */
334 if (opts->noecc) { 327 if (opts->noecc) {
335 memcpy(&meminfo->oobinfo, &none_oobinfo, 328 memcpy(&meminfo->oobinfo, &none_oobinfo,
336 sizeof(meminfo->oobinfo)); 329 sizeof(meminfo->oobinfo));
337 oobinfochanged = 1; 330 oobinfochanged = 1;
338 } 331 }
339 332
340 /* autoplace ECC? */ 333 /* autoplace ECC? */
341 if (opts->autoplace && (old_oobinfo.useecc != MTD_NANDECC_AUTOPLACE)) { 334 if (opts->autoplace && (old_oobinfo.useecc != MTD_NANDECC_AUTOPLACE)) {
342 335
343 memcpy(&meminfo->oobinfo, &autoplace_oobinfo, 336 memcpy(&meminfo->oobinfo, &autoplace_oobinfo,
344 sizeof(meminfo->oobinfo)); 337 sizeof(meminfo->oobinfo));
345 oobinfochanged = 1; 338 oobinfochanged = 1;
346 } 339 }
347 340
348 /* force OOB layout for jffs2 or yaffs? */ 341 /* force OOB layout for jffs2 or yaffs? */
349 if (opts->forcejffs2 || opts->forceyaffs) { 342 if (opts->forcejffs2 || opts->forceyaffs) {
350 struct nand_oobinfo *oobsel = 343 struct nand_oobinfo *oobsel =
351 opts->forcejffs2 ? &jffs2_oobinfo : &yaffs_oobinfo; 344 opts->forcejffs2 ? &jffs2_oobinfo : &yaffs_oobinfo;
352 345
353 if (meminfo->oobsize == 8) { 346 if (meminfo->oobsize == 8) {
354 if (opts->forceyaffs) { 347 if (opts->forceyaffs) {
355 printf("YAFSS cannot operate on " 348 printf("YAFSS cannot operate on "
356 "256 Byte page size\n"); 349 "256 Byte page size\n");
357 goto restoreoob; 350 goto restoreoob;
358 } 351 }
359 /* Adjust number of ecc bytes */ 352 /* Adjust number of ecc bytes */
360 jffs2_oobinfo.eccbytes = 3; 353 jffs2_oobinfo.eccbytes = 3;
361 } 354 }
362 355
363 memcpy(&meminfo->oobinfo, oobsel, sizeof(meminfo->oobinfo)); 356 memcpy(&meminfo->oobinfo, oobsel, sizeof(meminfo->oobinfo));
364 } 357 }
365 358
366 /* get image length */ 359 /* get image length */
367 imglen = opts->length; 360 imglen = opts->length;
368 pagelen = meminfo->oobblock 361 pagelen = meminfo->oobblock
369 + ((opts->writeoob != 0) ? meminfo->oobsize : 0); 362 + ((opts->writeoob != 0) ? meminfo->oobsize : 0);
370 363
371 /* check, if file is pagealigned */ 364 /* check, if file is pagealigned */
372 if ((!opts->pad) && ((imglen % pagelen) != 0)) { 365 if ((!opts->pad) && ((imglen % pagelen) != 0)) {
373 printf("Input block length is not page aligned\n"); 366 printf("Input block length is not page aligned\n");
374 goto restoreoob; 367 goto restoreoob;
375 } 368 }
376 369
377 /* check, if length fits into device */ 370 /* check, if length fits into device */
378 if (((imglen / pagelen) * meminfo->oobblock) 371 if (((imglen / pagelen) * meminfo->oobblock)
379 > (meminfo->size - opts->offset)) { 372 > (meminfo->size - opts->offset)) {
380 printf("Image %d bytes, NAND page %d bytes, " 373 printf("Image %d bytes, NAND page %d bytes, "
381 "OOB area %u bytes, device size %u bytes\n", 374 "OOB area %u bytes, device size %u bytes\n",
382 imglen, pagelen, meminfo->oobblock, meminfo->size); 375 imglen, pagelen, meminfo->oobblock, meminfo->size);
383 printf("Input block does not fit into device\n"); 376 printf("Input block does not fit into device\n");
384 goto restoreoob; 377 goto restoreoob;
385 } 378 }
386 379
387 if (!opts->quiet) 380 if (!opts->quiet)
388 printf("\n"); 381 printf("\n");
389 382
390 /* get data from input and write to the device */ 383 /* get data from input and write to the device */
391 while (imglen && (mtdoffset < meminfo->size)) { 384 while (imglen && (mtdoffset < meminfo->size)) {
392 385
393 WATCHDOG_RESET (); 386 WATCHDOG_RESET ();
394 387
395 /* 388 /*
396 * new eraseblock, check for bad block(s). Stay in the 389 * new eraseblock, check for bad block(s). Stay in the
397 * loop to be sure if the offset changes because of 390 * loop to be sure if the offset changes because of
398 * a bad block, that the next block that will be 391 * a bad block, that the next block that will be
399 * written to is also checked. Thus avoiding errors if 392 * written to is also checked. Thus avoiding errors if
400 * the block(s) after the skipped block(s) is also bad 393 * the block(s) after the skipped block(s) is also bad
401 * (number of blocks depending on the blockalign 394 * (number of blocks depending on the blockalign
402 */ 395 */
403 while (blockstart != (mtdoffset & (~erasesize_blockalign+1))) { 396 while (blockstart != (mtdoffset & (~erasesize_blockalign+1))) {
404 blockstart = mtdoffset & (~erasesize_blockalign+1); 397 blockstart = mtdoffset & (~erasesize_blockalign+1);
405 offs = blockstart; 398 offs = blockstart;
406 baderaseblock = 0; 399 baderaseblock = 0;
407 400
408 /* check all the blocks in an erase block for 401 /* check all the blocks in an erase block for
409 * bad blocks */ 402 * bad blocks */
410 do { 403 do {
411 int ret = meminfo->block_isbad(meminfo, offs); 404 int ret = meminfo->block_isbad(meminfo, offs);
412 405
413 if (ret < 0) { 406 if (ret < 0) {
414 printf("Bad block check failed\n"); 407 printf("Bad block check failed\n");
415 goto restoreoob; 408 goto restoreoob;
416 } 409 }
417 if (ret == 1) { 410 if (ret == 1) {
418 baderaseblock = 1; 411 baderaseblock = 1;
419 if (!opts->quiet) 412 if (!opts->quiet)
420 printf("\rBad block at 0x%lx " 413 printf("\rBad block at 0x%lx "
421 "in erase block from " 414 "in erase block from "
422 "0x%x will be skipped\n", 415 "0x%x will be skipped\n",
423 (long) offs, 416 (long) offs,
424 blockstart); 417 blockstart);
425 } 418 }
426 419
427 if (baderaseblock) { 420 if (baderaseblock) {
428 mtdoffset = blockstart 421 mtdoffset = blockstart
429 + erasesize_blockalign; 422 + erasesize_blockalign;
430 } 423 }
431 offs += erasesize_blockalign 424 offs += erasesize_blockalign
432 / opts->blockalign; 425 / opts->blockalign;
433 } while (offs < blockstart + erasesize_blockalign); 426 } while (offs < blockstart + erasesize_blockalign);
434 } 427 }
435 428
436 readlen = meminfo->oobblock; 429 readlen = meminfo->oobblock;
437 if (opts->pad && (imglen < readlen)) { 430 if (opts->pad && (imglen < readlen)) {
438 readlen = imglen; 431 readlen = imglen;
439 memset(data_buf + readlen, 0xff, 432 memset(data_buf + readlen, 0xff,
440 meminfo->oobblock - readlen); 433 meminfo->oobblock - readlen);
441 } 434 }
442 435
443 /* read page data from input memory buffer */ 436 /* read page data from input memory buffer */
444 memcpy(data_buf, buffer, readlen); 437 memcpy(data_buf, buffer, readlen);
445 buffer += readlen; 438 buffer += readlen;
446 439
447 if (opts->writeoob) { 440 if (opts->writeoob) {
448 /* read OOB data from input memory block, exit 441 /* read OOB data from input memory block, exit
449 * on failure */ 442 * on failure */
450 memcpy(oob_buf, buffer, meminfo->oobsize); 443 memcpy(oob_buf, buffer, meminfo->oobsize);
451 buffer += meminfo->oobsize; 444 buffer += meminfo->oobsize;
452 445
453 /* write OOB data first, as ecc will be placed 446 /* write OOB data first, as ecc will be placed
454 * in there*/ 447 * in there*/
455 result = meminfo->write_oob(meminfo, 448 result = meminfo->write_oob(meminfo,
456 mtdoffset, 449 mtdoffset,
457 meminfo->oobsize, 450 meminfo->oobsize,
458 &written, 451 &written,
459 (unsigned char *) 452 (unsigned char *)
460 &oob_buf); 453 &oob_buf);
461 454
462 if (result != 0) { 455 if (result != 0) {
463 printf("\nMTD writeoob failure: %d\n", 456 printf("\nMTD writeoob failure: %d\n",
464 result); 457 result);
465 goto restoreoob; 458 goto restoreoob;
466 } 459 }
467 imglen -= meminfo->oobsize; 460 imglen -= meminfo->oobsize;
468 } 461 }
469 462
470 /* write out the page data */ 463 /* write out the page data */
471 result = meminfo->write(meminfo, 464 result = meminfo->write(meminfo,
472 mtdoffset, 465 mtdoffset,
473 meminfo->oobblock, 466 meminfo->oobblock,
474 &written, 467 &written,
475 (unsigned char *) &data_buf); 468 (unsigned char *) &data_buf);
476 469
477 if (result != 0) { 470 if (result != 0) {
478 printf("writing NAND page at offset 0x%lx failed\n", 471 printf("writing NAND page at offset 0x%lx failed\n",
479 mtdoffset); 472 mtdoffset);
480 goto restoreoob; 473 goto restoreoob;
481 } 474 }
482 imglen -= readlen; 475 imglen -= readlen;
483 476
484 if (!opts->quiet) { 477 if (!opts->quiet) {
485 int percent = (int) 478 int percent = (int)
486 ((unsigned long long) 479 ((unsigned long long)
487 (opts->length-imglen) * 100 480 (opts->length-imglen) * 100
488 / opts->length); 481 / opts->length);
489 /* output progress message only at whole percent 482 /* output progress message only at whole percent
490 * steps to reduce the number of messages printed 483 * steps to reduce the number of messages printed
491 * on (slow) serial consoles 484 * on (slow) serial consoles
492 */ 485 */
493 if (percent != percent_complete) { 486 if (percent != percent_complete) {
494 printf("\rWriting data at 0x%x " 487 printf("\rWriting data at 0x%x "
495 "-- %3d%% complete.", 488 "-- %3d%% complete.",
496 mtdoffset, percent); 489 mtdoffset, percent);
497 percent_complete = percent; 490 percent_complete = percent;
498 } 491 }
499 } 492 }
500 493
501 mtdoffset += meminfo->oobblock; 494 mtdoffset += meminfo->oobblock;
502 } 495 }
503 496
504 if (!opts->quiet) 497 if (!opts->quiet)
505 printf("\n"); 498 printf("\n");
506 499
507 restoreoob: 500 restoreoob:
508 if (oobinfochanged) { 501 if (oobinfochanged) {
509 memcpy(&meminfo->oobinfo, &old_oobinfo, 502 memcpy(&meminfo->oobinfo, &old_oobinfo,
510 sizeof(meminfo->oobinfo)); 503 sizeof(meminfo->oobinfo));
511 } 504 }
512 505
513 if (imglen > 0) { 506 if (imglen > 0) {
514 printf("Data did not fit into device, due to bad blocks\n"); 507 printf("Data did not fit into device, due to bad blocks\n");
515 return -1; 508 return -1;
516 } 509 }
517 510
518 /* return happy */ 511 /* return happy */
519 return 0; 512 return 0;
520 } 513 }
521 514
522 /** 515 /**
523 * nand_read_opts: - read image from NAND flash with support for various options 516 * nand_read_opts: - read image from NAND flash with support for various options
524 * 517 *
525 * @param meminfo NAND device to erase 518 * @param meminfo NAND device to erase
526 * @param opts read options (@see struct nand_read_options) 519 * @param opts read options (@see struct nand_read_options)
527 * @return 0 in case of success 520 * @return 0 in case of success
528 * 521 *
529 */ 522 */
530 int nand_read_opts(nand_info_t *meminfo, const nand_read_options_t *opts) 523 int nand_read_opts(nand_info_t *meminfo, const nand_read_options_t *opts)
531 { 524 {
532 int imglen = opts->length; 525 int imglen = opts->length;
533 int pagelen; 526 int pagelen;
534 int baderaseblock; 527 int baderaseblock;
535 int blockstart = -1; 528 int blockstart = -1;
536 int percent_complete = -1; 529 int percent_complete = -1;
537 loff_t offs; 530 loff_t offs;
538 size_t readlen; 531 size_t readlen;
539 ulong mtdoffset = opts->offset; 532 ulong mtdoffset = opts->offset;
540 u_char *buffer = opts->buffer; 533 u_char *buffer = opts->buffer;
541 int result; 534 int result;
542 535
543 /* make sure device page sizes are valid */ 536 /* make sure device page sizes are valid */
544 if (!(meminfo->oobsize == 16 && meminfo->oobblock == 512) 537 if (!(meminfo->oobsize == 16 && meminfo->oobblock == 512)
545 && !(meminfo->oobsize == 8 && meminfo->oobblock == 256) 538 && !(meminfo->oobsize == 8 && meminfo->oobblock == 256)
546 && !(meminfo->oobsize == 64 && meminfo->oobblock == 2048)) { 539 && !(meminfo->oobsize == 64 && meminfo->oobblock == 2048)) {
547 printf("Unknown flash (not normal NAND)\n"); 540 printf("Unknown flash (not normal NAND)\n");
548 return -1; 541 return -1;
549 } 542 }
550 543
551 pagelen = meminfo->oobblock 544 pagelen = meminfo->oobblock
552 + ((opts->readoob != 0) ? meminfo->oobsize : 0); 545 + ((opts->readoob != 0) ? meminfo->oobsize : 0);
553 546
554 /* check, if length is not larger than device */ 547 /* check, if length is not larger than device */
555 if (((imglen / pagelen) * meminfo->oobblock) 548 if (((imglen / pagelen) * meminfo->oobblock)
556 > (meminfo->size - opts->offset)) { 549 > (meminfo->size - opts->offset)) {
557 printf("Image %d bytes, NAND page %d bytes, " 550 printf("Image %d bytes, NAND page %d bytes, "
558 "OOB area %u bytes, device size %u bytes\n", 551 "OOB area %u bytes, device size %u bytes\n",
559 imglen, pagelen, meminfo->oobblock, meminfo->size); 552 imglen, pagelen, meminfo->oobblock, meminfo->size);
560 printf("Input block is larger than device\n"); 553 printf("Input block is larger than device\n");
561 return -1; 554 return -1;
562 } 555 }
563 556
564 if (!opts->quiet) 557 if (!opts->quiet)
565 printf("\n"); 558 printf("\n");
566 559
567 /* get data from input and write to the device */ 560 /* get data from input and write to the device */
568 while (imglen && (mtdoffset < meminfo->size)) { 561 while (imglen && (mtdoffset < meminfo->size)) {
569 562
570 WATCHDOG_RESET (); 563 WATCHDOG_RESET ();
571 564
572 /* 565 /*
573 * new eraseblock, check for bad block(s). Stay in the 566 * new eraseblock, check for bad block(s). Stay in the
574 * loop to be sure if the offset changes because of 567 * loop to be sure if the offset changes because of
575 * a bad block, that the next block that will be 568 * a bad block, that the next block that will be
576 * written to is also checked. Thus avoiding errors if 569 * written to is also checked. Thus avoiding errors if
577 * the block(s) after the skipped block(s) is also bad 570 * the block(s) after the skipped block(s) is also bad
578 * (number of blocks depending on the blockalign 571 * (number of blocks depending on the blockalign
579 */ 572 */
580 while (blockstart != (mtdoffset & (~meminfo->erasesize+1))) { 573 while (blockstart != (mtdoffset & (~meminfo->erasesize+1))) {
581 blockstart = mtdoffset & (~meminfo->erasesize+1); 574 blockstart = mtdoffset & (~meminfo->erasesize+1);
582 offs = blockstart; 575 offs = blockstart;
583 baderaseblock = 0; 576 baderaseblock = 0;
584 577
585 /* check all the blocks in an erase block for 578 /* check all the blocks in an erase block for
586 * bad blocks */ 579 * bad blocks */
587 do { 580 do {
588 int ret = meminfo->block_isbad(meminfo, offs); 581 int ret = meminfo->block_isbad(meminfo, offs);
589 582
590 if (ret < 0) { 583 if (ret < 0) {
591 printf("Bad block check failed\n"); 584 printf("Bad block check failed\n");
592 return -1; 585 return -1;
593 } 586 }
594 if (ret == 1) { 587 if (ret == 1) {
595 baderaseblock = 1; 588 baderaseblock = 1;
596 if (!opts->quiet) 589 if (!opts->quiet)
597 printf("\rBad block at 0x%lx " 590 printf("\rBad block at 0x%lx "
598 "in erase block from " 591 "in erase block from "
599 "0x%x will be skipped\n", 592 "0x%x will be skipped\n",
600 (long) offs, 593 (long) offs,
601 blockstart); 594 blockstart);
602 } 595 }
603 596
604 if (baderaseblock) { 597 if (baderaseblock) {
605 mtdoffset = blockstart 598 mtdoffset = blockstart
606 + meminfo->erasesize; 599 + meminfo->erasesize;
607 } 600 }
608 offs += meminfo->erasesize; 601 offs += meminfo->erasesize;
609 602
610 } while (offs < blockstart + meminfo->erasesize); 603 } while (offs < blockstart + meminfo->erasesize);
611 } 604 }
612 605
613 606
614 /* read page data to memory buffer */ 607 /* read page data to memory buffer */
615 result = meminfo->read(meminfo, 608 result = meminfo->read(meminfo,
616 mtdoffset, 609 mtdoffset,
617 meminfo->oobblock, 610 meminfo->oobblock,
618 &readlen, 611 &readlen,
619 (unsigned char *) &data_buf); 612 (unsigned char *) &data_buf);
620 613
621 if (result != 0) { 614 if (result != 0) {
622 printf("reading NAND page at offset 0x%lx failed\n", 615 printf("reading NAND page at offset 0x%lx failed\n",
623 mtdoffset); 616 mtdoffset);
624 return -1; 617 return -1;
625 } 618 }
626 619
627 if (imglen < readlen) { 620 if (imglen < readlen) {
628 readlen = imglen; 621 readlen = imglen;
629 } 622 }
630 623
631 memcpy(buffer, data_buf, readlen); 624 memcpy(buffer, data_buf, readlen);
632 buffer += readlen; 625 buffer += readlen;
633 imglen -= readlen; 626 imglen -= readlen;
634 627
635 if (opts->readoob) { 628 if (opts->readoob) {
636 result = meminfo->read_oob(meminfo, 629 result = meminfo->read_oob(meminfo,
637 mtdoffset, 630 mtdoffset,
638 meminfo->oobsize, 631 meminfo->oobsize,
639 &readlen, 632 &readlen,
640 (unsigned char *) 633 (unsigned char *)
641 &oob_buf); 634 &oob_buf);
642 635
643 if (result != 0) { 636 if (result != 0) {
644 printf("\nMTD readoob failure: %d\n", 637 printf("\nMTD readoob failure: %d\n",
645 result); 638 result);
646 return -1; 639 return -1;
647 } 640 }
648 641
649 642
650 if (imglen < readlen) { 643 if (imglen < readlen) {
651 readlen = imglen; 644 readlen = imglen;
652 } 645 }
653 646
654 memcpy(buffer, oob_buf, readlen); 647 memcpy(buffer, oob_buf, readlen);
655 648
656 buffer += readlen; 649 buffer += readlen;
657 imglen -= readlen; 650 imglen -= readlen;
658 } 651 }
659 652
660 if (!opts->quiet) { 653 if (!opts->quiet) {
661 int percent = (int) 654 int percent = (int)
662 ((unsigned long long) 655 ((unsigned long long)
663 (opts->length-imglen) * 100 656 (opts->length-imglen) * 100
664 / opts->length); 657 / opts->length);
665 /* output progress message only at whole percent 658 /* output progress message only at whole percent
666 * steps to reduce the number of messages printed 659 * steps to reduce the number of messages printed
667 * on (slow) serial consoles 660 * on (slow) serial consoles
668 */ 661 */
669 if (percent != percent_complete) { 662 if (percent != percent_complete) {
670 if (!opts->quiet) 663 if (!opts->quiet)
671 printf("\rReading data from 0x%x " 664 printf("\rReading data from 0x%x "
672 "-- %3d%% complete.", 665 "-- %3d%% complete.",
673 mtdoffset, percent); 666 mtdoffset, percent);
674 percent_complete = percent; 667 percent_complete = percent;
675 } 668 }
676 } 669 }
677 670
678 mtdoffset += meminfo->oobblock; 671 mtdoffset += meminfo->oobblock;
679 } 672 }
680 673
681 if (!opts->quiet) 674 if (!opts->quiet)
682 printf("\n"); 675 printf("\n");
683 676
684 if (imglen > 0) { 677 if (imglen > 0) {
685 printf("Could not read entire image due to bad blocks\n"); 678 printf("Could not read entire image due to bad blocks\n");
686 return -1; 679 return -1;
687 } 680 }
688 681
689 /* return happy */ 682 /* return happy */
690 return 0; 683 return 0;
691 } 684 }
692 685
693 /****************************************************************************** 686 /******************************************************************************
694 * Support for locking / unlocking operations of some NAND devices 687 * Support for locking / unlocking operations of some NAND devices
695 *****************************************************************************/ 688 *****************************************************************************/
696 689
697 #define NAND_CMD_LOCK 0x2a 690 #define NAND_CMD_LOCK 0x2a
698 #define NAND_CMD_LOCK_TIGHT 0x2c 691 #define NAND_CMD_LOCK_TIGHT 0x2c
699 #define NAND_CMD_UNLOCK1 0x23 692 #define NAND_CMD_UNLOCK1 0x23
700 #define NAND_CMD_UNLOCK2 0x24 693 #define NAND_CMD_UNLOCK2 0x24
701 #define NAND_CMD_LOCK_STATUS 0x7a 694 #define NAND_CMD_LOCK_STATUS 0x7a
702 695
703 /** 696 /**
704 * nand_lock: Set all pages of NAND flash chip to the LOCK or LOCK-TIGHT 697 * nand_lock: Set all pages of NAND flash chip to the LOCK or LOCK-TIGHT
705 * state 698 * state
706 * 699 *
707 * @param meminfo nand mtd instance 700 * @param meminfo nand mtd instance
708 * @param tight bring device in lock tight mode 701 * @param tight bring device in lock tight mode
709 * 702 *
710 * @return 0 on success, -1 in case of error 703 * @return 0 on success, -1 in case of error
711 * 704 *
712 * The lock / lock-tight command only applies to the whole chip. To get some 705 * The lock / lock-tight command only applies to the whole chip. To get some
713 * parts of the chip lock and others unlocked use the following sequence: 706 * parts of the chip lock and others unlocked use the following sequence:
714 * 707 *
715 * - Lock all pages of the chip using nand_lock(mtd, 0) (or the lockpre pin) 708 * - Lock all pages of the chip using nand_lock(mtd, 0) (or the lockpre pin)
716 * - Call nand_unlock() once for each consecutive area to be unlocked 709 * - Call nand_unlock() once for each consecutive area to be unlocked
717 * - If desired: Bring the chip to the lock-tight state using nand_lock(mtd, 1) 710 * - If desired: Bring the chip to the lock-tight state using nand_lock(mtd, 1)
718 * 711 *
719 * If the device is in lock-tight state software can't change the 712 * If the device is in lock-tight state software can't change the
720 * current active lock/unlock state of all pages. nand_lock() / nand_unlock() 713 * current active lock/unlock state of all pages. nand_lock() / nand_unlock()
721 * calls will fail. It is only posible to leave lock-tight state by 714 * calls will fail. It is only posible to leave lock-tight state by
722 * an hardware signal (low pulse on _WP pin) or by power down. 715 * an hardware signal (low pulse on _WP pin) or by power down.
723 */ 716 */
724 int nand_lock(nand_info_t *meminfo, int tight) 717 int nand_lock(nand_info_t *meminfo, int tight)
725 { 718 {
726 int ret = 0; 719 int ret = 0;
727 int status; 720 int status;
728 struct nand_chip *this = meminfo->priv; 721 struct nand_chip *this = meminfo->priv;
729 722
730 /* select the NAND device */ 723 /* select the NAND device */
731 this->select_chip(meminfo, 0); 724 this->select_chip(meminfo, 0);
732 725
733 this->cmdfunc(meminfo, 726 this->cmdfunc(meminfo,
734 (tight ? NAND_CMD_LOCK_TIGHT : NAND_CMD_LOCK), 727 (tight ? NAND_CMD_LOCK_TIGHT : NAND_CMD_LOCK),
735 -1, -1); 728 -1, -1);
736 729
737 /* call wait ready function */ 730 /* call wait ready function */
738 status = this->waitfunc(meminfo, this, FL_WRITING); 731 status = this->waitfunc(meminfo, this, FL_WRITING);
739 732
740 /* see if device thinks it succeeded */ 733 /* see if device thinks it succeeded */
741 if (status & 0x01) { 734 if (status & 0x01) {
742 ret = -1; 735 ret = -1;
743 } 736 }
744 737
745 /* de-select the NAND device */ 738 /* de-select the NAND device */
746 this->select_chip(meminfo, -1); 739 this->select_chip(meminfo, -1);
747 return ret; 740 return ret;
748 } 741 }
749 742
750 /** 743 /**
751 * nand_get_lock_status: - query current lock state from one page of NAND 744 * nand_get_lock_status: - query current lock state from one page of NAND
752 * flash 745 * flash
753 * 746 *
754 * @param meminfo nand mtd instance 747 * @param meminfo nand mtd instance
755 * @param offset page address to query (muss be page aligned!) 748 * @param offset page address to query (muss be page aligned!)
756 * 749 *
757 * @return -1 in case of error 750 * @return -1 in case of error
758 * >0 lock status: 751 * >0 lock status:
759 * bitfield with the following combinations: 752 * bitfield with the following combinations:
760 * NAND_LOCK_STATUS_TIGHT: page in tight state 753 * NAND_LOCK_STATUS_TIGHT: page in tight state
761 * NAND_LOCK_STATUS_LOCK: page locked 754 * NAND_LOCK_STATUS_LOCK: page locked
762 * NAND_LOCK_STATUS_UNLOCK: page unlocked 755 * NAND_LOCK_STATUS_UNLOCK: page unlocked
763 * 756 *
764 */ 757 */
765 int nand_get_lock_status(nand_info_t *meminfo, ulong offset) 758 int nand_get_lock_status(nand_info_t *meminfo, ulong offset)
766 { 759 {
767 int ret = 0; 760 int ret = 0;
768 int chipnr; 761 int chipnr;
769 int page; 762 int page;
770 struct nand_chip *this = meminfo->priv; 763 struct nand_chip *this = meminfo->priv;
771 764
772 /* select the NAND device */ 765 /* select the NAND device */
773 chipnr = (int)(offset >> this->chip_shift); 766 chipnr = (int)(offset >> this->chip_shift);
774 this->select_chip(meminfo, chipnr); 767 this->select_chip(meminfo, chipnr);
775 768
776 769
777 if ((offset & (meminfo->oobblock - 1)) != 0) { 770 if ((offset & (meminfo->oobblock - 1)) != 0) {
778 printf ("nand_get_lock_status: " 771 printf ("nand_get_lock_status: "
779 "Start address must be beginning of " 772 "Start address must be beginning of "
780 "nand page!\n"); 773 "nand page!\n");
781 ret = -1; 774 ret = -1;
782 goto out; 775 goto out;
783 } 776 }
784 777
785 /* check the Lock Status */ 778 /* check the Lock Status */
786 page = (int)(offset >> this->page_shift); 779 page = (int)(offset >> this->page_shift);
787 this->cmdfunc(meminfo, NAND_CMD_LOCK_STATUS, -1, page & this->pagemask); 780 this->cmdfunc(meminfo, NAND_CMD_LOCK_STATUS, -1, page & this->pagemask);
788 781
789 ret = this->read_byte(meminfo) & (NAND_LOCK_STATUS_TIGHT 782 ret = this->read_byte(meminfo) & (NAND_LOCK_STATUS_TIGHT
790 | NAND_LOCK_STATUS_LOCK 783 | NAND_LOCK_STATUS_LOCK
791 | NAND_LOCK_STATUS_UNLOCK); 784 | NAND_LOCK_STATUS_UNLOCK);
792 785
793 out: 786 out:
794 /* de-select the NAND device */ 787 /* de-select the NAND device */
795 this->select_chip(meminfo, -1); 788 this->select_chip(meminfo, -1);
796 return ret; 789 return ret;
797 } 790 }
798 791
799 /** 792 /**
800 * nand_unlock: - Unlock area of NAND pages 793 * nand_unlock: - Unlock area of NAND pages
801 * only one consecutive area can be unlocked at one time! 794 * only one consecutive area can be unlocked at one time!
802 * 795 *
803 * @param meminfo nand mtd instance 796 * @param meminfo nand mtd instance
804 * @param start start byte address 797 * @param start start byte address
805 * @param length number of bytes to unlock (must be a multiple of 798 * @param length number of bytes to unlock (must be a multiple of
806 * page size nand->oobblock) 799 * page size nand->oobblock)
807 * 800 *
808 * @return 0 on success, -1 in case of error 801 * @return 0 on success, -1 in case of error
809 */ 802 */
810 int nand_unlock(nand_info_t *meminfo, ulong start, ulong length) 803 int nand_unlock(nand_info_t *meminfo, ulong start, ulong length)
811 { 804 {
812 int ret = 0; 805 int ret = 0;
813 int chipnr; 806 int chipnr;
814 int status; 807 int status;
815 int page; 808 int page;
816 struct nand_chip *this = meminfo->priv; 809 struct nand_chip *this = meminfo->priv;
817 printf ("nand_unlock: start: %08x, length: %d!\n", 810 printf ("nand_unlock: start: %08x, length: %d!\n",
818 (int)start, (int)length); 811 (int)start, (int)length);
819 812
820 /* select the NAND device */ 813 /* select the NAND device */
821 chipnr = (int)(start >> this->chip_shift); 814 chipnr = (int)(start >> this->chip_shift);
822 this->select_chip(meminfo, chipnr); 815 this->select_chip(meminfo, chipnr);
823 816
824 /* check the WP bit */ 817 /* check the WP bit */
825 this->cmdfunc(meminfo, NAND_CMD_STATUS, -1, -1); 818 this->cmdfunc(meminfo, NAND_CMD_STATUS, -1, -1);
826 if ((this->read_byte(meminfo) & 0x80) == 0) { 819 if ((this->read_byte(meminfo) & 0x80) == 0) {
827 printf ("nand_unlock: Device is write protected!\n"); 820 printf ("nand_unlock: Device is write protected!\n");
828 ret = -1; 821 ret = -1;
829 goto out; 822 goto out;
830 } 823 }
831 824
832 if ((start & (meminfo->oobblock - 1)) != 0) { 825 if ((start & (meminfo->oobblock - 1)) != 0) {
833 printf ("nand_unlock: Start address must be beginning of " 826 printf ("nand_unlock: Start address must be beginning of "
834 "nand page!\n"); 827 "nand page!\n");
835 ret = -1; 828 ret = -1;
836 goto out; 829 goto out;
837 } 830 }
838 831
839 if (length == 0 || (length & (meminfo->oobblock - 1)) != 0) { 832 if (length == 0 || (length & (meminfo->oobblock - 1)) != 0) {
840 printf ("nand_unlock: Length must be a multiple of nand page " 833 printf ("nand_unlock: Length must be a multiple of nand page "
841 "size!\n"); 834 "size!\n");
842 ret = -1; 835 ret = -1;
843 goto out; 836 goto out;
844 } 837 }
845 838
846 /* submit address of first page to unlock */ 839 /* submit address of first page to unlock */
847 page = (int)(start >> this->page_shift); 840 page = (int)(start >> this->page_shift);
848 this->cmdfunc(meminfo, NAND_CMD_UNLOCK1, -1, page & this->pagemask); 841 this->cmdfunc(meminfo, NAND_CMD_UNLOCK1, -1, page & this->pagemask);
849 842
850 /* submit ADDRESS of LAST page to unlock */ 843 /* submit ADDRESS of LAST page to unlock */
851 page += (int)(length >> this->page_shift) - 1; 844 page += (int)(length >> this->page_shift) - 1;
852 this->cmdfunc(meminfo, NAND_CMD_UNLOCK2, -1, page & this->pagemask); 845 this->cmdfunc(meminfo, NAND_CMD_UNLOCK2, -1, page & this->pagemask);
853 846
854 /* call wait ready function */ 847 /* call wait ready function */
855 status = this->waitfunc(meminfo, this, FL_WRITING); 848 status = this->waitfunc(meminfo, this, FL_WRITING);
856 /* see if device thinks it succeeded */ 849 /* see if device thinks it succeeded */
857 if (status & 0x01) { 850 if (status & 0x01) {
858 /* there was an error */ 851 /* there was an error */
859 ret = -1; 852 ret = -1;
860 goto out; 853 goto out;
861 } 854 }
862 855
863 out: 856 out:
864 /* de-select the NAND device */ 857 /* de-select the NAND device */
865 this->select_chip(meminfo, -1); 858 this->select_chip(meminfo, -1);
866 return ret; 859 return ret;
867 } 860 }
868 861
869 #endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY) */ 862 #endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY) */
870 863
1 /************************************************ 1 /************************************************
2 * NAME : arm925t.h 2 * NAME : arm925t.h
3 * Version : 23 June 2003 * 3 * Version : 23 June 2003 *
4 ************************************************/ 4 ************************************************/
5 5
6 #ifndef __ARM925T_H__ 6 #ifndef __ARM925T_H__
7 #define __ARM925T_H__ 7 #define __ARM925T_H__
8 8
9 void gpioreserve(ushort mask);
10 void gpiosetdir(ushort mask, ushort in);
11 void gpiosetout(ushort mask, ushort out);
12 void gpioinit(void);
13 void archflashwp(void *archdata, int wp); 9 void archflashwp(void *archdata, int wp);
14 10
15 #endif /*__ARM925T_H__*/ 11 #endif /*__ARM925T_H__*/
16 12