diff options
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/chips/cfi_cmdset_0002.c | 92 |
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 d02592e6a0f0..8336f078601f 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) { pr_debug("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"); + } } } @@ -1359,21 +1367,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; @@ -1394,6 +1399,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); @@ -1407,8 +1427,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); @@ -1457,8 +1490,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__ ); @@ -1487,36 +1525,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); @@ -1536,16 +1550,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; } |