All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH] cfi flash: add status polling method for amd flash
@ 2010-03-23  3:24 Thomas Chou
  2010-03-23 10:12 ` Stefan Roese
                   ` (4 more replies)
  0 siblings, 5 replies; 13+ messages in thread
From: Thomas Chou @ 2010-03-23  3:24 UTC (permalink / raw)
  To: u-boot

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

Include patch, "drivers/mtd/cfi_flash: precision and underflow
problem in tout calculation", submitted by
  Alessandro Rubini <rub...@gnudd.com>
  Renato Andreola <renato.andre...@imagos.it>

Signed-off-by: Thomas Chou <thomas@wytron.com.tw>
---
 drivers/mtd/cfi_flash.c |   78 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 77 insertions(+), 1 deletions(-)

diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c
index fdba297..db22255 100644
--- a/drivers/mtd/cfi_flash.c
+++ b/drivers/mtd/cfi_flash.c
@@ -537,7 +537,10 @@ static int flash_status_check (flash_info_t * info, flash_sect_t sector,
 	ulong start;
 
 #if CONFIG_SYS_HZ != 1000
-	tout *= 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 */
@@ -555,6 +558,53 @@ static int flash_status_check (flash_info_t * info, flash_sect_t sector,
 	return ERR_OK;
 }
 
+#ifdef CONFIG_SYS_CFI_FLASH_STATUS_POLL
+static int flash_status_poll (flash_info_t *info, void *src, void *dst,
+			     ulong tout, char *prompt)
+{
+	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 */
+	}
+	return ERR_OK;
+}
+#endif
+
 /*-----------------------------------------------------------------------
  * Wait for XSR.7 to be set, if it times out print an error, otherwise
  * do a full status check.
@@ -749,6 +799,13 @@ static int flash_write_cfiword (flash_info_t * info, ulong dest,
 	if (!sect_found)
 		sect = find_sector (info, dest);
 
+#ifdef CONFIG_SYS_CFI_FLASH_STATUS_POLL
+	if (info->vendor == CFI_CMDSET_AMD_EXTENDED ||
+	    info->vendor == CFI_CMDSET_AMD_STANDARD)
+		return flash_status_poll (info, &cword, dstaddr,
+					 info->write_tout, "write");
+	else
+#endif
 	return flash_full_status_check (info, sect, info->write_tout, "write");
 }
 
@@ -911,9 +968,14 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
 		}
 
 		flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM);
+#ifdef CONFIG_SYS_CFI_FLASH_STATUS_POLL
+		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");
+#endif
 		break;
 
 	default:
@@ -935,6 +997,10 @@ int flash_erase (flash_info_t * info, int s_first, int s_last)
 	int rcode = 0;
 	int prot;
 	flash_sect_t sect;
+#ifdef CONFIG_SYS_CFI_FLASH_STATUS_POLL
+	cfiword_t cword = (cfiword_t)0xffffffffffffffffULL;
+	void *dest;
+#endif
 
 	if (info->flash_id != FLASH_MAN_CFI) {
 		puts ("Can't erase unknown flash type - aborted\n");
@@ -998,6 +1064,16 @@ int flash_erase (flash_info_t * info, int s_first, int s_last)
 				break;
 			}
 
+#ifdef CONFIG_SYS_CFI_FLASH_STATUS_POLL
+			dest = flash_map (info, sect, 0);
+			flash_unmap (info, sect, 0, dest);
+			if ((info->vendor == CFI_CMDSET_AMD_EXTENDED ||
+			     info->vendor == CFI_CMDSET_AMD_STANDARD) &&
+			    flash_status_poll (info, &cword, dest,
+					      info->erase_blk_tout, "erase"))
+				rcode = 1;
+			else
+#endif
 			if (flash_full_status_check
 			    (info, sect, info->erase_blk_tout, "erase")) {
 				rcode = 1;
-- 
1.6.6.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2010-03-26 10:34 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-03-23  3:24 [U-Boot] [PATCH] cfi flash: add status polling method for amd flash Thomas Chou
2010-03-23 10:12 ` Stefan Roese
2010-03-24  2:37   ` Thomas Chou
2010-03-23 10:39 ` [U-Boot] [Nios2-dev] " Michael Schnell
2010-03-24  2:54   ` Thomas Chou
2010-03-24  2:29 ` [U-Boot] [PATCH v4] " Thomas Chou
2010-03-25  8:43   ` Stefan Roese
2010-03-25 11:49     ` Wolfgang Denk
2010-03-26 10:34       ` Stefan Roese
2010-03-25 11:49   ` Wolfgang Denk
2010-03-25 14:23     ` Thomas Chou
2010-03-25 14:38 ` [U-Boot] [PATCH v5] " Thomas Chou
2010-03-26  0:17 ` [U-Boot] [PATCH v6] " Thomas Chou

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.