diff options
| author | Wolfgang Denk <wd@pollux.(none)> | 2005-07-30 16:39:27 +0200 | 
|---|---|---|
| committer | Wolfgang Denk <wd@pollux.(none)> | 2005-07-30 16:39:27 +0200 | 
| commit | 010162eb729e9ed8233e902313c5f770b89e9202 (patch) | |
| tree | b03a605aa6833fb96e2dbc7277a01a9518981e8b /board/pm520/flash.c | |
| parent | 15f36a5efd31fe608b43dc197ebbd80d3cecbe44 (diff) | |
| download | olio-uboot-2014.01-010162eb729e9ed8233e902313c5f770b89e9202.tar.xz olio-uboot-2014.01-010162eb729e9ed8233e902313c5f770b89e9202.zip | |
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.
Diffstat (limited to 'board/pm520/flash.c')
| -rw-r--r-- | board/pm520/flash.c | 97 | 
1 files changed, 95 insertions, 2 deletions
| diff --git a/board/pm520/flash.c b/board/pm520/flash.c index 572cc9bbe..62700f9f9 100644 --- a/board/pm520/flash.c +++ b/board/pm520/flash.c @@ -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 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);  /*-----------------------------------------------------------------------   */ @@ -101,6 +103,9 @@ 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 @@ -138,7 +143,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_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   * 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;  	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  	 * 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)  	{ @@ -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) |