
write_buff_nb() introduces quite an amount of duplicate code compared to write_buff(), but I did not find an elegant solution to partition them.
Signed-off-by: Wolfgang Wegner w.wegner@astro-kom.de --- drivers/mtd/cfi_flash.c | 440 ++++++++++++++++++++++++++++++++++++++--------- include/flash.h | 3 + 2 files changed, 365 insertions(+), 78 deletions(-)
diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c index 4e8f5bf..0f813b0 100644 --- a/drivers/mtd/cfi_flash.c +++ b/drivers/mtd/cfi_flash.c @@ -681,17 +681,13 @@ static int flash_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. + * check retcode of flash_full_status_check[_nb] * * 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 flash_full_status_retcode_check (flash_info_t * info, flash_sect_t sector, + char *prompt, int retcode) { - int retcode; - - retcode = flash_status_check (info, sector, tout, prompt); switch (info->vendor) { case CFI_CMDSET_INTEL_PROG_REGIONS: case CFI_CMDSET_INTEL_EXTENDED: @@ -728,6 +724,21 @@ 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) +{ + int retcode; + + retcode = flash_status_check (info, sector, tout, prompt); + return flash_full_status_retcode_check (info, sector, prompt, retcode); +} + +/*----------------------------------------------------------------------- */ static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c) { @@ -796,12 +807,11 @@ 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_stub (flash_info_t * info, ulong dest, + cfiword_t cword, flash_sect_t *sect) { void *dstaddr = (void *)dest; int flag; - flash_sect_t sect = 0; char sect_found = 0;
/* Check if Flash is (sufficiently) erased */ @@ -837,14 +847,14 @@ static int flash_write_cfiword (flash_info_t * info, ulong dest, break; case CFI_CMDSET_AMD_EXTENDED: case CFI_CMDSET_AMD_STANDARD: - sect = find_sector(info, dest); - flash_unlock_seq (info, sect); - flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_WRITE); + *sect = find_sector(info, dest); + flash_unlock_seq (info, *sect); + flash_write_cmd (info, *sect, info->addr_unlock1, AMD_CMD_WRITE); sect_found = 1; break; #ifdef CONFIG_FLASH_CFI_LEGACY case CFI_CMDSET_AMD_LEGACY: - sect = find_sector(info, dest); + *sect = find_sector(info, dest); flash_unlock_seq (info, 0); flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_WRITE); sect_found = 1; @@ -872,19 +882,31 @@ static int flash_write_cfiword (flash_info_t * info, ulong dest, enable_interrupts ();
if (!sect_found) - sect = find_sector (info, dest); + *sect = find_sector (info, dest); + + return 0; +} + +static int flash_write_cfiword (flash_info_t * info, ulong dest, + cfiword_t cword) +{ + int retcode; + flash_sect_t sect = 0; + + retcode = flash_write_cfiword_stub (info, dest, cword, §); + if (retcode) + return retcode;
return flash_full_status_check (info, sect, info->write_tout, "write"); }
#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_stub (flash_info_t * info, ulong dest, uchar * cp, + int len, flash_sect_t *sector) { - flash_sect_t sector; int cnt; - int retcode; + int retcode = 0; void *src = cp; void *dst = (void *)dest; void *dst2 = dst; @@ -943,7 +965,7 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, }
src = cp; - sector = find_sector (info, dest); + *sector = find_sector (info, dest);
switch (info->vendor) { case CFI_CMDSET_INTEL_PROG_REGIONS: @@ -951,17 +973,17 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, case CFI_CMDSET_INTEL_EXTENDED: write_cmd = (info->vendor == CFI_CMDSET_INTEL_PROG_REGIONS) ? FLASH_CMD_WRITE_BUFFER_PROG : FLASH_CMD_WRITE_TO_BUFFER; - flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS); - flash_write_cmd (info, sector, 0, FLASH_CMD_READ_STATUS); - flash_write_cmd (info, sector, 0, write_cmd); - retcode = flash_status_check (info, sector, + flash_write_cmd (info, *sector, 0, FLASH_CMD_CLEAR_STATUS); + flash_write_cmd (info, *sector, 0, FLASH_CMD_READ_STATUS); + flash_write_cmd (info, *sector, 0, write_cmd); + 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 */ cnt = len >> shift; - flash_write_cmd (info, sector, 0, cnt - 1); + flash_write_cmd (info, *sector, 0, cnt - 1); while (cnt-- > 0) { switch (info->portwidth) { case FLASH_CFI_8BIT: @@ -985,11 +1007,8 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, goto out_unmap; } } - flash_write_cmd (info, sector, 0, + 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; @@ -999,11 +1018,11 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, flash_unlock_seq(info,0);
#ifdef CONFIG_FLASH_SPANSION_S29WS_N - offset = ((unsigned long)dst - info->start[sector]) >> shift; + offset = ((unsigned long)dst - info->start[*sector]) >> shift; #endif - flash_write_cmd(info, sector, offset, AMD_CMD_WRITE_TO_BUFFER); + flash_write_cmd(info, *sector, offset, AMD_CMD_WRITE_TO_BUFFER); cnt = len >> shift; - flash_write_cmd(info, sector, offset, cnt - 1); + flash_write_cmd(info, *sector, offset, cnt - 1);
switch (info->portwidth) { case FLASH_CFI_8BIT: @@ -1035,10 +1054,7 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, 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"); + flash_write_cmd (info, *sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM); break;
default: @@ -1050,16 +1066,92 @@ 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) +{ + flash_sect_t sector; + int retcode; + + retcode = flash_write_cfibuffer_stub(info, dest, cp, len, §or); + if (retcode) + return retcode; + return flash_full_status_check (info, sector, + info->buffer_write_tout, + "buffer write"); +} #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) { int rcode = 0; int prot; flash_sect_t sect; + int tmp_rcode;
if (info->flash_id != FLASH_MAN_CFI) { puts ("Can't erase unknown flash type - aborted\n"); @@ -1083,51 +1175,18 @@ 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; + tmp_rcode = flash_sector_erase (info, sect); + if (0 == tmp_rcode) { + if (flash_full_status_check + (info, sect, info->erase_blk_tout, "erase")) { + rcode = 1; + } else if (flash_verbose) + putc ('.'); } - - if (flash_full_status_check - (info, sect, info->erase_blk_tout, "erase")) { - rcode = 1; - } else if (flash_verbose) - putc ('.'); + else + rcode = tmp_rcode; } }
@@ -2135,3 +2194,228 @@ unsigned long flash_init (void)
return (size); } + +#if defined(CONFIG_SYS_FLASH_CFI_NONBLOCK) +/*----------------------------------------------------------------------- + * check if 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_nb (flash_info_t * info, flash_sect_t sector, + ulong tout, char *prompt) +{ + static ulong start; + static ulong stout; + +#if CONFIG_SYS_HZ != 1000 + tout *= CONFIG_SYS_HZ/1000; +#endif + + if (tout){ + stout = tout; + start = get_timer (0); + } + + /* Check for command completion */ + + if (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)); + flash_write_cmd (info, sector, 0, info->cmd_reset); + return ERR_TIMOUT; + } + udelay (1); /* also triggers watchdog */ + 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. + * 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) +{ + int retcode; + + retcode = flash_status_check_nb (info, sector, tout, prompt); + if (retcode == ERR_BUSY) + return retcode; + return flash_full_status_retcode_check (info, sector, prompt, retcode); +} + +int flash_erase_nb (flash_info_t * info, int sector) +{ + int rcode = 0; + flash_sect_t sect; + + sect = sector; + + rcode = flash_sector_erase (info, sect); + if (rcode == 0) + rcode = flash_full_status_check_nb(info, sect, info->erase_blk_tout, "erase"); + return rcode; +} + +static int flash_write_cfiword_nb (flash_info_t * info, ulong dest, + cfiword_t cword) +{ + int retcode; + flash_sect_t sect = 0; + + retcode = flash_write_cfiword_stub (info, dest, cword, §); + if (retcode) + return retcode; + + return flash_full_status_check_nb (info, sect, info->write_tout, "write"); +} + +#ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE +static int flash_write_cfibuffer_nb (flash_info_t * info, ulong dest, uchar * cp, + int len) +{ + int retcode; + flash_sect_t sector; + + retcode = flash_write_cfibuffer_stub (info, dest, cp, len, §or); + if(retcode) + return retcode; + sector = find_sector (info, dest);; + return flash_full_status_check_nb (info, sector, info->buffer_write_tout, + "buffer write"); +} +#endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */ + +/*----------------------------------------------------------------------- + * Copy memory to flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + */ +int write_buff_nb (flash_info_t * info, uchar * src, ulong addr, ulong cnt) +{ + ulong wp; + uchar *p; + int aln; + cfiword_t cword; + int i, rc; +#ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE + int buffered_size; +#endif +#ifdef CONFIG_FLASH_SHOW_PROGRESS + int digit = CONFIG_FLASH_SHOW_PROGRESS; + int scale = 0; + int dots = 0; + + /* + * Suppress if there are fewer than CONFIG_FLASH_SHOW_PROGRESS writes. + */ + if (cnt >= CONFIG_FLASH_SHOW_PROGRESS) { + scale = (int)((cnt + CONFIG_FLASH_SHOW_PROGRESS - 1) / + CONFIG_FLASH_SHOW_PROGRESS); + } +#endif + + /* get lower aligned address */ + wp = (addr & ~(info->portwidth - 1)); + + /* handle unaligned start */ + if ((aln = addr - wp) != 0) { + cword.l = 0; + p = (uchar *)wp; + 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--; + } + for (; (cnt == 0) && (i < info->portwidth); ++i) + flash_add_byte (info, &cword, flash_read8(p + i)); + + rc = flash_write_cfiword_nb (info, wp, cword); + if (rc != 0) + return rc; + + wp += i; + FLASH_SHOW_PROGRESS(scale, dots, digit, i); + } + + /* handle the aligned part */ +#ifdef CONFIG_SYS_FLASH_USE_BUFFER_WRITE + buffered_size = (info->portwidth / info->chipwidth); + buffered_size *= info->buffer_size; + while (cnt >= info->portwidth) { + /* prohibit buffer write when buffer_size is 1 */ + if (info->buffer_size == 1) { + cword.l = 0; + for (i = 0; i < info->portwidth; i++) + flash_add_byte (info, &cword, *src++); + if ((rc = flash_write_cfiword_nb (info, wp, cword)) != 0) + return rc; + wp += info->portwidth; + cnt -= info->portwidth; + continue; + } + + /* write buffer until next buffered_size aligned boundary */ + i = buffered_size - (wp % buffered_size); + if (i > cnt) + i = cnt; + rc = flash_write_cfibuffer_nb (info, wp, src, i); + if ((rc != ERR_OK) && (rc != ERR_BUSY)) + return rc; + i -= i & (info->portwidth - 1); + wp += i; + src += i; + cnt -= i; + if ((rc) != ERR_BUSY) + return rc; + + if (cnt >= info->portwidth) { + rc = flash_full_status_check (info, find_sector (info, wp), + info->buffer_write_tout, + "buffer write"); + if (rc != ERR_OK) + return rc; + } + FLASH_SHOW_PROGRESS(scale, dots, digit, i); + } +#else + while (cnt >= info->portwidth) { + cword.l = 0; + for (i = 0; i < info->portwidth; i++) { + flash_add_byte (info, &cword, *src++); + } + if ((rc = flash_write_cfiword_nb (info, wp, cword)) != 0) + return rc; + wp += info->portwidth; + cnt -= info->portwidth; + FLASH_SHOW_PROGRESS(scale, dots, digit, info->portwidth); + } +#endif /* CONFIG_SYS_FLASH_USE_BUFFER_WRITE */ + + if (cnt == 0) { + return (0); + } + + /* + * handle unaligned tail bytes + */ + cword.l = 0; + p = (uchar *)wp; + for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) { + flash_add_byte (info, &cword, *src++); + --cnt; + } + for (; i < info->portwidth; ++i) + flash_add_byte (info, &cword, flash_read8(p + i)); + + return flash_write_cfiword_nb (info, wp, cword); +} +#endif /* CONFIG_SYS_FLASH_CFI_NONBLOCK */ diff --git a/include/flash.h b/include/flash.h index 8feca1b..7b6fecc 100644 --- a/include/flash.h +++ b/include/flash.h @@ -138,6 +138,9 @@ 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 +#if defined(CONFIG_SYS_FLASH_CFI_NONBLOCK) +#define ERR_BUSY 256 +#endif
/*----------------------------------------------------------------------- * Protection Flags for flash_protect():