blob: efc89dc71e019ec91e076068bef97424cb46b752 [file] [log] [blame]
wdenk38a24a62002-09-18 12:49:44 +00001/*
2 * (C) Copyright 2000
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
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
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
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
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24/*
25 * FLASH support
26 */
27#include <common.h>
28#include <command.h>
29#include <cmd_boot.h>
30#include <flash.h>
31
wdenk381669a2003-06-16 23:50:08 +000032#ifdef CONFIG_HAS_DATAFLASH
33#include <dataflash.h>
34#endif
35
wdenk38a24a62002-09-18 12:49:44 +000036#if (CONFIG_COMMANDS & CFG_CMD_FLASH)
37
38extern flash_info_t flash_info[]; /* info for FLASH chips */
39
40/*
41 * The user interface starts numbering for Flash banks with 1
42 * for historical reasons.
43 */
44
45/*
46 * this routine looks for an abbreviated flash range specification.
47 * the syntax is B:SF[-SL], where B is the bank number, SF is the first
48 * sector to erase, and SL is the last sector to erase (defaults to SF).
49 * bank numbers start at 1 to be consistent with other specs, sector numbers
50 * start at zero.
51 *
52 * returns: 1 - correct spec; *pinfo, *psf and *psl are
53 * set appropriately
54 * 0 - doesn't look like an abbreviated spec
55 * -1 - looks like an abbreviated spec, but got
56 * a parsing error, a number out of range,
57 * or an invalid flash bank.
58 */
59static int
60abbrev_spec(char *str, flash_info_t **pinfo, int *psf, int *psl)
61{
62 flash_info_t *fp;
63 int bank, first, last;
64 char *p, *ep;
65
66 if ((p = strchr(str, ':')) == NULL)
67 return 0;
68 *p++ = '\0';
69
70 bank = simple_strtoul(str, &ep, 10);
71 if (ep == str || *ep != '\0' ||
72 bank < 1 || bank > CFG_MAX_FLASH_BANKS ||
73 (fp = &flash_info[bank - 1])->flash_id == FLASH_UNKNOWN)
74 return -1;
75
76 str = p;
77 if ((p = strchr(str, '-')) != NULL)
78 *p++ = '\0';
79
80 first = simple_strtoul(str, &ep, 10);
81 if (ep == str || *ep != '\0' || first >= fp->sector_count)
82 return -1;
83
84 if (p != NULL) {
85 last = simple_strtoul(p, &ep, 10);
86 if (ep == p || *ep != '\0' ||
87 last < first || last >= fp->sector_count)
88 return -1;
89 }
90 else
91 last = first;
92
93 *pinfo = fp;
94 *psf = first;
95 *psl = last;
96
97 return 1;
98}
99int do_flinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
100{
101 ulong bank;
102
wdenk381669a2003-06-16 23:50:08 +0000103#ifdef CONFIG_HAS_DATAFLASH
104 dataflash_print_info();
105#endif
106
wdenk38a24a62002-09-18 12:49:44 +0000107 if (argc == 1) { /* print info for all FLASH banks */
108 for (bank=0; bank <CFG_MAX_FLASH_BANKS; ++bank) {
109 printf ("\nBank # %ld: ", bank+1);
110
111 flash_print_info (&flash_info[bank]);
112 }
113 return 0;
114 }
115
116 bank = simple_strtoul(argv[1], NULL, 16);
117 if ((bank < 1) || (bank > CFG_MAX_FLASH_BANKS)) {
118 printf ("Only FLASH Banks # 1 ... # %d supported\n",
119 CFG_MAX_FLASH_BANKS);
120 return 1;
121 }
122 printf ("\nBank # %ld: ", bank);
123 flash_print_info (&flash_info[bank-1]);
124 return 0;
125}
126int do_flerase (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
127{
128 flash_info_t *info;
129 ulong bank, addr_first, addr_last;
130 int n, sect_first, sect_last;
131 int rcode = 0;
132
133 if (argc < 2) {
134 printf ("Usage:\n%s\n", cmdtp->usage);
135 return 1;
136 }
137
138 if (strcmp(argv[1], "all") == 0) {
139 for (bank=1; bank<=CFG_MAX_FLASH_BANKS; ++bank) {
140 printf ("Erase Flash Bank # %ld ", bank);
141 info = &flash_info[bank-1];
142 rcode = flash_erase (info, 0, info->sector_count-1);
143 }
144 return rcode;
145 }
146
147 if ((n = abbrev_spec(argv[1], &info, &sect_first, &sect_last)) != 0) {
148 if (n < 0) {
149 printf("Bad sector specification\n");
150 return 1;
151 }
152 printf ("Erase Flash Sectors %d-%d in Bank # %d ",
153 sect_first, sect_last, (info-flash_info)+1);
154 rcode = flash_erase(info, sect_first, sect_last);
155 return rcode;
156 }
157
158 if (argc != 3) {
159 printf ("Usage:\n%s\n", cmdtp->usage);
160 return 1;
161 }
162
163 if (strcmp(argv[1], "bank") == 0) {
164 bank = simple_strtoul(argv[2], NULL, 16);
165 if ((bank < 1) || (bank > CFG_MAX_FLASH_BANKS)) {
166 printf ("Only FLASH Banks # 1 ... # %d supported\n",
167 CFG_MAX_FLASH_BANKS);
168 return 1;
169 }
170 printf ("Erase Flash Bank # %ld ", bank);
171 info = &flash_info[bank-1];
172 rcode = flash_erase (info, 0, info->sector_count-1);
173 return rcode;
174 }
175
176 addr_first = simple_strtoul(argv[1], NULL, 16);
177 addr_last = simple_strtoul(argv[2], NULL, 16);
178
179 if (addr_first >= addr_last) {
180 printf ("Usage:\n%s\n", cmdtp->usage);
181 return 1;
182 }
183
184 printf ("Erase Flash from 0x%08lx to 0x%08lx ", addr_first, addr_last);
185 rcode = flash_sect_erase(addr_first, addr_last);
186 return rcode;
187}
188
189int flash_sect_erase (ulong addr_first, ulong addr_last)
190{
191 flash_info_t *info;
192 ulong bank;
193 int s_first, s_last;
194 int erased;
195 int rcode = 0;
196
197 erased = 0;
198
199 for (bank=0,info=&flash_info[0]; bank < CFG_MAX_FLASH_BANKS; ++bank, ++info) {
200 ulong b_end;
201 int sect;
202
203 if (info->flash_id == FLASH_UNKNOWN) {
204 continue;
205 }
206
207 b_end = info->start[0] + info->size - 1; /* bank end addr */
208
209 s_first = -1; /* first sector to erase */
210 s_last = -1; /* last sector to erase */
211
212 for (sect=0; sect < info->sector_count; ++sect) {
213 ulong end; /* last address in current sect */
214 short s_end;
215
216 s_end = info->sector_count - 1;
217
218 end = (sect == s_end) ? b_end : info->start[sect + 1] - 1;
219
220 if (addr_first > end)
221 continue;
222 if (addr_last < info->start[sect])
223 continue;
224
225 if (addr_first == info->start[sect]) {
226 s_first = sect;
227 }
228 if (addr_last == end) {
229 s_last = sect;
230 }
231 }
232 if (s_first>=0 && s_first<=s_last) {
233 erased += s_last - s_first + 1;
234 rcode = flash_erase (info, s_first, s_last);
235 }
236 }
237 if (erased) {
238 printf ("Erased %d sectors\n", erased);
239 } else {
240 printf ("Error: start and/or end address"
241 " not on sector boundary\n");
242 rcode = 1;
243 }
244 return rcode;
245}
246
247
248int do_protect (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
249{
250 flash_info_t *info;
251 ulong bank, addr_first, addr_last;
252 int i, p, n, sect_first, sect_last;
253 int rcode = 0;
254
255 if (argc < 3) {
256 printf ("Usage:\n%s\n", cmdtp->usage);
257 return 1;
258 }
259
260 if (strcmp(argv[1], "off") == 0)
261 p = 0;
262 else if (strcmp(argv[1], "on") == 0)
263 p = 1;
264 else {
265 printf ("Usage:\n%s\n", cmdtp->usage);
266 return 1;
267 }
268
269 if (strcmp(argv[2], "all") == 0) {
270 for (bank=1; bank<=CFG_MAX_FLASH_BANKS; ++bank) {
271 info = &flash_info[bank-1];
272 if (info->flash_id == FLASH_UNKNOWN) {
273 continue;
274 }
275 printf ("%sProtect Flash Bank # %ld\n",
276 p ? "" : "Un-", bank);
277
278 for (i=0; i<info->sector_count; ++i) {
279#if defined(CFG_FLASH_PROTECTION)
280 if (flash_real_protect(info, i, p))
281 rcode = 1;
282 putc ('.');
283#else
284 info->protect[i] = p;
285#endif /* CFG_FLASH_PROTECTION */
286 }
287 }
288
289#if defined(CFG_FLASH_PROTECTION)
290 if (!rcode) puts (" done\n");
291#endif /* CFG_FLASH_PROTECTION */
292
293 return rcode;
294 }
295
296 if ((n = abbrev_spec(argv[2], &info, &sect_first, &sect_last)) != 0) {
297 if (n < 0) {
298 printf("Bad sector specification\n");
299 return 1;
300 }
301 printf("%sProtect Flash Sectors %d-%d in Bank # %d\n",
302 p ? "" : "Un-", sect_first, sect_last,
303 (info-flash_info)+1);
304 for (i = sect_first; i <= sect_last; i++) {
305#if defined(CFG_FLASH_PROTECTION)
306 if (flash_real_protect(info, i, p))
307 rcode = 1;
308 putc ('.');
309#else
310 info->protect[i] = p;
311#endif /* CFG_FLASH_PROTECTION */
312 }
313
314#if defined(CFG_FLASH_PROTECTION)
315 if (!rcode) puts (" done\n");
316#endif /* CFG_FLASH_PROTECTION */
317
318 return rcode;
319 }
320
321 if (argc != 4) {
322 printf ("Usage:\n%s\n", cmdtp->usage);
323 return 1;
324 }
325
326 if (strcmp(argv[2], "bank") == 0) {
327 bank = simple_strtoul(argv[3], NULL, 16);
328 if ((bank < 1) || (bank > CFG_MAX_FLASH_BANKS)) {
329 printf ("Only FLASH Banks # 1 ... # %d supported\n",
330 CFG_MAX_FLASH_BANKS);
331 return 1;
332 }
333 printf ("%sProtect Flash Bank # %ld\n",
334 p ? "" : "Un-", bank);
335 info = &flash_info[bank-1];
336
337 if (info->flash_id == FLASH_UNKNOWN) {
338 printf ("missing or unknown FLASH type\n");
339 return 1;
340 }
341 for (i=0; i<info->sector_count; ++i) {
342#if defined(CFG_FLASH_PROTECTION)
343 if (flash_real_protect(info, i, p))
344 rcode = 1;
345 putc ('.');
346#else
347 info->protect[i] = p;
348#endif /* CFG_FLASH_PROTECTION */
349 }
350
351#if defined(CFG_FLASH_PROTECTION)
352 if (!rcode) puts (" done\n");
353#endif /* CFG_FLASH_PROTECTION */
354
355 return rcode;
356 }
357
358 addr_first = simple_strtoul(argv[2], NULL, 16);
359 addr_last = simple_strtoul(argv[3], NULL, 16);
360
361 if (addr_first >= addr_last) {
362 printf ("Usage:\n%s\n", cmdtp->usage);
363 return 1;
364 }
365 rcode = flash_sect_protect (p, addr_first, addr_last);
366 return rcode;
367}
368
369
370int flash_sect_protect (int p, ulong addr_first, ulong addr_last)
371{
372 flash_info_t *info;
373 ulong bank;
374 int s_first, s_last;
375 int protected, i;
376 int rcode = 0;
377
378 protected = 0;
379
380 for (bank=0,info=&flash_info[0]; bank < CFG_MAX_FLASH_BANKS; ++bank, ++info) {
381 ulong b_end;
382 int sect;
383
384 if (info->flash_id == FLASH_UNKNOWN) {
385 continue;
386 }
387
388 b_end = info->start[0] + info->size - 1; /* bank end addr */
389
390 s_first = -1; /* first sector to erase */
391 s_last = -1; /* last sector to erase */
392
393 for (sect=0; sect < info->sector_count; ++sect) {
394 ulong end; /* last address in current sect */
395 short s_end;
396
397 s_end = info->sector_count - 1;
398
399 end = (sect == s_end) ? b_end : info->start[sect + 1] - 1;
400
401 if (addr_first > end)
402 continue;
403 if (addr_last < info->start[sect])
404 continue;
405
406 if (addr_first == info->start[sect]) {
407 s_first = sect;
408 }
409 if (addr_last == end) {
410 s_last = sect;
411 }
412 }
413 if (s_first>=0 && s_first<=s_last) {
414 protected += s_last - s_first + 1;
415 for (i=s_first; i<=s_last; ++i) {
416#if defined(CFG_FLASH_PROTECTION)
417 if (flash_real_protect(info, i, p))
418 rcode = 1;
419 putc ('.');
420#else
421 info->protect[i] = p;
422#endif /* CFG_FLASH_PROTECTION */
423 }
424 }
425#if defined(CFG_FLASH_PROTECTION)
426 if (!rcode) putc ('\n');
427#endif /* CFG_FLASH_PROTECTION */
428
429 }
430 if (protected) {
431 printf ("%sProtected %d sectors\n",
432 p ? "" : "Un-", protected);
433 } else {
434 printf ("Error: start and/or end address"
435 " not on sector boundary\n");
436 rcode = 1;
437 }
438 return rcode;
439}
440
441#endif /* CFG_CMD_FLASH */