[PATCH v7 12/18] spi: cadence-quadspi: enable PHY for indirect writes
Santhosh Kumar K <[email protected]>
| Newsgroups | org.kernel.vger.linux-spi,org.infradead.lists.linux-mtd,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel |
|---|---|
| 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 was calibrated at the post-config frequency (phy_write_op.max_freq matches), which restricts PHY writes to NAND devices where a write op template was provided to execute_tuning. NOR flash writes are unaffected. The indirect write is cancelled before disabling PHY in the error path so that cqspi_wait_idle() inside cqspi_tune_phy() does not time out while the controller is still waiting for AHB data. 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 | 39 +++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index 8903b4cf4f6f..940cfb72b946 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -157,6 +157,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 @@ -1362,18 +1364,32 @@ 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)) return -ENODEV; + /* 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) + return ret; + } + writel(to_addr, reg_base + CQSPI_REG_INDIRECTWRSTARTADDR); writel(remaining, reg_base + CQSPI_REG_INDIRECTWRBYTES); @@ -1452,15 +1468,26 @@ 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: /* Disable interrupt. */ writel(0, reg_base + CQSPI_REG_IRQMASK); - /* Cancel the indirect write */ + /* + * Cancel the indirect write before disabling PHY so that + * cqspi_wait_idle() inside cqspi_tune_phy() does not time out + * while the controller is still waiting for AHB data. + */ writel(CQSPI_REG_INDIRECTWR_CANCEL_MASK, reg_base + CQSPI_REG_INDIRECTWR); + + if (use_tuned_phy_write) + cqspi_tune_phy(f_pdata, false); + return ret; } @@ -1590,7 +1617,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; @@ -1617,7 +1645,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, @@ -1810,7 +1839,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