Updated the xilinx qspi dual stacked flash access.
Now the two memories were linearly accessable without
need a user interaction for selecting chip select.
Below are the changes for dual stacked to work:
- mtd layer -> nr_sectors/nr_blocks*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@xilinx.com>
flash->page_size = 256;
flash->sector_size = 256 * params->pages_per_sector;
- /* page_size and nr_sectors are double for dual parallel qspi */
+ /*
+ * page_size and nr_sectors are double for dual parallel qspi
+ * and double the nr_sectors for dual stacked qspi
+ */
if (flash->spi->is_dual == 2) {
flash->page_size *= 2;
flash->size = flash->sector_size * (2 * params->nr_sectors);
- } else {
+ } else if (flash->spi->is_dual == 1)
+ flash->size = flash->sector_size * (2 * params->nr_sectors);
+ else
flash->size = flash->sector_size * params->nr_sectors;
- }
return flash;
}
unsigned long flags = SPI_XFER_BEGIN;
int ret;
+ if ((spi->is_dual == 1) && (spi->u_page == 1))
+ flags |= SPI_FLASH_U_PAGE;
+
if (data_len == 0)
flags |= SPI_XFER_END;
cmd[0] = CMD_PAGE_PROGRAM;
for (actual = 0; actual < len; actual += chunk_len) {
+ if (flash->spi->is_dual == 1) {
+ if (offset >= (flash->size / 2))
+ flash->spi->u_page = 1;
+ else
+ flash->spi->u_page = 0;
+ }
+
if (flash->spi->is_dual == 2)
offset /= 2;
bank_sel = offset / SPI_FLASH_16MB_BOUN;
+ if ((flash->spi->is_dual == 1) && (flash->spi->u_page == 1))
+ bank_sel -= ((flash->size / 2) / SPI_FLASH_16MB_BOUN);
ret = spi_flash_cmd_bankaddr_write(flash,
bank_sel, flash->idcode0);
cmd[sizeof(cmd)-1] = 0x00;
while (len) {
+ if (flash->spi->is_dual == 1) {
+ if (offset >= (flash->size / 2))
+ flash->spi->u_page = 1;
+ else
+ flash->spi->u_page = 0;
+ }
+
if (flash->spi->is_dual == 2)
offset /= 2;
bank_sel = offset / SPI_FLASH_16MB_BOUN;
- remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1) - offset);
+ if ((flash->spi->is_dual == 1) && (flash->spi->u_page == 1))
+ bank_sel -= ((flash->size / 2) / SPI_FLASH_16MB_BOUN);
ret = spi_flash_cmd_bankaddr_write(flash,
bank_sel, flash->idcode0);
return ret;
}
+ remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1) - offset);
if (len < remain_len)
read_len = len;
else
u8 cmd, u8 poll_bit)
{
struct spi_slave *spi = flash->spi;
+ unsigned long flags = SPI_XFER_BEGIN;
unsigned long timebase;
int ret;
u8 status;
- ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN);
+ if ((spi->is_dual == 1) && (spi->u_page == 1))
+ flags |= SPI_FLASH_U_PAGE;
+
+ ret = spi_xfer(spi, 8, &cmd, NULL, flags);
if (ret) {
debug("SF: Failed to send command %02x: %d\n", cmd, ret);
return ret;
u8 cmd[4];
u8 bank_sel;
+ start = offset;
+ end = len;
erase_size = flash->sector_size;
if (offset % erase_size || len % erase_size) {
debug("SF: Erase offset/length not multiple of erase size\n");
cmd[0] = CMD_ERASE_4K;
else
cmd[0] = CMD_ERASE_64K;
- start = offset;
- end = start + len;
- while (offset < end) {
+ while (len) {
+ if (flash->spi->is_dual == 1) {
+ if (offset >= (flash->size / 2))
+ flash->spi->u_page = 1;
+ else
+ flash->spi->u_page = 0;
+ }
+
bank_sel = offset / SPI_FLASH_16MB_BOUN;
- if (flash->spi->is_dual == 2)
+ if (((flash->spi->is_dual == 1) && (flash->spi->u_page == 1)) ||
+ (flash->spi->is_dual == 2))
bank_sel -= ((flash->size / 2) / SPI_FLASH_16MB_BOUN);
ret = spi_flash_cmd_bankaddr_write(flash,
goto out;
offset += erase_size;
+ len -= erase_size;
}
- printf("SF: Successfully erased %zu bytes @ %#x\n", len, start);
+ printf("SF: Successfully erased %zu bytes @ %#x\n", end, start);
out:
spi_release_bus(flash->spi);
flash->idcode0 = *idp;
if (((flash->spi->is_dual == 0) &&
(flash->size > SPI_FLASH_16MB_BOUN)) ||
- ((flash->spi->is_dual == 2) &&
+ (((flash->spi->is_dual == 1) ||
+ (flash->spi->is_dual == 2)) &&
((flash->size / 2) > SPI_FLASH_16MB_BOUN))) {
if (spi_flash_cmd_bankaddr_read(flash, &curr_bank,
flash->idcode0)) {
flash->page_size = 256;
flash->sector_size = 256 * params->pages_per_sector;
- /* page_size and nr_sectors are double for dual parallel qspi */
+ /*
+ * page_size and nr_sectors are double for dual parallel qspi
+ * and double the nr_sectors for dual stacked qspi
+ */
if (flash->spi->is_dual == 2) {
flash->page_size *= 2;
flash->size = flash->sector_size * (2 * params->nr_sectors);
- } else {
+ } else if (flash->spi->is_dual == 1)
+ flash->size = flash->sector_size * (2 * params->nr_sectors);
+ else
flash->size = flash->sector_size * params->nr_sectors;
- }
return flash;
}
flash->page_size = 256;
flash->sector_size = 4096;
- /* page_size and nr_blocks are double for dual parallel qspi */
+ /*
+ * page_size and nr_blocks are double for dual parallel qspi
+ * and double the nr_blocks for dual stacked qspi
+ */
if (flash->spi->is_dual == 2) {
flash->page_size *= 2;
flash->size = 4096 * 16 * (2 * params->nr_blocks);
- } else {
+ } else if (flash->spi->is_dual == 1)
+ flash->size = 4096 * 16 * (2 * params->nr_blocks);
+ else
flash->size = 4096 * 16 * params->nr_blocks;
- }
return flash;
}
u8 inst_response;
unsigned int is_inst;
unsigned int is_dual;
+ unsigned int u_page;
};
struct spi_device {
(1 << XQSPIPS_LCFG_DUMMY_SHIFT) |
XQSPIPS_FAST_READ_QOUT_CODE),
&xqspips_base->lcr);
- else if (is_dual == MODE_DUAL_STACKED) {
- if (cs)
- /* Enable two memories on shared buse with upper mem */
- writel((XQSPIPS_LCFG_TWO_MEM_MASK |
- XQSPIPS_LCFG_U_PAGE |
- (1 << XQSPIPS_LCFG_DUMMY_SHIFT) |
- XQSPIPS_FAST_READ_QOUT_CODE),
- &xqspips_base->lcr);
- else
- /* Enable two memories on shared buse with lower mem */
- writel((XQSPIPS_LCFG_TWO_MEM_MASK |
- (1 << XQSPIPS_LCFG_DUMMY_SHIFT) |
- XQSPIPS_FAST_READ_QOUT_CODE),
- &xqspips_base->lcr);
- }
+ else if (is_dual == MODE_DUAL_STACKED)
+ /* Configure two memories on shared bus by enabling lower mem */
+ writel((XQSPIPS_LCFG_TWO_MEM_MASK |
+ (1 << XQSPIPS_LCFG_DUMMY_SHIFT) |
+ XQSPIPS_FAST_READ_QOUT_CODE),
+ &xqspips_base->lcr);
writel(XQSPIPS_ENABLE_ENABLE_MASK, &xqspips_base->enbr);
}
struct spi_transfer *transfer)
{
struct xqspips *xqspi = &qspi->master;
+ static u8 current_u_page;
u32 config_reg;
u32 data = 0;
u8 instruction = 0;
xqspi->curr_inst = &flash_inst[index];
xqspi->inst_response = 1;
+ if ((xqspi->is_dual == MODE_DUAL_STACKED) &&
+ (current_u_page != xqspi->u_page)) {
+ if (xqspi->u_page) {
+ /* Configure two memories on shared bus
+ * by enabling upper mem
+ */
+ writel((XQSPIPS_LCFG_TWO_MEM_MASK |
+ XQSPIPS_LCFG_U_PAGE |
+ (1 << XQSPIPS_LCFG_DUMMY_SHIFT) |
+ XQSPIPS_FAST_READ_QOUT_CODE),
+ &xqspips_base->lcr);
+ } else {
+ /* Configure two memories on shared bus
+ * by enabling lower mem
+ */
+ writel((XQSPIPS_LCFG_TWO_MEM_MASK |
+ (1 << XQSPIPS_LCFG_DUMMY_SHIFT) |
+ XQSPIPS_FAST_READ_QOUT_CODE),
+ &xqspips_base->lcr);
+ }
+
+ current_u_page = xqspi->u_page;
+ }
+
/* Get the instruction */
data = 0;
xqspips_copy_write_data(xqspi, &data,
else
transfer.cs_change = 0;
+ if (flags & SPI_FLASH_U_PAGE)
+ pspi->qspi.master.u_page = 1;
+ else
+ pspi->qspi.master.u_page = 0;
+
transfer.delay_usecs = 0;
transfer.bits_per_word = 32;
transfer.speed_hz = pspi->qspi.max_speed_hz;
/* 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 */
/*-----------------------------------------------------------------------
* Representation of a SPI slave, i.e. what we're communicating with.
* bus: ID of the bus that the slave is attached to.
* cs: ID of the chip select connected to the slave.
* is_dual: Indicates whether dual memories are used
+ * u_page: Indicates the upper memory page, in dual stacked connection.
* max_write_size: If non-zero, the maximum number of bytes which can
* be written at once, excluding command bytes.
*/
unsigned int bus;
unsigned int cs;
unsigned int is_dual;
+ unsigned int u_page;
unsigned int max_write_size;
};