12e192b24SSimon Glass /* 22e192b24SSimon Glass * (C) Copyright 2000 32e192b24SSimon Glass * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 42e192b24SSimon Glass * 52e192b24SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 62e192b24SSimon Glass */ 72e192b24SSimon Glass 82e192b24SSimon Glass /* 92e192b24SSimon Glass * FLASH support 102e192b24SSimon Glass */ 112e192b24SSimon Glass #include <common.h> 122e192b24SSimon Glass #include <command.h> 132e192b24SSimon Glass 142e192b24SSimon Glass #if defined(CONFIG_CMD_MTDPARTS) 152e192b24SSimon Glass #include <jffs2/jffs2.h> 162e192b24SSimon Glass 172e192b24SSimon Glass /* partition handling routines */ 182e192b24SSimon Glass int mtdparts_init(void); 192e192b24SSimon Glass int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num); 202e192b24SSimon Glass int find_dev_and_part(const char *id, struct mtd_device **dev, 212e192b24SSimon Glass u8 *part_num, struct part_info **part); 222e192b24SSimon Glass #endif 232e192b24SSimon Glass 24e856bdcfSMasahiro Yamada #ifdef CONFIG_MTD_NOR_FLASH 252e192b24SSimon Glass #include <flash.h> 262e192b24SSimon Glass #include <mtd/cfi_flash.h> 272e192b24SSimon Glass extern flash_info_t flash_info[]; /* info for FLASH chips */ 282e192b24SSimon Glass 292e192b24SSimon Glass /* 302e192b24SSimon Glass * The user interface starts numbering for Flash banks with 1 312e192b24SSimon Glass * for historical reasons. 322e192b24SSimon Glass */ 332e192b24SSimon Glass 342e192b24SSimon Glass /* 352e192b24SSimon Glass * this routine looks for an abbreviated flash range specification. 362e192b24SSimon Glass * the syntax is B:SF[-SL], where B is the bank number, SF is the first 372e192b24SSimon Glass * sector to erase, and SL is the last sector to erase (defaults to SF). 382e192b24SSimon Glass * bank numbers start at 1 to be consistent with other specs, sector numbers 392e192b24SSimon Glass * start at zero. 402e192b24SSimon Glass * 412e192b24SSimon Glass * returns: 1 - correct spec; *pinfo, *psf and *psl are 422e192b24SSimon Glass * set appropriately 432e192b24SSimon Glass * 0 - doesn't look like an abbreviated spec 442e192b24SSimon Glass * -1 - looks like an abbreviated spec, but got 452e192b24SSimon Glass * a parsing error, a number out of range, 462e192b24SSimon Glass * or an invalid flash bank. 472e192b24SSimon Glass */ 482e192b24SSimon Glass static int 492e192b24SSimon Glass abbrev_spec (char *str, flash_info_t ** pinfo, int *psf, int *psl) 502e192b24SSimon Glass { 512e192b24SSimon Glass flash_info_t *fp; 522e192b24SSimon Glass int bank, first, last; 532e192b24SSimon Glass char *p, *ep; 542e192b24SSimon Glass 552e192b24SSimon Glass if ((p = strchr (str, ':')) == NULL) 562e192b24SSimon Glass return 0; 572e192b24SSimon Glass *p++ = '\0'; 582e192b24SSimon Glass 592e192b24SSimon Glass bank = simple_strtoul (str, &ep, 10); 602e192b24SSimon Glass if (ep == str || *ep != '\0' || 612e192b24SSimon Glass bank < 1 || bank > CONFIG_SYS_MAX_FLASH_BANKS || 622e192b24SSimon Glass (fp = &flash_info[bank - 1])->flash_id == FLASH_UNKNOWN) 632e192b24SSimon Glass return -1; 642e192b24SSimon Glass 652e192b24SSimon Glass str = p; 662e192b24SSimon Glass if ((p = strchr (str, '-')) != NULL) 672e192b24SSimon Glass *p++ = '\0'; 682e192b24SSimon Glass 692e192b24SSimon Glass first = simple_strtoul (str, &ep, 10); 702e192b24SSimon Glass if (ep == str || *ep != '\0' || first >= fp->sector_count) 712e192b24SSimon Glass return -1; 722e192b24SSimon Glass 732e192b24SSimon Glass if (p != NULL) { 742e192b24SSimon Glass last = simple_strtoul (p, &ep, 10); 752e192b24SSimon Glass if (ep == p || *ep != '\0' || 762e192b24SSimon Glass last < first || last >= fp->sector_count) 772e192b24SSimon Glass return -1; 782e192b24SSimon Glass } else { 792e192b24SSimon Glass last = first; 802e192b24SSimon Glass } 812e192b24SSimon Glass 822e192b24SSimon Glass *pinfo = fp; 832e192b24SSimon Glass *psf = first; 842e192b24SSimon Glass *psl = last; 852e192b24SSimon Glass 862e192b24SSimon Glass return 1; 872e192b24SSimon Glass } 882e192b24SSimon Glass 892e192b24SSimon Glass /* 902e192b24SSimon Glass * Take *addr in Flash and adjust it to fall on the end of its sector 912e192b24SSimon Glass */ 922e192b24SSimon Glass int flash_sect_roundb (ulong *addr) 932e192b24SSimon Glass { 942e192b24SSimon Glass flash_info_t *info; 952e192b24SSimon Glass ulong bank, sector_end_addr; 962e192b24SSimon Glass char found; 972e192b24SSimon Glass int i; 982e192b24SSimon Glass 992e192b24SSimon Glass /* find the end addr of the sector where the *addr is */ 1002e192b24SSimon Glass found = 0; 1012e192b24SSimon Glass for (bank = 0; bank < CONFIG_SYS_MAX_FLASH_BANKS && !found; ++bank) { 1022e192b24SSimon Glass info = &flash_info[bank]; 1032e192b24SSimon Glass for (i = 0; i < info->sector_count && !found; ++i) { 1042e192b24SSimon Glass /* get the end address of the sector */ 1052e192b24SSimon Glass if (i == info->sector_count - 1) { 1062e192b24SSimon Glass sector_end_addr = info->start[0] + 1072e192b24SSimon Glass info->size - 1; 1082e192b24SSimon Glass } else { 1092e192b24SSimon Glass sector_end_addr = info->start[i+1] - 1; 1102e192b24SSimon Glass } 1112e192b24SSimon Glass 1122e192b24SSimon Glass if (*addr <= sector_end_addr && 1132e192b24SSimon Glass *addr >= info->start[i]) { 1142e192b24SSimon Glass found = 1; 1152e192b24SSimon Glass /* adjust *addr if necessary */ 1162e192b24SSimon Glass if (*addr < sector_end_addr) 1172e192b24SSimon Glass *addr = sector_end_addr; 1182e192b24SSimon Glass } /* sector */ 1192e192b24SSimon Glass } /* bank */ 1202e192b24SSimon Glass } 1212e192b24SSimon Glass if (!found) { 1222e192b24SSimon Glass /* error, address not in flash */ 1232e192b24SSimon Glass printf("Error: end address (0x%08lx) not in flash!\n", *addr); 1242e192b24SSimon Glass return 1; 1252e192b24SSimon Glass } 1262e192b24SSimon Glass 1272e192b24SSimon Glass return 0; 1282e192b24SSimon Glass } 1292e192b24SSimon Glass 1302e192b24SSimon Glass /* 1312e192b24SSimon Glass * This function computes the start and end addresses for both 1322e192b24SSimon Glass * erase and protect commands. The range of the addresses on which 1332e192b24SSimon Glass * either of the commands is to operate can be given in two forms: 1342e192b24SSimon Glass * 1. <cmd> start end - operate on <'start', 'end') 1352e192b24SSimon Glass * 2. <cmd> start +length - operate on <'start', start + length) 1362e192b24SSimon Glass * If the second form is used and the end address doesn't fall on the 1372e192b24SSimon Glass * sector boundary, than it will be adjusted to the next sector boundary. 1382e192b24SSimon Glass * If it isn't in the flash, the function will fail (return -1). 1392e192b24SSimon Glass * Input: 1402e192b24SSimon Glass * arg1, arg2: address specification (i.e. both command arguments) 1412e192b24SSimon Glass * Output: 1422e192b24SSimon Glass * addr_first, addr_last: computed address range 1432e192b24SSimon Glass * Return: 1442e192b24SSimon Glass * 1: success 1452e192b24SSimon Glass * -1: failure (bad format, bad address). 1462e192b24SSimon Glass */ 1472e192b24SSimon Glass static int 1482e192b24SSimon Glass addr_spec(char *arg1, char *arg2, ulong *addr_first, ulong *addr_last) 1492e192b24SSimon Glass { 1502e192b24SSimon Glass char *ep; 1512e192b24SSimon Glass char len_used; /* indicates if the "start +length" form used */ 1522e192b24SSimon Glass 1532e192b24SSimon Glass *addr_first = simple_strtoul(arg1, &ep, 16); 1542e192b24SSimon Glass if (ep == arg1 || *ep != '\0') 1552e192b24SSimon Glass return -1; 1562e192b24SSimon Glass 1572e192b24SSimon Glass len_used = 0; 1582e192b24SSimon Glass if (arg2 && *arg2 == '+'){ 1592e192b24SSimon Glass len_used = 1; 1602e192b24SSimon Glass ++arg2; 1612e192b24SSimon Glass } 1622e192b24SSimon Glass 1632e192b24SSimon Glass *addr_last = simple_strtoul(arg2, &ep, 16); 1642e192b24SSimon Glass if (ep == arg2 || *ep != '\0') 1652e192b24SSimon Glass return -1; 1662e192b24SSimon Glass 1672e192b24SSimon Glass if (len_used){ 1682e192b24SSimon Glass /* 1692e192b24SSimon Glass * *addr_last has the length, compute correct *addr_last 1702e192b24SSimon Glass * XXX watch out for the integer overflow! Right now it is 1712e192b24SSimon Glass * checked for in both the callers. 1722e192b24SSimon Glass */ 1732e192b24SSimon Glass *addr_last = *addr_first + *addr_last - 1; 1742e192b24SSimon Glass 1752e192b24SSimon Glass /* 1762e192b24SSimon Glass * It may happen that *addr_last doesn't fall on the sector 1772e192b24SSimon Glass * boundary. We want to round such an address to the next 1782e192b24SSimon Glass * sector boundary, so that the commands don't fail later on. 1792e192b24SSimon Glass */ 1802e192b24SSimon Glass 1812e192b24SSimon Glass if (flash_sect_roundb(addr_last) > 0) 1822e192b24SSimon Glass return -1; 1832e192b24SSimon Glass } /* "start +length" from used */ 1842e192b24SSimon Glass 1852e192b24SSimon Glass return 1; 1862e192b24SSimon Glass } 1872e192b24SSimon Glass 1882e192b24SSimon Glass static int 1892e192b24SSimon Glass flash_fill_sect_ranges (ulong addr_first, ulong addr_last, 1902e192b24SSimon Glass int *s_first, int *s_last, 1912e192b24SSimon Glass int *s_count ) 1922e192b24SSimon Glass { 1932e192b24SSimon Glass flash_info_t *info; 1942e192b24SSimon Glass ulong bank; 1952e192b24SSimon Glass int rcode = 0; 1962e192b24SSimon Glass 1972e192b24SSimon Glass *s_count = 0; 1982e192b24SSimon Glass 1992e192b24SSimon Glass for (bank=0; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank) { 2002e192b24SSimon Glass s_first[bank] = -1; /* first sector to erase */ 2012e192b24SSimon Glass s_last [bank] = -1; /* last sector to erase */ 2022e192b24SSimon Glass } 2032e192b24SSimon Glass 2042e192b24SSimon Glass for (bank=0,info = &flash_info[0]; 2052e192b24SSimon Glass (bank < CONFIG_SYS_MAX_FLASH_BANKS) && (addr_first <= addr_last); 2062e192b24SSimon Glass ++bank, ++info) { 2072e192b24SSimon Glass ulong b_end; 2082e192b24SSimon Glass int sect; 2092e192b24SSimon Glass short s_end; 2102e192b24SSimon Glass 2112e192b24SSimon Glass if (info->flash_id == FLASH_UNKNOWN) { 2122e192b24SSimon Glass continue; 2132e192b24SSimon Glass } 2142e192b24SSimon Glass 2152e192b24SSimon Glass b_end = info->start[0] + info->size - 1; /* bank end addr */ 2162e192b24SSimon Glass s_end = info->sector_count - 1; /* last sector */ 2172e192b24SSimon Glass 2182e192b24SSimon Glass 2192e192b24SSimon Glass for (sect=0; sect < info->sector_count; ++sect) { 2202e192b24SSimon Glass ulong end; /* last address in current sect */ 2212e192b24SSimon Glass 2222e192b24SSimon Glass end = (sect == s_end) ? b_end : info->start[sect + 1] - 1; 2232e192b24SSimon Glass 2242e192b24SSimon Glass if (addr_first > end) 2252e192b24SSimon Glass continue; 2262e192b24SSimon Glass if (addr_last < info->start[sect]) 2272e192b24SSimon Glass continue; 2282e192b24SSimon Glass 2292e192b24SSimon Glass if (addr_first == info->start[sect]) { 2302e192b24SSimon Glass s_first[bank] = sect; 2312e192b24SSimon Glass } 2322e192b24SSimon Glass if (addr_last == end) { 2332e192b24SSimon Glass s_last[bank] = sect; 2342e192b24SSimon Glass } 2352e192b24SSimon Glass } 2362e192b24SSimon Glass if (s_first[bank] >= 0) { 2372e192b24SSimon Glass if (s_last[bank] < 0) { 2382e192b24SSimon Glass if (addr_last > b_end) { 2392e192b24SSimon Glass s_last[bank] = s_end; 2402e192b24SSimon Glass } else { 2412e192b24SSimon Glass puts ("Error: end address" 2422e192b24SSimon Glass " not on sector boundary\n"); 2432e192b24SSimon Glass rcode = 1; 2442e192b24SSimon Glass break; 2452e192b24SSimon Glass } 2462e192b24SSimon Glass } 2472e192b24SSimon Glass if (s_last[bank] < s_first[bank]) { 2482e192b24SSimon Glass puts ("Error: end sector" 2492e192b24SSimon Glass " precedes start sector\n"); 2502e192b24SSimon Glass rcode = 1; 2512e192b24SSimon Glass break; 2522e192b24SSimon Glass } 2532e192b24SSimon Glass sect = s_last[bank]; 2542e192b24SSimon Glass addr_first = (sect == s_end) ? b_end + 1: info->start[sect + 1]; 2552e192b24SSimon Glass (*s_count) += s_last[bank] - s_first[bank] + 1; 2562e192b24SSimon Glass } else if (addr_first >= info->start[0] && addr_first < b_end) { 2572e192b24SSimon Glass puts ("Error: start address not on sector boundary\n"); 2582e192b24SSimon Glass rcode = 1; 2592e192b24SSimon Glass break; 2602e192b24SSimon Glass } else if (s_last[bank] >= 0) { 2612e192b24SSimon Glass puts ("Error: cannot span across banks when they are" 2622e192b24SSimon Glass " mapped in reverse order\n"); 2632e192b24SSimon Glass rcode = 1; 2642e192b24SSimon Glass break; 2652e192b24SSimon Glass } 2662e192b24SSimon Glass } 2672e192b24SSimon Glass 2682e192b24SSimon Glass return rcode; 2692e192b24SSimon Glass } 270e856bdcfSMasahiro Yamada #endif /* CONFIG_MTD_NOR_FLASH */ 2712e192b24SSimon Glass 2722e192b24SSimon Glass static int do_flinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 2732e192b24SSimon Glass { 274e856bdcfSMasahiro Yamada #ifdef CONFIG_MTD_NOR_FLASH 2752e192b24SSimon Glass ulong bank; 2762e192b24SSimon Glass #endif 2772e192b24SSimon Glass 278e856bdcfSMasahiro Yamada #ifdef CONFIG_MTD_NOR_FLASH 2792e192b24SSimon Glass if (argc == 1) { /* print info for all FLASH banks */ 2802e192b24SSimon Glass for (bank=0; bank <CONFIG_SYS_MAX_FLASH_BANKS; ++bank) { 2812e192b24SSimon Glass printf ("\nBank # %ld: ", bank+1); 2822e192b24SSimon Glass 2832e192b24SSimon Glass flash_print_info (&flash_info[bank]); 2842e192b24SSimon Glass } 2852e192b24SSimon Glass return 0; 2862e192b24SSimon Glass } 2872e192b24SSimon Glass 2882e192b24SSimon Glass bank = simple_strtoul(argv[1], NULL, 16); 2892e192b24SSimon Glass if ((bank < 1) || (bank > CONFIG_SYS_MAX_FLASH_BANKS)) { 2902e192b24SSimon Glass printf ("Only FLASH Banks # 1 ... # %d supported\n", 2912e192b24SSimon Glass CONFIG_SYS_MAX_FLASH_BANKS); 2922e192b24SSimon Glass return 1; 2932e192b24SSimon Glass } 2942e192b24SSimon Glass printf ("\nBank # %ld: ", bank); 2952e192b24SSimon Glass flash_print_info (&flash_info[bank-1]); 296e856bdcfSMasahiro Yamada #endif /* CONFIG_MTD_NOR_FLASH */ 2972e192b24SSimon Glass return 0; 2982e192b24SSimon Glass } 2992e192b24SSimon Glass 3002e192b24SSimon Glass static int do_flerase(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 3012e192b24SSimon Glass { 302e856bdcfSMasahiro Yamada #ifdef CONFIG_MTD_NOR_FLASH 3032e192b24SSimon Glass flash_info_t *info = NULL; 3042e192b24SSimon Glass ulong bank, addr_first, addr_last; 3052e192b24SSimon Glass int n, sect_first = 0, sect_last = 0; 3062e192b24SSimon Glass #if defined(CONFIG_CMD_MTDPARTS) 3072e192b24SSimon Glass struct mtd_device *dev; 3082e192b24SSimon Glass struct part_info *part; 3092e192b24SSimon Glass u8 dev_type, dev_num, pnum; 3102e192b24SSimon Glass #endif 3112e192b24SSimon Glass int rcode = 0; 3122e192b24SSimon Glass 3132e192b24SSimon Glass if (argc < 2) 3142e192b24SSimon Glass return CMD_RET_USAGE; 3152e192b24SSimon Glass 3162e192b24SSimon Glass if (strcmp(argv[1], "all") == 0) { 3172e192b24SSimon Glass for (bank=1; bank<=CONFIG_SYS_MAX_FLASH_BANKS; ++bank) { 3182e192b24SSimon Glass printf ("Erase Flash Bank # %ld ", bank); 3192e192b24SSimon Glass info = &flash_info[bank-1]; 3202e192b24SSimon Glass rcode = flash_erase (info, 0, info->sector_count-1); 3212e192b24SSimon Glass } 3222e192b24SSimon Glass return rcode; 3232e192b24SSimon Glass } 3242e192b24SSimon Glass 3252e192b24SSimon Glass if ((n = abbrev_spec(argv[1], &info, §_first, §_last)) != 0) { 3262e192b24SSimon Glass if (n < 0) { 3272e192b24SSimon Glass puts ("Bad sector specification\n"); 3282e192b24SSimon Glass return 1; 3292e192b24SSimon Glass } 3302e192b24SSimon Glass printf ("Erase Flash Sectors %d-%d in Bank # %zu ", 3312e192b24SSimon Glass sect_first, sect_last, (info-flash_info)+1); 3322e192b24SSimon Glass rcode = flash_erase(info, sect_first, sect_last); 3332e192b24SSimon Glass return rcode; 3342e192b24SSimon Glass } 3352e192b24SSimon Glass 3362e192b24SSimon Glass #if defined(CONFIG_CMD_MTDPARTS) 3372e192b24SSimon Glass /* erase <part-id> - erase partition */ 3382e192b24SSimon Glass if ((argc == 2) && (mtd_id_parse(argv[1], NULL, &dev_type, &dev_num) == 0)) { 3392e192b24SSimon Glass mtdparts_init(); 3402e192b24SSimon Glass if (find_dev_and_part(argv[1], &dev, &pnum, &part) == 0) { 3412e192b24SSimon Glass if (dev->id->type == MTD_DEV_TYPE_NOR) { 3422e192b24SSimon Glass bank = dev->id->num; 3432e192b24SSimon Glass info = &flash_info[bank]; 3442e192b24SSimon Glass addr_first = part->offset + info->start[0]; 3452e192b24SSimon Glass addr_last = addr_first + part->size - 1; 3462e192b24SSimon Glass 3472e192b24SSimon Glass printf ("Erase Flash Partition %s, " 3482e192b24SSimon Glass "bank %ld, 0x%08lx - 0x%08lx ", 3492e192b24SSimon Glass argv[1], bank, addr_first, 3502e192b24SSimon Glass addr_last); 3512e192b24SSimon Glass 3522e192b24SSimon Glass rcode = flash_sect_erase(addr_first, addr_last); 3532e192b24SSimon Glass return rcode; 3542e192b24SSimon Glass } 3552e192b24SSimon Glass 3562e192b24SSimon Glass printf("cannot erase, not a NOR device\n"); 3572e192b24SSimon Glass return 1; 3582e192b24SSimon Glass } 3592e192b24SSimon Glass } 3602e192b24SSimon Glass #endif 3612e192b24SSimon Glass 3622e192b24SSimon Glass if (argc != 3) 3632e192b24SSimon Glass return CMD_RET_USAGE; 3642e192b24SSimon Glass 3652e192b24SSimon Glass if (strcmp(argv[1], "bank") == 0) { 3662e192b24SSimon Glass bank = simple_strtoul(argv[2], NULL, 16); 3672e192b24SSimon Glass if ((bank < 1) || (bank > CONFIG_SYS_MAX_FLASH_BANKS)) { 3682e192b24SSimon Glass printf ("Only FLASH Banks # 1 ... # %d supported\n", 3692e192b24SSimon Glass CONFIG_SYS_MAX_FLASH_BANKS); 3702e192b24SSimon Glass return 1; 3712e192b24SSimon Glass } 3722e192b24SSimon Glass printf ("Erase Flash Bank # %ld ", bank); 3732e192b24SSimon Glass info = &flash_info[bank-1]; 3742e192b24SSimon Glass rcode = flash_erase (info, 0, info->sector_count-1); 3752e192b24SSimon Glass return rcode; 3762e192b24SSimon Glass } 3772e192b24SSimon Glass 3782e192b24SSimon Glass if (addr_spec(argv[1], argv[2], &addr_first, &addr_last) < 0){ 3792e192b24SSimon Glass printf ("Bad address format\n"); 3802e192b24SSimon Glass return 1; 3812e192b24SSimon Glass } 3822e192b24SSimon Glass 3832e192b24SSimon Glass if (addr_first >= addr_last) 3842e192b24SSimon Glass return CMD_RET_USAGE; 3852e192b24SSimon Glass 3862e192b24SSimon Glass rcode = flash_sect_erase(addr_first, addr_last); 3872e192b24SSimon Glass return rcode; 3882e192b24SSimon Glass #else 3892e192b24SSimon Glass return 0; 390e856bdcfSMasahiro Yamada #endif /* CONFIG_MTD_NOR_FLASH */ 3912e192b24SSimon Glass } 3922e192b24SSimon Glass 393e856bdcfSMasahiro Yamada #ifdef CONFIG_MTD_NOR_FLASH 3942e192b24SSimon Glass int flash_sect_erase (ulong addr_first, ulong addr_last) 3952e192b24SSimon Glass { 3962e192b24SSimon Glass flash_info_t *info; 3972e192b24SSimon Glass ulong bank; 3982e192b24SSimon Glass int s_first[CONFIG_SYS_MAX_FLASH_BANKS], s_last[CONFIG_SYS_MAX_FLASH_BANKS]; 3992e192b24SSimon Glass int erased = 0; 4002e192b24SSimon Glass int planned; 4012e192b24SSimon Glass int rcode = 0; 4022e192b24SSimon Glass 4032e192b24SSimon Glass rcode = flash_fill_sect_ranges (addr_first, addr_last, 4042e192b24SSimon Glass s_first, s_last, &planned ); 4052e192b24SSimon Glass 4062e192b24SSimon Glass if (planned && (rcode == 0)) { 4072e192b24SSimon Glass for (bank=0,info = &flash_info[0]; 4082e192b24SSimon Glass (bank < CONFIG_SYS_MAX_FLASH_BANKS) && (rcode == 0); 4092e192b24SSimon Glass ++bank, ++info) { 4102e192b24SSimon Glass if (s_first[bank]>=0) { 4112e192b24SSimon Glass erased += s_last[bank] - s_first[bank] + 1; 4122e192b24SSimon Glass debug ("Erase Flash from 0x%08lx to 0x%08lx " 4132e192b24SSimon Glass "in Bank # %ld ", 4142e192b24SSimon Glass info->start[s_first[bank]], 4152e192b24SSimon Glass (s_last[bank] == info->sector_count) ? 4162e192b24SSimon Glass info->start[0] + info->size - 1: 4172e192b24SSimon Glass info->start[s_last[bank]+1] - 1, 4182e192b24SSimon Glass bank+1); 4192e192b24SSimon Glass rcode = flash_erase (info, s_first[bank], s_last[bank]); 4202e192b24SSimon Glass } 4212e192b24SSimon Glass } 4222e192b24SSimon Glass if (rcode == 0) 4232e192b24SSimon Glass printf("Erased %d sectors\n", erased); 4242e192b24SSimon Glass } else if (rcode == 0) { 4252e192b24SSimon Glass puts ("Error: start and/or end address" 4262e192b24SSimon Glass " not on sector boundary\n"); 4272e192b24SSimon Glass rcode = 1; 4282e192b24SSimon Glass } 4292e192b24SSimon Glass return rcode; 4302e192b24SSimon Glass } 431e856bdcfSMasahiro Yamada #endif /* CONFIG_MTD_NOR_FLASH */ 4322e192b24SSimon Glass 4332e192b24SSimon Glass static int do_protect(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 4342e192b24SSimon Glass { 4352e192b24SSimon Glass int rcode = 0; 436e856bdcfSMasahiro Yamada #ifdef CONFIG_MTD_NOR_FLASH 4372e192b24SSimon Glass flash_info_t *info = NULL; 4382e192b24SSimon Glass ulong bank; 4392e192b24SSimon Glass int i, n, sect_first = 0, sect_last = 0; 4402e192b24SSimon Glass #if defined(CONFIG_CMD_MTDPARTS) 4412e192b24SSimon Glass struct mtd_device *dev; 4422e192b24SSimon Glass struct part_info *part; 4432e192b24SSimon Glass u8 dev_type, dev_num, pnum; 4442e192b24SSimon Glass #endif 445e856bdcfSMasahiro Yamada #endif /* CONFIG_MTD_NOR_FLASH */ 446*c68c03f5STuomas Tynkkynen #if defined(CONFIG_MTD_NOR_FLASH) 4472e192b24SSimon Glass int p; 4482e192b24SSimon Glass ulong addr_first, addr_last; 4492e192b24SSimon Glass #endif 4502e192b24SSimon Glass 4512e192b24SSimon Glass if (argc < 3) 4522e192b24SSimon Glass return CMD_RET_USAGE; 4532e192b24SSimon Glass 454*c68c03f5STuomas Tynkkynen #if defined(CONFIG_MTD_NOR_FLASH) 4552e192b24SSimon Glass if (strcmp(argv[1], "off") == 0) 4562e192b24SSimon Glass p = 0; 4572e192b24SSimon Glass else if (strcmp(argv[1], "on") == 0) 4582e192b24SSimon Glass p = 1; 4592e192b24SSimon Glass else 4602e192b24SSimon Glass return CMD_RET_USAGE; 4612e192b24SSimon Glass #endif 4622e192b24SSimon Glass 463e856bdcfSMasahiro Yamada #ifdef CONFIG_MTD_NOR_FLASH 4642e192b24SSimon Glass if (strcmp(argv[2], "all") == 0) { 4652e192b24SSimon Glass for (bank=1; bank<=CONFIG_SYS_MAX_FLASH_BANKS; ++bank) { 4662e192b24SSimon Glass info = &flash_info[bank-1]; 4672e192b24SSimon Glass if (info->flash_id == FLASH_UNKNOWN) { 4682e192b24SSimon Glass continue; 4692e192b24SSimon Glass } 4702e192b24SSimon Glass printf ("%sProtect Flash Bank # %ld\n", 4712e192b24SSimon Glass p ? "" : "Un-", bank); 4722e192b24SSimon Glass 4732e192b24SSimon Glass for (i=0; i<info->sector_count; ++i) { 4742e192b24SSimon Glass #if defined(CONFIG_SYS_FLASH_PROTECTION) 4752e192b24SSimon Glass if (flash_real_protect(info, i, p)) 4762e192b24SSimon Glass rcode = 1; 4772e192b24SSimon Glass putc ('.'); 4782e192b24SSimon Glass #else 4792e192b24SSimon Glass info->protect[i] = p; 4802e192b24SSimon Glass #endif /* CONFIG_SYS_FLASH_PROTECTION */ 4812e192b24SSimon Glass } 4822e192b24SSimon Glass #if defined(CONFIG_SYS_FLASH_PROTECTION) 4832e192b24SSimon Glass if (!rcode) puts (" done\n"); 4842e192b24SSimon Glass #endif /* CONFIG_SYS_FLASH_PROTECTION */ 4852e192b24SSimon Glass } 4862e192b24SSimon Glass return rcode; 4872e192b24SSimon Glass } 4882e192b24SSimon Glass 4892e192b24SSimon Glass if ((n = abbrev_spec(argv[2], &info, §_first, §_last)) != 0) { 4902e192b24SSimon Glass if (n < 0) { 4912e192b24SSimon Glass puts ("Bad sector specification\n"); 4922e192b24SSimon Glass return 1; 4932e192b24SSimon Glass } 4942e192b24SSimon Glass printf("%sProtect Flash Sectors %d-%d in Bank # %zu\n", 4952e192b24SSimon Glass p ? "" : "Un-", sect_first, sect_last, 4962e192b24SSimon Glass (info-flash_info)+1); 4972e192b24SSimon Glass for (i = sect_first; i <= sect_last; i++) { 4982e192b24SSimon Glass #if defined(CONFIG_SYS_FLASH_PROTECTION) 4992e192b24SSimon Glass if (flash_real_protect(info, i, p)) 5002e192b24SSimon Glass rcode = 1; 5012e192b24SSimon Glass putc ('.'); 5022e192b24SSimon Glass #else 5032e192b24SSimon Glass info->protect[i] = p; 5042e192b24SSimon Glass #endif /* CONFIG_SYS_FLASH_PROTECTION */ 5052e192b24SSimon Glass } 5062e192b24SSimon Glass 5072e192b24SSimon Glass #if defined(CONFIG_SYS_FLASH_PROTECTION) 5082e192b24SSimon Glass if (!rcode) puts (" done\n"); 5092e192b24SSimon Glass #endif /* CONFIG_SYS_FLASH_PROTECTION */ 5102e192b24SSimon Glass 5112e192b24SSimon Glass return rcode; 5122e192b24SSimon Glass } 5132e192b24SSimon Glass 5142e192b24SSimon Glass #if defined(CONFIG_CMD_MTDPARTS) 5152e192b24SSimon Glass /* protect on/off <part-id> */ 5162e192b24SSimon Glass if ((argc == 3) && (mtd_id_parse(argv[2], NULL, &dev_type, &dev_num) == 0)) { 5172e192b24SSimon Glass mtdparts_init(); 5182e192b24SSimon Glass if (find_dev_and_part(argv[2], &dev, &pnum, &part) == 0) { 5192e192b24SSimon Glass if (dev->id->type == MTD_DEV_TYPE_NOR) { 5202e192b24SSimon Glass bank = dev->id->num; 5212e192b24SSimon Glass info = &flash_info[bank]; 5222e192b24SSimon Glass addr_first = part->offset + info->start[0]; 5232e192b24SSimon Glass addr_last = addr_first + part->size - 1; 5242e192b24SSimon Glass 5252e192b24SSimon Glass printf ("%sProtect Flash Partition %s, " 5262e192b24SSimon Glass "bank %ld, 0x%08lx - 0x%08lx\n", 5272e192b24SSimon Glass p ? "" : "Un", argv[1], 5282e192b24SSimon Glass bank, addr_first, addr_last); 5292e192b24SSimon Glass 5302e192b24SSimon Glass rcode = flash_sect_protect (p, addr_first, addr_last); 5312e192b24SSimon Glass return rcode; 5322e192b24SSimon Glass } 5332e192b24SSimon Glass 5342e192b24SSimon Glass printf("cannot %sprotect, not a NOR device\n", 5352e192b24SSimon Glass p ? "" : "un"); 5362e192b24SSimon Glass return 1; 5372e192b24SSimon Glass } 5382e192b24SSimon Glass } 5392e192b24SSimon Glass #endif 5402e192b24SSimon Glass 5412e192b24SSimon Glass if (argc != 4) 5422e192b24SSimon Glass return CMD_RET_USAGE; 5432e192b24SSimon Glass 5442e192b24SSimon Glass if (strcmp(argv[2], "bank") == 0) { 5452e192b24SSimon Glass bank = simple_strtoul(argv[3], NULL, 16); 5462e192b24SSimon Glass if ((bank < 1) || (bank > CONFIG_SYS_MAX_FLASH_BANKS)) { 5472e192b24SSimon Glass printf ("Only FLASH Banks # 1 ... # %d supported\n", 5482e192b24SSimon Glass CONFIG_SYS_MAX_FLASH_BANKS); 5492e192b24SSimon Glass return 1; 5502e192b24SSimon Glass } 5512e192b24SSimon Glass printf ("%sProtect Flash Bank # %ld\n", 5522e192b24SSimon Glass p ? "" : "Un-", bank); 5532e192b24SSimon Glass info = &flash_info[bank-1]; 5542e192b24SSimon Glass 5552e192b24SSimon Glass if (info->flash_id == FLASH_UNKNOWN) { 5562e192b24SSimon Glass puts ("missing or unknown FLASH type\n"); 5572e192b24SSimon Glass return 1; 5582e192b24SSimon Glass } 5592e192b24SSimon Glass for (i=0; i<info->sector_count; ++i) { 5602e192b24SSimon Glass #if defined(CONFIG_SYS_FLASH_PROTECTION) 5612e192b24SSimon Glass if (flash_real_protect(info, i, p)) 5622e192b24SSimon Glass rcode = 1; 5632e192b24SSimon Glass putc ('.'); 5642e192b24SSimon Glass #else 5652e192b24SSimon Glass info->protect[i] = p; 5662e192b24SSimon Glass #endif /* CONFIG_SYS_FLASH_PROTECTION */ 5672e192b24SSimon Glass } 5682e192b24SSimon Glass 5692e192b24SSimon Glass #if defined(CONFIG_SYS_FLASH_PROTECTION) 5702e192b24SSimon Glass if (!rcode) puts (" done\n"); 5712e192b24SSimon Glass #endif /* CONFIG_SYS_FLASH_PROTECTION */ 5722e192b24SSimon Glass 5732e192b24SSimon Glass return rcode; 5742e192b24SSimon Glass } 5752e192b24SSimon Glass 5762e192b24SSimon Glass if (addr_spec(argv[2], argv[3], &addr_first, &addr_last) < 0){ 5772e192b24SSimon Glass printf("Bad address format\n"); 5782e192b24SSimon Glass return 1; 5792e192b24SSimon Glass } 5802e192b24SSimon Glass 5812e192b24SSimon Glass if (addr_first >= addr_last) 5822e192b24SSimon Glass return CMD_RET_USAGE; 5832e192b24SSimon Glass 5842e192b24SSimon Glass rcode = flash_sect_protect (p, addr_first, addr_last); 585e856bdcfSMasahiro Yamada #endif /* CONFIG_MTD_NOR_FLASH */ 5862e192b24SSimon Glass return rcode; 5872e192b24SSimon Glass } 5882e192b24SSimon Glass 589e856bdcfSMasahiro Yamada #ifdef CONFIG_MTD_NOR_FLASH 5902e192b24SSimon Glass int flash_sect_protect (int p, ulong addr_first, ulong addr_last) 5912e192b24SSimon Glass { 5922e192b24SSimon Glass flash_info_t *info; 5932e192b24SSimon Glass ulong bank; 5942e192b24SSimon Glass int s_first[CONFIG_SYS_MAX_FLASH_BANKS], s_last[CONFIG_SYS_MAX_FLASH_BANKS]; 5952e192b24SSimon Glass int protected, i; 5962e192b24SSimon Glass int planned; 5972e192b24SSimon Glass int rcode; 5982e192b24SSimon Glass 5992e192b24SSimon Glass rcode = flash_fill_sect_ranges( addr_first, addr_last, s_first, s_last, &planned ); 6002e192b24SSimon Glass 6012e192b24SSimon Glass protected = 0; 6022e192b24SSimon Glass 6032e192b24SSimon Glass if (planned && (rcode == 0)) { 6042e192b24SSimon Glass for (bank=0,info = &flash_info[0]; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank, ++info) { 6052e192b24SSimon Glass if (info->flash_id == FLASH_UNKNOWN) { 6062e192b24SSimon Glass continue; 6072e192b24SSimon Glass } 6082e192b24SSimon Glass 6092e192b24SSimon Glass if (s_first[bank]>=0 && s_first[bank]<=s_last[bank]) { 6102e192b24SSimon Glass debug ("%sProtecting sectors %d..%d in bank %ld\n", 6112e192b24SSimon Glass p ? "" : "Un-", 6122e192b24SSimon Glass s_first[bank], s_last[bank], bank+1); 6132e192b24SSimon Glass protected += s_last[bank] - s_first[bank] + 1; 6142e192b24SSimon Glass for (i=s_first[bank]; i<=s_last[bank]; ++i) { 6152e192b24SSimon Glass #if defined(CONFIG_SYS_FLASH_PROTECTION) 6162e192b24SSimon Glass if (flash_real_protect(info, i, p)) 6172e192b24SSimon Glass rcode = 1; 6182e192b24SSimon Glass putc ('.'); 6192e192b24SSimon Glass #else 6202e192b24SSimon Glass info->protect[i] = p; 6212e192b24SSimon Glass #endif /* CONFIG_SYS_FLASH_PROTECTION */ 6222e192b24SSimon Glass } 6232e192b24SSimon Glass } 6242e192b24SSimon Glass } 6252e192b24SSimon Glass #if defined(CONFIG_SYS_FLASH_PROTECTION) 6262e192b24SSimon Glass puts (" done\n"); 6272e192b24SSimon Glass #endif /* CONFIG_SYS_FLASH_PROTECTION */ 6282e192b24SSimon Glass 6292e192b24SSimon Glass printf ("%sProtected %d sectors\n", 6302e192b24SSimon Glass p ? "" : "Un-", protected); 6312e192b24SSimon Glass } else if (rcode == 0) { 6322e192b24SSimon Glass puts ("Error: start and/or end address" 6332e192b24SSimon Glass " not on sector boundary\n"); 6342e192b24SSimon Glass rcode = 1; 6352e192b24SSimon Glass } 6362e192b24SSimon Glass return rcode; 6372e192b24SSimon Glass } 638e856bdcfSMasahiro Yamada #endif /* CONFIG_MTD_NOR_FLASH */ 6392e192b24SSimon Glass 6402e192b24SSimon Glass 6412e192b24SSimon Glass /**************************************************/ 6422e192b24SSimon Glass #if defined(CONFIG_CMD_MTDPARTS) 6432e192b24SSimon Glass # define TMP_ERASE "erase <part-id>\n - erase partition\n" 6442e192b24SSimon Glass # define TMP_PROT_ON "protect on <part-id>\n - protect partition\n" 6452e192b24SSimon Glass # define TMP_PROT_OFF "protect off <part-id>\n - make partition writable\n" 6462e192b24SSimon Glass #else 6472e192b24SSimon Glass # define TMP_ERASE /* empty */ 6482e192b24SSimon Glass # define TMP_PROT_ON /* empty */ 6492e192b24SSimon Glass # define TMP_PROT_OFF /* empty */ 6502e192b24SSimon Glass #endif 6512e192b24SSimon Glass 6522e192b24SSimon Glass U_BOOT_CMD( 6532e192b24SSimon Glass flinfo, 2, 1, do_flinfo, 6542e192b24SSimon Glass "print FLASH memory information", 6552e192b24SSimon Glass "\n - print information for all FLASH memory banks\n" 6562e192b24SSimon Glass "flinfo N\n - print information for FLASH memory bank # N" 6572e192b24SSimon Glass ); 6582e192b24SSimon Glass 6592e192b24SSimon Glass U_BOOT_CMD( 6602e192b24SSimon Glass erase, 3, 0, do_flerase, 6612e192b24SSimon Glass "erase FLASH memory", 6622e192b24SSimon Glass "start end\n" 6632e192b24SSimon Glass " - erase FLASH from addr 'start' to addr 'end'\n" 6642e192b24SSimon Glass "erase start +len\n" 6652e192b24SSimon Glass " - erase FLASH from addr 'start' to the end of sect " 6662e192b24SSimon Glass "w/addr 'start'+'len'-1\n" 6672e192b24SSimon Glass "erase N:SF[-SL]\n - erase sectors SF-SL in FLASH bank # N\n" 6682e192b24SSimon Glass "erase bank N\n - erase FLASH bank # N\n" 6692e192b24SSimon Glass TMP_ERASE 6702e192b24SSimon Glass "erase all\n - erase all FLASH banks" 6712e192b24SSimon Glass ); 6722e192b24SSimon Glass 6732e192b24SSimon Glass U_BOOT_CMD( 6742e192b24SSimon Glass protect, 4, 0, do_protect, 6752e192b24SSimon Glass "enable or disable FLASH write protection", 6762e192b24SSimon Glass "on start end\n" 6772e192b24SSimon Glass " - protect FLASH from addr 'start' to addr 'end'\n" 6782e192b24SSimon Glass "protect on start +len\n" 6792e192b24SSimon Glass " - protect FLASH from addr 'start' to end of sect " 6802e192b24SSimon Glass "w/addr 'start'+'len'-1\n" 6812e192b24SSimon Glass "protect on N:SF[-SL]\n" 6822e192b24SSimon Glass " - protect sectors SF-SL in FLASH bank # N\n" 6832e192b24SSimon Glass "protect on bank N\n - protect FLASH bank # N\n" 6842e192b24SSimon Glass TMP_PROT_ON 6852e192b24SSimon Glass "protect on all\n - protect all FLASH banks\n" 6862e192b24SSimon Glass "protect off start end\n" 6872e192b24SSimon Glass " - make FLASH from addr 'start' to addr 'end' writable\n" 6882e192b24SSimon Glass "protect off start +len\n" 6892e192b24SSimon Glass " - make FLASH from addr 'start' to end of sect " 6902e192b24SSimon Glass "w/addr 'start'+'len'-1 wrtable\n" 6912e192b24SSimon Glass "protect off N:SF[-SL]\n" 6922e192b24SSimon Glass " - make sectors SF-SL writable in FLASH bank # N\n" 6932e192b24SSimon Glass "protect off bank N\n - make FLASH bank # N writable\n" 6942e192b24SSimon Glass TMP_PROT_OFF 6952e192b24SSimon Glass "protect off all\n - make all FLASH banks writable" 6962e192b24SSimon Glass ); 6972e192b24SSimon Glass 6982e192b24SSimon Glass #undef TMP_ERASE 6992e192b24SSimon Glass #undef TMP_PROT_ON 7002e192b24SSimon Glass #undef TMP_PROT_OFF 701