[U-Boot] [PATCH 3/5] sf: Add support for accessing dual stacked memories

Jagannadha Sutradharudu Teki jagannadha.sutradharudu-teki at xilinx.com
Mon Jul 29 17:23:41 CEST 2013


This patch added support for accessing dual memories in
stacked connections with single chipselect line from controller.
this connection mode is implemented in xilinx zynq qspi controller.

For more info, see doc/README.spi-flash-conn-modes

Below are the changes for dual stacked to work:
- mtd layer -> sector_size*2, update the U_PAGE flag
  when memory change happen.
- driver -> on LQSPI_CFG, Enable TWO_MEM[BIT:30] on LQSPI_CFG
  Enable U_PAGE[BIT:28] if U_PAGE flag set - upper memory
  Disable U_PAGE[BIT:28] if U_PAGE flag unset - lower memory

Signed-off-by: Jagannadha Sutradharudu Teki <jaganna at xilinx.com>
---
 doc/README.spi-flash-conn-modes | 36 ++++++++++++++++++++++++++++++++++++
 drivers/mtd/spi/spi_flash.c     | 30 ++++++++++++++++++++++++++++--
 include/spi.h                   |  3 +++
 include/spi_flash.h             |  1 +
 4 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/doc/README.spi-flash-conn-modes b/doc/README.spi-flash-conn-modes
index f0c94b7..ab03b22 100644
--- a/doc/README.spi-flash-conn-modes
+++ b/doc/README.spi-flash-conn-modes
@@ -63,6 +63,42 @@ Note: Technically there is only one CS line from the controller, but
 zynq qspi controller has an internal hw logic to enable additional CS
 when controller is configured for dual memories.
 
+SPI_FLASH_CONN_DUALSTACKED:
+	- dual spi/qspi flash memories are connected with a single chipselect
+	  line and these two memories are operating stacked fasion with shared buses.
+	- xilinx zynq qspi controller has implemented this feature.
+	  see trm for more info
+	  http://www.xilinx.com/support/documentation/user_guides/ug585-Zynq-7000-TRM.pdf
+
+  +-------------+        CS		+---------------+
+  |		|---------------------->|		|
+  | 		|              I0[3:0]	| Upper Flash	|
+  | 		|	     +=========>| memory	|
+  |		|	     | 	   CLK	| (SPI/QSPI)	|
+  |		|	     |	  +---->|		|
+  | Controller	|	 CS  |	  |	+---------------+
+  | SPI/QSPI	|------------|----|---->|		|
+  | 		|    I0[3:0] | 	  |	| Lower Flash	|
+  | 		|<===========+====|====>| memory	|
+  |		|	   CLK	  |	| (SPI/QSPI)	|
+  |		|-----------------+---->|		|
+  +-------------+			+---------------+
+
+	- two memory flash devices should has same hw part attributes (like size,
+	  vendor..etc)
+	- Configurations:
+		on LQSPI_CFG register, Enable TWO_MEM[BIT:30] on LQSPI_CFG
+		Enable U_PAGE[BIT:28] if U_PAGE flag set - upper memory
+		Disable U_PAGE[BIT:28] if U_PAGE flag unset - lower memory
+	- Operation:
+		accessing memories serially like one after another.
+		by default, if U_PAGE is unset lower memory sould accessible,
+		once user wants to access upper memory need to set U_PAGE.
+
+Note: Technically there is only one CS line from the controller, but
+zynq qspi controller has an internal hw logic to enable additional CS
+when controller is configured for dual memories.
+
 --
 Jagannadha Sutradharudu Teki <jaganna at xilinx.com>
 29-07-2013.
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 3ed90bd..f7443fa 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -34,6 +34,9 @@ static int spi_flash_read_write(struct spi_slave *spi,
 	unsigned long flags = SPI_XFER_BEGIN;
 	int ret;
 
+	if ((spi->is_dual == SPI_FLASH_CONN_DUALSTACKED) && (spi->u_page == 1))
+		flags |= SPI_FLASH_U_PAGE;
+
 	if (data_len == 0)
 		flags |= SPI_XFER_END;
 
@@ -176,6 +179,13 @@ int spi_flash_cmd_erase(struct spi_flash *flash, u32 offset, size_t len)
 		erase_addr = offset;
 		if (is_dual == SPI_FLASH_CONN_DUALPARALLEL)
 			erase_addr /= 2;
+
+		if (is_dual == SPI_FLASH_CONN_DUALSTACKED) {
+			if (erase_addr >= (flash->size / 2))
+				flash->spi->u_page = 1;
+			else
+				flash->spi->u_page = 0;
+		}
 #ifdef CONFIG_SPI_FLASH_BAR
 		u8 bank_sel;
 
@@ -221,6 +231,13 @@ int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset,
 		write_addr = offset;
 		if (is_dual == SPI_FLASH_CONN_DUALPARALLEL)
 			write_addr /= 2;
+
+		if (is_dual == SPI_FLASH_CONN_DUALSTACKED) {
+			if (write_addr >= (flash->size / 2))
+				flash->spi->u_page = 1;
+			else
+				flash->spi->u_page = 0;
+		}
 #ifdef CONFIG_SPI_FLASH_BAR
 		u8 bank_sel;
 
@@ -304,6 +321,13 @@ int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset,
 		read_addr = offset;
 		if (is_dual == SPI_FLASH_CONN_DUALPARALLEL)
 			read_addr /= 2;
+
+		if (is_dual == SPI_FLASH_CONN_DUALSTACKED) {
+			if (read_addr >= (flash->size / 2))
+				flash->spi->u_page = 1;
+			else
+				flash->spi->u_page = 0;
+		}
 #ifdef CONFIG_SPI_FLASH_BAR
 		bank_sel = read_addr / SPI_FLASH_16MB_BOUN;
 
@@ -398,7 +422,8 @@ int spi_flash_bank_config(struct spi_flash *flash, u8 idcode0)
 	cmd = flash->bank_read_cmd;
 	if (((flash->spi->is_dual == SPI_FLASH_CONN_SINGLE) &&
 			(flash->size > SPI_FLASH_16MB_BOUN)) ||
-			((flash->spi->is_dual == SPI_FLASH_CONN_DUALPARALLEL) &&
+			(((flash->spi->is_dual == SPI_FLASH_CONN_DUALSTACKED) ||
+			(flash->spi->is_dual == SPI_FLASH_CONN_DUALPARALLEL)) &&
 			((flash->size / 2) > SPI_FLASH_16MB_BOUN))) {
 		if (spi_flash_read_common(flash, &cmd, 1, &curr_bank, 1)) {
 			debug("SF: fail to read bank addr register\n");
@@ -582,7 +607,8 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
 #ifndef CONFIG_SPI_FLASH_BAR
 	if (((flash->spi->is_dual == SPI_FLASH_CONN_SINGLE) &&
 			(flash->size > SPI_FLASH_16MB_BOUN)) ||
-			((flash->spi->is_dual == SPI_FLASH_CONN_DUALPARALLEL) &&
+			(((flash->spi->is_dual == SPI_FLASH_CONN_DUALSTACKED) ||
+			(flash->spi->is_dual == SPI_FLASH_CONN_DUALPARALLEL)) &&
 			((flash->size / 2) > SPI_FLASH_16MB_BOUN))) {
 		puts("SF: Warning - Only lower 16MiB accessible for given");
 		puts("device, Full access #define CONFIG_SPI_FLASH_BAR\n");
diff --git a/include/spi.h b/include/spi.h
index bb242bd..d8756ce 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -27,6 +27,7 @@
 /* SPI transfer flags */
 #define SPI_XFER_BEGIN	0x01			/* Assert CS before transfer */
 #define SPI_XFER_END	0x02			/* Deassert CS after transfer */
+#define SPI_FLASH_U_PAGE	0x04		/* Enable Upper memory page */
 
 /* Header byte that marks the start of the message */
 #define SPI_PREAMBLE_END_BYTE	0xec
@@ -41,12 +42,14 @@
  *   max_write_size:	If non-zero, the maximum number of bytes which can
  *		be written at once, excluding command bytes.
  *   is_dual:	Indicates whether dual memories are used.
+ *   u_page:	Indicates the upper memory page, in dual stacked connection.
  */
 struct spi_slave {
 	unsigned int	bus;
 	unsigned int	cs;
 	unsigned int max_write_size;
 	int	is_dual;
+	u8	u_page;
 };
 
 /*-----------------------------------------------------------------------
diff --git a/include/spi_flash.h b/include/spi_flash.h
index fb132ab..a58bf69 100644
--- a/include/spi_flash.h
+++ b/include/spi_flash.h
@@ -21,6 +21,7 @@
 enum spi_conn_modes {
 	SPI_FLASH_CONN_UNKNOWN = -1,
 	SPI_FLASH_CONN_SINGLE,
+	SPI_FLASH_CONN_DUALSTACKED,
 	SPI_FLASH_CONN_DUALPARALLEL,
 };
 
-- 
1.8.3




More information about the U-Boot mailing list