[PATCH 4/5] spi: cadence_qspi: Enable apb linear mode for apb read & write operations

Ashok Reddy Soma ashok.reddy.soma at xilinx.com
Thu May 12 12:05:34 CEST 2022


From: T Karthik Reddy <t.karthik.reddy at xilinx.com>

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 at xilinx.com>
Signed-off-by: Ashok Reddy Soma <ashok.reddy.soma at xilinx.com>
---

 arch/arm/mach-versal/include/mach/hardware.h |  4 ++++
 drivers/spi/cadence_ospi_versal.c            | 24 ++++++++++++++++++++
 drivers/spi/cadence_qspi.c                   |  7 ++++++
 drivers/spi/cadence_qspi.h                   |  1 +
 drivers/spi/cadence_qspi_apb.c               | 11 +++++++++
 include/zynqmp_firmware.h                    |  7 ++++++
 6 files changed, 54 insertions(+)

diff --git a/arch/arm/mach-versal/include/mach/hardware.h b/arch/arm/mach-versal/include/mach/hardware.h
index c47cb7132e..8815f1ecc6 100644
--- a/arch/arm/mach-versal/include/mach/hardware.h
+++ b/arch/arm/mach-versal/include/mach/hardware.h
@@ -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;
diff --git a/drivers/spi/cadence_ospi_versal.c b/drivers/spi/cadence_ospi_versal.c
index 0caf250203..52bcad053f 100644
--- a/drivers/spi/cadence_ospi_versal.c
+++ b/drivers/spi/cadence_ospi_versal.c
@@ -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);
+	}
+}
diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
index 923c5f5318..5fb4d2ff03 100644
--- a/drivers/spi/cadence_qspi.c
+++ b/drivers/spi/cadence_qspi.c
@@ -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) {
diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h
index 9d89e24ba4..c8d16bb0e4 100644
--- a/drivers/spi/cadence_qspi.h
+++ b/drivers/spi/cadence_qspi.h
@@ -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__ */
diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c
index b11bd2d2c6..c00755050e 100644
--- a/drivers/spi/cadence_qspi_apb.c
+++ b/drivers/spi/cadence_qspi_apb.c
@@ -38,6 +38,11 @@
 #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.
diff --git a/include/zynqmp_firmware.h b/include/zynqmp_firmware.h
index 6a5f01c839..6c4fd9a6c5 100644
--- a/include/zynqmp_firmware.h
+++ b/include/zynqmp_firmware.h
@@ -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
 
-- 
2.17.1



More information about the U-Boot mailing list