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