]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
spi: cadence_qspi: Add support for DMA reads
authorSiva Durga Prasad Paladugu <siva.durga.paladugu@xilinx.com>
Sat, 11 Aug 2018 08:52:37 +0000 (14:22 +0530)
committerMichal Simek <michal.simek@xilinx.com>
Wed, 27 Feb 2019 07:50:38 +0000 (08:50 +0100)
This patch adds support for DMA read operation if controller
supports it which is determined by reading DT property "cdns,is-dma".
This patch provides hooks for vendor specific DMA routines as the
cadence qspi controller supports external DMA which is vendor specific.

Signed-off-by: Siva Durga Prasad Paladugu <siva.durga.paladugu@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
drivers/spi/cadence_qspi.c
drivers/spi/cadence_qspi.h
drivers/spi/cadence_qspi_apb.c

index 11fce9c4fe5c73d22b68b884195a6dbe3b1f016a..17b1932445e5a4ee5d122da8fc8e73b5af2bbfb1 100644 (file)
@@ -291,6 +291,7 @@ static int cadence_spi_ofdata_to_platdata(struct udevice *bus)
        plat->fifo_width = fdtdec_get_uint(blob, node, "cdns,fifo-width", 4);
        plat->trigger_address = fdtdec_get_uint(blob, node,
                                                "cdns,trigger-address", 0);
+       plat->is_dma = fdtdec_get_bool(blob, node, "cdns,is-dma");
 
        /* All other paramters are embedded in the child node */
        subnode = fdt_first_subnode(blob, node);
index 055900def001ffe2e6a1d76cfdbb5534b31fc5c3..233793d4dcee6e23bf9a5e10316b34a7cdc974e9 100644 (file)
@@ -29,6 +29,7 @@ struct cadence_spi_platdata {
        u32             tsd2d_ns;
        u32             tchsh_ns;
        u32             tslch_ns;
+       bool            is_dma;
 };
 
 struct cadence_spi_priv {
@@ -76,5 +77,8 @@ void cadence_qspi_apb_delay(void *reg_base,
 void cadence_qspi_apb_enter_xip(void *reg_base, char xip_dummy);
 void cadence_qspi_apb_readdata_capture(void *reg_base,
        unsigned int bypass, unsigned int delay);
+void cadence_qspi_apb_dma_read(struct cadence_spi_platdata *plat,
+                              unsigned int n_rx, u8 *rxbuf);
+int cadence_qspi_apb_wait_for_dma_cmplt(struct cadence_spi_platdata *plat);
 
 #endif /* __CADENCE_QSPI_H__ */
index a8af3520303537e734405f23f633019e70a7fc0e..e7b67c91bd355073e93c148d33b9854b46dd903d 100644 (file)
@@ -56,6 +56,7 @@
 #define        CQSPI_REG_CONFIG_CLK_PHA                BIT(2)
 #define        CQSPI_REG_CONFIG_DIRECT                 BIT(7)
 #define        CQSPI_REG_CONFIG_DECODE                 BIT(9)
+#define        CQSPI_REG_CONFIG_ENBL_DMA               BIT(15)
 #define        CQSPI_REG_CONFIG_XIP_IMM                BIT(18)
 #define        CQSPI_REG_CONFIG_CHIPSELECT_LSB         10
 #define        CQSPI_REG_CONFIG_BAUD_LSB               19
        (((readl(reg_base + CQSPI_REG_SDRAMLEVEL)) >>   \
        CQSPI_REG_SDRAMLEVEL_WR_LSB) & CQSPI_REG_SDRAMLEVEL_WR_MASK)
 
+__weak void cadence_qspi_apb_dma_read(struct cadence_spi_platdata *plat,
+                                     unsigned int n_rx, u8 *rxbuf)
+{
+}
+
+__weak
+int cadence_qspi_apb_wait_for_dma_cmplt(struct cadence_spi_platdata *plat)
+{
+       return 0;
+}
+
 static unsigned int cadence_qspi_apb_cmd2addr(const unsigned char *addr_buf,
        unsigned int addr_width)
 {
@@ -398,6 +410,13 @@ void cadence_qspi_apb_controller_init(struct cadence_spi_platdata *plat)
        /* Disable all interrupts */
        writel(0, plat->regbase + CQSPI_REG_IRQMASK);
 
+       reg = readl(plat->regbase + CQSPI_REG_CONFIG);
+       reg &= ~CQSPI_REG_CONFIG_DIRECT;
+       if (plat->is_dma)
+               reg |= CQSPI_REG_CONFIG_ENBL_DMA;
+
+       writel(reg, plat->regbase + CQSPI_REG_CONFIG);
+
        cadence_qspi_apb_controller_enable(plat->regbase);
 }
 
@@ -631,10 +650,20 @@ int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
 
        writel(n_rx, plat->regbase + CQSPI_REG_INDIRECTRDBYTES);
 
+       if (plat->is_dma)
+               cadence_qspi_apb_dma_read(plat, n_rx, rxbuf);
+
        /* Start the indirect read transfer */
        writel(CQSPI_REG_INDIRECTRD_START,
               plat->regbase + CQSPI_REG_INDIRECTRD);
 
+       if (plat->is_dma) {
+               ret = cadence_qspi_apb_wait_for_dma_cmplt(plat);
+               if (ret)
+                       return ret;
+               goto rd_done;
+       }
+
        while (remaining > 0) {
                ret = cadence_qspi_wait_for_data(plat);
                if (ret < 0) {
@@ -663,6 +692,7 @@ int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
                }
        }
 
+rd_done:
        /* Check indirect done status */
        ret = wait_for_bit_le32(plat->regbase + CQSPI_REG_INDIRECTRD,
                                CQSPI_REG_INDIRECTRD_DONE, 1, 10, 0);