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