diff options
Diffstat (limited to 'drivers/mtd/cfi_flash.c')
| -rw-r--r-- | drivers/mtd/cfi_flash.c | 1905 | 
1 files changed, 1121 insertions, 784 deletions
diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c index 5579a1efc..f370e4fbd 100644 --- a/drivers/mtd/cfi_flash.c +++ b/drivers/mtd/cfi_flash.c @@ -42,9 +42,12 @@  #ifdef	CFG_FLASH_CFI_DRIVER  /* - * This file implements a Common Flash Interface (CFI) driver for U-Boot. - * The width of the port and the width of the chips are determined at initialization. - * These widths are used to calculate the address for access CFI data structures. + * This file implements a Common Flash Interface (CFI) driver for + * U-Boot. + * + * The width of the port and the width of the chips are determined at + * initialization.  These widths are used to calculate the address for + * access CFI data structures.   *   * References   * JEDEC Standard JESD68 - Common Flash Interface (CFI) @@ -55,7 +58,7 @@   * AMD/Spansion Application Note: Migration from Single-byte to Three-byte   *   Device IDs, Publication Number 25538 Revision A, November 8, 2001   * - * define CFG_WRITE_SWAPPED_DATA, if you have to swap the Bytes between + * Define CFG_WRITE_SWAPPED_DATA, if you have to swap the Bytes between   * reading and writing ... (yes there is such a Hardware).   */ @@ -98,10 +101,6 @@  #define AMD_STATUS_TOGGLE		0x40  #define AMD_STATUS_ERROR		0x20 -#define AMD_ADDR_ERASE_START	((info->portwidth == FLASH_CFI_8BIT) ? 0xAAA : 0x555) -#define AMD_ADDR_START		((info->portwidth == FLASH_CFI_8BIT) ? 0xAAA : 0x555) -#define AMD_ADDR_ACK		((info->portwidth == FLASH_CFI_8BIT) ? 0x555 : 0x2AA) -  #define FLASH_OFFSET_MANUFACTURER_ID	0x00  #define FLASH_OFFSET_DEVICE_ID		0x01  #define FLASH_OFFSET_DEVICE_ID2		0x0E @@ -110,7 +109,8 @@  #define FLASH_OFFSET_CFI_ALT		0x555  #define FLASH_OFFSET_CFI_RESP		0x10  #define FLASH_OFFSET_PRIMARY_VENDOR	0x13 -#define FLASH_OFFSET_EXT_QUERY_T_P_ADDR	0x15	/* extended query table primary addr */ +/* extended query table primary address */ +#define FLASH_OFFSET_EXT_QUERY_T_P_ADDR	0x15  #define FLASH_OFFSET_WTOUT		0x1F  #define FLASH_OFFSET_WBTOUT		0x20  #define FLASH_OFFSET_ETOUT		0x21 @@ -149,16 +149,9 @@ typedef union {  	unsigned long long ll;  } cfiword_t; -typedef union { -	volatile unsigned char *cp; -	volatile unsigned short *wp; -	volatile unsigned long *lp; -	volatile unsigned long long *llp; -} cfiptr_t; -  #define NUM_ERASE_REGIONS	4 /* max. number of erase regions */ -static uint flash_offset_cfi[2]={FLASH_OFFSET_CFI,FLASH_OFFSET_CFI_ALT}; +static uint flash_offset_cfi[2] = { FLASH_OFFSET_CFI, FLASH_OFFSET_CFI_ALT };  /* use CFG_MAX_FLASH_BANKS_DETECT if defined */  #ifdef CFG_MAX_FLASH_BANKS_DETECT @@ -176,46 +169,151 @@ flash_info_t flash_info[CFG_MAX_FLASH_BANKS];		/* FLASH chips info */  #define CFG_FLASH_CFI_WIDTH	FLASH_CFI_8BIT  #endif +typedef unsigned long flash_sect_t; + +/* CFI standard query structure */ +struct cfi_qry { +	u8	qry[3]; +	u16	p_id; +	u16	p_adr; +	u16	a_id; +	u16	a_adr; +	u8	vcc_min; +	u8	vcc_max; +	u8	vpp_min; +	u8	vpp_max; +	u8	word_write_timeout_typ; +	u8	buf_write_timeout_typ; +	u8	block_erase_timeout_typ; +	u8	chip_erase_timeout_typ; +	u8	word_write_timeout_max; +	u8	buf_write_timeout_max; +	u8	block_erase_timeout_max; +	u8	chip_erase_timeout_max; +	u8	dev_size; +	u16	interface_desc; +	u16	max_buf_write_size; +	u8	num_erase_regions; +	u32	erase_region_info[NUM_ERASE_REGIONS]; +} __attribute__((packed)); + +struct cfi_pri_hdr { +	u8	pri[3]; +	u8	major_version; +	u8	minor_version; +} __attribute__((packed)); + +static void flash_write8(u8 value, void *addr) +{ +	__raw_writeb(value, addr); +} + +static void flash_write16(u16 value, void *addr) +{ +	__raw_writew(value, addr); +} + +static void flash_write32(u32 value, void *addr) +{ +	__raw_writel(value, addr); +} + +static void flash_write64(u64 value, void *addr) +{ +	/* No architectures currently implement __raw_writeq() */ +	*(volatile u64 *)addr = value; +} + +static u8 flash_read8(void *addr) +{ +	return __raw_readb(addr); +} + +static u16 flash_read16(void *addr) +{ +	return __raw_readw(addr); +} + +static u32 flash_read32(void *addr) +{ +	return __raw_readl(addr); +} + +static u64 flash_read64(void *addr) +{ +	/* No architectures currently implement __raw_readq() */ +	return *(volatile u64 *)addr; +}  /*----------------------------------------------------------------------- - * Functions   */ +#if defined(CFG_ENV_IS_IN_FLASH) || defined(CFG_ENV_ADDR_REDUND) || (CFG_MONITOR_BASE >= CFG_FLASH_BASE) +static flash_info_t *flash_get_info(ulong base) +{ +	int i; +	flash_info_t * info = 0; -typedef unsigned long flash_sect_t; +	for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) { +		info = & flash_info[i]; +		if (info->size && info->start[0] <= base && +		    base <= info->start[0] + info->size - 1) +			break; +	} -static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c); -static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf); -static void flash_write_cmd (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd); -static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect); -static int flash_isequal (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd); -static int flash_isset (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd); -static int flash_toggle (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd); -static void flash_read_jedec_ids (flash_info_t * info); -static int flash_detect_cfi (flash_info_t * info); -static int flash_write_cfiword (flash_info_t * info, ulong dest, cfiword_t cword); -static int flash_full_status_check (flash_info_t * info, flash_sect_t sector, -				    ulong tout, char *prompt); -ulong flash_get_size (ulong base, int banknum); -#if defined(CFG_ENV_IS_IN_FLASH) || defined(CFG_ENV_ADDR_REDUND) || (CFG_MONITOR_BASE >= CFG_FLASH_BASE) -static flash_info_t *flash_get_info(ulong base); -#endif -#ifdef CFG_FLASH_USE_BUFFER_WRITE -static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, int len); +	return i == CFG_MAX_FLASH_BANKS ? 0 : info; +}  #endif +unsigned long flash_sector_size(flash_info_t *info, flash_sect_t sect) +{ +	if (sect != (info->sector_count - 1)) +		return info->start[sect + 1] - info->start[sect]; +	else +		return info->start[0] + info->size - info->start[sect]; +} +  /*-----------------------------------------------------------------------   * create an address based on the offset and the port width   */ -inline uchar *flash_make_addr (flash_info_t * info, flash_sect_t sect, uint offset) +static inline void * +flash_map (flash_info_t * info, flash_sect_t sect, uint offset)  { -	return ((uchar *) (info->start[sect] + (offset * info->portwidth))); +	unsigned int byte_offset = offset * info->portwidth; + +	return map_physmem(info->start[sect] + byte_offset, +			flash_sector_size(info, sect) - byte_offset, +			MAP_NOCACHE); +} + +static inline void flash_unmap(flash_info_t *info, flash_sect_t sect, +		unsigned int offset, void *addr) +{ +	unsigned int byte_offset = offset * info->portwidth; + +	unmap_physmem(addr, flash_sector_size(info, sect) - byte_offset); +} + +/*----------------------------------------------------------------------- + * make a proper sized command based on the port and chip widths + */ +static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf) +{ +	int i; +	uchar *cp = (uchar *) cmdbuf; + +#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA) +	for (i = info->portwidth; i > 0; i--) +#else +	for (i = 1; i <= info->portwidth; i++) +#endif +		*cp++ = (i & (info->chipwidth - 1)) ? '\0' : cmd;  }  #ifdef DEBUG  /*-----------------------------------------------------------------------   * Debug support   */ -void print_longlong (char *str, unsigned long long data) +static void print_longlong (char *str, unsigned long long data)  {  	int i;  	char *cp; @@ -224,28 +322,25 @@ void print_longlong (char *str, unsigned long long data)  	for (i = 0; i < 8; i++)  		sprintf (&str[i * 2], "%2.2x", *cp++);  } -static void flash_printqry (flash_info_t * info, flash_sect_t sect) + +static void flash_printqry (struct cfi_qry *qry)  { -	cfiptr_t cptr; +	u8 *p = (u8 *)qry;  	int x, y; -	for (x = 0; x < 0x40; x += 16U / info->portwidth) { -		cptr.cp = -			flash_make_addr (info, sect, -					 x + FLASH_OFFSET_CFI_RESP); -		debug ("%p : ", cptr.cp); +	for (x = 0; x < sizeof(struct cfi_qry); x += 16) { +		debug("%02x : ", x); +		for (y = 0; y < 16; y++) +			debug("%2.2x ", p[x + y]); +		debug(" ");  		for (y = 0; y < 16; y++) { -			debug ("%2.2x ", cptr.cp[y]); -		} -		debug (" "); -		for (y = 0; y < 16; y++) { -			if (cptr.cp[y] >= 0x20 && cptr.cp[y] <= 0x7e) { -				debug ("%c", cptr.cp[y]); -			} else { -				debug ("."); -			} +			unsigned char c = p[x + y]; +			if (c >= 0x20 && c <= 0x7e) +				debug("%c", c); +			else +				debug(".");  		} -		debug ("\n"); +		debug("\n");  	}  }  #endif @@ -254,192 +349,608 @@ static void flash_printqry (flash_info_t * info, flash_sect_t sect)  /*-----------------------------------------------------------------------   * read a character at a port width address   */ -inline uchar flash_read_uchar (flash_info_t * info, uint offset) +static inline uchar flash_read_uchar (flash_info_t * info, uint offset)  {  	uchar *cp; +	uchar retval; -	cp = flash_make_addr (info, 0, offset); +	cp = flash_map (info, 0, offset);  #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA) -	return (cp[0]); +	retval = flash_read8(cp);  #else -	return (cp[info->portwidth - 1]); +	retval = flash_read8(cp + info->portwidth - 1);  #endif +	flash_unmap (info, 0, offset, cp); +	return retval;  }  /*----------------------------------------------------------------------- - * read a short word by swapping for ppc format. + * read a long word by picking the least significant byte of each maximum + * port size word. Swap for ppc format.   */ -ushort flash_read_ushort (flash_info_t * info, flash_sect_t sect, uint offset) +static ulong flash_read_long (flash_info_t * info, flash_sect_t sect, +			      uint offset)  {  	uchar *addr; -	ushort retval; +	ulong retval;  #ifdef DEBUG  	int x;  #endif -	addr = flash_make_addr (info, sect, offset); +	addr = flash_map (info, sect, offset);  #ifdef DEBUG -	debug ("ushort addr is at %p info->portwidth = %d\n", addr, +	debug ("long addr is at %p info->portwidth = %d\n", addr,  	       info->portwidth); -	for (x = 0; x < 2 * info->portwidth; x++) { -		debug ("addr[%x] = 0x%x\n", x, addr[x]); +	for (x = 0; x < 4 * info->portwidth; x++) { +		debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x));  	}  #endif  #if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA) -	retval = ((addr[(info->portwidth)] << 8) | addr[0]); +	retval = ((flash_read8(addr) << 16) | +		  (flash_read8(addr + info->portwidth) << 24) | +		  (flash_read8(addr + 2 * info->portwidth)) | +		  (flash_read8(addr + 3 * info->portwidth) << 8));  #else -	retval = ((addr[(2 * info->portwidth) - 1] << 8) | -		  addr[info->portwidth - 1]); +	retval = ((flash_read8(addr + 2 * info->portwidth - 1) << 24) | +		  (flash_read8(addr + info->portwidth - 1) << 16) | +		  (flash_read8(addr + 4 * info->portwidth - 1) << 8) | +		  (flash_read8(addr + 3 * info->portwidth - 1)));  #endif +	flash_unmap(info, sect, offset, addr); -	debug ("retval = 0x%x\n", retval);  	return retval;  } -/*----------------------------------------------------------------------- - * read a long word by picking the least significant byte of each maximum - * port size word. Swap for ppc format. +/* + * Write a proper sized command to the correct address   */ -ulong flash_read_long (flash_info_t * info, flash_sect_t sect, uint offset) +static void flash_write_cmd (flash_info_t * info, flash_sect_t sect, +			     uint offset, uchar cmd)  { -	uchar *addr; -	ulong retval; +	void *addr; +	cfiword_t cword; + +	addr = flash_map (info, sect, offset); +	flash_make_cmd (info, cmd, &cword); +	switch (info->portwidth) { +	case FLASH_CFI_8BIT: +		debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd, +		       cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH); +		flash_write8(cword.c, addr); +		break; +	case FLASH_CFI_16BIT: +		debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr, +		       cmd, cword.w, +		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH); +		flash_write16(cword.w, addr); +		break; +	case FLASH_CFI_32BIT: +		debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr, +		       cmd, cword.l, +		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH); +		flash_write32(cword.l, addr); +		break; +	case FLASH_CFI_64BIT:  #ifdef DEBUG -	int x; +		{ +			char str[20]; + +			print_longlong (str, cword.ll); + +			debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n", +			       addr, cmd, str, +			       info->chipwidth << CFI_FLASH_SHIFT_WIDTH); +		}  #endif -	addr = flash_make_addr (info, sect, offset); +		flash_write64(cword.ll, addr); +		break; +	} + +	/* Ensure all the instructions are fully finished */ +	sync(); +	flash_unmap(info, sect, offset, addr); +} + +static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect) +{ +	flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_UNLOCK_START); +	flash_write_cmd (info, sect, info->addr_unlock2, AMD_CMD_UNLOCK_ACK); +} + +/*----------------------------------------------------------------------- + */ +static int flash_isequal (flash_info_t * info, flash_sect_t sect, +			  uint offset, uchar cmd) +{ +	void *addr; +	cfiword_t cword; +	int retval; + +	addr = flash_map (info, sect, offset); +	flash_make_cmd (info, cmd, &cword); + +	debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr); +	switch (info->portwidth) { +	case FLASH_CFI_8BIT: +		debug ("is= %x %x\n", flash_read8(addr), cword.c); +		retval = (flash_read8(addr) == cword.c); +		break; +	case FLASH_CFI_16BIT: +		debug ("is= %4.4x %4.4x\n", flash_read16(addr), cword.w); +		retval = (flash_read16(addr) == cword.w); +		break; +	case FLASH_CFI_32BIT: +		debug ("is= %8.8lx %8.8lx\n", flash_read32(addr), cword.l); +		retval = (flash_read32(addr) == cword.l); +		break; +	case FLASH_CFI_64BIT:  #ifdef DEBUG -	debug ("long addr is at %p info->portwidth = %d\n", addr, -	       info->portwidth); -	for (x = 0; x < 4 * info->portwidth; x++) { -		debug ("addr[%x] = 0x%x\n", x, addr[x]); -	} -#endif -#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA) -	retval = (addr[0] << 16) | (addr[(info->portwidth)] << 24) | -		(addr[(2 * info->portwidth)]) | (addr[(3 * info->portwidth)] << 8); -#else -	retval = (addr[(2 * info->portwidth) - 1] << 24) | -		(addr[(info->portwidth) - 1] << 16) | -		(addr[(4 * info->portwidth) - 1] << 8) | -		addr[(3 * info->portwidth) - 1]; +		{ +			char str1[20]; +			char str2[20]; + +			print_longlong (str1, flash_read64(addr)); +			print_longlong (str2, cword.ll); +			debug ("is= %s %s\n", str1, str2); +		}  #endif +		retval = (flash_read64(addr) == cword.ll); +		break; +	default: +		retval = 0; +		break; +	} +	flash_unmap(info, sect, offset, addr); +  	return retval;  } +/*----------------------------------------------------------------------- + */ +static int flash_isset (flash_info_t * info, flash_sect_t sect, +			uint offset, uchar cmd) +{ +	void *addr; +	cfiword_t cword; +	int retval; + +	addr = flash_map (info, sect, offset); +	flash_make_cmd (info, cmd, &cword); +	switch (info->portwidth) { +	case FLASH_CFI_8BIT: +		retval = ((flash_read8(addr) & cword.c) == cword.c); +		break; +	case FLASH_CFI_16BIT: +		retval = ((flash_read16(addr) & cword.w) == cword.w); +		break; +	case FLASH_CFI_32BIT: +		retval = ((flash_read16(addr) & cword.l) == cword.l); +		break; +	case FLASH_CFI_64BIT: +		retval = ((flash_read64(addr) & cword.ll) == cword.ll); +		break; +	default: +		retval = 0; +		break; +	} +	flash_unmap(info, sect, offset, addr); + +	return retval; +}  /*-----------------------------------------------------------------------   */ -unsigned long flash_init (void) +static int flash_toggle (flash_info_t * info, flash_sect_t sect, +			 uint offset, uchar cmd)  { -	unsigned long size = 0; -	int i; +	void *addr; +	cfiword_t cword; +	int retval; -#ifdef CFG_FLASH_PROTECTION -	char *s = getenv("unlock"); +	addr = flash_map (info, sect, offset); +	flash_make_cmd (info, cmd, &cword); +	switch (info->portwidth) { +	case FLASH_CFI_8BIT: +		retval = ((flash_read8(addr) & cword.c) != +			  (flash_read8(addr) & cword.c)); +		break; +	case FLASH_CFI_16BIT: +		retval = ((flash_read16(addr) & cword.w) != +			  (flash_read16(addr) & cword.w)); +		break; +	case FLASH_CFI_32BIT: +		retval = ((flash_read32(addr) & cword.l) != +			  (flash_read32(addr) & cword.l)); +		break; +	case FLASH_CFI_64BIT: +		retval = ((flash_read64(addr) & cword.ll) != +			  (flash_read64(addr) & cword.ll)); +		break; +	default: +		retval = 0; +		break; +	} +	flash_unmap(info, sect, offset, addr); + +	return retval; +} + +/* + * flash_is_busy - check to see if the flash is busy + * + * This routine checks the status of the chip and returns true if the + * chip is busy. + */ +static int flash_is_busy (flash_info_t * info, flash_sect_t sect) +{ +	int retval; + +	switch (info->vendor) { +	case CFI_CMDSET_INTEL_STANDARD: +	case CFI_CMDSET_INTEL_EXTENDED: +		retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE); +		break; +	case CFI_CMDSET_AMD_STANDARD: +	case CFI_CMDSET_AMD_EXTENDED: +#ifdef CONFIG_FLASH_CFI_LEGACY +	case CFI_CMDSET_AMD_LEGACY:  #endif +		retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE); +		break; +	default: +		retval = 0; +	} +	debug ("flash_is_busy: %d\n", retval); +	return retval; +} -	/* Init: no FLASHes known */ -	for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) { -		flash_info[i].flash_id = FLASH_UNKNOWN; -		size += flash_info[i].size = flash_get_size (bank_base[i], i); -		if (flash_info[i].flash_id == FLASH_UNKNOWN) { -#ifndef CFG_FLASH_QUIET_TEST -			printf ("## Unknown FLASH on Bank %d - Size = 0x%08lx = %ld MB\n", -				i+1, flash_info[i].size, flash_info[i].size << 20); -#endif /* CFG_FLASH_QUIET_TEST */ -		} -#ifdef CFG_FLASH_PROTECTION -		else if ((s != NULL) && (strcmp(s, "yes") == 0)) { -			/* -			 * Only the U-Boot image and it's environment is protected, -			 * all other sectors are unprotected (unlocked) if flash -			 * hardware protection is used (CFG_FLASH_PROTECTION) and -			 * the environment variable "unlock" is set to "yes". -			 */ -			if (flash_info[i].legacy_unlock) { -				int k; +/*----------------------------------------------------------------------- + *  wait for XSR.7 to be set. Time out with an error if it does not. + *  This routine does not set the flash to read-array mode. + */ +static int flash_status_check (flash_info_t * info, flash_sect_t sector, +			       ulong tout, char *prompt) +{ +	ulong start; -				/* -				 * Disable legacy_unlock temporarily, since -				 * flash_real_protect would relock all other sectors -				 * again otherwise. -				 */ -				flash_info[i].legacy_unlock = 0; +#if CFG_HZ != 1000 +	tout *= CFG_HZ/1000; +#endif -				/* -				 * Legacy unlocking (e.g. Intel J3) -> unlock only one -				 * sector. This will unlock all sectors. -				 */ -				flash_real_protect (&flash_info[i], 0, 0); +	/* Wait for command completion */ +	start = get_timer (0); +	while (flash_is_busy (info, sector)) { +		if (get_timer (start) > tout) { +			printf ("Flash %s timeout at address %lx data %lx\n", +				prompt, info->start[sector], +				flash_read_long (info, sector, 0)); +			flash_write_cmd (info, sector, 0, info->cmd_reset); +			return ERR_TIMOUT; +		} +		udelay (1);		/* also triggers watchdog */ +	} +	return ERR_OK; +} -				flash_info[i].legacy_unlock = 1; +/*----------------------------------------------------------------------- + * Wait for XSR.7 to be set, if it times out print an error, otherwise + * do a full status check. + * + * This routine sets the flash to read-array mode. + */ +static int flash_full_status_check (flash_info_t * info, flash_sect_t sector, +				    ulong tout, char *prompt) +{ +	int retcode; -				/* -				 * Manually mark other sectors as unlocked (unprotected) -				 */ -				for (k = 1; k < flash_info[i].sector_count; k++) -					flash_info[i].protect[k] = 0; -			} else { -				/* -				 * No legancy unlocking -> unlock all sectors -				 */ -				flash_protect (FLAG_PROTECT_CLEAR, -					       flash_info[i].start[0], -					       flash_info[i].start[0] + flash_info[i].size - 1, -					       &flash_info[i]); +	retcode = flash_status_check (info, sector, tout, prompt); +	switch (info->vendor) { +	case CFI_CMDSET_INTEL_EXTENDED: +	case CFI_CMDSET_INTEL_STANDARD: +		if ((retcode == ERR_OK) +		    && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) { +			retcode = ERR_INVAL; +			printf ("Flash %s error at address %lx\n", prompt, +				info->start[sector]); +			if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS | +					 FLASH_STATUS_PSLBS)) { +				puts ("Command Sequence Error.\n"); +			} else if (flash_isset (info, sector, 0, +						FLASH_STATUS_ECLBS)) { +				puts ("Block Erase Error.\n"); +				retcode = ERR_NOT_ERASED; +			} else if (flash_isset (info, sector, 0, +						FLASH_STATUS_PSLBS)) { +				puts ("Locking Error\n"); +			} +			if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) { +				puts ("Block locked.\n"); +				retcode = ERR_PROTECTED;  			} +			if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS)) +				puts ("Vpp Low Error.\n");  		} -#endif /* CFG_FLASH_PROTECTION */ +		flash_write_cmd (info, sector, 0, info->cmd_reset); +		break; +	default: +		break;  	} +	return retcode; +} -	/* Monitor protection ON by default */ -#if (CFG_MONITOR_BASE >= CFG_FLASH_BASE) -	flash_protect (FLAG_PROTECT_SET, -		       CFG_MONITOR_BASE, -		       CFG_MONITOR_BASE + monitor_flash_len  - 1, -		       flash_get_info(CFG_MONITOR_BASE)); +/*----------------------------------------------------------------------- + */ +static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c) +{ +#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) +	unsigned short	w; +	unsigned int	l; +	unsigned long long ll;  #endif -	/* Environment protection ON by default */ -#ifdef CFG_ENV_IS_IN_FLASH -	flash_protect (FLAG_PROTECT_SET, -		       CFG_ENV_ADDR, -		       CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1, -		       flash_get_info(CFG_ENV_ADDR)); +	switch (info->portwidth) { +	case FLASH_CFI_8BIT: +		cword->c = c; +		break; +	case FLASH_CFI_16BIT: +#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) +		w = c; +		w <<= 8; +		cword->w = (cword->w >> 8) | w; +#else +		cword->w = (cword->w << 8) | c;  #endif - -	/* Redundant environment protection ON by default */ -#ifdef CFG_ENV_ADDR_REDUND -	flash_protect (FLAG_PROTECT_SET, -		       CFG_ENV_ADDR_REDUND, -		       CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1, -		       flash_get_info(CFG_ENV_ADDR_REDUND)); +		break; +	case FLASH_CFI_32BIT: +#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) +		l = c; +		l <<= 24; +		cword->l = (cword->l >> 8) | l; +#else +		cword->l = (cword->l << 8) | c;  #endif -	return (size); +		break; +	case FLASH_CFI_64BIT: +#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) +		ll = c; +		ll <<= 56; +		cword->ll = (cword->ll >> 8) | ll; +#else +		cword->ll = (cword->ll << 8) | c; +#endif +		break; +	} +} + +/* loop through the sectors from the highest address when the passed + * address is greater or equal to the sector address we have a match + */ +static flash_sect_t find_sector (flash_info_t * info, ulong addr) +{ +	flash_sect_t sector; + +	for (sector = info->sector_count - 1; sector >= 0; sector--) { +		if (addr >= info->start[sector]) +			break; +	} +	return sector;  }  /*-----------------------------------------------------------------------   */ -#if defined(CFG_ENV_IS_IN_FLASH) || defined(CFG_ENV_ADDR_REDUND) || (CFG_MONITOR_BASE >= CFG_FLASH_BASE) -static flash_info_t *flash_get_info(ulong base) +static int flash_write_cfiword (flash_info_t * info, ulong dest, +				cfiword_t cword)  { -	int i; -	flash_info_t * info = 0; +	void *dstaddr; +	int flag; -	for (i = 0; i < CFG_MAX_FLASH_BANKS; i ++) { -		info = & flash_info[i]; -		if (info->size && info->start[0] <= base && -		    base <= info->start[0] + info->size - 1) +	dstaddr = map_physmem(dest, info->portwidth, MAP_NOCACHE); + +	/* Check if Flash is (sufficiently) erased */ +	switch (info->portwidth) { +	case FLASH_CFI_8BIT: +		flag = ((flash_read8(dstaddr) & cword.c) == cword.c); +		break; +	case FLASH_CFI_16BIT: +		flag = ((flash_read16(dstaddr) & cword.w) == cword.w); +		break; +	case FLASH_CFI_32BIT: +		flag = ((flash_read32(dstaddr) & cword.l) == cword.l); +		break; +	case FLASH_CFI_64BIT: +		flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll); +		break; +	default: +		flag = 0; +		break; +	} +	if (!flag) { +		unmap_physmem(dstaddr, info->portwidth); +		return 2; +	} + +	/* Disable interrupts which might cause a timeout here */ +	flag = disable_interrupts (); + +	switch (info->vendor) { +	case CFI_CMDSET_INTEL_EXTENDED: +	case CFI_CMDSET_INTEL_STANDARD: +		flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS); +		flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE); +		break; +	case CFI_CMDSET_AMD_EXTENDED: +	case CFI_CMDSET_AMD_STANDARD: +#ifdef CONFIG_FLASH_CFI_LEGACY +	case CFI_CMDSET_AMD_LEGACY: +#endif +		flash_unlock_seq (info, 0); +		flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_WRITE); +		break; +	} + +	switch (info->portwidth) { +	case FLASH_CFI_8BIT: +		flash_write8(cword.c, dstaddr); +		break; +	case FLASH_CFI_16BIT: +		flash_write16(cword.w, dstaddr); +		break; +	case FLASH_CFI_32BIT: +		flash_write32(cword.l, dstaddr); +		break; +	case FLASH_CFI_64BIT: +		flash_write64(cword.ll, dstaddr); +		break; +	} + +	/* re-enable interrupts if necessary */ +	if (flag) +		enable_interrupts (); + +	unmap_physmem(dstaddr, info->portwidth); + +	return flash_full_status_check (info, find_sector (info, dest), +					info->write_tout, "write"); +} + +#ifdef CFG_FLASH_USE_BUFFER_WRITE + +static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, +				  int len) +{ +	flash_sect_t sector; +	int cnt; +	int retcode; +	void *src = cp; +	void *dst = map_physmem(dest, len, MAP_NOCACHE); + +	sector = find_sector (info, dest); + +	switch (info->vendor) { +	case CFI_CMDSET_INTEL_STANDARD: +	case CFI_CMDSET_INTEL_EXTENDED: +		flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS); +		flash_write_cmd (info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER); +		retcode = flash_status_check (info, sector, +					      info->buffer_write_tout, +					      "write to buffer"); +		if (retcode == ERR_OK) { +			/* reduce the number of loops by the width of +			 * the port */ +			switch (info->portwidth) { +			case FLASH_CFI_8BIT: +				cnt = len; +				break; +			case FLASH_CFI_16BIT: +				cnt = len >> 1; +				break; +			case FLASH_CFI_32BIT: +				cnt = len >> 2; +				break; +			case FLASH_CFI_64BIT: +				cnt = len >> 3; +				break; +			default: +				retcode = ERR_INVAL; +				goto out_unmap; +			} +			flash_write_cmd (info, sector, 0, (uchar) cnt - 1); +			while (cnt-- > 0) { +				switch (info->portwidth) { +				case FLASH_CFI_8BIT: +					flash_write8(flash_read8(src), dst); +					src += 1, dst += 1; +					break; +				case FLASH_CFI_16BIT: +					flash_write16(flash_read16(src), dst); +					src += 2, dst += 2; +					break; +				case FLASH_CFI_32BIT: +					flash_write32(flash_read32(src), dst); +					src += 4, dst += 4; +					break; +				case FLASH_CFI_64BIT: +					flash_write64(flash_read64(src), dst); +					src += 8, dst += 8; +					break; +				default: +					retcode = ERR_INVAL; +					goto out_unmap; +				} +			} +			flash_write_cmd (info, sector, 0, +					 FLASH_CMD_WRITE_BUFFER_CONFIRM); +			retcode = flash_full_status_check ( +				info, sector, info->buffer_write_tout, +				"buffer write"); +		} + +		break; + +	case CFI_CMDSET_AMD_STANDARD: +	case CFI_CMDSET_AMD_EXTENDED: +		flash_unlock_seq(info,0); +		flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_TO_BUFFER); + +		switch (info->portwidth) { +		case FLASH_CFI_8BIT: +			cnt = len; +			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1); +			while (cnt-- > 0) { +				flash_write8(flash_read8(src), dst); +				src += 1, dst += 1; +			}  			break; +		case FLASH_CFI_16BIT: +			cnt = len >> 1; +			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1); +			while (cnt-- > 0) { +				flash_write16(flash_read16(src), dst); +				src += 2, dst += 2; +			} +			break; +		case FLASH_CFI_32BIT: +			cnt = len >> 2; +			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1); +			while (cnt-- > 0) { +				flash_write32(flash_read32(src), dst); +				src += 4, dst += 4; +			} +			break; +		case FLASH_CFI_64BIT: +			cnt = len >> 3; +			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1); +			while (cnt-- > 0) { +				flash_write64(flash_read64(src), dst); +				src += 8, dst += 8; +			} +			break; +		default: +			retcode = ERR_INVAL; +			goto out_unmap; +		} + +		flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM); +		retcode = flash_full_status_check (info, sector, +						   info->buffer_write_tout, +						   "buffer write"); +		break; + +	default: +		debug ("Unknown Command Set\n"); +		retcode = ERR_INVAL; +		break;  	} -	return i == CFG_MAX_FLASH_BANKS ? 0 : info; +out_unmap: +	unmap_physmem(dst, len); +	return retcode;  } -#endif +#endif /* CFG_FLASH_USE_BUFFER_WRITE */ +  /*-----------------------------------------------------------------------   */ @@ -465,7 +976,8 @@ int flash_erase (flash_info_t * info, int s_first, int s_last)  		}  	}  	if (prot) { -		printf ("- Warning: %d protected sectors will not be erased!\n", prot); +		printf ("- Warning: %d protected sectors will not be erased!\n", +			prot);  	} else {  		putc ('\n');  	} @@ -476,18 +988,33 @@ int flash_erase (flash_info_t * info, int s_first, int s_last)  			switch (info->vendor) {  			case CFI_CMDSET_INTEL_STANDARD:  			case CFI_CMDSET_INTEL_EXTENDED: -				flash_write_cmd (info, sect, 0, FLASH_CMD_CLEAR_STATUS); -				flash_write_cmd (info, sect, 0, FLASH_CMD_BLOCK_ERASE); -				flash_write_cmd (info, sect, 0, FLASH_CMD_ERASE_CONFIRM); +				flash_write_cmd (info, sect, 0, +						 FLASH_CMD_CLEAR_STATUS); +				flash_write_cmd (info, sect, 0, +						 FLASH_CMD_BLOCK_ERASE); +				flash_write_cmd (info, sect, 0, +						 FLASH_CMD_ERASE_CONFIRM);  				break;  			case CFI_CMDSET_AMD_STANDARD:  			case CFI_CMDSET_AMD_EXTENDED:  				flash_unlock_seq (info, sect); -				flash_write_cmd (info, sect, AMD_ADDR_ERASE_START, -							AMD_CMD_ERASE_START); +				flash_write_cmd (info, sect, +						info->addr_unlock1, +						AMD_CMD_ERASE_START);  				flash_unlock_seq (info, sect); -				flash_write_cmd (info, sect, 0, AMD_CMD_ERASE_SECTOR); +				flash_write_cmd (info, sect, 0, +						 AMD_CMD_ERASE_SECTOR); +				break; +#ifdef CONFIG_FLASH_CFI_LEGACY +			case CFI_CMDSET_AMD_LEGACY: +				flash_unlock_seq (info, 0); +				flash_write_cmd (info, 0, info->addr_unlock1, +						AMD_CMD_ERASE_START); +				flash_unlock_seq (info, 0); +				flash_write_cmd (info, sect, 0, +						AMD_CMD_ERASE_SECTOR);  				break; +#endif  			default:  				debug ("Unkown flash vendor %d\n",  				       info->vendor); @@ -516,10 +1043,15 @@ void flash_print_info (flash_info_t * info)  		return;  	} -	printf ("CFI conformant FLASH (%d x %d)", +	printf ("%s FLASH (%d x %d)", +		info->name,  		(info->portwidth << 3), (info->chipwidth << 3)); -	printf ("  Size: %ld MB in %d Sectors\n", -		info->size >> 20, info->sector_count); +	if (info->size < 1024*1024) +		printf ("  Size: %ld kB in %d Sectors\n", +			info->size >> 10, info->sector_count); +	else +		printf ("  Size: %ld MB in %d Sectors\n", +			info->size >> 20, info->sector_count);  	printf ("  ");  	switch (info->vendor) {  		case CFI_CMDSET_INTEL_STANDARD: @@ -534,6 +1066,11 @@ void flash_print_info (flash_info_t * info)  		case CFI_CMDSET_AMD_EXTENDED:  			printf ("AMD Extended");  			break; +#ifdef CONFIG_FLASH_CFI_LEGACY +		case CFI_CMDSET_AMD_LEGACY: +			printf ("AMD Legacy"); +			break; +#endif  		default:  			printf ("Unknown (%d)", info->vendor);  			break; @@ -547,7 +1084,8 @@ void flash_print_info (flash_info_t * info)  		info->erase_blk_tout,  		info->write_tout);  	if (info->buffer_size > 1) { -		printf ("  Buffer write timeout: %ld ms, buffer size: %d bytes\n", +		printf ("  Buffer write timeout: %ld ms, " +			"buffer size: %d bytes\n",  		info->buffer_write_tout,  		info->buffer_size);  	} @@ -565,10 +1103,7 @@ void flash_print_info (flash_info_t * info)  		/*  		 * Check if whole sector is erased  		 */ -		if (i != (info->sector_count - 1)) -			size = info->start[i + 1] - info->start[i]; -		else -			size = info->start[0] + info->size - info->start[i]; +		size = flash_sector_size(info, i);  		erased = 1;  		flash = (volatile unsigned long *) info->start[i];  		size = size >> 2;	/* divide by 4 for longword access */ @@ -603,7 +1138,7 @@ void flash_print_info (flash_info_t * info)  int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)  {  	ulong wp; -	ulong cp; +	uchar *p;  	int aln;  	cfiword_t cword;  	int i, rc; @@ -612,26 +1147,28 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)  	int buffered_size;  #endif  	/* get lower aligned address */ -	/* get lower aligned address */  	wp = (addr & ~(info->portwidth - 1));  	/* handle unaligned start */  	if ((aln = addr - wp) != 0) {  		cword.l = 0; -		cp = wp; -		for (i = 0; i < aln; ++i, ++cp) -			flash_add_byte (info, &cword, (*(uchar *) cp)); +		p = map_physmem(wp, info->portwidth, MAP_NOCACHE); +		for (i = 0; i < aln; ++i) +			flash_add_byte (info, &cword, flash_read8(p + i));  		for (; (i < info->portwidth) && (cnt > 0); i++) {  			flash_add_byte (info, &cword, *src++);  			cnt--; -			cp++;  		} -		for (; (cnt == 0) && (i < info->portwidth); ++i, ++cp) -			flash_add_byte (info, &cword, (*(uchar *) cp)); -		if ((rc = flash_write_cfiword (info, wp, cword)) != 0) +		for (; (cnt == 0) && (i < info->portwidth); ++i) +			flash_add_byte (info, &cword, flash_read8(p + i)); + +		rc = flash_write_cfiword (info, wp, cword); +		unmap_physmem(p, info->portwidth); +		if (rc != 0)  			return rc; -		wp = cp; + +		wp += i;  	}  	/* handle the aligned part */ @@ -682,13 +1219,14 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)  	 * handle unaligned tail bytes  	 */  	cword.l = 0; -	for (i = 0, cp = wp; (i < info->portwidth) && (cnt > 0); ++i, ++cp) { +	p = map_physmem(wp, info->portwidth, MAP_NOCACHE); +	for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) {  		flash_add_byte (info, &cword, *src++);  		--cnt;  	} -	for (; i < info->portwidth; ++i, ++cp) { -		flash_add_byte (info, &cword, (*(uchar *) cp)); -	} +	for (; i < info->portwidth; ++i) +		flash_add_byte (info, &cword, flash_read8(p + i)); +	unmap_physmem(p, info->portwidth);  	return flash_write_cfiword (info, wp, cword);  } @@ -740,10 +1278,11 @@ void flash_read_user_serial (flash_info_t * info, void *buffer, int offset,  	uchar *dst;  	dst = buffer; -	src = flash_make_addr (info, 0, FLASH_OFFSET_USER_PROTECTION); +	src = flash_map (info, 0, FLASH_OFFSET_USER_PROTECTION);  	flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);  	memcpy (dst, src + offset, len);  	flash_write_cmd (info, 0, 0, info->cmd_reset); +	flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src);  }  /* @@ -754,418 +1293,310 @@ void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset,  {  	uchar *src; -	src = flash_make_addr (info, 0, FLASH_OFFSET_INTEL_PROTECTION); +	src = flash_map (info, 0, FLASH_OFFSET_INTEL_PROTECTION);  	flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);  	memcpy (buffer, src + offset, len);  	flash_write_cmd (info, 0, 0, info->cmd_reset); +	flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src);  }  #endif /* CFG_FLASH_PROTECTION */ -/* - * flash_is_busy - check to see if the flash is busy - * This routine checks the status of the chip and returns true if the chip is busy +/*----------------------------------------------------------------------- + * Reverse the order of the erase regions in the CFI QRY structure. + * This is needed for chips that are either a) correctly detected as + * top-boot, or b) buggy.   */ -static int flash_is_busy (flash_info_t * info, flash_sect_t sect) +static void cfi_reverse_geometry(struct cfi_qry *qry)  { -	int retval; +	unsigned int i, j; +	u32 tmp; -	switch (info->vendor) { -	case CFI_CMDSET_INTEL_STANDARD: -	case CFI_CMDSET_INTEL_EXTENDED: -		retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE); -		break; -	case CFI_CMDSET_AMD_STANDARD: -	case CFI_CMDSET_AMD_EXTENDED: -		retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE); -		break; -	default: -		retval = 0; +	for (i = 0, j = qry->num_erase_regions - 1; i < j; i++, j--) { +		tmp = qry->erase_region_info[i]; +		qry->erase_region_info[i] = qry->erase_region_info[j]; +		qry->erase_region_info[j] = tmp;  	} -	debug ("flash_is_busy: %d\n", retval); -	return retval;  }  /*----------------------------------------------------------------------- - *  wait for XSR.7 to be set. Time out with an error if it does not. - *  This routine does not set the flash to read-array mode. + * read jedec ids from device and set corresponding fields in info struct + * + * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct + *   */ -static int flash_status_check (flash_info_t * info, flash_sect_t sector, -			       ulong tout, char *prompt) +static void cmdset_intel_read_jedec_ids(flash_info_t *info)  { -	ulong start; - -#if CFG_HZ != 1000 -	tout *= CFG_HZ/1000; -#endif - -	/* Wait for command completion */ -	start = get_timer (0); -	while (flash_is_busy (info, sector)) { -		if (get_timer (start) > tout) { -			printf ("Flash %s timeout at address %lx data %lx\n", -				prompt, info->start[sector], -				flash_read_long (info, sector, 0)); -			flash_write_cmd (info, sector, 0, info->cmd_reset); -			return ERR_TIMOUT; -		} -		udelay (1);		/* also triggers watchdog */ -	} -	return ERR_OK; +	flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); +	flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID); +	udelay(1000); /* some flash are slow to respond */ +	info->manufacturer_id = flash_read_uchar (info, +					FLASH_OFFSET_MANUFACTURER_ID); +	info->device_id = flash_read_uchar (info, +					FLASH_OFFSET_DEVICE_ID); +	flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);  } -/*----------------------------------------------------------------------- - * Wait for XSR.7 to be set, if it times out print an error, otherwise do a full status check. - * This routine sets the flash to read-array mode. - */ -static int flash_full_status_check (flash_info_t * info, flash_sect_t sector, -				    ulong tout, char *prompt) +static int cmdset_intel_init(flash_info_t *info, struct cfi_qry *qry)  { -	int retcode; +	info->cmd_reset = FLASH_CMD_RESET; -	retcode = flash_status_check (info, sector, tout, prompt); -	switch (info->vendor) { -	case CFI_CMDSET_INTEL_EXTENDED: -	case CFI_CMDSET_INTEL_STANDARD: -		if ((retcode == ERR_OK) -		    && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) { -			retcode = ERR_INVAL; -			printf ("Flash %s error at address %lx\n", prompt, -				info->start[sector]); -			if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS | FLASH_STATUS_PSLBS)) { -				puts ("Command Sequence Error.\n"); -			} else if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS)) { -				puts ("Block Erase Error.\n"); -				retcode = ERR_NOT_ERASED; -			} else if (flash_isset (info, sector, 0, FLASH_STATUS_PSLBS)) { -				puts ("Locking Error\n"); -			} -			if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) { -				puts ("Block locked.\n"); -				retcode = ERR_PROTECTED; -			} -			if (flash_isset (info, sector, 0, FLASH_STATUS_VPENS)) -				puts ("Vpp Low Error.\n"); -		} -		flash_write_cmd (info, sector, 0, info->cmd_reset); -		break; -	default: -		break; +	cmdset_intel_read_jedec_ids(info); +	flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI); + +#ifdef CFG_FLASH_PROTECTION +	/* read legacy lock/unlock bit from intel flash */ +	if (info->ext_addr) { +		info->legacy_unlock = flash_read_uchar (info, +				info->ext_addr + 5) & 0x08;  	} -	return retcode; +#endif + +	return 0;  } -/*----------------------------------------------------------------------- - */ -static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c) +static void cmdset_amd_read_jedec_ids(flash_info_t *info)  { -#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) -	unsigned short	w; -	unsigned int	l; -	unsigned long long ll; -#endif - -	switch (info->portwidth) { -	case FLASH_CFI_8BIT: -		cword->c = c; -		break; -	case FLASH_CFI_16BIT: -#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) -		w = c; -		w <<= 8; -		cword->w = (cword->w >> 8) | w; -#else -		cword->w = (cword->w << 8) | c; -#endif -		break; -	case FLASH_CFI_32BIT: -#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) -		l = c; -		l <<= 24; -		cword->l = (cword->l >> 8) | l; -#else -		cword->l = (cword->l << 8) | c; -#endif -		break; -	case FLASH_CFI_64BIT: -#if defined(__LITTLE_ENDIAN) && !defined(CFG_WRITE_SWAPPED_DATA) -		ll = c; -		ll <<= 56; -		cword->ll = (cword->ll >> 8) | ll; -#else -		cword->ll = (cword->ll << 8) | c; -#endif -		break; +	flash_write_cmd(info, 0, 0, AMD_CMD_RESET); +	flash_unlock_seq(info, 0); +	flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID); +	udelay(1000); /* some flash are slow to respond */ +	info->manufacturer_id = flash_read_uchar (info, +					FLASH_OFFSET_MANUFACTURER_ID); +	info->device_id = flash_read_uchar (info, +					FLASH_OFFSET_DEVICE_ID); +	if (info->device_id == 0x7E) { +		/* AMD 3-byte (expanded) device ids */ +		info->device_id2 = flash_read_uchar (info, +					FLASH_OFFSET_DEVICE_ID2); +		info->device_id2 <<= 8; +		info->device_id2 |= flash_read_uchar (info, +					FLASH_OFFSET_DEVICE_ID3);  	} +	flash_write_cmd(info, 0, 0, AMD_CMD_RESET);  } - -/*----------------------------------------------------------------------- - * make a proper sized command based on the port and chip widths - */ -static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf) +static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry)  { -	int i; -	uchar *cp = (uchar *) cmdbuf; +	info->cmd_reset = AMD_CMD_RESET; -#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA) -	for (i = info->portwidth; i > 0; i--) -#else -	for (i = 1; i <= info->portwidth; i++) -#endif -		*cp++ = (i & (info->chipwidth - 1)) ? '\0' : cmd; +	cmdset_amd_read_jedec_ids(info); +	flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI); + +	return 0;  } -/* - * Write a proper sized command to the correct address - */ -static void flash_write_cmd (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd) +#ifdef CONFIG_FLASH_CFI_LEGACY +static void flash_read_jedec_ids (flash_info_t * info)  { +	info->manufacturer_id = 0; +	info->device_id       = 0; +	info->device_id2      = 0; -	volatile cfiptr_t addr; -	cfiword_t cword; - -	addr.cp = flash_make_addr (info, sect, offset); -	flash_make_cmd (info, cmd, &cword); -	switch (info->portwidth) { -	case FLASH_CFI_8BIT: -		debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr.cp, cmd, -		       cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH); -		*addr.cp = cword.c; -		break; -	case FLASH_CFI_16BIT: -		debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr.wp, -		       cmd, cword.w, -		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH); -		*addr.wp = cword.w; +	switch (info->vendor) { +	case CFI_CMDSET_INTEL_STANDARD: +	case CFI_CMDSET_INTEL_EXTENDED: +		flash_read_jedec_ids_intel(info);  		break; -	case FLASH_CFI_32BIT: -		debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr.lp, -		       cmd, cword.l, -		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH); -		*addr.lp = cword.l; +	case CFI_CMDSET_AMD_STANDARD: +	case CFI_CMDSET_AMD_EXTENDED: +		flash_read_jedec_ids_amd(info);  		break; -	case FLASH_CFI_64BIT: -#ifdef DEBUG -		{ -			char str[20]; - -			print_longlong (str, cword.ll); - -			debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n", -			       addr.llp, cmd, str, -			       info->chipwidth << CFI_FLASH_SHIFT_WIDTH); -		} -#endif -		*addr.llp = cword.ll; +	default:  		break;  	} - -	/* Ensure all the instructions are fully finished */ -	sync(); -} - -static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect) -{ -	flash_write_cmd (info, sect, AMD_ADDR_START, AMD_CMD_UNLOCK_START); -	flash_write_cmd (info, sect, AMD_ADDR_ACK, AMD_CMD_UNLOCK_ACK);  }  /*----------------------------------------------------------------------- + * Call board code to request info about non-CFI flash. + * board_flash_get_legacy needs to fill in at least: + * info->portwidth, info->chipwidth and info->interface for Jedec probing.   */ -static int flash_isequal (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd) +static int flash_detect_legacy(ulong base, int banknum)  { -	cfiptr_t cptr; -	cfiword_t cword; -	int retval; +	flash_info_t *info = &flash_info[banknum]; -	cptr.cp = flash_make_addr (info, sect, offset); -	flash_make_cmd (info, cmd, &cword); +	if (board_flash_get_legacy(base, banknum, info)) { +		/* board code may have filled info completely. If not, we +		   use JEDEC ID probing. */ +		if (!info->vendor) { +			int modes[] = { +				CFI_CMDSET_AMD_STANDARD, +				CFI_CMDSET_INTEL_STANDARD +			}; +			int i; -	debug ("is= cmd %x(%c) addr %p ", cmd, cmd, cptr.cp); -	switch (info->portwidth) { -	case FLASH_CFI_8BIT: -		debug ("is= %x %x\n", cptr.cp[0], cword.c); -		retval = (cptr.cp[0] == cword.c); -		break; -	case FLASH_CFI_16BIT: -		debug ("is= %4.4x %4.4x\n", cptr.wp[0], cword.w); -		retval = (cptr.wp[0] == cword.w); -		break; -	case FLASH_CFI_32BIT: -		debug ("is= %8.8lx %8.8lx\n", cptr.lp[0], cword.l); -		retval = (cptr.lp[0] == cword.l); -		break; -	case FLASH_CFI_64BIT: -#ifdef DEBUG -		{ -			char str1[20]; -			char str2[20]; +			for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) { +				info->vendor = modes[i]; +				info->start[0] = base; +				if (info->portwidth == FLASH_CFI_8BIT +					&& info->interface == FLASH_CFI_X8X16) { +					info->addr_unlock1 = 0x2AAA; +					info->addr_unlock2 = 0x5555; +				} else { +					info->addr_unlock1 = 0x5555; +					info->addr_unlock2 = 0x2AAA; +				} +				flash_read_jedec_ids(info); +				debug("JEDEC PROBE: ID %x %x %x\n", +						info->manufacturer_id, +						info->device_id, +						info->device_id2); +				if (jedec_flash_match(info, base)) +					break; +			} +		} -			print_longlong (str1, cptr.llp[0]); -			print_longlong (str2, cword.ll); -			debug ("is= %s %s\n", str1, str2); +		switch(info->vendor) { +		case CFI_CMDSET_INTEL_STANDARD: +		case CFI_CMDSET_INTEL_EXTENDED: +			info->cmd_reset = FLASH_CMD_RESET; +			break; +		case CFI_CMDSET_AMD_STANDARD: +		case CFI_CMDSET_AMD_EXTENDED: +		case CFI_CMDSET_AMD_LEGACY: +			info->cmd_reset = AMD_CMD_RESET; +			break;  		} -#endif -		retval = (cptr.llp[0] == cword.ll); -		break; -	default: -		retval = 0; -		break; +		info->flash_id = FLASH_MAN_CFI; +		return 1;  	} -	return retval; +	return 0; /* use CFI */  } - -/*----------------------------------------------------------------------- - */ -static int flash_isset (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd) +#else +static inline int flash_detect_legacy(ulong base, int banknum)  { -	cfiptr_t cptr; -	cfiword_t cword; -	int retval; - -	cptr.cp = flash_make_addr (info, sect, offset); -	flash_make_cmd (info, cmd, &cword); -	switch (info->portwidth) { -	case FLASH_CFI_8BIT: -		retval = ((cptr.cp[0] & cword.c) == cword.c); -		break; -	case FLASH_CFI_16BIT: -		retval = ((cptr.wp[0] & cword.w) == cword.w); -		break; -	case FLASH_CFI_32BIT: -		retval = ((cptr.lp[0] & cword.l) == cword.l); -		break; -	case FLASH_CFI_64BIT: -		retval = ((cptr.llp[0] & cword.ll) == cword.ll); -		break; -	default: -		retval = 0; -		break; -	} -	return retval; +	return 0; /* use CFI */  } +#endif  /*----------------------------------------------------------------------- + * detect if flash is compatible with the Common Flash Interface (CFI) + * http://www.jedec.org/download/search/jesd68.pdf   */ -static int flash_toggle (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd) +static void flash_read_cfi (flash_info_t *info, void *buf, +		unsigned int start, size_t len)  { -	cfiptr_t cptr; -	cfiword_t cword; -	int retval; +	u8 *p = buf; +	unsigned int i; -	cptr.cp = flash_make_addr (info, sect, offset); -	flash_make_cmd (info, cmd, &cword); -	switch (info->portwidth) { -	case FLASH_CFI_8BIT: -		retval = ((cptr.cp[0] & cword.c) != (cptr.cp[0] & cword.c)); -		break; -	case FLASH_CFI_16BIT: -		retval = ((cptr.wp[0] & cword.w) != (cptr.wp[0] & cword.w)); -		break; -	case FLASH_CFI_32BIT: -		retval = ((cptr.lp[0] & cword.l) != (cptr.lp[0] & cword.l)); -		break; -	case FLASH_CFI_64BIT: -		retval = ((cptr.llp[0] & cword.ll) != -			  (cptr.llp[0] & cword.ll)); -		break; -	default: -		retval = 0; -		break; -	} -	return retval; +	for (i = 0; i < len; i++) +		p[i] = flash_read_uchar(info, start + i);  } -/*----------------------------------------------------------------------- - * read jedec ids from device and set corresponding fields in info struct - * - * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct - * -*/ -static void flash_read_jedec_ids (flash_info_t * info) +static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)  { -	info->manufacturer_id = 0; -	info->device_id       = 0; -	info->device_id2      = 0; +	int cfi_offset; -	switch (info->vendor) { -	case CFI_CMDSET_INTEL_STANDARD: -	case CFI_CMDSET_INTEL_EXTENDED: -		flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); -		flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID); -		udelay(1000); /* some flash are slow to respond */ -		info->manufacturer_id = flash_read_uchar (info, -						FLASH_OFFSET_MANUFACTURER_ID); -		info->device_id = flash_read_uchar (info, -						FLASH_OFFSET_DEVICE_ID); -		flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); -		break; -	case CFI_CMDSET_AMD_STANDARD: -	case CFI_CMDSET_AMD_EXTENDED: -		flash_write_cmd(info, 0, 0, AMD_CMD_RESET); -		flash_unlock_seq(info, 0); -		flash_write_cmd(info, 0, AMD_ADDR_START, FLASH_CMD_READ_ID); -		udelay(1000); /* some flash are slow to respond */ -		info->manufacturer_id = flash_read_uchar (info, -						FLASH_OFFSET_MANUFACTURER_ID); -		info->device_id = flash_read_uchar (info, -						FLASH_OFFSET_DEVICE_ID); -		if (info->device_id == 0x7E) { -			/* AMD 3-byte (expanded) device ids */ -			info->device_id2 = flash_read_uchar (info, -						FLASH_OFFSET_DEVICE_ID2); -			info->device_id2 <<= 8; -			info->device_id2 |= flash_read_uchar (info, -						FLASH_OFFSET_DEVICE_ID3); +	flash_write_cmd (info, 0, 0, info->cmd_reset); +	for (cfi_offset=0; +	     cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint); +	     cfi_offset++) { +		flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset], +				 FLASH_CMD_CFI); +		if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q') +		    && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R') +		    && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) { +			flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP, +					sizeof(struct cfi_qry)); +			info->interface	= le16_to_cpu(qry->interface_desc); + +			info->cfi_offset = flash_offset_cfi[cfi_offset]; +			debug ("device interface is %d\n", +			       info->interface); +			debug ("found port %d chip %d ", +			       info->portwidth, info->chipwidth); +			debug ("port %d bits chip %d bits\n", +			       info->portwidth << CFI_FLASH_SHIFT_WIDTH, +			       info->chipwidth << CFI_FLASH_SHIFT_WIDTH); + +			/* calculate command offsets as in the Linux driver */ +			info->addr_unlock1 = 0x555; +			info->addr_unlock2 = 0x2aa; + +			/* +			 * modify the unlock address if we are +			 * in compatibility mode +			 */ +			if (	/* x8/x16 in x8 mode */ +				((info->chipwidth == FLASH_CFI_BY8) && +					(info->interface == FLASH_CFI_X8X16)) || +				/* x16/x32 in x16 mode */ +				((info->chipwidth == FLASH_CFI_BY16) && +					(info->interface == FLASH_CFI_X16X32))) +			{ +				info->addr_unlock1 = 0xaaa; +				info->addr_unlock2 = 0x555; +			} + +			info->name = "CFI conformant"; +			return 1;  		} -		flash_write_cmd(info, 0, 0, AMD_CMD_RESET); -		break; -	default: -		break;  	} + +	return 0;  } -/*----------------------------------------------------------------------- - * detect if flash is compatible with the Common Flash Interface (CFI) - * http://www.jedec.org/download/search/jesd68.pdf - * -*/ -static int flash_detect_cfi (flash_info_t * info) +static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)  { -	int cfi_offset;  	debug ("flash detect cfi\n");  	for (info->portwidth = CFG_FLASH_CFI_WIDTH;  	     info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) {  		for (info->chipwidth = FLASH_CFI_BY8;  		     info->chipwidth <= info->portwidth; -		     info->chipwidth <<= 1) { -			flash_write_cmd (info, 0, 0, info->cmd_reset); -			for (cfi_offset=0; cfi_offset < sizeof(flash_offset_cfi)/sizeof(uint); cfi_offset++) { -				flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset], FLASH_CMD_CFI); -				if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q') -				 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R') -				 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) { -					info->interface = flash_read_ushort (info, 0, FLASH_OFFSET_INTERFACE); -					info->cfi_offset=flash_offset_cfi[cfi_offset]; -					debug ("device interface is %d\n", -						info->interface); -					debug ("found port %d chip %d ", -						info->portwidth, info->chipwidth); -					debug ("port %d bits chip %d bits\n", -						info->portwidth << CFI_FLASH_SHIFT_WIDTH, -						info->chipwidth << CFI_FLASH_SHIFT_WIDTH); -					return 1; -				} -			} -		} +		     info->chipwidth <<= 1) +			if (__flash_detect_cfi(info, qry)) +				return 1;  	}  	debug ("not found\n");  	return 0;  }  /* + * Manufacturer-specific quirks. Add workarounds for geometry + * reversal, etc. here. + */ +static void flash_fixup_amd(flash_info_t *info, struct cfi_qry *qry) +{ +	/* check if flash geometry needs reversal */ +	if (qry->num_erase_regions > 1) { +		/* reverse geometry if top boot part */ +		if (info->cfi_version < 0x3131) { +			/* CFI < 1.1, try to guess from device id */ +			if ((info->device_id & 0x80) != 0) +				cfi_reverse_geometry(qry); +		} else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) { +			/* CFI >= 1.1, deduct from top/bottom flag */ +			/* note: ext_addr is valid since cfi_version > 0 */ +			cfi_reverse_geometry(qry); +		} +	} +} + +static void flash_fixup_atmel(flash_info_t *info, struct cfi_qry *qry) +{ +	int reverse_geometry = 0; + +	/* Check the "top boot" bit in the PRI */ +	if (info->ext_addr && !(flash_read_uchar(info, info->ext_addr + 6) & 1)) +		reverse_geometry = 1; + +	/* AT49BV6416(T) list the erase regions in the wrong order. +	 * However, the device ID is identical with the non-broken +	 * AT49BV642D since u-boot only reads the low byte (they +	 * differ in the high byte.) So leave out this fixup for now. +	 */ +#if 0 +	if (info->device_id == 0xd6 || info->device_id == 0xd2) +		reverse_geometry = !reverse_geometry; +#endif + +	if (reverse_geometry) +		cfi_reverse_geometry(qry); +} + +/*   * The following code cannot be run from FLASH!   *   */ @@ -1180,7 +1611,7 @@ ulong flash_get_size (ulong base, int banknum)  	uchar num_erase_regions;  	int erase_region_size;  	int erase_region_count; -	int geometry_reversed = 0; +	struct cfi_qry qry;  	info->ext_addr = 0;  	info->cfi_version = 0; @@ -1190,56 +1621,50 @@ ulong flash_get_size (ulong base, int banknum)  	info->start[0] = base; -	if (flash_detect_cfi (info)) { -		info->vendor = flash_read_ushort (info, 0, -					FLASH_OFFSET_PRIMARY_VENDOR); -		flash_read_jedec_ids (info); -		flash_write_cmd (info, 0, info->cfi_offset, FLASH_CMD_CFI); -		num_erase_regions = flash_read_uchar (info, -					FLASH_OFFSET_NUM_ERASE_REGIONS); -		info->ext_addr = flash_read_ushort (info, 0, -					FLASH_OFFSET_EXT_QUERY_T_P_ADDR); +	if (flash_detect_cfi (info, &qry)) { +		info->vendor = le16_to_cpu(qry.p_id); +		info->ext_addr = le16_to_cpu(qry.p_adr); +		num_erase_regions = qry.num_erase_regions; +  		if (info->ext_addr) {  			info->cfi_version = (ushort) flash_read_uchar (info,  						info->ext_addr + 3) << 8;  			info->cfi_version |= (ushort) flash_read_uchar (info,  						info->ext_addr + 4);  		} +  #ifdef DEBUG -		flash_printqry (info, 0); +		flash_printqry (&qry);  #endif +  		switch (info->vendor) {  		case CFI_CMDSET_INTEL_STANDARD:  		case CFI_CMDSET_INTEL_EXTENDED: -		default: -			info->cmd_reset = FLASH_CMD_RESET; -#ifdef CFG_FLASH_PROTECTION -			/* read legacy lock/unlock bit from intel flash */ -			if (info->ext_addr) { -				info->legacy_unlock = flash_read_uchar (info, -						info->ext_addr + 5) & 0x08; -			} -#endif +			cmdset_intel_init(info, &qry);  			break;  		case CFI_CMDSET_AMD_STANDARD:  		case CFI_CMDSET_AMD_EXTENDED: -			info->cmd_reset = AMD_CMD_RESET; -			/* check if flash geometry needs reversal */ -			if (num_erase_regions <= 1) -				break; -			/* reverse geometry if top boot part */ -			if (info->cfi_version < 0x3131) { -				/* CFI < 1.1, try to guess from device id */ -				if ((info->device_id & 0x80) != 0) { -					geometry_reversed = 1; -				} -				break; -			} -			/* CFI >= 1.1, deduct from top/bottom flag */ -			/* note: ext_addr is valid since cfi_version > 0 */ -			if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) { -				geometry_reversed = 1; -			} +			cmdset_amd_init(info, &qry); +			break; +		default: +			printf("CFI: Unknown command set 0x%x\n", +					info->vendor); +			/* +			 * Unfortunately, this means we don't know how +			 * to get the chip back to Read mode. Might +			 * as well try an Intel-style reset... +			 */ +			flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); +			return 0; +		} + +		/* Do manufacturer-specific fixups */ +		switch (info->manufacturer_id) { +		case 0x0001: +			flash_fixup_amd(info, &qry); +			break; +		case 0x001f: +			flash_fixup_atmel(info, &qry);  			break;  		} @@ -1267,26 +1692,27 @@ ulong flash_get_size (ulong base, int banknum)  					num_erase_regions, NUM_ERASE_REGIONS);  				break;  			} -			if (geometry_reversed) -				tmp = flash_read_long (info, 0, -					       FLASH_OFFSET_ERASE_REGIONS + -					       (num_erase_regions - 1 - i) * 4); -			else -				tmp = flash_read_long (info, 0, -					       FLASH_OFFSET_ERASE_REGIONS + -					       i * 4); + +			tmp = le32_to_cpu(qry.erase_region_info[i]); +			debug("erase region %u: 0x%08lx\n", i, tmp); + +			erase_region_count = (tmp & 0xffff) + 1; +			tmp >>= 16;  			erase_region_size =  				(tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128; -			tmp >>= 16; -			erase_region_count = (tmp & 0xffff) + 1;  			debug ("erase_region_count = %d erase_region_size = %d\n",  				erase_region_count, erase_region_size);  			for (j = 0; j < erase_region_count; j++) { +				if (sect_cnt >= CFG_MAX_FLASH_SECT) { +					printf("ERROR: too many flash sectors\n"); +					break; +				}  				info->start[sect_cnt] = sector;  				sector += (erase_region_size * size_ratio);  				/* -				 * Only read protection status from supported devices (intel...) +				 * Only read protection status from +				 * supported devices (intel...)  				 */  				switch (info->vendor) {  				case CFI_CMDSET_INTEL_EXTENDED: @@ -1297,7 +1723,8 @@ ulong flash_get_size (ulong base, int banknum)  							     FLASH_STATUS_PROTECT);  					break;  				default: -					info->protect[sect_cnt] = 0; /* default: not protected */ +					/* default: not protected */ +					info->protect[sect_cnt] = 0;  				}  				sect_cnt++; @@ -1305,20 +1732,27 @@ ulong flash_get_size (ulong base, int banknum)  		}  		info->sector_count = sect_cnt; +		info->size = 1 << qry.dev_size;  		/* multiply the size by the number of chips */ -		info->size = (1 << flash_read_uchar (info, FLASH_OFFSET_SIZE)) * size_ratio; -		info->buffer_size = (1 << flash_read_ushort (info, 0, FLASH_OFFSET_BUFFER_SIZE)); -		tmp = 1 << flash_read_uchar (info, FLASH_OFFSET_ETOUT); -		info->erase_blk_tout = (tmp * (1 << flash_read_uchar (info, FLASH_OFFSET_EMAX_TOUT))); -		tmp = (1 << flash_read_uchar (info, FLASH_OFFSET_WBTOUT)) * -			(1 << flash_read_uchar (info, FLASH_OFFSET_WBMAX_TOUT)); -		info->buffer_write_tout = tmp / 1000 + (tmp % 1000 ? 1 : 0); /* round up when converting to ms */ -		tmp = (1 << flash_read_uchar (info, FLASH_OFFSET_WTOUT)) * -		      (1 << flash_read_uchar (info, FLASH_OFFSET_WMAX_TOUT)); -		info->write_tout = tmp / 1000 + (tmp % 1000 ? 1 : 0); /* round up when converting to ms */ +		info->size *= size_ratio; +		info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size); +		tmp = 1 << qry.block_erase_timeout_typ; +		info->erase_blk_tout = tmp * +			(1 << qry.block_erase_timeout_max); +		tmp = (1 << qry.buf_write_timeout_typ) * +			(1 << qry.buf_write_timeout_max); + +		/* round up when converting to ms */ +		info->buffer_write_tout = (tmp + 999) / 1000; +		tmp = (1 << qry.word_write_timeout_typ) * +			(1 << qry.word_write_timeout_max); +		/* round up when converting to ms */ +		info->write_tout = (tmp + 999) / 1000;  		info->flash_id = FLASH_MAN_CFI; -		if ((info->interface == FLASH_CFI_X8X16) && (info->chipwidth == FLASH_CFI_BY8)) { -			info->portwidth >>= 1;	/* XXX - Need to test on x8/x16 in parallel. */ +		if ((info->interface == FLASH_CFI_X8X16) && +		    (info->chipwidth == FLASH_CFI_BY8)) { +			/* XXX - Need to test on x8/x16 in parallel. */ +			info->portwidth >>= 1;  		}  	} @@ -1326,203 +1760,106 @@ ulong flash_get_size (ulong base, int banknum)  	return (info->size);  } -/* loop through the sectors from the highest address - * when the passed address is greater or equal to the sector address - * we have a match - */ -static flash_sect_t find_sector (flash_info_t * info, ulong addr) -{ -	flash_sect_t sector; - -	for (sector = info->sector_count - 1; sector >= 0; sector--) { -		if (addr >= info->start[sector]) -			break; -	} -	return sector; -} -  /*-----------------------------------------------------------------------   */ -static int flash_write_cfiword (flash_info_t * info, ulong dest, -				cfiword_t cword) +unsigned long flash_init (void)  { -	cfiptr_t ctladdr; -	cfiptr_t cptr; -	int flag; - -	ctladdr.cp = flash_make_addr (info, 0, 0); -	cptr.cp = (uchar *) dest; - -	/* Check if Flash is (sufficiently) erased */ -	switch (info->portwidth) { -	case FLASH_CFI_8BIT: -		flag = ((cptr.cp[0] & cword.c) == cword.c); -		break; -	case FLASH_CFI_16BIT: -		flag = ((cptr.wp[0] & cword.w) == cword.w); -		break; -	case FLASH_CFI_32BIT: -		flag = ((cptr.lp[0] & cword.l) == cword.l); -		break; -	case FLASH_CFI_64BIT: -		flag = ((cptr.llp[0] & cword.ll) == cword.ll); -		break; -	default: -		return 2; -	} -	if (!flag) -		return 2; - -	/* Disable interrupts which might cause a timeout here */ -	flag = disable_interrupts (); +	unsigned long size = 0; +	int i; -	switch (info->vendor) { -	case CFI_CMDSET_INTEL_EXTENDED: -	case CFI_CMDSET_INTEL_STANDARD: -		flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS); -		flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE); -		break; -	case CFI_CMDSET_AMD_EXTENDED: -	case CFI_CMDSET_AMD_STANDARD: -		flash_unlock_seq (info, 0); -		flash_write_cmd (info, 0, AMD_ADDR_START, AMD_CMD_WRITE); -		break; -	} +#ifdef CFG_FLASH_PROTECTION +	char *s = getenv("unlock"); +#endif -	switch (info->portwidth) { -	case FLASH_CFI_8BIT: -		cptr.cp[0] = cword.c; -		break; -	case FLASH_CFI_16BIT: -		cptr.wp[0] = cword.w; -		break; -	case FLASH_CFI_32BIT: -		cptr.lp[0] = cword.l; -		break; -	case FLASH_CFI_64BIT: -		cptr.llp[0] = cword.ll; -		break; -	} +	/* Init: no FLASHes known */ +	for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) { +		flash_info[i].flash_id = FLASH_UNKNOWN; -	/* re-enable interrupts if necessary */ -	if (flag) -		enable_interrupts (); +		if (!flash_detect_legacy (bank_base[i], i)) +			flash_get_size (bank_base[i], i); +		size += flash_info[i].size; +		if (flash_info[i].flash_id == FLASH_UNKNOWN) { +#ifndef CFG_FLASH_QUIET_TEST +			printf ("## Unknown FLASH on Bank %d " +				"- Size = 0x%08lx = %ld MB\n", +				i+1, flash_info[i].size, +				flash_info[i].size << 20); +#endif /* CFG_FLASH_QUIET_TEST */ +		} +#ifdef CFG_FLASH_PROTECTION +		else if ((s != NULL) && (strcmp(s, "yes") == 0)) { +			/* +			 * Only the U-Boot image and it's environment +			 * is protected, all other sectors are +			 * unprotected (unlocked) if flash hardware +			 * protection is used (CFG_FLASH_PROTECTION) +			 * and the environment variable "unlock" is +			 * set to "yes". +			 */ +			if (flash_info[i].legacy_unlock) { +				int k; -	return flash_full_status_check (info, find_sector (info, dest), -					info->write_tout, "write"); -} +				/* +				 * Disable legacy_unlock temporarily, +				 * since flash_real_protect would +				 * relock all other sectors again +				 * otherwise. +				 */ +				flash_info[i].legacy_unlock = 0; -#ifdef CFG_FLASH_USE_BUFFER_WRITE +				/* +				 * Legacy unlocking (e.g. Intel J3) -> +				 * unlock only one sector. This will +				 * unlock all sectors. +				 */ +				flash_real_protect (&flash_info[i], 0, 0); -static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, -				  int len) -{ -	flash_sect_t sector; -	int cnt; -	int retcode; -	volatile cfiptr_t src; -	volatile cfiptr_t dst; +				flash_info[i].legacy_unlock = 1; -	switch (info->vendor) { -	case CFI_CMDSET_INTEL_STANDARD: -	case CFI_CMDSET_INTEL_EXTENDED: -		src.cp = cp; -		dst.cp = (uchar *) dest; -		sector = find_sector (info, dest); -		flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS); -		flash_write_cmd (info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER); -		if ((retcode = flash_status_check (info, sector, info->buffer_write_tout, -						   "write to buffer")) == ERR_OK) { -			/* reduce the number of loops by the width of the port	*/ -			switch (info->portwidth) { -			case FLASH_CFI_8BIT: -				cnt = len; -				break; -			case FLASH_CFI_16BIT: -				cnt = len >> 1; -				break; -			case FLASH_CFI_32BIT: -				cnt = len >> 2; -				break; -			case FLASH_CFI_64BIT: -				cnt = len >> 3; -				break; -			default: -				return ERR_INVAL; -				break; -			} -			flash_write_cmd (info, sector, 0, (uchar) cnt - 1); -			while (cnt-- > 0) { -				switch (info->portwidth) { -				case FLASH_CFI_8BIT: -					*dst.cp++ = *src.cp++; -					break; -				case FLASH_CFI_16BIT: -					*dst.wp++ = *src.wp++; -					break; -				case FLASH_CFI_32BIT: -					*dst.lp++ = *src.lp++; -					break; -				case FLASH_CFI_64BIT: -					*dst.llp++ = *src.llp++; -					break; -				default: -					return ERR_INVAL; -					break; -				} +				/* +				 * Manually mark other sectors as +				 * unlocked (unprotected) +				 */ +				for (k = 1; k < flash_info[i].sector_count; k++) +					flash_info[i].protect[k] = 0; +			} else { +				/* +				 * No legancy unlocking -> unlock all sectors +				 */ +				flash_protect (FLAG_PROTECT_CLEAR, +					       flash_info[i].start[0], +					       flash_info[i].start[0] +					       + flash_info[i].size - 1, +					       &flash_info[i]);  			} -			flash_write_cmd (info, sector, 0, -					 FLASH_CMD_WRITE_BUFFER_CONFIRM); -			retcode = flash_full_status_check (info, sector, -							   info->buffer_write_tout, -							   "buffer write");  		} -		return retcode; - -	case CFI_CMDSET_AMD_STANDARD: -	case CFI_CMDSET_AMD_EXTENDED: -		src.cp = cp; -		dst.cp = (uchar *) dest; -		sector = find_sector (info, dest); - -		flash_unlock_seq(info,0); -		flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_TO_BUFFER); +#endif /* CFG_FLASH_PROTECTION */ +	} -		switch (info->portwidth) { -		case FLASH_CFI_8BIT: -			cnt = len; -			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1); -			while (cnt-- > 0) *dst.cp++ = *src.cp++; -			break; -		case FLASH_CFI_16BIT: -			cnt = len >> 1; -			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1); -			while (cnt-- > 0) *dst.wp++ = *src.wp++; -			break; -		case FLASH_CFI_32BIT: -			cnt = len >> 2; -			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1); -			while (cnt-- > 0) *dst.lp++ = *src.lp++; -			break; -		case FLASH_CFI_64BIT: -			cnt = len >> 3; -			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1); -			while (cnt-- > 0) *dst.llp++ = *src.llp++; -			break; -		default: -			return ERR_INVAL; -		} +	/* Monitor protection ON by default */ +#if (CFG_MONITOR_BASE >= CFG_FLASH_BASE) +	flash_protect (FLAG_PROTECT_SET, +		       CFG_MONITOR_BASE, +		       CFG_MONITOR_BASE + monitor_flash_len  - 1, +		       flash_get_info(CFG_MONITOR_BASE)); +#endif -		flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM); -		retcode = flash_full_status_check (info, sector, info->buffer_write_tout, -						   "buffer write"); -		return retcode; +	/* Environment protection ON by default */ +#ifdef CFG_ENV_IS_IN_FLASH +	flash_protect (FLAG_PROTECT_SET, +		       CFG_ENV_ADDR, +		       CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1, +		       flash_get_info(CFG_ENV_ADDR)); +#endif -	default: -		debug ("Unknown Command Set\n"); -		return ERR_INVAL; -	} +	/* Redundant environment protection ON by default */ +#ifdef CFG_ENV_ADDR_REDUND +	flash_protect (FLAG_PROTECT_SET, +		       CFG_ENV_ADDR_REDUND, +		       CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1, +		       flash_get_info(CFG_ENV_ADDR_REDUND)); +#endif +	return (size);  } -#endif /* CFG_FLASH_USE_BUFFER_WRITE */  #endif /* CFG_FLASH_CFI */  |