spi: cadence_qspi: Enable apb linear mode for apb read & write operations
authorT Karthik Reddy <t.karthik.reddy@xilinx.com>
Thu, 12 May 2022 10:05:34 +0000 (04:05 -0600)
committerMichal Simek <michal.simek@amd.com>
Wed, 29 Jun 2022 14:00:31 +0000 (16:00 +0200)
On versal platform, enable apb linear mode for apb read and write
execute operations amd disable it when using dma reads. This is done by
xilinx_pm_request() secure calls when CONFIG_ZYNQMP_FIRMWARE is enabled,
else we use direct raw reads and writes in case of mini U-Boot.

Signed-off-by: T Karthik Reddy <t.karthik.reddy@xilinx.com>
Signed-off-by: Ashok Reddy Soma <ashok.reddy.soma@xilinx.com>
Link: https://lore.kernel.org/r/20220512100535.16364-5-ashok.reddy.soma@xilinx.com
Signed-off-by: Michal Simek <michal.simek@amd.com>
arch/arm/mach-versal/include/mach/hardware.h
drivers/spi/cadence_ospi_versal.c
drivers/spi/cadence_qspi.c
drivers/spi/cadence_qspi.h
drivers/spi/cadence_qspi_apb.c
include/zynqmp_firmware.h

index c52c9d9..000af97 100644 (file)
@@ -58,6 +58,10 @@ struct rpu_regs {
 
 #define VERSAL_CRP_BASEADDR    0xF1260000
 
+#define VERSAL_SLCR_BASEADDR   0xF1060000
+#define VERSAL_AXI_MUX_SEL     (VERSAL_SLCR_BASEADDR + 0x504)
+#define VERSAL_OSPI_LINEAR_MODE        BIT(1)
+
 struct crp_regs {
        u32 reserved0[128];
        u32 boot_mode_usr;
index 0caf250..52bcad0 100644 (file)
@@ -33,6 +33,7 @@ int cadence_qspi_apb_dma_read(struct cadence_spi_plat *plat,
        bytes_to_dma = n_rx - rx_rem;
 
        if (bytes_to_dma) {
+               cadence_qspi_apb_enable_linear_mode(false);
                reg = readl(plat->regbase + CQSPI_REG_CONFIG);
                reg |= CQSPI_REG_CONFIG_ENBL_DMA;
                writel(reg, plat->regbase + CQSPI_REG_CONFIG);
@@ -211,3 +212,26 @@ int cadence_spi_versal_flash_reset(struct udevice *dev)
        return 0;
 }
 #endif
+
+void cadence_qspi_apb_enable_linear_mode(bool enable)
+{
+       if (CONFIG_IS_ENABLED(ZYNQMP_FIRMWARE)) {
+               if (enable)
+                       /* ahb read mode */
+                       xilinx_pm_request(PM_IOCTL, PM_DEV_OSPI,
+                                         IOCTL_OSPI_MUX_SELECT,
+                                         PM_OSPI_MUX_SEL_LINEAR, 0, NULL);
+               else
+                       /* DMA mode */
+                       xilinx_pm_request(PM_IOCTL, PM_DEV_OSPI,
+                                         IOCTL_OSPI_MUX_SELECT,
+                                         PM_OSPI_MUX_SEL_DMA, 0, NULL);
+       } else {
+               if (enable)
+                       writel(readl(VERSAL_AXI_MUX_SEL) |
+                              VERSAL_OSPI_LINEAR_MODE, VERSAL_AXI_MUX_SEL);
+               else
+                       writel(readl(VERSAL_AXI_MUX_SEL) &
+                              ~VERSAL_OSPI_LINEAR_MODE, VERSAL_AXI_MUX_SEL);
+       }
+}
index 923c5f5..5fb4d2f 100644 (file)
@@ -18,7 +18,9 @@
 #include <linux/err.h>
 #include <linux/errno.h>
 #include <linux/sizes.h>
+#include <zynqmp_firmware.h>
 #include "cadence_qspi.h"
+#include <dt-bindings/power/xlnx-versal-power.h>
 
 #define NSEC_PER_SEC                   1000000000L
 
@@ -196,6 +198,11 @@ static int cadence_spi_probe(struct udevice *bus)
        priv->regbase = plat->regbase;
        priv->ahbbase = plat->ahbbase;
 
+       if (CONFIG_IS_ENABLED(ZYNQMP_FIRMWARE))
+               xilinx_pm_request(PM_REQUEST_NODE, PM_DEV_OSPI,
+                                 ZYNQMP_PM_CAPABILITY_ACCESS, ZYNQMP_PM_MAX_QOS,
+                                 ZYNQMP_PM_REQUEST_ACK_NO, NULL);
+
        if (plat->ref_clk_hz == 0) {
                ret = clk_get_by_index(bus, 0, &clk);
                if (ret) {
index 9d89e24..c8d16bb 100644 (file)
@@ -284,5 +284,6 @@ int cadence_qspi_apb_dma_read(struct cadence_spi_plat *plat,
 int cadence_qspi_apb_wait_for_dma_cmplt(struct cadence_spi_plat *plat);
 int cadence_qspi_apb_exec_flash_cmd(void *reg_base, unsigned int reg);
 int cadence_qspi_versal_flash_reset(struct udevice *dev);
+void cadence_qspi_apb_enable_linear_mode(bool enable);
 
 #endif /* __CADENCE_QSPI_H__ */
index b11bd2d..c007550 100644 (file)
 #include <malloc.h>
 #include "cadence_qspi.h"
 
+__weak void cadence_qspi_apb_enable_linear_mode(bool enable)
+{
+       return;
+}
+
 void cadence_qspi_apb_controller_enable(void *reg_base)
 {
        unsigned int reg;
@@ -730,6 +735,9 @@ int cadence_qspi_apb_read_execute(struct cadence_spi_plat *plat,
        void *buf = op->data.buf.in;
        size_t len = op->data.nbytes;
 
+       if (CONFIG_IS_ENABLED(ARCH_VERSAL))
+               cadence_qspi_apb_enable_linear_mode(true);
+
        if (plat->use_dac_mode && (from + len < plat->ahbsize)) {
                if (len < 256 ||
                    dma_memcpy(buf, plat->ahbbase + from, len) < 0) {
@@ -897,6 +905,9 @@ int cadence_qspi_apb_write_execute(struct cadence_spi_plat *plat,
        const void *buf = op->data.buf.out;
        size_t len = op->data.nbytes;
 
+       if (CONFIG_IS_ENABLED(ARCH_VERSAL))
+               cadence_qspi_apb_enable_linear_mode(true);
+
        /*
         * Some flashes like the Cypress Semper flash expect a dummy 4-byte
         * address (all 0s) with the read status register command in DTR mode.
index 6a5f01c..6c4fd9a 100644 (file)
@@ -160,6 +160,12 @@ enum dll_reset_type {
        PM_DLL_RESET_PULSE = 2,
 };
 
+enum ospi_mux_select_type {
+       PM_OSPI_MUX_SEL_DMA,
+       PM_OSPI_MUX_SEL_LINEAR,
+       PM_OSPI_MUX_GET_MODE,
+};
+
 enum pm_query_id {
        PM_QID_INVALID = 0,
        PM_QID_CLOCK_GET_NAME = 1,
@@ -427,6 +433,7 @@ enum pm_gem_config_type {
 #define ZYNQMP_PM_VERSION_INVALID      ~0
 
 #define PMUFW_V1_0     ((1 << ZYNQMP_PM_VERSION_MAJOR_SHIFT) | 0)
+#define PMIO_NODE_ID_BASE              0x1410801B
 
 #define PMIO_NODE_ID_BASE              0x1410801B