More tightly integrated non-blocking variants of some CFI flash access functions. Enable with CONFIG_SYS_FLASH_CFI_NONBLOCK These can be useful to erase flash or write complete sectors of flash during a serial data transfer for software updates.
Signed-off-by: Wolfgang Wegner <w.weg...@astro-kom.de> --- Re-worked patch avoiding code duplication and fixing white-space as well as line length errors I found while forwarding to next branch. drivers/mtd/cfi_flash.c | 269 +++++++++++++++++++++++++++++++++++------------ include/flash.h | 9 ++ 2 files changed, 210 insertions(+), 68 deletions(-) diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c index c611f6b..74fa75f 100644 --- a/drivers/mtd/cfi_flash.c +++ b/drivers/mtd/cfi_flash.c @@ -528,22 +528,30 @@ static int flash_is_busy (flash_info_t * info, flash_sect_t sect) } /*----------------------------------------------------------------------- - * wait for XSR.7 to be set. Time out with an error if it does not. + * check/wait for XSR.7 is set. When tout is nonzero, start timer, else check + * if time out value is reached. * 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) +static int flash_status_check_int (flash_info_t * info, flash_sect_t sector, + ulong tout, char *prompt, int nonblock) { - ulong start; + static ulong start; + static ulong stout; #if CONFIG_SYS_HZ != 1000 tout *= CONFIG_SYS_HZ/1000; #endif - /* Wait for command completion */ - start = get_timer (0); - while (flash_is_busy (info, sector)) { - if (get_timer (start) > tout) { + if (tout || (nonblock == 0)){ + stout = tout; + start = get_timer (0); + } + + /* Check for command completion */ + + while (flash_is_busy (info, sector)) + { + if (get_timer (start) > stout) { printf ("Flash %s timeout at address %lx data %lx\n", prompt, info->start[sector], flash_read_long (info, sector, 0)); @@ -551,22 +559,38 @@ static int flash_status_check (flash_info_t * info, flash_sect_t sector, return ERR_TIMOUT; } udelay (1); /* also triggers watchdog */ + if(nonblock) + return ERR_BUSY; } return ERR_OK; } /*----------------------------------------------------------------------- - * Wait for XSR.7 to be set, if it times out print an error, otherwise - * do a full status check. + * 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) +{ + return flash_status_check_int (info, sector, tout, prompt, 0); +} + +/*----------------------------------------------------------------------- + * Check for XSR.7 to be set, either waiting for it (0 == nonblock) or + * returning FLASH_BUSY (1 == nonblock). If timeout is reached, print an + * error; * - * This routine sets the flash to read-array mode. + * This routine sets the flash to read-array mode if blocking mode is + * enabled or if successful in non-blocking mode. */ -static int flash_full_status_check (flash_info_t * info, flash_sect_t sector, - ulong tout, char *prompt) +static int flash_full_status_check_int (flash_info_t * info, flash_sect_t sector, + ulong tout, char *prompt, int nonblock) { int retcode; - retcode = flash_status_check (info, sector, tout, prompt); + retcode = flash_status_check_int (info, sector, tout, prompt, nonblock); + if(retcode == ERR_BUSY) + return retcode; switch (info->vendor) { case CFI_CMDSET_INTEL_PROG_REGIONS: case CFI_CMDSET_INTEL_EXTENDED: @@ -603,6 +627,18 @@ static int flash_full_status_check (flash_info_t * info, flash_sect_t sector, } /*----------------------------------------------------------------------- + * 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) +{ + return flash_full_status_check_int (info, sector, tout, prompt, 0); +} + +/*----------------------------------------------------------------------- */ static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c) { @@ -671,8 +707,8 @@ static flash_sect_t find_sector (flash_info_t * info, ulong addr) /*----------------------------------------------------------------------- */ -static int flash_write_cfiword (flash_info_t * info, ulong dest, - cfiword_t cword) +static int flash_write_cfiword_int (flash_info_t * info, ulong dest, + cfiword_t cword, int nonblock) { void *dstaddr = (void *)dest; int flag; @@ -749,13 +785,19 @@ 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"); + return flash_full_status_check_int (info, sect, info->write_tout, "write", nonblock); +} + +static int flash_write_cfiword (flash_info_t * info, ulong dest, + cfiword_t cword) +{ + return flash_write_cfiword_int (info, dest, cword, 0); } #ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE -static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, - int len) +static int flash_write_cfibuffer_int (flash_info_t * info, ulong dest, uchar * cp, + int len, int nonblock) { flash_sect_t sector; int cnt; @@ -862,9 +904,9 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, } flash_write_cmd (info, sector, 0, FLASH_CMD_WRITE_BUFFER_CONFIRM); - retcode = flash_full_status_check ( + retcode = flash_full_status_check_int ( info, sector, info->buffer_write_tout, - "buffer write"); + "buffer write", nonblock); } break; @@ -911,9 +953,9 @@ 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"); + retcode = flash_full_status_check_int (info, sector, + info->buffer_write_tout, + "buffer write", nonblock); break; default: @@ -925,10 +967,77 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, out_unmap: return retcode; } + +static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, + int len) +{ + return flash_write_cfibuffer_int(info, dest, cp, len, 0); +} #endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */ /*----------------------------------------------------------------------- + * internal sector erase without final status check + */ +int flash_sector_erase (flash_info_t * info, flash_sect_t sect) +{ + int rcode = 0; + + if (info->flash_id != FLASH_MAN_CFI) { + puts ("Can't erase unknown flash type - aborted\n"); + return 1; + } + if (sect < 0) { + puts ("- no sector to erase\n"); + return 1; + } + + if (info->protect[sect] == 0) { /* not protected */ + switch (info->vendor) { + case CFI_CMDSET_INTEL_PROG_REGIONS: + 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); + break; + case CFI_CMDSET_AMD_STANDARD: + case CFI_CMDSET_AMD_EXTENDED: + flash_unlock_seq (info, sect); + 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); + 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); + break; + } + } + else { + printf ("- Error: protected sector %d can not be erased!\n", (int)sect); + rcode = ERR_PROTECTED; + } + return rcode; +} + +/*----------------------------------------------------------------------- */ int flash_erase (flash_info_t * info, int s_first, int s_last) { @@ -958,46 +1067,9 @@ int flash_erase (flash_info_t * info, int s_first, int s_last) putc ('\n'); } - for (sect = s_first; sect <= s_last; sect++) { if (info->protect[sect] == 0) { /* not protected */ - switch (info->vendor) { - case CFI_CMDSET_INTEL_PROG_REGIONS: - 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); - break; - case CFI_CMDSET_AMD_STANDARD: - case CFI_CMDSET_AMD_EXTENDED: - flash_unlock_seq (info, sect); - 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); - 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); - break; - } - + flash_sector_erase (info, sect); if (flash_full_status_check (info, sect, info->erase_blk_tout, "erase")) { rcode = 1; @@ -1140,8 +1212,9 @@ void flash_print_info (flash_info_t * info) * 0 - OK * 1 - write timeout * 2 - Flash not erased + * 256 - Flash busy (when CONFIG_SYS_FLASH_CFI_NONBLOCK is set) */ -int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) +int write_buff_int (flash_info_t * info, uchar * src, ulong addr, ulong cnt, int nonblock) { ulong wp; uchar *p; @@ -1182,7 +1255,7 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) for (; (cnt == 0) && (i < info->portwidth); ++i) flash_add_byte (info, &cword, flash_read8(p + i)); - rc = flash_write_cfiword (info, wp, cword); + rc = flash_write_cfiword_int (info, wp, cword, nonblock); if (rc != 0) return rc; @@ -1200,7 +1273,7 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) cword.l = 0; for (i = 0; i < info->portwidth; i++) flash_add_byte (info, &cword, *src++); - if ((rc = flash_write_cfiword (info, wp, cword)) != 0) + if ((rc = flash_write_cfiword_int (info, wp, cword, nonblock)) != 0) return rc; wp += info->portwidth; cnt -= info->portwidth; @@ -1211,12 +1284,25 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) i = buffered_size - (wp % buffered_size); if (i > cnt) i = cnt; - if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK) + rc = flash_write_cfibuffer_int (info, wp, src, i, nonblock); + if ((rc != ERR_OK) && (!nonblock || (rc != ERR_BUSY))) return rc; i -= i & (info->portwidth - 1); wp += i; src += i; cnt -= i; + if(nonblock) { + if ((rc) != ERR_BUSY) + return rc; + + if (cnt >= info->portwidth) { + rc = flash_full_status_check_int (info, find_sector (info, wp), + info->buffer_write_tout, + "buffer write", nonblock); + if (rc != ERR_OK) + return rc; + } + } FLASH_SHOW_PROGRESS(scale, dots, digit, i); } #else @@ -1225,7 +1311,7 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) for (i = 0; i < info->portwidth; i++) { flash_add_byte (info, &cword, *src++); } - if ((rc = flash_write_cfiword (info, wp, cword)) != 0) + if ((rc = flash_write_cfiword_int (info, wp, cword, nonblock)) != 0) return rc; wp += info->portwidth; cnt -= info->portwidth; @@ -1249,7 +1335,18 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) for (; i < info->portwidth; ++i) flash_add_byte (info, &cword, flash_read8(p + i)); - return flash_write_cfiword (info, wp, cword); + return flash_write_cfiword_int (info, wp, cword, nonblock); +} + +/*----------------------------------------------------------------------- + * Copy memory to flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + */ +int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) +{ + return write_buff_int(info, src, addr, cnt, 0); } /*----------------------------------------------------------------------- @@ -2020,3 +2117,39 @@ unsigned long flash_init (void) return (size); } + +#if defined(CONFIG_SYS_FLASH_CFI_NONBLOCK) +/*----------------------------------------------------------------------- + * 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. + */ +int flash_full_status_check_nb (flash_info_t * info, flash_sect_t sector, + ulong tout, char *prompt) +{ + return flash_full_status_check_int (info, sector, tout, prompt, 1); +} + +int flash_erase_nb (flash_info_t * info, int sector) +{ + int rcode; + flash_sect_t sect = sector; + + if ((rcode = flash_sector_erase (info, sect)) == 0) + rcode = flash_full_status_check_int (info, sect, + info->erase_blk_tout, "erase", 1); + return rcode; +} + +/*----------------------------------------------------------------------- + * Copy memory to flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + * 256 - Flash busy + */ +int write_buff_nb (flash_info_t * info, uchar * src, ulong addr, ulong cnt) +{ + return write_buff_int(info, src, addr, cnt, 1); +} +#endif /* CONFIG_SYS_FLASH_CFI_NONBLOCK */ diff --git a/include/flash.h b/include/flash.h index 8feca1b..026497b 100644 --- a/include/flash.h +++ b/include/flash.h @@ -126,6 +126,14 @@ extern int jedec_flash_match(flash_info_t *info, ulong base); extern flash_info_t *flash_get_info(ulong base); #endif +#if defined(CONFIG_SYS_FLASH_CFI_NONBLOCK) +extern int flash_full_status_check_nb (flash_info_t * info, ulong sector, + ulong tout, char *prompt); +extern int flash_erase_nb (flash_info_t * info, int sector); +extern int write_buff_nb (flash_info_t * info, uchar * src, ulong addr, + ulong cnt); +#endif + /*----------------------------------------------------------------------- * return codes from flash_write(): */ @@ -138,6 +146,7 @@ extern flash_info_t *flash_get_info(ulong base); #define ERR_UNKNOWN_FLASH_VENDOR 32 #define ERR_UNKNOWN_FLASH_TYPE 64 #define ERR_PROG_ERROR 128 +#define ERR_BUSY 256 /*----------------------------------------------------------------------- * Protection Flags for flash_protect(): -- 1.5.6.5 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot