]> git.sur5r.net Git - u-boot/blobdiff - drivers/spi/cadence_qspi_apb.c
Merge git://git.denx.de/u-boot-fsl-qoriq
[u-boot] / drivers / spi / cadence_qspi_apb.c
index 5e84144940789ae924c0deebf1db35cc0e04748b..e285d3c1e761047cd9562dc0520c5fc6350c5a5f 100644 (file)
@@ -27,8 +27,9 @@
 
 #include <common.h>
 #include <asm/io.h>
-#include <asm/errno.h>
+#include <linux/errno.h>
 #include <wait_bit.h>
+#include <spi.h>
 #include "cadence_qspi.h"
 
 #define CQSPI_REG_POLL_US                      (1) /* 1us */
@@ -45,7 +46,6 @@
 #define CQSPI_INST_TYPE_QUAD                   (2)
 
 #define CQSPI_STIG_DATA_LEN_MAX                        (8)
-#define CQSPI_INDIRECTTRIGGER_ADDR_MASK                (0xFFFFF)
 
 #define CQSPI_DUMMY_CLKS_PER_BYTE              (8)
 #define CQSPI_DUMMY_BYTES_MAX                  (4)
@@ -193,64 +193,6 @@ static unsigned int cadence_qspi_apb_cmd2addr(const unsigned char *addr_buf,
        return addr;
 }
 
-static void cadence_qspi_apb_read_fifo_data(void *dest,
-       const void *src_ahb_addr, unsigned int bytes)
-{
-       unsigned int temp;
-       int remaining = bytes;
-       unsigned int *dest_ptr = (unsigned int *)dest;
-       unsigned int *src_ptr = (unsigned int *)src_ahb_addr;
-
-       while (remaining >= sizeof(dest_ptr)) {
-               *dest_ptr = readl(src_ptr);
-               remaining -= sizeof(src_ptr);
-               dest_ptr++;
-       }
-       if (remaining) {
-               /* dangling bytes */
-               temp = readl(src_ptr);
-               memcpy(dest_ptr, &temp, remaining);
-       }
-
-       return;
-}
-
-/* Read from SRAM FIFO with polling SRAM fill level. */
-static int qspi_read_sram_fifo_poll(const void *reg_base, void *dest_addr,
-                       const void *src_addr,  unsigned int num_bytes)
-{
-       unsigned int remaining = num_bytes;
-       unsigned int retry;
-       unsigned int sram_level = 0;
-       unsigned char *dest = (unsigned char *)dest_addr;
-
-       while (remaining > 0) {
-               retry = CQSPI_REG_RETRY;
-               while (retry--) {
-                       sram_level = CQSPI_GET_RD_SRAM_LEVEL(reg_base);
-                       if (sram_level)
-                               break;
-                       udelay(1);
-               }
-
-               if (!retry) {
-                       printf("QSPI: No receive data after polling for %d times\n",
-                              CQSPI_REG_RETRY);
-                       return -1;
-               }
-
-               sram_level *= CQSPI_FIFO_WIDTH;
-               sram_level = sram_level > remaining ? remaining : sram_level;
-
-               /* Read data from FIFO. */
-               cadence_qspi_apb_read_fifo_data(dest, src_addr, sram_level);
-               dest += sram_level;
-               remaining -= sram_level;
-               udelay(1);
-       }
-       return 0;
-}
-
 void cadence_qspi_apb_controller_enable(void *reg_base)
 {
        unsigned int reg;
@@ -351,8 +293,11 @@ void cadence_qspi_apb_config_baudrate_div(void *reg_base,
        debug("%s: ref_clk %dHz sclk %dHz Div 0x%x\n", __func__,
              ref_clk_hz, sclk_hz, div);
 
-       div = (div & CQSPI_REG_CONFIG_BAUD_MASK) << CQSPI_REG_CONFIG_BAUD_LSB;
-       reg |= div;
+       /* ensure the baud rate doesn't exceed the max value */
+       if (div > CQSPI_REG_CONFIG_BAUD_MASK)
+               div = CQSPI_REG_CONFIG_BAUD_MASK;
+
+       reg |= (div << CQSPI_REG_CONFIG_BAUD_LSB);
        writel(reg, reg_base + CQSPI_REG_CONFIG);
 
        cadence_qspi_apb_controller_enable(reg_base);
@@ -607,7 +552,7 @@ int cadence_qspi_apb_command_write(void *reg_base, unsigned int cmdlen,
 
 /* Opcode + Address (3/4 bytes) + dummy bytes (0-4 bytes) */
 int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
-       unsigned int cmdlen, const u8 *cmdbuf)
+       unsigned int cmdlen, unsigned int rx_width, const u8 *cmdbuf)
 {
        unsigned int reg;
        unsigned int rd_reg;
@@ -631,16 +576,15 @@ int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
                addr_bytes = cmdlen - 1;
 
        /* Setup the indirect trigger address */
-       writel(((u32)plat->ahbbase & CQSPI_INDIRECTTRIGGER_ADDR_MASK),
+       writel((u32)plat->ahbbase,
               plat->regbase + CQSPI_REG_INDIRECTTRIGGER);
 
        /* Configure the opcode */
        rd_reg = cmdbuf[0] << CQSPI_REG_RD_INSTR_OPCODE_LSB;
 
-#if (CONFIG_SPI_FLASH_QUAD == 1)
-       /* Instruction and address at DQ0, data at DQ0-3. */
-       rd_reg |= CQSPI_INST_TYPE_QUAD << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB;
-#endif
+       if (rx_width & SPI_RX_QUAD)
+               /* Instruction and address at DQ0, data at DQ0-3. */
+               rd_reg |= CQSPI_INST_TYPE_QUAD << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB;
 
        /* Get address */
        addr_value = cadence_qspi_apb_cmd2addr(&cmdbuf[1], addr_bytes);
@@ -679,40 +623,84 @@ int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
        return 0;
 }
 
+static u32 cadence_qspi_get_rd_sram_level(struct cadence_spi_platdata *plat)
+{
+       u32 reg = readl(plat->regbase + CQSPI_REG_SDRAMLEVEL);
+       reg >>= CQSPI_REG_SDRAMLEVEL_RD_LSB;
+       return reg & CQSPI_REG_SDRAMLEVEL_RD_MASK;
+}
+
+static int cadence_qspi_wait_for_data(struct cadence_spi_platdata *plat)
+{
+       unsigned int timeout = 10000;
+       u32 reg;
+
+       while (timeout--) {
+               reg = cadence_qspi_get_rd_sram_level(plat);
+               if (reg)
+                       return reg;
+               udelay(1);
+       }
+
+       return -ETIMEDOUT;
+}
+
 int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
-       unsigned int rxlen, u8 *rxbuf)
+       unsigned int n_rx, u8 *rxbuf)
 {
-       unsigned int reg;
+       unsigned int remaining = n_rx;
+       unsigned int bytes_to_read = 0;
+       int ret;
 
-       writel(rxlen, plat->regbase + CQSPI_REG_INDIRECTRDBYTES);
+       writel(n_rx, plat->regbase + CQSPI_REG_INDIRECTRDBYTES);
 
        /* Start the indirect read transfer */
        writel(CQSPI_REG_INDIRECTRD_START_MASK,
               plat->regbase + CQSPI_REG_INDIRECTRD);
 
-       if (qspi_read_sram_fifo_poll(plat->regbase, (void *)rxbuf,
-                                    (const void *)plat->ahbbase, rxlen))
-               goto failrd;
+       while (remaining > 0) {
+               ret = cadence_qspi_wait_for_data(plat);
+               if (ret < 0) {
+                       printf("Indirect write timed out (%i)\n", ret);
+                       goto failrd;
+               }
 
-       /* Check flash indirect controller */
-       reg = readl(plat->regbase + CQSPI_REG_INDIRECTRD);
-       if (!(reg & CQSPI_REG_INDIRECTRD_DONE_MASK)) {
-               reg = readl(plat->regbase + CQSPI_REG_INDIRECTRD);
-               printf("QSPI: indirect completion status error with reg 0x%08x\n",
-                      reg);
+               bytes_to_read = ret;
+
+               while (bytes_to_read != 0) {
+                       bytes_to_read *= CQSPI_FIFO_WIDTH;
+                       bytes_to_read = bytes_to_read > remaining ?
+                                       remaining : bytes_to_read;
+                       /* Handle non-4-byte aligned access to avoid data abort. */
+                       if (((uintptr_t)rxbuf % 4) || (bytes_to_read % 4))
+                               readsb(plat->ahbbase, rxbuf, bytes_to_read);
+                       else
+                               readsl(plat->ahbbase, rxbuf, bytes_to_read >> 2);
+                       rxbuf += bytes_to_read;
+                       remaining -= bytes_to_read;
+                       bytes_to_read = cadence_qspi_get_rd_sram_level(plat);
+               }
+       }
+
+       /* Check indirect done status */
+       ret = wait_for_bit("QSPI", plat->regbase + CQSPI_REG_INDIRECTRD,
+                          CQSPI_REG_INDIRECTRD_DONE_MASK, 1, 10, 0);
+       if (ret) {
+               printf("Indirect read completion error (%i)\n", ret);
                goto failrd;
        }
 
        /* Clear indirect completion status */
        writel(CQSPI_REG_INDIRECTRD_DONE_MASK,
               plat->regbase + CQSPI_REG_INDIRECTRD);
+
        return 0;
 
 failrd:
        /* Cancel the indirect read */
        writel(CQSPI_REG_INDIRECTRD_CANCEL_MASK,
               plat->regbase + CQSPI_REG_INDIRECTRD);
-       return -1;
+       return ret;
 }
 
 /* Opcode + Address (3/4 bytes) */
@@ -728,7 +716,7 @@ int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
                return -EINVAL;
        }
        /* Setup the indirect trigger address */
-       writel(((u32)plat->ahbbase & CQSPI_INDIRECTTRIGGER_ADDR_MASK),
+       writel((u32)plat->ahbbase,
               plat->regbase + CQSPI_REG_INDIRECTTRIGGER);
 
        /* Configure the opcode */