This reverts commit a040578d8270ed8788d7663808ea63ce5ffd7840. Based on feedback other SOCs (for example Star64) are using driver in non DMA mode which is causing issues that's why revert this patch. cdns,is-dma should be removed differently.
Signed-off-by: Michal Simek <[email protected]> --- Tom: Would be good if you can get this to rc1. --- arch/arm/dts/versal-mini-ospi.dtsi | 1 + arch/arm/dts/versal-net-mini-ospi.dtsi | 1 + drivers/spi/cadence_qspi.c | 8 +- drivers/spi/cadence_qspi.h | 5 ++ drivers/spi/cadence_qspi_apb.c | 119 +++++++++++++++++++++++++ 5 files changed, 133 insertions(+), 1 deletion(-) diff --git a/arch/arm/dts/versal-mini-ospi.dtsi b/arch/arm/dts/versal-mini-ospi.dtsi index 6991f6a51db0..eec2a08e7c70 100644 --- a/arch/arm/dts/versal-mini-ospi.dtsi +++ b/arch/arm/dts/versal-mini-ospi.dtsi @@ -38,6 +38,7 @@ num-cs = <1>; cdns,fifo-depth = <256>; cdns,fifo-width = <4>; + cdns,is-dma = <1>; cdns,trigger-address = <0xc0000000>; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/dts/versal-net-mini-ospi.dtsi b/arch/arm/dts/versal-net-mini-ospi.dtsi index d2d5ec8e5cbf..1c94b352dc97 100644 --- a/arch/arm/dts/versal-net-mini-ospi.dtsi +++ b/arch/arm/dts/versal-net-mini-ospi.dtsi @@ -52,6 +52,7 @@ num-cs = <1>; cdns,fifo-depth = <256>; cdns,fifo-width = <4>; + cdns,is-dma = <1>; cdns,is-stig-pgm = <1>; cdns,trigger-address = <0xc0000000>; #address-cells = <1>; diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c index 849bd930edf0..599596f9f087 100644 --- a/drivers/spi/cadence_qspi.c +++ b/drivers/spi/cadence_qspi.c @@ -210,6 +210,7 @@ static int cadence_spi_probe(struct udevice *bus) 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; @@ -347,7 +348,10 @@ static int cadence_spi_mem_exec_op(struct spi_slave *spi, case CQSPI_READ: err = cadence_qspi_apb_read_setup(priv, op); if (!err) { - err = cadence_qspi_apb_dma_read(priv, op); + if (priv->is_dma) + err = cadence_qspi_apb_dma_read(priv, op); + else + err = cadence_qspi_apb_read_execute(priv, op); } break; case CQSPI_WRITE: @@ -408,6 +412,8 @@ static int cadence_spi_of_to_plat(struct udevice *bus) if (plat->ahbsize >= SZ_8M) priv->use_dac_mode = true; + plat->is_dma = dev_read_bool(bus, "cdns,is-dma"); + /* All other parameters are embedded in the child node */ subnode = cadence_qspi_get_subnode(bus); if (!ofnode_valid(subnode)) { diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h index 10c4ad14cc05..879e7f8dbfb8 100644 --- a/drivers/spi/cadence_qspi.h +++ b/drivers/spi/cadence_qspi.h @@ -223,6 +223,8 @@ struct cadence_spi_plat { u32 tchsh_ns; u32 tslch_ns; u32 quirks; + + bool is_dma; }; struct cadence_spi_priv { @@ -259,6 +261,7 @@ struct cadence_spi_priv { bool ddr_init; bool is_decoded_cs; bool use_dac_mode; + bool is_dma; /* Transaction protocol parameters. */ u8 inst_width; @@ -289,6 +292,8 @@ int cadence_qspi_apb_command_write(struct cadence_spi_priv *priv, 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_priv *priv, + const struct spi_mem_op *op); 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_priv *priv, diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c index 58be017720bc..4696c09f754b 100644 --- a/drivers/spi/cadence_qspi_apb.c +++ b/drivers/spi/cadence_qspi_apb.c @@ -667,6 +667,125 @@ int cadence_qspi_apb_read_setup(struct cadence_spi_priv *priv, return 0; } +static u32 cadence_qspi_get_rd_sram_level(struct cadence_spi_priv *priv) +{ + 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_priv *priv) +{ + unsigned int timeout = 10000; + u32 reg; + + while (timeout--) { + reg = cadence_qspi_get_rd_sram_level(priv); + if (reg) + return reg; + udelay(1); + } + + return -ETIMEDOUT; +} + +static int +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, priv->regbase + CQSPI_REG_INDIRECTRDBYTES); + + /* Start the indirect read transfer */ + writel(CQSPI_REG_INDIRECTRD_START, + priv->regbase + CQSPI_REG_INDIRECTRD); + + while (remaining > 0) { + ret = cadence_qspi_wait_for_data(priv); + if (ret < 0) { + printf("Indirect write timed out (%i)\n", ret); + goto failrd; + } + + bytes_to_read = ret; + + while (bytes_to_read != 0) { + bytes_to_read *= priv->fifo_width; + bytes_to_read = bytes_to_read > remaining ? + remaining : bytes_to_read; + /* + * Handle non-4-byte aligned access to avoid + * data abort. + */ + if (((uintptr_t)rxbuf % 4) || (bytes_to_read % 4)) + readsb(priv->ahbbase, rxbuf, bytes_to_read); + else + 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(priv); + } + } + + /* Check indirect done status */ + 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); + goto failrd; + } + + /* Clear indirect completion status */ + writel(CQSPI_REG_INDIRECTRD_DONE, + priv->regbase + CQSPI_REG_INDIRECTRD); + + /* Check indirect done status */ + 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); + goto failrd; + } + + /* Wait til QSPI is idle */ + if (!cadence_qspi_wait_idle(priv->regbase)) + return -EIO; + + return 0; + +failrd: + /* Cancel the indirect read */ + writel(CQSPI_REG_INDIRECTRD_CANCEL, + priv->regbase + CQSPI_REG_INDIRECTRD); + return ret; +} + +int cadence_qspi_apb_read_execute(struct cadence_spi_priv *priv, + const struct spi_mem_op *op) +{ + u64 from = op->addr.val; + void *buf = op->data.buf.in; + size_t len = op->data.nbytes; + + cadence_qspi_apb_enable_linear_mode(true); + + if (priv->use_dac_mode && (from + len < priv->ahbsize)) { + if (len < 256 || + dma_memcpy(buf, priv->ahbbase + from, len) < 0) { + memcpy_fromio(buf, priv->ahbbase + from, len); + } + if (!cadence_qspi_wait_idle(priv->regbase)) + return -EIO; + return 0; + } + + return cadence_qspi_apb_indirect_read_execute(priv, len, buf); +} + /* Opcode + Address (3/4 bytes) */ int cadence_qspi_apb_write_setup(struct cadence_spi_priv *priv, const struct spi_mem_op *op) -- 2.43.0 base-commit: 5946afb20b6409eb72db634e2e61c97e8663895f

