summaryrefslogtreecommitdiff
path: root/drivers/spi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/Kconfig8
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/cadence_ospi_versal.c237
-rw-r--r--drivers/spi/cadence_qspi.c40
-rw-r--r--drivers/spi/cadence_qspi.h189
-rw-r--r--drivers/spi/cadence_qspi_apb.c163
6 files changed, 483 insertions, 155 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index e48d72d7445..766d5636c09 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -136,6 +136,14 @@ config CQSPI_REF_CLK
int "Cadence QSPI reference clock value in Hz"
depends on HAS_CQSPI_REF_CLK
+config CADENCE_OSPI_VERSAL
+ bool "Configure Versal OSPI"
+ depends on ARCH_VERSAL && CADENCE_QSPI
+ imply DM_GPIO
+ help
+ This option is used to enable Versal OSPI DMA operations which
+ are used for ospi flash read using cadence qspi controller.
+
config CF_SPI
bool "ColdFire SPI driver"
help
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 8755408e629..4de77c260ad 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -7,6 +7,7 @@
ifdef CONFIG_$(SPL_TPL_)DM_SPI
obj-y += spi-uclass.o
obj-$(CONFIG_CADENCE_QSPI) += cadence_qspi.o cadence_qspi_apb.o
+obj-$(CONFIG_CADENCE_OSPI_VERSAL) += cadence_ospi_versal.o
obj-$(CONFIG_SANDBOX) += spi-emul-uclass.o
obj-$(CONFIG_SOFT_SPI) += soft_spi.o
obj-$(CONFIG_SPI_MEM) += spi-mem.o
diff --git a/drivers/spi/cadence_ospi_versal.c b/drivers/spi/cadence_ospi_versal.c
new file mode 100644
index 00000000000..52bcad053fe
--- /dev/null
+++ b/drivers/spi/cadence_ospi_versal.c
@@ -0,0 +1,237 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) Copyright 2018 Xilinx
+ *
+ * Cadence QSPI controller DMA operations
+ */
+
+#include <clk.h>
+#include <common.h>
+#include <memalign.h>
+#include <wait_bit.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <asm/cache.h>
+#include <cpu_func.h>
+#include <zynqmp_firmware.h>
+#include <asm/arch/hardware.h>
+#include "cadence_qspi.h"
+#include <dt-bindings/power/xlnx-versal-power.h>
+
+#define CMD_4BYTE_READ 0x13
+#define CMD_4BYTE_FAST_READ 0x0C
+
+int cadence_qspi_apb_dma_read(struct cadence_spi_plat *plat,
+ const struct spi_mem_op *op)
+{
+ u32 reg, ret, rx_rem, n_rx, bytes_to_dma, data;
+ u8 opcode, addr_bytes, *rxbuf, dummy_cycles;
+
+ n_rx = op->data.nbytes;
+ rxbuf = op->data.buf.in;
+ rx_rem = n_rx % 4;
+ 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);
+
+ writel(bytes_to_dma, plat->regbase + CQSPI_REG_INDIRECTRDBYTES);
+
+ writel(CQSPI_DFLT_INDIR_TRIG_ADDR_RANGE,
+ plat->regbase + CQSPI_REG_INDIR_TRIG_ADDR_RANGE);
+ writel(CQSPI_DFLT_DMA_PERIPH_CFG,
+ plat->regbase + CQSPI_REG_DMA_PERIPH_CFG);
+ writel((unsigned long)rxbuf, plat->regbase +
+ CQSPI_DMA_DST_ADDR_REG);
+ writel(plat->trigger_address, plat->regbase +
+ CQSPI_DMA_SRC_RD_ADDR_REG);
+ writel(bytes_to_dma, plat->regbase +
+ CQSPI_DMA_DST_SIZE_REG);
+ flush_dcache_range((unsigned long)rxbuf,
+ (unsigned long)rxbuf + bytes_to_dma);
+ writel(CQSPI_DFLT_DST_CTRL_REG_VAL,
+ plat->regbase + CQSPI_DMA_DST_CTRL_REG);
+
+ /* Start the indirect read transfer */
+ writel(CQSPI_REG_INDIRECTRD_START, plat->regbase +
+ CQSPI_REG_INDIRECTRD);
+ /* Wait for dma to complete transfer */
+ ret = cadence_qspi_apb_wait_for_dma_cmplt(plat);
+ if (ret)
+ return ret;
+
+ /* Clear indirect completion status */
+ writel(CQSPI_REG_INDIRECTRD_DONE, plat->regbase +
+ CQSPI_REG_INDIRECTRD);
+ rxbuf += bytes_to_dma;
+ }
+
+ if (rx_rem) {
+ reg = readl(plat->regbase + CQSPI_REG_CONFIG);
+ reg &= ~CQSPI_REG_CONFIG_ENBL_DMA;
+ writel(reg, plat->regbase + CQSPI_REG_CONFIG);
+
+ reg = readl(plat->regbase + CQSPI_REG_INDIRECTRDSTARTADDR);
+ reg += bytes_to_dma;
+ writel(reg, plat->regbase + CQSPI_REG_CMDADDRESS);
+
+ addr_bytes = readl(plat->regbase + CQSPI_REG_SIZE) &
+ CQSPI_REG_SIZE_ADDRESS_MASK;
+
+ opcode = CMD_4BYTE_FAST_READ;
+ dummy_cycles = 8;
+ writel((dummy_cycles << CQSPI_REG_RD_INSTR_DUMMY_LSB) | opcode,
+ plat->regbase + CQSPI_REG_RD_INSTR);
+
+ reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
+ reg |= (0x1 << CQSPI_REG_CMDCTRL_RD_EN_LSB);
+ reg |= (addr_bytes & CQSPI_REG_CMDCTRL_ADD_BYTES_MASK) <<
+ CQSPI_REG_CMDCTRL_ADD_BYTES_LSB;
+ reg |= (0x1 << CQSPI_REG_CMDCTRL_ADDR_EN_LSB);
+ dummy_cycles = (readl(plat->regbase + CQSPI_REG_RD_INSTR) >>
+ CQSPI_REG_RD_INSTR_DUMMY_LSB) &
+ CQSPI_REG_RD_INSTR_DUMMY_MASK;
+ reg |= (dummy_cycles & CQSPI_REG_CMDCTRL_DUMMY_MASK) <<
+ CQSPI_REG_CMDCTRL_DUMMY_LSB;
+ reg |= (((rx_rem - 1) & CQSPI_REG_CMDCTRL_RD_BYTES_MASK) <<
+ CQSPI_REG_CMDCTRL_RD_BYTES_LSB);
+ ret = cadence_qspi_apb_exec_flash_cmd(plat->regbase, reg);
+ if (ret)
+ return ret;
+
+ data = readl(plat->regbase + CQSPI_REG_CMDREADDATALOWER);
+ memcpy(rxbuf, &data, rx_rem);
+ }
+
+ return 0;
+}
+
+int cadence_qspi_apb_wait_for_dma_cmplt(struct cadence_spi_plat *plat)
+{
+ u32 timeout = CQSPI_DMA_TIMEOUT;
+
+ while (!(readl(plat->regbase + CQSPI_DMA_DST_I_STS_REG) &
+ CQSPI_DMA_DST_I_STS_DONE) && timeout--)
+ udelay(1);
+
+ if (!timeout) {
+ printf("DMA timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ writel(readl(plat->regbase + CQSPI_DMA_DST_I_STS_REG),
+ plat->regbase + CQSPI_DMA_DST_I_STS_REG);
+ return 0;
+}
+
+#if defined(CONFIG_DM_GPIO)
+int cadence_spi_versal_flash_reset(struct udevice *dev)
+{
+ struct gpio_desc gpio;
+ u32 reset_gpio;
+ int ret;
+
+ /* request gpio and set direction as output set to 1 */
+ ret = gpio_request_by_name(dev, "reset-gpios", 0, &gpio,
+ GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+ if (ret) {
+ printf("%s: unable to reset ospi flash device", __func__);
+ return ret;
+ }
+
+ reset_gpio = PMIO_NODE_ID_BASE + gpio.offset;
+
+ /* Request for pin */
+ xilinx_pm_request(PM_PINCTRL_REQUEST, reset_gpio, 0, 0, 0, NULL);
+
+ /* Enable hysteresis in cmos receiver */
+ xilinx_pm_request(PM_PINCTRL_CONFIG_PARAM_SET, reset_gpio,
+ PM_PINCTRL_CONFIG_SCHMITT_CMOS,
+ PM_PINCTRL_INPUT_TYPE_SCHMITT, 0, NULL);
+
+ /* Disable Tri-state */
+ xilinx_pm_request(PM_PINCTRL_CONFIG_PARAM_SET, reset_gpio,
+ PM_PINCTRL_CONFIG_TRI_STATE,
+ PM_PINCTRL_TRI_STATE_DISABLE, 0, NULL);
+ udelay(1);
+
+ /* Set value 0 to pin */
+ dm_gpio_set_value(&gpio, 0);
+ udelay(1);
+
+ /* Set value 1 to pin */
+ dm_gpio_set_value(&gpio, 1);
+ udelay(1);
+
+ return 0;
+}
+#else
+int cadence_spi_versal_flash_reset(struct udevice *dev)
+{
+ /* CRP WPROT */
+ writel(0, WPROT_CRP);
+ /* GPIO Reset */
+ writel(0, RST_GPIO);
+
+ /* disable IOU write protection */
+ writel(0, WPROT_LPD_MIO);
+
+ /* set direction as output */
+ writel((readl(BOOT_MODE_DIR) | BIT(FLASH_RESET_GPIO)),
+ BOOT_MODE_POR_0);
+
+ /* Data output enable */
+ writel((readl(BOOT_MODE_OUT) | BIT(FLASH_RESET_GPIO)),
+ BOOT_MODE_POR_1);
+
+ /* IOU SLCR write enable */
+ writel(0, WPROT_PMC_MIO);
+
+ /* set MIO as GPIO */
+ writel(0x60, MIO_PIN_12);
+
+ /* Set value 1 to pin */
+ writel((readl(BANK0_OUTPUT) | BIT(FLASH_RESET_GPIO)), BANK0_OUTPUT);
+ udelay(10);
+
+ /* Disable Tri-state */
+ writel((readl(BANK0_TRI) & ~BIT(FLASH_RESET_GPIO)), BANK0_TRI);
+ udelay(1);
+
+ /* Set value 0 to pin */
+ writel((readl(BANK0_OUTPUT) & ~BIT(FLASH_RESET_GPIO)), BANK0_OUTPUT);
+ udelay(10);
+
+ /* Set value 1 to pin */
+ writel((readl(BANK0_OUTPUT) | BIT(FLASH_RESET_GPIO)), BANK0_OUTPUT);
+ udelay(10);
+
+ 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 7209bb43a77..907f5dadc4f 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
@@ -27,6 +29,17 @@
#define CQSPI_READ 2
#define CQSPI_WRITE 3
+__weak int cadence_qspi_apb_dma_read(struct cadence_spi_plat *plat,
+ const struct spi_mem_op *op)
+{
+ return 0;
+}
+
+__weak int cadence_qspi_versal_flash_reset(struct udevice *dev)
+{
+ return 0;
+}
+
static int cadence_spi_write_speed(struct udevice *bus, uint hz)
{
struct cadence_spi_plat *plat = dev_get_plat(bus);
@@ -138,7 +151,7 @@ static int cadence_spi_set_speed(struct udevice *bus, uint hz)
struct cadence_spi_priv *priv = dev_get_priv(bus);
int err;
- if (hz > plat->max_hz)
+ if (!hz || hz > plat->max_hz)
hz = plat->max_hz;
/* Disable QSPI */
@@ -185,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) {
@@ -214,6 +232,16 @@ static int cadence_spi_probe(struct udevice *bus)
plat->wr_delay = 50 * DIV_ROUND_UP(NSEC_PER_SEC, plat->ref_clk_hz);
+ if (CONFIG_IS_ENABLED(ARCH_VERSAL)) {
+ /* Versal platform uses spi calibration to set read delay */
+ if (plat->read_delay >= 0)
+ plat->read_delay = -1;
+ /* Reset ospi flash device */
+ ret = cadence_qspi_versal_flash_reset(bus);
+ if (ret)
+ return ret;
+ }
+
return 0;
}
@@ -288,8 +316,12 @@ static int cadence_spi_mem_exec_op(struct spi_slave *spi,
break;
case CQSPI_READ:
err = cadence_qspi_apb_read_setup(plat, op);
- if (!err)
- err = cadence_qspi_apb_read_execute(plat, op);
+ if (!err) {
+ if (plat->is_dma)
+ err = cadence_qspi_apb_dma_read(plat, op);
+ else
+ err = cadence_qspi_apb_read_execute(plat, op);
+ }
break;
case CQSPI_WRITE:
err = cadence_qspi_apb_write_setup(plat, op);
@@ -342,6 +374,8 @@ static int cadence_spi_of_to_plat(struct udevice *bus)
if (plat->ahbsize >= SZ_8M)
plat->use_dac_mode = true;
+ plat->is_dma = dev_read_bool(bus, "cdns,is-dma");
+
/* All other paramters are embedded in the child node */
subnode = dev_read_first_subnode(bus);
if (!ofnode_valid(subnode)) {
diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h
index a2b620a5fe2..c8d16bb0e44 100644
--- a/drivers/spi/cadence_qspi.h
+++ b/drivers/spi/cadence_qspi.h
@@ -8,6 +8,8 @@
#define __CADENCE_QSPI_H__
#include <reset.h>
+#include <linux/mtd/spi-nor.h>
+#include <spi-mem.h>
#define CQSPI_IS_ADDR(cmd_len) (cmd_len > 1 ? 1 : 0)
@@ -15,6 +17,186 @@
#define CQSPI_DECODER_MAX_CS 16
#define CQSPI_READ_CAPTURE_MAX_DELAY 16
+#define CQSPI_REG_POLL_US 1 /* 1us */
+#define CQSPI_REG_RETRY 10000
+#define CQSPI_POLL_IDLE_RETRY 3
+
+/* Transfer mode */
+#define CQSPI_INST_TYPE_SINGLE 0
+#define CQSPI_INST_TYPE_DUAL 1
+#define CQSPI_INST_TYPE_QUAD 2
+#define CQSPI_INST_TYPE_OCTAL 3
+
+#define CQSPI_STIG_DATA_LEN_MAX 8
+
+#define CQSPI_DUMMY_CLKS_PER_BYTE 8
+#define CQSPI_DUMMY_BYTES_MAX 4
+#define CQSPI_DUMMY_CLKS_MAX 31
+
+/****************************************************************************
+ * Controller's configuration and status register (offset from QSPI_BASE)
+ ****************************************************************************/
+#define CQSPI_REG_CONFIG 0x00
+#define CQSPI_REG_CONFIG_ENABLE BIT(0)
+#define CQSPI_REG_CONFIG_CLK_POL BIT(1)
+#define CQSPI_REG_CONFIG_CLK_PHA BIT(2)
+#define CQSPI_REG_CONFIG_PHY_ENABLE_MASK BIT(3)
+#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_DTR_PROT_EN_MASK BIT(24)
+#define CQSPI_REG_CONFIG_CHIPSELECT_LSB 10
+#define CQSPI_REG_CONFIG_BAUD_LSB 19
+#define CQSPI_REG_CONFIG_DTR_PROTO BIT(24)
+#define CQSPI_REG_CONFIG_DUAL_OPCODE BIT(30)
+#define CQSPI_REG_CONFIG_IDLE_LSB 31
+#define CQSPI_REG_CONFIG_CHIPSELECT_MASK 0xF
+#define CQSPI_REG_CONFIG_BAUD_MASK 0xF
+
+#define CQSPI_REG_RD_INSTR 0x04
+#define CQSPI_REG_RD_INSTR_OPCODE_LSB 0
+#define CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB 8
+#define CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB 12
+#define CQSPI_REG_RD_INSTR_TYPE_DATA_LSB 16
+#define CQSPI_REG_RD_INSTR_MODE_EN_LSB 20
+#define CQSPI_REG_RD_INSTR_DUMMY_LSB 24
+#define CQSPI_REG_RD_INSTR_TYPE_INSTR_MASK 0x3
+#define CQSPI_REG_RD_INSTR_TYPE_ADDR_MASK 0x3
+#define CQSPI_REG_RD_INSTR_TYPE_DATA_MASK 0x3
+#define CQSPI_REG_RD_INSTR_DUMMY_MASK 0x1F
+
+#define CQSPI_REG_WR_INSTR 0x08
+#define CQSPI_REG_WR_INSTR_OPCODE_LSB 0
+#define CQSPI_REG_WR_INSTR_TYPE_ADDR_LSB 12
+#define CQSPI_REG_WR_INSTR_TYPE_DATA_LSB 16
+
+#define CQSPI_REG_DELAY 0x0C
+#define CQSPI_REG_DELAY_TSLCH_LSB 0
+#define CQSPI_REG_DELAY_TCHSH_LSB 8
+#define CQSPI_REG_DELAY_TSD2D_LSB 16
+#define CQSPI_REG_DELAY_TSHSL_LSB 24
+#define CQSPI_REG_DELAY_TSLCH_MASK 0xFF
+#define CQSPI_REG_DELAY_TCHSH_MASK 0xFF
+#define CQSPI_REG_DELAY_TSD2D_MASK 0xFF
+#define CQSPI_REG_DELAY_TSHSL_MASK 0xFF
+
+#define CQSPI_REG_RD_DATA_CAPTURE 0x10
+#define CQSPI_REG_RD_DATA_CAPTURE_BYPASS BIT(0)
+#define CQSPI_REG_READCAPTURE_DQS_ENABLE BIT(8)
+#define CQSPI_REG_RD_DATA_CAPTURE_DELAY_LSB 1
+#define CQSPI_REG_RD_DATA_CAPTURE_DELAY_MASK 0xF
+
+#define CQSPI_REG_SIZE 0x14
+#define CQSPI_REG_SIZE_ADDRESS_LSB 0
+#define CQSPI_REG_SIZE_PAGE_LSB 4
+#define CQSPI_REG_SIZE_BLOCK_LSB 16
+#define CQSPI_REG_SIZE_ADDRESS_MASK 0xF
+#define CQSPI_REG_SIZE_PAGE_MASK 0xFFF
+#define CQSPI_REG_SIZE_BLOCK_MASK 0x3F
+
+#define CQSPI_REG_SRAMPARTITION 0x18
+#define CQSPI_REG_INDIRECTTRIGGER 0x1C
+
+#define CQSPI_REG_REMAP 0x24
+#define CQSPI_REG_MODE_BIT 0x28
+
+#define CQSPI_REG_SDRAMLEVEL 0x2C
+#define CQSPI_REG_SDRAMLEVEL_RD_LSB 0
+#define CQSPI_REG_SDRAMLEVEL_WR_LSB 16
+#define CQSPI_REG_SDRAMLEVEL_RD_MASK 0xFFFF
+#define CQSPI_REG_SDRAMLEVEL_WR_MASK 0xFFFF
+
+#define CQSPI_REG_WR_COMPLETION_CTRL 0x38
+#define CQSPI_REG_WR_DISABLE_AUTO_POLL BIT(14)
+
+#define CQSPI_REG_IRQSTATUS 0x40
+#define CQSPI_REG_IRQMASK 0x44
+
+#define CQSPI_REG_INDIRECTRD 0x60
+#define CQSPI_REG_INDIRECTRD_START BIT(0)
+#define CQSPI_REG_INDIRECTRD_CANCEL BIT(1)
+#define CQSPI_REG_INDIRECTRD_INPROGRESS BIT(2)
+#define CQSPI_REG_INDIRECTRD_DONE BIT(5)
+
+#define CQSPI_REG_INDIRECTRDWATERMARK 0x64
+#define CQSPI_REG_INDIRECTRDSTARTADDR 0x68
+#define CQSPI_REG_INDIRECTRDBYTES 0x6C
+
+#define CQSPI_REG_CMDCTRL 0x90
+#define CQSPI_REG_CMDCTRL_EXECUTE BIT(0)
+#define CQSPI_REG_CMDCTRL_INPROGRESS BIT(1)
+#define CQSPI_REG_CMDCTRL_DUMMY_LSB 7
+#define CQSPI_REG_CMDCTRL_WR_BYTES_LSB 12
+#define CQSPI_REG_CMDCTRL_WR_EN_LSB 15
+#define CQSPI_REG_CMDCTRL_ADD_BYTES_LSB 16
+#define CQSPI_REG_CMDCTRL_ADDR_EN_LSB 19
+#define CQSPI_REG_CMDCTRL_RD_BYTES_LSB 20
+#define CQSPI_REG_CMDCTRL_RD_EN_LSB 23
+#define CQSPI_REG_CMDCTRL_OPCODE_LSB 24
+#define CQSPI_REG_CMDCTRL_DUMMY_MASK 0x1F
+#define CQSPI_REG_CMDCTRL_WR_BYTES_MASK 0x7
+#define CQSPI_REG_CMDCTRL_ADD_BYTES_MASK 0x3
+#define CQSPI_REG_CMDCTRL_RD_BYTES_MASK 0x7
+#define CQSPI_REG_CMDCTRL_OPCODE_MASK 0xFF
+
+#define CQSPI_REG_INDIRECTWR 0x70
+#define CQSPI_REG_INDIRECTWR_START BIT(0)
+#define CQSPI_REG_INDIRECTWR_CANCEL BIT(1)
+#define CQSPI_REG_INDIRECTWR_INPROGRESS BIT(2)
+#define CQSPI_REG_INDIRECTWR_DONE BIT(5)
+
+#define CQSPI_REG_INDIRECTWRWATERMARK 0x74
+#define CQSPI_REG_INDIRECTWRSTARTADDR 0x78
+#define CQSPI_REG_INDIRECTWRBYTES 0x7C
+
+#define CQSPI_REG_CMDADDRESS 0x94
+#define CQSPI_REG_CMDREADDATALOWER 0xA0
+#define CQSPI_REG_CMDREADDATAUPPER 0xA4
+#define CQSPI_REG_CMDWRITEDATALOWER 0xA8
+#define CQSPI_REG_CMDWRITEDATAUPPER 0xAC
+
+#define CQSPI_REG_OP_EXT_LOWER 0xE0
+#define CQSPI_REG_OP_EXT_READ_LSB 24
+#define CQSPI_REG_OP_EXT_WRITE_LSB 16
+#define CQSPI_REG_OP_EXT_STIG_LSB 0
+
+#define CQSPI_REG_PHY_CONFIG 0xB4
+#define CQSPI_REG_PHY_CONFIG_RESET_FLD_MASK 0x40000000
+
+#define CQSPI_DMA_DST_ADDR_REG 0x1800
+#define CQSPI_DMA_DST_SIZE_REG 0x1804
+#define CQSPI_DMA_DST_STS_REG 0x1808
+#define CQSPI_DMA_DST_CTRL_REG 0x180C
+#define CQSPI_DMA_DST_I_STS_REG 0x1814
+#define CQSPI_DMA_DST_I_ENBL_REG 0x1818
+#define CQSPI_DMA_DST_I_DISBL_REG 0x181C
+#define CQSPI_DMA_DST_CTRL2_REG 0x1824
+#define CQSPI_DMA_DST_ADDR_MSB_REG 0x1828
+
+#define CQSPI_DMA_SRC_RD_ADDR_REG 0x1000
+
+#define CQSPI_REG_DMA_PERIPH_CFG 0x20
+#define CQSPI_REG_INDIR_TRIG_ADDR_RANGE 0x80
+#define CQSPI_DFLT_INDIR_TRIG_ADDR_RANGE 6
+#define CQSPI_DFLT_DMA_PERIPH_CFG 0x602
+#define CQSPI_DFLT_DST_CTRL_REG_VAL 0xF43FFA00
+
+#define CQSPI_DMA_DST_I_STS_DONE BIT(1)
+#define CQSPI_DMA_TIMEOUT 10000000
+
+#define CQSPI_REG_IS_IDLE(base) \
+ ((readl((base) + CQSPI_REG_CONFIG) >> \
+ CQSPI_REG_CONFIG_IDLE_LSB) & 0x1)
+
+#define CQSPI_GET_RD_SRAM_LEVEL(reg_base) \
+ (((readl((reg_base) + CQSPI_REG_SDRAMLEVEL)) >> \
+ CQSPI_REG_SDRAMLEVEL_RD_LSB) & CQSPI_REG_SDRAMLEVEL_RD_MASK)
+
+#define CQSPI_GET_WR_SRAM_LEVEL(reg_base) \
+ (((readl((reg_base) + CQSPI_REG_SDRAMLEVEL)) >> \
+ CQSPI_REG_SDRAMLEVEL_WR_LSB) & CQSPI_REG_SDRAMLEVEL_WR_MASK)
+
struct cadence_spi_plat {
unsigned int ref_clk_hz;
unsigned int max_hz;
@@ -42,6 +224,7 @@ struct cadence_spi_plat {
u8 addr_width;
u8 data_width;
bool dtr;
+ bool is_dma;
};
struct cadence_spi_priv {
@@ -96,5 +279,11 @@ 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);
unsigned int cm_get_qspi_controller_clk_hz(void);
+int cadence_qspi_apb_dma_read(struct cadence_spi_plat *plat,
+ const struct spi_mem_op *op);
+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 2cdf4c9c9f8..c00755050e1 100644
--- a/drivers/spi/cadence_qspi_apb.c
+++ b/drivers/spi/cadence_qspi_apb.c
@@ -38,156 +38,10 @@
#include <malloc.h>
#include "cadence_qspi.h"
-#define CQSPI_REG_POLL_US 1 /* 1us */
-#define CQSPI_REG_RETRY 10000
-#define CQSPI_POLL_IDLE_RETRY 3
-
-/* Transfer mode */
-#define CQSPI_INST_TYPE_SINGLE 0
-#define CQSPI_INST_TYPE_DUAL 1
-#define CQSPI_INST_TYPE_QUAD 2
-#define CQSPI_INST_TYPE_OCTAL 3
-
-#define CQSPI_STIG_DATA_LEN_MAX 8
-
-#define CQSPI_DUMMY_CLKS_PER_BYTE 8
-#define CQSPI_DUMMY_CLKS_MAX 31
-
-/****************************************************************************
- * Controller's configuration and status register (offset from QSPI_BASE)
- ****************************************************************************/
-#define CQSPI_REG_CONFIG 0x00
-#define CQSPI_REG_CONFIG_ENABLE BIT(0)
-#define CQSPI_REG_CONFIG_CLK_POL BIT(1)
-#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_XIP_IMM BIT(18)
-#define CQSPI_REG_CONFIG_CHIPSELECT_LSB 10
-#define CQSPI_REG_CONFIG_BAUD_LSB 19
-#define CQSPI_REG_CONFIG_DTR_PROTO BIT(24)
-#define CQSPI_REG_CONFIG_DUAL_OPCODE BIT(30)
-#define CQSPI_REG_CONFIG_IDLE_LSB 31
-#define CQSPI_REG_CONFIG_CHIPSELECT_MASK 0xF
-#define CQSPI_REG_CONFIG_BAUD_MASK 0xF
-
-#define CQSPI_REG_RD_INSTR 0x04
-#define CQSPI_REG_RD_INSTR_OPCODE_LSB 0
-#define CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB 8
-#define CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB 12
-#define CQSPI_REG_RD_INSTR_TYPE_DATA_LSB 16
-#define CQSPI_REG_RD_INSTR_MODE_EN_LSB 20
-#define CQSPI_REG_RD_INSTR_DUMMY_LSB 24
-#define CQSPI_REG_RD_INSTR_TYPE_INSTR_MASK 0x3
-#define CQSPI_REG_RD_INSTR_TYPE_ADDR_MASK 0x3
-#define CQSPI_REG_RD_INSTR_TYPE_DATA_MASK 0x3
-#define CQSPI_REG_RD_INSTR_DUMMY_MASK 0x1F
-
-#define CQSPI_REG_WR_INSTR 0x08
-#define CQSPI_REG_WR_INSTR_OPCODE_LSB 0
-#define CQSPI_REG_WR_INSTR_TYPE_ADDR_LSB 12
-#define CQSPI_REG_WR_INSTR_TYPE_DATA_LSB 16
-
-#define CQSPI_REG_DELAY 0x0C
-#define CQSPI_REG_DELAY_TSLCH_LSB 0
-#define CQSPI_REG_DELAY_TCHSH_LSB 8
-#define CQSPI_REG_DELAY_TSD2D_LSB 16
-#define CQSPI_REG_DELAY_TSHSL_LSB 24
-#define CQSPI_REG_DELAY_TSLCH_MASK 0xFF
-#define CQSPI_REG_DELAY_TCHSH_MASK 0xFF
-#define CQSPI_REG_DELAY_TSD2D_MASK 0xFF
-#define CQSPI_REG_DELAY_TSHSL_MASK 0xFF
-
-#define CQSPI_REG_RD_DATA_CAPTURE 0x10
-#define CQSPI_REG_RD_DATA_CAPTURE_BYPASS BIT(0)
-#define CQSPI_REG_RD_DATA_CAPTURE_DELAY_LSB 1
-#define CQSPI_REG_RD_DATA_CAPTURE_DELAY_MASK 0xF
-
-#define CQSPI_REG_SIZE 0x14
-#define CQSPI_REG_SIZE_ADDRESS_LSB 0
-#define CQSPI_REG_SIZE_PAGE_LSB 4
-#define CQSPI_REG_SIZE_BLOCK_LSB 16
-#define CQSPI_REG_SIZE_ADDRESS_MASK 0xF
-#define CQSPI_REG_SIZE_PAGE_MASK 0xFFF
-#define CQSPI_REG_SIZE_BLOCK_MASK 0x3F
-
-#define CQSPI_REG_SRAMPARTITION 0x18
-#define CQSPI_REG_INDIRECTTRIGGER 0x1C
-
-#define CQSPI_REG_REMAP 0x24
-#define CQSPI_REG_MODE_BIT 0x28
-
-#define CQSPI_REG_SDRAMLEVEL 0x2C
-#define CQSPI_REG_SDRAMLEVEL_RD_LSB 0
-#define CQSPI_REG_SDRAMLEVEL_WR_LSB 16
-#define CQSPI_REG_SDRAMLEVEL_RD_MASK 0xFFFF
-#define CQSPI_REG_SDRAMLEVEL_WR_MASK 0xFFFF
-
-#define CQSPI_REG_WR_COMPLETION_CTRL 0x38
-#define CQSPI_REG_WR_DISABLE_AUTO_POLL BIT(14)
-
-#define CQSPI_REG_IRQSTATUS 0x40
-#define CQSPI_REG_IRQMASK 0x44
-
-#define CQSPI_REG_INDIRECTRD 0x60
-#define CQSPI_REG_INDIRECTRD_START BIT(0)
-#define CQSPI_REG_INDIRECTRD_CANCEL BIT(1)
-#define CQSPI_REG_INDIRECTRD_INPROGRESS BIT(2)
-#define CQSPI_REG_INDIRECTRD_DONE BIT(5)
-
-#define CQSPI_REG_INDIRECTRDWATERMARK 0x64
-#define CQSPI_REG_INDIRECTRDSTARTADDR 0x68
-#define CQSPI_REG_INDIRECTRDBYTES 0x6C
-
-#define CQSPI_REG_CMDCTRL 0x90
-#define CQSPI_REG_CMDCTRL_EXECUTE BIT(0)
-#define CQSPI_REG_CMDCTRL_INPROGRESS BIT(1)
-#define CQSPI_REG_CMDCTRL_DUMMY_LSB 7
-#define CQSPI_REG_CMDCTRL_WR_BYTES_LSB 12
-#define CQSPI_REG_CMDCTRL_WR_EN_LSB 15
-#define CQSPI_REG_CMDCTRL_ADD_BYTES_LSB 16
-#define CQSPI_REG_CMDCTRL_ADDR_EN_LSB 19
-#define CQSPI_REG_CMDCTRL_RD_BYTES_LSB 20
-#define CQSPI_REG_CMDCTRL_RD_EN_LSB 23
-#define CQSPI_REG_CMDCTRL_OPCODE_LSB 24
-#define CQSPI_REG_CMDCTRL_DUMMY_MASK 0x1F
-#define CQSPI_REG_CMDCTRL_WR_BYTES_MASK 0x7
-#define CQSPI_REG_CMDCTRL_ADD_BYTES_MASK 0x3
-#define CQSPI_REG_CMDCTRL_RD_BYTES_MASK 0x7
-#define CQSPI_REG_CMDCTRL_OPCODE_MASK 0xFF
-
-#define CQSPI_REG_INDIRECTWR 0x70
-#define CQSPI_REG_INDIRECTWR_START BIT(0)
-#define CQSPI_REG_INDIRECTWR_CANCEL BIT(1)
-#define CQSPI_REG_INDIRECTWR_INPROGRESS BIT(2)
-#define CQSPI_REG_INDIRECTWR_DONE BIT(5)
-
-#define CQSPI_REG_INDIRECTWRWATERMARK 0x74
-#define CQSPI_REG_INDIRECTWRSTARTADDR 0x78
-#define CQSPI_REG_INDIRECTWRBYTES 0x7C
-
-#define CQSPI_REG_CMDADDRESS 0x94
-#define CQSPI_REG_CMDREADDATALOWER 0xA0
-#define CQSPI_REG_CMDREADDATAUPPER 0xA4
-#define CQSPI_REG_CMDWRITEDATALOWER 0xA8
-#define CQSPI_REG_CMDWRITEDATAUPPER 0xAC
-
-#define CQSPI_REG_OP_EXT_LOWER 0xE0
-#define CQSPI_REG_OP_EXT_READ_LSB 24
-#define CQSPI_REG_OP_EXT_WRITE_LSB 16
-#define CQSPI_REG_OP_EXT_STIG_LSB 0
-
-#define CQSPI_REG_IS_IDLE(base) \
- ((readl(base + CQSPI_REG_CONFIG) >> \
- CQSPI_REG_CONFIG_IDLE_LSB) & 0x1)
-
-#define CQSPI_GET_RD_SRAM_LEVEL(reg_base) \
- (((readl(reg_base + CQSPI_REG_SDRAMLEVEL)) >> \
- CQSPI_REG_SDRAMLEVEL_RD_LSB) & CQSPI_REG_SDRAMLEVEL_RD_MASK)
-
-#define CQSPI_GET_WR_SRAM_LEVEL(reg_base) \
- (((readl(reg_base + CQSPI_REG_SDRAMLEVEL)) >> \
- CQSPI_REG_SDRAMLEVEL_WR_LSB) & CQSPI_REG_SDRAMLEVEL_WR_MASK)
+__weak void cadence_qspi_apb_enable_linear_mode(bool enable)
+{
+ return;
+}
void cadence_qspi_apb_controller_enable(void *reg_base)
{
@@ -487,8 +341,7 @@ void cadence_qspi_apb_controller_init(struct cadence_spi_plat *plat)
cadence_qspi_apb_controller_enable(plat->regbase);
}
-static int cadence_qspi_apb_exec_flash_cmd(void *reg_base,
- unsigned int reg)
+int cadence_qspi_apb_exec_flash_cmd(void *reg_base, unsigned int reg)
{
unsigned int retry = CQSPI_REG_RETRY;
@@ -882,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) {
@@ -1049,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.