[PATCH v6 12/17] spi: cadence-quadspi: enable PHY for indirect writes
Santhosh Kumar K <[email protected]> Thu, 23 Jul 2026 16:32:14 +0530
| Newsgroups | org.infradead.lists.linux-mtd,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel,org.kernel.vger.linux-spi |
|---|---|
| Message-ID | <[email protected]> |
Enable PHY for indirect writes of at least CQSPI_PHY_MIN_INDIRECT_WRITE_LEN bytes. PHY is activated only when tuning completed successfully and the write op runs at the calibrated post-config frequency, matching the same frequency guard used by the read path. Thread post_config_max_speed_hz from cqspi_mem_process() through cqspi_write() into cqspi_indirect_write_execute() for the frequency check. Signed-off-by: Santhosh Kumar K <[email protected]> --- drivers/spi/spi-cadence-quadspi.c | 32 +++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index 35a400073944..542ad331ff16 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -153,6 +153,8 @@ struct cqspi_driver_platdata { #define CQSPI_DLL_TIMEOUT_US 300 /* Minimum transfer length to use DMA for direct reads */ #define CQSPI_PHY_MIN_DIRECT_READ_LEN 17 +/* Minimum indirect write length to amortize PHY enable/disable overhead */ +#define CQSPI_PHY_MIN_INDIRECT_WRITE_LEN SZ_1K /* Runtime_pm autosuspend delay */ #define CQSPI_AUTOSUSPEND_TIMEOUT 2000 @@ -1335,13 +1337,15 @@ static int cqspi_write_setup(struct cqspi_flash_pdata *f_pdata, static int cqspi_indirect_write_execute(struct cqspi_flash_pdata *f_pdata, loff_t to_addr, const u8 *txbuf, - const size_t n_tx) + const size_t n_tx, + u32 post_config_max_speed_hz) { struct cqspi_st *cqspi = f_pdata->cqspi; struct device *dev = &cqspi->pdev->dev; void __iomem *reg_base = cqspi->iobase; unsigned int remaining = n_tx; unsigned int write_bytes; + bool use_tuned_phy_write; int ret; if (!refcount_read(&cqspi->refcount)) @@ -1377,6 +1381,18 @@ static int cqspi_indirect_write_execute(struct cqspi_flash_pdata *f_pdata, if (cqspi->apb_ahb_hazard) readl(reg_base + CQSPI_REG_INDIRECTWR); + /* Use PHY only for large writes at the calibrated rate */ + use_tuned_phy_write = n_tx >= CQSPI_PHY_MIN_INDIRECT_WRITE_LEN && + f_pdata->use_tuned_phy && + f_pdata->phy_write_op.max_freq == + post_config_max_speed_hz; + + if (use_tuned_phy_write) { + ret = cqspi_tune_phy(f_pdata, true); + if (ret) + goto failwr; + } + while (remaining > 0) { size_t write_words, mod_bytes; @@ -1425,9 +1441,15 @@ static int cqspi_indirect_write_execute(struct cqspi_flash_pdata *f_pdata, cqspi_wait_idle(cqspi); + if (use_tuned_phy_write) + cqspi_tune_phy(f_pdata, false); + return 0; failwr: + if (use_tuned_phy_write) + cqspi_tune_phy(f_pdata, false); + /* Disable interrupt. */ writel(0, reg_base + CQSPI_REG_IRQMASK); @@ -1562,7 +1584,8 @@ static void cqspi_configure(struct cqspi_flash_pdata *f_pdata, } static ssize_t cqspi_write(struct cqspi_flash_pdata *f_pdata, - const struct spi_mem_op *op) + const struct spi_mem_op *op, + u32 post_config_max_speed_hz) { struct cqspi_st *cqspi = f_pdata->cqspi; loff_t to = op->addr.val; @@ -1589,7 +1612,8 @@ static ssize_t cqspi_write(struct cqspi_flash_pdata *f_pdata, return cqspi_wait_idle(cqspi); } - return cqspi_indirect_write_execute(f_pdata, to, buf, len); + return cqspi_indirect_write_execute(f_pdata, to, buf, len, + post_config_max_speed_hz); } static bool cqspi_use_tuned_phy(struct cqspi_flash_pdata *f_pdata, @@ -1805,7 +1829,7 @@ static int cqspi_mem_process(struct spi_mem *mem, const struct spi_mem_op *op) if (!op->addr.nbytes || !op->data.buf.out) return cqspi_command_write(f_pdata, op); - return cqspi_write(f_pdata, op); + return cqspi_write(f_pdata, op, mem->spi->post_config_max_speed_hz); } static int cqspi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op) -- 2.34.1 ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/