[PATCH 08/11] dmaengine: ste_dma40: Use power domain for LCLA SRAM
Linus Walleij
linusw at kernel.org
Wed Jun 17 22:00:54 PDT 2026
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 <linusw at kernel.org>
---
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
More information about the linux-arm-kernel
mailing list