Browse Source

sf: Add dual memories support - DUAL_PARALLEL

This patch added support for accessing dual memories in
parallel connection with single chipselect line from controller.

For more info - see doc/SPI/README.dual-flash

Signed-off-by: Jagannadha Sutradharudu Teki <jaganna@xilinx.com>
Jagannadha Sutradharudu Teki 10 years ago
parent
commit
056fbc73d5
5 changed files with 45 additions and 9 deletions
  1. 27 0
      doc/SPI/README.dual-flash
  2. 6 2
      drivers/mtd/spi/sf_ops.c
  3. 6 5
      drivers/mtd/spi/sf_probe.c
  4. 2 1
      include/spi.h
  5. 4 1
      include/spi_flash.h

+ 27 - 0
doc/SPI/README.dual-flash

@@ -54,6 +54,33 @@ SF_DUAL_STACKED_FLASH:
                by default, if U_PAGE is unset lower memory should accessible,
                once user wants to access upper memory need to set U_PAGE.
 
+SPI_FLASH_CONN_DUALPARALLEL:
+	- dual spi/qspi flash memories are connected with a single chipselect
+	  line and these two memories are operating parallel with separate buses.
+	- xilinx zynq qspi controller has implemented this feature [1]
+
+  +-------------+           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:
+		Need to enable SEP_BUS[BIT:29],TWO_MEM[BIT:30] on LQSPI_CFG register.
+	- Operation:
+		Even bits, i.e. bit 0, 2, 4 ., of a data word is located in the lower memory
+		and odd bits, i.e. bit 1, 3, 5, ., of a data word is located in the upper memory.
+
 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.

+ 6 - 2
drivers/mtd/spi/sf_ops.c

@@ -119,7 +119,7 @@ static int spi_flash_bank(struct spi_flash *flash, u32 offset)
 	u8 bank_sel;
 	int ret;
 
-	bank_sel = offset / SPI_FLASH_16MB_BOUN;
+	bank_sel = offset / (SPI_FLASH_16MB_BOUN << flash->shift);
 
 	ret = spi_flash_cmd_bankaddr_write(flash, bank_sel);
 	if (ret) {
@@ -142,6 +142,9 @@ static void spi_flash_dual_flash(struct spi_flash *flash, u32 *addr)
 			flash->spi->flags &= ~SPI_XFER_U_PAGE;
 		}
 		break;
+	case SF_DUAL_PARALLEL_FLASH:
+		*addr >>= flash->shift;
+		break;
 	default:
 		debug("SF: Unsupported dual_flash=%d\n", flash->dual_flash);
 		break;
@@ -388,7 +391,8 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
 		if (bank_sel < 0)
 			return ret;
 #endif
-		remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1)) - offset;
+		remain_len = ((SPI_FLASH_16MB_BOUN << flash->shift) *
+				(bank_sel + 1)) - offset;
 		if (len < remain_len)
 			read_len = len;
 		else

+ 6 - 5
drivers/mtd/spi/sf_probe.c

@@ -146,19 +146,20 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi,
 	flash->read = spi_flash_cmd_read_ops;
 
 	/* Compute the flash size */
-	flash->page_size = (ext_jedec == 0x4d00) ? 512 : 256;
-	flash->sector_size = params->sector_size;
-	flash->size = flash->sector_size * params->nr_sectors;
+	flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0;
+	flash->page_size = ((ext_jedec == 0x4d00) ? 512 : 256) << flash->shift;
+	flash->sector_size = params->sector_size << flash->shift;
+	flash->size = flash->sector_size * params->nr_sectors << flash->shift;
 	if (flash->dual_flash & SF_DUAL_STACKED_FLASH)
 		flash->size <<= 1;
 
 	/* Compute erase sector and command */
 	if (params->flags & SECT_4K) {
 		flash->erase_cmd = CMD_ERASE_4K;
-		flash->erase_size = 4096;
+		flash->erase_size = 4096 << flash->shift;
 	} else if (params->flags & SECT_32K) {
 		flash->erase_cmd = CMD_ERASE_32K;
-		flash->erase_size = 32768;
+		flash->erase_size = 32768 << flash->shift;
 	} else {
 		flash->erase_cmd = CMD_ERASE_64K;
 		flash->erase_size = flash->sector_size;

+ 2 - 1
include/spi.h

@@ -47,6 +47,7 @@
 
 /* SPI bus connection options */
 #define SPI_CONN_DUAL_SHARED	1 << 0
+#define SPI_CONN_DUAL_SEPARATED	1 << 1
 
 /* Header byte that marks the start of the message */
 #define SPI_PREAMBLE_END_BYTE	0xec
@@ -66,7 +67,7 @@
  * @max_write_size:	If non-zero, the maximum number of bytes which can
  *			be written at once, excluding command bytes.
  * @memory_map:		Address of read-only SPI flash access.
- * @option:		Varies SPI bus options - separate bus.
+ * @option:		Varies SPI bus options - separate, shared bus.
  * @flags:		Indication of SPI flags.
  */
 struct spi_slave {

+ 4 - 1
include/spi_flash.h

@@ -40,6 +40,7 @@ enum spi_read_cmds {
 enum spi_dual_flash {
 	SF_SINGLE_FLASH = 0,
 	SF_DUAL_STACKED_FLASH = 1 << 0,
+	SF_DUAL_PARALLEL_FLASH = 1 << 1,
 };
 
 /**
@@ -70,7 +71,8 @@ extern const struct spi_flash_params spi_flash_params_table[];
  *
  * @spi:		SPI slave
  * @name:		Name of SPI flash
- * @dual_flash:		Indicates dual flash memories - dual stacked
+ * @dual_flash:		Indicates dual flash memories - dual stacked, parallel
+ * @shift:		Flash shift useful in dual parallel
  * @size:		Total flash size
  * @page_size:		Write (page) size
  * @sector_size:	Sector size
@@ -96,6 +98,7 @@ struct spi_flash {
 	struct spi_slave *spi;
 	const char *name;
 	u8 dual_flash;
+	u8 shift;
 
 	u32 size;
 	u32 page_size;