Skip to content
Snippets Groups Projects
Commit 056fbc73 authored by Jagan Teki's avatar Jagan Teki
Browse files

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: default avatarJagannadha Sutradharudu Teki <jaganna@xilinx.com>
parent f77f4691
No related branches found
No related tags found
No related merge requests found
...@@ -54,6 +54,33 @@ SF_DUAL_STACKED_FLASH: ...@@ -54,6 +54,33 @@ SF_DUAL_STACKED_FLASH:
by default, if U_PAGE is unset lower memory should accessible, by default, if U_PAGE is unset lower memory should accessible,
once user wants to access upper memory need to set U_PAGE. 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 Note: Technically there is only one CS line from the controller, but
zynq qspi controller has an internal hw logic to enable additional CS zynq qspi controller has an internal hw logic to enable additional CS
when controller is configured for dual memories. when controller is configured for dual memories.
......
...@@ -119,7 +119,7 @@ static int spi_flash_bank(struct spi_flash *flash, u32 offset) ...@@ -119,7 +119,7 @@ static int spi_flash_bank(struct spi_flash *flash, u32 offset)
u8 bank_sel; u8 bank_sel;
int ret; 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); ret = spi_flash_cmd_bankaddr_write(flash, bank_sel);
if (ret) { if (ret) {
...@@ -142,6 +142,9 @@ static void spi_flash_dual_flash(struct spi_flash *flash, u32 *addr) ...@@ -142,6 +142,9 @@ static void spi_flash_dual_flash(struct spi_flash *flash, u32 *addr)
flash->spi->flags &= ~SPI_XFER_U_PAGE; flash->spi->flags &= ~SPI_XFER_U_PAGE;
} }
break; break;
case SF_DUAL_PARALLEL_FLASH:
*addr >>= flash->shift;
break;
default: default:
debug("SF: Unsupported dual_flash=%d\n", flash->dual_flash); debug("SF: Unsupported dual_flash=%d\n", flash->dual_flash);
break; break;
...@@ -388,7 +391,8 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, ...@@ -388,7 +391,8 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
if (bank_sel < 0) if (bank_sel < 0)
return ret; return ret;
#endif #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) if (len < remain_len)
read_len = len; read_len = len;
else else
......
...@@ -146,19 +146,20 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi, ...@@ -146,19 +146,20 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi,
flash->read = spi_flash_cmd_read_ops; flash->read = spi_flash_cmd_read_ops;
/* Compute the flash size */ /* Compute the flash size */
flash->page_size = (ext_jedec == 0x4d00) ? 512 : 256; flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0;
flash->sector_size = params->sector_size; flash->page_size = ((ext_jedec == 0x4d00) ? 512 : 256) << flash->shift;
flash->size = flash->sector_size * params->nr_sectors; 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) if (flash->dual_flash & SF_DUAL_STACKED_FLASH)
flash->size <<= 1; flash->size <<= 1;
/* Compute erase sector and command */ /* Compute erase sector and command */
if (params->flags & SECT_4K) { if (params->flags & SECT_4K) {
flash->erase_cmd = CMD_ERASE_4K; flash->erase_cmd = CMD_ERASE_4K;
flash->erase_size = 4096; flash->erase_size = 4096 << flash->shift;
} else if (params->flags & SECT_32K) { } else if (params->flags & SECT_32K) {
flash->erase_cmd = CMD_ERASE_32K; flash->erase_cmd = CMD_ERASE_32K;
flash->erase_size = 32768; flash->erase_size = 32768 << flash->shift;
} else { } else {
flash->erase_cmd = CMD_ERASE_64K; flash->erase_cmd = CMD_ERASE_64K;
flash->erase_size = flash->sector_size; flash->erase_size = flash->sector_size;
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
/* SPI bus connection options */ /* SPI bus connection options */
#define SPI_CONN_DUAL_SHARED 1 << 0 #define SPI_CONN_DUAL_SHARED 1 << 0
#define SPI_CONN_DUAL_SEPARATED 1 << 1
/* Header byte that marks the start of the message */ /* Header byte that marks the start of the message */
#define SPI_PREAMBLE_END_BYTE 0xec #define SPI_PREAMBLE_END_BYTE 0xec
...@@ -66,7 +67,7 @@ ...@@ -66,7 +67,7 @@
* @max_write_size: If non-zero, the maximum number of bytes which can * @max_write_size: If non-zero, the maximum number of bytes which can
* be written at once, excluding command bytes. * be written at once, excluding command bytes.
* @memory_map: Address of read-only SPI flash access. * @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. * @flags: Indication of SPI flags.
*/ */
struct spi_slave { struct spi_slave {
......
...@@ -40,6 +40,7 @@ enum spi_read_cmds { ...@@ -40,6 +40,7 @@ enum spi_read_cmds {
enum spi_dual_flash { enum spi_dual_flash {
SF_SINGLE_FLASH = 0, SF_SINGLE_FLASH = 0,
SF_DUAL_STACKED_FLASH = 1 << 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[]; ...@@ -70,7 +71,8 @@ extern const struct spi_flash_params spi_flash_params_table[];
* *
* @spi: SPI slave * @spi: SPI slave
* @name: Name of SPI flash * @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 * @size: Total flash size
* @page_size: Write (page) size * @page_size: Write (page) size
* @sector_size: Sector size * @sector_size: Sector size
...@@ -96,6 +98,7 @@ struct spi_flash { ...@@ -96,6 +98,7 @@ struct spi_flash {
struct spi_slave *spi; struct spi_slave *spi;
const char *name; const char *name;
u8 dual_flash; u8 dual_flash;
u8 shift;
u32 size; u32 size;
u32 page_size; u32 page_size;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment