]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
Xilinx: ARM: Add QSPIx2 support
authorBrian Hill <brian.hill@xilinx.com>
Mon, 21 Mar 2011 15:04:55 +0000 (09:04 -0600)
committerBrian Hill <brian.hill@xilinx.com>
Mon, 21 Mar 2011 15:04:55 +0000 (09:04 -0600)
 Add QSPIx2 support.
 Note that update Boot ROM requred to boot from images programmed in this
 manner.

 (common) flash driver modifed to lie about total number of sectors, and
 to use 4 byte addressing for memories > 16MB.

board/xilinx/dfe/pele_qspi.c
board/xilinx/dfe/xilinx_qspipss.c
drivers/mtd/spi/stmicro.c
include/configs/xpele.h

index cc61babc8e4599feff382d329a42b93be9889e24..6274bb9d6a57542d81d9b29c833659e3c7e58d92 100644 (file)
@@ -137,7 +137,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
        
        /* Festering sore.
         * Assume that the beginning of a transfer with bits to
-        * transmit must contain a defice command.
+        * transmit must contain a device command.
         */
        if (dout && flags & SPI_XFER_BEGIN) {
                pspi->qspi.master.is_inst = 1;
index fc8973801817f69c76543e9cde68b1488d625c8d..68a46d448b3d6fd53af8963d9fd970ab6a773064 100755 (executable)
@@ -96,7 +96,7 @@ typedef enum irqreturn irqreturn_t;
 
 /*******************************************************************/
 
-#define HACK_WRITE_NO_DELAY
+#undef HACK_WRITE_NO_DELAY
 
 /*
  * Name of this driver
@@ -199,11 +199,11 @@ typedef enum irqreturn irqreturn_t;
 #define xqspipss_write(addr, val)      __raw_writel((val), (addr))
 #else
 static inline
-u32 xqspipss_read(u32 addr)            
+u32 xqspipss_read(void *addr)          
 {                                      
        u32 val;
 
-       val =  XIo_In32(addr);
+       val =  XIo_In32((unsigned)addr);
 #ifdef DEBUG_REG
        printf("xqspipss_read:  addr: 0x%08x = 0x%08x\n",
                addr, val);
@@ -211,13 +211,13 @@ u32 xqspipss_read(u32 addr)
        return val;
 }
 static inline
-void xqspipss_write(u32 addr, u32 val)
+void xqspipss_write(void *addr, u32 val)
 {
 #ifdef DEBUG_REG
        printf("xqspipss_write: addr: 0x%08x = 0x%08x\n",
                addr, val);
 #endif
-       XIo_Out32(addr, val);
+       XIo_Out32((unsigned)addr, val);
 }
 #endif
 
@@ -347,6 +347,11 @@ void xqspipss_init_hw(void __iomem *regs_base)
        config_reg &= 0xFBFFFFFF; /* Set little endian mode of TX FIFO */
        config_reg |= 0x8000FCC1;
        xqspipss_write(regs_base + XQSPIPSS_CONFIG_OFFSET, config_reg);
+
+#ifdef CONFIG_XILINX_PSS_QSPI_USE_DUAL_FLASH
+        xqspipss_write(regs_base + XQSPIPSS_LINEAR_CFG_OFFSET, 0x6400016B);
+#endif
+
        xqspipss_write(regs_base + XQSPIPSS_ENABLE_OFFSET,
                        XQSPIPSS_ENABLE_ENABLE_MASK);
 }
@@ -811,6 +816,32 @@ static int xqspipss_start_transfer(struct spi_device *qspi,
                xqspi->curr_inst = &flash_inst[index];
                xqspi->inst_response = 1;
 
+#ifdef CONFIG_XILINX_PSS_QSPI_USE_DUAL_FLASH
+               /* In case of dual memories, convert 25 bit address to 24 bit
+                * address before transmitting to the 2 memories
+                */
+               if ((instruction == XQSPIPSS_FLASH_OPCODE_PP) ||
+                   (instruction == XQSPIPSS_FLASH_OPCODE_SE) ||
+                   (instruction == XQSPIPSS_FLASH_OPCODE_BE_32K) ||
+                   (instruction == XQSPIPSS_FLASH_OPCODE_BE_4K) ||
+                   (instruction == XQSPIPSS_FLASH_OPCODE_BE) ||
+                   (instruction == XQSPIPSS_FLASH_OPCODE_NORM_READ) ||
+                   (instruction == XQSPIPSS_FLASH_OPCODE_FAST_READ) ||
+                   (instruction == XQSPIPSS_FLASH_OPCODE_DUAL_READ) ||
+                   (instruction == XQSPIPSS_FLASH_OPCODE_QUAD_READ)) {
+
+                       u8 *ptr = (u8*) (xqspi->txbuf);
+                       data = ((u32) ptr[1] << 24) | ((u32) ptr[2] << 16) |
+                               ((u32) ptr[3] << 8) | ((u32) ptr[4]);
+                       data = data/2;
+                       ptr[1] = (u8) (data >> 16);
+                       ptr[2] = (u8) (data >> 8);
+                       ptr[3] = (u8) (data);
+                       xqspi->bytes_to_transfer -= 1;
+                       xqspi->bytes_to_receive -= 1;
+               }
+#endif
+
                /* Get the instruction */
                data = 0;
                xqspipss_copy_write_data(xqspi, &data,
index 7b83c849a7c1e344ae725e468e04dba4308f977f..fe711ea2085fe783d72bc73bdc6febde8a768308 100644 (file)
@@ -74,6 +74,8 @@ struct stmicro_spi_flash_params {
 struct stmicro_spi_flash {
        struct spi_flash flash;
        const struct stmicro_spi_flash_params *params;
+
+       unsigned addr_width;
 };
 
 static inline struct stmicro_spi_flash *to_stmicro_spi_flash(struct spi_flash
@@ -144,8 +146,13 @@ static const struct stmicro_spi_flash_params stmicro_spi_flash_table[] = {
                .idcode = STM_ID_N25Q128,
                .page_size = 256,
                .pages_per_sector = 256,
+#ifdef CONFIG_XILINX_PSS_QSPI_USE_DUAL_FLASH
+               .nr_sectors = 512,
+               .name = "N25Q128x2",
+#else
                .nr_sectors = 256,
                .name = "N25Q128",
+#endif
        },
        {
                .idcode1 = STM_ID_M25P128,
@@ -156,6 +163,27 @@ static const struct stmicro_spi_flash_params stmicro_spi_flash_table[] = {
        },
 };
 
+static inline void stmicro_addr2cmd(struct stmicro_spi_flash *stm,
+                             unsigned page_addr, unsigned byte_addr, u8 *cmd)
+{
+       /* opcode is in cmd[0] */
+       if (stm->addr_width == 4) {
+               cmd[1] = page_addr >> 16;
+               cmd[2] = page_addr >> 8;
+               cmd[3] = page_addr;
+               cmd[4] = byte_addr;
+       } else {
+               cmd[1] = page_addr >> 8;
+               cmd[2] = page_addr;
+               cmd[3] = byte_addr;
+       }
+}
+
+static inline int stmicro_cmdsz(struct stmicro_spi_flash *flash)
+{
+       return 1 + flash->addr_width;
+}
+
 static int stmicro_wait_ready(struct spi_flash *flash, unsigned long timeout)
 {
        struct spi_slave *spi = flash->spi;
@@ -196,18 +224,16 @@ static int stmicro_read_fast(struct spi_flash *flash,
        struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash);
        unsigned long page_addr;
        unsigned long page_size;
-       u8 cmd[5];
+       u8 cmd[6];
 
        page_size = stm->params->page_size;
        page_addr = offset / page_size;
 
        cmd[0] = CMD_READ_ARRAY_FAST;
-       cmd[1] = page_addr >> 8;
-       cmd[2] = page_addr;
-       cmd[3] = offset % page_size;
-       cmd[4] = 0x00;
+       stmicro_addr2cmd(stm, page_addr, offset % page_size, cmd);
+       cmd[stmicro_cmdsz(stm)] = 0x00;
 
-       return spi_flash_read_common(flash, cmd, sizeof(cmd), buf, len);
+       return spi_flash_read_common(flash, cmd, stmicro_cmdsz(stm)+1 , buf, len);
 }
 
 static int stmicro_write(struct spi_flash *flash,
@@ -220,7 +246,7 @@ static int stmicro_write(struct spi_flash *flash,
        size_t chunk_len;
        size_t actual;
        int ret;
-       u8 cmd[4];
+       u8 cmd[5];
 
        page_size = stm->params->page_size;
        page_addr = offset / page_size;
@@ -237,9 +263,7 @@ static int stmicro_write(struct spi_flash *flash,
                chunk_len = min(len - actual, page_size - byte_addr);
 
                cmd[0] = CMD_M25PXX_PP;
-               cmd[1] = page_addr >> 8;
-               cmd[2] = page_addr;
-               cmd[3] = byte_addr;
+               stmicro_addr2cmd(stm, page_addr, byte_addr, cmd);
 
                debug
                    ("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %d\n",
@@ -251,7 +275,7 @@ static int stmicro_write(struct spi_flash *flash,
                        break;
                }
 
-               ret = spi_flash_cmd_write(flash->spi, cmd, 4,
+               ret = spi_flash_cmd_write(flash->spi, cmd, stmicro_cmdsz(stm),
                                          buf + actual, chunk_len);
                if (ret < 0) {
                        debug("SF: STMicro Page Program failed\n");
@@ -281,7 +305,7 @@ int stmicro_erase(struct spi_flash *flash, u32 offset, size_t len)
        unsigned long sector_size;
        size_t actual;
        int ret;
-       u8 cmd[4];
+       u8 cmd[5];
 
        /*
         * This function currently uses sector erase only.
@@ -298,8 +322,6 @@ int stmicro_erase(struct spi_flash *flash, u32 offset, size_t len)
 
        len /= sector_size;
        cmd[0] = CMD_M25PXX_SE;
-       cmd[2] = 0x00;
-       cmd[3] = 0x00;
 
        ret = spi_claim_bus(flash->spi);
        if (ret) {
@@ -309,7 +331,11 @@ int stmicro_erase(struct spi_flash *flash, u32 offset, size_t len)
 
        ret = 0;
        for (actual = 0; actual < len; actual++) {
-               cmd[1] = offset >> 16;
+               unsigned page_addr;
+
+               page_addr = offset / stm->params->page_size;
+               stmicro_addr2cmd(stm, page_addr, 0, cmd);
+
                offset += sector_size;
 
                ret = spi_flash_cmd(flash->spi, CMD_M25PXX_WREN, NULL, 0);
@@ -318,7 +344,7 @@ int stmicro_erase(struct spi_flash *flash, u32 offset, size_t len)
                        break;
                }
 
-               ret = spi_flash_cmd_write(flash->spi, cmd, 4, NULL, 0);
+               ret = spi_flash_cmd_write(flash->spi, cmd, stmicro_cmdsz(stm), NULL, 0);
                if (ret < 0) {
                        debug("SF: STMicro page erase failed\n");
                        break;
@@ -393,6 +419,12 @@ struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode)
        stm->flash.size = params->page_size * params->pages_per_sector
            * params->nr_sectors;
 
+       if (stm->flash.size > 0x1000000) {
+               stm->addr_width = 4;
+       } else {
+               stm->addr_width = 3;
+       } 
+
        printf("SF: Detected %s with page size %u, total ",
               params->name, params->page_size);
        print_size(stm->flash.size, "\n");
index 3c7879fcc49d9810338d39d72b6e7d982ff913df..15b0c0c09a0c4d547ef6f170560ad366b6c4203f 100644 (file)
 #define CONFIG_SF_DEFAULT_SPEED 30000000
 #define CONFIG_SPI_FLASH
 #define CONFIG_CMD_SF
+#define CONFIG_XILINX_PSS_QSPI_USE_DUAL_FLASH
 #ifdef NOTOW_BHILL
 #define CONFIG_SPI_FLASH_ATMEL
 #define CONFIG_SPI_FLASH_SPANSION