1515#include <linux/of_address.h>
1616#include <linux/of_device.h>
1717#include <linux/platform_device.h>
18+ #include <linux/pm_domain.h>
19+ #include <linux/pm_runtime.h>
1820#include <linux/qcom_scm.h>
1921#include <linux/regulator/consumer.h>
2022#include <linux/remoteproc.h>
@@ -32,6 +34,9 @@ struct adsp_data {
3234 int pas_id ;
3335 bool has_aggre2_clk ;
3436
37+ char * * active_pd_names ;
38+ char * * proxy_pd_names ;
39+
3540 const char * ssr_name ;
3641 const char * sysmon_name ;
3742 int ssctl_id ;
@@ -49,6 +54,12 @@ struct qcom_adsp {
4954 struct regulator * cx_supply ;
5055 struct regulator * px_supply ;
5156
57+ struct device * active_pds [1 ];
58+ struct device * proxy_pds [3 ];
59+
60+ int active_pd_count ;
61+ int proxy_pd_count ;
62+
5263 int pas_id ;
5364 int crash_reason_smem ;
5465 bool has_aggre2_clk ;
@@ -67,6 +78,41 @@ struct qcom_adsp {
6778 struct qcom_sysmon * sysmon ;
6879};
6980
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+
70116static int adsp_load (struct rproc * rproc , const struct firmware * fw )
71117{
72118 struct qcom_adsp * adsp = (struct qcom_adsp * )rproc -> priv ;
@@ -84,9 +130,17 @@ static int adsp_start(struct rproc *rproc)
84130
85131 qcom_q6v5_prepare (& adsp -> q6v5 );
86132
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+
87141 ret = clk_prepare_enable (adsp -> xo );
88142 if (ret )
89- goto disable_irqs ;
143+ goto disable_proxy_pds ;
90144
91145 ret = clk_prepare_enable (adsp -> aggre2_clk );
92146 if (ret )
@@ -124,6 +178,10 @@ static int adsp_start(struct rproc *rproc)
124178 clk_disable_unprepare (adsp -> aggre2_clk );
125179disable_xo_clk :
126180 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 );
127185disable_irqs :
128186 qcom_q6v5_unprepare (& adsp -> q6v5 );
129187
@@ -138,6 +196,7 @@ static void qcom_pas_handover(struct qcom_q6v5 *q6v5)
138196 regulator_disable (adsp -> cx_supply );
139197 clk_disable_unprepare (adsp -> aggre2_clk );
140198 clk_disable_unprepare (adsp -> xo );
199+ adsp_pds_disable (adsp , adsp -> proxy_pds , adsp -> proxy_pd_count );
141200}
142201
143202static int adsp_stop (struct rproc * rproc )
@@ -154,6 +213,7 @@ static int adsp_stop(struct rproc *rproc)
154213 if (ret )
155214 dev_err (adsp -> dev , "failed to shutdown: %d\n" , ret );
156215
216+ adsp_pds_disable (adsp , adsp -> active_pds , adsp -> active_pd_count );
157217 handover = qcom_q6v5_unprepare (& adsp -> q6v5 );
158218 if (handover )
159219 qcom_pas_handover (& adsp -> q6v5 );
@@ -219,6 +279,59 @@ static int adsp_init_regulator(struct qcom_adsp *adsp)
219279 return PTR_ERR_OR_ZERO (adsp -> px_supply );
220280}
221281
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+
222335static int adsp_alloc_memory_region (struct qcom_adsp * adsp )
223336{
224337 struct device_node * node ;
@@ -294,10 +407,22 @@ static int adsp_probe(struct platform_device *pdev)
294407 if (ret )
295408 goto free_rproc ;
296409
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+
297422 ret = qcom_q6v5_init (& adsp -> q6v5 , pdev , rproc , desc -> crash_reason_smem ,
298423 qcom_pas_handover );
299424 if (ret )
300- goto free_rproc ;
425+ goto detach_proxy_pds ;
301426
302427 qcom_add_glink_subdev (rproc , & adsp -> glink_subdev );
303428 qcom_add_smd_subdev (rproc , & adsp -> smd_subdev );
@@ -307,15 +432,19 @@ static int adsp_probe(struct platform_device *pdev)
307432 desc -> ssctl_id );
308433 if (IS_ERR (adsp -> sysmon )) {
309434 ret = PTR_ERR (adsp -> sysmon );
310- goto free_rproc ;
435+ goto detach_proxy_pds ;
311436 }
312437
313438 ret = rproc_add (rproc );
314439 if (ret )
315- goto free_rproc ;
440+ goto detach_proxy_pds ;
316441
317442 return 0 ;
318443
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 );
319448free_rproc :
320449 rproc_free (rproc );
321450
0 commit comments