spi: cadence_qspi: Enable apb linear mode for apb read & write operations
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>
diff --git a/arch/arm/mach-versal/include/mach/hardware.h b/arch/arm/mach-versal/include/mach/hardware.h
index c52c9d9..000af97 100644
--- a/arch/arm/mach-versal/include/mach/hardware.h
+++ b/arch/arm/mach-versal/include/mach/hardware.h
@@ -58,6 +58,10 @@
#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 0caf250..52bcad0 100644
--- a/drivers/spi/cadence_ospi_versal.c
+++ b/drivers/spi/cadence_ospi_versal.c
@@ -33,6 +33,7 @@
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 @@
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 923c5f5..5fb4d2f 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 @@
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 9d89e24..c8d16bb 100644
--- a/drivers/spi/cadence_qspi.h
+++ b/drivers/spi/cadence_qspi.h
@@ -284,5 +284,6 @@
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 b11bd2d..c007550 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 @@
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 @@
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 6a5f01c..6c4fd9a 100644
--- a/include/zynqmp_firmware.h
+++ b/include/zynqmp_firmware.h
@@ -160,6 +160,12 @@
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 @@
#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