]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
sf: Update the qspi dual stacked flash access logic
authorJagannadha Sutradharudu Teki <jaganna@xilinx.com>
Wed, 15 May 2013 17:38:05 +0000 (23:08 +0530)
committerMichal Simek <michal.simek@xilinx.com>
Mon, 27 May 2013 11:21:19 +0000 (13:21 +0200)
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>
drivers/mtd/spi/spansion.c
drivers/mtd/spi/spi_flash.c
drivers/mtd/spi/stmicro.c
drivers/mtd/spi/winbond.c
drivers/spi/zynq_qspips.c
include/spi.h

index 09569ebefef700e83feb713862c20fe79f4180ba..55e079293354ae1ca6399edfdeb07b79a294e03b 100644 (file)
@@ -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;
 }
index 7c8089f4419c8832cc2234c8540b06e219e57148..29162b5432ea887ee0b0ebb752fc3b214897900e 100644 (file)
@@ -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)) {
index eae4227f72f19417d5d8754e03effa9aaf394135..f423f954fb7ca38f0e0c34dacd5e542a2ea93710 100644 (file)
@@ -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;
 }
index d7eb7f1e6303ef3aad3178fe72095a0bd2703a64..91277e3a95b7d50db304b553629fe623c3ad27c7 100644 (file)
@@ -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;
 }
index 5288711ee3e06ab59c2bac7b7bd019fb016759b1..057b289ed348ca181b09aa8c240bc19e7240912b 100644 (file)
@@ -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;
index 7de7ac91c79a22e2ae4a19e788e38ec79047a156..1dcc9aeb8b0e5ccfeac302599955edb692aca4b6 100644 (file)
@@ -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;
 };