summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManoj Chourasia <mchourasia@nvidia.com>2012-03-26 14:40:56 +0530
committerRohan Somvanshi <rsomvanshi@nvidia.com>2012-03-30 09:13:01 -0700
commit4a64b1e3e1e571e5b66719835f2c669cebaa894d (patch)
treee3609cdfff19ea597658a684164e465a3ed35e9b
parent0cb87f8335b7bce04e1851506156f592dfb052be (diff)
mtd: chips: support for the new CFI version 1.5 and write buffer programming
This patch add CFI version 1.5 support. It replaces classic word programming by write buffer programming and sets the FFS write size to 512 bytes. The patch taken from spansion bug 906309 Reviewed-on: http://git-master/r/89412 (cherry picked from commit 733c7ef4b9bdc52ac95095436a5cf83aa0296da5) Change-Id: I63cbd0bad077e055d6efd4e2b4c7d26c608d1b66 Signed-off-by: Manoj Chourasia <mchourasia@nvidia.com> Reviewed-on: http://git-master/r/91307 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Amlan Kundu <akundu@nvidia.com> Reviewed-by: Varun Wadekar <vwadekar@nvidia.com>
-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;
}