From: Ashok Reddy Soma <ashok.reddy.s...@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.s...@xilinx.com> Signed-off-by: Michal Simek <michal.si...@xilinx.com> Signed-off-by: Tejas Bhumkar <tejas.arvind.bhum...@amd.com> --- drivers/mtd/spi/spi-nor-core.c | 42 ++++++++++++++++++++++++++++++---- include/spi.h | 3 ++- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index e0398a7a29..ffb9a48316 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -1528,11 +1528,9 @@ 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; - loff_t offset = from; - u32 read_len = 0; - u32 rem_bank_len = 0; - u8 bank; - bool is_ofst_odd = false; + u32 offset = from; + 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); @@ -1565,6 +1563,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; diff --git a/include/spi.h b/include/spi.h index ade30fab73..7b6c49cfc5 100644 --- a/include/spi.h +++ b/include/spi.h @@ -166,7 +166,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) @@ -180,6 +180,7 @@ struct spi_slave { */ bool multi_cs_cap; u32 bytemode; + bool multi_die; /* flash with multiple dies */ }; /** -- 2.27.0