Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.2-rc7 315 lines 7.5 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. */ 3 4#include <linux/err.h> 5#include <linux/init.h> 6#include <linux/kernel.h> 7#include <linux/mutex.h> 8#include <linux/pm_domain.h> 9#include <linux/of.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> 14 15#include <dt-bindings/power/qcom-rpmpd.h> 16 17#define domain_to_rpmpd(domain) container_of(domain, struct rpmpd, pd) 18 19/* Resource types */ 20#define RPMPD_SMPA 0x61706d73 21#define RPMPD_LDOA 0x616f646c 22 23/* Operation Keys */ 24#define KEY_CORNER 0x6e726f63 /* corn */ 25#define KEY_ENABLE 0x6e657773 /* swen */ 26#define KEY_FLOOR_CORNER 0x636676 /* vfc */ 27 28#define MAX_RPMPD_STATE 6 29 30#define DEFINE_RPMPD_CORNER_SMPA(_platform, _name, _active, r_id) \ 31 static struct rpmpd _platform##_##_active; \ 32 static struct rpmpd _platform##_##_name = { \ 33 .pd = { .name = #_name, }, \ 34 .peer = &_platform##_##_active, \ 35 .res_type = RPMPD_SMPA, \ 36 .res_id = r_id, \ 37 .key = KEY_CORNER, \ 38 }; \ 39 static struct rpmpd _platform##_##_active = { \ 40 .pd = { .name = #_active, }, \ 41 .peer = &_platform##_##_name, \ 42 .active_only = true, \ 43 .res_type = RPMPD_SMPA, \ 44 .res_id = r_id, \ 45 .key = KEY_CORNER, \ 46 } 47 48#define DEFINE_RPMPD_CORNER_LDOA(_platform, _name, r_id) \ 49 static struct rpmpd _platform##_##_name = { \ 50 .pd = { .name = #_name, }, \ 51 .res_type = RPMPD_LDOA, \ 52 .res_id = r_id, \ 53 .key = KEY_CORNER, \ 54 } 55 56#define DEFINE_RPMPD_VFC(_platform, _name, r_id, r_type) \ 57 static struct rpmpd _platform##_##_name = { \ 58 .pd = { .name = #_name, }, \ 59 .res_type = r_type, \ 60 .res_id = r_id, \ 61 .key = KEY_FLOOR_CORNER, \ 62 } 63 64#define DEFINE_RPMPD_VFC_SMPA(_platform, _name, r_id) \ 65 DEFINE_RPMPD_VFC(_platform, _name, r_id, RPMPD_SMPA) 66 67#define DEFINE_RPMPD_VFC_LDOA(_platform, _name, r_id) \ 68 DEFINE_RPMPD_VFC(_platform, _name, r_id, RPMPD_LDOA) 69 70struct rpmpd_req { 71 __le32 key; 72 __le32 nbytes; 73 __le32 value; 74}; 75 76struct rpmpd { 77 struct generic_pm_domain pd; 78 struct rpmpd *peer; 79 const bool active_only; 80 unsigned int corner; 81 bool enabled; 82 const char *res_name; 83 const int res_type; 84 const int res_id; 85 struct qcom_smd_rpm *rpm; 86 __le32 key; 87}; 88 89struct rpmpd_desc { 90 struct rpmpd **rpmpds; 91 size_t num_pds; 92}; 93 94static DEFINE_MUTEX(rpmpd_lock); 95 96/* msm8996 RPM Power domains */ 97DEFINE_RPMPD_CORNER_SMPA(msm8996, vddcx, vddcx_ao, 1); 98DEFINE_RPMPD_CORNER_SMPA(msm8996, vddmx, vddmx_ao, 2); 99DEFINE_RPMPD_CORNER_LDOA(msm8996, vddsscx, 26); 100 101DEFINE_RPMPD_VFC_SMPA(msm8996, vddcx_vfc, 1); 102DEFINE_RPMPD_VFC_LDOA(msm8996, vddsscx_vfc, 26); 103 104static struct rpmpd *msm8996_rpmpds[] = { 105 [MSM8996_VDDCX] = &msm8996_vddcx, 106 [MSM8996_VDDCX_AO] = &msm8996_vddcx_ao, 107 [MSM8996_VDDCX_VFC] = &msm8996_vddcx_vfc, 108 [MSM8996_VDDMX] = &msm8996_vddmx, 109 [MSM8996_VDDMX_AO] = &msm8996_vddmx_ao, 110 [MSM8996_VDDSSCX] = &msm8996_vddsscx, 111 [MSM8996_VDDSSCX_VFC] = &msm8996_vddsscx_vfc, 112}; 113 114static const struct rpmpd_desc msm8996_desc = { 115 .rpmpds = msm8996_rpmpds, 116 .num_pds = ARRAY_SIZE(msm8996_rpmpds), 117}; 118 119static const struct of_device_id rpmpd_match_table[] = { 120 { .compatible = "qcom,msm8996-rpmpd", .data = &msm8996_desc }, 121 { } 122}; 123 124static int rpmpd_send_enable(struct rpmpd *pd, bool enable) 125{ 126 struct rpmpd_req req = { 127 .key = KEY_ENABLE, 128 .nbytes = cpu_to_le32(sizeof(u32)), 129 .value = cpu_to_le32(enable), 130 }; 131 132 return qcom_rpm_smd_write(pd->rpm, QCOM_SMD_RPM_ACTIVE_STATE, 133 pd->res_type, pd->res_id, &req, sizeof(req)); 134} 135 136static int rpmpd_send_corner(struct rpmpd *pd, int state, unsigned int corner) 137{ 138 struct rpmpd_req req = { 139 .key = pd->key, 140 .nbytes = cpu_to_le32(sizeof(u32)), 141 .value = cpu_to_le32(corner), 142 }; 143 144 return qcom_rpm_smd_write(pd->rpm, state, pd->res_type, pd->res_id, 145 &req, sizeof(req)); 146}; 147 148static void to_active_sleep(struct rpmpd *pd, unsigned int corner, 149 unsigned int *active, unsigned int *sleep) 150{ 151 *active = corner; 152 153 if (pd->active_only) 154 *sleep = 0; 155 else 156 *sleep = *active; 157} 158 159static int rpmpd_aggregate_corner(struct rpmpd *pd) 160{ 161 int ret; 162 struct rpmpd *peer = pd->peer; 163 unsigned int active_corner, sleep_corner; 164 unsigned int this_active_corner = 0, this_sleep_corner = 0; 165 unsigned int peer_active_corner = 0, peer_sleep_corner = 0; 166 167 to_active_sleep(pd, pd->corner, &this_active_corner, &this_sleep_corner); 168 169 if (peer && peer->enabled) 170 to_active_sleep(peer, peer->corner, &peer_active_corner, 171 &peer_sleep_corner); 172 173 active_corner = max(this_active_corner, peer_active_corner); 174 175 ret = rpmpd_send_corner(pd, QCOM_SMD_RPM_ACTIVE_STATE, active_corner); 176 if (ret) 177 return ret; 178 179 sleep_corner = max(this_sleep_corner, peer_sleep_corner); 180 181 return rpmpd_send_corner(pd, QCOM_SMD_RPM_SLEEP_STATE, sleep_corner); 182} 183 184static int rpmpd_power_on(struct generic_pm_domain *domain) 185{ 186 int ret; 187 struct rpmpd *pd = domain_to_rpmpd(domain); 188 189 mutex_lock(&rpmpd_lock); 190 191 ret = rpmpd_send_enable(pd, true); 192 if (ret) 193 goto out; 194 195 pd->enabled = true; 196 197 if (pd->corner) 198 ret = rpmpd_aggregate_corner(pd); 199 200out: 201 mutex_unlock(&rpmpd_lock); 202 203 return ret; 204} 205 206static int rpmpd_power_off(struct generic_pm_domain *domain) 207{ 208 int ret; 209 struct rpmpd *pd = domain_to_rpmpd(domain); 210 211 mutex_lock(&rpmpd_lock); 212 213 ret = rpmpd_send_enable(pd, false); 214 if (!ret) 215 pd->enabled = false; 216 217 mutex_unlock(&rpmpd_lock); 218 219 return ret; 220} 221 222static int rpmpd_set_performance(struct generic_pm_domain *domain, 223 unsigned int state) 224{ 225 int ret = 0; 226 struct rpmpd *pd = domain_to_rpmpd(domain); 227 228 if (state > MAX_RPMPD_STATE) 229 goto out; 230 231 mutex_lock(&rpmpd_lock); 232 233 pd->corner = state; 234 235 if (!pd->enabled && pd->key != KEY_FLOOR_CORNER) 236 goto out; 237 238 ret = rpmpd_aggregate_corner(pd); 239 240out: 241 mutex_unlock(&rpmpd_lock); 242 243 return ret; 244} 245 246static unsigned int rpmpd_get_performance(struct generic_pm_domain *genpd, 247 struct dev_pm_opp *opp) 248{ 249 return dev_pm_opp_get_level(opp); 250} 251 252static int rpmpd_probe(struct platform_device *pdev) 253{ 254 int i; 255 size_t num; 256 struct genpd_onecell_data *data; 257 struct qcom_smd_rpm *rpm; 258 struct rpmpd **rpmpds; 259 const struct rpmpd_desc *desc; 260 261 rpm = dev_get_drvdata(pdev->dev.parent); 262 if (!rpm) { 263 dev_err(&pdev->dev, "Unable to retrieve handle to RPM\n"); 264 return -ENODEV; 265 } 266 267 desc = of_device_get_match_data(&pdev->dev); 268 if (!desc) 269 return -EINVAL; 270 271 rpmpds = desc->rpmpds; 272 num = desc->num_pds; 273 274 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 275 if (!data) 276 return -ENOMEM; 277 278 data->domains = devm_kcalloc(&pdev->dev, num, sizeof(*data->domains), 279 GFP_KERNEL); 280 data->num_domains = num; 281 282 for (i = 0; i < num; i++) { 283 if (!rpmpds[i]) { 284 dev_warn(&pdev->dev, "rpmpds[] with empty entry at index=%d\n", 285 i); 286 continue; 287 } 288 289 rpmpds[i]->rpm = rpm; 290 rpmpds[i]->pd.power_off = rpmpd_power_off; 291 rpmpds[i]->pd.power_on = rpmpd_power_on; 292 rpmpds[i]->pd.set_performance_state = rpmpd_set_performance; 293 rpmpds[i]->pd.opp_to_performance_state = rpmpd_get_performance; 294 pm_genpd_init(&rpmpds[i]->pd, NULL, true); 295 296 data->domains[i] = &rpmpds[i]->pd; 297 } 298 299 return of_genpd_add_provider_onecell(pdev->dev.of_node, data); 300} 301 302static struct platform_driver rpmpd_driver = { 303 .driver = { 304 .name = "qcom-rpmpd", 305 .of_match_table = rpmpd_match_table, 306 .suppress_bind_attrs = true, 307 }, 308 .probe = rpmpd_probe, 309}; 310 311static int __init rpmpd_init(void) 312{ 313 return platform_driver_register(&rpmpd_driver); 314} 315core_initcall(rpmpd_init);