[PATCH v2 5/9] drm/panthor: Implement support for multiple power domains
Steven Price
steven.price at arm.com
Wed Mar 26 08:07:05 PDT 2025
On 21/03/2025 20:05, Marek Vasut wrote:
> 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 <marex at denx.de>
> ---
> Cc: Boris Brezillon <boris.brezillon at collabora.com>
> Cc: Conor Dooley <conor+dt at kernel.org>
> Cc: David Airlie <airlied at gmail.com>
> Cc: Fabio Estevam <festevam at gmail.com>
> Cc: Krzysztof Kozlowski <krzk+dt at kernel.org>
> Cc: Liviu Dudau <liviu.dudau at arm.com>
> Cc: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
> Cc: Maxime Ripard <mripard at kernel.org>
> Cc: Pengutronix Kernel Team <kernel at pengutronix.de>
> Cc: Philipp Zabel <p.zabel at pengutronix.de>
> Cc: Rob Herring <robh at kernel.org>
> Cc: Sascha Hauer <s.hauer at pengutronix.de>
> Cc: Sebastian Reichel <sre at kernel.org>
> Cc: Shawn Guo <shawnguo at kernel.org>
> Cc: Simona Vetter <simona at ffwll.ch>
> Cc: Steven Price <steven.price at arm.com>
> Cc: Thomas Zimmermann <tzimmermann at suse.de>
> Cc: devicetree at vger.kernel.org
> Cc: dri-devel at lists.freedesktop.org
> Cc: imx at lists.linux.dev
> Cc: linux-arm-kernel at 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);
If ptdev->pwr_dom_devs[i] is assigned an error pointer, then the call in
panthor_detach_genpd() to dev_pm_domain_detach() is going to use that
error pointer. But AFAICT dev_pm_domain_detach() assumes the pointer is
valid. So this will break.
Steve
> + 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;
>
More information about the linux-arm-kernel
mailing list