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