From e5720823f6f81a0f3a9e3404dbc37059bf6644f1 Mon Sep 17 00:00:00 2001 From: Thomas Chou Date: Fri, 26 Mar 2010 08:17:00 +0800 Subject: [PATCH] cfi flash: add status polling method for amd flash This patch adds status polling method to offer an alternative to data toggle method for amd flash chips. This patch is needed for nios2 cfi flash interface, where the bus controller performs 4 bytes read cycles for a single byte read instruction. The data toggle method can not detect chip busy status correctly. So we have to poll DQ7, which will be inverted when the chip is busy. This feature is enabled with the config def, CONFIG_SYS_CFI_FLASH_STATUS_POLL Signed-off-by: Thomas Chou Signed-off-by: Stefan Roese --- drivers/mtd/cfi_flash.c | 93 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 86 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c index fdba297c88..15a4220d4f 100644 --- a/drivers/mtd/cfi_flash.c +++ b/drivers/mtd/cfi_flash.c @@ -602,6 +602,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) @@ -749,7 +806,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 @@ -911,9 +973,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: @@ -935,6 +1003,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"); @@ -998,10 +1067,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 ('.'); } } -- 2.39.5