mirror of
https://github.com/Stichting-MINIX-Research-Foundation/u-boot.git
synced 2025-09-14 06:26:13 -04:00
Implement h/w sector protection status synchronization at boot.
The code is provided for, and was tested on, the Yukon/Alaska and PM520 boards only. A bug in flash_real_protect() for the Yukon board was fixed by adding a function that tells if two banks are on one flash chip.
This commit is contained in:
parent
15f36a5efd
commit
010162eb72
@ -64,7 +64,6 @@ typedef volatile unsigned char FLASH_PORT_WIDTHV;
|
|||||||
#define FLASH_CYCLE2 0x02aa
|
#define FLASH_CYCLE2 0x02aa
|
||||||
|
|
||||||
#define WR_BLOCK 0x20
|
#define WR_BLOCK 0x20
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------
|
/*-----------------------------------------------------------------------
|
||||||
* Functions
|
* 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 int write_word_amd (flash_info_t * info, FPWV * dest, FPW data);
|
||||||
static void flash_get_offsets (ulong base, flash_info_t * info);
|
static void flash_get_offsets (ulong base, flash_info_t * info);
|
||||||
void inline spin_wheel (void);
|
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);
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------
|
/*-----------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -115,6 +117,9 @@ unsigned long flash_init (void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
size += flash_info[i].size;
|
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
|
/* Protect monitor and environment sectors
|
||||||
@ -167,7 +172,6 @@ static void flash_get_offsets (ulong base, flash_info_t * info)
|
|||||||
if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
|
if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
|
||||||
for (i = 0; i < info->sector_count; i++) {
|
for (i = 0; i < info->sector_count; i++) {
|
||||||
info->start[i] = base + (i * PHYS_INTEL_SECT_SIZE);
|
info->start[i] = base + (i * PHYS_INTEL_SECT_SIZE);
|
||||||
info->protect[i] = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -305,6 +309,98 @@ 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
|
||||||
|
* CFG_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) > CFG_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[CFG_MAX_FLASH_BANKS][CFG_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 flash_erase (flash_info_t * info, int s_first, int s_last)
|
||||||
@ -729,7 +825,9 @@ void inline spin_wheel (void)
|
|||||||
int flash_real_protect (flash_info_t * info, long sector, int prot)
|
int flash_real_protect (flash_info_t * info, long sector, int prot)
|
||||||
{
|
{
|
||||||
ulong start;
|
ulong start;
|
||||||
int i;
|
int i, j;
|
||||||
|
int curr_bank;
|
||||||
|
int bank;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
FPWV *addr = (FPWV *) (info->start[sector]);
|
FPWV *addr = (FPWV *) (info->start[sector]);
|
||||||
int flag = disable_interrupts ();
|
int flag = disable_interrupts ();
|
||||||
@ -779,23 +877,54 @@ int flash_real_protect (flash_info_t * info, long sector, int prot)
|
|||||||
* we have to restore lock bits of protected sectors.
|
* we have to restore lock bits of protected sectors.
|
||||||
*/
|
*/
|
||||||
if (!prot) {
|
if (!prot) {
|
||||||
for (i = 0; i < info->sector_count; i++) {
|
/*
|
||||||
if (info->protect[i]) {
|
* re-locking must be done for all banks that belong on one
|
||||||
start = get_timer (0);
|
* FLASH chip, as all the sectors on the chip were unlocked
|
||||||
addr = (FPWV *) (info->start[i]);
|
* by INTEL_LOCKBIT/INTEL_CONFIRM commands. (let's hope
|
||||||
*addr = INTEL_LOCKBIT; /* Sector lock bit */
|
* that banks never span chips, in particular chips which
|
||||||
*addr = INTEL_PROTECT; /* set */
|
* support h/w protection differently).
|
||||||
while ((*addr & INTEL_FINISHED) !=
|
*/
|
||||||
INTEL_FINISHED) {
|
|
||||||
if (get_timer (start) >
|
/* find the current bank number */
|
||||||
CFG_FLASH_UNLOCK_TOUT) {
|
curr_bank = CFG_MAX_FLASH_BANKS + 1;
|
||||||
printf ("Flash lock bit operation timed out\n");
|
for (j = 0; j < CFG_MAX_FLASH_BANKS; ++j) {
|
||||||
rc = 1;
|
if (&flash_info[j] == info) {
|
||||||
break;
|
curr_bank = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (curr_bank == CFG_MAX_FLASH_BANKS + 1) {
|
||||||
|
printf("Error: can't determine bank number!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (bank = 0; bank < CFG_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) >
|
||||||
|
CFG_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)
|
if (flag)
|
||||||
|
@ -75,6 +75,8 @@ static ulong flash_get_size (FPW *addr, flash_info_t *info);
|
|||||||
static int write_data (flash_info_t *info, ulong dest, FPW data);
|
static int write_data (flash_info_t *info, ulong dest, FPW data);
|
||||||
static void flash_get_offsets (ulong base, flash_info_t *info);
|
static void flash_get_offsets (ulong base, flash_info_t *info);
|
||||||
void inline spin_wheel (void);
|
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);
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------
|
/*-----------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -101,6 +103,9 @@ unsigned long flash_init (void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
size += flash_info[i].size;
|
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
|
/* Protect monitor and environment sectors
|
||||||
@ -138,7 +143,6 @@ static void flash_get_offsets (ulong base, flash_info_t *info)
|
|||||||
if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
|
if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) {
|
||||||
for (i = 0; i < info->sector_count; i++) {
|
for (i = 0; i < info->sector_count; i++) {
|
||||||
info->start[i] = base + (i * PHYS_FLASH_SECT_SIZE);
|
info->start[i] = base + (i * PHYS_FLASH_SECT_SIZE);
|
||||||
info->protect[i] = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -270,6 +274,85 @@ 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:
|
||||||
|
case FLASH_28F640J3A:
|
||||||
|
case FLASH_28F320J3A:
|
||||||
|
for (i = 0; i < info->sector_count; ++i) {
|
||||||
|
info->protect[i] = intel_sector_protected(info, i);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
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
|
||||||
|
* CFG_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) > CFG_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 2 for 16 bit flash */
|
||||||
|
lock_conf_addr = (FPWV *) info->start[sector] + 2;
|
||||||
|
ret = (*lock_conf_addr & (FPW) INTEL_PROTECT) ? 1 : 0;
|
||||||
|
|
||||||
|
/* put flash back in read mode */
|
||||||
|
*addr = (FPW) INTEL_RESET;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------
|
/*-----------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -491,7 +574,7 @@ void inline spin_wheel (void)
|
|||||||
* 0 - OK
|
* 0 - OK
|
||||||
* 1 - Error (timeout, voltage problems, etc.)
|
* 1 - Error (timeout, voltage problems, etc.)
|
||||||
*/
|
*/
|
||||||
int flash_real_protect(flash_info_t *info, long sector, int prot)
|
int flash_real_protect (flash_info_t *info, long sector, int prot)
|
||||||
{
|
{
|
||||||
ulong start;
|
ulong start;
|
||||||
int i;
|
int i;
|
||||||
@ -531,6 +614,11 @@ int flash_real_protect(flash_info_t *info, long sector, int prot)
|
|||||||
/*
|
/*
|
||||||
* Clear lock bit command clears all sectors lock bits, so
|
* Clear lock bit command clears all sectors lock bits, so
|
||||||
* we have to restore lock bits of protected sectors.
|
* we have to restore lock bits of protected sectors.
|
||||||
|
* WARNING: code below re-locks sectors only for one bank (info).
|
||||||
|
* This causes problems on boards where several banks share
|
||||||
|
* the same chip, as sectors in othere banks will be unlocked
|
||||||
|
* but not re-locked. It works fine on pm520 though, as there
|
||||||
|
* is only one chip and one bank.
|
||||||
*/
|
*/
|
||||||
if (!prot)
|
if (!prot)
|
||||||
{
|
{
|
||||||
@ -553,6 +641,11 @@ int flash_real_protect(flash_info_t *info, long sector, int prot)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* 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)
|
if (flag)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user