summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPratyush Yadav <p.yadav@ti.com>2021-04-14 23:53:20 +0530
committerPraneeth Bajjuri <praneeth@ti.com>2021-04-14 13:52:44 -0500
commit37534ef5f25653b42c93ee14d8ac1d933414b0b4 (patch)
treea620d7d168523289d6d76f7bb597bfcb655aa162
parentc1227026a4b8f76a52c6f757f1d066cdc8447c84 (diff)
mtd: spi-nor-core: Do not start or end writes at odd address in DTR mode
On DTR capable flashes like Micron Xcella the writes cannot start or end at an odd address in DTR mode. Extra 0xff bytes need to be prepended or appended respectively to make sure both the start and end addresses are even. Signed-off-by: Pratyush Yadav <p.yadav@ti.com> Reviewed-by: Vignesh Raghavendra <vigneshr@ti.com>
-rw-r--r--drivers/mtd/spi/spi-nor-core.c59
1 files changed, 55 insertions, 4 deletions
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index e411d0e9d1f..488a06b83ac 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -1554,11 +1554,62 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
if (ret < 0)
return ret;
#endif
+
write_enable(nor);
- ret = nor->write(nor, addr, page_remain, buf + i);
- if (ret < 0)
- goto write_err;
- written = ret;
+
+ /*
+ * On DTR capable flashes like Micron Xcella the writes cannot
+ * start or end at an odd address in DTR mode. So we need to
+ * append or prepend extra 0xff bytes to make sure the start
+ * address and end address are even.
+ */
+ if (spi_nor_protocol_is_dtr(nor->write_proto) &&
+ ((addr | page_remain) & 1)) {
+ u_char *tmp;
+ size_t extra_bytes = 0;
+
+ tmp = kmalloc(nor->page_size, 0);
+ if (!tmp) {
+ ret = -ENOMEM;
+ goto write_err;
+ }
+
+ /* Prepend a 0xff byte if the start address is odd. */
+ if (addr & 1) {
+ tmp[0] = 0xff;
+ memcpy(tmp + 1, buf + i, page_remain);
+ addr--;
+ page_remain++;
+ extra_bytes++;
+ } else {
+ memcpy(tmp, buf + i, page_remain);
+ }
+
+ /* Append a 0xff byte if the end address is odd. */
+ if ((addr + page_remain) & 1) {
+ tmp[page_remain + extra_bytes] = 0xff;
+ extra_bytes++;
+ page_remain++;
+ }
+
+ ret = nor->write(nor, addr, page_remain, tmp);
+
+ kfree(tmp);
+
+ if (ret < 0)
+ goto write_err;
+
+ /*
+ * We write extra bytes but they are not part of the
+ * original write.
+ */
+ written = ret - extra_bytes;
+ } else {
+ ret = nor->write(nor, addr, page_remain, buf + i);
+ if (ret < 0)
+ goto write_err;
+ written = ret;
+ }
ret = spi_nor_wait_till_ready(nor);
if (ret)