summaryrefslogtreecommitdiff
path: root/drivers/mtd
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0002.c92
1 files changed, 48 insertions, 44 deletions
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index 23175edd5634..51d79223bc71 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -190,9 +190,17 @@ static void fixup_use_write_buffers(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
+ struct cfi_pri_amdstd *extp = cfi->cmdset_priv;
+
if (cfi->cfiq->BufWriteTimeoutTyp) {
DEBUG(MTD_DEBUG_LEVEL1, "Using buffer write method\n" );
mtd->write = cfi_amdstd_write_buffers;
+
+ if (extp->SiliconRevision >= 0x1C) {
+ mtd->writesize = 512;
+ mtd->flags &= ~MTD_BIT_WRITEABLE;
+ printk(KERN_INFO "Enabling Spansion 65nm mode, writesize = 512 bytes\n");
+ }
}
}
@@ -1372,21 +1380,18 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
}
-/*
- * FIXME: interleaved mode not tested, and probably not supported!
- */
static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
unsigned long adr, const u_char *buf,
int len)
{
struct cfi_private *cfi = map->fldrv_priv;
unsigned long timeo = jiffies + HZ;
- /* see comments in do_write_oneword() regarding uWriteTimeo. */
- unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
+ /* see comments in do_write_oneword() regarding uWriteTimeout, 20ms */
+ unsigned long uWriteTimeout = (HZ / 50) + 1;
int ret = -EIO;
unsigned long cmd_adr;
- int z, words;
- map_word datum;
+ int z, words, prolog, epilog, buflen = len;
+ map_word datum, pdat, edat;
adr += chip->start;
cmd_adr = adr;
@@ -1407,6 +1412,21 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
ENABLE_VPP(map);
xip_disable(map, chip, cmd_adr);
+ /* If start is not bus-aligned, prepend old contents of flash */
+ prolog = (adr & (map_bankwidth(map)-1));
+ if (prolog) {
+ adr -= prolog;
+ cmd_adr -= prolog;
+ len += prolog;
+ pdat = map_read(map, adr);
+ }
+ /* If end is not bus-aligned, append old contents of flash */
+ epilog = ((adr + len) & (map_bankwidth(map)-1));
+ if (epilog) {
+ len += map_bankwidth(map)-epilog;
+ edat = map_read(map, adr + len - map_bankwidth(map));
+ }
+
cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
@@ -1420,8 +1440,21 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
map_write(map, CMD(words - 1), cmd_adr);
/* Write data */
z = 0;
+ if (prolog) {
+ datum = map_word_load_partial(map, pdat, buf, prolog,
+ min_t(int, buflen,
+ map_bankwidth(map) - prolog));
+ map_write(map, datum, adr);
+
+ z += map_bankwidth(map);
+ buf += map_bankwidth(map) - prolog;
+ }
while(z < words * map_bankwidth(map)) {
- datum = map_word_load(map, buf);
+ if (epilog && z >= (words-1) * map_bankwidth(map))
+ datum = map_word_load_partial(map, edat,
+ buf, 0, epilog);
+ else
+ datum = map_word_load(map, buf);
map_write(map, datum, adr + z);
z += map_bankwidth(map);
@@ -1470,8 +1503,13 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
/* reset on all failures. */
map_write( map, CMD(0xF0), chip->start );
+ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map,
+ cfi, cfi->device_type, NULL);
+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map,
+ cfi, cfi->device_type, NULL);
+ cfi_send_gen_cmd(0xF0, cfi->addr_unlock1, chip->start, map,
+ cfi, cfi->device_type, NULL);
xip_enable(map, chip, adr);
- /* FIXME - should have reset delay before continuing */
printk(KERN_WARNING "MTD %s(): software timeout\n",
__func__ );
@@ -1503,36 +1541,12 @@ static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,
chipnum = to >> cfi->chipshift;
ofs = to - (chipnum << cfi->chipshift);
- /* If it's not bus-aligned, do the first word write */
- if (ofs & (map_bankwidth(map)-1)) {
- size_t local_len = (-ofs)&(map_bankwidth(map)-1);
- if (local_len > len)
- local_len = len;
- ret = cfi_amdstd_write_words(mtd, ofs + (chipnum<<cfi->chipshift),
- local_len, retlen, buf);
- if (ret)
- return ret;
- ofs += local_len;
- buf += local_len;
- len -= local_len;
-
- if (ofs >> cfi->chipshift) {
- chipnum ++;
- ofs = 0;
- if (chipnum == cfi->numchips)
- return 0;
- }
- }
-
- /* Write buffer is worth it only if more than one word to write... */
- while (len >= map_bankwidth(map) * 2) {
+ while (len) {
/* We must not cross write block boundaries */
int size = wbufsize - (ofs & (wbufsize-1));
if (size > len)
size = len;
- if (size % map_bankwidth(map))
- size -= size % map_bankwidth(map);
ret = do_write_buffer(map, &cfi->chips[chipnum],
ofs, buf, size);
@@ -1552,16 +1566,6 @@ static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,
}
}
- if (len) {
- size_t retlen_dregs = 0;
-
- ret = cfi_amdstd_write_words(mtd, ofs + (chipnum<<cfi->chipshift),
- len, &retlen_dregs, buf);
-
- *retlen += retlen_dregs;
- return ret;
- }
-
return 0;
}