From: Viken Dadhaniya Date: Wed, 29 Apr 2026 17:01:38 +0000 (+0530) Subject: spi: spi-qcom-qspi: Add interconnect support for memory path X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=104b5e9b85c00c3fe552032164bf5bbd78e0f0b4;p=thirdparty%2Flinux.git spi: spi-qcom-qspi: Add interconnect support for memory path The QSPI controller has two interconnect paths: 1. qspi-config: CPU to QSPI controller for register access 2. qspi-memory: QSPI controller to memory for DMA operations Currently, the driver only manages the qspi-config path. Add support for the qspi-memory path to ensure proper bandwidth allocation for QSPI data transfers to/from memory. Enable and disable both paths during runtime PM transitions. Signed-off-by: Viken Dadhaniya Link: https://patch.msgid.link/20260429-spi-nor-v5-3-993016c9711e@oss.qualcomm.com Signed-off-by: Mark Brown --- diff --git a/drivers/spi/spi-qcom-qspi.c b/drivers/spi/spi-qcom-qspi.c index edfbf0b5d1faa..caf55a6f70b31 100644 --- a/drivers/spi/spi-qcom-qspi.c +++ b/drivers/spi/spi-qcom-qspi.c @@ -174,6 +174,7 @@ struct qcom_qspi { void *virt_cmd_desc[QSPI_MAX_SG]; unsigned int n_cmd_desc; struct icc_path *icc_path_cpu_to_qspi; + struct icc_path *icc_path_mem; unsigned long last_speed; /* Lock to protect data accessed by IRQs */ spinlock_t lock; @@ -272,7 +273,7 @@ static void qcom_qspi_handle_err(struct spi_controller *host, static int qcom_qspi_set_speed(struct qcom_qspi *ctrl, unsigned long speed_hz) { int ret; - unsigned int avg_bw_cpu; + unsigned int avg_bw_cpu, avg_bw_mem; if (speed_hz == ctrl->last_speed) return 0; @@ -285,7 +286,7 @@ static int qcom_qspi_set_speed(struct qcom_qspi *ctrl, unsigned long speed_hz) } /* - * Set BW quota for CPU. + * Set BW quota for CPU and memory paths. * We don't have explicit peak requirement so keep it equal to avg_bw. */ avg_bw_cpu = Bps_to_icc(speed_hz); @@ -296,6 +297,13 @@ static int qcom_qspi_set_speed(struct qcom_qspi *ctrl, unsigned long speed_hz) return ret; } + avg_bw_mem = Bps_to_icc(speed_hz); + ret = icc_set_bw(ctrl->icc_path_mem, avg_bw_mem, avg_bw_mem); + if (ret) { + dev_err(ctrl->dev, "ICC BW voting failed for memory: %d\n", ret); + return ret; + } + ctrl->last_speed = speed_hz; return 0; @@ -729,6 +737,14 @@ static int qcom_qspi_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(ctrl->icc_path_cpu_to_qspi), "Failed to get cpu path\n"); + ctrl->icc_path_mem = devm_of_icc_get(dev, "qspi-memory"); + if (IS_ERR(ctrl->icc_path_mem)) { + if (PTR_ERR(ctrl->icc_path_mem) != -ENODATA) + return dev_err_probe(dev, PTR_ERR(ctrl->icc_path_mem), + "Failed to get memory path\n"); + ctrl->icc_path_mem = NULL; + } + /* Set BW vote for register access */ ret = icc_set_bw(ctrl->icc_path_cpu_to_qspi, Bps_to_icc(1000), Bps_to_icc(1000)); @@ -827,9 +843,15 @@ static int __maybe_unused qcom_qspi_runtime_suspend(struct device *dev) goto err_enable_clk; } + ret = icc_disable(ctrl->icc_path_mem); + if (ret) { + dev_err_ratelimited(ctrl->dev, "ICC disable failed for memory: %d\n", ret); + goto err_enable_icc_cpu; + } + ret = pinctrl_pm_select_sleep_state(dev); if (ret) - goto err_enable_icc; + goto err_enable_icc_mem; /* Drop the performance state vote */ ret = dev_pm_opp_set_rate(dev, 0); @@ -840,7 +862,9 @@ static int __maybe_unused qcom_qspi_runtime_suspend(struct device *dev) err_select_default_state: pinctrl_pm_select_default_state(dev); -err_enable_icc: +err_enable_icc_mem: + icc_enable(ctrl->icc_path_mem); +err_enable_icc_cpu: icc_enable(ctrl->icc_path_cpu_to_qspi); err_enable_clk: if (clk_bulk_prepare_enable(QSPI_NUM_CLKS, ctrl->clks)) @@ -869,13 +893,21 @@ static int __maybe_unused qcom_qspi_runtime_resume(struct device *dev) goto err_select_sleep_state; } + ret = icc_enable(ctrl->icc_path_mem); + if (ret) { + dev_err_ratelimited(ctrl->dev, "ICC enable failed for memory: %d\n", ret); + goto err_disable_icc_cpu; + } + ret = clk_bulk_prepare_enable(QSPI_NUM_CLKS, ctrl->clks); if (ret) - goto err_disable_icc; + goto err_disable_icc_mem; return 0; -err_disable_icc: +err_disable_icc_mem: + icc_disable(ctrl->icc_path_mem); +err_disable_icc_cpu: icc_disable(ctrl->icc_path_cpu_to_qspi); err_select_sleep_state: pinctrl_pm_select_sleep_state(dev);