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