
From: Ashok Reddy Soma ashok.reddy.soma@xilinx.com
In a dual parallel configuration, halve the read offset. Determine whether the read offset points to the lower or upper flash in a dual stacked configuration and set the corresponding flags accordingly.
Include support for cases where the read involves an odd number of bytes.
Extend support for cross-die reads in flash memory devices that contain multiple dies within them.
Signed-off-by: Ashok Reddy Soma ashok.reddy.soma@xilinx.com Signed-off-by: Michal Simek michal.simek@xilinx.com Signed-off-by: Tejas Bhumkar tejas.arvind.bhumkar@amd.com --- drivers/mtd/spi/spi-nor-core.c | 61 ++++++++++++++++++++++++++++++---- include/spi.h | 3 +- 2 files changed, 56 insertions(+), 8 deletions(-)
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index e505648e5d..f6e7592458 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -1503,11 +1503,8 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, struct spi_nor *nor = mtd_to_spi_nor(mtd); int ret; u32 offset = from; - u32 stack_shift = 0; - u32 read_len = 0; - u32 rem_bank_len = 0; - u8 bank; - u8 is_ofst_odd = 0; + u32 bank_size, stack_shift = 0, read_len = 0, rem_bank_len = 0; + u8 bank, cur_bank, nxt_bank, is_ofst_odd = 0;
dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len);
@@ -1541,6 +1538,40 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, } }
+ if (nor->addr_width == 4) { + /* + * Some flash devices like N25Q512 have multiple dies + * in it. Read operation in these devices is bounded + * by its die segment. In a continuous read, across + * multiple dies, when the last byte of the selected + * die segment is read, the next byte read is the + * first byte of the same die segment. This is Die + * cross over issue. So to handle this issue, split + * a read transaction, that spans across multiple + * banks, into one read per bank. Bank size is 16MB + * for single and dual stacked mode and 32MB for dual + * parallel mode. + */ + if (nor->spi && nor->spi->multi_die) { + bank_size = SZ_16M; + if (nor->flags & SNOR_F_HAS_PARALLEL) + bank_size <<= 1; + cur_bank = offset / bank_size; + nxt_bank = (offset + len) / bank_size; + if (cur_bank != nxt_bank) + rem_bank_len = (bank_size * + (cur_bank + 1)) - + offset; + else + rem_bank_len = (mtd->size >> + stack_shift) - + offset; + } else { + rem_bank_len = (mtd->size >> stack_shift) - + offset; + } + } + if (nor->flags & SNOR_F_HAS_PARALLEL) offset /= 2;
@@ -1552,6 +1583,15 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, #endif }
+ if (len < rem_bank_len) + read_len = len; + else + read_len = rem_bank_len; + + ret = spi_nor_wait_till_ready(nor); + if (ret) + goto read_err; + ret = nor->read(nor, offset, read_len, buf); if (ret == 0) { /* We shouldn't see 0-length reads */ @@ -1561,8 +1601,15 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, if (ret < 0) goto read_err;
- *retlen += ret; - buf += ret; + if (is_ofst_odd == 1) { + memcpy(buf, (buf + 1), (len - 1)); + *retlen += (ret - 1); + buf += ret - 1; + is_ofst_odd = 0; + } else { + *retlen += ret; + buf += ret; + } from += ret; len -= ret; } diff --git a/include/spi.h b/include/spi.h index eb015ecbf5..9014066ee3 100644 --- a/include/spi.h +++ b/include/spi.h @@ -165,7 +165,7 @@ struct spi_slave { unsigned int max_write_size; void *memory_map;
- u8 flags; + u32 flags; #define SPI_XFER_BEGIN BIT(0) /* Assert CS before transfer */ #define SPI_XFER_END BIT(1) /* Deassert CS after transfer */ #define SPI_XFER_ONCE (SPI_XFER_BEGIN | SPI_XFER_END) @@ -179,6 +179,7 @@ struct spi_slave { */ bool multi_cs_cap; u32 bytemode; + bool multi_die; /* flash with multiple dies */ };
/**