Replace the LCLA ESRAM regulator with runtime PM.

Use the SRAM device that owns the ESRAM34 power domain.

Hold that domain while DMA transfers are active.

Assisted-by: Codex:gpt-5-5
Signed-off-by: Linus Walleij <[email protected]>
---
 drivers/dma/ste_dma40.c | 97 ++++++++++++++++++++++++++++---------------------
 1 file changed, 55 insertions(+), 42 deletions(-)

diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index 9b803c0aec25..6ca67ec446dc 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -21,8 +21,8 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_dma.h>
+#include <linux/of_platform.h>
 #include <linux/amba/bus.h>
-#include <linux/regulator/consumer.h>
 
 #include "dmaengine.h"
 #include "ste_dma40.h"
@@ -571,7 +571,8 @@ struct d40_gen_dmac {
  * to phy_chans entries.
  * @plat_data: Pointer to provided platform_data which is the driver
  * configuration.
- * @lcpa_regulator: Pointer to hold the regulator for the esram bank for lcla.
+ * @lcla_dev: SRAM device for the ESRAM bank used by LCLA.
+ * @lcla_pm_enabled: Whether runtime PM was enabled for LCLA by this driver.
  * @phy_res: Vector containing all physical channels.
  * @lcla_pool: lcla pool settings and data.
  * @lcpa_base: The virtual mapped address of LCPA.
@@ -607,7 +608,8 @@ struct d40_base {
        struct d40_chan                 **lookup_log_chans;
        struct d40_chan                 **lookup_phy_chans;
        struct stedma40_platform_data    *plat_data;
-       struct regulator                 *lcpa_regulator;
+       struct device                    *lcla_dev;
+       bool                              lcla_pm_enabled;
        /* Physical half channels */
        struct d40_phy_res               *phy_res;
        struct d40_lcla_pool              lcla_pool;
@@ -628,6 +630,22 @@ static struct device *chan2dev(struct d40_chan *d40c)
        return &d40c->chan.dev->device;
 }
 
+static void d40_transfer_runtime_get(struct d40_base *base)
+{
+       if (base->lcla_dev)
+               pm_runtime_get_sync(base->lcla_dev);
+
+       pm_runtime_get_sync(base->dev);
+}
+
+static void d40_transfer_runtime_put(struct d40_base *base)
+{
+       pm_runtime_put_autosuspend(base->dev);
+
+       if (base->lcla_dev)
+               pm_runtime_put_sync_suspend(base->lcla_dev);
+}
+
 static bool chan_is_physical(struct d40_chan *chan)
 {
        return chan->log_num == D40_PHY_CHAN;
@@ -1516,7 +1534,7 @@ static struct d40_desc *d40_queue_start(struct d40_chan 
*d40c)
        if (d40d != NULL) {
                if (!d40c->busy) {
                        d40c->busy = true;
-                       pm_runtime_get_sync(d40c->base->dev);
+                       d40_transfer_runtime_get(d40c->base);
                }
 
                /* Remove from queue */
@@ -1579,7 +1597,7 @@ static void dma_tc_handle(struct d40_chan *d40c)
                if (d40_queue_start(d40c) == NULL) {
                        d40c->busy = false;
 
-                       pm_runtime_put_autosuspend(d40c->base->dev);
+                       d40_transfer_runtime_put(d40c->base);
                }
 
                d40_desc_remove(d40d);
@@ -2052,7 +2070,7 @@ static int d40_free_dma(struct d40_chan *d40c)
                d40c->base->lookup_phy_chans[phy->num] = NULL;
 
        if (d40c->busy)
-               pm_runtime_put_autosuspend(d40c->base->dev);
+               d40_transfer_runtime_put(d40c->base);
 
        d40c->busy = false;
        d40c->phy_chan = NULL;
@@ -2613,7 +2631,7 @@ static int d40_terminate_all(struct dma_chan *chan)
        d40_term_all(d40c);
        pm_runtime_put_autosuspend(d40c->base->dev);
        if (d40c->busy)
-               pm_runtime_put_autosuspend(d40c->base->dev);
+               d40_transfer_runtime_put(d40c->base);
        d40c->busy = false;
 
        spin_unlock_irqrestore(&d40c->lock, flags);
@@ -2916,29 +2934,11 @@ static int __init d40_dmaengine_init(struct d40_base 
*base,
 #ifdef CONFIG_PM_SLEEP
 static int dma40_suspend(struct device *dev)
 {
-       struct d40_base *base = dev_get_drvdata(dev);
-       int ret;
-
-       ret = pm_runtime_force_suspend(dev);
-       if (ret)
-               return ret;
-
-       if (base->lcpa_regulator)
-               ret = regulator_disable(base->lcpa_regulator);
-       return ret;
+       return pm_runtime_force_suspend(dev);
 }
 
 static int dma40_resume(struct device *dev)
 {
-       struct d40_base *base = dev_get_drvdata(dev);
-       int ret = 0;
-
-       if (base->lcpa_regulator) {
-               ret = regulator_enable(base->lcpa_regulator);
-               if (ret)
-                       return ret;
-       }
-
        return pm_runtime_force_resume(dev);
 }
 #endif
@@ -3492,7 +3492,10 @@ static int __init d40_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct device_node *np = pdev->dev.of_node;
        struct device_node *np_lcpa;
+       struct device_node *np_lcla;
+       struct device_node *np_lcla_parent;
        struct d40_base *base;
+       struct platform_device *lcla_pdev;
        struct resource *res;
        struct resource res_lcpa;
        int num_reserved_chans;
@@ -3590,23 +3593,32 @@ static int __init d40_probe(struct platform_device 
*pdev)
        }
 
        if (base->plat_data->use_esram_lcla) {
+               np_lcla = of_parse_phandle(np, "sram", 1);
+               if (!np_lcla) {
+                       dev_err(dev, "no LCLA SRAM node\n");
+                       ret = -EINVAL;
+                       goto destroy_cache;
+               }
 
-               base->lcpa_regulator = regulator_get(base->dev, "lcla_esram");
-               if (IS_ERR(base->lcpa_regulator)) {
-                       d40_err(dev, "Failed to get lcpa_regulator\n");
-                       ret = PTR_ERR(base->lcpa_regulator);
-                       base->lcpa_regulator = NULL;
+               np_lcla_parent = of_get_parent(np_lcla);
+               of_node_put(np_lcla);
+               if (!np_lcla_parent) {
+                       dev_err(dev, "no LCLA SRAM parent node\n");
+                       ret = -EINVAL;
                        goto destroy_cache;
                }
 
-               ret = regulator_enable(base->lcpa_regulator);
-               if (ret) {
-                       d40_err(dev,
-                               "Failed to enable lcpa_regulator\n");
-                       regulator_put(base->lcpa_regulator);
-                       base->lcpa_regulator = NULL;
+               lcla_pdev = of_find_device_by_node(np_lcla_parent);
+               of_node_put(np_lcla_parent);
+               if (!lcla_pdev) {
+                       ret = -EPROBE_DEFER;
                        goto destroy_cache;
                }
+               base->lcla_dev = &lcla_pdev->dev;
+               if (!pm_runtime_enabled(base->lcla_dev)) {
+                       pm_runtime_enable(base->lcla_dev);
+                       base->lcla_pm_enabled = true;
+               }
        }
 
        writel_relaxed(D40_DREG_GCC_ENABLE_ALL, base->virtbase + D40_DREG_GCC);
@@ -3642,16 +3654,17 @@ static int __init d40_probe(struct platform_device 
*pdev)
                                 SZ_1K * base->num_phy_chans,
                                 DMA_TO_DEVICE);
 
-       if (!base->lcla_pool.base_unaligned && base->lcla_pool.base)
+       if (!base->lcla_pool.base_unaligned && base->lcla_pool.base &&
+           base->lcla_pool.pages)
                free_pages((unsigned long)base->lcla_pool.base,
                           base->lcla_pool.pages);
 
        kfree(base->lcla_pool.base_unaligned);
 
-       if (base->lcpa_regulator) {
-               regulator_disable(base->lcpa_regulator);
-               regulator_put(base->lcpa_regulator);
-       }
+       if (base->lcla_pm_enabled)
+               pm_runtime_disable(base->lcla_dev);
+       if (base->lcla_dev)
+               put_device(base->lcla_dev);
        pm_runtime_disable(base->dev);
 
  report_failure:

-- 
2.54.0

Reply via email to