1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. */
4 #include <linux/cleanup.h>
6 #include <linux/init.h>
7 #include <linux/kernel.h>
8 #include <linux/module.h>
9 #include <linux/mutex.h>
10 #include <linux/pm_domain.h>
12 #include <linux/platform_device.h>
13 #include <linux/pm_opp.h>
14 #include <linux/soc/qcom/smd-rpm.h>
16 #include <dt-bindings/power/qcom-rpmpd.h>
18 #define domain_to_rpmpd(domain) container_of(domain, struct rpmpd, pd)
20 static struct qcom_smd_rpm
*rpmpd_smd_rpm
;
23 * RPMPD_X is X encoded as a little-endian, lower-case, ASCII string */
24 #define RPMPD_SMPA 0x61706d73
25 #define RPMPD_LDOA 0x616f646c
26 #define RPMPD_SMPB 0x62706d73
27 #define RPMPD_LDOB 0x626f646c
28 #define RPMPD_RWCX 0x78637772
29 #define RPMPD_RWMX 0x786d7772
30 #define RPMPD_RWLC 0x636c7772
31 #define RPMPD_RWLM 0x6d6c7772
32 #define RPMPD_RWSC 0x63737772
33 #define RPMPD_RWSM 0x6d737772
34 #define RPMPD_RWGX 0x78677772
37 #define KEY_CORNER 0x6e726f63 /* corn */
38 #define KEY_ENABLE 0x6e657773 /* swen */
39 #define KEY_FLOOR_CORNER 0x636676 /* vfc */
40 #define KEY_FLOOR_LEVEL 0x6c6676 /* vfl */
41 #define KEY_LEVEL 0x6c766c76 /* vlvl */
43 #define MAX_CORNER_RPMPD_STATE 6
52 struct generic_pm_domain pd
;
53 struct generic_pm_domain
*parent
;
55 const bool active_only
;
60 unsigned int max_state
;
66 struct rpmpd
**rpmpds
;
68 unsigned int max_state
;
71 static DEFINE_MUTEX(rpmpd_lock
);
74 static struct rpmpd cx_rwcx0_lvl_ao
;
75 static struct rpmpd cx_rwcx0_lvl
= {
76 .pd
= { .name
= "cx", },
77 .peer
= &cx_rwcx0_lvl_ao
,
78 .res_type
= RPMPD_RWCX
,
83 static struct rpmpd cx_rwcx0_lvl_ao
= {
84 .pd
= { .name
= "cx_ao", },
85 .peer
= &cx_rwcx0_lvl
,
87 .res_type
= RPMPD_RWCX
,
92 static struct rpmpd cx_s1a_corner_ao
;
93 static struct rpmpd cx_s1a_corner
= {
94 .pd
= { .name
= "cx", },
95 .peer
= &cx_s1a_corner_ao
,
96 .res_type
= RPMPD_SMPA
,
101 static struct rpmpd cx_s1a_corner_ao
= {
102 .pd
= { .name
= "cx_ao", },
103 .peer
= &cx_s1a_corner
,
105 .res_type
= RPMPD_SMPA
,
110 static struct rpmpd cx_s1a_lvl_ao
;
111 static struct rpmpd cx_s1a_lvl
= {
112 .pd
= { .name
= "cx", },
113 .peer
= &cx_s1a_lvl_ao
,
114 .res_type
= RPMPD_SMPA
,
119 static struct rpmpd cx_s1a_lvl_ao
= {
120 .pd
= { .name
= "cx_ao", },
123 .res_type
= RPMPD_SMPA
,
128 static struct rpmpd cx_s2a_corner_ao
;
129 static struct rpmpd cx_s2a_corner
= {
130 .pd
= { .name
= "cx", },
131 .peer
= &cx_s2a_corner_ao
,
132 .res_type
= RPMPD_SMPA
,
137 static struct rpmpd cx_s2a_corner_ao
= {
138 .pd
= { .name
= "cx_ao", },
139 .peer
= &cx_s2a_corner
,
141 .res_type
= RPMPD_SMPA
,
146 static struct rpmpd cx_s2a_lvl_ao
;
147 static struct rpmpd cx_s2a_lvl
= {
148 .pd
= { .name
= "cx", },
149 .peer
= &cx_s2a_lvl_ao
,
150 .res_type
= RPMPD_SMPA
,
155 static struct rpmpd cx_s2a_lvl_ao
= {
156 .pd
= { .name
= "cx_ao", },
159 .res_type
= RPMPD_SMPA
,
164 static struct rpmpd cx_s3a_lvl_ao
;
165 static struct rpmpd cx_s3a_lvl
= {
166 .pd
= { .name
= "cx", },
167 .peer
= &cx_s3a_lvl_ao
,
168 .res_type
= RPMPD_SMPA
,
173 static struct rpmpd cx_s3a_lvl_ao
= {
174 .pd
= { .name
= "cx_ao", },
177 .res_type
= RPMPD_SMPA
,
182 static struct rpmpd cx_rwcx0_vfl
= {
183 .pd
= { .name
= "cx_vfl", },
184 .res_type
= RPMPD_RWCX
,
186 .key
= KEY_FLOOR_LEVEL
,
189 static struct rpmpd cx_rwsc2_vfl
= {
190 .pd
= { .name
= "cx_vfl", },
191 .res_type
= RPMPD_RWSC
,
193 .key
= KEY_FLOOR_LEVEL
,
196 static struct rpmpd cx_s1a_vfc
= {
197 .pd
= { .name
= "cx_vfc", },
198 .res_type
= RPMPD_SMPA
,
200 .key
= KEY_FLOOR_CORNER
,
203 static struct rpmpd cx_s1a_vfl
= {
204 .pd
= { .name
= "cx_vfl", },
205 .res_type
= RPMPD_SMPA
,
207 .key
= KEY_FLOOR_LEVEL
,
210 static struct rpmpd cx_s2a_vfc
= {
211 .pd
= { .name
= "cx_vfc", },
212 .res_type
= RPMPD_SMPA
,
214 .key
= KEY_FLOOR_CORNER
,
217 static struct rpmpd cx_s2a_vfl
= {
218 .pd
= { .name
= "cx_vfl", },
219 .res_type
= RPMPD_SMPA
,
221 .key
= KEY_FLOOR_LEVEL
,
224 static struct rpmpd cx_s3a_vfl
= {
225 .pd
= { .name
= "cx_vfl", },
226 .res_type
= RPMPD_SMPA
,
228 .key
= KEY_FLOOR_LEVEL
,
231 static struct rpmpd cx_s2b_corner_ao
;
232 static struct rpmpd cx_s2b_corner
= {
233 .pd
= { .name
= "cx", },
234 .peer
= &cx_s2b_corner_ao
,
235 .res_type
= RPMPD_SMPB
,
240 static struct rpmpd cx_s2b_corner_ao
= {
241 .pd
= { .name
= "cx_ao", },
242 .peer
= &cx_s2b_corner
,
244 .res_type
= RPMPD_SMPB
,
249 static struct rpmpd cx_s2b_vfc
= {
250 .pd
= { .name
= "cx_vfc", },
251 .res_type
= RPMPD_SMPB
,
253 .key
= KEY_FLOOR_CORNER
,
257 static struct rpmpd gfx_s7a_corner
= {
258 .pd
= { .name
= "gfx", },
259 .res_type
= RPMPD_SMPA
,
264 static struct rpmpd gfx_s7a_vfc
= {
265 .pd
= { .name
= "gfx_vfc", },
266 .res_type
= RPMPD_SMPA
,
268 .key
= KEY_FLOOR_CORNER
,
271 static struct rpmpd gfx_s2b_corner
= {
272 .pd
= { .name
= "gfx", },
273 .res_type
= RPMPD_SMPB
,
278 static struct rpmpd gfx_s2b_vfc
= {
279 .pd
= { .name
= "gfx_vfc", },
280 .res_type
= RPMPD_SMPB
,
282 .key
= KEY_FLOOR_CORNER
,
285 static struct rpmpd gfx_s4b_corner
= {
286 .pd
= { .name
= "gfx", },
287 .res_type
= RPMPD_SMPB
,
292 static struct rpmpd gfx_s4b_vfc
= {
293 .pd
= { .name
= "gfx_vfc", },
294 .res_type
= RPMPD_SMPB
,
296 .key
= KEY_FLOOR_CORNER
,
299 static struct rpmpd mx_rwmx0_lvl
;
300 static struct rpmpd gx_rwgx0_lvl_ao
;
301 static struct rpmpd gx_rwgx0_lvl
= {
302 .pd
= { .name
= "gx", },
303 .peer
= &gx_rwgx0_lvl_ao
,
304 .res_type
= RPMPD_RWGX
,
305 .parent
= &mx_rwmx0_lvl
.pd
,
310 static struct rpmpd mx_rwmx0_lvl_ao
;
311 static struct rpmpd gx_rwgx0_lvl_ao
= {
312 .pd
= { .name
= "gx_ao", },
313 .peer
= &gx_rwgx0_lvl
,
314 .parent
= &mx_rwmx0_lvl_ao
.pd
,
316 .res_type
= RPMPD_RWGX
,
322 static struct rpmpd mx_l2a_lvl_ao
;
323 static struct rpmpd mx_l2a_lvl
= {
324 .pd
= { .name
= "mx", },
325 .peer
= &mx_l2a_lvl_ao
,
326 .res_type
= RPMPD_LDOA
,
331 static struct rpmpd mx_l2a_lvl_ao
= {
332 .pd
= { .name
= "mx_ao", },
335 .res_type
= RPMPD_LDOA
,
340 static struct rpmpd mx_l3a_corner_ao
;
341 static struct rpmpd mx_l3a_corner
= {
342 .pd
= { .name
= "mx", },
343 .peer
= &mx_l3a_corner_ao
,
344 .res_type
= RPMPD_LDOA
,
349 static struct rpmpd mx_l3a_corner_ao
= {
350 .pd
= { .name
= "mx_ao", },
351 .peer
= &mx_l3a_corner
,
353 .res_type
= RPMPD_LDOA
,
358 static struct rpmpd mx_l3a_lvl_ao
;
359 static struct rpmpd mx_l3a_lvl
= {
360 .pd
= { .name
= "mx", },
361 .peer
= &mx_l3a_lvl_ao
,
362 .res_type
= RPMPD_LDOA
,
367 static struct rpmpd mx_l3a_lvl_ao
= {
368 .pd
= { .name
= "mx_ao", },
371 .res_type
= RPMPD_LDOA
,
376 static struct rpmpd mx_l12a_lvl_ao
;
377 static struct rpmpd mx_l12a_lvl
= {
378 .pd
= { .name
= "mx", },
379 .peer
= &mx_l12a_lvl_ao
,
380 .res_type
= RPMPD_LDOA
,
385 static struct rpmpd mx_l12a_lvl_ao
= {
386 .pd
= { .name
= "mx_ao", },
387 .peer
= &mx_l12a_lvl
,
389 .res_type
= RPMPD_LDOA
,
394 static struct rpmpd mx_s2a_corner_ao
;
395 static struct rpmpd mx_s2a_corner
= {
396 .pd
= { .name
= "mx", },
397 .peer
= &mx_s2a_corner_ao
,
398 .res_type
= RPMPD_SMPA
,
403 static struct rpmpd mx_s2a_corner_ao
= {
404 .pd
= { .name
= "mx_ao", },
405 .peer
= &mx_s2a_corner
,
407 .res_type
= RPMPD_SMPA
,
412 static struct rpmpd mx_rwmx0_lvl_ao
;
413 static struct rpmpd mx_rwmx0_lvl
= {
414 .pd
= { .name
= "mx", },
415 .peer
= &mx_rwmx0_lvl_ao
,
416 .res_type
= RPMPD_RWMX
,
421 static struct rpmpd mx_rwmx0_lvl_ao
= {
422 .pd
= { .name
= "mx_ao", },
423 .peer
= &mx_rwmx0_lvl
,
425 .res_type
= RPMPD_RWMX
,
430 static struct rpmpd mx_s6a_lvl_ao
;
431 static struct rpmpd mx_s6a_lvl
= {
432 .pd
= { .name
= "mx", },
433 .peer
= &mx_s6a_lvl_ao
,
434 .res_type
= RPMPD_SMPA
,
439 static struct rpmpd mx_s6a_lvl_ao
= {
440 .pd
= { .name
= "mx_ao", },
443 .res_type
= RPMPD_SMPA
,
448 static struct rpmpd mx_s7a_lvl_ao
;
449 static struct rpmpd mx_s7a_lvl
= {
450 .pd
= { .name
= "mx", },
451 .peer
= &mx_s7a_lvl_ao
,
452 .res_type
= RPMPD_SMPA
,
457 static struct rpmpd mx_s7a_lvl_ao
= {
458 .pd
= { .name
= "mx_ao", },
461 .res_type
= RPMPD_SMPA
,
466 static struct rpmpd mx_l12a_vfl
= {
467 .pd
= { .name
= "mx_vfl", },
468 .res_type
= RPMPD_LDOA
,
470 .key
= KEY_FLOOR_LEVEL
,
473 static struct rpmpd mx_rwmx0_vfl
= {
474 .pd
= { .name
= "mx_vfl", },
475 .res_type
= RPMPD_RWMX
,
477 .key
= KEY_FLOOR_LEVEL
,
480 static struct rpmpd mx_rwsm6_vfl
= {
481 .pd
= { .name
= "mx_vfl", },
482 .res_type
= RPMPD_RWSM
,
484 .key
= KEY_FLOOR_LEVEL
,
488 static struct rpmpd md_s1a_corner_ao
;
489 static struct rpmpd md_s1a_corner
= {
490 .pd
= { .name
= "md", },
491 .peer
= &md_s1a_corner_ao
,
492 .res_type
= RPMPD_SMPA
,
497 static struct rpmpd md_s1a_corner_ao
= {
498 .pd
= { .name
= "md_ao", },
499 .peer
= &md_s1a_corner
,
501 .res_type
= RPMPD_SMPA
,
506 static struct rpmpd md_s1a_lvl_ao
;
507 static struct rpmpd md_s1a_lvl
= {
508 .pd
= { .name
= "md", },
509 .peer
= &md_s1a_lvl_ao
,
510 .res_type
= RPMPD_SMPA
,
515 static struct rpmpd md_s1a_lvl_ao
= {
516 .pd
= { .name
= "md_ao", },
519 .res_type
= RPMPD_SMPA
,
524 static struct rpmpd md_s1a_vfc
= {
525 .pd
= { .name
= "md_vfc", },
526 .res_type
= RPMPD_SMPA
,
528 .key
= KEY_FLOOR_CORNER
,
532 static struct rpmpd lpi_cx_rwlc0_lvl
= {
533 .pd
= { .name
= "lpi_cx", },
534 .res_type
= RPMPD_RWLC
,
539 static struct rpmpd lpi_cx_rwlc0_vfl
= {
540 .pd
= { .name
= "lpi_cx_vfl", },
541 .res_type
= RPMPD_RWLC
,
543 .key
= KEY_FLOOR_LEVEL
,
547 static struct rpmpd lpi_mx_rwlm0_lvl
= {
548 .pd
= { .name
= "lpi_mx", },
549 .res_type
= RPMPD_RWLM
,
554 static struct rpmpd lpi_mx_rwlm0_vfl
= {
555 .pd
= { .name
= "lpi_mx_vfl", },
556 .res_type
= RPMPD_RWLM
,
558 .key
= KEY_FLOOR_LEVEL
,
562 static struct rpmpd ssc_cx_l26a_corner
= {
563 .pd
= { .name
= "ssc_cx", },
564 .res_type
= RPMPD_LDOA
,
569 static struct rpmpd ssc_cx_rwlc0_lvl
= {
570 .pd
= { .name
= "ssc_cx", },
571 .res_type
= RPMPD_RWLC
,
576 static struct rpmpd ssc_cx_rwsc0_lvl
= {
577 .pd
= { .name
= "ssc_cx", },
578 .res_type
= RPMPD_RWSC
,
583 static struct rpmpd ssc_cx_l26a_vfc
= {
584 .pd
= { .name
= "ssc_cx_vfc", },
585 .res_type
= RPMPD_LDOA
,
587 .key
= KEY_FLOOR_CORNER
,
590 static struct rpmpd ssc_cx_rwlc0_vfl
= {
591 .pd
= { .name
= "ssc_cx_vfl", },
592 .res_type
= RPMPD_RWLC
,
594 .key
= KEY_FLOOR_LEVEL
,
597 static struct rpmpd ssc_cx_rwsc0_vfl
= {
598 .pd
= { .name
= "ssc_cx_vfl", },
599 .res_type
= RPMPD_RWSC
,
601 .key
= KEY_FLOOR_LEVEL
,
605 static struct rpmpd ssc_mx_rwlm0_lvl
= {
606 .pd
= { .name
= "ssc_mx", },
607 .res_type
= RPMPD_RWLM
,
612 static struct rpmpd ssc_mx_rwsm0_lvl
= {
613 .pd
= { .name
= "ssc_mx", },
614 .res_type
= RPMPD_RWSM
,
619 static struct rpmpd ssc_mx_rwlm0_vfl
= {
620 .pd
= { .name
= "ssc_mx_vfl", },
621 .res_type
= RPMPD_RWLM
,
623 .key
= KEY_FLOOR_LEVEL
,
626 static struct rpmpd ssc_mx_rwsm0_vfl
= {
627 .pd
= { .name
= "ssc_mx_vfl", },
628 .res_type
= RPMPD_RWSM
,
630 .key
= KEY_FLOOR_LEVEL
,
633 static struct rpmpd
*mdm9607_rpmpds
[] = {
634 [MDM9607_VDDCX
] = &cx_s3a_lvl
,
635 [MDM9607_VDDCX_AO
] = &cx_s3a_lvl_ao
,
636 [MDM9607_VDDCX_VFL
] = &cx_s3a_vfl
,
637 [MDM9607_VDDMX
] = &mx_l12a_lvl
,
638 [MDM9607_VDDMX_AO
] = &mx_l12a_lvl_ao
,
639 [MDM9607_VDDMX_VFL
] = &mx_l12a_vfl
,
642 static const struct rpmpd_desc mdm9607_desc
= {
643 .rpmpds
= mdm9607_rpmpds
,
644 .num_pds
= ARRAY_SIZE(mdm9607_rpmpds
),
645 .max_state
= RPM_SMD_LEVEL_TURBO
,
648 static struct rpmpd
*msm8226_rpmpds
[] = {
649 [MSM8226_VDDCX
] = &cx_s1a_corner
,
650 [MSM8226_VDDCX_AO
] = &cx_s1a_corner_ao
,
651 [MSM8226_VDDCX_VFC
] = &cx_s1a_vfc
,
654 static const struct rpmpd_desc msm8226_desc
= {
655 .rpmpds
= msm8226_rpmpds
,
656 .num_pds
= ARRAY_SIZE(msm8226_rpmpds
),
657 .max_state
= MAX_CORNER_RPMPD_STATE
,
660 static struct rpmpd
*msm8939_rpmpds
[] = {
661 [MSM8939_VDDMDCX
] = &md_s1a_corner
,
662 [MSM8939_VDDMDCX_AO
] = &md_s1a_corner_ao
,
663 [MSM8939_VDDMDCX_VFC
] = &md_s1a_vfc
,
664 [MSM8939_VDDCX
] = &cx_s2a_corner
,
665 [MSM8939_VDDCX_AO
] = &cx_s2a_corner_ao
,
666 [MSM8939_VDDCX_VFC
] = &cx_s2a_vfc
,
667 [MSM8939_VDDMX
] = &mx_l3a_corner
,
668 [MSM8939_VDDMX_AO
] = &mx_l3a_corner_ao
,
671 static const struct rpmpd_desc msm8939_desc
= {
672 .rpmpds
= msm8939_rpmpds
,
673 .num_pds
= ARRAY_SIZE(msm8939_rpmpds
),
674 .max_state
= MAX_CORNER_RPMPD_STATE
,
677 static struct rpmpd
*msm8916_rpmpds
[] = {
678 [MSM8916_VDDCX
] = &cx_s1a_corner
,
679 [MSM8916_VDDCX_AO
] = &cx_s1a_corner_ao
,
680 [MSM8916_VDDCX_VFC
] = &cx_s1a_vfc
,
681 [MSM8916_VDDMX
] = &mx_l3a_corner
,
682 [MSM8916_VDDMX_AO
] = &mx_l3a_corner_ao
,
685 static const struct rpmpd_desc msm8916_desc
= {
686 .rpmpds
= msm8916_rpmpds
,
687 .num_pds
= ARRAY_SIZE(msm8916_rpmpds
),
688 .max_state
= MAX_CORNER_RPMPD_STATE
,
691 static struct rpmpd
*msm8917_rpmpds
[] = {
692 [MSM8917_VDDCX
] = &cx_s2a_lvl
,
693 [MSM8917_VDDCX_AO
] = &cx_s2a_lvl_ao
,
694 [MSM8917_VDDCX_VFL
] = &cx_s2a_vfl
,
695 [MSM8917_VDDMX
] = &mx_l3a_lvl
,
696 [MSM8917_VDDMX_AO
] = &mx_l3a_lvl_ao
,
699 static const struct rpmpd_desc msm8917_desc
= {
700 .rpmpds
= msm8917_rpmpds
,
701 .num_pds
= ARRAY_SIZE(msm8917_rpmpds
),
702 .max_state
= RPM_SMD_LEVEL_TURBO
,
705 static struct rpmpd
*msm8953_rpmpds
[] = {
706 [MSM8953_VDDMD
] = &md_s1a_lvl
,
707 [MSM8953_VDDMD_AO
] = &md_s1a_lvl_ao
,
708 [MSM8953_VDDCX
] = &cx_s2a_lvl
,
709 [MSM8953_VDDCX_AO
] = &cx_s2a_lvl_ao
,
710 [MSM8953_VDDCX_VFL
] = &cx_s2a_vfl
,
711 [MSM8953_VDDMX
] = &mx_s7a_lvl
,
712 [MSM8953_VDDMX_AO
] = &mx_s7a_lvl_ao
,
715 static const struct rpmpd_desc msm8953_desc
= {
716 .rpmpds
= msm8953_rpmpds
,
717 .num_pds
= ARRAY_SIZE(msm8953_rpmpds
),
718 .max_state
= RPM_SMD_LEVEL_TURBO
,
721 static struct rpmpd
*msm8974_rpmpds
[] = {
722 [MSM8974_VDDCX
] = &cx_s2b_corner
,
723 [MSM8974_VDDCX_AO
] = &cx_s2b_corner_ao
,
724 [MSM8974_VDDCX_VFC
] = &cx_s2b_vfc
,
725 [MSM8974_VDDGFX
] = &gfx_s4b_corner
,
726 [MSM8974_VDDGFX_VFC
] = &gfx_s4b_vfc
,
729 static const struct rpmpd_desc msm8974_desc
= {
730 .rpmpds
= msm8974_rpmpds
,
731 .num_pds
= ARRAY_SIZE(msm8974_rpmpds
),
732 .max_state
= MAX_CORNER_RPMPD_STATE
,
735 static struct rpmpd
*msm8974pro_pma8084_rpmpds
[] = {
736 [MSM8974_VDDCX
] = &cx_s2a_corner
,
737 [MSM8974_VDDCX_AO
] = &cx_s2a_corner_ao
,
738 [MSM8974_VDDCX_VFC
] = &cx_s2a_vfc
,
739 [MSM8974_VDDGFX
] = &gfx_s7a_corner
,
740 [MSM8974_VDDGFX_VFC
] = &gfx_s7a_vfc
,
743 static const struct rpmpd_desc msm8974pro_pma8084_desc
= {
744 .rpmpds
= msm8974pro_pma8084_rpmpds
,
745 .num_pds
= ARRAY_SIZE(msm8974pro_pma8084_rpmpds
),
746 .max_state
= MAX_CORNER_RPMPD_STATE
,
749 static struct rpmpd
*msm8976_rpmpds
[] = {
750 [MSM8976_VDDCX
] = &cx_s2a_lvl
,
751 [MSM8976_VDDCX_AO
] = &cx_s2a_lvl_ao
,
752 [MSM8976_VDDCX_VFL
] = &cx_rwsc2_vfl
,
753 [MSM8976_VDDMX
] = &mx_s6a_lvl
,
754 [MSM8976_VDDMX_AO
] = &mx_s6a_lvl_ao
,
755 [MSM8976_VDDMX_VFL
] = &mx_rwsm6_vfl
,
758 static const struct rpmpd_desc msm8976_desc
= {
759 .rpmpds
= msm8976_rpmpds
,
760 .num_pds
= ARRAY_SIZE(msm8976_rpmpds
),
761 .max_state
= RPM_SMD_LEVEL_TURBO_HIGH
,
764 static struct rpmpd
*msm8994_rpmpds
[] = {
765 [MSM8994_VDDCX
] = &cx_s1a_corner
,
766 [MSM8994_VDDCX_AO
] = &cx_s1a_corner_ao
,
767 [MSM8994_VDDCX_VFC
] = &cx_s1a_vfc
,
768 [MSM8994_VDDMX
] = &mx_s2a_corner
,
769 [MSM8994_VDDMX_AO
] = &mx_s2a_corner_ao
,
771 /* Attention! *Some* 8994 boards with pm8004 may use SMPC here! */
772 [MSM8994_VDDGFX
] = &gfx_s2b_corner
,
773 [MSM8994_VDDGFX_VFC
] = &gfx_s2b_vfc
,
776 static const struct rpmpd_desc msm8994_desc
= {
777 .rpmpds
= msm8994_rpmpds
,
778 .num_pds
= ARRAY_SIZE(msm8994_rpmpds
),
779 .max_state
= MAX_CORNER_RPMPD_STATE
,
782 static struct rpmpd
*msm8996_rpmpds
[] = {
783 [MSM8996_VDDCX
] = &cx_s1a_corner
,
784 [MSM8996_VDDCX_AO
] = &cx_s1a_corner_ao
,
785 [MSM8996_VDDCX_VFC
] = &cx_s1a_vfc
,
786 [MSM8996_VDDMX
] = &mx_s2a_corner
,
787 [MSM8996_VDDMX_AO
] = &mx_s2a_corner_ao
,
788 [MSM8996_VDDSSCX
] = &ssc_cx_l26a_corner
,
789 [MSM8996_VDDSSCX_VFC
] = &ssc_cx_l26a_vfc
,
792 static const struct rpmpd_desc msm8996_desc
= {
793 .rpmpds
= msm8996_rpmpds
,
794 .num_pds
= ARRAY_SIZE(msm8996_rpmpds
),
795 .max_state
= MAX_CORNER_RPMPD_STATE
,
798 static struct rpmpd
*msm8998_rpmpds
[] = {
799 [MSM8998_VDDCX
] = &cx_rwcx0_lvl
,
800 [MSM8998_VDDCX_AO
] = &cx_rwcx0_lvl_ao
,
801 [MSM8998_VDDCX_VFL
] = &cx_rwcx0_vfl
,
802 [MSM8998_VDDMX
] = &mx_rwmx0_lvl
,
803 [MSM8998_VDDMX_AO
] = &mx_rwmx0_lvl_ao
,
804 [MSM8998_VDDMX_VFL
] = &mx_rwmx0_vfl
,
805 [MSM8998_SSCCX
] = &ssc_cx_rwsc0_lvl
,
806 [MSM8998_SSCCX_VFL
] = &ssc_cx_rwsc0_vfl
,
807 [MSM8998_SSCMX
] = &ssc_mx_rwsm0_lvl
,
808 [MSM8998_SSCMX_VFL
] = &ssc_mx_rwsm0_vfl
,
811 static const struct rpmpd_desc msm8998_desc
= {
812 .rpmpds
= msm8998_rpmpds
,
813 .num_pds
= ARRAY_SIZE(msm8998_rpmpds
),
814 .max_state
= RPM_SMD_LEVEL_BINNING
,
817 static struct rpmpd
*qcs404_rpmpds
[] = {
818 [QCS404_VDDMX
] = &mx_rwmx0_lvl
,
819 [QCS404_VDDMX_AO
] = &mx_rwmx0_lvl_ao
,
820 [QCS404_VDDMX_VFL
] = &mx_rwmx0_vfl
,
821 [QCS404_LPICX
] = &lpi_cx_rwlc0_lvl
,
822 [QCS404_LPICX_VFL
] = &lpi_cx_rwlc0_vfl
,
823 [QCS404_LPIMX
] = &lpi_mx_rwlm0_lvl
,
824 [QCS404_LPIMX_VFL
] = &lpi_mx_rwlm0_vfl
,
827 static const struct rpmpd_desc qcs404_desc
= {
828 .rpmpds
= qcs404_rpmpds
,
829 .num_pds
= ARRAY_SIZE(qcs404_rpmpds
),
830 .max_state
= RPM_SMD_LEVEL_BINNING
,
833 static struct rpmpd
*qm215_rpmpds
[] = {
834 [QM215_VDDCX
] = &cx_s1a_lvl
,
835 [QM215_VDDCX_AO
] = &cx_s1a_lvl_ao
,
836 [QM215_VDDCX_VFL
] = &cx_s1a_vfl
,
837 [QM215_VDDMX
] = &mx_l2a_lvl
,
838 [QM215_VDDMX_AO
] = &mx_l2a_lvl_ao
,
841 static const struct rpmpd_desc qm215_desc
= {
842 .rpmpds
= qm215_rpmpds
,
843 .num_pds
= ARRAY_SIZE(qm215_rpmpds
),
844 .max_state
= RPM_SMD_LEVEL_TURBO
,
847 static struct rpmpd
*sdm660_rpmpds
[] = {
848 [SDM660_VDDCX
] = &cx_rwcx0_lvl
,
849 [SDM660_VDDCX_AO
] = &cx_rwcx0_lvl_ao
,
850 [SDM660_VDDCX_VFL
] = &cx_rwcx0_vfl
,
851 [SDM660_VDDMX
] = &mx_rwmx0_lvl
,
852 [SDM660_VDDMX_AO
] = &mx_rwmx0_lvl_ao
,
853 [SDM660_VDDMX_VFL
] = &mx_rwmx0_vfl
,
854 [SDM660_SSCCX
] = &ssc_cx_rwlc0_lvl
,
855 [SDM660_SSCCX_VFL
] = &ssc_cx_rwlc0_vfl
,
856 [SDM660_SSCMX
] = &ssc_mx_rwlm0_lvl
,
857 [SDM660_SSCMX_VFL
] = &ssc_mx_rwlm0_vfl
,
860 static const struct rpmpd_desc sdm660_desc
= {
861 .rpmpds
= sdm660_rpmpds
,
862 .num_pds
= ARRAY_SIZE(sdm660_rpmpds
),
863 .max_state
= RPM_SMD_LEVEL_TURBO
,
866 static struct rpmpd
*sm6115_rpmpds
[] = {
867 [SM6115_VDDCX
] = &cx_rwcx0_lvl
,
868 [SM6115_VDDCX_AO
] = &cx_rwcx0_lvl_ao
,
869 [SM6115_VDDCX_VFL
] = &cx_rwcx0_vfl
,
870 [SM6115_VDDMX
] = &mx_rwmx0_lvl
,
871 [SM6115_VDDMX_AO
] = &mx_rwmx0_lvl_ao
,
872 [SM6115_VDDMX_VFL
] = &mx_rwmx0_vfl
,
873 [SM6115_VDD_LPI_CX
] = &lpi_cx_rwlc0_lvl
,
874 [SM6115_VDD_LPI_MX
] = &lpi_mx_rwlm0_lvl
,
877 static const struct rpmpd_desc sm6115_desc
= {
878 .rpmpds
= sm6115_rpmpds
,
879 .num_pds
= ARRAY_SIZE(sm6115_rpmpds
),
880 .max_state
= RPM_SMD_LEVEL_TURBO_NO_CPR
,
883 static struct rpmpd
*sm6125_rpmpds
[] = {
884 [SM6125_VDDCX
] = &cx_rwcx0_lvl
,
885 [SM6125_VDDCX_AO
] = &cx_rwcx0_lvl_ao
,
886 [SM6125_VDDCX_VFL
] = &cx_rwcx0_vfl
,
887 [SM6125_VDDMX
] = &mx_rwmx0_lvl
,
888 [SM6125_VDDMX_AO
] = &mx_rwmx0_lvl_ao
,
889 [SM6125_VDDMX_VFL
] = &mx_rwmx0_vfl
,
892 static const struct rpmpd_desc sm6125_desc
= {
893 .rpmpds
= sm6125_rpmpds
,
894 .num_pds
= ARRAY_SIZE(sm6125_rpmpds
),
895 .max_state
= RPM_SMD_LEVEL_BINNING
,
898 static struct rpmpd
*sm6375_rpmpds
[] = {
899 [SM6375_VDDCX
] = &cx_rwcx0_lvl
,
900 [SM6375_VDDCX_AO
] = &cx_rwcx0_lvl_ao
,
901 [SM6375_VDDCX_VFL
] = &cx_rwcx0_vfl
,
902 [SM6375_VDDMX
] = &mx_rwmx0_lvl
,
903 [SM6375_VDDMX_AO
] = &mx_rwmx0_lvl_ao
,
904 [SM6375_VDDMX_VFL
] = &mx_rwmx0_vfl
,
905 [SM6375_VDDGX
] = &gx_rwgx0_lvl
,
906 [SM6375_VDDGX_AO
] = &gx_rwgx0_lvl_ao
,
907 [SM6375_VDD_LPI_CX
] = &lpi_cx_rwlc0_lvl
,
908 [SM6375_VDD_LPI_MX
] = &lpi_mx_rwlm0_lvl
,
911 static const struct rpmpd_desc sm6375_desc
= {
912 .rpmpds
= sm6375_rpmpds
,
913 .num_pds
= ARRAY_SIZE(sm6375_rpmpds
),
914 .max_state
= RPM_SMD_LEVEL_TURBO_NO_CPR
,
917 static struct rpmpd
*qcm2290_rpmpds
[] = {
918 [QCM2290_VDDCX
] = &cx_rwcx0_lvl
,
919 [QCM2290_VDDCX_AO
] = &cx_rwcx0_lvl_ao
,
920 [QCM2290_VDDCX_VFL
] = &cx_rwcx0_vfl
,
921 [QCM2290_VDDMX
] = &mx_rwmx0_lvl
,
922 [QCM2290_VDDMX_AO
] = &mx_rwmx0_lvl_ao
,
923 [QCM2290_VDDMX_VFL
] = &mx_rwmx0_vfl
,
924 [QCM2290_VDD_LPI_CX
] = &lpi_cx_rwlc0_lvl
,
925 [QCM2290_VDD_LPI_MX
] = &lpi_mx_rwlm0_lvl
,
928 static const struct rpmpd_desc qcm2290_desc
= {
929 .rpmpds
= qcm2290_rpmpds
,
930 .num_pds
= ARRAY_SIZE(qcm2290_rpmpds
),
931 .max_state
= RPM_SMD_LEVEL_TURBO_NO_CPR
,
934 static const struct of_device_id rpmpd_match_table
[] = {
935 { .compatible
= "qcom,mdm9607-rpmpd", .data
= &mdm9607_desc
},
936 { .compatible
= "qcom,msm8226-rpmpd", .data
= &msm8226_desc
},
937 { .compatible
= "qcom,msm8909-rpmpd", .data
= &msm8916_desc
},
938 { .compatible
= "qcom,msm8916-rpmpd", .data
= &msm8916_desc
},
939 { .compatible
= "qcom,msm8917-rpmpd", .data
= &msm8917_desc
},
940 { .compatible
= "qcom,msm8939-rpmpd", .data
= &msm8939_desc
},
941 { .compatible
= "qcom,msm8953-rpmpd", .data
= &msm8953_desc
},
942 { .compatible
= "qcom,msm8974-rpmpd", .data
= &msm8974_desc
},
943 { .compatible
= "qcom,msm8974pro-pma8084-rpmpd", .data
= &msm8974pro_pma8084_desc
},
944 { .compatible
= "qcom,msm8976-rpmpd", .data
= &msm8976_desc
},
945 { .compatible
= "qcom,msm8994-rpmpd", .data
= &msm8994_desc
},
946 { .compatible
= "qcom,msm8996-rpmpd", .data
= &msm8996_desc
},
947 { .compatible
= "qcom,msm8998-rpmpd", .data
= &msm8998_desc
},
948 { .compatible
= "qcom,qcm2290-rpmpd", .data
= &qcm2290_desc
},
949 { .compatible
= "qcom,qcs404-rpmpd", .data
= &qcs404_desc
},
950 { .compatible
= "qcom,qm215-rpmpd", .data
= &qm215_desc
},
951 { .compatible
= "qcom,sdm660-rpmpd", .data
= &sdm660_desc
},
952 { .compatible
= "qcom,sm6115-rpmpd", .data
= &sm6115_desc
},
953 { .compatible
= "qcom,sm6125-rpmpd", .data
= &sm6125_desc
},
954 { .compatible
= "qcom,sm6375-rpmpd", .data
= &sm6375_desc
},
957 MODULE_DEVICE_TABLE(of
, rpmpd_match_table
);
959 static int rpmpd_send_enable(struct rpmpd
*pd
, bool enable
)
961 struct rpmpd_req req
= {
963 .nbytes
= cpu_to_le32(sizeof(u32
)),
964 .value
= cpu_to_le32(enable
),
967 return qcom_rpm_smd_write(rpmpd_smd_rpm
, QCOM_SMD_RPM_ACTIVE_STATE
,
968 pd
->res_type
, pd
->res_id
, &req
, sizeof(req
));
971 static int rpmpd_send_corner(struct rpmpd
*pd
, int state
, unsigned int corner
)
973 struct rpmpd_req req
= {
975 .nbytes
= cpu_to_le32(sizeof(u32
)),
976 .value
= cpu_to_le32(corner
),
979 return qcom_rpm_smd_write(rpmpd_smd_rpm
, state
, pd
->res_type
, pd
->res_id
,
983 static void to_active_sleep(struct rpmpd
*pd
, unsigned int corner
,
984 unsigned int *active
, unsigned int *sleep
)
994 static int rpmpd_aggregate_corner(struct rpmpd
*pd
)
997 struct rpmpd
*peer
= pd
->peer
;
998 unsigned int active_corner
, sleep_corner
;
999 unsigned int this_active_corner
= 0, this_sleep_corner
= 0;
1000 unsigned int peer_active_corner
= 0, peer_sleep_corner
= 0;
1002 /* Clamp to the highest corner/level if sync_state isn't done yet */
1003 if (!pd
->state_synced
)
1004 this_active_corner
= this_sleep_corner
= pd
->max_state
- 1;
1006 to_active_sleep(pd
, pd
->corner
, &this_active_corner
, &this_sleep_corner
);
1008 if (peer
&& peer
->enabled
)
1009 to_active_sleep(peer
, peer
->corner
, &peer_active_corner
,
1010 &peer_sleep_corner
);
1012 active_corner
= max(this_active_corner
, peer_active_corner
);
1014 ret
= rpmpd_send_corner(pd
, QCOM_SMD_RPM_ACTIVE_STATE
, active_corner
);
1018 sleep_corner
= max(this_sleep_corner
, peer_sleep_corner
);
1020 return rpmpd_send_corner(pd
, QCOM_SMD_RPM_SLEEP_STATE
, sleep_corner
);
1023 static int rpmpd_power_on(struct generic_pm_domain
*domain
)
1026 struct rpmpd
*pd
= domain_to_rpmpd(domain
);
1028 guard(mutex
)(&rpmpd_lock
);
1030 ret
= rpmpd_send_enable(pd
, true);
1037 ret
= rpmpd_aggregate_corner(pd
);
1042 static int rpmpd_power_off(struct generic_pm_domain
*domain
)
1045 struct rpmpd
*pd
= domain_to_rpmpd(domain
);
1047 mutex_lock(&rpmpd_lock
);
1049 ret
= rpmpd_send_enable(pd
, false);
1051 pd
->enabled
= false;
1053 mutex_unlock(&rpmpd_lock
);
1058 static int rpmpd_set_performance(struct generic_pm_domain
*domain
,
1061 struct rpmpd
*pd
= domain_to_rpmpd(domain
);
1063 if (state
> pd
->max_state
)
1064 state
= pd
->max_state
;
1066 guard(mutex
)(&rpmpd_lock
);
1070 /* Always send updates for vfc and vfl */
1071 if (!pd
->enabled
&& pd
->key
!= cpu_to_le32(KEY_FLOOR_CORNER
) &&
1072 pd
->key
!= cpu_to_le32(KEY_FLOOR_LEVEL
))
1075 return rpmpd_aggregate_corner(pd
);
1078 static int rpmpd_probe(struct platform_device
*pdev
)
1082 struct genpd_onecell_data
*data
;
1083 struct rpmpd
**rpmpds
;
1084 const struct rpmpd_desc
*desc
;
1086 rpmpd_smd_rpm
= dev_get_drvdata(pdev
->dev
.parent
);
1087 if (!rpmpd_smd_rpm
) {
1088 dev_err(&pdev
->dev
, "Unable to retrieve handle to RPM\n");
1092 desc
= of_device_get_match_data(&pdev
->dev
);
1096 rpmpds
= desc
->rpmpds
;
1097 num
= desc
->num_pds
;
1099 data
= devm_kzalloc(&pdev
->dev
, sizeof(*data
), GFP_KERNEL
);
1103 data
->domains
= devm_kcalloc(&pdev
->dev
, num
, sizeof(*data
->domains
),
1108 data
->num_domains
= num
;
1110 for (i
= 0; i
< num
; i
++) {
1112 dev_warn(&pdev
->dev
, "rpmpds[] with empty entry at index=%d\n",
1117 rpmpds
[i
]->max_state
= desc
->max_state
;
1118 rpmpds
[i
]->pd
.power_off
= rpmpd_power_off
;
1119 rpmpds
[i
]->pd
.power_on
= rpmpd_power_on
;
1120 rpmpds
[i
]->pd
.set_performance_state
= rpmpd_set_performance
;
1121 rpmpds
[i
]->pd
.flags
= GENPD_FLAG_ACTIVE_WAKEUP
;
1122 pm_genpd_init(&rpmpds
[i
]->pd
, NULL
, true);
1124 data
->domains
[i
] = &rpmpds
[i
]->pd
;
1127 /* Add subdomains */
1128 for (i
= 0; i
< num
; i
++) {
1132 if (rpmpds
[i
]->parent
)
1133 pm_genpd_add_subdomain(rpmpds
[i
]->parent
, &rpmpds
[i
]->pd
);
1136 return of_genpd_add_provider_onecell(pdev
->dev
.of_node
, data
);
1139 static void rpmpd_sync_state(struct device
*dev
)
1141 const struct rpmpd_desc
*desc
= of_device_get_match_data(dev
);
1142 struct rpmpd
**rpmpds
= desc
->rpmpds
;
1147 mutex_lock(&rpmpd_lock
);
1148 for (i
= 0; i
< desc
->num_pds
; i
++) {
1153 pd
->state_synced
= true;
1158 ret
= rpmpd_aggregate_corner(pd
);
1160 dev_err(dev
, "failed to sync %s: %d\n", pd
->pd
.name
, ret
);
1162 mutex_unlock(&rpmpd_lock
);
1165 static struct platform_driver rpmpd_driver
= {
1167 .name
= "qcom-rpmpd",
1168 .of_match_table
= rpmpd_match_table
,
1169 .suppress_bind_attrs
= true,
1170 .sync_state
= rpmpd_sync_state
,
1172 .probe
= rpmpd_probe
,
1175 static int __init
rpmpd_init(void)
1177 return platform_driver_register(&rpmpd_driver
);
1179 core_initcall(rpmpd_init
);
1181 MODULE_DESCRIPTION("Qualcomm Technologies, Inc. RPM Power Domain Driver");
1182 MODULE_LICENSE("GPL v2");