1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. */
5 #include <linux/init.h>
6 #include <linux/kernel.h>
7 #include <linux/mutex.h>
8 #include <linux/pm_domain.h>
10 #include <linux/of_device.h>
11 #include <linux/platform_device.h>
12 #include <linux/pm_opp.h>
13 #include <linux/soc/qcom/smd-rpm.h>
15 #include <dt-bindings/power/qcom-rpmpd.h>
17 #define domain_to_rpmpd(domain) container_of(domain, struct rpmpd, pd)
20 * RPMPD_X is X encoded as a little-endian, lower-case, ASCII string */
21 #define RPMPD_SMPA 0x61706d73
22 #define RPMPD_LDOA 0x616f646c
23 #define RPMPD_RWCX 0x78637772
24 #define RPMPD_RWMX 0x786d7772
25 #define RPMPD_RWLC 0x636c7772
26 #define RPMPD_RWLM 0x6d6c7772
27 #define RPMPD_RWSC 0x63737772
28 #define RPMPD_RWSM 0x6d737772
31 #define KEY_CORNER 0x6e726f63 /* corn */
32 #define KEY_ENABLE 0x6e657773 /* swen */
33 #define KEY_FLOOR_CORNER 0x636676 /* vfc */
34 #define KEY_FLOOR_LEVEL 0x6c6676 /* vfl */
35 #define KEY_LEVEL 0x6c766c76 /* vlvl */
37 #define MAX_8996_RPMPD_STATE 6
39 #define DEFINE_RPMPD_PAIR(_platform, _name, _active, r_type, r_key, \
41 static struct rpmpd _platform##_##_active; \
42 static struct rpmpd _platform##_##_name = { \
43 .pd = { .name = #_name, }, \
44 .peer = &_platform##_##_active, \
45 .res_type = RPMPD_##r_type, \
49 static struct rpmpd _platform##_##_active = { \
50 .pd = { .name = #_active, }, \
51 .peer = &_platform##_##_name, \
52 .active_only = true, \
53 .res_type = RPMPD_##r_type, \
58 #define DEFINE_RPMPD_CORNER(_platform, _name, r_type, r_id) \
59 static struct rpmpd _platform##_##_name = { \
60 .pd = { .name = #_name, }, \
61 .res_type = RPMPD_##r_type, \
66 #define DEFINE_RPMPD_LEVEL(_platform, _name, r_type, r_id) \
67 static struct rpmpd _platform##_##_name = { \
68 .pd = { .name = #_name, }, \
69 .res_type = RPMPD_##r_type, \
74 #define DEFINE_RPMPD_VFC(_platform, _name, r_type, r_id) \
75 static struct rpmpd _platform##_##_name = { \
76 .pd = { .name = #_name, }, \
77 .res_type = RPMPD_##r_type, \
79 .key = KEY_FLOOR_CORNER, \
82 #define DEFINE_RPMPD_VFL(_platform, _name, r_type, r_id) \
83 static struct rpmpd _platform##_##_name = { \
84 .pd = { .name = #_name, }, \
85 .res_type = RPMPD_##r_type, \
87 .key = KEY_FLOOR_LEVEL, \
97 struct generic_pm_domain pd
;
99 const bool active_only
;
102 const char *res_name
;
105 struct qcom_smd_rpm
*rpm
;
106 unsigned int max_state
;
111 struct rpmpd
**rpmpds
;
113 unsigned int max_state
;
116 static DEFINE_MUTEX(rpmpd_lock
);
118 /* msm8976 RPM Power Domains */
119 DEFINE_RPMPD_PAIR(msm8976
, vddcx
, vddcx_ao
, SMPA
, LEVEL
, 2);
120 DEFINE_RPMPD_PAIR(msm8976
, vddmx
, vddmx_ao
, SMPA
, LEVEL
, 6);
122 DEFINE_RPMPD_VFL(msm8976
, vddcx_vfl
, RWSC
, 2);
123 DEFINE_RPMPD_VFL(msm8976
, vddmx_vfl
, RWSM
, 6);
125 static struct rpmpd
*msm8976_rpmpds
[] = {
126 [MSM8976_VDDCX
] = &msm8976_vddcx
,
127 [MSM8976_VDDCX_AO
] = &msm8976_vddcx_ao
,
128 [MSM8976_VDDCX_VFL
] = &msm8976_vddcx_vfl
,
129 [MSM8976_VDDMX
] = &msm8976_vddmx
,
130 [MSM8976_VDDMX_AO
] = &msm8976_vddmx_ao
,
131 [MSM8976_VDDMX_VFL
] = &msm8976_vddmx_vfl
,
134 static const struct rpmpd_desc msm8976_desc
= {
135 .rpmpds
= msm8976_rpmpds
,
136 .num_pds
= ARRAY_SIZE(msm8976_rpmpds
),
137 .max_state
= RPM_SMD_LEVEL_TURBO_HIGH
,
140 /* msm8996 RPM Power domains */
141 DEFINE_RPMPD_PAIR(msm8996
, vddcx
, vddcx_ao
, SMPA
, CORNER
, 1);
142 DEFINE_RPMPD_PAIR(msm8996
, vddmx
, vddmx_ao
, SMPA
, CORNER
, 2);
143 DEFINE_RPMPD_CORNER(msm8996
, vddsscx
, LDOA
, 26);
145 DEFINE_RPMPD_VFC(msm8996
, vddcx_vfc
, SMPA
, 1);
146 DEFINE_RPMPD_VFC(msm8996
, vddsscx_vfc
, LDOA
, 26);
148 static struct rpmpd
*msm8996_rpmpds
[] = {
149 [MSM8996_VDDCX
] = &msm8996_vddcx
,
150 [MSM8996_VDDCX_AO
] = &msm8996_vddcx_ao
,
151 [MSM8996_VDDCX_VFC
] = &msm8996_vddcx_vfc
,
152 [MSM8996_VDDMX
] = &msm8996_vddmx
,
153 [MSM8996_VDDMX_AO
] = &msm8996_vddmx_ao
,
154 [MSM8996_VDDSSCX
] = &msm8996_vddsscx
,
155 [MSM8996_VDDSSCX_VFC
] = &msm8996_vddsscx_vfc
,
158 static const struct rpmpd_desc msm8996_desc
= {
159 .rpmpds
= msm8996_rpmpds
,
160 .num_pds
= ARRAY_SIZE(msm8996_rpmpds
),
161 .max_state
= MAX_8996_RPMPD_STATE
,
164 /* msm8998 RPM Power domains */
165 DEFINE_RPMPD_PAIR(msm8998
, vddcx
, vddcx_ao
, RWCX
, LEVEL
, 0);
166 DEFINE_RPMPD_VFL(msm8998
, vddcx_vfl
, RWCX
, 0);
168 DEFINE_RPMPD_PAIR(msm8998
, vddmx
, vddmx_ao
, RWMX
, LEVEL
, 0);
169 DEFINE_RPMPD_VFL(msm8998
, vddmx_vfl
, RWMX
, 0);
171 DEFINE_RPMPD_LEVEL(msm8998
, vdd_ssccx
, RWSC
, 0);
172 DEFINE_RPMPD_VFL(msm8998
, vdd_ssccx_vfl
, RWSC
, 0);
174 DEFINE_RPMPD_LEVEL(msm8998
, vdd_sscmx
, RWSM
, 0);
175 DEFINE_RPMPD_VFL(msm8998
, vdd_sscmx_vfl
, RWSM
, 0);
177 static struct rpmpd
*msm8998_rpmpds
[] = {
178 [MSM8998_VDDCX
] = &msm8998_vddcx
,
179 [MSM8998_VDDCX_AO
] = &msm8998_vddcx_ao
,
180 [MSM8998_VDDCX_VFL
] = &msm8998_vddcx_vfl
,
181 [MSM8998_VDDMX
] = &msm8998_vddmx
,
182 [MSM8998_VDDMX_AO
] = &msm8998_vddmx_ao
,
183 [MSM8998_VDDMX_VFL
] = &msm8998_vddmx_vfl
,
184 [MSM8998_SSCCX
] = &msm8998_vdd_ssccx
,
185 [MSM8998_SSCCX_VFL
] = &msm8998_vdd_ssccx_vfl
,
186 [MSM8998_SSCMX
] = &msm8998_vdd_sscmx
,
187 [MSM8998_SSCMX_VFL
] = &msm8998_vdd_sscmx_vfl
,
190 static const struct rpmpd_desc msm8998_desc
= {
191 .rpmpds
= msm8998_rpmpds
,
192 .num_pds
= ARRAY_SIZE(msm8998_rpmpds
),
193 .max_state
= RPM_SMD_LEVEL_BINNING
,
196 /* qcs404 RPM Power domains */
197 DEFINE_RPMPD_PAIR(qcs404
, vddmx
, vddmx_ao
, RWMX
, LEVEL
, 0);
198 DEFINE_RPMPD_VFL(qcs404
, vddmx_vfl
, RWMX
, 0);
200 DEFINE_RPMPD_LEVEL(qcs404
, vdd_lpicx
, RWLC
, 0);
201 DEFINE_RPMPD_VFL(qcs404
, vdd_lpicx_vfl
, RWLC
, 0);
203 DEFINE_RPMPD_LEVEL(qcs404
, vdd_lpimx
, RWLM
, 0);
204 DEFINE_RPMPD_VFL(qcs404
, vdd_lpimx_vfl
, RWLM
, 0);
206 static struct rpmpd
*qcs404_rpmpds
[] = {
207 [QCS404_VDDMX
] = &qcs404_vddmx
,
208 [QCS404_VDDMX_AO
] = &qcs404_vddmx_ao
,
209 [QCS404_VDDMX_VFL
] = &qcs404_vddmx_vfl
,
210 [QCS404_LPICX
] = &qcs404_vdd_lpicx
,
211 [QCS404_LPICX_VFL
] = &qcs404_vdd_lpicx_vfl
,
212 [QCS404_LPIMX
] = &qcs404_vdd_lpimx
,
213 [QCS404_LPIMX_VFL
] = &qcs404_vdd_lpimx_vfl
,
216 static const struct rpmpd_desc qcs404_desc
= {
217 .rpmpds
= qcs404_rpmpds
,
218 .num_pds
= ARRAY_SIZE(qcs404_rpmpds
),
219 .max_state
= RPM_SMD_LEVEL_BINNING
,
222 static const struct of_device_id rpmpd_match_table
[] = {
223 { .compatible
= "qcom,msm8976-rpmpd", .data
= &msm8976_desc
},
224 { .compatible
= "qcom,msm8996-rpmpd", .data
= &msm8996_desc
},
225 { .compatible
= "qcom,msm8998-rpmpd", .data
= &msm8998_desc
},
226 { .compatible
= "qcom,qcs404-rpmpd", .data
= &qcs404_desc
},
230 static int rpmpd_send_enable(struct rpmpd
*pd
, bool enable
)
232 struct rpmpd_req req
= {
234 .nbytes
= cpu_to_le32(sizeof(u32
)),
235 .value
= cpu_to_le32(enable
),
238 return qcom_rpm_smd_write(pd
->rpm
, QCOM_SMD_RPM_ACTIVE_STATE
,
239 pd
->res_type
, pd
->res_id
, &req
, sizeof(req
));
242 static int rpmpd_send_corner(struct rpmpd
*pd
, int state
, unsigned int corner
)
244 struct rpmpd_req req
= {
246 .nbytes
= cpu_to_le32(sizeof(u32
)),
247 .value
= cpu_to_le32(corner
),
250 return qcom_rpm_smd_write(pd
->rpm
, state
, pd
->res_type
, pd
->res_id
,
254 static void to_active_sleep(struct rpmpd
*pd
, unsigned int corner
,
255 unsigned int *active
, unsigned int *sleep
)
265 static int rpmpd_aggregate_corner(struct rpmpd
*pd
)
268 struct rpmpd
*peer
= pd
->peer
;
269 unsigned int active_corner
, sleep_corner
;
270 unsigned int this_active_corner
= 0, this_sleep_corner
= 0;
271 unsigned int peer_active_corner
= 0, peer_sleep_corner
= 0;
273 to_active_sleep(pd
, pd
->corner
, &this_active_corner
, &this_sleep_corner
);
275 if (peer
&& peer
->enabled
)
276 to_active_sleep(peer
, peer
->corner
, &peer_active_corner
,
279 active_corner
= max(this_active_corner
, peer_active_corner
);
281 ret
= rpmpd_send_corner(pd
, QCOM_SMD_RPM_ACTIVE_STATE
, active_corner
);
285 sleep_corner
= max(this_sleep_corner
, peer_sleep_corner
);
287 return rpmpd_send_corner(pd
, QCOM_SMD_RPM_SLEEP_STATE
, sleep_corner
);
290 static int rpmpd_power_on(struct generic_pm_domain
*domain
)
293 struct rpmpd
*pd
= domain_to_rpmpd(domain
);
295 mutex_lock(&rpmpd_lock
);
297 ret
= rpmpd_send_enable(pd
, true);
304 ret
= rpmpd_aggregate_corner(pd
);
307 mutex_unlock(&rpmpd_lock
);
312 static int rpmpd_power_off(struct generic_pm_domain
*domain
)
315 struct rpmpd
*pd
= domain_to_rpmpd(domain
);
317 mutex_lock(&rpmpd_lock
);
319 ret
= rpmpd_send_enable(pd
, false);
323 mutex_unlock(&rpmpd_lock
);
328 static int rpmpd_set_performance(struct generic_pm_domain
*domain
,
332 struct rpmpd
*pd
= domain_to_rpmpd(domain
);
334 if (state
> pd
->max_state
)
335 state
= pd
->max_state
;
337 mutex_lock(&rpmpd_lock
);
341 /* Always send updates for vfc and vfl */
342 if (!pd
->enabled
&& pd
->key
!= KEY_FLOOR_CORNER
&&
343 pd
->key
!= KEY_FLOOR_LEVEL
)
346 ret
= rpmpd_aggregate_corner(pd
);
349 mutex_unlock(&rpmpd_lock
);
354 static unsigned int rpmpd_get_performance(struct generic_pm_domain
*genpd
,
355 struct dev_pm_opp
*opp
)
357 return dev_pm_opp_get_level(opp
);
360 static int rpmpd_probe(struct platform_device
*pdev
)
364 struct genpd_onecell_data
*data
;
365 struct qcom_smd_rpm
*rpm
;
366 struct rpmpd
**rpmpds
;
367 const struct rpmpd_desc
*desc
;
369 rpm
= dev_get_drvdata(pdev
->dev
.parent
);
371 dev_err(&pdev
->dev
, "Unable to retrieve handle to RPM\n");
375 desc
= of_device_get_match_data(&pdev
->dev
);
379 rpmpds
= desc
->rpmpds
;
382 data
= devm_kzalloc(&pdev
->dev
, sizeof(*data
), GFP_KERNEL
);
386 data
->domains
= devm_kcalloc(&pdev
->dev
, num
, sizeof(*data
->domains
),
388 data
->num_domains
= num
;
390 for (i
= 0; i
< num
; i
++) {
392 dev_warn(&pdev
->dev
, "rpmpds[] with empty entry at index=%d\n",
397 rpmpds
[i
]->rpm
= rpm
;
398 rpmpds
[i
]->max_state
= desc
->max_state
;
399 rpmpds
[i
]->pd
.power_off
= rpmpd_power_off
;
400 rpmpds
[i
]->pd
.power_on
= rpmpd_power_on
;
401 rpmpds
[i
]->pd
.set_performance_state
= rpmpd_set_performance
;
402 rpmpds
[i
]->pd
.opp_to_performance_state
= rpmpd_get_performance
;
403 pm_genpd_init(&rpmpds
[i
]->pd
, NULL
, true);
405 data
->domains
[i
] = &rpmpds
[i
]->pd
;
408 return of_genpd_add_provider_onecell(pdev
->dev
.of_node
, data
);
411 static struct platform_driver rpmpd_driver
= {
413 .name
= "qcom-rpmpd",
414 .of_match_table
= rpmpd_match_table
,
415 .suppress_bind_attrs
= true,
417 .probe
= rpmpd_probe
,
420 static int __init
rpmpd_init(void)
422 return platform_driver_register(&rpmpd_driver
);
424 core_initcall(rpmpd_init
);