[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