]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
spi: cadence-qspi: defer runtime support on socfpga if reset bit is enabled
authorKhairul Anuar Romli <khairul.anuar.romli@altera.com>
Wed, 10 Sep 2025 08:06:32 +0000 (16:06 +0800)
committerMark Brown <broonie@kernel.org>
Thu, 18 Sep 2025 21:24:03 +0000 (22:24 +0100)
Enabling runtime PM allows the kernel to gate clocks and power to idle
devices. On SoCFPGA, a warm reset does not fully reinitialize these
domains.This leaves devices suspended and powered down, preventing U-Boot
or the kernel from reusing them after a warm reset, which breaks the boot
process.

Fixes: 4892b374c9b7 ("mtd: spi-nor: cadence-quadspi: Add runtime PM support")
CC: stable@vger.kernel.org # 6.12+
Signed-off-by: Khairul Anuar Romli <khairul.anuar.romli@altera.com>
Signed-off-by: Adrian Ng Ho Yin <adrianhoyin.ng@altera.com>
Reviewed-by: Niravkumar L Rabara <nirav.rabara@altera.com>
Reviewed-by: Matthew Gerlach <matthew.gerlach@altera.com>
Link: https://patch.msgid.link/910aad68ba5d948919a7b90fa85a2fadb687229b.1757491372.git.khairul.anuar.romli@altera.com
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/spi/spi-cadence-quadspi.c

index 9bf823348cd30db53abb9c76117b0d5f674064af..d288e9d9c18739186bebe48ee81b76d525c51b5b 100644 (file)
@@ -46,6 +46,7 @@ static_assert(CQSPI_MAX_CHIPSELECT <= SPI_CS_CNT_MAX);
 #define CQSPI_DMA_SET_MASK             BIT(7)
 #define CQSPI_SUPPORT_DEVICE_RESET     BIT(8)
 #define CQSPI_DISABLE_STIG_MODE                BIT(9)
+#define CQSPI_DISABLE_RUNTIME_PM       BIT(10)
 
 /* Capabilities */
 #define CQSPI_SUPPORTS_OCTAL           BIT(0)
@@ -1468,14 +1469,17 @@ static int cqspi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
        int ret;
        struct cqspi_st *cqspi = spi_controller_get_devdata(mem->spi->controller);
        struct device *dev = &cqspi->pdev->dev;
+       const struct cqspi_driver_platdata *ddata = of_device_get_match_data(dev);
 
        if (refcount_read(&cqspi->inflight_ops) == 0)
                return -ENODEV;
 
-       ret = pm_runtime_resume_and_get(dev);
-       if (ret) {
-               dev_err(&mem->spi->dev, "resume failed with %d\n", ret);
-               return ret;
+       if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) {
+               ret = pm_runtime_resume_and_get(dev);
+               if (ret) {
+                       dev_err(&mem->spi->dev, "resume failed with %d\n", ret);
+                       return ret;
+               }
        }
 
        if (!refcount_read(&cqspi->refcount))
@@ -1491,7 +1495,8 @@ static int cqspi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
 
        ret = cqspi_mem_process(mem, op);
 
-       pm_runtime_put_autosuspend(dev);
+       if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM)))
+               pm_runtime_put_autosuspend(dev);
 
        if (ret)
                dev_err(&mem->spi->dev, "operation failed with %d\n", ret);
@@ -1985,11 +1990,12 @@ static int cqspi_probe(struct platform_device *pdev)
                        goto probe_setup_failed;
        }
 
-       pm_runtime_enable(dev);
-
-       pm_runtime_set_autosuspend_delay(dev, CQSPI_AUTOSUSPEND_TIMEOUT);
-       pm_runtime_use_autosuspend(dev);
-       pm_runtime_get_noresume(dev);
+       if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) {
+               pm_runtime_enable(dev);
+               pm_runtime_set_autosuspend_delay(dev, CQSPI_AUTOSUSPEND_TIMEOUT);
+               pm_runtime_use_autosuspend(dev);
+               pm_runtime_get_noresume(dev);
+       }
 
        ret = spi_register_controller(host);
        if (ret) {
@@ -1997,12 +2003,17 @@ static int cqspi_probe(struct platform_device *pdev)
                goto probe_setup_failed;
        }
 
-       pm_runtime_put_autosuspend(dev);
+       if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) {
+               pm_runtime_put_autosuspend(dev);
+               pm_runtime_mark_last_busy(dev);
+               pm_runtime_put_autosuspend(dev);
+       }
 
        return 0;
 probe_setup_failed:
        cqspi_controller_enable(cqspi, 0);
-       pm_runtime_disable(dev);
+       if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM)))
+               pm_runtime_disable(dev);
 probe_reset_failed:
        if (cqspi->is_jh7110)
                cqspi_jh7110_disable_clk(pdev, cqspi);
@@ -2013,7 +2024,11 @@ probe_clk_failed:
 
 static void cqspi_remove(struct platform_device *pdev)
 {
+       const struct cqspi_driver_platdata *ddata;
        struct cqspi_st *cqspi = platform_get_drvdata(pdev);
+       struct device *dev = &pdev->dev;
+
+       ddata = of_device_get_match_data(dev);
 
        refcount_set(&cqspi->refcount, 0);
 
@@ -2026,14 +2041,17 @@ static void cqspi_remove(struct platform_device *pdev)
        if (cqspi->rx_chan)
                dma_release_channel(cqspi->rx_chan);
 
-       if (pm_runtime_get_sync(&pdev->dev) >= 0)
-               clk_disable(cqspi->clk);
+       if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM)))
+               if (pm_runtime_get_sync(&pdev->dev) >= 0)
+                       clk_disable(cqspi->clk);
 
        if (cqspi->is_jh7110)
                cqspi_jh7110_disable_clk(pdev, cqspi);
 
-       pm_runtime_put_sync(&pdev->dev);
-       pm_runtime_disable(&pdev->dev);
+       if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) {
+               pm_runtime_put_sync(&pdev->dev);
+               pm_runtime_disable(&pdev->dev);
+       }
 }
 
 static int cqspi_runtime_suspend(struct device *dev)
@@ -2112,7 +2130,8 @@ static const struct cqspi_driver_platdata socfpga_qspi = {
        .quirks = CQSPI_DISABLE_DAC_MODE
                        | CQSPI_NO_SUPPORT_WR_COMPLETION
                        | CQSPI_SLOW_SRAM
-                       | CQSPI_DISABLE_STIG_MODE,
+                       | CQSPI_DISABLE_STIG_MODE
+                       | CQSPI_DISABLE_RUNTIME_PM,
 };
 
 static const struct cqspi_driver_platdata versal_ospi = {