Skip to content

Commit 3b7b8ac

Browse files
committed
pmdomain: core: Add common ->sync_state() support for genpd providers
If the genpd provider's fwnode doesn't have an associated struct device with it, we can make use of the generic genpd->dev and it corresponding driver internally in genpd to manage ->sync_state(). More precisely, while adding a genpd OF provider let's check if the fwnode has a device and if not, make the preparation to handle ->sync_state() internally through the genpd_provider_driver and the genpd_provider_bus. Note that, genpd providers may opt out from this behaviour by setting the GENPD_FLAG_NO_SYNC_STATE config options for the genpds in question. Suggested-by: Saravana Kannan <saravanak@google.com> Tested-by: Hiago De Franco <hiago.franco@toradex.com> # Colibri iMX8X Tested-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> # TI AM62A,Xilinx ZynqMP ZCU106 Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Link: https://lore.kernel.org/r/20250701114733.636510-19-ulf.hansson@linaro.org
1 parent 9a4681a commit 3b7b8ac

File tree

2 files changed

+57
-2
lines changed

2 files changed

+57
-2
lines changed

drivers/pmdomain/core.c

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ static const struct genpd_lock_ops genpd_raw_spin_ops = {
186186
#define genpd_is_rpm_always_on(genpd) (genpd->flags & GENPD_FLAG_RPM_ALWAYS_ON)
187187
#define genpd_is_opp_table_fw(genpd) (genpd->flags & GENPD_FLAG_OPP_TABLE_FW)
188188
#define genpd_is_dev_name_fw(genpd) (genpd->flags & GENPD_FLAG_DEV_NAME_FW)
189+
#define genpd_is_no_sync_state(genpd) (genpd->flags & GENPD_FLAG_NO_SYNC_STATE)
189190

190191
static inline bool irq_safe_dev_in_sleep_domain(struct device *dev,
191192
const struct generic_pm_domain *genpd)
@@ -2351,6 +2352,7 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
23512352
INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn);
23522353
atomic_set(&genpd->sd_count, 0);
23532354
genpd->status = is_off ? GENPD_STATE_OFF : GENPD_STATE_ON;
2355+
genpd->sync_state = GENPD_SYNC_STATE_OFF;
23542356
genpd->device_count = 0;
23552357
genpd->provider = NULL;
23562358
genpd->device_id = -ENXIO;
@@ -2606,6 +2608,8 @@ static bool genpd_present(const struct generic_pm_domain *genpd)
26062608
int of_genpd_add_provider_simple(struct device_node *np,
26072609
struct generic_pm_domain *genpd)
26082610
{
2611+
struct fwnode_handle *fwnode;
2612+
struct device *dev;
26092613
int ret;
26102614

26112615
if (!np || !genpd)
@@ -2619,6 +2623,15 @@ int of_genpd_add_provider_simple(struct device_node *np,
26192623

26202624
genpd->dev.of_node = np;
26212625

2626+
fwnode = of_fwnode_handle(np);
2627+
dev = get_dev_from_fwnode(fwnode);
2628+
if (!dev && !genpd_is_no_sync_state(genpd)) {
2629+
genpd->sync_state = GENPD_SYNC_STATE_SIMPLE;
2630+
device_set_node(&genpd->dev, fwnode);
2631+
}
2632+
2633+
put_device(dev);
2634+
26222635
ret = device_add(&genpd->dev);
26232636
if (ret)
26242637
return ret;
@@ -2643,7 +2656,7 @@ int of_genpd_add_provider_simple(struct device_node *np,
26432656
if (ret)
26442657
goto err_opp;
26452658

2646-
genpd->provider = &np->fwnode;
2659+
genpd->provider = fwnode;
26472660
genpd->has_provider = true;
26482661

26492662
return 0;
@@ -2668,8 +2681,11 @@ int of_genpd_add_provider_onecell(struct device_node *np,
26682681
struct genpd_onecell_data *data)
26692682
{
26702683
struct generic_pm_domain *genpd;
2684+
struct fwnode_handle *fwnode;
2685+
struct device *dev;
26712686
unsigned int i;
26722687
int ret = -EINVAL;
2688+
bool sync_state = false;
26732689

26742690
if (!np || !data)
26752691
return -EINVAL;
@@ -2680,6 +2696,13 @@ int of_genpd_add_provider_onecell(struct device_node *np,
26802696
if (!data->xlate)
26812697
data->xlate = genpd_xlate_onecell;
26822698

2699+
fwnode = of_fwnode_handle(np);
2700+
dev = get_dev_from_fwnode(fwnode);
2701+
if (!dev)
2702+
sync_state = true;
2703+
2704+
put_device(dev);
2705+
26832706
for (i = 0; i < data->num_domains; i++) {
26842707
genpd = data->domains[i];
26852708

@@ -2690,6 +2713,12 @@ int of_genpd_add_provider_onecell(struct device_node *np,
26902713

26912714
genpd->dev.of_node = np;
26922715

2716+
if (sync_state && !genpd_is_no_sync_state(genpd)) {
2717+
genpd->sync_state = GENPD_SYNC_STATE_ONECELL;
2718+
device_set_node(&genpd->dev, fwnode);
2719+
sync_state = false;
2720+
}
2721+
26932722
ret = device_add(&genpd->dev);
26942723
if (ret)
26952724
goto error;
@@ -2712,7 +2741,7 @@ int of_genpd_add_provider_onecell(struct device_node *np,
27122741
WARN_ON(IS_ERR(genpd->opp_table));
27132742
}
27142743

2715-
genpd->provider = &np->fwnode;
2744+
genpd->provider = fwnode;
27162745
genpd->has_provider = true;
27172746
}
27182747

@@ -3430,6 +3459,25 @@ static int genpd_provider_probe(struct device *dev)
34303459

34313460
static void genpd_provider_sync_state(struct device *dev)
34323461
{
3462+
struct generic_pm_domain *genpd = container_of(dev, struct generic_pm_domain, dev);
3463+
3464+
switch (genpd->sync_state) {
3465+
case GENPD_SYNC_STATE_OFF:
3466+
break;
3467+
3468+
case GENPD_SYNC_STATE_ONECELL:
3469+
of_genpd_sync_state(dev->of_node);
3470+
break;
3471+
3472+
case GENPD_SYNC_STATE_SIMPLE:
3473+
genpd_lock(genpd);
3474+
genpd_power_off(genpd, false, 0);
3475+
genpd_unlock(genpd);
3476+
break;
3477+
3478+
default:
3479+
break;
3480+
}
34333481
}
34343482

34353483
static struct device_driver genpd_provider_drv = {

include/linux/pm_domain.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,12 @@ enum genpd_notication {
133133
GENPD_NOTIFY_ON,
134134
};
135135

136+
enum genpd_sync_state {
137+
GENPD_SYNC_STATE_OFF = 0,
138+
GENPD_SYNC_STATE_SIMPLE,
139+
GENPD_SYNC_STATE_ONECELL,
140+
};
141+
136142
struct dev_power_governor {
137143
bool (*power_down_ok)(struct dev_pm_domain *domain);
138144
bool (*suspend_ok)(struct device *dev);
@@ -193,6 +199,7 @@ struct generic_pm_domain {
193199
unsigned int performance_state; /* Aggregated max performance state */
194200
cpumask_var_t cpus; /* A cpumask of the attached CPUs */
195201
bool synced_poweroff; /* A consumer needs a synced poweroff */
202+
enum genpd_sync_state sync_state; /* How sync_state is managed. */
196203
int (*power_off)(struct generic_pm_domain *domain);
197204
int (*power_on)(struct generic_pm_domain *domain);
198205
struct raw_notifier_head power_notifiers; /* Power on/off notifiers */

0 commit comments

Comments
 (0)