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

Signed-off-by: Atle Nissestad <[EMAIL PROTECTED]>

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

_______________________________________________
uClinux-dev mailing list
[email protected]
http://mailman.uclinux.org/mailman/listinfo/uclinux-dev
This message was resent by [email protected]
To unsubscribe see:
http://mailman.uclinux.org/mailman/options/uclinux-dev

Reply via email to