[uClinux-dev] [PATCH 9/9] nios2: Updates for kernel 2.6.23

Atle Nissestad atle at nissestad.no
Wed Nov 21 05:51:17 EST 2007


Work around the limitations of the Nios2 bus to get MTD CFI flash erase/write to work properly.

Signed-off-by: Atle Nissestad <atle at nissestad.no>

diff --git a/linux-2.6.x/drivers/mtd/chips/cfi_cmdset_0002.c b/linux-2.6.x/drivers/mtd/chips/cfi_cmdset_0002.c
index 1f64458..e85ea1b 100644
--- a/linux-2.6.x/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/linux-2.6.x/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -448,6 +448,7 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd)
  * correctly and is therefore not done	(particulary with interleaved chips
  * as each chip must be checked independantly of the others).
  */
+#ifndef CONFIG_NIOS2
 static int __xipram chip_ready(struct map_info *map, unsigned long addr)
 {
 	map_word d, t;
@@ -457,6 +458,28 @@ static int __xipram chip_ready(struct map_info *map, unsigned long addr)
 
 	return map_word_equal(map, d, t);
 }
+#else
+/* On avalon bus, there is no such a luxury of toggling bit ... 
+ * Use the polling bit, if we know the datum ...
+ */ 
+static int __xipram chip_ready_dq7(struct map_info *map, unsigned long addr, map_word datum)
+{
+	map_word d;
+
+	d = map_read(map, addr);
+
+	return map_word_equal(map, d, datum);
+}
+
+static int __xipram erase_is_done(struct map_info *map, unsigned long addr)
+{
+	map_word d;
+
+	d = map_read(map, addr);
+
+	return (d.x[0] & 0x80);
+}
+#endif
 
 /*
  * Return true if the chip is ready and has the correct value.
@@ -477,10 +500,16 @@ static int __xipram chip_good(struct map_info *map, unsigned long addr, map_word
 {
 	map_word oldd, curd;
 
+#ifndef CONFIG_NIOS2
 	oldd = map_read(map, addr);
+#endif
 	curd = map_read(map, addr);
 
+#ifdef CONFIG_NIOS2
+	return
+#else
 	return	map_word_equal(map, oldd, curd) &&
+#endif
 		map_word_equal(map, curd, expected);
 }
 
@@ -498,8 +527,10 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
 
 	case FL_STATUS:
 		for (;;) {
+#ifndef CONFIG_NIOS2
 			if (chip_ready(map, adr))
 				break;
+#endif
 
 			if (time_after(jiffies, timeo)) {
 				printk(KERN_ERR "Waiting for chip to be ready timed out.\n");
@@ -519,6 +550,12 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
 		return 0;
 
 	case FL_ERASING:
+#ifdef CONFIG_NIOS2
+		/* Because of Avalon bus, it is impossible to tell if a
+		 * sector is suspended or not, better avoid erase suspending
+		 */
+		 	goto sleep;
+#endif
 		if (mode == FL_WRITING) /* FIXME: Erase-suspend-program appears broken. */
 			goto sleep;
 
@@ -542,8 +579,10 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
 		chip->state = FL_ERASE_SUSPENDING;
 		chip->erase_suspended = 1;
 		for (;;) {
+#ifndef CONFIG_NIOS2
 			if (chip_ready(map, adr))
 				break;
+#endif
 
 			if (time_after(jiffies, timeo)) {
 				/* Should have suspended the erase by now.
@@ -995,7 +1034,11 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
 	 * depending of the conditions.	 The ' + 1' is to avoid having a
 	 * timeout of 0 jiffies if HZ is smaller than 1000.
 	 */
+#ifdef CONFIG_NIOS2
+	unsigned long uWriteTimeout = ( HZ / 1000 ) + 2;
+#else
 	unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
+#endif
 	int ret = 0;
 	map_word oldd;
 	int retry_cnt = 0;
@@ -1056,14 +1099,22 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
 			continue;
 		}
 
+#ifdef CONFIG_NIOS2
+		if (time_after(jiffies, timeo) && !chip_ready_dq7(map, adr, datum)){
+#else
 		if (time_after(jiffies, timeo) && !chip_ready(map, adr)){
+#endif
 			xip_enable(map, chip, adr);
 			printk(KERN_WARNING "MTD %s(): software timeout\n", __func__);
 			xip_disable(map, chip, adr);
 			break;
 		}
 
+#ifdef CONFIG_NIOS2
+		if (chip_ready_dq7(map, adr, datum))
+#else
 		if (chip_ready(map, adr))
+#endif
 			break;
 
 		/* Latency issues. Drop the lock, wait a while and retry */
@@ -1242,7 +1293,11 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
 	struct cfi_private *cfi = map->fldrv_priv;
 	unsigned long timeo = jiffies + HZ;
 	/* see comments in do_write_oneword() regarding uWriteTimeo. */
+#ifdef CONFIG_NIOS2
+	unsigned long uWriteTimeout = ( HZ / 1000 ) + 2;
+#else
 	unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
+#endif
 	int ret = -EIO;
 	unsigned long cmd_adr;
 	int z, words;
@@ -1317,10 +1372,18 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
 			continue;
 		}
 
+#ifdef CONFIG_NIOS2
+		if (time_after(jiffies, timeo) && !chip_ready_dq7(map, adr, datum))
+#else
 		if (time_after(jiffies, timeo) && !chip_ready(map, adr))
+#endif
 			break;
 
+#ifdef CONFIG_NIOS2
+		if (chip_ready_dq7(map, adr, datum)) {
+#else
 		if (chip_ready(map, adr)) {
+#endif
 			xip_enable(map, chip, adr);
 			goto op_done;
 		}
@@ -1490,7 +1553,11 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)
 			chip->erase_suspended = 0;
 		}
 
+#ifdef CONFIG_NIOS2
+		if (erase_is_done(map, adr))
+#else
 		if (chip_ready(map, adr))
+#endif
 			break;
 
 		if (time_after(jiffies, timeo)) {
@@ -1526,6 +1593,9 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
 	unsigned long timeo = jiffies + HZ;
 	DECLARE_WAITQUEUE(wait, current);
 	int ret = 0;
+#ifdef CONFIG_NIOS2
+	int altera_retried = 0;
+#endif
 
 	adr += chip->start;
 
@@ -1539,6 +1609,10 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
 	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n",
 	       __func__, adr );
 
+#ifdef CONFIG_NIOS2
+/* the erase sometimes needs a second try on altera platforms */
+altera_retry:
+#endif
 	XIP_INVAL_CACHED_RANGE(map, adr, len);
 	ENABLE_VPP(map);
 	xip_disable(map, chip, adr);
@@ -1578,7 +1652,11 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
 			chip->erase_suspended = 0;
 		}
 
+#ifdef CONFIG_NIOS2
+		if (erase_is_done(map, adr)) {
+#else
 		if (chip_ready(map, adr)) {
+#endif
 			xip_enable(map, chip, adr);
 			break;
 		}
@@ -1593,6 +1671,17 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
 		/* Latency issues. Drop the lock, wait a while and retry */
 		UDELAY(map, chip, adr, 1000000/HZ);
 	}
+
+#ifdef CONFIG_NIOS2
+	/* give altera's platform a second chance */
+	if (!altera_retried) {
+		altera_retried=1;
+		/* reset on all failures. */
+		map_write( map, CMD(0xF0), chip->start );
+		goto altera_retry;
+	}
+#endif
+
 	/* Did we succeed? */
 	if (!chip_good(map, adr, map_word_ff(map))) {
 		/* reset on all failures. */
-- 
1.5.3.2



More information about the uClinux-dev mailing list