diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index bcc2ce67c996..a2b12d347f4d 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -49,6 +49,10 @@ #define SST49LF008A 0x005a #define AT49BV6416 0x00d6 +enum cfi_quirks { + CFI_QUIRK_DQ_TRUE_DATA = BIT(0), +}; + static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); static int cfi_amdstd_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); @@ -361,6 +365,15 @@ static void fixup_s29ns512p_sectors(struct mtd_info *mtd) pr_warning("%s: Bad S29NS512P CFI data; adjust to 512 sectors\n", mtd->name); } +static void fixup_quirks(struct mtd_info *mtd) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + + if (cfi->mfr == CFI_MFR_AMD && cfi->id == 0x0c01) + cfi->quirks |= CFI_QUIRK_DQ_TRUE_DATA; +} + /* Used to fix CFI-Tables of chips without Extended Query Tables */ static struct cfi_fixup cfi_nopri_fixup_table[] = { { CFI_MFR_SST, 0x234a, fixup_sst39vf }, /* SST39VF1602 */ @@ -399,6 +412,7 @@ static struct cfi_fixup cfi_fixup_table[] = { #if !FORCE_WORD_WRITE { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers }, #endif + { CFI_MFR_ANY, CFI_ID_ANY, fixup_quirks }, { 0, 0, NULL } }; static struct cfi_fixup jedec_fixup_table[] = { @@ -756,6 +770,18 @@ static int __xipram chip_ready(struct map_info *map, unsigned long addr, return map_word_equal(map, t, *expected); } +static int __xipram chip_good(struct map_info *map, unsigned long addr, + map_word *expected) +{ + struct cfi_private *cfi = map->fldrv_priv; + map_word *datum = expected; + + if (cfi->quirks & CFI_QUIRK_DQ_TRUE_DATA) + datum = NULL; + + return chip_ready(map, addr, datum); +} + static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode) { DECLARE_WAITQUEUE(wait, current); @@ -1608,11 +1634,11 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, } /* - * We check "time_after" and "!chip_ready" before checking - * "chip_ready" to avoid the failure due to scheduling. + * We check "time_after" and "!chip_good" before checking + * "chip_good" to avoid the failure due to scheduling. */ if (time_after(jiffies, timeo) && - !chip_ready(map, adr, &datum)) { + !chip_good(map, adr, &datum)) { xip_enable(map, chip, adr); printk(KERN_WARNING "MTD %s(): software timeout\n", __func__); xip_disable(map, chip, adr); @@ -1620,7 +1646,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, break; } - if (chip_ready(map, adr, &datum)) + if (chip_good(map, adr, &datum)) break; /* Latency issues. Drop the lock, wait a while and retry */ @@ -1864,13 +1890,13 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, } /* - * We check "time_after" and "!chip_ready" before checking - * "chip_ready" to avoid the failure due to scheduling. + * We check "time_after" and "!chip_good" before checking + * "chip_good" to avoid the failure due to scheduling. */ - if (time_after(jiffies, timeo) && !chip_ready(map, adr, &datum)) + if (time_after(jiffies, timeo) && !chip_good(map, adr, &datum)) break; - if (chip_ready(map, adr, &datum)) { + if (chip_good(map, adr, &datum)) { xip_enable(map, chip, adr); goto op_done; } diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h index 9b57a9b1b081..4ead3d1559f5 100644 --- a/include/linux/mtd/cfi.h +++ b/include/linux/mtd/cfi.h @@ -293,6 +293,7 @@ struct cfi_private { map_word sector_erase_cmd; unsigned long chipshift; /* Because they're of the same type */ const char *im_name; /* inter_module name for cmdset_setup */ + unsigned long quirks; struct flchip chips[0]; /* per-chip data structure for each chip */ };