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