From: Jagannadha Sutradharudu Teki Date: Wed, 15 May 2013 17:38:05 +0000 (+0530) Subject: sf: Update the qspi dual stacked flash access logic X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=9340bc55b8c0c3b4b65adadf4222244b53c97ad1;p=thirdparty%2Fu-boot.git sf: Update the qspi dual stacked flash access logic 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 --- diff --git a/drivers/mtd/spi/spansion.c b/drivers/mtd/spi/spansion.c index 09569ebefef..55e07929335 100644 --- a/drivers/mtd/spi/spansion.c +++ b/drivers/mtd/spi/spansion.c @@ -144,13 +144,17 @@ struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode) 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; } diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index 7c8089f4419..29162b5432e 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -35,6 +35,9 @@ static int spi_flash_read_write(struct spi_slave *spi, 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; @@ -90,10 +93,19 @@ int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset, 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); @@ -173,11 +185,19 @@ int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, 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); @@ -186,6 +206,7 @@ int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, return ret; } + remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1) - offset); if (len < remain_len) read_len = len; else @@ -215,11 +236,15 @@ int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, 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; @@ -262,6 +287,8 @@ int spi_flash_cmd_erase(struct spi_flash *flash, u32 offset, size_t len) 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"); @@ -278,12 +305,18 @@ int spi_flash_cmd_erase(struct spi_flash *flash, u32 offset, size_t len) 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, @@ -312,9 +345,10 @@ int spi_flash_cmd_erase(struct spi_flash *flash, u32 offset, size_t len) 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); @@ -569,7 +603,8 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, 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)) { diff --git a/drivers/mtd/spi/stmicro.c b/drivers/mtd/spi/stmicro.c index eae4227f72f..f423f954fb7 100644 --- a/drivers/mtd/spi/stmicro.c +++ b/drivers/mtd/spi/stmicro.c @@ -209,13 +209,17 @@ struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode) 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; } diff --git a/drivers/mtd/spi/winbond.c b/drivers/mtd/spi/winbond.c index d7eb7f1e630..91277e3a95b 100644 --- a/drivers/mtd/spi/winbond.c +++ b/drivers/mtd/spi/winbond.c @@ -111,13 +111,17 @@ struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode) 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; } diff --git a/drivers/spi/zynq_qspips.c b/drivers/spi/zynq_qspips.c index 5288711ee3e..057b289ed34 100644 --- a/drivers/spi/zynq_qspips.c +++ b/drivers/spi/zynq_qspips.c @@ -161,6 +161,7 @@ struct xqspips { u8 inst_response; unsigned int is_inst; unsigned int is_dual; + unsigned int u_page; }; struct spi_device { @@ -273,21 +274,12 @@ static void xqspips_init_hw(int is_dual, unsigned int cs) (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); } @@ -626,6 +618,7 @@ static int xqspips_start_transfer(struct spi_device *qspi, struct spi_transfer *transfer) { struct xqspips *xqspi = &qspi->master; + static u8 current_u_page; u32 config_reg; u32 data = 0; u8 instruction = 0; @@ -657,6 +650,30 @@ static int xqspips_start_transfer(struct spi_device *qspi, 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, @@ -1026,6 +1043,11 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, 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; diff --git a/include/spi.h b/include/spi.h index 7de7ac91c79..1dcc9aeb8b0 100644 --- a/include/spi.h +++ b/include/spi.h @@ -41,6 +41,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 */ /*----------------------------------------------------------------------- * Representation of a SPI slave, i.e. what we're communicating with. @@ -50,6 +51,7 @@ * 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. */ @@ -57,6 +59,7 @@ struct spi_slave { unsigned int bus; unsigned int cs; unsigned int is_dual; + unsigned int u_page; unsigned int max_write_size; };