X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=board%2Falaska%2Fflash.c;h=977822ac51e10b562d9af76f54bbf6bb66a2bea4;hb=74cf809972658eae18c33e078c05a7cc9c9460c9;hp=48c94727e07961cc41b3ac7d8ee79eb03b8ba4e1;hpb=983fda8391fa0ccfd4e0fd0bfb5a5e662e07b222;p=u-boot diff --git a/board/alaska/flash.c b/board/alaska/flash.c index 48c94727e0..977822ac51 100644 --- a/board/alaska/flash.c +++ b/board/alaska/flash.c @@ -28,7 +28,7 @@ #include -flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */ +flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */ /* Board support for 1 or 2 flash devices */ #define FLASH_PORT_WIDTH8 @@ -64,7 +64,6 @@ typedef volatile unsigned char FLASH_PORT_WIDTHV; #define FLASH_CYCLE2 0x02aa #define WR_BLOCK 0x20 - /*----------------------------------------------------------------------- * Functions */ @@ -74,6 +73,9 @@ static int write_data_block (flash_info_t * info, ulong src, ulong dest); static int write_word_amd (flash_info_t * info, FPWV * dest, FPW data); static void flash_get_offsets (ulong base, flash_info_t * info); void inline spin_wheel (void); +static void flash_sync_real_protect (flash_info_t * info); +static unsigned char intel_sector_protected (flash_info_t *info, ushort sector); +static unsigned char same_chip_banks (int bank1, int bank2); /*----------------------------------------------------------------------- */ @@ -84,30 +86,30 @@ unsigned long flash_init (void) ulong size = 0; ulong fsize = 0; - for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) { + for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) { memset (&flash_info[i], 0, sizeof (flash_info_t)); switch (i) { case 0: - flash_get_size ((FPW *) CFG_FLASH1_BASE, + flash_get_size ((FPW *) CONFIG_SYS_FLASH1_BASE, &flash_info[i]); - flash_get_offsets (CFG_FLASH1_BASE, &flash_info[i]); + flash_get_offsets (CONFIG_SYS_FLASH1_BASE, &flash_info[i]); break; case 1: - flash_get_size ((FPW *) CFG_FLASH1_BASE, + flash_get_size ((FPW *) CONFIG_SYS_FLASH1_BASE, &flash_info[i]); - fsize = CFG_FLASH1_BASE + flash_info[i - 1].size; + fsize = CONFIG_SYS_FLASH1_BASE + flash_info[i - 1].size; flash_get_offsets (fsize, &flash_info[i]); break; case 2: - flash_get_size ((FPW *) CFG_FLASH0_BASE, + flash_get_size ((FPW *) CONFIG_SYS_FLASH0_BASE, &flash_info[i]); - flash_get_offsets (CFG_FLASH0_BASE, &flash_info[i]); + flash_get_offsets (CONFIG_SYS_FLASH0_BASE, &flash_info[i]); break; case 3: - flash_get_size ((FPW *) CFG_FLASH0_BASE, + flash_get_size ((FPW *) CONFIG_SYS_FLASH0_BASE, &flash_info[i]); - fsize = CFG_FLASH0_BASE + flash_info[i - 1].size; + fsize = CONFIG_SYS_FLASH0_BASE + flash_info[i - 1].size; flash_get_offsets (fsize, &flash_info[i]); break; default: @@ -115,35 +117,38 @@ unsigned long flash_init (void) break; } size += flash_info[i].size; + + /* get the h/w and s/w protection status in sync */ + flash_sync_real_protect(&flash_info[i]); } /* Protect monitor and environment sectors */ -#if defined (CFG_AMD_BOOT) +#if defined (CONFIG_SYS_AMD_BOOT) flash_protect (FLAG_PROTECT_SET, - CFG_MONITOR_BASE, - CFG_MONITOR_BASE + monitor_flash_len - 1, + CONFIG_SYS_MONITOR_BASE, + CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1, &flash_info[2]); flash_protect (FLAG_PROTECT_SET, - CFG_INTEL_BASE, - CFG_INTEL_BASE + monitor_flash_len - 1, + CONFIG_SYS_INTEL_BASE, + CONFIG_SYS_INTEL_BASE + monitor_flash_len - 1, &flash_info[1]); #else flash_protect (FLAG_PROTECT_SET, - CFG_MONITOR_BASE, - CFG_MONITOR_BASE + monitor_flash_len - 1, + CONFIG_SYS_MONITOR_BASE, + CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1, &flash_info[3]); flash_protect (FLAG_PROTECT_SET, - CFG_AMD_BASE, - CFG_AMD_BASE + monitor_flash_len - 1, &flash_info[0]); + CONFIG_SYS_AMD_BASE, + CONFIG_SYS_AMD_BASE + monitor_flash_len - 1, &flash_info[0]); #endif flash_protect (FLAG_PROTECT_SET, - CFG_ENV1_ADDR, - CFG_ENV1_ADDR + CFG_ENV1_SIZE - 1, &flash_info[1]); + CONFIG_ENV1_ADDR, + CONFIG_ENV1_ADDR + CONFIG_ENV1_SIZE - 1, &flash_info[1]); flash_protect (FLAG_PROTECT_SET, - CFG_ENV_ADDR, - CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[3]); + CONFIG_ENV_ADDR, + CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, &flash_info[3]); return size; } @@ -167,7 +172,6 @@ static void flash_get_offsets (ulong base, flash_info_t * info) if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) { for (i = 0; i < info->sector_count; i++) { info->start[i] = base + (i * PHYS_INTEL_SECT_SIZE); - info->protect[i] = 0; } } } @@ -290,10 +294,10 @@ static ulong flash_get_size (FPW * addr, flash_info_t * info) break; } - if (info->sector_count > CFG_MAX_FLASH_SECT) { + if (info->sector_count > CONFIG_SYS_MAX_FLASH_SECT) { printf ("** ERROR: sector count %d > max (%d) **\n", - info->sector_count, CFG_MAX_FLASH_SECT); - info->sector_count = CFG_MAX_FLASH_SECT; + info->sector_count, CONFIG_SYS_MAX_FLASH_SECT); + info->sector_count = CONFIG_SYS_MAX_FLASH_SECT; } if (value == (FPW) INTEL_ID_28F128J3A) @@ -305,12 +309,104 @@ static ulong flash_get_size (FPW * addr, flash_info_t * info) } +/* + * This function gets the u-boot flash sector protection status + * (flash_info_t.protect[]) in sync with the sector protection + * status stored in hardware. + */ +static void flash_sync_real_protect (flash_info_t * info) +{ + int i; + + switch (info->flash_id & FLASH_TYPEMASK) { + case FLASH_28F128J3A: + for (i = 0; i < info->sector_count; ++i) { + info->protect[i] = intel_sector_protected(info, i); + } + break; + case FLASH_AM040: + default: + /* no h/w protect support */ + break; + } +} + + +/* + * checks if "sector" in bank "info" is protected. Should work on intel + * strata flash chips 28FxxxJ3x in 8-bit mode. + * Returns 1 if sector is protected (or timed-out while trying to read + * protection status), 0 if it is not. + */ +static unsigned char intel_sector_protected (flash_info_t *info, ushort sector) +{ + FPWV *addr; + FPWV *lock_conf_addr; + ulong start; + unsigned char ret; + + /* + * first, wait for the WSM to be finished. The rationale for + * waiting for the WSM to become idle for at most + * CONFIG_SYS_FLASH_ERASE_TOUT is as follows. The WSM can be busy + * because of: (1) erase, (2) program or (3) lock bit + * configuration. So we just wait for the longest timeout of + * the (1)-(3), i.e. the erase timeout. + */ + + /* wait at least 35ns (W12) before issuing Read Status Register */ + udelay(1); + addr = (FPWV *) info->start[sector]; + *addr = (FPW) INTEL_STATUS; + + start = get_timer (0); + while ((*addr & (FPW) INTEL_FINISHED) != (FPW) INTEL_FINISHED) { + if (get_timer (start) > CONFIG_SYS_FLASH_ERASE_TOUT) { + *addr = (FPW) INTEL_RESET; /* restore read mode */ + printf("WSM busy too long, can't get prot status\n"); + return 1; + } + } + + /* issue the Read Identifier Codes command */ + *addr = (FPW) INTEL_READID; + + /* wait at least 35ns (W12) before reading */ + udelay(1); + + /* Intel example code uses offset of 4 for 8-bit flash */ + lock_conf_addr = (FPWV *) info->start[sector] + 4; + ret = (*lock_conf_addr & (FPW) INTEL_PROTECT) ? 1 : 0; + + /* put flash back in read mode */ + *addr = (FPW) INTEL_RESET; + + return ret; +} + + +/* + * Checks if "bank1" and "bank2" are on the same chip. Returns 1 if they + * are and 0 otherwise. + */ +static unsigned char same_chip_banks (int bank1, int bank2) +{ + unsigned char same_chip[CONFIG_SYS_MAX_FLASH_BANKS][CONFIG_SYS_MAX_FLASH_BANKS] = { + {1, 1, 0, 0}, + {1, 1, 0, 0}, + {0, 0, 1, 1}, + {0, 0, 1, 1} + }; + return same_chip[bank1][bank2]; +} + + /*----------------------------------------------------------------------- */ int flash_erase (flash_info_t * info, int s_first, int s_last) { int flag, prot, sect; - ulong type, start, last; + ulong type, start; int rcode = 0, intel = 0; if ((s_first < 0) || (s_first > s_last)) { @@ -348,7 +444,6 @@ int flash_erase (flash_info_t * info, int s_first, int s_last) } start = get_timer (0); - last = start; /* Disable interrupts which might cause a timeout here */ flag = disable_interrupts (); @@ -371,7 +466,7 @@ int flash_erase (flash_info_t * info, int s_first, int s_last) } else { FPWV *base; /* first address in bank */ - base = (FPWV *) (CFG_AMD_BASE); + base = (FPWV *) (CONFIG_SYS_AMD_BASE); base[FLASH_CYCLE1] = (FPW) 0x00AA00AA; /* unlock */ base[FLASH_CYCLE2] = (FPW) 0x00550055; /* unlock */ base[FLASH_CYCLE1] = (FPW) 0x00800080; /* erase mode */ @@ -383,7 +478,7 @@ int flash_erase (flash_info_t * info, int s_first, int s_last) while (((status = *addr) & (FPW) 0x00800080) != (FPW) 0x00800080) { - if (get_timer (start) > CFG_FLASH_ERASE_TOUT) { + if (get_timer (start) > CONFIG_SYS_FLASH_ERASE_TOUT) { printf ("Timeout\n"); if (intel) { *addr = (FPW) 0x00B000B0; /* suspend erase */ @@ -405,6 +500,9 @@ int flash_erase (flash_info_t * info, int s_first, int s_last) printf (" done\n"); } } + if (flag) + enable_interrupts(); + return rcode; } @@ -570,11 +668,11 @@ static int write_data (flash_info_t * info, ulong dest, FPW data) { FPWV *addr = (FPWV *) dest; ulong start; - int flag; + int flag, rc = 0; /* Check if Flash is (sufficiently) erased */ if ((*addr & data) != data) { - printf ("not erased at %08lx (%lx)\n", (ulong) addr, *addr); + printf ("not erased at %08lx (%lx)\n", (ulong)addr, (ulong)*addr); return (2); } /* Disable interrupts which might cause a timeout here */ @@ -588,15 +686,19 @@ static int write_data (flash_info_t * info, ulong dest, FPW data) /* wait while polling the status register */ while ((*addr & (FPW) 0x00800080) != (FPW) 0x00800080) { - if (get_timer (start) > CFG_FLASH_WRITE_TOUT) { - *addr = (FPW) 0x00FF00FF; /* restore read mode */ - return (1); + if (get_timer (start) > CONFIG_SYS_FLASH_WRITE_TOUT) { + rc = 1; + goto OUT; } } - *addr = (FPW) 0x00FF00FF; /* restore read mode */ +OUT: + *addr = (FPW)0x00FF00FF; /* restore read mode */ - return (0); + if (flag) + enable_interrupts(); + + return rc; } /*----------------------------------------------------------------------- @@ -610,13 +712,13 @@ static int write_data_block (flash_info_t * info, ulong src, ulong dest) FPWV *srcaddr = (FPWV *) src; FPWV *dstaddr = (FPWV *) dest; ulong start; - int flag, i; + int flag, i, rc = 0; /* Check if Flash is (sufficiently) erased */ for (i = 0; i < WR_BLOCK; i++) if ((*dstaddr++ & 0xff) != 0xff) { printf ("not erased at %08lx (%lx)\n", - (ulong) dstaddr, *dstaddr); + (ulong)dstaddr, (ulong)*dstaddr); return (2); } @@ -631,10 +733,10 @@ static int write_data_block (flash_info_t * info, ulong src, ulong dest) start = get_timer (0); /* wait while polling the status register */ - while ((*dstaddr & (FPW) 0x00800080) != (FPW) 0x00800080) { - if (get_timer (start) > CFG_FLASH_WRITE_TOUT) { - *dstaddr = (FPW) 0x00FF00FF; /* restore read mode */ - return (1); + while ((*dstaddr & (FPW)0x00800080) != (FPW)0x00800080) { + if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) { + rc = 1; + goto OUT; } } @@ -650,15 +752,18 @@ static int write_data_block (flash_info_t * info, ulong src, ulong dest) /* wait while polling the status register */ while ((*dstaddr & (FPW) 0x00800080) != (FPW) 0x00800080) { - if (get_timer (start) > CFG_FLASH_WRITE_TOUT) { + if (get_timer (start) > CONFIG_SYS_FLASH_WRITE_TOUT) { *dstaddr = (FPW) 0x00FF00FF; /* restore read mode */ return (1); } } - *dstaddr = (FPW) 0x00FF00FF; /* restore read mode */ +OUT: + *dstaddr = (FPW)0x00FF00FF; /* restore read mode */ + if (flag) + enable_interrupts(); - return (0); + return rc; } /*----------------------------------------------------------------------- @@ -683,7 +788,7 @@ static int write_word_amd (flash_info_t * info, FPWV * dest, FPW data) return (2); } - base = (FPWV *) (CFG_AMD_BASE); + base = (FPWV *) (CONFIG_SYS_AMD_BASE); /* Disable interrupts which might cause a timeout here */ flag = disable_interrupts (); @@ -703,7 +808,7 @@ static int write_word_amd (flash_info_t * info, FPWV * dest, FPW data) /* data polling for D7 */ while (res == 0 && (*dest & (FPW) 0x00800080) != (data & (FPW) 0x00800080)) { - if (get_timer (start) > CFG_FLASH_WRITE_TOUT) { + if (get_timer (start) > CONFIG_SYS_FLASH_WRITE_TOUT) { *dest = (FPW) 0x00F000F0; /* reset bank */ res = 1; } @@ -729,7 +834,9 @@ void inline spin_wheel (void) int flash_real_protect (flash_info_t * info, long sector, int prot) { ulong start; - int i; + int i, j; + int curr_bank; + int bank; int rc = 0; FPWV *addr = (FPWV *) (info->start[sector]); int flag = disable_interrupts (); @@ -758,7 +865,7 @@ int flash_real_protect (flash_info_t * info, long sector, int prot) start = get_timer (0); while ((*addr & INTEL_FINISHED) != INTEL_FINISHED) { - if (get_timer (start) > CFG_FLASH_UNLOCK_TOUT) { + if (get_timer (start) > CONFIG_SYS_FLASH_UNLOCK_TOUT) { printf ("Flash lock bit operation timed out\n"); rc = 1; break; @@ -779,23 +886,54 @@ int flash_real_protect (flash_info_t * info, long sector, int prot) * we have to restore lock bits of protected sectors. */ if (!prot) { - for (i = 0; i < info->sector_count; i++) { - if (info->protect[i]) { - start = get_timer (0); - addr = (FPWV *) (info->start[i]); - *addr = INTEL_LOCKBIT; /* Sector lock bit */ - *addr = INTEL_PROTECT; /* set */ - while ((*addr & INTEL_FINISHED) != - INTEL_FINISHED) { - if (get_timer (start) > - CFG_FLASH_UNLOCK_TOUT) { - printf ("Flash lock bit operation timed out\n"); - rc = 1; - break; + /* + * re-locking must be done for all banks that belong on one + * FLASH chip, as all the sectors on the chip were unlocked + * by INTEL_LOCKBIT/INTEL_CONFIRM commands. (let's hope + * that banks never span chips, in particular chips which + * support h/w protection differently). + */ + + /* find the current bank number */ + curr_bank = CONFIG_SYS_MAX_FLASH_BANKS + 1; + for (j = 0; j < CONFIG_SYS_MAX_FLASH_BANKS; ++j) { + if (&flash_info[j] == info) { + curr_bank = j; + } + } + if (curr_bank == CONFIG_SYS_MAX_FLASH_BANKS + 1) { + printf("Error: can't determine bank number!\n"); + } + + for (bank = 0; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank) { + if (!same_chip_banks(curr_bank, bank)) { + continue; + } + info = &flash_info[bank]; + for (i = 0; i < info->sector_count; i++) { + if (info->protect[i]) { + start = get_timer (0); + addr = (FPWV *) (info->start[i]); + *addr = INTEL_LOCKBIT; /* Sector lock bit */ + *addr = INTEL_PROTECT; /* set */ + while ((*addr & INTEL_FINISHED) != + INTEL_FINISHED) { + if (get_timer (start) > + CONFIG_SYS_FLASH_UNLOCK_TOUT) { + printf ("Flash lock bit operation timed out\n"); + rc = 1; + break; + } } } } } + + /* + * get the s/w sector protection status in sync with the h/w, + * in case something went wrong during the re-locking. + */ + flash_sync_real_protect(info); /* resets flash to read mode */ } if (flag)