3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5 * See file CREDITS for list of people who contributed to this
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.
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.
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,
30 #if (CONFIG_COMMANDS & CFG_CMD_FLASH)
32 extern flash_info_t flash_info[]; /* info for FLASH chips */
35 * The user interface starts numbering for Flash banks with 1
36 * for historical reasons.
40 * this routine looks for an abbreviated flash range specification.
41 * the syntax is B:SF[-SL], where B is the bank number, SF is the first
42 * sector to erase, and SL is the last sector to erase (defaults to SF).
43 * bank numbers start at 1 to be consistent with other specs, sector numbers
46 * returns: 1 - correct spec; *pinfo, *psf and *psl are
48 * 0 - doesn't look like an abbreviated spec
49 * -1 - looks like an abbreviated spec, but got
50 * a parsing error, a number out of range,
51 * or an invalid flash bank.
53 static int abbrev_spec(char *str, flash_info_t ** pinfo, int *psf, int *psl){
55 int bank, first, last;
58 if((p = strchr(str, ':')) == NULL){
64 bank = simple_strtoul(str, &ep, 10);
66 if(ep == str || *ep != '\0' || bank < 1 || bank > CFG_MAX_FLASH_BANKS || (fp = &flash_info[bank - 1])->flash_id == FLASH_UNKNOWN){
72 if((p = strchr(str, '-')) != NULL){
76 first = simple_strtoul(str, &ep, 10);
78 if(ep == str || *ep != '\0' || first >= fp->sector_count){
83 last = simple_strtoul(p, &ep, 10);
85 if(ep == p || *ep != '\0' || last < first || last >= fp->sector_count){
100 * This function computes the start and end addresses for both
101 * erase and protect commands. The range of the addresses on which
102 * either of the commands is to operate can be given in two forms:
103 * 1. <cmd> start end - operate on <'start', 'end')
104 * 2. <cmd> start +length - operate on <'start', start + length)
105 * If the second form is used and the end address doesn't fall on the
106 * sector boundary, than it will be adjusted to the next sector boundary.
107 * If it isn't in the flash, the function will fail (return -1).
109 * arg1, arg2: address specification (i.e. both command arguments)
111 * addr_first, addr_last: computed address range
114 * -1: failure (bad format, bad address).
116 static int addr_spec(char *arg1, char *arg2, ulong *addr_first, ulong *addr_last){
117 char len_used = 0; /* indicates if the "start +length" form used */
120 *addr_first = simple_strtoul(arg1, &ep, 16);
122 if(ep == arg1 || *ep != '\0'){
126 if(arg2 && *arg2 == '+'){
131 *addr_last = simple_strtoul(arg2, &ep, 16);
133 if(ep == arg2 || *ep != '\0'){
142 * *addr_last has the length, compute correct *addr_last
143 * XXX watch out for the integer overflow! Right now it is
144 * checked for in both the callers.
146 *addr_last = *addr_first + *addr_last - 1;
149 * It may happen that *addr_last doesn't fall on the sector
150 * boundary. We want to round such an address to the next
151 * sector boundary, so that the commands don't fail later on.
154 /* find the end addr of the sector where the *addr_last is */
155 for(bank = 0; bank < CFG_MAX_FLASH_BANKS && !found; ++bank){
157 flash_info_t *info = &flash_info[bank];
159 for(i = 0; i < info->sector_count && !found; ++i){
160 /* get the end address of the sector */
161 ulong sector_end_addr;
163 if(i == info->sector_count - 1){
164 sector_end_addr = info->start[0] + info->size - 1;
166 sector_end_addr = info->start[i + 1] - 1;
169 if(*addr_last <= sector_end_addr && *addr_last >= info->start[i]){
173 /* adjust *addr_last if necessary */
174 if(*addr_last < sector_end_addr){
175 *addr_last = sector_end_addr;
182 /* error, addres not in flash */
183 printf("## Error: end address (0x%08lx) not in flash!\n", *addr_last);
187 } /* "start +length" from used */
192 static int flash_fill_sect_ranges(ulong addr_first, ulong addr_last, int *s_first, int *s_last, int *s_count){
199 for(bank = 0; bank < CFG_MAX_FLASH_BANKS; ++bank){
200 s_first[bank] = -1; /* first sector to erase */
201 s_last[bank] = -1; /* last sector to erase */
204 for(bank = 0, info = &flash_info[0]; (bank < CFG_MAX_FLASH_BANKS) && (addr_first <= addr_last); ++bank, ++info){
209 if(info->flash_id == FLASH_UNKNOWN){
213 b_end = info->start[0] + info->size - 1; /* bank end addr */
214 s_end = info->sector_count - 1; /* last sector */
216 for(sect = 0; sect < info->sector_count; ++sect){
217 ulong end; /* last address in current sect */
219 end = (sect == s_end) ? b_end : info->start[sect + 1] - 1;
221 if(addr_first > end){
225 if(addr_last < info->start[sect]){
229 if(addr_first == info->start[sect]){
230 s_first[bank] = sect;
233 if(addr_last == end){
238 if(s_first[bank] >= 0){
239 if(s_last[bank] < 0){
240 if(addr_last > b_end){
241 s_last[bank] = s_end;
243 puts("## Error: end address not on sector boundary\n");
249 if(s_last[bank] < s_first[bank]){
250 puts("## Error: end sector precedes start sector\n");
256 addr_first = (sect == s_end) ? b_end + 1 : info->start[sect + 1];
257 (*s_count) += s_last[bank] - s_first[bank] + 1;
258 } else if(addr_first >= info->start[0] && addr_first < b_end){
259 puts("## Error: start address not on sector boundary\n");
262 } else if(s_last[bank] >= 0){
263 puts("## Error: cannot span across banks when they are mapped in reverse order\n");
272 int do_flerase(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){
274 ulong bank, addr_first, addr_last;
275 int n, sect_first, sect_last;
280 if(cmdtp->help != NULL){
281 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->help);
283 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
286 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
291 // erase whole flash?
292 if(strcmp(argv[1], "all") == 0){
293 for(bank = 1; bank <= CFG_MAX_FLASH_BANKS; ++bank){
294 printf("Erase flash bank #%ld ", bank);
295 info = &flash_info[bank - 1];
296 rcode = flash_erase(info, 0, info->sector_count - 1);
301 if((n = abbrev_spec(argv[1], &info, §_first, §_last)) != 0){
303 puts("## Error: bad sector spec\n");
306 printf("Erase flash sectors %d-%d in bank #%d ", sect_first, sect_last, (info - flash_info) + 1);
307 rcode = flash_erase(info, sect_first, sect_last);
313 if(cmdtp->help != NULL){
314 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->help);
316 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
319 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
324 if(strcmp(argv[1], "bank") == 0){
325 bank = simple_strtoul(argv[2], NULL, 16);
327 if((bank < 1) || (bank > CFG_MAX_FLASH_BANKS)){
328 printf("## Error: only flash banks #1...#%d supported\n", CFG_MAX_FLASH_BANKS);
332 printf("Erase flash bank #%ld ", bank);
333 info = &flash_info[bank - 1];
334 rcode = flash_erase(info, 0, info->sector_count - 1);
338 if(addr_spec(argv[1], argv[2], &addr_first, &addr_last) < 0){
339 printf("## Error: bad address format\n");
343 if(addr_first >= addr_last){
345 if(cmdtp->help != NULL){
346 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->help);
348 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
351 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
356 rcode = flash_sect_erase(addr_first, addr_last);
360 int flash_sect_erase(ulong addr_first, ulong addr_last){
363 int s_first[CFG_MAX_FLASH_BANKS], s_last[CFG_MAX_FLASH_BANKS];
368 rcode = flash_fill_sect_ranges(addr_first, addr_last, s_first, s_last, &planned);
370 if(planned && (rcode == 0)){
371 for(bank = 0, info = &flash_info[0]; (bank < CFG_MAX_FLASH_BANKS) && (rcode == 0); ++bank, ++info){
372 if(s_first[bank] >= 0){
373 erased += s_last[bank] - s_first[bank] + 1;
374 printf("Erase flash from 0x%08lX to 0x%08lX in bank #%ld\n", info->start[s_first[bank]], (s_last[bank] == info->sector_count - 1) ? info->start[0] + info->size - 1 : info->start[s_last[bank] + 1] - 1, bank + 1);
375 rcode = flash_erase(info, s_first[bank], s_last[bank]);
378 printf("Erased sectors: %d\n\n", erased);
379 } else if(rcode == 0){
380 puts("## Error: start and/or end address not on sector boundary\n");
386 #ifndef COMPRESSED_UBOOT
387 #if 0 // we don't need do_protect cmd
388 int do_protect(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){
390 ulong bank, addr_first, addr_last;
391 int i, p, n, sect_first, sect_last;
396 if(cmdtp->help != NULL){
397 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->help);
399 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
402 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
407 if(strcmp(argv[1], "off") == 0){
409 } else if(strcmp(argv[1], "on") == 0){
413 if(cmdtp->help != NULL){
414 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->help);
416 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
419 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
424 if(strcmp(argv[2], "all") == 0){
425 for(bank=1; bank <= CFG_MAX_FLASH_BANKS; ++bank){
426 info = &flash_info[bank-1];
428 if(info->flash_id == FLASH_UNKNOWN){
432 printf("%sProtecting flash bank #%ld\n", p ? "" : "Un-", bank);
434 for(i = 0; i < info->sector_count; ++i){
435 info->protect[i] = p;
442 if((n = abbrev_spec(argv[2], &info, §_first, §_last)) != 0){
444 puts("## Error: bad sector spec\n");
448 printf("%sProtecting flash sectors: %d-%d in bank #%d\n", p ? "" : "Un-", sect_first, sect_last, (info-flash_info)+1);
450 for(i = sect_first; i <= sect_last; i++){
451 info->protect[i] = p;
459 if(cmdtp->help != NULL){
460 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->help);
462 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
465 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
470 if(strcmp(argv[2], "bank") == 0){
471 bank = simple_strtoul(argv[3], NULL, 16);
473 if((bank < 1) || (bank > CFG_MAX_FLASH_BANKS)){
474 printf("## Error: only flash banks #1...#%d supported\n", CFG_MAX_FLASH_BANKS);
478 printf("%sProtecting flash bank #%ld\n", p ? "" : "Un-", bank);
479 info = &flash_info[bank-1];
481 if(info->flash_id == FLASH_UNKNOWN){
482 puts("## Error: missing or unknown flash type\n");
486 for(i=0; i<info->sector_count; ++i){
487 info->protect[i] = p;
493 if(addr_spec(argv[2], argv[3], &addr_first, &addr_last) < 0){
494 printf("## Error: bad address format\n");
498 if(addr_first >= addr_last){
500 if(cmdtp->help != NULL){
501 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->help);
503 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
506 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
511 rcode = flash_sect_protect(p, addr_first, addr_last);
514 #endif /* we don't need do_protect cmd */
516 int flash_sect_protect(int p, ulong addr_first, ulong addr_last){
519 int s_first[CFG_MAX_FLASH_BANKS], s_last[CFG_MAX_FLASH_BANKS];
524 rcode = flash_fill_sect_ranges( addr_first, addr_last, s_first, s_last, &planned );
528 if(planned && (rcode == 0)){
529 for(bank=0,info=&flash_info[0]; bank < CFG_MAX_FLASH_BANKS; ++bank, ++info){
530 if(info->flash_id == FLASH_UNKNOWN){
534 if(s_first[bank] >= 0 && s_first[bank] <= s_last[bank]){
535 //debug("%sProtecting sectors %d..%d in bank %ld\n", p ? "" : "Un-", s_first[bank], s_last[bank], bank+1);
536 protected += s_last[bank] - s_first[bank] + 1;
538 for(i=s_first[bank]; i<=s_last[bank]; ++i){
539 info->protect[i] = p;
543 //debug("%sProtected %d sectors\n", p ? "" : "Un-", protected);
544 } else if(rcode == 0){
545 puts("## Error: start and/or end address not on sector boundary\n");
551 #endif /* ifndef COMPRESSED_UBOOT */
553 /**************************************************/
555 U_BOOT_CMD(erase, 3, 1, do_flerase, "erase FLASH memory\n",
557 "\t- erase FLASH from addr 'start' to addr 'end'\n"
559 "\t- erase FLASH from addr 'start' to the end of sect w/addr 'start'+'len'-1\n"
561 "\t- erase sectors SF-SL in FLASH bank #N\n"
563 "\t- erase FLASH bank #N\n"
565 "\t- erase all FLASH banks\n");
567 #ifndef COMPRESSED_UBOOT
568 #if 0 // we don't need do_protect cmd
569 U_BOOT_CMD(protect, 4, 1, do_protect, "enable or disable FLASH write protection\n",
571 "\t- protect FLASH from addr 'start' to addr 'end'\n"
572 "protect start +len\n"
573 "\t- protect FLASH from addr 'start' to end of sect w/addr 'start'+'len'-1\n"
574 "protect on N:SF[-SL]\n"
575 "\t- protect sectors SF-SL in FLASH bank #N\n"
576 "protect on bank N\n"
577 "\t- protect FLASH bank #N\n"
579 "\t- protect all FLASH banks\n"
580 "protect off start end\n"
581 "\t- make FLASH from addr 'start' to addr 'end' writable\n"
582 "protect off start +len\n"
583 "\t- make FLASH from addr 'start' to end of sect w/addr 'start'+'len'-1 writable\n"
584 "protect off N:SF[-SL]\n"
585 "\t- make sectors SF-SL writable in FLASH bank #N\n"
586 "protect off bank N\n"
587 "\t- make FLASH bank #N writable\n"
589 "\t- make all FLASH banks writable\n"
591 #endif /* we don't need do_protect cmd */
592 #endif /* ifndef COMPRESSED_UBOOT */
594 #endif /* CFG_CMD_FLASH */