summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorT Karthik Reddy <t.karthik.reddy@xilinx.com>2022-05-12 04:05:34 -0600
committerMichal Simek <michal.simek@amd.com>2022-06-29 16:00:31 +0200
commit248fe9f302df5f20d75a7d88b793db017262d750 (patch)
tree642dc7f671ce7af7deca3a61857a43c5c60e38f5
parentbf8dae5fcf400a593d56d5847d8ee62bc4c27855 (diff)
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>
-rw-r--r--arch/arm/mach-versal/include/mach/hardware.h4
-rw-r--r--drivers/spi/cadence_ospi_versal.c24
-rw-r--r--drivers/spi/cadence_qspi.c7
-rw-r--r--drivers/spi/cadence_qspi.h1
-rw-r--r--drivers/spi/cadence_qspi_apb.c11
-rw-r--r--include/zynqmp_firmware.h7
6 files changed, 54 insertions, 0 deletions
diff --git a/arch/arm/mach-versal/include/mach/hardware.h b/arch/arm/mach-versal/include/mach/hardware.h
index c52c9d97925..000af974e86 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 0caf2502034..52bcad053fe 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 923c5f53182..5fb4d2ff03b 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 9d89e24ba49..c8d16bb0e44 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 b11bd2d2c61..c00755050e1 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 6a5f01c8391..6c4fd9a6c5f 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