diff options
Diffstat (limited to 'drivers/mtd/cfi_flash.c')
| -rw-r--r-- | drivers/mtd/cfi_flash.c | 93 | 
1 files changed, 86 insertions, 7 deletions
| diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c index cd1a86eba..d0240f55d 100644 --- a/drivers/mtd/cfi_flash.c +++ b/drivers/mtd/cfi_flash.c @@ -605,6 +605,63 @@ static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,  	return retcode;  } +static int use_flash_status_poll(flash_info_t *info) +{ +#ifdef CONFIG_SYS_CFI_FLASH_STATUS_POLL +	if (info->vendor == CFI_CMDSET_AMD_EXTENDED || +	    info->vendor == CFI_CMDSET_AMD_STANDARD) +		return 1; +#endif +	return 0; +} + +static int flash_status_poll(flash_info_t *info, void *src, void *dst, +			     ulong tout, char *prompt) +{ +#ifdef CONFIG_SYS_CFI_FLASH_STATUS_POLL +	ulong start; +	int ready; + +#if CONFIG_SYS_HZ != 1000 +	if ((ulong)CONFIG_SYS_HZ > 100000) +		tout *= (ulong)CONFIG_SYS_HZ / 1000;  /* for a big HZ, avoid overflow */ +	else +		tout = DIV_ROUND_UP(tout * (ulong)CONFIG_SYS_HZ, 1000); +#endif + +	/* Wait for command completion */ +	start = get_timer(0); +	while (1) { +		switch (info->portwidth) { +		case FLASH_CFI_8BIT: +			ready = flash_read8(dst) == flash_read8(src); +			break; +		case FLASH_CFI_16BIT: +			ready = flash_read16(dst) == flash_read16(src); +			break; +		case FLASH_CFI_32BIT: +			ready = flash_read32(dst) == flash_read32(src); +			break; +		case FLASH_CFI_64BIT: +			ready = flash_read64(dst) == flash_read64(src); +			break; +		default: +			ready = 0; +			break; +		} +		if (ready) +			break; +		if (get_timer(start) > tout) { +			printf("Flash %s timeout at address %lx data %lx\n", +			       prompt, (ulong)dst, (ulong)flash_read8(dst)); +			return ERR_TIMOUT; +		} +		udelay(1);		/* also triggers watchdog */ +	} +#endif /* CONFIG_SYS_CFI_FLASH_STATUS_POLL */ +	return ERR_OK; +} +  /*-----------------------------------------------------------------------   */  static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c) @@ -752,7 +809,12 @@ static int flash_write_cfiword (flash_info_t * info, ulong dest,  	if (!sect_found)  		sect = find_sector (info, dest); -	return flash_full_status_check (info, sect, info->write_tout, "write"); +	if (use_flash_status_poll(info)) +		return flash_status_poll(info, &cword, dstaddr, +					 info->write_tout, "write"); +	else +		return flash_full_status_check(info, sect, +					       info->write_tout, "write");  }  #ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE @@ -914,9 +976,15 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,  		}  		flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM); -		retcode = flash_full_status_check (info, sector, -						   info->buffer_write_tout, -						   "buffer write"); +		if (use_flash_status_poll(info)) +			retcode = flash_status_poll(info, src - (1 << shift), +						    dst - (1 << shift), +						    info->buffer_write_tout, +						    "buffer write"); +		else +			retcode = flash_full_status_check(info, sector, +							  info->buffer_write_tout, +							  "buffer write");  		break;  	default: @@ -938,6 +1006,7 @@ int flash_erase (flash_info_t * info, int s_first, int s_last)  	int rcode = 0;  	int prot;  	flash_sect_t sect; +	int st;  	if (info->flash_id != FLASH_MAN_CFI) {  		puts ("Can't erase unknown flash type - aborted\n"); @@ -1001,10 +1070,20 @@ int flash_erase (flash_info_t * info, int s_first, int s_last)  				break;  			} -			if (flash_full_status_check -			    (info, sect, info->erase_blk_tout, "erase")) { +			if (use_flash_status_poll(info)) { +				cfiword_t cword = (cfiword_t)0xffffffffffffffffULL; +				void *dest; +				dest = flash_map(info, sect, 0); +				st = flash_status_poll(info, &cword, dest, +						       info->erase_blk_tout, "erase"); +				flash_unmap(info, sect, 0, dest); +			} else +				st = flash_full_status_check(info, sect, +							     info->erase_blk_tout, +							     "erase"); +			if (st)  				rcode = 1; -			} else if (flash_verbose) +			else if (flash_verbose)  				putc ('.');  		}  	} |