15
15
#include <linux/of_address.h>
16
16
#include <linux/of_device.h>
17
17
#include <linux/platform_device.h>
18
+ #include <linux/pm_domain.h>
19
+ #include <linux/pm_runtime.h>
18
20
#include <linux/qcom_scm.h>
19
21
#include <linux/regulator/consumer.h>
20
22
#include <linux/remoteproc.h>
@@ -32,6 +34,9 @@ struct adsp_data {
32
34
int pas_id ;
33
35
bool has_aggre2_clk ;
34
36
37
+ char * * active_pd_names ;
38
+ char * * proxy_pd_names ;
39
+
35
40
const char * ssr_name ;
36
41
const char * sysmon_name ;
37
42
int ssctl_id ;
@@ -49,6 +54,12 @@ struct qcom_adsp {
49
54
struct regulator * cx_supply ;
50
55
struct regulator * px_supply ;
51
56
57
+ struct device * active_pds [1 ];
58
+ struct device * proxy_pds [3 ];
59
+
60
+ int active_pd_count ;
61
+ int proxy_pd_count ;
62
+
52
63
int pas_id ;
53
64
int crash_reason_smem ;
54
65
bool has_aggre2_clk ;
@@ -67,6 +78,41 @@ struct qcom_adsp {
67
78
struct qcom_sysmon * sysmon ;
68
79
};
69
80
81
+ static int adsp_pds_enable (struct qcom_adsp * adsp , struct device * * pds ,
82
+ size_t pd_count )
83
+ {
84
+ int ret ;
85
+ int i ;
86
+
87
+ for (i = 0 ; i < pd_count ; i ++ ) {
88
+ dev_pm_genpd_set_performance_state (pds [i ], INT_MAX );
89
+ ret = pm_runtime_get_sync (pds [i ]);
90
+ if (ret < 0 )
91
+ goto unroll_pd_votes ;
92
+ }
93
+
94
+ return 0 ;
95
+
96
+ unroll_pd_votes :
97
+ for (i -- ; i >= 0 ; i -- ) {
98
+ dev_pm_genpd_set_performance_state (pds [i ], 0 );
99
+ pm_runtime_put (pds [i ]);
100
+ }
101
+
102
+ return ret ;
103
+ };
104
+
105
+ static void adsp_pds_disable (struct qcom_adsp * adsp , struct device * * pds ,
106
+ size_t pd_count )
107
+ {
108
+ int i ;
109
+
110
+ for (i = 0 ; i < pd_count ; i ++ ) {
111
+ dev_pm_genpd_set_performance_state (pds [i ], 0 );
112
+ pm_runtime_put (pds [i ]);
113
+ }
114
+ }
115
+
70
116
static int adsp_load (struct rproc * rproc , const struct firmware * fw )
71
117
{
72
118
struct qcom_adsp * adsp = (struct qcom_adsp * )rproc -> priv ;
@@ -84,9 +130,17 @@ static int adsp_start(struct rproc *rproc)
84
130
85
131
qcom_q6v5_prepare (& adsp -> q6v5 );
86
132
133
+ ret = adsp_pds_enable (adsp , adsp -> active_pds , adsp -> active_pd_count );
134
+ if (ret < 0 )
135
+ goto disable_irqs ;
136
+
137
+ ret = adsp_pds_enable (adsp , adsp -> proxy_pds , adsp -> proxy_pd_count );
138
+ if (ret < 0 )
139
+ goto disable_active_pds ;
140
+
87
141
ret = clk_prepare_enable (adsp -> xo );
88
142
if (ret )
89
- goto disable_irqs ;
143
+ goto disable_proxy_pds ;
90
144
91
145
ret = clk_prepare_enable (adsp -> aggre2_clk );
92
146
if (ret )
@@ -124,6 +178,10 @@ static int adsp_start(struct rproc *rproc)
124
178
clk_disable_unprepare (adsp -> aggre2_clk );
125
179
disable_xo_clk :
126
180
clk_disable_unprepare (adsp -> xo );
181
+ disable_proxy_pds :
182
+ adsp_pds_disable (adsp , adsp -> proxy_pds , adsp -> proxy_pd_count );
183
+ disable_active_pds :
184
+ adsp_pds_disable (adsp , adsp -> active_pds , adsp -> active_pd_count );
127
185
disable_irqs :
128
186
qcom_q6v5_unprepare (& adsp -> q6v5 );
129
187
@@ -138,6 +196,7 @@ static void qcom_pas_handover(struct qcom_q6v5 *q6v5)
138
196
regulator_disable (adsp -> cx_supply );
139
197
clk_disable_unprepare (adsp -> aggre2_clk );
140
198
clk_disable_unprepare (adsp -> xo );
199
+ adsp_pds_disable (adsp , adsp -> proxy_pds , adsp -> proxy_pd_count );
141
200
}
142
201
143
202
static int adsp_stop (struct rproc * rproc )
@@ -154,6 +213,7 @@ static int adsp_stop(struct rproc *rproc)
154
213
if (ret )
155
214
dev_err (adsp -> dev , "failed to shutdown: %d\n" , ret );
156
215
216
+ adsp_pds_disable (adsp , adsp -> active_pds , adsp -> active_pd_count );
157
217
handover = qcom_q6v5_unprepare (& adsp -> q6v5 );
158
218
if (handover )
159
219
qcom_pas_handover (& adsp -> q6v5 );
@@ -219,6 +279,59 @@ static int adsp_init_regulator(struct qcom_adsp *adsp)
219
279
return PTR_ERR_OR_ZERO (adsp -> px_supply );
220
280
}
221
281
282
+ static int adsp_pds_attach (struct device * dev , struct device * * devs ,
283
+ char * * pd_names )
284
+ {
285
+ size_t num_pds = 0 ;
286
+ int ret ;
287
+ int i ;
288
+
289
+ if (!pd_names )
290
+ return 0 ;
291
+
292
+ /* Handle single power domain */
293
+ if (dev -> pm_domain ) {
294
+ devs [0 ] = dev ;
295
+ pm_runtime_enable (dev );
296
+ return 1 ;
297
+ }
298
+
299
+ while (pd_names [num_pds ])
300
+ num_pds ++ ;
301
+
302
+ for (i = 0 ; i < num_pds ; i ++ ) {
303
+ devs [i ] = dev_pm_domain_attach_by_name (dev , pd_names [i ]);
304
+ if (IS_ERR_OR_NULL (devs [i ])) {
305
+ ret = PTR_ERR (devs [i ]) ? : - ENODATA ;
306
+ goto unroll_attach ;
307
+ }
308
+ }
309
+
310
+ return num_pds ;
311
+
312
+ unroll_attach :
313
+ for (i -- ; i >= 0 ; i -- )
314
+ dev_pm_domain_detach (devs [i ], false);
315
+
316
+ return ret ;
317
+ };
318
+
319
+ static void adsp_pds_detach (struct qcom_adsp * adsp , struct device * * pds ,
320
+ size_t pd_count )
321
+ {
322
+ struct device * dev = adsp -> dev ;
323
+ int i ;
324
+
325
+ /* Handle single power domain */
326
+ if (dev -> pm_domain && pd_count ) {
327
+ pm_runtime_disable (dev );
328
+ return ;
329
+ }
330
+
331
+ for (i = 0 ; i < pd_count ; i ++ )
332
+ dev_pm_domain_detach (pds [i ], false);
333
+ }
334
+
222
335
static int adsp_alloc_memory_region (struct qcom_adsp * adsp )
223
336
{
224
337
struct device_node * node ;
@@ -294,10 +407,22 @@ static int adsp_probe(struct platform_device *pdev)
294
407
if (ret )
295
408
goto free_rproc ;
296
409
410
+ ret = adsp_pds_attach (& pdev -> dev , adsp -> active_pds ,
411
+ desc -> active_pd_names );
412
+ if (ret < 0 )
413
+ goto free_rproc ;
414
+ adsp -> active_pd_count = ret ;
415
+
416
+ ret = adsp_pds_attach (& pdev -> dev , adsp -> proxy_pds ,
417
+ desc -> proxy_pd_names );
418
+ if (ret < 0 )
419
+ goto detach_active_pds ;
420
+ adsp -> proxy_pd_count = ret ;
421
+
297
422
ret = qcom_q6v5_init (& adsp -> q6v5 , pdev , rproc , desc -> crash_reason_smem ,
298
423
qcom_pas_handover );
299
424
if (ret )
300
- goto free_rproc ;
425
+ goto detach_proxy_pds ;
301
426
302
427
qcom_add_glink_subdev (rproc , & adsp -> glink_subdev );
303
428
qcom_add_smd_subdev (rproc , & adsp -> smd_subdev );
@@ -307,15 +432,19 @@ static int adsp_probe(struct platform_device *pdev)
307
432
desc -> ssctl_id );
308
433
if (IS_ERR (adsp -> sysmon )) {
309
434
ret = PTR_ERR (adsp -> sysmon );
310
- goto free_rproc ;
435
+ goto detach_proxy_pds ;
311
436
}
312
437
313
438
ret = rproc_add (rproc );
314
439
if (ret )
315
- goto free_rproc ;
440
+ goto detach_proxy_pds ;
316
441
317
442
return 0 ;
318
443
444
+ detach_proxy_pds :
445
+ adsp_pds_detach (adsp , adsp -> proxy_pds , adsp -> proxy_pd_count );
446
+ detach_active_pds :
447
+ adsp_pds_detach (adsp , adsp -> active_pds , adsp -> active_pd_count );
319
448
free_rproc :
320
449
rproc_free (rproc );
321
450
0 commit comments