The driver code power domain binding to driver instances only works
for single power domain, in case there are multiple power domains,
it is necessary to explicitly attach via dev_pm_domain_attach*().
As DT bindings list support for up to 5 power domains, add support
for attaching them all. This is useful on Freescale i.MX95 which
does have two power domains.

Signed-off-by: Marek Vasut <ma...@denx.de>
---
Cc: Boris Brezillon <boris.brezil...@collabora.com>
Cc: Conor Dooley <conor...@kernel.org>
Cc: David Airlie <airl...@gmail.com>
Cc: Fabio Estevam <feste...@gmail.com>
Cc: Krzysztof Kozlowski <krzk...@kernel.org>
Cc: Liviu Dudau <liviu.du...@arm.com>
Cc: Maarten Lankhorst <maarten.lankho...@linux.intel.com>
Cc: Maxime Ripard <mrip...@kernel.org>
Cc: Pengutronix Kernel Team <ker...@pengutronix.de>
Cc: Philipp Zabel <p.za...@pengutronix.de>
Cc: Rob Herring <r...@kernel.org>
Cc: Sascha Hauer <s.ha...@pengutronix.de>
Cc: Sebastian Reichel <s...@kernel.org>
Cc: Shawn Guo <shawn...@kernel.org>
Cc: Simona Vetter <sim...@ffwll.ch>
Cc: Steven Price <steven.pr...@arm.com>
Cc: Thomas Zimmermann <tzimmerm...@suse.de>
Cc: devicet...@vger.kernel.org
Cc: dri-devel@lists.freedesktop.org
Cc: i...@lists.linux.dev
Cc: linux-arm-ker...@lists.infradead.org
---
V2: Exit from panthor_genpd_init() on any pm_domain_attach_by_id() failure
---
 drivers/gpu/drm/panthor/panthor_device.c | 52 ++++++++++++++++++++++++
 drivers/gpu/drm/panthor/panthor_device.h |  5 +++
 2 files changed, 57 insertions(+)

diff --git a/drivers/gpu/drm/panthor/panthor_device.c 
b/drivers/gpu/drm/panthor/panthor_device.c
index 51ee9cae94504..8aa79c6d157e1 100644
--- a/drivers/gpu/drm/panthor/panthor_device.c
+++ b/drivers/gpu/drm/panthor/panthor_device.c
@@ -75,6 +75,54 @@ static int panthor_reset_init(struct panthor_device *ptdev)
        return 0;
 }
 
+/* Generic power domain handling code, see drivers/gpu/drm/tiny/simpledrm.c */
+static void panthor_detach_genpd(void *res)
+{
+       struct panthor_device *ptdev = res;
+       int i;
+
+       if (ptdev->pwr_dom_count <= 1)
+               return;
+
+       for (i = ptdev->pwr_dom_count - 1; i >= 0; i--)
+               dev_pm_domain_detach(ptdev->pwr_dom_devs[i], true);
+}
+
+static int panthor_genpd_init(struct panthor_device *ptdev)
+{
+       struct device *dev = ptdev->base.dev;
+       int i;
+
+       ptdev->pwr_dom_count = of_count_phandle_with_args(dev->of_node, 
"power-domains",
+                                                         
"#power-domain-cells");
+       /*
+        * Single power-domain devices are handled by driver core nothing to do
+        * here. The same for device nodes without "power-domains" property.
+        */
+       if (ptdev->pwr_dom_count <= 1)
+               return 0;
+
+       if (ptdev->pwr_dom_count > ARRAY_SIZE(ptdev->pwr_dom_devs)) {
+               drm_warn(&ptdev->base, "Too many power domains (%d) for this 
device\n",
+                        ptdev->pwr_dom_count);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < ptdev->pwr_dom_count; i++) {
+               ptdev->pwr_dom_devs[i] = dev_pm_domain_attach_by_id(dev, i);
+               if (!IS_ERR(ptdev->pwr_dom_devs[i]))
+                       continue;
+
+               /* Missing dependency, try again. */
+               panthor_detach_genpd(ptdev);
+               return dev_err_probe(ptdev->base.dev,
+                                    PTR_ERR(ptdev->pwr_dom_devs[i]),
+                                    "pm_domain_attach_by_id(%u) failed\n", i);
+       }
+
+       return devm_add_action_or_reset(dev, panthor_detach_genpd, ptdev);
+}
+
 void panthor_device_unplug(struct panthor_device *ptdev)
 {
        /* This function can be called from two different path: the reset work
@@ -232,6 +280,10 @@ int panthor_device_init(struct panthor_device *ptdev)
        if (ret)
                return ret;
 
+       ret = panthor_genpd_init(ptdev);
+       if (ret)
+               return ret;
+
        ret = panthor_devfreq_init(ptdev);
        if (ret)
                return ret;
diff --git a/drivers/gpu/drm/panthor/panthor_device.h 
b/drivers/gpu/drm/panthor/panthor_device.h
index fea3a05778e2e..7fb65447253e9 100644
--- a/drivers/gpu/drm/panthor/panthor_device.h
+++ b/drivers/gpu/drm/panthor/panthor_device.h
@@ -114,6 +114,11 @@ struct panthor_device {
        /** @resets: GPU reset. */
        struct reset_control *resets;
 
+       /** @pwr_dom_count: Power domain count */
+       int pwr_dom_count;
+       /** @pwr_dom_dev: Power domain devices */
+       struct device *pwr_dom_devs[5];
+
        /** @coherent: True if the CPU/GPU are memory coherent. */
        bool coherent;
 
-- 
2.47.2

Reply via email to