summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2022-09-13 09:34:12 -0400
committerTom Rini <[email protected]>2022-09-13 09:34:12 -0400
commitb3d9c0b6d5895e91b3e6b3566423d09e5a4d5ee8 (patch)
treebc8b9e23e3b38ab10bfecbbb4c55df5254f1fb46 /drivers
parentaa2ef9f525a4d31ec3ae451b927cc714ba926157 (diff)
parent39d3c3cfaa4f5099a2d687de4530c9ca4bee256d (diff)
Merge tag 'xilinx-for-v2023.01-rc1' of https://source.denx.de/u-boot/custodians/u-boot-microblaze into next
Xilinx changes for v2023.01-rc1 cmd: - bdinfo - guard LMB code to run only when LMB is enabled timer: - convert arm twd timer to DM power-domain: - Skip loading config object for Versal xilinx: - Fix logic when dfu_alt_info is generated - Define only mmc devnum not partition - Add xlnx prefix to GEM compatible string - Add missing tca6416 to zynqmp SC - vck190 - Add env redund offset - Enable CMD_GREPENV/SETEXPR by default - Move board_get_usable_ram_top() to common location - Add support for SOC detection net/gem: - Check rate before setting it up microblaze: - drop CONFIG_SYS_INIT_RAM_ADDR and CONFIG_SYS_INIT_RAM_SIZE - Show cache size in bdinfo spi: - cadence_qspi: driver updates - zynqmp_gqspi: driver updates - zynqmp_gqspi: Add tap delays for Versal zynq: - Enable mkeficapsule compilation - Use CONFIG_SPL_FS_LOAD_PAYLOAD_NAME for dfu_alt_info - Align bss and end of u-boot image to 64bits - Align qspi node name with Linux kernel - DT: List OCM memory zynqmp: - Fix AES cache handling with a user provided key - SOM: Add mtd partition for secure OS storage area - Add ref_clk property for REFCLKPER calculation - Fix mdio bus description for vck190-sc xilinx-mini: - Remove unneeded configs - Disable LMB versal: - Enable i2c mux pca954x by default - Define CONFIG_CQSPI_REF_CLK - Enable power domain driver - Enable zynqmp_gqspi driver
Diffstat (limited to 'drivers')
-rw-r--r--drivers/cpu/microblaze_cpu.c4
-rw-r--r--drivers/fpga/zynqpl.c3
-rw-r--r--drivers/net/zynq_gem.c11
-rw-r--r--drivers/power/domain/zynqmp-power-domain.c5
-rw-r--r--drivers/spi/cadence_ospi_versal.c56
-rw-r--r--drivers/spi/cadence_qspi.c104
-rw-r--r--drivers/spi/cadence_qspi.h56
-rw-r--r--drivers/spi/cadence_qspi_apb.c231
-rw-r--r--drivers/spi/zynqmp_gqspi.c221
-rw-r--r--drivers/timer/Kconfig6
-rw-r--r--drivers/timer/Makefile1
-rw-r--r--drivers/timer/arm_twd_timer.c108
12 files changed, 532 insertions, 274 deletions
diff --git a/drivers/cpu/microblaze_cpu.c b/drivers/cpu/microblaze_cpu.c
index 969a1047e59..b9d07928223 100644
--- a/drivers/cpu/microblaze_cpu.c
+++ b/drivers/cpu/microblaze_cpu.c
@@ -97,8 +97,10 @@ static int microblaze_cpu_get_desc(const struct udevice *dev, char *buf,
ret = snprintf(buf, size,
"MicroBlaze @ %uMHz, Rev: %s, FPGA family: %s",
cpu_freq_mhz, cpu_ver, fpga_family);
+ if (ret < 0)
+ return ret;
- return 0;
+ return (ret >= size) ? -ENOSPC : 0;
}
static int microblaze_cpu_get_info(const struct udevice *dev,
diff --git a/drivers/fpga/zynqpl.c b/drivers/fpga/zynqpl.c
index d8ebd542abd..0c83df46da4 100644
--- a/drivers/fpga/zynqpl.c
+++ b/drivers/fpga/zynqpl.c
@@ -413,7 +413,8 @@ static int zynq_load(xilinx_desc *desc, const void *buf, size_t bsize,
if (bstype != BIT_PARTIAL)
zynq_slcr_devcfg_enable();
- puts("INFO:post config was not run, please run manually if needed\n");
+ if (!IS_ENABLED(CONFIG_SPL_BUILD))
+ puts("INFO:post config was not run, please run manually if needed\n");
return FPGA_SUCCESS;
}
diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c
index 4e8dd4badd6..61a6c83e335 100644
--- a/drivers/net/zynq_gem.c
+++ b/drivers/net/zynq_gem.c
@@ -500,10 +500,13 @@ static int zynq_gem_init(struct udevice *dev)
}
#endif
- ret = clk_set_rate(&priv->tx_clk, clk_rate);
- if (IS_ERR_VALUE(ret)) {
- dev_err(dev, "failed to set tx clock rate\n");
- return ret;
+ ret = clk_get_rate(&priv->tx_clk);
+ if (ret != clk_rate) {
+ ret = clk_set_rate(&priv->tx_clk, clk_rate);
+ if (IS_ERR_VALUE(ret)) {
+ dev_err(dev, "failed to set tx clock rate %ld\n", clk_rate);
+ return ret;
+ }
}
ret = clk_enable(&priv->tx_clk);
diff --git a/drivers/power/domain/zynqmp-power-domain.c b/drivers/power/domain/zynqmp-power-domain.c
index 6943658be42..adbbb5fdd93 100644
--- a/drivers/power/domain/zynqmp-power-domain.c
+++ b/drivers/power/domain/zynqmp-power-domain.c
@@ -25,7 +25,10 @@ static int zynqmp_power_domain_request(struct power_domain *power_domain)
{
dev_dbg(power_domain->dev, "Request for id: %ld\n", power_domain->id);
- return zynqmp_pmufw_node(power_domain->id);
+ if (IS_ENABLED(CONFIG_ARCH_ZYNQMP))
+ return zynqmp_pmufw_node(power_domain->id);
+
+ return 0;
}
static int zynqmp_power_domain_free(struct power_domain *power_domain)
diff --git a/drivers/spi/cadence_ospi_versal.c b/drivers/spi/cadence_ospi_versal.c
index 52bcad053fe..a25c50bc508 100644
--- a/drivers/spi/cadence_ospi_versal.c
+++ b/drivers/spi/cadence_ospi_versal.c
@@ -21,7 +21,7 @@
#define CMD_4BYTE_READ 0x13
#define CMD_4BYTE_FAST_READ 0x0C
-int cadence_qspi_apb_dma_read(struct cadence_spi_plat *plat,
+int cadence_qspi_apb_dma_read(struct cadence_spi_priv *priv,
const struct spi_mem_op *op)
{
u32 reg, ret, rx_rem, n_rx, bytes_to_dma, data;
@@ -34,86 +34,86 @@ int cadence_qspi_apb_dma_read(struct cadence_spi_plat *plat,
if (bytes_to_dma) {
cadence_qspi_apb_enable_linear_mode(false);
- reg = readl(plat->regbase + CQSPI_REG_CONFIG);
+ reg = readl(priv->regbase + CQSPI_REG_CONFIG);
reg |= CQSPI_REG_CONFIG_ENBL_DMA;
- writel(reg, plat->regbase + CQSPI_REG_CONFIG);
+ writel(reg, priv->regbase + CQSPI_REG_CONFIG);
- writel(bytes_to_dma, plat->regbase + CQSPI_REG_INDIRECTRDBYTES);
+ writel(bytes_to_dma, priv->regbase + CQSPI_REG_INDIRECTRDBYTES);
writel(CQSPI_DFLT_INDIR_TRIG_ADDR_RANGE,
- plat->regbase + CQSPI_REG_INDIR_TRIG_ADDR_RANGE);
+ priv->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 +
+ priv->regbase + CQSPI_REG_DMA_PERIPH_CFG);
+ writel((unsigned long)rxbuf, priv->regbase +
CQSPI_DMA_DST_ADDR_REG);
- writel(plat->trigger_address, plat->regbase +
+ writel(priv->trigger_address, priv->regbase +
CQSPI_DMA_SRC_RD_ADDR_REG);
- writel(bytes_to_dma, plat->regbase +
+ writel(bytes_to_dma, priv->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);
+ priv->regbase + CQSPI_DMA_DST_CTRL_REG);
/* Start the indirect read transfer */
- writel(CQSPI_REG_INDIRECTRD_START, plat->regbase +
+ writel(CQSPI_REG_INDIRECTRD_START, priv->regbase +
CQSPI_REG_INDIRECTRD);
/* Wait for dma to complete transfer */
- ret = cadence_qspi_apb_wait_for_dma_cmplt(plat);
+ ret = cadence_qspi_apb_wait_for_dma_cmplt(priv);
if (ret)
return ret;
/* Clear indirect completion status */
- writel(CQSPI_REG_INDIRECTRD_DONE, plat->regbase +
+ writel(CQSPI_REG_INDIRECTRD_DONE, priv->regbase +
CQSPI_REG_INDIRECTRD);
rxbuf += bytes_to_dma;
}
if (rx_rem) {
- reg = readl(plat->regbase + CQSPI_REG_CONFIG);
+ reg = readl(priv->regbase + CQSPI_REG_CONFIG);
reg &= ~CQSPI_REG_CONFIG_ENBL_DMA;
- writel(reg, plat->regbase + CQSPI_REG_CONFIG);
+ writel(reg, priv->regbase + CQSPI_REG_CONFIG);
- reg = readl(plat->regbase + CQSPI_REG_INDIRECTRDSTARTADDR);
+ reg = readl(priv->regbase + CQSPI_REG_INDIRECTRDSTARTADDR);
reg += bytes_to_dma;
- writel(reg, plat->regbase + CQSPI_REG_CMDADDRESS);
+ writel(reg, priv->regbase + CQSPI_REG_CMDADDRESS);
- addr_bytes = readl(plat->regbase + CQSPI_REG_SIZE) &
+ addr_bytes = readl(priv->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);
+ priv->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) >>
+ dummy_cycles = (readl(priv->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);
+ ret = cadence_qspi_apb_exec_flash_cmd(priv->regbase, reg);
if (ret)
return ret;
- data = readl(plat->regbase + CQSPI_REG_CMDREADDATALOWER);
+ data = readl(priv->regbase + CQSPI_REG_CMDREADDATALOWER);
memcpy(rxbuf, &data, rx_rem);
}
return 0;
}
-int cadence_qspi_apb_wait_for_dma_cmplt(struct cadence_spi_plat *plat)
+int cadence_qspi_apb_wait_for_dma_cmplt(struct cadence_spi_priv *priv)
{
u32 timeout = CQSPI_DMA_TIMEOUT;
- while (!(readl(plat->regbase + CQSPI_DMA_DST_I_STS_REG) &
+ while (!(readl(priv->regbase + CQSPI_DMA_DST_I_STS_REG) &
CQSPI_DMA_DST_I_STS_DONE) && timeout--)
udelay(1);
@@ -122,13 +122,13 @@ int cadence_qspi_apb_wait_for_dma_cmplt(struct cadence_spi_plat *plat)
return -ETIMEDOUT;
}
- writel(readl(plat->regbase + CQSPI_DMA_DST_I_STS_REG),
- plat->regbase + CQSPI_DMA_DST_I_STS_REG);
+ writel(readl(priv->regbase + CQSPI_DMA_DST_I_STS_REG),
+ priv->regbase + CQSPI_DMA_DST_I_STS_REG);
return 0;
}
#if defined(CONFIG_DM_GPIO)
-int cadence_spi_versal_flash_reset(struct udevice *dev)
+int cadence_qspi_versal_flash_reset(struct udevice *dev)
{
struct gpio_desc gpio;
u32 reset_gpio;
@@ -169,7 +169,7 @@ int cadence_spi_versal_flash_reset(struct udevice *dev)
return 0;
}
#else
-int cadence_spi_versal_flash_reset(struct udevice *dev)
+int cadence_qspi_versal_flash_reset(struct udevice *dev)
{
/* CRP WPROT */
writel(0, WPROT_CRP);
diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
index 907f5dadc4f..ab0a681c837 100644
--- a/drivers/spi/cadence_qspi.c
+++ b/drivers/spi/cadence_qspi.c
@@ -29,7 +29,7 @@
#define CQSPI_READ 2
#define CQSPI_WRITE 3
-__weak int cadence_qspi_apb_dma_read(struct cadence_spi_plat *plat,
+__weak int cadence_qspi_apb_dma_read(struct cadence_spi_priv *priv,
const struct spi_mem_op *op)
{
return 0;
@@ -42,36 +42,40 @@ __weak int cadence_qspi_versal_flash_reset(struct udevice *dev)
static int cadence_spi_write_speed(struct udevice *bus, uint hz)
{
- struct cadence_spi_plat *plat = dev_get_plat(bus);
struct cadence_spi_priv *priv = dev_get_priv(bus);
cadence_qspi_apb_config_baudrate_div(priv->regbase,
- plat->ref_clk_hz, hz);
+ priv->ref_clk_hz, hz);
/* Reconfigure delay timing if speed is changed. */
- cadence_qspi_apb_delay(priv->regbase, plat->ref_clk_hz, hz,
- plat->tshsl_ns, plat->tsd2d_ns,
- plat->tchsh_ns, plat->tslch_ns);
+ cadence_qspi_apb_delay(priv->regbase, priv->ref_clk_hz, hz,
+ priv->tshsl_ns, priv->tsd2d_ns,
+ priv->tchsh_ns, priv->tslch_ns);
return 0;
}
-static int cadence_spi_read_id(struct cadence_spi_plat *plat, u8 len,
+static int cadence_spi_read_id(struct cadence_spi_priv *priv, u8 len,
u8 *idcode)
{
+ int err;
+
struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(0x9F, 1),
SPI_MEM_OP_NO_ADDR,
SPI_MEM_OP_NO_DUMMY,
SPI_MEM_OP_DATA_IN(len, idcode, 1));
- return cadence_qspi_apb_command_read(plat, &op);
+ err = cadence_qspi_apb_command_read_setup(priv, &op);
+ if (!err)
+ err = cadence_qspi_apb_command_read(priv, &op);
+
+ return err;
}
/* Calibration sequence to determine the read data capture delay register */
static int spi_calibration(struct udevice *bus, uint hz)
{
struct cadence_spi_priv *priv = dev_get_priv(bus);
- struct cadence_spi_plat *plat = dev_get_plat(bus);
void *base = priv->regbase;
unsigned int idcode = 0, temp = 0;
int err = 0, i, range_lo = -1, range_hi = -1;
@@ -86,7 +90,7 @@ static int spi_calibration(struct udevice *bus, uint hz)
cadence_qspi_apb_controller_enable(base);
/* read the ID which will be our golden value */
- err = cadence_spi_read_id(plat, 3, (u8 *)&idcode);
+ err = cadence_spi_read_id(priv, 3, (u8 *)&idcode);
if (err) {
puts("SF: Calibration failed (read)\n");
return err;
@@ -105,7 +109,7 @@ static int spi_calibration(struct udevice *bus, uint hz)
cadence_qspi_apb_controller_enable(base);
/* issue a RDID to get the ID value */
- err = cadence_spi_read_id(plat, 3, (u8 *)&temp);
+ err = cadence_spi_read_id(priv, 3, (u8 *)&temp);
if (err) {
puts("SF: Calibration failed (read)\n");
return err;
@@ -147,13 +151,11 @@ static int spi_calibration(struct udevice *bus, uint hz)
static int cadence_spi_set_speed(struct udevice *bus, uint hz)
{
- struct cadence_spi_plat *plat = dev_get_plat(bus);
struct cadence_spi_priv *priv = dev_get_priv(bus);
int err;
- if (!hz || hz > plat->max_hz)
- hz = plat->max_hz;
-
+ if (!hz || hz > priv->max_hz)
+ hz = priv->max_hz;
/* Disable QSPI */
cadence_qspi_apb_controller_disable(priv->regbase);
@@ -161,10 +163,10 @@ static int cadence_spi_set_speed(struct udevice *bus, uint hz)
* If the device tree already provides a read delay value, use that
* instead of calibrating.
*/
- if (plat->read_delay >= 0) {
+ if (priv->read_delay >= 0) {
cadence_spi_write_speed(bus, hz);
cadence_qspi_apb_readdata_capture(priv->regbase, 1,
- plat->read_delay);
+ priv->read_delay);
} else if (priv->previous_hz != hz ||
priv->qspi_calibrated_hz != hz ||
priv->qspi_calibrated_cs != spi_chip_select(bus)) {
@@ -195,29 +197,44 @@ static int cadence_spi_probe(struct udevice *bus)
struct clk clk;
int ret;
- priv->regbase = plat->regbase;
- priv->ahbbase = plat->ahbbase;
+ priv->regbase = plat->regbase;
+ priv->ahbbase = plat->ahbbase;
+ priv->is_dma = plat->is_dma;
+ priv->is_decoded_cs = plat->is_decoded_cs;
+ priv->fifo_depth = plat->fifo_depth;
+ priv->fifo_width = plat->fifo_width;
+ priv->trigger_address = plat->trigger_address;
+ priv->read_delay = plat->read_delay;
+ priv->ahbsize = plat->ahbsize;
+ priv->max_hz = plat->max_hz;
+
+ priv->page_size = plat->page_size;
+ priv->block_size = plat->block_size;
+ priv->tshsl_ns = plat->tshsl_ns;
+ priv->tsd2d_ns = plat->tsd2d_ns;
+ priv->tchsh_ns = plat->tchsh_ns;
+ priv->tslch_ns = plat->tslch_ns;
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) {
+ if (priv->ref_clk_hz == 0) {
ret = clk_get_by_index(bus, 0, &clk);
if (ret) {
#ifdef CONFIG_HAS_CQSPI_REF_CLK
- plat->ref_clk_hz = CONFIG_CQSPI_REF_CLK;
+ priv->ref_clk_hz = CONFIG_CQSPI_REF_CLK;
#elif defined(CONFIG_ARCH_SOCFPGA)
- plat->ref_clk_hz = cm_get_qspi_controller_clk_hz();
+ priv->ref_clk_hz = cm_get_qspi_controller_clk_hz();
#else
return ret;
#endif
} else {
- plat->ref_clk_hz = clk_get_rate(&clk);
+ priv->ref_clk_hz = clk_get_rate(&clk);
clk_free(&clk);
- if (IS_ERR_VALUE(plat->ref_clk_hz))
- return plat->ref_clk_hz;
+ if (IS_ERR_VALUE(priv->ref_clk_hz))
+ return priv->ref_clk_hz;
}
}
@@ -226,16 +243,16 @@ static int cadence_spi_probe(struct udevice *bus)
reset_deassert_bulk(priv->resets);
if (!priv->qspi_is_init) {
- cadence_qspi_apb_controller_init(plat);
+ cadence_qspi_apb_controller_init(priv);
priv->qspi_is_init = 1;
}
- plat->wr_delay = 50 * DIV_ROUND_UP(NSEC_PER_SEC, plat->ref_clk_hz);
+ priv->wr_delay = 50 * DIV_ROUND_UP(NSEC_PER_SEC, priv->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;
+ if (priv->read_delay >= 0)
+ priv->read_delay = -1;
/* Reset ospi flash device */
ret = cadence_qspi_versal_flash_reset(bus);
if (ret)
@@ -258,7 +275,6 @@ static int cadence_spi_remove(struct udevice *dev)
static int cadence_spi_set_mode(struct udevice *bus, uint mode)
{
- struct cadence_spi_plat *plat = dev_get_plat(bus);
struct cadence_spi_priv *priv = dev_get_priv(bus);
/* Disable QSPI */
@@ -268,7 +284,7 @@ static int cadence_spi_set_mode(struct udevice *bus, uint mode)
cadence_qspi_apb_set_clk_mode(priv->regbase, mode);
/* Enable Direct Access Controller */
- if (plat->use_dac_mode)
+ if (priv->use_dac_mode)
cadence_qspi_apb_dac_mode_enable(priv->regbase);
/* Enable QSPI */
@@ -281,7 +297,6 @@ static int cadence_spi_mem_exec_op(struct spi_slave *spi,
const struct spi_mem_op *op)
{
struct udevice *bus = spi->dev->parent;
- struct cadence_spi_plat *plat = dev_get_plat(bus);
struct cadence_spi_priv *priv = dev_get_priv(bus);
void *base = priv->regbase;
int err = 0;
@@ -289,7 +304,7 @@ static int cadence_spi_mem_exec_op(struct spi_slave *spi,
/* Set Chip select */
cadence_qspi_apb_chipselect(base, spi_chip_select(spi->dev),
- plat->is_decoded_cs);
+ priv->is_decoded_cs);
if (op->data.dir == SPI_MEM_DATA_IN && op->data.buf.in) {
if (!op->addr.nbytes)
@@ -305,28 +320,28 @@ static int cadence_spi_mem_exec_op(struct spi_slave *spi,
switch (mode) {
case CQSPI_STIG_READ:
- err = cadence_qspi_apb_command_read_setup(plat, op);
+ err = cadence_qspi_apb_command_read_setup(priv, op);
if (!err)
- err = cadence_qspi_apb_command_read(plat, op);
+ err = cadence_qspi_apb_command_read(priv, op);
break;
case CQSPI_STIG_WRITE:
- err = cadence_qspi_apb_command_write_setup(plat, op);
+ err = cadence_qspi_apb_command_write_setup(priv, op);
if (!err)
- err = cadence_qspi_apb_command_write(plat, op);
+ err = cadence_qspi_apb_command_write(priv, op);
break;
case CQSPI_READ:
- err = cadence_qspi_apb_read_setup(plat, op);
+ err = cadence_qspi_apb_read_setup(priv, op);
if (!err) {
- if (plat->is_dma)
- err = cadence_qspi_apb_dma_read(plat, op);
+ if (priv->is_dma)
+ err = cadence_qspi_apb_dma_read(priv, op);
else
- err = cadence_qspi_apb_read_execute(plat, op);
+ err = cadence_qspi_apb_read_execute(priv, op);
}
break;
case CQSPI_WRITE:
- err = cadence_qspi_apb_write_setup(plat, op);
+ err = cadence_qspi_apb_write_setup(priv, op);
if (!err)
- err = cadence_qspi_apb_write_execute(plat, op);
+ err = cadence_qspi_apb_write_execute(priv, op);
break;
default:
err = -1;
@@ -359,6 +374,7 @@ static bool cadence_spi_mem_supports_op(struct spi_slave *slave,
static int cadence_spi_of_to_plat(struct udevice *bus)
{
struct cadence_spi_plat *plat = dev_get_plat(bus);
+ struct cadence_spi_priv *priv = dev_get_priv(bus);
ofnode subnode;
plat->regbase = (void *)devfdt_get_addr_index(bus, 0);
@@ -372,7 +388,7 @@ static int cadence_spi_of_to_plat(struct udevice *bus)
0);
/* Use DAC mode only when MMIO window is at least 8M wide */
if (plat->ahbsize >= SZ_8M)
- plat->use_dac_mode = true;
+ priv->use_dac_mode = true;
plat->is_dma = dev_read_bool(bus, "cdns,is-dma");
diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h
index c8d16bb0e44..1c59d1a9d9a 100644
--- a/drivers/spi/cadence_qspi.h
+++ b/drivers/spi/cadence_qspi.h
@@ -198,7 +198,6 @@
CQSPI_REG_SDRAMLEVEL_WR_LSB) & CQSPI_REG_SDRAMLEVEL_WR_MASK)
struct cadence_spi_plat {
- unsigned int ref_clk_hz;
unsigned int max_hz;
void *regbase;
void *ahbbase;
@@ -209,7 +208,6 @@ struct cadence_spi_plat {
fdt_addr_t ahbsize;
bool use_dac_mode;
int read_delay;
- u32 wr_delay;
/* Flash parameters */
u32 page_size;
@@ -219,17 +217,18 @@ struct cadence_spi_plat {
u32 tchsh_ns;
u32 tslch_ns;
- /* Transaction protocol parameters. */
- u8 inst_width;
- u8 addr_width;
- u8 data_width;
- bool dtr;
bool is_dma;
};
struct cadence_spi_priv {
+ unsigned int ref_clk_hz;
+ unsigned int max_hz;
void *regbase;
void *ahbbase;
+ unsigned int fifo_depth;
+ unsigned int fifo_width;
+ unsigned int trigger_address;
+ fdt_addr_t ahbsize;
size_t cmd_len;
u8 cmd_buf[32];
size_t data_len;
@@ -238,32 +237,53 @@ struct cadence_spi_priv {
unsigned int qspi_calibrated_hz;
unsigned int qspi_calibrated_cs;
unsigned int previous_hz;
+ u32 wr_delay;
+ int read_delay;
struct reset_ctl_bulk *resets;
+ u32 page_size;
+ u32 block_size;
+ u32 tshsl_ns;
+ u32 tsd2d_ns;
+ u32 tchsh_ns;
+ u32 tslch_ns;
+ u8 edge_mode;
+ u8 dll_mode;
+ bool extra_dummy;
+ bool ddr_init;
+ bool is_decoded_cs;
+ bool use_dac_mode;
+ bool is_dma;
+
+ /* Transaction protocol parameters. */
+ u8 inst_width;
+ u8 addr_width;
+ u8 data_width;
+ bool dtr;
};
/* Functions call declaration */
-void cadence_qspi_apb_controller_init(struct cadence_spi_plat *plat);
+void cadence_qspi_apb_controller_init(struct cadence_spi_priv *priv);
void cadence_qspi_apb_controller_enable(void *reg_base_addr);
void cadence_qspi_apb_controller_disable(void *reg_base_addr);
void cadence_qspi_apb_dac_mode_enable(void *reg_base);
-int cadence_qspi_apb_command_read_setup(struct cadence_spi_plat *plat,
+int cadence_qspi_apb_command_read_setup(struct cadence_spi_priv *priv,
const struct spi_mem_op *op);
-int cadence_qspi_apb_command_read(struct cadence_spi_plat *plat,
+int cadence_qspi_apb_command_read(struct cadence_spi_priv *priv,
const struct spi_mem_op *op);
-int cadence_qspi_apb_command_write_setup(struct cadence_spi_plat *plat,
+int cadence_qspi_apb_command_write_setup(struct cadence_spi_priv *priv,
const struct spi_mem_op *op);
-int cadence_qspi_apb_command_write(struct cadence_spi_plat *plat,
+int cadence_qspi_apb_command_write(struct cadence_spi_priv *priv,
const struct spi_mem_op *op);
-int cadence_qspi_apb_read_setup(struct cadence_spi_plat *plat,
+int cadence_qspi_apb_read_setup(struct cadence_spi_priv *priv,
const struct spi_mem_op *op);
-int cadence_qspi_apb_read_execute(struct cadence_spi_plat *plat,
+int cadence_qspi_apb_read_execute(struct cadence_spi_priv *priv,
const struct spi_mem_op *op);
-int cadence_qspi_apb_write_setup(struct cadence_spi_plat *plat,
+int cadence_qspi_apb_write_setup(struct cadence_spi_priv *priv,
const struct spi_mem_op *op);
-int cadence_qspi_apb_write_execute(struct cadence_spi_plat *plat,
+int cadence_qspi_apb_write_execute(struct cadence_spi_priv *priv,
const struct spi_mem_op *op);
void cadence_qspi_apb_chipselect(void *reg_base,
@@ -279,9 +299,9 @@ 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,
+int cadence_qspi_apb_dma_read(struct cadence_spi_priv *priv,
const struct spi_mem_op *op);
-int cadence_qspi_apb_wait_for_dma_cmplt(struct cadence_spi_plat *plat);
+int cadence_qspi_apb_wait_for_dma_cmplt(struct cadence_spi_priv *priv);
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);
diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c
index c00755050e1..cfae5dcbda0 100644
--- a/drivers/spi/cadence_qspi_apb.c
+++ b/drivers/spi/cadence_qspi_apb.c
@@ -83,13 +83,13 @@ static unsigned int cadence_qspi_calc_dummy(const struct spi_mem_op *op,
return dummy_clk;
}
-static u32 cadence_qspi_calc_rdreg(struct cadence_spi_plat *plat)
+static u32 cadence_qspi_calc_rdreg(struct cadence_spi_priv *priv)
{
u32 rdreg = 0;
- rdreg |= plat->inst_width << CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB;
- rdreg |= plat->addr_width << CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB;
- rdreg |= plat->data_width << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB;
+ rdreg |= priv->inst_width << CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB;
+ rdreg |= priv->addr_width << CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB;
+ rdreg |= priv->data_width << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB;
return rdreg;
}
@@ -115,27 +115,27 @@ static int cadence_qspi_buswidth_to_inst_type(u8 buswidth)
}
}
-static int cadence_qspi_set_protocol(struct cadence_spi_plat *plat,
+static int cadence_qspi_set_protocol(struct cadence_spi_priv *priv,
const struct spi_mem_op *op)
{
int ret;
- plat->dtr = op->data.dtr && op->cmd.dtr && op->addr.dtr;
+ priv->dtr = op->data.dtr && op->cmd.dtr && op->addr.dtr;
ret = cadence_qspi_buswidth_to_inst_type(op->cmd.buswidth);
if (ret < 0)
return ret;
- plat->inst_width = ret;
+ priv->inst_width = ret;
ret = cadence_qspi_buswidth_to_inst_type(op->addr.buswidth);
if (ret < 0)
return ret;
- plat->addr_width = ret;
+ priv->addr_width = ret;
ret = cadence_qspi_buswidth_to_inst_type(op->data.buswidth);
if (ret < 0)
return ret;
- plat->data_width = ret;
+ priv->data_width = ret;
return 0;
}
@@ -314,31 +314,31 @@ void cadence_qspi_apb_delay(void *reg_base,
cadence_qspi_apb_controller_enable(reg_base);
}
-void cadence_qspi_apb_controller_init(struct cadence_spi_plat *plat)
+void cadence_qspi_apb_controller_init(struct cadence_spi_priv *priv)
{
unsigned reg;
- cadence_qspi_apb_controller_disable(plat->regbase);
+ cadence_qspi_apb_controller_disable(priv->regbase);
/* Configure the device size and address bytes */
- reg = readl(plat->regbase + CQSPI_REG_SIZE);
+ reg = readl(priv->regbase + CQSPI_REG_SIZE);
/* Clear the previous value */
reg &= ~(CQSPI_REG_SIZE_PAGE_MASK << CQSPI_REG_SIZE_PAGE_LSB);
reg &= ~(CQSPI_REG_SIZE_BLOCK_MASK << CQSPI_REG_SIZE_BLOCK_LSB);
- reg |= (plat->page_size << CQSPI_REG_SIZE_PAGE_LSB);
- reg |= (plat->block_size << CQSPI_REG_SIZE_BLOCK_LSB);
- writel(reg, plat->regbase + CQSPI_REG_SIZE);
+ reg |= (priv->page_size << CQSPI_REG_SIZE_PAGE_LSB);
+ reg |= (priv->block_size << CQSPI_REG_SIZE_BLOCK_LSB);
+ writel(reg, priv->regbase + CQSPI_REG_SIZE);
/* Configure the remap address register, no remap */
- writel(0, plat->regbase + CQSPI_REG_REMAP);
+ writel(0, priv->regbase + CQSPI_REG_REMAP);
/* Indirect mode configurations */
- writel(plat->fifo_depth / 2, plat->regbase + CQSPI_REG_SRAMPARTITION);
+ writel(priv->fifo_depth / 2, priv->regbase + CQSPI_REG_SRAMPARTITION);
/* Disable all interrupts */
- writel(0, plat->regbase + CQSPI_REG_IRQMASK);
+ writel(0, priv->regbase + CQSPI_REG_IRQMASK);
- cadence_qspi_apb_controller_enable(plat->regbase);
+ cadence_qspi_apb_controller_enable(priv->regbase);
}
int cadence_qspi_apb_exec_flash_cmd(void *reg_base, unsigned int reg)
@@ -370,7 +370,7 @@ int cadence_qspi_apb_exec_flash_cmd(void *reg_base, unsigned int reg)
return 0;
}
-static int cadence_qspi_setup_opcode_ext(struct cadence_spi_plat *plat,
+static int cadence_qspi_setup_opcode_ext(struct cadence_spi_priv *priv,
const struct spi_mem_op *op,
unsigned int shift)
{
@@ -383,15 +383,15 @@ static int cadence_qspi_setup_opcode_ext(struct cadence_spi_plat *plat,
/* Opcode extension is the LSB. */
ext = op->cmd.opcode & 0xff;
- reg = readl(plat->regbase + CQSPI_REG_OP_EXT_LOWER);
+ reg = readl(priv->regbase + CQSPI_REG_OP_EXT_LOWER);
reg &= ~(0xff << shift);
reg |= ext << shift;
- writel(reg, plat->regbase + CQSPI_REG_OP_EXT_LOWER);
+ writel(reg, priv->regbase + CQSPI_REG_OP_EXT_LOWER);
return 0;
}
-static int cadence_qspi_enable_dtr(struct cadence_spi_plat *plat,
+static int cadence_qspi_enable_dtr(struct cadence_spi_priv *priv,
const struct spi_mem_op *op,
unsigned int shift,
bool enable)
@@ -399,14 +399,14 @@ static int cadence_qspi_enable_dtr(struct cadence_spi_plat *plat,
unsigned int reg;
int ret;
- reg = readl(plat->regbase + CQSPI_REG_CONFIG);
+ reg = readl(priv->regbase + CQSPI_REG_CONFIG);
if (enable) {
reg |= CQSPI_REG_CONFIG_DTR_PROTO;
reg |= CQSPI_REG_CONFIG_DUAL_OPCODE;
/* Set up command opcode extension. */
- ret = cadence_qspi_setup_opcode_ext(plat, op, shift);
+ ret = cadence_qspi_setup_opcode_ext(priv, op, shift);
if (ret)
return ret;
} else {
@@ -414,37 +414,37 @@ static int cadence_qspi_enable_dtr(struct cadence_spi_plat *plat,
reg &= ~CQSPI_REG_CONFIG_DUAL_OPCODE;
}
- writel(reg, plat->regbase + CQSPI_REG_CONFIG);
+ writel(reg, priv->regbase + CQSPI_REG_CONFIG);
return 0;
}
-int cadence_qspi_apb_command_read_setup(struct cadence_spi_plat *plat,
+int cadence_qspi_apb_command_read_setup(struct cadence_spi_priv *priv,
const struct spi_mem_op *op)
{
int ret;
unsigned int reg;
- ret = cadence_qspi_set_protocol(plat, op);
+ ret = cadence_qspi_set_protocol(priv, op);
if (ret)
return ret;
- ret = cadence_qspi_enable_dtr(plat, op, CQSPI_REG_OP_EXT_STIG_LSB,
- plat->dtr);
+ ret = cadence_qspi_enable_dtr(priv, op, CQSPI_REG_OP_EXT_STIG_LSB,
+ priv->dtr);
if (ret)
return ret;
- reg = cadence_qspi_calc_rdreg(plat);
- writel(reg, plat->regbase + CQSPI_REG_RD_INSTR);
+ reg = cadence_qspi_calc_rdreg(priv);
+ writel(reg, priv->regbase + CQSPI_REG_RD_INSTR);
return 0;
}
/* For command RDID, RDSR. */
-int cadence_qspi_apb_command_read(struct cadence_spi_plat *plat,
+int cadence_qspi_apb_command_read(struct cadence_spi_priv *priv,
const struct spi_mem_op *op)
{
- void *reg_base = plat->regbase;
+ void *reg_base = priv->regbase;
unsigned int reg;
unsigned int read_len;
int status;
@@ -458,7 +458,7 @@ int cadence_qspi_apb_command_read(struct cadence_spi_plat *plat,
return -EINVAL;
}
- if (plat->dtr)
+ if (priv->dtr)
opcode = op->cmd.opcode >> 8;
else
opcode = op->cmd.opcode;
@@ -466,7 +466,7 @@ int cadence_qspi_apb_command_read(struct cadence_spi_plat *plat,
reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
/* Set up dummy cycles. */
- dummy_clk = cadence_qspi_calc_dummy(op, plat->dtr);
+ dummy_clk = cadence_qspi_calc_dummy(op, priv->dtr);
if (dummy_clk > CQSPI_DUMMY_CLKS_MAX)
return -ENOTSUPP;
@@ -499,29 +499,29 @@ int cadence_qspi_apb_command_read(struct cadence_spi_plat *plat,
return 0;
}
-int cadence_qspi_apb_command_write_setup(struct cadence_spi_plat *plat,
+int cadence_qspi_apb_command_write_setup(struct cadence_spi_priv *priv,
const struct spi_mem_op *op)
{
int ret;
unsigned int reg;
- ret = cadence_qspi_set_protocol(plat, op);
+ ret = cadence_qspi_set_protocol(priv, op);
if (ret)
return ret;
- ret = cadence_qspi_enable_dtr(plat, op, CQSPI_REG_OP_EXT_STIG_LSB,
- plat->dtr);
+ ret = cadence_qspi_enable_dtr(priv, op, CQSPI_REG_OP_EXT_STIG_LSB,
+ priv->dtr);
if (ret)
return ret;
- reg = cadence_qspi_calc_rdreg(plat);
- writel(reg, plat->regbase + CQSPI_REG_RD_INSTR);
+ reg = cadence_qspi_calc_rdreg(priv);
+ writel(reg, priv->regbase + CQSPI_REG_RD_INSTR);
return 0;
}
/* For commands: WRSR, WREN, WRDI, CHIP_ERASE, BE, etc. */
-int cadence_qspi_apb_command_write(struct cadence_spi_plat *plat,
+int cadence_qspi_apb_command_write(struct cadence_spi_priv *priv,
const struct spi_mem_op *op)
{
unsigned int reg = 0;
@@ -529,7 +529,7 @@ int cadence_qspi_apb_command_write(struct cadence_spi_plat *plat,
unsigned int wr_len;
unsigned int txlen = op->data.nbytes;
const void *txbuf = op->data.buf.out;
- void *reg_base = plat->regbase;
+ void *reg_base = priv->regbase;
u32 addr;
u8 opcode;
@@ -547,7 +547,7 @@ int cadence_qspi_apb_command_write(struct cadence_spi_plat *plat,
return -EINVAL;
}
- if (plat->dtr)
+ if (priv->dtr)
opcode = op->cmd.opcode >> 8;
else
opcode = op->cmd.opcode;
@@ -579,7 +579,7 @@ int cadence_qspi_apb_command_write(struct cadence_spi_plat *plat,
}
/* Opcode + Address (3/4 bytes) + dummy bytes (0-4 bytes) */
-int cadence_qspi_apb_read_setup(struct cadence_spi_plat *plat,
+int cadence_qspi_apb_read_setup(struct cadence_spi_priv *priv,
const struct spi_mem_op *op)
{
unsigned int reg;
@@ -589,33 +589,33 @@ int cadence_qspi_apb_read_setup(struct cadence_spi_plat *plat,
int ret;
u8 opcode;
- ret = cadence_qspi_set_protocol(plat, op);
+ ret = cadence_qspi_set_protocol(priv, op);
if (ret)
return ret;
- ret = cadence_qspi_enable_dtr(plat, op, CQSPI_REG_OP_EXT_READ_LSB,
- plat->dtr);
+ ret = cadence_qspi_enable_dtr(priv, op, CQSPI_REG_OP_EXT_READ_LSB,
+ priv->dtr);
if (ret)
return ret;
/* Setup the indirect trigger address */
- writel(plat->trigger_address,
- plat->regbase + CQSPI_REG_INDIRECTTRIGGER);
+ writel(priv->trigger_address,
+ priv->regbase + CQSPI_REG_INDIRECTTRIGGER);
/* Configure the opcode */
- if (plat->dtr)
+ if (priv->dtr)
opcode = op->cmd.opcode >> 8;
else
opcode = op->cmd.opcode;
rd_reg = opcode << CQSPI_REG_RD_INSTR_OPCODE_LSB;
- rd_reg |= cadence_qspi_calc_rdreg(plat);
+ rd_reg |= cadence_qspi_calc_rdreg(priv);
- writel(op->addr.val, plat->regbase + CQSPI_REG_INDIRECTRDSTARTADDR);
+ writel(op->addr.val, priv->regbase + CQSPI_REG_INDIRECTRDSTARTADDR);
if (dummy_bytes) {
/* Convert to clock cycles. */
- dummy_clk = cadence_qspi_calc_dummy(op, plat->dtr);
+ dummy_clk = cadence_qspi_calc_dummy(op, priv->dtr);
if (dummy_clk > CQSPI_DUMMY_CLKS_MAX)
return -ENOTSUPP;
@@ -625,30 +625,30 @@ int cadence_qspi_apb_read_setup(struct cadence_spi_plat *plat,
<< CQSPI_REG_RD_INSTR_DUMMY_LSB;
}
- writel(rd_reg, plat->regbase + CQSPI_REG_RD_INSTR);
+ writel(rd_reg, priv->regbase + CQSPI_REG_RD_INSTR);
/* set device size */
- reg = readl(plat->regbase + CQSPI_REG_SIZE);
+ reg = readl(priv->regbase + CQSPI_REG_SIZE);
reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
reg |= (op->addr.nbytes - 1);
- writel(reg, plat->regbase + CQSPI_REG_SIZE);
+ writel(reg, priv->regbase + CQSPI_REG_SIZE);
return 0;
}
-static u32 cadence_qspi_get_rd_sram_level(struct cadence_spi_plat *plat)
+static u32 cadence_qspi_get_rd_sram_level(struct cadence_spi_priv *priv)
{
- u32 reg = readl(plat->regbase + CQSPI_REG_SDRAMLEVEL);
+ u32 reg = readl(priv->regbase + CQSPI_REG_SDRAMLEVEL);
reg >>= CQSPI_REG_SDRAMLEVEL_RD_LSB;
return reg & CQSPI_REG_SDRAMLEVEL_RD_MASK;
}
-static int cadence_qspi_wait_for_data(struct cadence_spi_plat *plat)
+static int cadence_qspi_wait_for_data(struct cadence_spi_priv *priv)
{
unsigned int timeout = 10000;
u32 reg;
while (timeout--) {
- reg = cadence_qspi_get_rd_sram_level(plat);
+ reg = cadence_qspi_get_rd_sram_level(priv);
if (reg)
return reg;
udelay(1);
@@ -658,21 +658,21 @@ static int cadence_qspi_wait_for_data(struct cadence_spi_plat *plat)
}
static int
-cadence_qspi_apb_indirect_read_execute(struct cadence_spi_plat *plat,
+cadence_qspi_apb_indirect_read_execute(struct cadence_spi_priv *priv,
unsigned int n_rx, u8 *rxbuf)
{
unsigned int remaining = n_rx;
unsigned int bytes_to_read = 0;
int ret;
- writel(n_rx, plat->regbase + CQSPI_REG_INDIRECTRDBYTES);
+ writel(n_rx, priv->regbase + CQSPI_REG_INDIRECTRDBYTES);
/* Start the indirect read transfer */
writel(CQSPI_REG_INDIRECTRD_START,
- plat->regbase + CQSPI_REG_INDIRECTRD);
+ priv->regbase + CQSPI_REG_INDIRECTRD);
while (remaining > 0) {
- ret = cadence_qspi_wait_for_data(plat);
+ ret = cadence_qspi_wait_for_data(priv);
if (ret < 0) {
printf("Indirect write timed out (%i)\n", ret);
goto failrd;
@@ -681,7 +681,7 @@ cadence_qspi_apb_indirect_read_execute(struct cadence_spi_plat *plat,
bytes_to_read = ret;
while (bytes_to_read != 0) {
- bytes_to_read *= plat->fifo_width;
+ bytes_to_read *= priv->fifo_width;
bytes_to_read = bytes_to_read > remaining ?
remaining : bytes_to_read;
/*
@@ -689,18 +689,18 @@ cadence_qspi_apb_indirect_read_execute(struct cadence_spi_plat *plat,
* data abort.
*/
if (((uintptr_t)rxbuf % 4) || (bytes_to_read % 4))
- readsb(plat->ahbbase, rxbuf, bytes_to_read);
+ readsb(priv->ahbbase, rxbuf, bytes_to_read);
else
- readsl(plat->ahbbase, rxbuf,
+ readsl(priv->ahbbase, rxbuf,
bytes_to_read >> 2);
rxbuf += bytes_to_read;
remaining -= bytes_to_read;
- bytes_to_read = cadence_qspi_get_rd_sram_level(plat);
+ bytes_to_read = cadence_qspi_get_rd_sram_level(priv);
}
}
/* Check indirect done status */
- ret = wait_for_bit_le32(plat->regbase + CQSPI_REG_INDIRECTRD,
+ ret = wait_for_bit_le32(priv->regbase + CQSPI_REG_INDIRECTRD,
CQSPI_REG_INDIRECTRD_DONE, 1, 10, 0);
if (ret) {
printf("Indirect read completion error (%i)\n", ret);
@@ -709,10 +709,10 @@ cadence_qspi_apb_indirect_read_execute(struct cadence_spi_plat *plat,
/* Clear indirect completion status */
writel(CQSPI_REG_INDIRECTRD_DONE,
- plat->regbase + CQSPI_REG_INDIRECTRD);
+ priv->regbase + CQSPI_REG_INDIRECTRD);
/* Check indirect done status */
- ret = wait_for_bit_le32(plat->regbase + CQSPI_REG_INDIRECTRD,
+ ret = wait_for_bit_le32(priv->regbase + CQSPI_REG_INDIRECTRD,
CQSPI_REG_INDIRECTRD_DONE, 0, 10, 0);
if (ret) {
printf("Indirect read clear completion error (%i)\n", ret);
@@ -724,11 +724,11 @@ cadence_qspi_apb_indirect_read_execute(struct cadence_spi_plat *plat,
failrd:
/* Cancel the indirect read */
writel(CQSPI_REG_INDIRECTRD_CANCEL,
- plat->regbase + CQSPI_REG_INDIRECTRD);
+ priv->regbase + CQSPI_REG_INDIRECTRD);
return ret;
}
-int cadence_qspi_apb_read_execute(struct cadence_spi_plat *plat,
+int cadence_qspi_apb_read_execute(struct cadence_spi_priv *priv,
const struct spi_mem_op *op)
{
u64 from = op->addr.val;
@@ -738,57 +738,57 @@ int cadence_qspi_apb_read_execute(struct cadence_spi_plat *plat,
if (CONFIG_IS_ENABLED(ARCH_VERSAL))
cadence_qspi_apb_enable_linear_mode(true);
- if (plat->use_dac_mode && (from + len < plat->ahbsize)) {
+ if (priv->use_dac_mode && (from + len < priv->ahbsize)) {
if (len < 256 ||
- dma_memcpy(buf, plat->ahbbase + from, len) < 0) {
- memcpy_fromio(buf, plat->ahbbase + from, len);
+ dma_memcpy(buf, priv->ahbbase + from, len) < 0) {
+ memcpy_fromio(buf, priv->ahbbase + from, len);
}
- if (!cadence_qspi_wait_idle(plat->regbase))
+ if (!cadence_qspi_wait_idle(priv->regbase))
return -EIO;
return 0;
}
- return cadence_qspi_apb_indirect_read_execute(plat, len, buf);
+ return cadence_qspi_apb_indirect_read_execute(priv, len, buf);
}
/* Opcode + Address (3/4 bytes) */
-int cadence_qspi_apb_write_setup(struct cadence_spi_plat *plat,
+int cadence_qspi_apb_write_setup(struct cadence_spi_priv *priv,
const struct spi_mem_op *op)
{
unsigned int reg;
int ret;
u8 opcode;
- ret = cadence_qspi_set_protocol(plat, op);
+ ret = cadence_qspi_set_protocol(priv, op);
if (ret)
return ret;
- ret = cadence_qspi_enable_dtr(plat, op, CQSPI_REG_OP_EXT_WRITE_LSB,
- plat->dtr);
+ ret = cadence_qspi_enable_dtr(priv, op, CQSPI_REG_OP_EXT_WRITE_LSB,
+ priv->dtr);
if (ret)
return ret;
/* Setup the indirect trigger address */
- writel(plat->trigger_address,
- plat->regbase + CQSPI_REG_INDIRECTTRIGGER);
+ writel(priv->trigger_address,
+ priv->regbase + CQSPI_REG_INDIRECTTRIGGER);
/* Configure the opcode */
- if (plat->dtr)
+ if (priv->dtr)
opcode = op->cmd.opcode >> 8;
else
opcode = op->cmd.opcode;
reg = opcode << CQSPI_REG_WR_INSTR_OPCODE_LSB;
- reg |= plat->data_width << CQSPI_REG_WR_INSTR_TYPE_DATA_LSB;
- reg |= plat->addr_width << CQSPI_REG_WR_INSTR_TYPE_ADDR_LSB;
- writel(reg, plat->regbase + CQSPI_REG_WR_INSTR);
+ reg |= priv->data_width << CQSPI_REG_WR_INSTR_TYPE_DATA_LSB;
+ reg |= priv->addr_width << CQSPI_REG_WR_INSTR_TYPE_ADDR_LSB;
+ writel(reg, priv->regbase + CQSPI_REG_WR_INSTR);
- reg = cadence_qspi_calc_rdreg(plat);
- writel(reg, plat->regbase + CQSPI_REG_RD_INSTR);
+ reg = cadence_qspi_calc_rdreg(priv);
+ writel(reg, priv->regbase + CQSPI_REG_RD_INSTR);
- writel(op->addr.val, plat->regbase + CQSPI_REG_INDIRECTWRSTARTADDR);
+ writel(op->addr.val, priv->regbase + CQSPI_REG_INDIRECTWRSTARTADDR);
- if (plat->dtr) {
+ if (priv->dtr) {
/*
* Some flashes like the cypress Semper flash expect a 4-byte
* dummy address with the Read SR command in DTR mode, but this
@@ -797,23 +797,23 @@ int cadence_qspi_apb_write_setup(struct cadence_spi_plat *plat,
* controller's side. spi-nor will take care of polling the
* status register.
*/
- reg = readl(plat->regbase + CQSPI_REG_WR_COMPLETION_CTRL);
+ reg = readl(priv->regbase + CQSPI_REG_WR_COMPLETION_CTRL);
reg |= CQSPI_REG_WR_DISABLE_AUTO_POLL;
- writel(reg, plat->regbase + CQSPI_REG_WR_COMPLETION_CTRL);
+ writel(reg, priv->regbase + CQSPI_REG_WR_COMPLETION_CTRL);
}
- reg = readl(plat->regbase + CQSPI_REG_SIZE);
+ reg = readl(priv->regbase + CQSPI_REG_SIZE);
reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
reg |= (op->addr.nbytes - 1);
- writel(reg, plat->regbase + CQSPI_REG_SIZE);
+ writel(reg, priv->regbase + CQSPI_REG_SIZE);
return 0;
}
static int
-cadence_qspi_apb_indirect_write_execute(struct cadence_spi_plat *plat,
+cadence_qspi_apb_indirect_write_execute(struct cadence_spi_priv *priv,
unsigned int n_tx, const u8 *txbuf)
{
- unsigned int page_size = plat->page_size;
+ unsigned int page_size = priv->page_size;
unsigned int remaining = n_tx;
const u8 *bb_txbuf = txbuf;
void *bounce_buf = NULL;
@@ -833,27 +833,27 @@ cadence_qspi_apb_indirect_write_execute(struct cadence_spi_plat *plat,
}
/* Configure the indirect read transfer bytes */
- writel(n_tx, plat->regbase + CQSPI_REG_INDIRECTWRBYTES);
+ writel(n_tx, priv->regbase + CQSPI_REG_INDIRECTWRBYTES);
/* Start the indirect write transfer */
writel(CQSPI_REG_INDIRECTWR_START,
- plat->regbase + CQSPI_REG_INDIRECTWR);
+ priv->regbase + CQSPI_REG_INDIRECTWR);
/*
* Some delay is required for the above bit to be internally
* synchronized by the QSPI module.
*/
- ndelay(plat->wr_delay);
+ ndelay(priv->wr_delay);
while (remaining > 0) {
write_bytes = remaining > page_size ? page_size : remaining;
- writesl(plat->ahbbase, bb_txbuf, write_bytes >> 2);
+ writesl(priv->ahbbase, bb_txbuf, write_bytes >> 2);
if (write_bytes % 4)
- writesb(plat->ahbbase,
+ writesb(priv->ahbbase,
bb_txbuf + rounddown(write_bytes, 4),
write_bytes % 4);
- ret = wait_for_bit_le32(plat->regbase + CQSPI_REG_SDRAMLEVEL,
+ ret = wait_for_bit_le32(priv->regbase + CQSPI_REG_SDRAMLEVEL,
CQSPI_REG_SDRAMLEVEL_WR_MASK <<
CQSPI_REG_SDRAMLEVEL_WR_LSB, 0, 10, 0);
if (ret) {
@@ -866,7 +866,7 @@ cadence_qspi_apb_indirect_write_execute(struct cadence_spi_plat *plat,
}
/* Check indirect done status */
- ret = wait_for_bit_le32(plat->regbase + CQSPI_REG_INDIRECTWR,
+ ret = wait_for_bit_le32(priv->regbase + CQSPI_REG_INDIRECTWR,
CQSPI_REG_INDIRECTWR_DONE, 1, 10, 0);
if (ret) {
printf("Indirect write completion error (%i)\n", ret);
@@ -875,10 +875,10 @@ cadence_qspi_apb_indirect_write_execute(struct cadence_spi_plat *plat,
/* Clear indirect completion status */
writel(CQSPI_REG_INDIRECTWR_DONE,
- plat->regbase + CQSPI_REG_INDIRECTWR);
+ priv->regbase + CQSPI_REG_INDIRECTWR);
/* Check indirect done status */
- ret = wait_for_bit_le32(plat->regbase + CQSPI_REG_INDIRECTWR,
+ ret = wait_for_bit_le32(priv->regbase + CQSPI_REG_INDIRECTWR,
CQSPI_REG_INDIRECTWR_DONE, 0, 10, 0);
if (ret) {
printf("Indirect write clear completion error (%i)\n", ret);
@@ -892,13 +892,13 @@ cadence_qspi_apb_indirect_write_execute(struct cadence_spi_plat *plat,
failwr:
/* Cancel the indirect write */
writel(CQSPI_REG_INDIRECTWR_CANCEL,
- plat->regbase + CQSPI_REG_INDIRECTWR);
+ priv->regbase + CQSPI_REG_INDIRECTWR);
if (bounce_buf)
free(bounce_buf);
return ret;
}
-int cadence_qspi_apb_write_execute(struct cadence_spi_plat *plat,
+int cadence_qspi_apb_write_execute(struct cadence_spi_priv *priv,
const struct spi_mem_op *op)
{
u32 to = op->addr.val;
@@ -916,14 +916,15 @@ int cadence_qspi_apb_write_execute(struct cadence_spi_plat *plat,
* mode. So, we can not use direct mode when in DTR mode for writing
* data.
*/
- if (!plat->dtr && plat->use_dac_mode && (to + len < plat->ahbsize)) {
- memcpy_toio(plat->ahbbase + to, buf, len);
- if (!cadence_qspi_wait_idle(plat->regbase))
+ cadence_qspi_apb_enable_linear_mode(true);
+ if (!priv->dtr && priv->use_dac_mode && (to + len < priv->ahbsize)) {
+ memcpy_toio(priv->ahbbase + to, buf, len);
+ if (!cadence_qspi_wait_idle(priv->regbase))
return -EIO;
return 0;
}
- return cadence_qspi_apb_indirect_write_execute(plat, len, buf);
+ return cadence_qspi_apb_indirect_write_execute(priv, len, buf);
}
void cadence_qspi_apb_enter_xip(void *reg_base, char xip_dummy)
diff --git a/drivers/spi/zynqmp_gqspi.c b/drivers/spi/zynqmp_gqspi.c
index c772bae3ccf..4e718c545c6 100644
--- a/drivers/spi/zynqmp_gqspi.c
+++ b/drivers/spi/zynqmp_gqspi.c
@@ -22,6 +22,8 @@
#include <dm/device_compat.h>
#include <linux/bitops.h>
#include <linux/err.h>
+#include <linux/sizes.h>
+#include <zynqmp_firmware.h>
#define GQSPI_GFIFO_STRT_MODE_MASK BIT(29)
#define GQSPI_CONFIG_MODE_EN_MASK (3 << 30)
@@ -102,8 +104,10 @@
#define TAP_DLY_BYPASS_LQSPI_RX_VALUE 0x1
#define TAP_DLY_BYPASS_LQSPI_RX_SHIFT 2
#define GQSPI_DATA_DLY_ADJ_OFST 0x000001F8
-#define IOU_TAPDLY_BYPASS_OFST 0xFF180390
+#define IOU_TAPDLY_BYPASS_OFST !IS_ENABLED(CONFIG_ARCH_VERSAL) ? \
+ 0xFF180390 : 0xF103003C
#define GQSPI_LPBK_DLY_ADJ_LPBK_MASK 0x00000020
+#define GQSPI_FREQ_37_5MHZ 37500000
#define GQSPI_FREQ_40MHZ 40000000
#define GQSPI_FREQ_100MHZ 100000000
#define GQSPI_FREQ_150MHZ 150000000
@@ -163,6 +167,7 @@ struct zynqmp_qspi_plat {
struct zynqmp_qspi_dma_regs *dma_regs;
u32 frequency;
u32 speed_hz;
+ unsigned int io_mode;
};
struct zynqmp_qspi_priv {
@@ -171,6 +176,7 @@ struct zynqmp_qspi_priv {
const void *tx_buf;
void *rx_buf;
unsigned int len;
+ unsigned int io_mode;
int bytes_to_transfer;
int bytes_to_receive;
const struct spi_mem_op *op;
@@ -187,6 +193,8 @@ static int zynqmp_qspi_of_to_plat(struct udevice *bus)
plat->dma_regs = (struct zynqmp_qspi_dma_regs *)
(dev_read_addr(bus) + GQSPI_DMA_REG_OFFSET);
+ plat->io_mode = dev_read_bool(bus, "has-io-mode");
+
return 0;
}
@@ -206,8 +214,11 @@ static void zynqmp_qspi_init_hw(struct zynqmp_qspi_priv *priv)
config_reg = readl(&regs->confr);
config_reg &= ~(GQSPI_GFIFO_STRT_MODE_MASK |
GQSPI_CONFIG_MODE_EN_MASK);
- config_reg |= GQSPI_CONFIG_DMA_MODE | GQSPI_GFIFO_WP_HOLD |
- GQSPI_DFLT_BAUD_RATE_DIV | GQSPI_GFIFO_STRT_MODE_MASK;
+ config_reg |= GQSPI_GFIFO_WP_HOLD | GQSPI_DFLT_BAUD_RATE_DIV;
+ config_reg |= GQSPI_GFIFO_STRT_MODE_MASK;
+ if (!priv->io_mode)
+ config_reg |= GQSPI_CONFIG_DMA_MODE;
+
writel(config_reg, &regs->confr);
writel(GQSPI_ENABLE_ENABLE_MASK, &regs->enbr);
@@ -297,28 +308,41 @@ void zynqmp_qspi_set_tapdelay(struct udevice *bus, u32 baudrateval)
debug("%s, req_hz:%d, clk_rate:%d, baudrateval:%d\n",
__func__, reqhz, clk_rate, baudrateval);
- if (reqhz < GQSPI_FREQ_40MHZ) {
- zynqmp_mmio_read(IOU_TAPDLY_BYPASS_OFST, &tapdlybypass);
- tapdlybypass |= (TAP_DLY_BYPASS_LQSPI_RX_VALUE <<
- TAP_DLY_BYPASS_LQSPI_RX_SHIFT);
- } else if (reqhz <= GQSPI_FREQ_100MHZ) {
- zynqmp_mmio_read(IOU_TAPDLY_BYPASS_OFST, &tapdlybypass);
- tapdlybypass |= (TAP_DLY_BYPASS_LQSPI_RX_VALUE <<
- TAP_DLY_BYPASS_LQSPI_RX_SHIFT);
- lpbkdlyadj = readl(&regs->lpbkdly);
- lpbkdlyadj |= (GQSPI_LPBK_DLY_ADJ_LPBK_MASK);
- datadlyadj = readl(&regs->gqspidlyadj);
- datadlyadj |= ((GQSPI_USE_DATA_DLY << GQSPI_USE_DATA_DLY_SHIFT)
- | (GQSPI_DATA_DLY_ADJ_VALUE <<
- GQSPI_DATA_DLY_ADJ_SHIFT));
- } else if (reqhz <= GQSPI_FREQ_150MHZ) {
- lpbkdlyadj = readl(&regs->lpbkdly);
- lpbkdlyadj |= ((GQSPI_LPBK_DLY_ADJ_LPBK_MASK) |
- GQSPI_LPBK_DLY_ADJ_DLY_0);
+ if (!IS_ENABLED(CONFIG_ARCH_VERSAL)) {
+ if (reqhz <= GQSPI_FREQ_40MHZ) {
+ tapdlybypass = TAP_DLY_BYPASS_LQSPI_RX_VALUE <<
+ TAP_DLY_BYPASS_LQSPI_RX_SHIFT;
+ } else if (reqhz <= GQSPI_FREQ_100MHZ) {
+ tapdlybypass = TAP_DLY_BYPASS_LQSPI_RX_VALUE <<
+ TAP_DLY_BYPASS_LQSPI_RX_SHIFT;
+ lpbkdlyadj = GQSPI_LPBK_DLY_ADJ_LPBK_MASK;
+ datadlyadj = (GQSPI_USE_DATA_DLY <<
+ GQSPI_USE_DATA_DLY_SHIFT) |
+ (GQSPI_DATA_DLY_ADJ_VALUE <<
+ GQSPI_DATA_DLY_ADJ_SHIFT);
+ } else if (reqhz <= GQSPI_FREQ_150MHZ) {
+ lpbkdlyadj = GQSPI_LPBK_DLY_ADJ_LPBK_MASK |
+ GQSPI_LPBK_DLY_ADJ_DLY_0;
+ }
+ zynqmp_mmio_write(IOU_TAPDLY_BYPASS_OFST,
+ IOU_TAPDLY_BYPASS_MASK, tapdlybypass);
+ } else {
+ if (reqhz <= GQSPI_FREQ_37_5MHZ) {
+ tapdlybypass = TAP_DLY_BYPASS_LQSPI_RX_VALUE <<
+ TAP_DLY_BYPASS_LQSPI_RX_SHIFT;
+ } else if (reqhz <= GQSPI_FREQ_100MHZ) {
+ tapdlybypass = TAP_DLY_BYPASS_LQSPI_RX_VALUE <<
+ TAP_DLY_BYPASS_LQSPI_RX_SHIFT;
+ lpbkdlyadj = GQSPI_LPBK_DLY_ADJ_LPBK_MASK;
+ datadlyadj = GQSPI_USE_DATA_DLY <<
+ GQSPI_USE_DATA_DLY_SHIFT;
+ } else if (reqhz <= GQSPI_FREQ_150MHZ) {
+ lpbkdlyadj = GQSPI_LPBK_DLY_ADJ_LPBK_MASK |
+ (GQSPI_LPBK_DLY_ADJ_DLY_1 <<
+ GQSPI_LPBK_DLY_ADJ_DLY_1_SHIFT);
+ }
+ writel(tapdlybypass, IOU_TAPDLY_BYPASS_OFST);
}
-
- zynqmp_mmio_write(IOU_TAPDLY_BYPASS_OFST, IOU_TAPDLY_BYPASS_MASK,
- tapdlybypass);
writel(lpbkdlyadj, &regs->lpbkdly);
writel(datadlyadj, &regs->gqspidlyadj);
}
@@ -372,6 +396,7 @@ static int zynqmp_qspi_probe(struct udevice *bus)
priv->regs = plat->regs;
priv->dma_regs = plat->dma_regs;
+ priv->io_mode = plat->io_mode;
ret = clk_get_by_index(bus, 0, &clk);
if (ret < 0) {
@@ -409,8 +434,7 @@ static int zynqmp_qspi_set_mode(struct udevice *bus, uint mode)
debug("%s\n", __func__);
/* Set the SPI Clock phase and polarities */
confr = readl(&regs->confr);
- confr &= ~(GQSPI_CONFIG_CPHA_MASK |
- GQSPI_CONFIG_CPOL_MASK);
+ confr &= ~(GQSPI_CONFIG_CPHA_MASK | GQSPI_CONFIG_CPOL_MASK);
if (mode & SPI_CPHA)
confr |= GQSPI_CONFIG_CPHA_MASK;
@@ -554,8 +578,7 @@ static int zynqmp_qspi_genfifo_fill_tx(struct zynqmp_qspi_priv *priv)
gen_fifo_cmd = zynqmp_qspi_bus_select(priv);
gen_fifo_cmd |= zynqmp_qspi_genfifo_mode(priv->op->data.buswidth);
- gen_fifo_cmd |= GQSPI_GFIFO_TX |
- GQSPI_GFIFO_DATA_XFR_MASK;
+ gen_fifo_cmd |= GQSPI_GFIFO_TX | GQSPI_GFIFO_DATA_XFR_MASK;
while (priv->len) {
len = zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd);
@@ -564,11 +587,9 @@ static int zynqmp_qspi_genfifo_fill_tx(struct zynqmp_qspi_priv *priv)
debug("GFIFO_CMD_TX:0x%x\n", gen_fifo_cmd);
if (gen_fifo_cmd & GQSPI_GFIFO_EXP_MASK)
- ret = zynqmp_qspi_fill_tx_fifo(priv,
- 1 << len);
+ ret = zynqmp_qspi_fill_tx_fifo(priv, 1 << len);
else
- ret = zynqmp_qspi_fill_tx_fifo(priv,
- len);
+ ret = zynqmp_qspi_fill_tx_fifo(priv, len);
if (ret)
return ret;
@@ -576,44 +597,119 @@ static int zynqmp_qspi_genfifo_fill_tx(struct zynqmp_qspi_priv *priv)
return ret;
}
+static int zynqmp_qspi_start_io(struct zynqmp_qspi_priv *priv,
+ u32 gen_fifo_cmd, u32 *buf)
+{
+ u32 len;
+ u32 actuallen = priv->len;
+ u32 config_reg, ier, isr;
+ u32 timeout = GQSPI_TIMEOUT;
+ struct zynqmp_qspi_regs *regs = priv->regs;
+ u32 last_bits;
+ u32 *traverse = buf;
+
+ while (priv->len) {
+ len = zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd);
+ /* If exponent bit is set, reset immediate to be 2^len */
+ if (gen_fifo_cmd & GQSPI_GFIFO_EXP_MASK)
+ priv->bytes_to_receive = (1 << len);
+ else
+ priv->bytes_to_receive = len;
+ zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd);
+ debug("GFIFO_CMD_RX:0x%x\n", gen_fifo_cmd);
+ /* Manual start */
+ config_reg = readl(&regs->confr);
+ config_reg |= GQSPI_STRT_GEN_FIFO;
+ writel(config_reg, &regs->confr);
+ /* Enable RX interrupts for IO mode */
+ ier = readl(&regs->ier);
+ ier |= GQSPI_IXR_ALL_MASK;
+ writel(ier, &regs->ier);
+ while (priv->bytes_to_receive && timeout) {
+ isr = readl(&regs->isr);
+ if (isr & GQSPI_IXR_RXNEMTY_MASK) {
+ if (priv->bytes_to_receive >= 4) {
+ *traverse = readl(&regs->drxr);
+ traverse++;
+ priv->bytes_to_receive -= 4;
+ } else {
+ last_bits = readl(&regs->drxr);
+ memcpy(traverse, &last_bits,
+ priv->bytes_to_receive);
+ priv->bytes_to_receive = 0;
+ }
+ timeout = GQSPI_TIMEOUT;
+ } else {
+ udelay(1);
+ timeout--;
+ }
+ }
+
+ debug("buf:0x%lx, rxbuf:0x%lx, *buf:0x%x len: 0x%x\n",
+ (unsigned long)buf, (unsigned long)priv->rx_buf,
+ *buf, actuallen);
+ if (!timeout) {
+ printf("IO timeout: %d\n", readl(&regs->isr));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
static int zynqmp_qspi_start_dma(struct zynqmp_qspi_priv *priv,
u32 gen_fifo_cmd, u32 *buf)
{
u32 addr;
u32 size;
u32 actuallen = priv->len;
+ u32 totallen = priv->len;
int ret = 0;
struct zynqmp_qspi_dma_regs *dma_regs = priv->dma_regs;
- writel((unsigned long)buf, &dma_regs->dmadst);
- writel(roundup(priv->len, GQSPI_DMA_ALIGN), &dma_regs->dmasize);
- writel(GQSPI_DMA_DST_I_STS_MASK, &dma_regs->dmaier);
- addr = (unsigned long)buf;
- size = roundup(priv->len, GQSPI_DMA_ALIGN);
- flush_dcache_range(addr, addr + size);
+ while (totallen) {
+ if (totallen >= SZ_512M)
+ priv->len = SZ_256M;
+ else
+ priv->len = totallen;
- while (priv->len) {
- zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd);
- zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd);
+ totallen -= priv->len; /* Save remaining bytes length to read */
+ actuallen = priv->len; /* Actual number of bytes reading */
- debug("GFIFO_CMD_RX:0x%x\n", gen_fifo_cmd);
- }
+ writel((unsigned long)buf, &dma_regs->dmadst);
+ writel(roundup(priv->len, GQSPI_DMA_ALIGN), &dma_regs->dmasize);
+ writel(GQSPI_DMA_DST_I_STS_MASK, &dma_regs->dmaier);
+ addr = (unsigned long)buf;
+ size = roundup(priv->len, GQSPI_DMA_ALIGN);
+ flush_dcache_range(addr, addr + size);
- ret = wait_for_bit_le32(&dma_regs->dmaisr, GQSPI_DMA_DST_I_STS_DONE,
- 1, GQSPI_TIMEOUT, 1);
- if (ret) {
- printf("DMA Timeout:0x%x\n", readl(&dma_regs->dmaisr));
- return -ETIMEDOUT;
- }
+ while (priv->len) {
+ zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd);
+ zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd);
+
+ debug("GFIFO_CMD_RX:0x%x\n", gen_fifo_cmd);
+ }
+
+ ret = wait_for_bit_le32(&dma_regs->dmaisr,
+ GQSPI_DMA_DST_I_STS_DONE, 1,
+ GQSPI_TIMEOUT, 1);
+ if (ret) {
+ printf("DMA Timeout:0x%x\n", readl(&dma_regs->dmaisr));
+ return -ETIMEDOUT;
+ }
- writel(GQSPI_DMA_DST_I_STS_DONE, &dma_regs->dmaisr);
+ writel(GQSPI_DMA_DST_I_STS_DONE, &dma_regs->dmaisr);
- debug("buf:0x%lx, rxbuf:0x%lx, *buf:0x%x len: 0x%x\n",
- (unsigned long)buf, (unsigned long)priv->rx_buf, *buf,
- actuallen);
+ debug("buf:0x%lx, rxbuf:0x%lx, *buf:0x%x len: 0x%x\n",
+ (unsigned long)buf, (unsigned long)priv->rx_buf, *buf,
+ actuallen);
- if (buf != priv->rx_buf)
- memcpy(priv->rx_buf, buf, actuallen);
+ if (buf != priv->rx_buf)
+ memcpy(priv->rx_buf, buf, actuallen);
+
+ buf = (u32 *)((u8 *)buf + actuallen);
+ priv->rx_buf = (u8 *)priv->rx_buf + actuallen;
+ }
return 0;
}
@@ -626,21 +722,22 @@ static int zynqmp_qspi_genfifo_fill_rx(struct zynqmp_qspi_priv *priv)
gen_fifo_cmd = zynqmp_qspi_bus_select(priv);
gen_fifo_cmd |= zynqmp_qspi_genfifo_mode(priv->op->data.buswidth);
- gen_fifo_cmd |= GQSPI_GFIFO_RX |
- GQSPI_GFIFO_DATA_XFR_MASK;
+ gen_fifo_cmd |= GQSPI_GFIFO_RX | GQSPI_GFIFO_DATA_XFR_MASK;
/*
* Check if receive buffer is aligned to 4 byte and length
* is multiples of four byte as we are using dma to receive.
*/
- if (!((unsigned long)priv->rx_buf & (GQSPI_DMA_ALIGN - 1)) &&
- !(actuallen % GQSPI_DMA_ALIGN)) {
+ if ((!((unsigned long)priv->rx_buf & (GQSPI_DMA_ALIGN - 1)) &&
+ !(actuallen % GQSPI_DMA_ALIGN)) || priv->io_mode) {
buf = (u32 *)priv->rx_buf;
- return zynqmp_qspi_start_dma(priv, gen_fifo_cmd, buf);
+ if (priv->io_mode)
+ return zynqmp_qspi_start_io(priv, gen_fifo_cmd, buf);
+ else
+ return zynqmp_qspi_start_dma(priv, gen_fifo_cmd, buf);
}
- ALLOC_CACHE_ALIGN_BUFFER(u8, tmp, roundup(priv->len,
- GQSPI_DMA_ALIGN));
+ ALLOC_CACHE_ALIGN_BUFFER(u8, tmp, roundup(priv->len, GQSPI_DMA_ALIGN));
buf = (u32 *)tmp;
return zynqmp_qspi_start_dma(priv, gen_fifo_cmd, buf);
}
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
index 40492901481..1b492360396 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -73,6 +73,12 @@ config ARC_TIMER
usually at least one of them exists. Either of them is supported
in U-Boot.
+config ARM_TWD_TIMER
+ bool "ARM timer watchdog (TWD) timer support"
+ depends on TIMER && CLK
+ help
+ Select this to enable support for the ARM global timer watchdog timer.
+
config AST_TIMER
bool "Aspeed ast2400/ast2500 timer support"
depends on TIMER
diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile
index 560e2d27e14..7bfb7749e97 100644
--- a/drivers/timer/Makefile
+++ b/drivers/timer/Makefile
@@ -6,6 +6,7 @@ obj-y += timer-uclass.o
obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o
obj-$(CONFIG_ANDES_PLMT_TIMER) += andes_plmt_timer.o
obj-$(CONFIG_ARC_TIMER) += arc_timer.o
+obj-$(CONFIG_ARM_TWD_TIMER) += arm_twd_timer.o
obj-$(CONFIG_AST_TIMER) += ast_timer.o
obj-$(CONFIG_ATCPIT100_TIMER) += atcpit100_timer.o
obj-$(CONFIG_$(SPL_)ATMEL_PIT_TIMER) += atmel_pit_timer.o
diff --git a/drivers/timer/arm_twd_timer.c b/drivers/timer/arm_twd_timer.c
new file mode 100644
index 00000000000..40ccd165874
--- /dev/null
+++ b/drivers/timer/arm_twd_timer.c
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017-2022 Weidmüller Interface GmbH & Co. KG
+ * Stefan Herbrechtsmeier <[email protected]>
+ *
+ * Copyright (C) 2012 Michal Simek <[email protected]>
+ * Copyright (C) 2011-2017 Xilinx, Inc. All rights reserved.
+ *
+ * (C) Copyright 2008
+ * Guennadi Liakhovetki, DENX Software Engineering, <[email protected]>
+ *
+ * (C) Copyright 2004
+ * Philippe Robin, ARM Ltd. <[email protected]>
+ *
+ * (C) Copyright 2002-2004
+ * Gary Jennejohn, DENX Software Engineering, <[email protected]>
+ *
+ * (C) Copyright 2003
+ * Texas Instruments <www.ti.com>
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <[email protected]>
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Alex Zuepke <[email protected]>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <timer.h>
+#include <linux/bitops.h>
+
+#include <asm/io.h>
+
+#define SCUTIMER_CONTROL_PRESCALER_MASK 0x0000FF00 /* Prescaler */
+#define SCUTIMER_CONTROL_AUTO_RELOAD_MASK 0x00000002 /* Auto-reload */
+#define SCUTIMER_CONTROL_ENABLE_MASK 0x00000001 /* Timer enable */
+
+#define TIMER_LOAD_VAL 0xFFFFFFFF
+
+struct arm_twd_timer_regs {
+ u32 load; /* Timer Load Register */
+ u32 counter; /* Timer Counter Register */
+ u32 control; /* Timer Control Register */
+};
+
+struct arm_twd_timer_priv {
+ struct arm_twd_timer_regs *base;
+};
+
+static u64 arm_twd_timer_get_count(struct udevice *dev)
+{
+ struct arm_twd_timer_priv *priv = dev_get_priv(dev);
+ struct arm_twd_timer_regs *regs = priv->base;
+ u32 count = TIMER_LOAD_VAL - readl(&regs->counter);
+
+ return timer_conv_64(count);
+}
+
+static int arm_twd_timer_probe(struct udevice *dev)
+{
+ struct arm_twd_timer_priv *priv = dev_get_priv(dev);
+ struct arm_twd_timer_regs *regs;
+ fdt_addr_t addr;
+
+ addr = dev_read_addr(dev);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->base = (struct arm_twd_timer_regs *)addr;
+
+ regs = priv->base;
+
+ /* Load the timer counter register */
+ writel(0xFFFFFFFF, &regs->load);
+
+ /*
+ * Start the A9Timer device
+ * Enable Auto reload mode, Clear prescaler control bits
+ * Set prescaler value, Enable the decrementer
+ */
+ clrsetbits_le32(&regs->control, SCUTIMER_CONTROL_PRESCALER_MASK,
+ SCUTIMER_CONTROL_AUTO_RELOAD_MASK |
+ SCUTIMER_CONTROL_ENABLE_MASK);
+
+ return 0;
+}
+
+static const struct timer_ops arm_twd_timer_ops = {
+ .get_count = arm_twd_timer_get_count,
+};
+
+static const struct udevice_id arm_twd_timer_ids[] = {
+ { .compatible = "arm,cortex-a9-twd-timer" },
+ {}
+};
+
+U_BOOT_DRIVER(arm_twd_timer) = {
+ .name = "arm_twd_timer",
+ .id = UCLASS_TIMER,
+ .of_match = arm_twd_timer_ids,
+ .priv_auto = sizeof(struct arm_twd_timer_priv),
+ .probe = arm_twd_timer_probe,
+ .ops = &arm_twd_timer_ops,
+};