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