Commit 12bc4e94251c369c529ffa505cf58b148c372f7f
Committed by
Wolfgang Denk
1 parent
1b9ed2574a
Exists in
master
and in
54 other branches
cmd_nand: fix warning: str2long ncompatible pointer type
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Showing 1 changed file with 1 additions and 1 deletions Inline Diff
common/cmd_nand.c
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 defined(CONFIG_CMD_NAND) | 22 | #if defined(CONFIG_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 | #include <jffs2/jffs2.h> | 28 | #include <jffs2/jffs2.h> |
29 | #include <nand.h> | 29 | #include <nand.h> |
30 | 30 | ||
31 | #if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE) | 31 | #if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE) |
32 | 32 | ||
33 | /* parition handling routines */ | 33 | /* parition handling routines */ |
34 | int mtdparts_init(void); | 34 | int mtdparts_init(void); |
35 | int id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num); | 35 | int id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num); |
36 | int find_dev_and_part(const char *id, struct mtd_device **dev, | 36 | int find_dev_and_part(const char *id, struct mtd_device **dev, |
37 | u8 *part_num, struct part_info **part); | 37 | u8 *part_num, struct part_info **part); |
38 | #endif | 38 | #endif |
39 | 39 | ||
40 | extern nand_info_t nand_info[]; /* info for NAND chips */ | 40 | extern nand_info_t nand_info[]; /* info for NAND chips */ |
41 | 41 | ||
42 | static int nand_dump_oob(nand_info_t *nand, ulong off) | 42 | static int nand_dump_oob(nand_info_t *nand, ulong off) |
43 | { | 43 | { |
44 | return 0; | 44 | return 0; |
45 | } | 45 | } |
46 | 46 | ||
47 | static int nand_dump(nand_info_t *nand, ulong off) | 47 | static int nand_dump(nand_info_t *nand, ulong off) |
48 | { | 48 | { |
49 | int i; | 49 | int i; |
50 | u_char *buf, *p; | 50 | u_char *buf, *p; |
51 | 51 | ||
52 | buf = malloc(nand->oobblock + nand->oobsize); | 52 | buf = malloc(nand->oobblock + nand->oobsize); |
53 | if (!buf) { | 53 | if (!buf) { |
54 | puts("No memory for page buffer\n"); | 54 | puts("No memory for page buffer\n"); |
55 | return 1; | 55 | return 1; |
56 | } | 56 | } |
57 | off &= ~(nand->oobblock - 1); | 57 | off &= ~(nand->oobblock - 1); |
58 | i = nand_read_raw(nand, buf, off, nand->oobblock, nand->oobsize); | 58 | i = nand_read_raw(nand, buf, off, nand->oobblock, nand->oobsize); |
59 | if (i < 0) { | 59 | if (i < 0) { |
60 | printf("Error (%d) reading page %08x\n", i, off); | 60 | printf("Error (%d) reading page %08x\n", i, off); |
61 | free(buf); | 61 | free(buf); |
62 | return 1; | 62 | return 1; |
63 | } | 63 | } |
64 | printf("Page %08x dump:\n", off); | 64 | printf("Page %08x dump:\n", off); |
65 | i = nand->oobblock >> 4; p = buf; | 65 | i = nand->oobblock >> 4; p = buf; |
66 | while (i--) { | 66 | while (i--) { |
67 | printf( "\t%02x %02x %02x %02x %02x %02x %02x %02x" | 67 | printf( "\t%02x %02x %02x %02x %02x %02x %02x %02x" |
68 | " %02x %02x %02x %02x %02x %02x %02x %02x\n", | 68 | " %02x %02x %02x %02x %02x %02x %02x %02x\n", |
69 | p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], | 69 | p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], |
70 | p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); | 70 | p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); |
71 | p += 16; | 71 | p += 16; |
72 | } | 72 | } |
73 | puts("OOB:\n"); | 73 | puts("OOB:\n"); |
74 | i = nand->oobsize >> 3; | 74 | i = nand->oobsize >> 3; |
75 | while (i--) { | 75 | while (i--) { |
76 | printf( "\t%02x %02x %02x %02x %02x %02x %02x %02x\n", | 76 | printf( "\t%02x %02x %02x %02x %02x %02x %02x %02x\n", |
77 | 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]); |
78 | p += 8; | 78 | p += 8; |
79 | } | 79 | } |
80 | free(buf); | 80 | free(buf); |
81 | 81 | ||
82 | return 0; | 82 | return 0; |
83 | } | 83 | } |
84 | 84 | ||
85 | /* ------------------------------------------------------------------------- */ | 85 | /* ------------------------------------------------------------------------- */ |
86 | 86 | ||
87 | static inline int str2long(char *p, ulong *num) | 87 | static inline int str2long(char *p, ulong *num) |
88 | { | 88 | { |
89 | char *endptr; | 89 | char *endptr; |
90 | 90 | ||
91 | *num = simple_strtoul(p, &endptr, 16); | 91 | *num = simple_strtoul(p, &endptr, 16); |
92 | return (*p != '\0' && *endptr == '\0') ? 1 : 0; | 92 | return (*p != '\0' && *endptr == '\0') ? 1 : 0; |
93 | } | 93 | } |
94 | 94 | ||
95 | static int | 95 | static int |
96 | arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off, size_t *size) | 96 | arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off, size_t *size) |
97 | { | 97 | { |
98 | int idx = nand_curr_device; | 98 | int idx = nand_curr_device; |
99 | #if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE) | 99 | #if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE) |
100 | struct mtd_device *dev; | 100 | struct mtd_device *dev; |
101 | struct part_info *part; | 101 | struct part_info *part; |
102 | u8 pnum; | 102 | u8 pnum; |
103 | 103 | ||
104 | if (argc >= 1 && !(str2long(argv[0], off))) { | 104 | if (argc >= 1 && !(str2long(argv[0], off))) { |
105 | if ((mtdparts_init() == 0) && | 105 | if ((mtdparts_init() == 0) && |
106 | (find_dev_and_part(argv[0], &dev, &pnum, &part) == 0)) { | 106 | (find_dev_and_part(argv[0], &dev, &pnum, &part) == 0)) { |
107 | if (dev->id->type != MTD_DEV_TYPE_NAND) { | 107 | if (dev->id->type != MTD_DEV_TYPE_NAND) { |
108 | puts("not a NAND device\n"); | 108 | puts("not a NAND device\n"); |
109 | return -1; | 109 | return -1; |
110 | } | 110 | } |
111 | *off = part->offset; | 111 | *off = part->offset; |
112 | if (argc >= 2) { | 112 | if (argc >= 2) { |
113 | if (!(str2long(argv[1], size))) { | 113 | if (!(str2long(argv[1], (ulong *)size))) { |
114 | printf("'%s' is not a number\n", argv[1]); | 114 | printf("'%s' is not a number\n", argv[1]); |
115 | return -1; | 115 | return -1; |
116 | } | 116 | } |
117 | if (*size > part->size) | 117 | if (*size > part->size) |
118 | *size = part->size; | 118 | *size = part->size; |
119 | } else { | 119 | } else { |
120 | *size = part->size; | 120 | *size = part->size; |
121 | } | 121 | } |
122 | idx = dev->id->num; | 122 | idx = dev->id->num; |
123 | *nand = nand_info[idx]; | 123 | *nand = nand_info[idx]; |
124 | goto out; | 124 | goto out; |
125 | } | 125 | } |
126 | } | 126 | } |
127 | #endif | 127 | #endif |
128 | 128 | ||
129 | if (argc >= 1) { | 129 | if (argc >= 1) { |
130 | if (!(str2long(argv[0], off))) { | 130 | if (!(str2long(argv[0], off))) { |
131 | printf("'%s' is not a number\n", argv[0]); | 131 | printf("'%s' is not a number\n", argv[0]); |
132 | return -1; | 132 | return -1; |
133 | } | 133 | } |
134 | } else { | 134 | } else { |
135 | *off = 0; | 135 | *off = 0; |
136 | } | 136 | } |
137 | 137 | ||
138 | if (argc >= 2) { | 138 | if (argc >= 2) { |
139 | if (!(str2long(argv[1], (ulong *)size))) { | 139 | if (!(str2long(argv[1], (ulong *)size))) { |
140 | printf("'%s' is not a number\n", argv[1]); | 140 | printf("'%s' is not a number\n", argv[1]); |
141 | return -1; | 141 | return -1; |
142 | } | 142 | } |
143 | } else { | 143 | } else { |
144 | *size = nand->size - *off; | 144 | *size = nand->size - *off; |
145 | } | 145 | } |
146 | 146 | ||
147 | #if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE) | 147 | #if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE) |
148 | out: | 148 | out: |
149 | #endif | 149 | #endif |
150 | printf("device %d ", idx); | 150 | printf("device %d ", idx); |
151 | if (*size == nand->size) | 151 | if (*size == nand->size) |
152 | puts("whole chip\n"); | 152 | puts("whole chip\n"); |
153 | else | 153 | else |
154 | printf("offset 0x%x, size 0x%x\n", *off, *size); | 154 | printf("offset 0x%x, size 0x%x\n", *off, *size); |
155 | return 0; | 155 | return 0; |
156 | } | 156 | } |
157 | 157 | ||
158 | int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) | 158 | int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) |
159 | { | 159 | { |
160 | int i, dev, ret; | 160 | int i, dev, ret; |
161 | ulong addr, off; | 161 | ulong addr, off; |
162 | size_t size; | 162 | size_t size; |
163 | char *cmd, *s; | 163 | char *cmd, *s; |
164 | nand_info_t *nand; | 164 | nand_info_t *nand; |
165 | #ifdef CFG_NAND_QUIET | 165 | #ifdef CFG_NAND_QUIET |
166 | int quiet = CFG_NAND_QUIET; | 166 | int quiet = CFG_NAND_QUIET; |
167 | #else | 167 | #else |
168 | int quiet = 0; | 168 | int quiet = 0; |
169 | #endif | 169 | #endif |
170 | const char *quiet_str = getenv("quiet"); | 170 | const char *quiet_str = getenv("quiet"); |
171 | 171 | ||
172 | /* at least two arguments please */ | 172 | /* at least two arguments please */ |
173 | if (argc < 2) | 173 | if (argc < 2) |
174 | goto usage; | 174 | goto usage; |
175 | 175 | ||
176 | if (quiet_str) | 176 | if (quiet_str) |
177 | quiet = simple_strtoul(quiet_str, NULL, 0) != 0; | 177 | quiet = simple_strtoul(quiet_str, NULL, 0) != 0; |
178 | 178 | ||
179 | cmd = argv[1]; | 179 | cmd = argv[1]; |
180 | 180 | ||
181 | if (strcmp(cmd, "info") == 0) { | 181 | if (strcmp(cmd, "info") == 0) { |
182 | 182 | ||
183 | putc('\n'); | 183 | putc('\n'); |
184 | for (i = 0; i < CFG_MAX_NAND_DEVICE; i++) { | 184 | for (i = 0; i < CFG_MAX_NAND_DEVICE; i++) { |
185 | if (nand_info[i].name) | 185 | if (nand_info[i].name) |
186 | printf("Device %d: %s, sector size %lu KiB\n", | 186 | printf("Device %d: %s, sector size %lu KiB\n", |
187 | i, nand_info[i].name, | 187 | i, nand_info[i].name, |
188 | nand_info[i].erasesize >> 10); | 188 | nand_info[i].erasesize >> 10); |
189 | } | 189 | } |
190 | return 0; | 190 | return 0; |
191 | } | 191 | } |
192 | 192 | ||
193 | if (strcmp(cmd, "device") == 0) { | 193 | if (strcmp(cmd, "device") == 0) { |
194 | 194 | ||
195 | if (argc < 3) { | 195 | if (argc < 3) { |
196 | if ((nand_curr_device < 0) || | 196 | if ((nand_curr_device < 0) || |
197 | (nand_curr_device >= CFG_MAX_NAND_DEVICE)) | 197 | (nand_curr_device >= CFG_MAX_NAND_DEVICE)) |
198 | puts("\nno devices available\n"); | 198 | puts("\nno devices available\n"); |
199 | else | 199 | else |
200 | printf("\nDevice %d: %s\n", nand_curr_device, | 200 | printf("\nDevice %d: %s\n", nand_curr_device, |
201 | nand_info[nand_curr_device].name); | 201 | nand_info[nand_curr_device].name); |
202 | return 0; | 202 | return 0; |
203 | } | 203 | } |
204 | dev = (int)simple_strtoul(argv[2], NULL, 10); | 204 | dev = (int)simple_strtoul(argv[2], NULL, 10); |
205 | if (dev < 0 || dev >= CFG_MAX_NAND_DEVICE || !nand_info[dev].name) { | 205 | if (dev < 0 || dev >= CFG_MAX_NAND_DEVICE || !nand_info[dev].name) { |
206 | puts("No such device\n"); | 206 | puts("No such device\n"); |
207 | return 1; | 207 | return 1; |
208 | } | 208 | } |
209 | printf("Device %d: %s", dev, nand_info[dev].name); | 209 | printf("Device %d: %s", dev, nand_info[dev].name); |
210 | puts("... is now current device\n"); | 210 | puts("... is now current device\n"); |
211 | nand_curr_device = dev; | 211 | nand_curr_device = dev; |
212 | 212 | ||
213 | #ifdef CFG_NAND_SELECT_DEVICE | 213 | #ifdef CFG_NAND_SELECT_DEVICE |
214 | /* | 214 | /* |
215 | * Select the chip in the board/cpu specific driver | 215 | * Select the chip in the board/cpu specific driver |
216 | */ | 216 | */ |
217 | board_nand_select_device(nand_info[dev].priv, dev); | 217 | board_nand_select_device(nand_info[dev].priv, dev); |
218 | #endif | 218 | #endif |
219 | 219 | ||
220 | return 0; | 220 | return 0; |
221 | } | 221 | } |
222 | 222 | ||
223 | if (strcmp(cmd, "bad") != 0 && strcmp(cmd, "erase") != 0 && | 223 | if (strcmp(cmd, "bad") != 0 && strcmp(cmd, "erase") != 0 && |
224 | strncmp(cmd, "dump", 4) != 0 && | 224 | strncmp(cmd, "dump", 4) != 0 && |
225 | strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0 && | 225 | strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0 && |
226 | strcmp(cmd, "scrub") != 0 && strcmp(cmd, "markbad") != 0 && | 226 | strcmp(cmd, "scrub") != 0 && strcmp(cmd, "markbad") != 0 && |
227 | strcmp(cmd, "biterr") != 0 && | 227 | strcmp(cmd, "biterr") != 0 && |
228 | strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0 ) | 228 | strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0 ) |
229 | goto usage; | 229 | goto usage; |
230 | 230 | ||
231 | /* the following commands operate on the current device */ | 231 | /* the following commands operate on the current device */ |
232 | if (nand_curr_device < 0 || nand_curr_device >= CFG_MAX_NAND_DEVICE || | 232 | if (nand_curr_device < 0 || nand_curr_device >= CFG_MAX_NAND_DEVICE || |
233 | !nand_info[nand_curr_device].name) { | 233 | !nand_info[nand_curr_device].name) { |
234 | puts("\nno devices available\n"); | 234 | puts("\nno devices available\n"); |
235 | return 1; | 235 | return 1; |
236 | } | 236 | } |
237 | nand = &nand_info[nand_curr_device]; | 237 | nand = &nand_info[nand_curr_device]; |
238 | 238 | ||
239 | if (strcmp(cmd, "bad") == 0) { | 239 | if (strcmp(cmd, "bad") == 0) { |
240 | printf("\nDevice %d bad blocks:\n", nand_curr_device); | 240 | printf("\nDevice %d bad blocks:\n", nand_curr_device); |
241 | for (off = 0; off < nand->size; off += nand->erasesize) | 241 | for (off = 0; off < nand->size; off += nand->erasesize) |
242 | if (nand_block_isbad(nand, off)) | 242 | if (nand_block_isbad(nand, off)) |
243 | printf(" %08x\n", off); | 243 | printf(" %08x\n", off); |
244 | return 0; | 244 | return 0; |
245 | } | 245 | } |
246 | 246 | ||
247 | /* | 247 | /* |
248 | * Syntax is: | 248 | * Syntax is: |
249 | * 0 1 2 3 4 | 249 | * 0 1 2 3 4 |
250 | * nand erase [clean] [off size] | 250 | * nand erase [clean] [off size] |
251 | */ | 251 | */ |
252 | if (strcmp(cmd, "erase") == 0 || strcmp(cmd, "scrub") == 0) { | 252 | if (strcmp(cmd, "erase") == 0 || strcmp(cmd, "scrub") == 0) { |
253 | nand_erase_options_t opts; | 253 | nand_erase_options_t opts; |
254 | /* "clean" at index 2 means request to write cleanmarker */ | 254 | /* "clean" at index 2 means request to write cleanmarker */ |
255 | int clean = argc > 2 && !strcmp("clean", argv[2]); | 255 | int clean = argc > 2 && !strcmp("clean", argv[2]); |
256 | int o = clean ? 3 : 2; | 256 | int o = clean ? 3 : 2; |
257 | int scrub = !strcmp(cmd, "scrub"); | 257 | int scrub = !strcmp(cmd, "scrub"); |
258 | 258 | ||
259 | printf("\nNAND %s: ", scrub ? "scrub" : "erase"); | 259 | printf("\nNAND %s: ", scrub ? "scrub" : "erase"); |
260 | /* skip first two or three arguments, look for offset and size */ | 260 | /* skip first two or three arguments, look for offset and size */ |
261 | if (arg_off_size(argc - o, argv + o, nand, &off, &size) != 0) | 261 | if (arg_off_size(argc - o, argv + o, nand, &off, &size) != 0) |
262 | return 1; | 262 | return 1; |
263 | 263 | ||
264 | memset(&opts, 0, sizeof(opts)); | 264 | memset(&opts, 0, sizeof(opts)); |
265 | opts.offset = off; | 265 | opts.offset = off; |
266 | opts.length = size; | 266 | opts.length = size; |
267 | opts.jffs2 = clean; | 267 | opts.jffs2 = clean; |
268 | opts.quiet = quiet; | 268 | opts.quiet = quiet; |
269 | 269 | ||
270 | if (scrub) { | 270 | if (scrub) { |
271 | puts("Warning: " | 271 | puts("Warning: " |
272 | "scrub option will erase all factory set " | 272 | "scrub option will erase all factory set " |
273 | "bad blocks!\n" | 273 | "bad blocks!\n" |
274 | " " | 274 | " " |
275 | "There is no reliable way to recover them.\n" | 275 | "There is no reliable way to recover them.\n" |
276 | " " | 276 | " " |
277 | "Use this command only for testing purposes " | 277 | "Use this command only for testing purposes " |
278 | "if you\n" | 278 | "if you\n" |
279 | " " | 279 | " " |
280 | "are sure of what you are doing!\n" | 280 | "are sure of what you are doing!\n" |
281 | "\nReally scrub this NAND flash? <y/N>\n"); | 281 | "\nReally scrub this NAND flash? <y/N>\n"); |
282 | 282 | ||
283 | if (getc() == 'y' && getc() == '\r') { | 283 | if (getc() == 'y' && getc() == '\r') { |
284 | opts.scrub = 1; | 284 | opts.scrub = 1; |
285 | } else { | 285 | } else { |
286 | puts("scrub aborted\n"); | 286 | puts("scrub aborted\n"); |
287 | return -1; | 287 | return -1; |
288 | } | 288 | } |
289 | } | 289 | } |
290 | ret = nand_erase_opts(nand, &opts); | 290 | ret = nand_erase_opts(nand, &opts); |
291 | printf("%s\n", ret ? "ERROR" : "OK"); | 291 | printf("%s\n", ret ? "ERROR" : "OK"); |
292 | 292 | ||
293 | return ret == 0 ? 0 : 1; | 293 | return ret == 0 ? 0 : 1; |
294 | } | 294 | } |
295 | 295 | ||
296 | if (strncmp(cmd, "dump", 4) == 0) { | 296 | if (strncmp(cmd, "dump", 4) == 0) { |
297 | if (argc < 3) | 297 | if (argc < 3) |
298 | goto usage; | 298 | goto usage; |
299 | 299 | ||
300 | s = strchr(cmd, '.'); | 300 | s = strchr(cmd, '.'); |
301 | off = (int)simple_strtoul(argv[2], NULL, 16); | 301 | off = (int)simple_strtoul(argv[2], NULL, 16); |
302 | 302 | ||
303 | if (s != NULL && strcmp(s, ".oob") == 0) | 303 | if (s != NULL && strcmp(s, ".oob") == 0) |
304 | ret = nand_dump_oob(nand, off); | 304 | ret = nand_dump_oob(nand, off); |
305 | else | 305 | else |
306 | ret = nand_dump(nand, off); | 306 | ret = nand_dump(nand, off); |
307 | 307 | ||
308 | return ret == 0 ? 1 : 0; | 308 | return ret == 0 ? 1 : 0; |
309 | 309 | ||
310 | } | 310 | } |
311 | 311 | ||
312 | /* read write */ | 312 | /* read write */ |
313 | if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) { | 313 | if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) { |
314 | int read; | 314 | int read; |
315 | 315 | ||
316 | if (argc < 4) | 316 | if (argc < 4) |
317 | goto usage; | 317 | goto usage; |
318 | 318 | ||
319 | addr = (ulong)simple_strtoul(argv[2], NULL, 16); | 319 | addr = (ulong)simple_strtoul(argv[2], NULL, 16); |
320 | 320 | ||
321 | read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */ | 321 | read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */ |
322 | printf("\nNAND %s: ", read ? "read" : "write"); | 322 | printf("\nNAND %s: ", read ? "read" : "write"); |
323 | if (arg_off_size(argc - 3, argv + 3, nand, &off, &size) != 0) | 323 | if (arg_off_size(argc - 3, argv + 3, nand, &off, &size) != 0) |
324 | return 1; | 324 | return 1; |
325 | 325 | ||
326 | s = strchr(cmd, '.'); | 326 | s = strchr(cmd, '.'); |
327 | if (s != NULL && | 327 | if (s != NULL && |
328 | (!strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i"))) { | 328 | (!strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i"))) { |
329 | if (read) { | 329 | if (read) { |
330 | /* read */ | 330 | /* read */ |
331 | nand_read_options_t opts; | 331 | nand_read_options_t opts; |
332 | memset(&opts, 0, sizeof(opts)); | 332 | memset(&opts, 0, sizeof(opts)); |
333 | opts.buffer = (u_char*) addr; | 333 | opts.buffer = (u_char*) addr; |
334 | opts.length = size; | 334 | opts.length = size; |
335 | opts.offset = off; | 335 | opts.offset = off; |
336 | opts.quiet = quiet; | 336 | opts.quiet = quiet; |
337 | ret = nand_read_opts(nand, &opts); | 337 | ret = nand_read_opts(nand, &opts); |
338 | } else { | 338 | } else { |
339 | /* write */ | 339 | /* write */ |
340 | nand_write_options_t opts; | 340 | nand_write_options_t opts; |
341 | memset(&opts, 0, sizeof(opts)); | 341 | memset(&opts, 0, sizeof(opts)); |
342 | opts.buffer = (u_char*) addr; | 342 | opts.buffer = (u_char*) addr; |
343 | opts.length = size; | 343 | opts.length = size; |
344 | opts.offset = off; | 344 | opts.offset = off; |
345 | /* opts.forcejffs2 = 1; */ | 345 | /* opts.forcejffs2 = 1; */ |
346 | opts.pad = 1; | 346 | opts.pad = 1; |
347 | opts.blockalign = 1; | 347 | opts.blockalign = 1; |
348 | opts.quiet = quiet; | 348 | opts.quiet = quiet; |
349 | ret = nand_write_opts(nand, &opts); | 349 | ret = nand_write_opts(nand, &opts); |
350 | } | 350 | } |
351 | } else if (s != NULL && !strcmp(s, ".oob")) { | 351 | } else if (s != NULL && !strcmp(s, ".oob")) { |
352 | /* read out-of-band data */ | 352 | /* read out-of-band data */ |
353 | if (read) | 353 | if (read) |
354 | ret = nand->read_oob(nand, off, size, &size, | 354 | ret = nand->read_oob(nand, off, size, &size, |
355 | (u_char *) addr); | 355 | (u_char *) addr); |
356 | else | 356 | else |
357 | ret = nand->write_oob(nand, off, size, &size, | 357 | ret = nand->write_oob(nand, off, size, &size, |
358 | (u_char *) addr); | 358 | (u_char *) addr); |
359 | } else { | 359 | } else { |
360 | if (read) | 360 | if (read) |
361 | ret = nand_read(nand, off, &size, (u_char *)addr); | 361 | ret = nand_read(nand, off, &size, (u_char *)addr); |
362 | else | 362 | else |
363 | ret = nand_write(nand, off, &size, (u_char *)addr); | 363 | ret = nand_write(nand, off, &size, (u_char *)addr); |
364 | } | 364 | } |
365 | 365 | ||
366 | printf(" %d bytes %s: %s\n", size, | 366 | printf(" %d bytes %s: %s\n", size, |
367 | read ? "read" : "written", ret ? "ERROR" : "OK"); | 367 | read ? "read" : "written", ret ? "ERROR" : "OK"); |
368 | 368 | ||
369 | return ret == 0 ? 0 : 1; | 369 | return ret == 0 ? 0 : 1; |
370 | } | 370 | } |
371 | 371 | ||
372 | if (strcmp(cmd, "markbad") == 0) { | 372 | if (strcmp(cmd, "markbad") == 0) { |
373 | addr = (ulong)simple_strtoul(argv[2], NULL, 16); | 373 | addr = (ulong)simple_strtoul(argv[2], NULL, 16); |
374 | 374 | ||
375 | int ret = nand->block_markbad(nand, addr); | 375 | int ret = nand->block_markbad(nand, addr); |
376 | if (ret == 0) { | 376 | if (ret == 0) { |
377 | printf("block 0x%08lx successfully marked as bad\n", | 377 | printf("block 0x%08lx successfully marked as bad\n", |
378 | (ulong) addr); | 378 | (ulong) addr); |
379 | return 0; | 379 | return 0; |
380 | } else { | 380 | } else { |
381 | printf("block 0x%08lx NOT marked as bad! ERROR %d\n", | 381 | printf("block 0x%08lx NOT marked as bad! ERROR %d\n", |
382 | (ulong) addr, ret); | 382 | (ulong) addr, ret); |
383 | } | 383 | } |
384 | return 1; | 384 | return 1; |
385 | } | 385 | } |
386 | if (strcmp(cmd, "biterr") == 0) { | 386 | if (strcmp(cmd, "biterr") == 0) { |
387 | /* todo */ | 387 | /* todo */ |
388 | return 1; | 388 | return 1; |
389 | } | 389 | } |
390 | 390 | ||
391 | if (strcmp(cmd, "lock") == 0) { | 391 | if (strcmp(cmd, "lock") == 0) { |
392 | int tight = 0; | 392 | int tight = 0; |
393 | int status = 0; | 393 | int status = 0; |
394 | if (argc == 3) { | 394 | if (argc == 3) { |
395 | if (!strcmp("tight", argv[2])) | 395 | if (!strcmp("tight", argv[2])) |
396 | tight = 1; | 396 | tight = 1; |
397 | if (!strcmp("status", argv[2])) | 397 | if (!strcmp("status", argv[2])) |
398 | status = 1; | 398 | status = 1; |
399 | } | 399 | } |
400 | 400 | ||
401 | if (status) { | 401 | if (status) { |
402 | ulong block_start = 0; | 402 | ulong block_start = 0; |
403 | ulong off; | 403 | ulong off; |
404 | int last_status = -1; | 404 | int last_status = -1; |
405 | 405 | ||
406 | struct nand_chip *nand_chip = nand->priv; | 406 | struct nand_chip *nand_chip = nand->priv; |
407 | /* check the WP bit */ | 407 | /* check the WP bit */ |
408 | nand_chip->cmdfunc (nand, NAND_CMD_STATUS, -1, -1); | 408 | nand_chip->cmdfunc (nand, NAND_CMD_STATUS, -1, -1); |
409 | printf("device is %swrite protected\n", | 409 | printf("device is %swrite protected\n", |
410 | (nand_chip->read_byte(nand) & 0x80 ? | 410 | (nand_chip->read_byte(nand) & 0x80 ? |
411 | "NOT " : "" ) ); | 411 | "NOT " : "" ) ); |
412 | 412 | ||
413 | for (off = 0; off < nand->size; off += nand->oobblock) { | 413 | for (off = 0; off < nand->size; off += nand->oobblock) { |
414 | int s = nand_get_lock_status(nand, off); | 414 | int s = nand_get_lock_status(nand, off); |
415 | 415 | ||
416 | /* print message only if status has changed | 416 | /* print message only if status has changed |
417 | * or at end of chip | 417 | * or at end of chip |
418 | */ | 418 | */ |
419 | if (off == nand->size - nand->oobblock | 419 | if (off == nand->size - nand->oobblock |
420 | || (s != last_status && off != 0)) { | 420 | || (s != last_status && off != 0)) { |
421 | 421 | ||
422 | printf("%08x - %08x: %8d pages %s%s%s\n", | 422 | printf("%08x - %08x: %8d pages %s%s%s\n", |
423 | block_start, | 423 | block_start, |
424 | off-1, | 424 | off-1, |
425 | (off-block_start)/nand->oobblock, | 425 | (off-block_start)/nand->oobblock, |
426 | ((last_status & NAND_LOCK_STATUS_TIGHT) ? "TIGHT " : ""), | 426 | ((last_status & NAND_LOCK_STATUS_TIGHT) ? "TIGHT " : ""), |
427 | ((last_status & NAND_LOCK_STATUS_LOCK) ? "LOCK " : ""), | 427 | ((last_status & NAND_LOCK_STATUS_LOCK) ? "LOCK " : ""), |
428 | ((last_status & NAND_LOCK_STATUS_UNLOCK) ? "UNLOCK " : "")); | 428 | ((last_status & NAND_LOCK_STATUS_UNLOCK) ? "UNLOCK " : "")); |
429 | } | 429 | } |
430 | 430 | ||
431 | last_status = s; | 431 | last_status = s; |
432 | } | 432 | } |
433 | } else { | 433 | } else { |
434 | if (!nand_lock(nand, tight)) { | 434 | if (!nand_lock(nand, tight)) { |
435 | puts("NAND flash successfully locked\n"); | 435 | puts("NAND flash successfully locked\n"); |
436 | } else { | 436 | } else { |
437 | puts("Error locking NAND flash\n"); | 437 | puts("Error locking NAND flash\n"); |
438 | return 1; | 438 | return 1; |
439 | } | 439 | } |
440 | } | 440 | } |
441 | return 0; | 441 | return 0; |
442 | } | 442 | } |
443 | 443 | ||
444 | if (strcmp(cmd, "unlock") == 0) { | 444 | if (strcmp(cmd, "unlock") == 0) { |
445 | if (arg_off_size(argc - 2, argv + 2, nand, &off, &size) < 0) | 445 | if (arg_off_size(argc - 2, argv + 2, nand, &off, &size) < 0) |
446 | return 1; | 446 | return 1; |
447 | 447 | ||
448 | if (!nand_unlock(nand, off, size)) { | 448 | if (!nand_unlock(nand, off, size)) { |
449 | puts("NAND flash successfully unlocked\n"); | 449 | puts("NAND flash successfully unlocked\n"); |
450 | } else { | 450 | } else { |
451 | puts("Error unlocking NAND flash, " | 451 | puts("Error unlocking NAND flash, " |
452 | "write and erase will probably fail\n"); | 452 | "write and erase will probably fail\n"); |
453 | return 1; | 453 | return 1; |
454 | } | 454 | } |
455 | return 0; | 455 | return 0; |
456 | } | 456 | } |
457 | 457 | ||
458 | usage: | 458 | usage: |
459 | printf("Usage:\n%s\n", cmdtp->usage); | 459 | printf("Usage:\n%s\n", cmdtp->usage); |
460 | return 1; | 460 | return 1; |
461 | } | 461 | } |
462 | 462 | ||
463 | U_BOOT_CMD(nand, 5, 1, do_nand, | 463 | U_BOOT_CMD(nand, 5, 1, do_nand, |
464 | "nand - NAND sub-system\n", | 464 | "nand - NAND sub-system\n", |
465 | "info - show available NAND devices\n" | 465 | "info - show available NAND devices\n" |
466 | "nand device [dev] - show or set current device\n" | 466 | "nand device [dev] - show or set current device\n" |
467 | "nand read[.jffs2] - addr off|partition size\n" | 467 | "nand read[.jffs2] - addr off|partition size\n" |
468 | "nand write[.jffs2] - addr off|partition size - read/write `size' bytes starting\n" | 468 | "nand write[.jffs2] - addr off|partition size - read/write `size' bytes starting\n" |
469 | " at offset `off' to/from memory address `addr'\n" | 469 | " at offset `off' to/from memory address `addr'\n" |
470 | "nand erase [clean] [off size] - erase `size' bytes from\n" | 470 | "nand erase [clean] [off size] - erase `size' bytes from\n" |
471 | " offset `off' (entire device if not specified)\n" | 471 | " offset `off' (entire device if not specified)\n" |
472 | "nand bad - show bad blocks\n" | 472 | "nand bad - show bad blocks\n" |
473 | "nand dump[.oob] off - dump page\n" | 473 | "nand dump[.oob] off - dump page\n" |
474 | "nand scrub - really clean NAND erasing bad blocks (UNSAFE)\n" | 474 | "nand scrub - really clean NAND erasing bad blocks (UNSAFE)\n" |
475 | "nand markbad off - mark bad block at offset (UNSAFE)\n" | 475 | "nand markbad off - mark bad block at offset (UNSAFE)\n" |
476 | "nand biterr off - make a bit error at offset (UNSAFE)\n" | 476 | "nand biterr off - make a bit error at offset (UNSAFE)\n" |
477 | "nand lock [tight] [status] - bring nand to lock state or display locked pages\n" | 477 | "nand lock [tight] [status] - bring nand to lock state or display locked pages\n" |
478 | "nand unlock [offset] [size] - unlock section\n"); | 478 | "nand unlock [offset] [size] - unlock section\n"); |
479 | 479 | ||
480 | static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand, | 480 | static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand, |
481 | ulong offset, ulong addr, char *cmd) | 481 | ulong offset, ulong addr, char *cmd) |
482 | { | 482 | { |
483 | int r; | 483 | int r; |
484 | char *ep, *s; | 484 | char *ep, *s; |
485 | size_t cnt; | 485 | size_t cnt; |
486 | image_header_t *hdr; | 486 | image_header_t *hdr; |
487 | int jffs2 = 0; | 487 | int jffs2 = 0; |
488 | #if defined(CONFIG_FIT) | 488 | #if defined(CONFIG_FIT) |
489 | const void *fit_hdr; | 489 | const void *fit_hdr; |
490 | #endif | 490 | #endif |
491 | 491 | ||
492 | s = strchr(cmd, '.'); | 492 | s = strchr(cmd, '.'); |
493 | if (s != NULL && | 493 | if (s != NULL && |
494 | (!strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i"))) | 494 | (!strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i"))) |
495 | jffs2 = 1; | 495 | jffs2 = 1; |
496 | 496 | ||
497 | printf("\nLoading from %s, offset 0x%lx\n", nand->name, offset); | 497 | printf("\nLoading from %s, offset 0x%lx\n", nand->name, offset); |
498 | 498 | ||
499 | cnt = nand->oobblock; | 499 | cnt = nand->oobblock; |
500 | if (jffs2) { | 500 | if (jffs2) { |
501 | nand_read_options_t opts; | 501 | nand_read_options_t opts; |
502 | memset(&opts, 0, sizeof(opts)); | 502 | memset(&opts, 0, sizeof(opts)); |
503 | opts.buffer = (u_char*) addr; | 503 | opts.buffer = (u_char*) addr; |
504 | opts.length = cnt; | 504 | opts.length = cnt; |
505 | opts.offset = offset; | 505 | opts.offset = offset; |
506 | opts.quiet = 1; | 506 | opts.quiet = 1; |
507 | r = nand_read_opts(nand, &opts); | 507 | r = nand_read_opts(nand, &opts); |
508 | } else { | 508 | } else { |
509 | r = nand_read(nand, offset, &cnt, (u_char *) addr); | 509 | r = nand_read(nand, offset, &cnt, (u_char *) addr); |
510 | } | 510 | } |
511 | 511 | ||
512 | if (r) { | 512 | if (r) { |
513 | puts("** Read error\n"); | 513 | puts("** Read error\n"); |
514 | show_boot_progress (-56); | 514 | show_boot_progress (-56); |
515 | return 1; | 515 | return 1; |
516 | } | 516 | } |
517 | show_boot_progress (56); | 517 | show_boot_progress (56); |
518 | 518 | ||
519 | switch (genimg_get_format ((void *)addr)) { | 519 | switch (genimg_get_format ((void *)addr)) { |
520 | case IMAGE_FORMAT_LEGACY: | 520 | case IMAGE_FORMAT_LEGACY: |
521 | hdr = (image_header_t *)addr; | 521 | hdr = (image_header_t *)addr; |
522 | 522 | ||
523 | show_boot_progress (57); | 523 | show_boot_progress (57); |
524 | image_print_contents (hdr); | 524 | image_print_contents (hdr); |
525 | 525 | ||
526 | cnt = image_get_image_size (hdr); | 526 | cnt = image_get_image_size (hdr); |
527 | break; | 527 | break; |
528 | #if defined(CONFIG_FIT) | 528 | #if defined(CONFIG_FIT) |
529 | case IMAGE_FORMAT_FIT: | 529 | case IMAGE_FORMAT_FIT: |
530 | fit_hdr = (const void *)addr; | 530 | fit_hdr = (const void *)addr; |
531 | if (!fit_check_format (fit_hdr)) { | 531 | if (!fit_check_format (fit_hdr)) { |
532 | show_boot_progress (-150); | 532 | show_boot_progress (-150); |
533 | puts ("** Bad FIT image format\n"); | 533 | puts ("** Bad FIT image format\n"); |
534 | return 1; | 534 | return 1; |
535 | } | 535 | } |
536 | show_boot_progress (151); | 536 | show_boot_progress (151); |
537 | puts ("Fit image detected...\n"); | 537 | puts ("Fit image detected...\n"); |
538 | 538 | ||
539 | cnt = fit_get_size (fit_hdr); | 539 | cnt = fit_get_size (fit_hdr); |
540 | break; | 540 | break; |
541 | #endif | 541 | #endif |
542 | default: | 542 | default: |
543 | show_boot_progress (-57); | 543 | show_boot_progress (-57); |
544 | puts ("** Unknown image type\n"); | 544 | puts ("** Unknown image type\n"); |
545 | return 1; | 545 | return 1; |
546 | } | 546 | } |
547 | 547 | ||
548 | if (jffs2) { | 548 | if (jffs2) { |
549 | nand_read_options_t opts; | 549 | nand_read_options_t opts; |
550 | memset(&opts, 0, sizeof(opts)); | 550 | memset(&opts, 0, sizeof(opts)); |
551 | opts.buffer = (u_char*) addr; | 551 | opts.buffer = (u_char*) addr; |
552 | opts.length = cnt; | 552 | opts.length = cnt; |
553 | opts.offset = offset; | 553 | opts.offset = offset; |
554 | opts.quiet = 1; | 554 | opts.quiet = 1; |
555 | r = nand_read_opts(nand, &opts); | 555 | r = nand_read_opts(nand, &opts); |
556 | } else { | 556 | } else { |
557 | r = nand_read(nand, offset, &cnt, (u_char *) addr); | 557 | r = nand_read(nand, offset, &cnt, (u_char *) addr); |
558 | } | 558 | } |
559 | 559 | ||
560 | if (r) { | 560 | if (r) { |
561 | puts("** Read error\n"); | 561 | puts("** Read error\n"); |
562 | show_boot_progress (-58); | 562 | show_boot_progress (-58); |
563 | return 1; | 563 | return 1; |
564 | } | 564 | } |
565 | show_boot_progress (58); | 565 | show_boot_progress (58); |
566 | 566 | ||
567 | #if defined(CONFIG_FIT) | 567 | #if defined(CONFIG_FIT) |
568 | /* This cannot be done earlier, we need complete FIT image in RAM first */ | 568 | /* This cannot be done earlier, we need complete FIT image in RAM first */ |
569 | if (genimg_get_format ((void *)addr) == IMAGE_FORMAT_FIT) | 569 | if (genimg_get_format ((void *)addr) == IMAGE_FORMAT_FIT) |
570 | fit_print_contents ((const void *)addr); | 570 | fit_print_contents ((const void *)addr); |
571 | #endif | 571 | #endif |
572 | 572 | ||
573 | /* Loading ok, update default load address */ | 573 | /* Loading ok, update default load address */ |
574 | 574 | ||
575 | load_addr = addr; | 575 | load_addr = addr; |
576 | 576 | ||
577 | /* Check if we should attempt an auto-start */ | 577 | /* Check if we should attempt an auto-start */ |
578 | if (((ep = getenv("autostart")) != NULL) && (strcmp(ep, "yes") == 0)) { | 578 | if (((ep = getenv("autostart")) != NULL) && (strcmp(ep, "yes") == 0)) { |
579 | char *local_args[2]; | 579 | char *local_args[2]; |
580 | extern int do_bootm(cmd_tbl_t *, int, int, char *[]); | 580 | extern int do_bootm(cmd_tbl_t *, int, int, char *[]); |
581 | 581 | ||
582 | local_args[0] = cmd; | 582 | local_args[0] = cmd; |
583 | local_args[1] = NULL; | 583 | local_args[1] = NULL; |
584 | 584 | ||
585 | printf("Automatic boot of image at addr 0x%08lx ...\n", addr); | 585 | printf("Automatic boot of image at addr 0x%08lx ...\n", addr); |
586 | 586 | ||
587 | do_bootm(cmdtp, 0, 1, local_args); | 587 | do_bootm(cmdtp, 0, 1, local_args); |
588 | return 1; | 588 | return 1; |
589 | } | 589 | } |
590 | return 0; | 590 | return 0; |
591 | } | 591 | } |
592 | 592 | ||
593 | int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) | 593 | int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) |
594 | { | 594 | { |
595 | char *boot_device = NULL; | 595 | char *boot_device = NULL; |
596 | int idx; | 596 | int idx; |
597 | ulong addr, offset = 0; | 597 | ulong addr, offset = 0; |
598 | #if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE) | 598 | #if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE) |
599 | struct mtd_device *dev; | 599 | struct mtd_device *dev; |
600 | struct part_info *part; | 600 | struct part_info *part; |
601 | u8 pnum; | 601 | u8 pnum; |
602 | 602 | ||
603 | if (argc >= 2) { | 603 | if (argc >= 2) { |
604 | char *p = (argc == 2) ? argv[1] : argv[2]; | 604 | char *p = (argc == 2) ? argv[1] : argv[2]; |
605 | if (!(str2long(p, &addr)) && (mtdparts_init() == 0) && | 605 | if (!(str2long(p, &addr)) && (mtdparts_init() == 0) && |
606 | (find_dev_and_part(p, &dev, &pnum, &part) == 0)) { | 606 | (find_dev_and_part(p, &dev, &pnum, &part) == 0)) { |
607 | if (dev->id->type != MTD_DEV_TYPE_NAND) { | 607 | if (dev->id->type != MTD_DEV_TYPE_NAND) { |
608 | puts("Not a NAND device\n"); | 608 | puts("Not a NAND device\n"); |
609 | return 1; | 609 | return 1; |
610 | } | 610 | } |
611 | if (argc > 3) | 611 | if (argc > 3) |
612 | goto usage; | 612 | goto usage; |
613 | if (argc == 3) | 613 | if (argc == 3) |
614 | addr = simple_strtoul(argv[1], NULL, 16); | 614 | addr = simple_strtoul(argv[1], NULL, 16); |
615 | else | 615 | else |
616 | addr = CFG_LOAD_ADDR; | 616 | addr = CFG_LOAD_ADDR; |
617 | return nand_load_image(cmdtp, &nand_info[dev->id->num], | 617 | return nand_load_image(cmdtp, &nand_info[dev->id->num], |
618 | part->offset, addr, argv[0]); | 618 | part->offset, addr, argv[0]); |
619 | } | 619 | } |
620 | } | 620 | } |
621 | #endif | 621 | #endif |
622 | 622 | ||
623 | show_boot_progress(52); | 623 | show_boot_progress(52); |
624 | switch (argc) { | 624 | switch (argc) { |
625 | case 1: | 625 | case 1: |
626 | addr = CFG_LOAD_ADDR; | 626 | addr = CFG_LOAD_ADDR; |
627 | boot_device = getenv("bootdevice"); | 627 | boot_device = getenv("bootdevice"); |
628 | break; | 628 | break; |
629 | case 2: | 629 | case 2: |
630 | addr = simple_strtoul(argv[1], NULL, 16); | 630 | addr = simple_strtoul(argv[1], NULL, 16); |
631 | boot_device = getenv("bootdevice"); | 631 | boot_device = getenv("bootdevice"); |
632 | break; | 632 | break; |
633 | case 3: | 633 | case 3: |
634 | addr = simple_strtoul(argv[1], NULL, 16); | 634 | addr = simple_strtoul(argv[1], NULL, 16); |
635 | boot_device = argv[2]; | 635 | boot_device = argv[2]; |
636 | break; | 636 | break; |
637 | case 4: | 637 | case 4: |
638 | addr = simple_strtoul(argv[1], NULL, 16); | 638 | addr = simple_strtoul(argv[1], NULL, 16); |
639 | boot_device = argv[2]; | 639 | boot_device = argv[2]; |
640 | offset = simple_strtoul(argv[3], NULL, 16); | 640 | offset = simple_strtoul(argv[3], NULL, 16); |
641 | break; | 641 | break; |
642 | default: | 642 | default: |
643 | #if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE) | 643 | #if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE) |
644 | usage: | 644 | usage: |
645 | #endif | 645 | #endif |
646 | printf("Usage:\n%s\n", cmdtp->usage); | 646 | printf("Usage:\n%s\n", cmdtp->usage); |
647 | show_boot_progress(-53); | 647 | show_boot_progress(-53); |
648 | return 1; | 648 | return 1; |
649 | } | 649 | } |
650 | 650 | ||
651 | show_boot_progress(53); | 651 | show_boot_progress(53); |
652 | if (!boot_device) { | 652 | if (!boot_device) { |
653 | puts("\n** No boot device **\n"); | 653 | puts("\n** No boot device **\n"); |
654 | show_boot_progress(-54); | 654 | show_boot_progress(-54); |
655 | return 1; | 655 | return 1; |
656 | } | 656 | } |
657 | show_boot_progress(54); | 657 | show_boot_progress(54); |
658 | 658 | ||
659 | idx = simple_strtoul(boot_device, NULL, 16); | 659 | idx = simple_strtoul(boot_device, NULL, 16); |
660 | 660 | ||
661 | if (idx < 0 || idx >= CFG_MAX_NAND_DEVICE || !nand_info[idx].name) { | 661 | if (idx < 0 || idx >= CFG_MAX_NAND_DEVICE || !nand_info[idx].name) { |
662 | printf("\n** Device %d not available\n", idx); | 662 | printf("\n** Device %d not available\n", idx); |
663 | show_boot_progress(-55); | 663 | show_boot_progress(-55); |
664 | return 1; | 664 | return 1; |
665 | } | 665 | } |
666 | show_boot_progress(55); | 666 | show_boot_progress(55); |
667 | 667 | ||
668 | return nand_load_image(cmdtp, &nand_info[idx], offset, addr, argv[0]); | 668 | return nand_load_image(cmdtp, &nand_info[idx], offset, addr, argv[0]); |
669 | } | 669 | } |
670 | 670 | ||
671 | U_BOOT_CMD(nboot, 4, 1, do_nandboot, | 671 | U_BOOT_CMD(nboot, 4, 1, do_nandboot, |
672 | "nboot - boot from NAND device\n", | 672 | "nboot - boot from NAND device\n", |
673 | "[.jffs2] [partition] | [[[loadAddr] dev] offset]\n"); | 673 | "[.jffs2] [partition] | [[[loadAddr] dev] offset]\n"); |
674 | 674 | ||
675 | #endif | 675 | #endif |
676 | 676 | ||
677 | #else /* CFG_NAND_LEGACY */ | 677 | #else /* CFG_NAND_LEGACY */ |
678 | /* | 678 | /* |
679 | * | 679 | * |
680 | * Legacy NAND support - to be phased out | 680 | * Legacy NAND support - to be phased out |
681 | * | 681 | * |
682 | */ | 682 | */ |
683 | #include <command.h> | 683 | #include <command.h> |
684 | #include <malloc.h> | 684 | #include <malloc.h> |
685 | #include <asm/io.h> | 685 | #include <asm/io.h> |
686 | #include <watchdog.h> | 686 | #include <watchdog.h> |
687 | 687 | ||
688 | #ifdef CONFIG_show_boot_progress | 688 | #ifdef CONFIG_show_boot_progress |
689 | # include <status_led.h> | 689 | # include <status_led.h> |
690 | # define show_boot_progress(arg) show_boot_progress(arg) | 690 | # define show_boot_progress(arg) show_boot_progress(arg) |
691 | #else | 691 | #else |
692 | # define show_boot_progress(arg) | 692 | # define show_boot_progress(arg) |
693 | #endif | 693 | #endif |
694 | 694 | ||
695 | #if defined(CONFIG_CMD_NAND) | 695 | #if defined(CONFIG_CMD_NAND) |
696 | #include <linux/mtd/nand_legacy.h> | 696 | #include <linux/mtd/nand_legacy.h> |
697 | #if 0 | 697 | #if 0 |
698 | #include <linux/mtd/nand_ids.h> | 698 | #include <linux/mtd/nand_ids.h> |
699 | #include <jffs2/jffs2.h> | 699 | #include <jffs2/jffs2.h> |
700 | #endif | 700 | #endif |
701 | 701 | ||
702 | #ifdef CONFIG_OMAP1510 | 702 | #ifdef CONFIG_OMAP1510 |
703 | void archflashwp(void *archdata, int wp); | 703 | void archflashwp(void *archdata, int wp); |
704 | #endif | 704 | #endif |
705 | 705 | ||
706 | #define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1))) | 706 | #define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1))) |
707 | 707 | ||
708 | #undef NAND_DEBUG | 708 | #undef NAND_DEBUG |
709 | #undef PSYCHO_DEBUG | 709 | #undef PSYCHO_DEBUG |
710 | 710 | ||
711 | /* ****************** WARNING ********************* | 711 | /* ****************** WARNING ********************* |
712 | * When ALLOW_ERASE_BAD_DEBUG is non-zero the erase command will | 712 | * When ALLOW_ERASE_BAD_DEBUG is non-zero the erase command will |
713 | * erase (or at least attempt to erase) blocks that are marked | 713 | * erase (or at least attempt to erase) blocks that are marked |
714 | * bad. This can be very handy if you are _sure_ that the block | 714 | * bad. This can be very handy if you are _sure_ that the block |
715 | * is OK, say because you marked a good block bad to test bad | 715 | * is OK, say because you marked a good block bad to test bad |
716 | * block handling and you are done testing, or if you have | 716 | * block handling and you are done testing, or if you have |
717 | * accidentally marked blocks bad. | 717 | * accidentally marked blocks bad. |
718 | * | 718 | * |
719 | * Erasing factory marked bad blocks is a _bad_ idea. If the | 719 | * Erasing factory marked bad blocks is a _bad_ idea. If the |
720 | * erase succeeds there is no reliable way to find them again, | 720 | * erase succeeds there is no reliable way to find them again, |
721 | * and attempting to program or erase bad blocks can affect | 721 | * and attempting to program or erase bad blocks can affect |
722 | * the data in _other_ (good) blocks. | 722 | * the data in _other_ (good) blocks. |
723 | */ | 723 | */ |
724 | #define ALLOW_ERASE_BAD_DEBUG 0 | 724 | #define ALLOW_ERASE_BAD_DEBUG 0 |
725 | 725 | ||
726 | #define CONFIG_MTD_NAND_ECC /* enable ECC */ | 726 | #define CONFIG_MTD_NAND_ECC /* enable ECC */ |
727 | #define CONFIG_MTD_NAND_ECC_JFFS2 | 727 | #define CONFIG_MTD_NAND_ECC_JFFS2 |
728 | 728 | ||
729 | /* bits for nand_legacy_rw() `cmd'; or together as needed */ | 729 | /* bits for nand_legacy_rw() `cmd'; or together as needed */ |
730 | #define NANDRW_READ 0x01 | 730 | #define NANDRW_READ 0x01 |
731 | #define NANDRW_WRITE 0x00 | 731 | #define NANDRW_WRITE 0x00 |
732 | #define NANDRW_JFFS2 0x02 | 732 | #define NANDRW_JFFS2 0x02 |
733 | #define NANDRW_JFFS2_SKIP 0x04 | 733 | #define NANDRW_JFFS2_SKIP 0x04 |
734 | 734 | ||
735 | /* | 735 | /* |
736 | * Imports from nand_legacy.c | 736 | * Imports from nand_legacy.c |
737 | */ | 737 | */ |
738 | extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE]; | 738 | extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE]; |
739 | extern int curr_device; | 739 | extern int curr_device; |
740 | extern int nand_legacy_erase(struct nand_chip *nand, size_t ofs, | 740 | extern int nand_legacy_erase(struct nand_chip *nand, size_t ofs, |
741 | size_t len, int clean); | 741 | size_t len, int clean); |
742 | extern int nand_legacy_rw(struct nand_chip *nand, int cmd, size_t start, | 742 | extern int nand_legacy_rw(struct nand_chip *nand, int cmd, size_t start, |
743 | size_t len, size_t *retlen, u_char *buf); | 743 | size_t len, size_t *retlen, u_char *buf); |
744 | extern void nand_print(struct nand_chip *nand); | 744 | extern void nand_print(struct nand_chip *nand); |
745 | extern void nand_print_bad(struct nand_chip *nand); | 745 | extern void nand_print_bad(struct nand_chip *nand); |
746 | extern int nand_read_oob(struct nand_chip *nand, size_t ofs, | 746 | extern int nand_read_oob(struct nand_chip *nand, size_t ofs, |
747 | size_t len, size_t *retlen, u_char *buf); | 747 | size_t len, size_t *retlen, u_char *buf); |
748 | extern int nand_write_oob(struct nand_chip *nand, size_t ofs, | 748 | extern int nand_write_oob(struct nand_chip *nand, size_t ofs, |
749 | size_t len, size_t *retlen, const u_char *buf); | 749 | size_t len, size_t *retlen, const u_char *buf); |
750 | 750 | ||
751 | 751 | ||
752 | int do_nand (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) | 752 | int do_nand (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) |
753 | { | 753 | { |
754 | int rcode = 0; | 754 | int rcode = 0; |
755 | 755 | ||
756 | switch (argc) { | 756 | switch (argc) { |
757 | case 0: | 757 | case 0: |
758 | case 1: | 758 | case 1: |
759 | printf ("Usage:\n%s\n", cmdtp->usage); | 759 | printf ("Usage:\n%s\n", cmdtp->usage); |
760 | return 1; | 760 | return 1; |
761 | case 2: | 761 | case 2: |
762 | if (strcmp (argv[1], "info") == 0) { | 762 | if (strcmp (argv[1], "info") == 0) { |
763 | int i; | 763 | int i; |
764 | 764 | ||
765 | putc ('\n'); | 765 | putc ('\n'); |
766 | 766 | ||
767 | for (i = 0; i < CFG_MAX_NAND_DEVICE; ++i) { | 767 | for (i = 0; i < CFG_MAX_NAND_DEVICE; ++i) { |
768 | if (nand_dev_desc[i].ChipID == | 768 | if (nand_dev_desc[i].ChipID == |
769 | NAND_ChipID_UNKNOWN) | 769 | NAND_ChipID_UNKNOWN) |
770 | continue; /* list only known devices */ | 770 | continue; /* list only known devices */ |
771 | printf ("Device %d: ", i); | 771 | printf ("Device %d: ", i); |
772 | nand_print (&nand_dev_desc[i]); | 772 | nand_print (&nand_dev_desc[i]); |
773 | } | 773 | } |
774 | return 0; | 774 | return 0; |
775 | 775 | ||
776 | } else if (strcmp (argv[1], "device") == 0) { | 776 | } else if (strcmp (argv[1], "device") == 0) { |
777 | if ((curr_device < 0) | 777 | if ((curr_device < 0) |
778 | || (curr_device >= CFG_MAX_NAND_DEVICE)) { | 778 | || (curr_device >= CFG_MAX_NAND_DEVICE)) { |
779 | puts ("\nno devices available\n"); | 779 | puts ("\nno devices available\n"); |
780 | return 1; | 780 | return 1; |
781 | } | 781 | } |
782 | printf ("\nDevice %d: ", curr_device); | 782 | printf ("\nDevice %d: ", curr_device); |
783 | nand_print (&nand_dev_desc[curr_device]); | 783 | nand_print (&nand_dev_desc[curr_device]); |
784 | return 0; | 784 | return 0; |
785 | 785 | ||
786 | } else if (strcmp (argv[1], "bad") == 0) { | 786 | } else if (strcmp (argv[1], "bad") == 0) { |
787 | if ((curr_device < 0) | 787 | if ((curr_device < 0) |
788 | || (curr_device >= CFG_MAX_NAND_DEVICE)) { | 788 | || (curr_device >= CFG_MAX_NAND_DEVICE)) { |
789 | puts ("\nno devices available\n"); | 789 | puts ("\nno devices available\n"); |
790 | return 1; | 790 | return 1; |
791 | } | 791 | } |
792 | printf ("\nDevice %d bad blocks:\n", curr_device); | 792 | printf ("\nDevice %d bad blocks:\n", curr_device); |
793 | nand_print_bad (&nand_dev_desc[curr_device]); | 793 | nand_print_bad (&nand_dev_desc[curr_device]); |
794 | return 0; | 794 | return 0; |
795 | 795 | ||
796 | } | 796 | } |
797 | printf ("Usage:\n%s\n", cmdtp->usage); | 797 | printf ("Usage:\n%s\n", cmdtp->usage); |
798 | return 1; | 798 | return 1; |
799 | case 3: | 799 | case 3: |
800 | if (strcmp (argv[1], "device") == 0) { | 800 | if (strcmp (argv[1], "device") == 0) { |
801 | int dev = (int) simple_strtoul (argv[2], NULL, 10); | 801 | int dev = (int) simple_strtoul (argv[2], NULL, 10); |
802 | 802 | ||
803 | printf ("\nDevice %d: ", dev); | 803 | printf ("\nDevice %d: ", dev); |
804 | if (dev >= CFG_MAX_NAND_DEVICE) { | 804 | if (dev >= CFG_MAX_NAND_DEVICE) { |
805 | puts ("unknown device\n"); | 805 | puts ("unknown device\n"); |
806 | return 1; | 806 | return 1; |
807 | } | 807 | } |
808 | nand_print (&nand_dev_desc[dev]); | 808 | nand_print (&nand_dev_desc[dev]); |
809 | /*nand_print (dev); */ | 809 | /*nand_print (dev); */ |
810 | 810 | ||
811 | if (nand_dev_desc[dev].ChipID == NAND_ChipID_UNKNOWN) { | 811 | if (nand_dev_desc[dev].ChipID == NAND_ChipID_UNKNOWN) { |
812 | return 1; | 812 | return 1; |
813 | } | 813 | } |
814 | 814 | ||
815 | curr_device = dev; | 815 | curr_device = dev; |
816 | 816 | ||
817 | puts ("... is now current device\n"); | 817 | puts ("... is now current device\n"); |
818 | 818 | ||
819 | return 0; | 819 | return 0; |
820 | } else if (strcmp (argv[1], "erase") == 0 | 820 | } else if (strcmp (argv[1], "erase") == 0 |
821 | && strcmp (argv[2], "clean") == 0) { | 821 | && strcmp (argv[2], "clean") == 0) { |
822 | struct nand_chip *nand = &nand_dev_desc[curr_device]; | 822 | struct nand_chip *nand = &nand_dev_desc[curr_device]; |
823 | ulong off = 0; | 823 | ulong off = 0; |
824 | ulong size = nand->totlen; | 824 | ulong size = nand->totlen; |
825 | int ret; | 825 | int ret; |
826 | 826 | ||
827 | printf ("\nNAND erase: device %d offset %ld, size %ld ... ", curr_device, off, size); | 827 | printf ("\nNAND erase: device %d offset %ld, size %ld ... ", curr_device, off, size); |
828 | 828 | ||
829 | ret = nand_legacy_erase (nand, off, size, 1); | 829 | ret = nand_legacy_erase (nand, off, size, 1); |
830 | 830 | ||
831 | printf ("%s\n", ret ? "ERROR" : "OK"); | 831 | printf ("%s\n", ret ? "ERROR" : "OK"); |
832 | 832 | ||
833 | return ret; | 833 | return ret; |
834 | } | 834 | } |
835 | 835 | ||
836 | printf ("Usage:\n%s\n", cmdtp->usage); | 836 | printf ("Usage:\n%s\n", cmdtp->usage); |
837 | return 1; | 837 | return 1; |
838 | default: | 838 | default: |
839 | /* at least 4 args */ | 839 | /* at least 4 args */ |
840 | 840 | ||
841 | if (strncmp (argv[1], "read", 4) == 0 || | 841 | if (strncmp (argv[1], "read", 4) == 0 || |
842 | strncmp (argv[1], "write", 5) == 0) { | 842 | strncmp (argv[1], "write", 5) == 0) { |
843 | ulong addr = simple_strtoul (argv[2], NULL, 16); | 843 | ulong addr = simple_strtoul (argv[2], NULL, 16); |
844 | off_t off = simple_strtoul (argv[3], NULL, 16); | 844 | off_t off = simple_strtoul (argv[3], NULL, 16); |
845 | size_t size = simple_strtoul (argv[4], NULL, 16); | 845 | size_t size = simple_strtoul (argv[4], NULL, 16); |
846 | int cmd = (strncmp (argv[1], "read", 4) == 0) ? | 846 | int cmd = (strncmp (argv[1], "read", 4) == 0) ? |
847 | NANDRW_READ : NANDRW_WRITE; | 847 | NANDRW_READ : NANDRW_WRITE; |
848 | size_t total; | 848 | size_t total; |
849 | int ret; | 849 | int ret; |
850 | char *cmdtail = strchr (argv[1], '.'); | 850 | char *cmdtail = strchr (argv[1], '.'); |
851 | 851 | ||
852 | if (cmdtail && !strncmp (cmdtail, ".oob", 2)) { | 852 | if (cmdtail && !strncmp (cmdtail, ".oob", 2)) { |
853 | /* read out-of-band data */ | 853 | /* read out-of-band data */ |
854 | if (cmd & NANDRW_READ) { | 854 | if (cmd & NANDRW_READ) { |
855 | ret = nand_read_oob (nand_dev_desc + curr_device, | 855 | ret = nand_read_oob (nand_dev_desc + curr_device, |
856 | off, size, &total, | 856 | off, size, &total, |
857 | (u_char *) addr); | 857 | (u_char *) addr); |
858 | } else { | 858 | } else { |
859 | ret = nand_write_oob (nand_dev_desc + curr_device, | 859 | ret = nand_write_oob (nand_dev_desc + curr_device, |
860 | off, size, &total, | 860 | off, size, &total, |
861 | (u_char *) addr); | 861 | (u_char *) addr); |
862 | } | 862 | } |
863 | return ret; | 863 | return ret; |
864 | } else if (cmdtail && !strncmp (cmdtail, ".jffs2", 2)) | 864 | } else if (cmdtail && !strncmp (cmdtail, ".jffs2", 2)) |
865 | cmd |= NANDRW_JFFS2; /* skip bad blocks */ | 865 | cmd |= NANDRW_JFFS2; /* skip bad blocks */ |
866 | else if (cmdtail && !strncmp (cmdtail, ".jffs2s", 2)) { | 866 | else if (cmdtail && !strncmp (cmdtail, ".jffs2s", 2)) { |
867 | cmd |= NANDRW_JFFS2; /* skip bad blocks (on read too) */ | 867 | cmd |= NANDRW_JFFS2; /* skip bad blocks (on read too) */ |
868 | if (cmd & NANDRW_READ) | 868 | if (cmd & NANDRW_READ) |
869 | cmd |= NANDRW_JFFS2_SKIP; /* skip bad blocks (on read too) */ | 869 | cmd |= NANDRW_JFFS2_SKIP; /* skip bad blocks (on read too) */ |
870 | } | 870 | } |
871 | #ifdef SXNI855T | 871 | #ifdef SXNI855T |
872 | /* need ".e" same as ".j" for compatibility with older units */ | 872 | /* need ".e" same as ".j" for compatibility with older units */ |
873 | else if (cmdtail && !strcmp (cmdtail, ".e")) | 873 | else if (cmdtail && !strcmp (cmdtail, ".e")) |
874 | cmd |= NANDRW_JFFS2; /* skip bad blocks */ | 874 | cmd |= NANDRW_JFFS2; /* skip bad blocks */ |
875 | #endif | 875 | #endif |
876 | #ifdef CFG_NAND_SKIP_BAD_DOT_I | 876 | #ifdef CFG_NAND_SKIP_BAD_DOT_I |
877 | /* need ".i" same as ".jffs2s" for compatibility with older units (esd) */ | 877 | /* need ".i" same as ".jffs2s" for compatibility with older units (esd) */ |
878 | /* ".i" for image -> read skips bad block (no 0xff) */ | 878 | /* ".i" for image -> read skips bad block (no 0xff) */ |
879 | else if (cmdtail && !strcmp (cmdtail, ".i")) { | 879 | else if (cmdtail && !strcmp (cmdtail, ".i")) { |
880 | cmd |= NANDRW_JFFS2; /* skip bad blocks (on read too) */ | 880 | cmd |= NANDRW_JFFS2; /* skip bad blocks (on read too) */ |
881 | if (cmd & NANDRW_READ) | 881 | if (cmd & NANDRW_READ) |
882 | cmd |= NANDRW_JFFS2_SKIP; /* skip bad blocks (on read too) */ | 882 | cmd |= NANDRW_JFFS2_SKIP; /* skip bad blocks (on read too) */ |
883 | } | 883 | } |
884 | #endif /* CFG_NAND_SKIP_BAD_DOT_I */ | 884 | #endif /* CFG_NAND_SKIP_BAD_DOT_I */ |
885 | else if (cmdtail) { | 885 | else if (cmdtail) { |
886 | printf ("Usage:\n%s\n", cmdtp->usage); | 886 | printf ("Usage:\n%s\n", cmdtp->usage); |
887 | return 1; | 887 | return 1; |
888 | } | 888 | } |
889 | 889 | ||
890 | printf ("\nNAND %s: device %d offset %ld, size %ld ...\n", | 890 | printf ("\nNAND %s: device %d offset %ld, size %ld ...\n", |
891 | (cmd & NANDRW_READ) ? "read" : "write", | 891 | (cmd & NANDRW_READ) ? "read" : "write", |
892 | curr_device, off, size); | 892 | curr_device, off, size); |
893 | 893 | ||
894 | ret = nand_legacy_rw (nand_dev_desc + curr_device, | 894 | ret = nand_legacy_rw (nand_dev_desc + curr_device, |
895 | cmd, off, size, | 895 | cmd, off, size, |
896 | &total, | 896 | &total, |
897 | (u_char *) addr); | 897 | (u_char *) addr); |
898 | 898 | ||
899 | printf (" %d bytes %s: %s\n", total, | 899 | printf (" %d bytes %s: %s\n", total, |
900 | (cmd & NANDRW_READ) ? "read" : "written", | 900 | (cmd & NANDRW_READ) ? "read" : "written", |
901 | ret ? "ERROR" : "OK"); | 901 | ret ? "ERROR" : "OK"); |
902 | 902 | ||
903 | return ret; | 903 | return ret; |
904 | } else if (strcmp (argv[1], "erase") == 0 && | 904 | } else if (strcmp (argv[1], "erase") == 0 && |
905 | (argc == 4 || strcmp ("clean", argv[2]) == 0)) { | 905 | (argc == 4 || strcmp ("clean", argv[2]) == 0)) { |
906 | int clean = argc == 5; | 906 | int clean = argc == 5; |
907 | ulong off = | 907 | ulong off = |
908 | simple_strtoul (argv[2 + clean], NULL, 16); | 908 | simple_strtoul (argv[2 + clean], NULL, 16); |
909 | ulong size = | 909 | ulong size = |
910 | simple_strtoul (argv[3 + clean], NULL, 16); | 910 | simple_strtoul (argv[3 + clean], NULL, 16); |
911 | int ret; | 911 | int ret; |
912 | 912 | ||
913 | printf ("\nNAND erase: device %d offset %ld, size %ld ...\n", | 913 | printf ("\nNAND erase: device %d offset %ld, size %ld ...\n", |
914 | curr_device, off, size); | 914 | curr_device, off, size); |
915 | 915 | ||
916 | ret = nand_legacy_erase (nand_dev_desc + curr_device, | 916 | ret = nand_legacy_erase (nand_dev_desc + curr_device, |
917 | off, size, clean); | 917 | off, size, clean); |
918 | 918 | ||
919 | printf ("%s\n", ret ? "ERROR" : "OK"); | 919 | printf ("%s\n", ret ? "ERROR" : "OK"); |
920 | 920 | ||
921 | return ret; | 921 | return ret; |
922 | } else { | 922 | } else { |
923 | printf ("Usage:\n%s\n", cmdtp->usage); | 923 | printf ("Usage:\n%s\n", cmdtp->usage); |
924 | rcode = 1; | 924 | rcode = 1; |
925 | } | 925 | } |
926 | 926 | ||
927 | return rcode; | 927 | return rcode; |
928 | } | 928 | } |
929 | } | 929 | } |
930 | 930 | ||
931 | U_BOOT_CMD( | 931 | U_BOOT_CMD( |
932 | nand, 5, 1, do_nand, | 932 | nand, 5, 1, do_nand, |
933 | "nand - legacy NAND sub-system\n", | 933 | "nand - legacy NAND sub-system\n", |
934 | "info - show available NAND devices\n" | 934 | "info - show available NAND devices\n" |
935 | "nand device [dev] - show or set current device\n" | 935 | "nand device [dev] - show or set current device\n" |
936 | "nand read[.jffs2[s]] addr off size\n" | 936 | "nand read[.jffs2[s]] addr off size\n" |
937 | "nand write[.jffs2] addr off size - read/write `size' bytes starting\n" | 937 | "nand write[.jffs2] addr off size - read/write `size' bytes starting\n" |
938 | " at offset `off' to/from memory address `addr'\n" | 938 | " at offset `off' to/from memory address `addr'\n" |
939 | "nand erase [clean] [off size] - erase `size' bytes from\n" | 939 | "nand erase [clean] [off size] - erase `size' bytes from\n" |
940 | " offset `off' (entire device if not specified)\n" | 940 | " offset `off' (entire device if not specified)\n" |
941 | "nand bad - show bad blocks\n" | 941 | "nand bad - show bad blocks\n" |
942 | "nand read.oob addr off size - read out-of-band data\n" | 942 | "nand read.oob addr off size - read out-of-band data\n" |
943 | "nand write.oob addr off size - read out-of-band data\n" | 943 | "nand write.oob addr off size - read out-of-band data\n" |
944 | ); | 944 | ); |
945 | 945 | ||
946 | int do_nandboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) | 946 | int do_nandboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) |
947 | { | 947 | { |
948 | char *boot_device = NULL; | 948 | char *boot_device = NULL; |
949 | char *ep; | 949 | char *ep; |
950 | int dev; | 950 | int dev; |
951 | ulong cnt; | 951 | ulong cnt; |
952 | ulong addr; | 952 | ulong addr; |
953 | ulong offset = 0; | 953 | ulong offset = 0; |
954 | image_header_t *hdr; | 954 | image_header_t *hdr; |
955 | int rcode = 0; | 955 | int rcode = 0; |
956 | #if defined(CONFIG_FIT) | 956 | #if defined(CONFIG_FIT) |
957 | const void *fit_hdr; | 957 | const void *fit_hdr; |
958 | #endif | 958 | #endif |
959 | 959 | ||
960 | show_boot_progress (52); | 960 | show_boot_progress (52); |
961 | switch (argc) { | 961 | switch (argc) { |
962 | case 1: | 962 | case 1: |
963 | addr = CFG_LOAD_ADDR; | 963 | addr = CFG_LOAD_ADDR; |
964 | boot_device = getenv ("bootdevice"); | 964 | boot_device = getenv ("bootdevice"); |
965 | break; | 965 | break; |
966 | case 2: | 966 | case 2: |
967 | addr = simple_strtoul(argv[1], NULL, 16); | 967 | addr = simple_strtoul(argv[1], NULL, 16); |
968 | boot_device = getenv ("bootdevice"); | 968 | boot_device = getenv ("bootdevice"); |
969 | break; | 969 | break; |
970 | case 3: | 970 | case 3: |
971 | addr = simple_strtoul(argv[1], NULL, 16); | 971 | addr = simple_strtoul(argv[1], NULL, 16); |
972 | boot_device = argv[2]; | 972 | boot_device = argv[2]; |
973 | break; | 973 | break; |
974 | case 4: | 974 | case 4: |
975 | addr = simple_strtoul(argv[1], NULL, 16); | 975 | addr = simple_strtoul(argv[1], NULL, 16); |
976 | boot_device = argv[2]; | 976 | boot_device = argv[2]; |
977 | offset = simple_strtoul(argv[3], NULL, 16); | 977 | offset = simple_strtoul(argv[3], NULL, 16); |
978 | break; | 978 | break; |
979 | default: | 979 | default: |
980 | printf ("Usage:\n%s\n", cmdtp->usage); | 980 | printf ("Usage:\n%s\n", cmdtp->usage); |
981 | show_boot_progress (-53); | 981 | show_boot_progress (-53); |
982 | return 1; | 982 | return 1; |
983 | } | 983 | } |
984 | 984 | ||
985 | show_boot_progress (53); | 985 | show_boot_progress (53); |
986 | if (!boot_device) { | 986 | if (!boot_device) { |
987 | puts ("\n** No boot device **\n"); | 987 | puts ("\n** No boot device **\n"); |
988 | show_boot_progress (-54); | 988 | show_boot_progress (-54); |
989 | return 1; | 989 | return 1; |
990 | } | 990 | } |
991 | show_boot_progress (54); | 991 | show_boot_progress (54); |
992 | 992 | ||
993 | dev = simple_strtoul(boot_device, &ep, 16); | 993 | dev = simple_strtoul(boot_device, &ep, 16); |
994 | 994 | ||
995 | if ((dev >= CFG_MAX_NAND_DEVICE) || | 995 | if ((dev >= CFG_MAX_NAND_DEVICE) || |
996 | (nand_dev_desc[dev].ChipID == NAND_ChipID_UNKNOWN)) { | 996 | (nand_dev_desc[dev].ChipID == NAND_ChipID_UNKNOWN)) { |
997 | printf ("\n** Device %d not available\n", dev); | 997 | printf ("\n** Device %d not available\n", dev); |
998 | show_boot_progress (-55); | 998 | show_boot_progress (-55); |
999 | return 1; | 999 | return 1; |
1000 | } | 1000 | } |
1001 | show_boot_progress (55); | 1001 | show_boot_progress (55); |
1002 | 1002 | ||
1003 | printf ("\nLoading from device %d: %s at 0x%lx (offset 0x%lx)\n", | 1003 | printf ("\nLoading from device %d: %s at 0x%lx (offset 0x%lx)\n", |
1004 | dev, nand_dev_desc[dev].name, nand_dev_desc[dev].IO_ADDR, | 1004 | dev, nand_dev_desc[dev].name, nand_dev_desc[dev].IO_ADDR, |
1005 | offset); | 1005 | offset); |
1006 | 1006 | ||
1007 | if (nand_legacy_rw (nand_dev_desc + dev, NANDRW_READ, offset, | 1007 | if (nand_legacy_rw (nand_dev_desc + dev, NANDRW_READ, offset, |
1008 | SECTORSIZE, NULL, (u_char *)addr)) { | 1008 | SECTORSIZE, NULL, (u_char *)addr)) { |
1009 | printf ("** Read error on %d\n", dev); | 1009 | printf ("** Read error on %d\n", dev); |
1010 | show_boot_progress (-56); | 1010 | show_boot_progress (-56); |
1011 | return 1; | 1011 | return 1; |
1012 | } | 1012 | } |
1013 | show_boot_progress (56); | 1013 | show_boot_progress (56); |
1014 | 1014 | ||
1015 | switch (genimg_get_format ((void *)addr)) { | 1015 | switch (genimg_get_format ((void *)addr)) { |
1016 | case IMAGE_FORMAT_LEGACY: | 1016 | case IMAGE_FORMAT_LEGACY: |
1017 | hdr = (image_header_t *)addr; | 1017 | hdr = (image_header_t *)addr; |
1018 | image_print_contents (hdr); | 1018 | image_print_contents (hdr); |
1019 | 1019 | ||
1020 | cnt = image_get_image_size (hdr); | 1020 | cnt = image_get_image_size (hdr); |
1021 | cnt -= SECTORSIZE; | 1021 | cnt -= SECTORSIZE; |
1022 | break; | 1022 | break; |
1023 | #if defined(CONFIG_FIT) | 1023 | #if defined(CONFIG_FIT) |
1024 | case IMAGE_FORMAT_FIT: | 1024 | case IMAGE_FORMAT_FIT: |
1025 | fit_hdr = (const void *)addr; | 1025 | fit_hdr = (const void *)addr; |
1026 | if (!fit_check_format (fit_hdr)) { | 1026 | if (!fit_check_format (fit_hdr)) { |
1027 | show_boot_progress (-150); | 1027 | show_boot_progress (-150); |
1028 | puts ("** Bad FIT image format\n"); | 1028 | puts ("** Bad FIT image format\n"); |
1029 | return 1; | 1029 | return 1; |
1030 | } | 1030 | } |
1031 | show_boot_progress (151); | 1031 | show_boot_progress (151); |
1032 | puts ("Fit image detected...\n"); | 1032 | puts ("Fit image detected...\n"); |
1033 | 1033 | ||
1034 | cnt = fit_get_size (fit_hdr); | 1034 | cnt = fit_get_size (fit_hdr); |
1035 | break; | 1035 | break; |
1036 | #endif | 1036 | #endif |
1037 | default: | 1037 | default: |
1038 | show_boot_progress (-57); | 1038 | show_boot_progress (-57); |
1039 | puts ("** Unknown image type\n"); | 1039 | puts ("** Unknown image type\n"); |
1040 | return 1; | 1040 | return 1; |
1041 | } | 1041 | } |
1042 | show_boot_progress (57); | 1042 | show_boot_progress (57); |
1043 | 1043 | ||
1044 | if (nand_legacy_rw (nand_dev_desc + dev, NANDRW_READ, | 1044 | if (nand_legacy_rw (nand_dev_desc + dev, NANDRW_READ, |
1045 | offset + SECTORSIZE, cnt, NULL, | 1045 | offset + SECTORSIZE, cnt, NULL, |
1046 | (u_char *)(addr+SECTORSIZE))) { | 1046 | (u_char *)(addr+SECTORSIZE))) { |
1047 | printf ("** Read error on %d\n", dev); | 1047 | printf ("** Read error on %d\n", dev); |
1048 | show_boot_progress (-58); | 1048 | show_boot_progress (-58); |
1049 | return 1; | 1049 | return 1; |
1050 | } | 1050 | } |
1051 | show_boot_progress (58); | 1051 | show_boot_progress (58); |
1052 | 1052 | ||
1053 | #if defined(CONFIG_FIT) | 1053 | #if defined(CONFIG_FIT) |
1054 | /* This cannot be done earlier, we need complete FIT image in RAM first */ | 1054 | /* This cannot be done earlier, we need complete FIT image in RAM first */ |
1055 | if (genimg_get_format ((void *)addr) == IMAGE_FORMAT_FIT) | 1055 | if (genimg_get_format ((void *)addr) == IMAGE_FORMAT_FIT) |
1056 | fit_print_contents ((const void *)addr); | 1056 | fit_print_contents ((const void *)addr); |
1057 | #endif | 1057 | #endif |
1058 | 1058 | ||
1059 | /* Loading ok, update default load address */ | 1059 | /* Loading ok, update default load address */ |
1060 | 1060 | ||
1061 | load_addr = addr; | 1061 | load_addr = addr; |
1062 | 1062 | ||
1063 | /* Check if we should attempt an auto-start */ | 1063 | /* Check if we should attempt an auto-start */ |
1064 | if (((ep = getenv("autostart")) != NULL) && (strcmp(ep,"yes") == 0)) { | 1064 | if (((ep = getenv("autostart")) != NULL) && (strcmp(ep,"yes") == 0)) { |
1065 | char *local_args[2]; | 1065 | char *local_args[2]; |
1066 | extern int do_bootm (cmd_tbl_t *, int, int, char *[]); | 1066 | extern int do_bootm (cmd_tbl_t *, int, int, char *[]); |
1067 | 1067 | ||
1068 | local_args[0] = argv[0]; | 1068 | local_args[0] = argv[0]; |
1069 | local_args[1] = NULL; | 1069 | local_args[1] = NULL; |
1070 | 1070 | ||
1071 | printf ("Automatic boot of image at addr 0x%08lx ...\n", addr); | 1071 | printf ("Automatic boot of image at addr 0x%08lx ...\n", addr); |
1072 | 1072 | ||
1073 | do_bootm (cmdtp, 0, 1, local_args); | 1073 | do_bootm (cmdtp, 0, 1, local_args); |
1074 | rcode = 1; | 1074 | rcode = 1; |
1075 | } | 1075 | } |
1076 | return rcode; | 1076 | return rcode; |
1077 | } | 1077 | } |
1078 | 1078 | ||
1079 | U_BOOT_CMD( | 1079 | U_BOOT_CMD( |
1080 | nboot, 4, 1, do_nandboot, | 1080 | nboot, 4, 1, do_nandboot, |
1081 | "nboot - boot from NAND device\n", | 1081 | "nboot - boot from NAND device\n", |
1082 | "loadAddr dev\n" | 1082 | "loadAddr dev\n" |
1083 | ); | 1083 | ); |
1084 | 1084 | ||
1085 | #endif | 1085 | #endif |
1086 | 1086 | ||
1087 | #endif /* CFG_NAND_LEGACY */ | 1087 | #endif /* CFG_NAND_LEGACY */ |
1088 | 1088 |