12
12
#include <linux/cpu.h>
13
13
#include <linux/device.h>
14
14
#include <linux/kernel.h>
15
+ #include <linux/platform_device.h>
15
16
#include <linux/pm_domain.h>
16
17
#include <linux/pm_runtime.h>
17
18
#include <linux/psci.h>
@@ -26,7 +27,7 @@ struct psci_pd_provider {
26
27
};
27
28
28
29
static LIST_HEAD (psci_pd_providers );
29
- static bool osi_mode_enabled __initdata ;
30
+ static bool psci_pd_allow_domain_state ;
30
31
31
32
static int psci_pd_power_off (struct generic_pm_domain * pd )
32
33
{
@@ -36,15 +37,18 @@ static int psci_pd_power_off(struct generic_pm_domain *pd)
36
37
if (!state -> data )
37
38
return 0 ;
38
39
40
+ if (!psci_pd_allow_domain_state )
41
+ return - EBUSY ;
42
+
39
43
/* OSI mode is enabled, set the corresponding domain state. */
40
44
pd_state = state -> data ;
41
45
psci_set_domain_state (* pd_state );
42
46
43
47
return 0 ;
44
48
}
45
49
46
- static int __init psci_pd_parse_state_nodes (struct genpd_power_state * states ,
47
- int state_count )
50
+ static int psci_pd_parse_state_nodes (struct genpd_power_state * states ,
51
+ int state_count )
48
52
{
49
53
int i , ret ;
50
54
u32 psci_state , * psci_state_buf ;
@@ -73,7 +77,7 @@ static int __init psci_pd_parse_state_nodes(struct genpd_power_state *states,
73
77
return ret ;
74
78
}
75
79
76
- static int __init psci_pd_parse_states (struct device_node * np ,
80
+ static int psci_pd_parse_states (struct device_node * np ,
77
81
struct genpd_power_state * * states , int * state_count )
78
82
{
79
83
int ret ;
@@ -101,7 +105,7 @@ static void psci_pd_free_states(struct genpd_power_state *states,
101
105
kfree (states );
102
106
}
103
107
104
- static int __init psci_pd_init (struct device_node * np )
108
+ static int psci_pd_init (struct device_node * np )
105
109
{
106
110
struct generic_pm_domain * pd ;
107
111
struct psci_pd_provider * pd_provider ;
@@ -168,7 +172,7 @@ static int __init psci_pd_init(struct device_node *np)
168
172
return ret ;
169
173
}
170
174
171
- static void __init psci_pd_remove (void )
175
+ static void psci_pd_remove (void )
172
176
{
173
177
struct psci_pd_provider * pd_provider , * it ;
174
178
struct generic_pm_domain * genpd ;
@@ -186,7 +190,7 @@ static void __init psci_pd_remove(void)
186
190
}
187
191
}
188
192
189
- static int __init psci_pd_init_topology (struct device_node * np , bool add )
193
+ static int psci_pd_init_topology (struct device_node * np , bool add )
190
194
{
191
195
struct device_node * node ;
192
196
struct of_phandle_args child , parent ;
@@ -212,24 +216,33 @@ static int __init psci_pd_init_topology(struct device_node *np, bool add)
212
216
return 0 ;
213
217
}
214
218
215
- static int __init psci_pd_add_topology (struct device_node * np )
219
+ static int psci_pd_add_topology (struct device_node * np )
216
220
{
217
221
return psci_pd_init_topology (np , true);
218
222
}
219
223
220
- static void __init psci_pd_remove_topology (struct device_node * np )
224
+ static void psci_pd_remove_topology (struct device_node * np )
221
225
{
222
226
psci_pd_init_topology (np , false);
223
227
}
224
228
225
- static const struct of_device_id psci_of_match [] __initconst = {
229
+ static void psci_cpuidle_domain_sync_state (struct device * dev )
230
+ {
231
+ /*
232
+ * All devices have now been attached/probed to the PM domain topology,
233
+ * hence it's fine to allow domain states to be picked.
234
+ */
235
+ psci_pd_allow_domain_state = true;
236
+ }
237
+
238
+ static const struct of_device_id psci_of_match [] = {
226
239
{ .compatible = "arm,psci-1.0" },
227
240
{}
228
241
};
229
242
230
- static int __init psci_idle_init_domains ( void )
243
+ static int psci_cpuidle_domain_probe ( struct platform_device * pdev )
231
244
{
232
- struct device_node * np = of_find_matching_node ( NULL , psci_of_match ) ;
245
+ struct device_node * np = pdev -> dev . of_node ;
233
246
struct device_node * node ;
234
247
int ret = 0 , pd_count = 0 ;
235
248
@@ -238,7 +251,7 @@ static int __init psci_idle_init_domains(void)
238
251
239
252
/* Currently limit the hierarchical topology to be used in OSI mode. */
240
253
if (!psci_has_osi_support ())
241
- goto out ;
254
+ return 0 ;
242
255
243
256
/*
244
257
* Parse child nodes for the "#power-domain-cells" property and
@@ -257,7 +270,7 @@ static int __init psci_idle_init_domains(void)
257
270
258
271
/* Bail out if not using the hierarchical CPU topology. */
259
272
if (!pd_count )
260
- goto out ;
273
+ return 0 ;
261
274
262
275
/* Link genpd masters/subdomains to model the CPU topology. */
263
276
ret = psci_pd_add_topology (np );
@@ -272,30 +285,37 @@ static int __init psci_idle_init_domains(void)
272
285
goto remove_pd ;
273
286
}
274
287
275
- osi_mode_enabled = true;
276
- of_node_put (np );
277
288
pr_info ("Initialized CPU PM domain topology\n" );
278
- return pd_count ;
289
+ return 0 ;
279
290
280
291
put_node :
281
292
of_node_put (node );
282
293
remove_pd :
283
294
if (pd_count )
284
295
psci_pd_remove ();
285
296
pr_err ("failed to create CPU PM domains ret=%d\n" , ret );
286
- out :
287
- of_node_put (np );
288
297
return ret ;
289
298
}
299
+
300
+ static struct platform_driver psci_cpuidle_domain_driver = {
301
+ .probe = psci_cpuidle_domain_probe ,
302
+ .driver = {
303
+ .name = "psci-cpuidle-domain" ,
304
+ .of_match_table = psci_of_match ,
305
+ .sync_state = psci_cpuidle_domain_sync_state ,
306
+ },
307
+ };
308
+
309
+ static int __init psci_idle_init_domains (void )
310
+ {
311
+ return platform_driver_register (& psci_cpuidle_domain_driver );
312
+ }
290
313
subsys_initcall (psci_idle_init_domains );
291
314
292
- struct device __init * psci_dt_attach_cpu (int cpu )
315
+ struct device * psci_dt_attach_cpu (int cpu )
293
316
{
294
317
struct device * dev ;
295
318
296
- if (!osi_mode_enabled )
297
- return NULL ;
298
-
299
319
dev = dev_pm_domain_attach_by_name (get_cpu_device (cpu ), "psci" );
300
320
if (IS_ERR_OR_NULL (dev ))
301
321
return dev ;
@@ -306,3 +326,11 @@ struct device __init *psci_dt_attach_cpu(int cpu)
306
326
307
327
return dev ;
308
328
}
329
+
330
+ void psci_dt_detach_cpu (struct device * dev )
331
+ {
332
+ if (IS_ERR_OR_NULL (dev ))
333
+ return ;
334
+
335
+ dev_pm_domain_detach (dev , false);
336
+ }
0 commit comments