Merge branch 'master' of git://www.denx.de/git/u-boot
[platform/kernel/u-boot.git] / common / cmd_flash.c
1 /*
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
30 #ifdef CONFIG_HAS_DATAFLASH
31 #include <dataflash.h>
32 #endif
33
34 #if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
35 #include <jffs2/jffs2.h>
36
37 /* parition handling routines */
38 int mtdparts_init(void);
39 int id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num);
40 int find_dev_and_part(const char *id, struct mtd_device **dev,
41                 u8 *part_num, struct part_info **part);
42 #endif
43
44 #ifndef CFG_NO_FLASH
45 extern flash_info_t flash_info[];       /* info for FLASH chips */
46
47 /*
48  * The user interface starts numbering for Flash banks with 1
49  * for historical reasons.
50  */
51
52 /*
53  * this routine looks for an abbreviated flash range specification.
54  * the syntax is B:SF[-SL], where B is the bank number, SF is the first
55  * sector to erase, and SL is the last sector to erase (defaults to SF).
56  * bank numbers start at 1 to be consistent with other specs, sector numbers
57  * start at zero.
58  *
59  * returns:     1       - correct spec; *pinfo, *psf and *psl are
60  *                        set appropriately
61  *              0       - doesn't look like an abbreviated spec
62  *              -1      - looks like an abbreviated spec, but got
63  *                        a parsing error, a number out of range,
64  *                        or an invalid flash bank.
65  */
66 static int
67 abbrev_spec (char *str, flash_info_t ** pinfo, int *psf, int *psl)
68 {
69         flash_info_t *fp;
70         int bank, first, last;
71         char *p, *ep;
72
73         if ((p = strchr (str, ':')) == NULL)
74                 return 0;
75         *p++ = '\0';
76
77         bank = simple_strtoul (str, &ep, 10);
78         if (ep == str || *ep != '\0' ||
79                 bank < 1 || bank > CFG_MAX_FLASH_BANKS ||
80                 (fp = &flash_info[bank - 1])->flash_id == FLASH_UNKNOWN)
81                 return -1;
82
83         str = p;
84         if ((p = strchr (str, '-')) != NULL)
85                 *p++ = '\0';
86
87         first = simple_strtoul (str, &ep, 10);
88         if (ep == str || *ep != '\0' || first >= fp->sector_count)
89                 return -1;
90
91         if (p != NULL) {
92                 last = simple_strtoul (p, &ep, 10);
93                 if (ep == p || *ep != '\0' ||
94                         last < first || last >= fp->sector_count)
95                         return -1;
96         } else {
97                 last = first;
98         }
99
100         *pinfo = fp;
101         *psf = first;
102         *psl = last;
103
104         return 1;
105 }
106
107 /*
108  * This function computes the start and end addresses for both
109  * erase and protect commands. The range of the addresses on which
110  * either of the commands is to operate can be given in two forms:
111  * 1. <cmd> start end - operate on <'start',  'end')
112  * 2. <cmd> start +length - operate on <'start', start + length)
113  * If the second form is used and the end address doesn't fall on the
114  * sector boundary, than it will be adjusted to the next sector boundary.
115  * If it isn't in the flash, the function will fail (return -1).
116  * Input:
117  *    arg1, arg2: address specification (i.e. both command arguments)
118  * Output:
119  *    addr_first, addr_last: computed address range
120  * Return:
121  *    1: success
122  *   -1: failure (bad format, bad address).
123 */
124 static int
125 addr_spec(char *arg1, char *arg2, ulong *addr_first, ulong *addr_last)
126 {
127         char *ep;
128         char len_used; /* indicates if the "start +length" form used */
129         char found;
130         ulong bank;
131
132         *addr_first = simple_strtoul(arg1, &ep, 16);
133         if (ep == arg1 || *ep != '\0')
134                 return -1;
135
136         len_used = 0;
137         if (arg2 && *arg2 == '+'){
138                 len_used = 1;
139                 ++arg2;
140         }
141
142         *addr_last = simple_strtoul(arg2, &ep, 16);
143         if (ep == arg2 || *ep != '\0')
144                 return -1;
145
146         if (len_used){
147                 /*
148                  * *addr_last has the length, compute correct *addr_last
149                  * XXX watch out for the integer overflow! Right now it is
150                  * checked for in both the callers.
151                  */
152                 *addr_last = *addr_first + *addr_last - 1;
153
154                 /*
155                  * It may happen that *addr_last doesn't fall on the sector
156                  * boundary. We want to round such an address to the next
157                  * sector boundary, so that the commands don't fail later on.
158                  */
159
160                 /* find the end addr of the sector where the *addr_last is */
161                 found = 0;
162                 for (bank = 0; bank < CFG_MAX_FLASH_BANKS && !found; ++bank){
163                         int i;
164                         flash_info_t *info = &flash_info[bank];
165                         for (i = 0; i < info->sector_count && !found; ++i){
166                                 /* get the end address of the sector */
167                                 ulong sector_end_addr;
168                                 if (i == info->sector_count - 1){
169                                         sector_end_addr =
170                                                 info->start[0] + info->size - 1;
171                                 } else {
172                                         sector_end_addr =
173                                                 info->start[i+1] - 1;
174                                 }
175                                 if (*addr_last <= sector_end_addr &&
176                                                 *addr_last >= info->start[i]){
177                                         /* sector found */
178                                         found = 1;
179                                         /* adjust *addr_last if necessary */
180                                         if (*addr_last < sector_end_addr){
181                                                 *addr_last = sector_end_addr;
182                                         }
183                                 }
184                         } /* sector */
185                 } /* bank */
186                 if (!found){
187                         /* error, addres not in flash */
188                         printf("Error: end address (0x%08lx) not in flash!\n",
189                                                                 *addr_last);
190                         return -1;
191                 }
192         } /* "start +length" from used */
193
194         return 1;
195 }
196
197 static int
198 flash_fill_sect_ranges (ulong addr_first, ulong addr_last,
199                         int *s_first, int *s_last,
200                         int *s_count )
201 {
202         flash_info_t *info;
203         ulong bank;
204         int rcode = 0;
205
206         *s_count = 0;
207
208         for (bank=0; bank < CFG_MAX_FLASH_BANKS; ++bank) {
209                 s_first[bank] = -1;     /* first sector to erase        */
210                 s_last [bank] = -1;     /* last  sector to erase        */
211         }
212
213         for (bank=0,info = &flash_info[0];
214              (bank < CFG_MAX_FLASH_BANKS) && (addr_first <= addr_last);
215              ++bank, ++info) {
216                 ulong b_end;
217                 int sect;
218                 short s_end;
219
220                 if (info->flash_id == FLASH_UNKNOWN) {
221                         continue;
222                 }
223
224                 b_end = info->start[0] + info->size - 1;        /* bank end addr */
225                 s_end = info->sector_count - 1;                 /* last sector   */
226
227
228                 for (sect=0; sect < info->sector_count; ++sect) {
229                         ulong end;      /* last address in current sect */
230
231                         end = (sect == s_end) ? b_end : info->start[sect + 1] - 1;
232
233                         if (addr_first > end)
234                                 continue;
235                         if (addr_last < info->start[sect])
236                                 continue;
237
238                         if (addr_first == info->start[sect]) {
239                                 s_first[bank] = sect;
240                         }
241                         if (addr_last  == end) {
242                                 s_last[bank]  = sect;
243                         }
244                 }
245                 if (s_first[bank] >= 0) {
246                         if (s_last[bank] < 0) {
247                                 if (addr_last > b_end) {
248                                         s_last[bank] = s_end;
249                                 } else {
250                                         puts ("Error: end address"
251                                                 " not on sector boundary\n");
252                                         rcode = 1;
253                                         break;
254                                 }
255                         }
256                         if (s_last[bank] < s_first[bank]) {
257                                 puts ("Error: end sector"
258                                         " precedes start sector\n");
259                                 rcode = 1;
260                                 break;
261                         }
262                         sect = s_last[bank];
263                         addr_first = (sect == s_end) ? b_end + 1: info->start[sect + 1];
264                         (*s_count) += s_last[bank] - s_first[bank] + 1;
265                 } else if (addr_first >= info->start[0] && addr_first < b_end) {
266                         puts ("Error: start address not on sector boundary\n");
267                         rcode = 1;
268                         break;
269                 } else if (s_last[bank] >= 0) {
270                         puts ("Error: cannot span across banks when they are"
271                                " mapped in reverse order\n");
272                         rcode = 1;
273                         break;
274                 }
275         }
276
277         return rcode;
278 }
279 #endif /* CFG_NO_FLASH */
280
281 int do_flinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
282 {
283 #ifndef CFG_NO_FLASH
284         ulong bank;
285 #endif
286
287 #ifdef CONFIG_HAS_DATAFLASH
288         dataflash_print_info();
289 #endif
290
291 #ifndef CFG_NO_FLASH
292         if (argc == 1) {        /* print info for all FLASH banks */
293                 for (bank=0; bank <CFG_MAX_FLASH_BANKS; ++bank) {
294                         printf ("\nBank # %ld: ", bank+1);
295
296                         flash_print_info (&flash_info[bank]);
297                 }
298                 return 0;
299         }
300
301         bank = simple_strtoul(argv[1], NULL, 16);
302         if ((bank < 1) || (bank > CFG_MAX_FLASH_BANKS)) {
303                 printf ("Only FLASH Banks # 1 ... # %d supported\n",
304                         CFG_MAX_FLASH_BANKS);
305                 return 1;
306         }
307         printf ("\nBank # %ld: ", bank);
308         flash_print_info (&flash_info[bank-1]);
309 #endif /* CFG_NO_FLASH */
310         return 0;
311 }
312
313 int do_flerase (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
314 {
315 #ifndef CFG_NO_FLASH
316         flash_info_t *info;
317         ulong bank, addr_first, addr_last;
318         int n, sect_first, sect_last;
319 #if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
320         struct mtd_device *dev;
321         struct part_info *part;
322         u8 dev_type, dev_num, pnum;
323 #endif
324         int rcode = 0;
325
326         if (argc < 2) {
327                 printf ("Usage:\n%s\n", cmdtp->usage);
328                 return 1;
329         }
330
331         if (strcmp(argv[1], "all") == 0) {
332                 for (bank=1; bank<=CFG_MAX_FLASH_BANKS; ++bank) {
333                         printf ("Erase Flash Bank # %ld ", bank);
334                         info = &flash_info[bank-1];
335                         rcode = flash_erase (info, 0, info->sector_count-1);
336                 }
337                 return rcode;
338         }
339
340         if ((n = abbrev_spec(argv[1], &info, &sect_first, &sect_last)) != 0) {
341                 if (n < 0) {
342                         puts ("Bad sector specification\n");
343                         return 1;
344                 }
345                 printf ("Erase Flash Sectors %d-%d in Bank # %zu ",
346                         sect_first, sect_last, (info-flash_info)+1);
347                 rcode = flash_erase(info, sect_first, sect_last);
348                 return rcode;
349         }
350
351 #if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
352         /* erase <part-id> - erase partition */
353         if ((argc == 2) && (id_parse(argv[1], NULL, &dev_type, &dev_num) == 0)) {
354                 mtdparts_init();
355                 if (find_dev_and_part(argv[1], &dev, &pnum, &part) == 0) {
356                         if (dev->id->type == MTD_DEV_TYPE_NOR) {
357                                 bank = dev->id->num;
358                                 info = &flash_info[bank];
359                                 addr_first = part->offset + info->start[0];
360                                 addr_last = addr_first + part->size - 1;
361
362                                 printf ("Erase Flash Parition %s, "
363                                                 "bank %ld, 0x%08lx - 0x%08lx ",
364                                                 argv[1], bank, addr_first,
365                                                 addr_last);
366
367                                 rcode = flash_sect_erase(addr_first, addr_last);
368                                 return rcode;
369                         }
370
371                         printf("cannot erase, not a NOR device\n");
372                         return 1;
373                 }
374         }
375 #endif
376
377         if (argc != 3) {
378                 printf ("Usage:\n%s\n", cmdtp->usage);
379                 return 1;
380         }
381
382         if (strcmp(argv[1], "bank") == 0) {
383                 bank = simple_strtoul(argv[2], NULL, 16);
384                 if ((bank < 1) || (bank > CFG_MAX_FLASH_BANKS)) {
385                         printf ("Only FLASH Banks # 1 ... # %d supported\n",
386                                 CFG_MAX_FLASH_BANKS);
387                         return 1;
388                 }
389                 printf ("Erase Flash Bank # %ld ", bank);
390                 info = &flash_info[bank-1];
391                 rcode = flash_erase (info, 0, info->sector_count-1);
392                 return rcode;
393         }
394
395         if (addr_spec(argv[1], argv[2], &addr_first, &addr_last) < 0){
396                 printf ("Bad address format\n");
397                 return 1;
398         }
399
400         if (addr_first >= addr_last) {
401                 printf ("Usage:\n%s\n", cmdtp->usage);
402                 return 1;
403         }
404
405         rcode = flash_sect_erase(addr_first, addr_last);
406         return rcode;
407 #else
408         return 0;
409 #endif /* CFG_NO_FLASH */
410 }
411
412 #ifndef CFG_NO_FLASH
413 int flash_sect_erase (ulong addr_first, ulong addr_last)
414 {
415         flash_info_t *info;
416         ulong bank;
417 #ifdef CFG_MAX_FLASH_BANKS_DETECT
418         int s_first[CFG_MAX_FLASH_BANKS_DETECT], s_last[CFG_MAX_FLASH_BANKS_DETECT];
419 #else
420         int s_first[CFG_MAX_FLASH_BANKS], s_last[CFG_MAX_FLASH_BANKS];
421 #endif
422         int erased = 0;
423         int planned;
424         int rcode = 0;
425
426         rcode = flash_fill_sect_ranges (addr_first, addr_last,
427                                         s_first, s_last, &planned );
428
429         if (planned && (rcode == 0)) {
430                 for (bank=0,info = &flash_info[0];
431                      (bank < CFG_MAX_FLASH_BANKS) && (rcode == 0);
432                      ++bank, ++info) {
433                         if (s_first[bank]>=0) {
434                                 erased += s_last[bank] - s_first[bank] + 1;
435                                 debug ("Erase Flash from 0x%08lx to 0x%08lx "
436                                         "in Bank # %ld ",
437                                         info->start[s_first[bank]],
438                                         (s_last[bank] == info->sector_count) ?
439                                                 info->start[0] + info->size - 1:
440                                                 info->start[s_last[bank]+1] - 1,
441                                         bank+1);
442                                 rcode = flash_erase (info, s_first[bank], s_last[bank]);
443                         }
444                 }
445                 printf ("Erased %d sectors\n", erased);
446         } else if (rcode == 0) {
447                 puts ("Error: start and/or end address"
448                         " not on sector boundary\n");
449                 rcode = 1;
450         }
451         return rcode;
452 }
453 #endif /* CFG_NO_FLASH */
454
455 int do_protect (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
456 {
457 #ifndef CFG_NO_FLASH
458         flash_info_t *info;
459         ulong bank;
460         int i, n, sect_first, sect_last;
461 #endif /* CFG_NO_FLASH */
462         ulong addr_first, addr_last;
463         int p;
464 #if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
465         struct mtd_device *dev;
466         struct part_info *part;
467         u8 dev_type, dev_num, pnum;
468 #endif
469         int rcode = 0;
470 #ifdef CONFIG_HAS_DATAFLASH
471         int status;
472 #endif
473
474         if (argc < 3) {
475                 printf ("Usage:\n%s\n", cmdtp->usage);
476                 return 1;
477         }
478
479         if (strcmp(argv[1], "off") == 0) {
480                 p = 0;
481         } else if (strcmp(argv[1], "on") == 0) {
482                 p = 1;
483         } else {
484                 printf ("Usage:\n%s\n", cmdtp->usage);
485                 return 1;
486         }
487
488 #ifdef CONFIG_HAS_DATAFLASH
489         if ((strcmp(argv[2], "all") != 0) && (strcmp(argv[2], "bank") != 0)) {
490                 addr_first = simple_strtoul(argv[2], NULL, 16);
491                 addr_last  = simple_strtoul(argv[3], NULL, 16);
492
493                 if (addr_dataflash(addr_first) && addr_dataflash(addr_last)) {
494                         status = dataflash_real_protect(p,addr_first,addr_last);
495                         if (status < 0){
496                                 puts ("Bad DataFlash sector specification\n");
497                                 return 1;
498                         }
499                         printf("%sProtect %d DataFlash Sectors\n",
500                                 p ? "" : "Un-", status);
501                         return 0;
502                 }
503         }
504 #endif
505
506 #ifndef CFG_NO_FLASH
507         if (strcmp(argv[2], "all") == 0) {
508                 for (bank=1; bank<=CFG_MAX_FLASH_BANKS; ++bank) {
509                         info = &flash_info[bank-1];
510                         if (info->flash_id == FLASH_UNKNOWN) {
511                                 continue;
512                         }
513                         printf ("%sProtect Flash Bank # %ld\n",
514                                 p ? "" : "Un-", bank);
515
516                         for (i=0; i<info->sector_count; ++i) {
517 #if defined(CFG_FLASH_PROTECTION)
518                                 if (flash_real_protect(info, i, p))
519                                         rcode = 1;
520                                 putc ('.');
521 #else
522                                 info->protect[i] = p;
523 #endif  /* CFG_FLASH_PROTECTION */
524                         }
525 #if defined(CFG_FLASH_PROTECTION)
526                         if (!rcode) puts (" done\n");
527 #endif  /* CFG_FLASH_PROTECTION */
528                 }
529                 return rcode;
530         }
531
532         if ((n = abbrev_spec(argv[2], &info, &sect_first, &sect_last)) != 0) {
533                 if (n < 0) {
534                         puts ("Bad sector specification\n");
535                         return 1;
536                 }
537                 printf("%sProtect Flash Sectors %d-%d in Bank # %zu\n",
538                         p ? "" : "Un-", sect_first, sect_last,
539                         (info-flash_info)+1);
540                 for (i = sect_first; i <= sect_last; i++) {
541 #if defined(CFG_FLASH_PROTECTION)
542                         if (flash_real_protect(info, i, p))
543                                 rcode =  1;
544                         putc ('.');
545 #else
546                         info->protect[i] = p;
547 #endif  /* CFG_FLASH_PROTECTION */
548                 }
549
550 #if defined(CFG_FLASH_PROTECTION)
551                 if (!rcode) puts (" done\n");
552 #endif  /* CFG_FLASH_PROTECTION */
553
554                 return rcode;
555         }
556
557 #if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
558         /* protect on/off <part-id> */
559         if ((argc == 3) && (id_parse(argv[2], NULL, &dev_type, &dev_num) == 0)) {
560                 mtdparts_init();
561                 if (find_dev_and_part(argv[2], &dev, &pnum, &part) == 0) {
562                         if (dev->id->type == MTD_DEV_TYPE_NOR) {
563                                 bank = dev->id->num;
564                                 info = &flash_info[bank];
565                                 addr_first = part->offset + info->start[0];
566                                 addr_last = addr_first + part->size - 1;
567
568                                 printf ("%sProtect Flash Parition %s, "
569                                                 "bank %ld, 0x%08lx - 0x%08lx\n",
570                                                 p ? "" : "Un", argv[1],
571                                                 bank, addr_first, addr_last);
572
573                                 rcode = flash_sect_protect (p, addr_first, addr_last);
574                                 return rcode;
575                         }
576
577                         printf("cannot %sprotect, not a NOR device\n",
578                                         p ? "" : "un");
579                         return 1;
580                 }
581         }
582 #endif
583
584         if (argc != 4) {
585                 printf ("Usage:\n%s\n", cmdtp->usage);
586                 return 1;
587         }
588
589         if (strcmp(argv[2], "bank") == 0) {
590                 bank = simple_strtoul(argv[3], NULL, 16);
591                 if ((bank < 1) || (bank > CFG_MAX_FLASH_BANKS)) {
592                         printf ("Only FLASH Banks # 1 ... # %d supported\n",
593                                 CFG_MAX_FLASH_BANKS);
594                         return 1;
595                 }
596                 printf ("%sProtect Flash Bank # %ld\n",
597                         p ? "" : "Un-", bank);
598                 info = &flash_info[bank-1];
599
600                 if (info->flash_id == FLASH_UNKNOWN) {
601                         puts ("missing or unknown FLASH type\n");
602                         return 1;
603                 }
604                 for (i=0; i<info->sector_count; ++i) {
605 #if defined(CFG_FLASH_PROTECTION)
606                         if (flash_real_protect(info, i, p))
607                                 rcode =  1;
608                         putc ('.');
609 #else
610                         info->protect[i] = p;
611 #endif  /* CFG_FLASH_PROTECTION */
612                 }
613
614 #if defined(CFG_FLASH_PROTECTION)
615                 if (!rcode) puts (" done\n");
616 #endif  /* CFG_FLASH_PROTECTION */
617
618                 return rcode;
619         }
620
621         if (addr_spec(argv[2], argv[3], &addr_first, &addr_last) < 0){
622                 printf("Bad address format\n");
623                 return 1;
624         }
625
626         if (addr_first >= addr_last) {
627                 printf ("Usage:\n%s\n", cmdtp->usage);
628                 return 1;
629         }
630         rcode = flash_sect_protect (p, addr_first, addr_last);
631 #endif /* CFG_NO_FLASH */
632         return rcode;
633 }
634
635 #ifndef CFG_NO_FLASH
636 int flash_sect_protect (int p, ulong addr_first, ulong addr_last)
637 {
638         flash_info_t *info;
639         ulong bank;
640 #ifdef CFG_MAX_FLASH_BANKS_DETECT
641         int s_first[CFG_MAX_FLASH_BANKS_DETECT], s_last[CFG_MAX_FLASH_BANKS_DETECT];
642 #else
643         int s_first[CFG_MAX_FLASH_BANKS], s_last[CFG_MAX_FLASH_BANKS];
644 #endif
645         int protected, i;
646         int planned;
647         int rcode;
648
649         rcode = flash_fill_sect_ranges( addr_first, addr_last, s_first, s_last, &planned );
650
651         protected = 0;
652
653         if (planned && (rcode == 0)) {
654                 for (bank=0,info = &flash_info[0]; bank < CFG_MAX_FLASH_BANKS; ++bank, ++info) {
655                         if (info->flash_id == FLASH_UNKNOWN) {
656                                 continue;
657                         }
658
659                         if (s_first[bank]>=0 && s_first[bank]<=s_last[bank]) {
660                                 debug ("%sProtecting sectors %d..%d in bank %ld\n",
661                                         p ? "" : "Un-",
662                                         s_first[bank], s_last[bank], bank+1);
663                                 protected += s_last[bank] - s_first[bank] + 1;
664                                 for (i=s_first[bank]; i<=s_last[bank]; ++i) {
665 #if defined(CFG_FLASH_PROTECTION)
666                                         if (flash_real_protect(info, i, p))
667                                                 rcode = 1;
668                                         putc ('.');
669 #else
670                                         info->protect[i] = p;
671 #endif  /* CFG_FLASH_PROTECTION */
672                                 }
673                         }
674                 }
675 #if defined(CFG_FLASH_PROTECTION)
676                 puts (" done\n");
677 #endif  /* CFG_FLASH_PROTECTION */
678
679                 printf ("%sProtected %d sectors\n",
680                         p ? "" : "Un-", protected);
681         } else if (rcode == 0) {
682                 puts ("Error: start and/or end address"
683                         " not on sector boundary\n");
684                 rcode = 1;
685         }
686         return rcode;
687 }
688 #endif /* CFG_NO_FLASH */
689
690
691 /**************************************************/
692 #if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
693 # define TMP_ERASE      "erase <part-id>\n    - erase partition\n"
694 # define TMP_PROT_ON    "protect on <part-id>\n    - protect partition\n"
695 # define TMP_PROT_OFF   "protect off <part-id>\n    - make partition writable\n"
696 #else
697 # define TMP_ERASE      /* empty */
698 # define TMP_PROT_ON    /* empty */
699 # define TMP_PROT_OFF   /* empty */
700 #endif
701
702 U_BOOT_CMD(
703         flinfo,    2,    1,    do_flinfo,
704         "flinfo  - print FLASH memory information\n",
705         "\n    - print information for all FLASH memory banks\n"
706         "flinfo N\n    - print information for FLASH memory bank # N\n"
707 );
708
709 U_BOOT_CMD(
710         erase,   3,   0,  do_flerase,
711         "erase   - erase FLASH memory\n",
712         "start end\n"
713         "    - erase FLASH from addr 'start' to addr 'end'\n"
714         "erase start +len\n"
715         "    - erase FLASH from addr 'start' to the end of sect "
716         "w/addr 'start'+'len'-1\n"
717         "erase N:SF[-SL]\n    - erase sectors SF-SL in FLASH bank # N\n"
718         "erase bank N\n    - erase FLASH bank # N\n"
719         TMP_ERASE
720         "erase all\n    - erase all FLASH banks\n"
721 );
722
723 U_BOOT_CMD(
724         protect,  4,  0,   do_protect,
725         "protect - enable or disable FLASH write protection\n",
726         "on  start end\n"
727         "    - protect FLASH from addr 'start' to addr 'end'\n"
728         "protect on start +len\n"
729         "    - protect FLASH from addr 'start' to end of sect "
730         "w/addr 'start'+'len'-1\n"
731         "protect on  N:SF[-SL]\n"
732         "    - protect sectors SF-SL in FLASH bank # N\n"
733         "protect on  bank N\n    - protect FLASH bank # N\n"
734         TMP_PROT_ON
735         "protect on  all\n    - protect all FLASH banks\n"
736         "protect off start end\n"
737         "    - make FLASH from addr 'start' to addr 'end' writable\n"
738         "protect off start +len\n"
739         "    - make FLASH from addr 'start' to end of sect "
740         "w/addr 'start'+'len'-1 wrtable\n"
741         "protect off N:SF[-SL]\n"
742         "    - make sectors SF-SL writable in FLASH bank # N\n"
743         "protect off bank N\n    - make FLASH bank # N writable\n"
744         TMP_PROT_OFF
745         "protect off all\n    - make all FLASH banks writable\n"
746 );
747
748 #undef  TMP_ERASE
749 #undef  TMP_PROT_ON
750 #undef  TMP_PROT_OFF