diff mbox series

[13/19] mtd: spi-nor: Add support for cross die read in dual flash configuration

Message ID 053fcdc0b80bba53d30b159d788621a9f6361c37.1710098033.git.tejas.arvind.bhumkar@amd.com
State New
Delegated to: Jagannadha Sutradharudu Teki
Headers show
Series Add support for DDR PHY mode | expand

Commit Message

Bhumkar, Tejas Arvind March 11, 2024, 5:22 p.m. UTC
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 | 42 ++++++++++++++++++++++++++++++----
 include/spi.h                  |  3 ++-
 2 files changed, 39 insertions(+), 6 deletions(-)
diff mbox series

Patch

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 */
 };
 
 /**