summaryrefslogtreecommitdiff
path: root/drivers/mtd
diff options
context:
space:
mode:
authorManoj Chourasia <mchourasia@nvidia.com>2012-04-11 19:32:06 +0530
committerVarun Wadekar <vwadekar@nvidia.com>2012-04-11 19:32:37 +0530
commitf0b0dd81bab606a5070839737d89fae6cbca9366 (patch)
tree26ae05ef58f4f50b606c3ac7438a18784a48e7f3 /drivers/mtd
parent239b937581064fe637b1441f9fe91b8f57fd5481 (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> Conflicts: drivers/mtd/chips/cfi_cmdset_0002.c Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
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 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;
}