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@xxxxxxx> --- Cc: Boris Brezillon <boris.brezillon@xxxxxxxxxxxxx> Cc: Conor Dooley <conor+dt@xxxxxxxxxx> Cc: David Airlie <airlied@xxxxxxxxx> Cc: Fabio Estevam <festevam@xxxxxxxxx> Cc: Krzysztof Kozlowski <krzk+dt@xxxxxxxxxx> Cc: Liviu Dudau <liviu.dudau@xxxxxxx> Cc: Maarten Lankhorst <maarten.lankhorst@xxxxxxxxxxxxxxx> Cc: Maxime Ripard <mripard@xxxxxxxxxx> Cc: Pengutronix Kernel Team <kernel@xxxxxxxxxxxxxx> Cc: Philipp Zabel <p.zabel@xxxxxxxxxxxxxx> Cc: Rob Herring <robh@xxxxxxxxxx> Cc: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx> Cc: Sebastian Reichel <sre@xxxxxxxxxx> Cc: Shawn Guo <shawnguo@xxxxxxxxxx> Cc: Simona Vetter <simona@xxxxxxxx> Cc: Steven Price <steven.price@xxxxxxx> Cc: Thomas Zimmermann <tzimmermann@xxxxxxx> Cc: devicetree@xxxxxxxxxxxxxxx Cc: dri-devel@xxxxxxxxxxxxxxxxxxxxx Cc: imx@xxxxxxxxxxxxxxx Cc: linux-arm-kernel@xxxxxxxxxxxxxxxxxxx --- drivers/gpu/drm/panthor/panthor_device.c | 56 ++++++++++++++++++++++++ drivers/gpu/drm/panthor/panthor_device.h | 5 +++ 2 files changed, 61 insertions(+) diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/panthor/panthor_device.c index 51ee9cae94504..4348b7e917b64 100644 --- a/drivers/gpu/drm/panthor/panthor_device.c +++ b/drivers/gpu/drm/panthor/panthor_device.c @@ -75,6 +75,58 @@ 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, ret; + + 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; + + ret = PTR_ERR(ptdev->pwr_dom_devs[i]); + if (ret != -EPROBE_DEFER) { + drm_warn(&ptdev->base, "pm_domain_attach_by_id(%u) failed: %d\n", i, ret); + continue; + } + + /* Missing dependency, try again. */ + panthor_detach_genpd(ptdev); + return ret; + } + + 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 +284,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