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.4-rc2 401 lines 10 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 * 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 29 30/* Operation Keys */ 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 */ 36 37#define MAX_8996_RPMPD_STATE 6 38 39#define DEFINE_RPMPD_PAIR(_platform, _name, _active, r_type, r_key, \ 40 r_id) \ 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, \ 46 .res_id = r_id, \ 47 .key = KEY_##r_key, \ 48 }; \ 49 static struct rpmpd _platform##_##_active = { \ 50 .pd = { .name = #_active, }, \ 51 .peer = &_platform##_##_name, \ 52 .active_only = true, \ 53 .res_type = RPMPD_##r_type, \ 54 .res_id = r_id, \ 55 .key = KEY_##r_key, \ 56 } 57 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, \ 62 .res_id = r_id, \ 63 .key = KEY_CORNER, \ 64 } 65 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, \ 70 .res_id = r_id, \ 71 .key = KEY_LEVEL, \ 72 } 73 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, \ 78 .res_id = r_id, \ 79 .key = KEY_FLOOR_CORNER, \ 80 } 81 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, \ 86 .res_id = r_id, \ 87 .key = KEY_FLOOR_LEVEL, \ 88 } 89 90struct rpmpd_req { 91 __le32 key; 92 __le32 nbytes; 93 __le32 value; 94}; 95 96struct rpmpd { 97 struct generic_pm_domain pd; 98 struct rpmpd *peer; 99 const bool active_only; 100 unsigned int corner; 101 bool enabled; 102 const char *res_name; 103 const int res_type; 104 const int res_id; 105 struct qcom_smd_rpm *rpm; 106 unsigned int max_state; 107 __le32 key; 108}; 109 110struct rpmpd_desc { 111 struct rpmpd **rpmpds; 112 size_t num_pds; 113 unsigned int max_state; 114}; 115 116static DEFINE_MUTEX(rpmpd_lock); 117 118/* msm8996 RPM Power domains */ 119DEFINE_RPMPD_PAIR(msm8996, vddcx, vddcx_ao, SMPA, CORNER, 1); 120DEFINE_RPMPD_PAIR(msm8996, vddmx, vddmx_ao, SMPA, CORNER, 2); 121DEFINE_RPMPD_CORNER(msm8996, vddsscx, LDOA, 26); 122 123DEFINE_RPMPD_VFC(msm8996, vddcx_vfc, SMPA, 1); 124DEFINE_RPMPD_VFC(msm8996, vddsscx_vfc, LDOA, 26); 125 126static struct rpmpd *msm8996_rpmpds[] = { 127 [MSM8996_VDDCX] = &msm8996_vddcx, 128 [MSM8996_VDDCX_AO] = &msm8996_vddcx_ao, 129 [MSM8996_VDDCX_VFC] = &msm8996_vddcx_vfc, 130 [MSM8996_VDDMX] = &msm8996_vddmx, 131 [MSM8996_VDDMX_AO] = &msm8996_vddmx_ao, 132 [MSM8996_VDDSSCX] = &msm8996_vddsscx, 133 [MSM8996_VDDSSCX_VFC] = &msm8996_vddsscx_vfc, 134}; 135 136static const struct rpmpd_desc msm8996_desc = { 137 .rpmpds = msm8996_rpmpds, 138 .num_pds = ARRAY_SIZE(msm8996_rpmpds), 139 .max_state = MAX_8996_RPMPD_STATE, 140}; 141 142/* msm8998 RPM Power domains */ 143DEFINE_RPMPD_PAIR(msm8998, vddcx, vddcx_ao, RWCX, LEVEL, 0); 144DEFINE_RPMPD_VFL(msm8998, vddcx_vfl, RWCX, 0); 145 146DEFINE_RPMPD_PAIR(msm8998, vddmx, vddmx_ao, RWMX, LEVEL, 0); 147DEFINE_RPMPD_VFL(msm8998, vddmx_vfl, RWMX, 0); 148 149DEFINE_RPMPD_LEVEL(msm8998, vdd_ssccx, RWSC, 0); 150DEFINE_RPMPD_VFL(msm8998, vdd_ssccx_vfl, RWSC, 0); 151 152DEFINE_RPMPD_LEVEL(msm8998, vdd_sscmx, RWSM, 0); 153DEFINE_RPMPD_VFL(msm8998, vdd_sscmx_vfl, RWSM, 0); 154 155static struct rpmpd *msm8998_rpmpds[] = { 156 [MSM8998_VDDCX] = &msm8998_vddcx, 157 [MSM8998_VDDCX_AO] = &msm8998_vddcx_ao, 158 [MSM8998_VDDCX_VFL] = &msm8998_vddcx_vfl, 159 [MSM8998_VDDMX] = &msm8998_vddmx, 160 [MSM8998_VDDMX_AO] = &msm8998_vddmx_ao, 161 [MSM8998_VDDMX_VFL] = &msm8998_vddmx_vfl, 162 [MSM8998_SSCCX] = &msm8998_vdd_ssccx, 163 [MSM8998_SSCCX_VFL] = &msm8998_vdd_ssccx_vfl, 164 [MSM8998_SSCMX] = &msm8998_vdd_sscmx, 165 [MSM8998_SSCMX_VFL] = &msm8998_vdd_sscmx_vfl, 166}; 167 168static const struct rpmpd_desc msm8998_desc = { 169 .rpmpds = msm8998_rpmpds, 170 .num_pds = ARRAY_SIZE(msm8998_rpmpds), 171 .max_state = RPM_SMD_LEVEL_BINNING, 172}; 173 174/* qcs404 RPM Power domains */ 175DEFINE_RPMPD_PAIR(qcs404, vddmx, vddmx_ao, RWMX, LEVEL, 0); 176DEFINE_RPMPD_VFL(qcs404, vddmx_vfl, RWMX, 0); 177 178DEFINE_RPMPD_LEVEL(qcs404, vdd_lpicx, RWLC, 0); 179DEFINE_RPMPD_VFL(qcs404, vdd_lpicx_vfl, RWLC, 0); 180 181DEFINE_RPMPD_LEVEL(qcs404, vdd_lpimx, RWLM, 0); 182DEFINE_RPMPD_VFL(qcs404, vdd_lpimx_vfl, RWLM, 0); 183 184static struct rpmpd *qcs404_rpmpds[] = { 185 [QCS404_VDDMX] = &qcs404_vddmx, 186 [QCS404_VDDMX_AO] = &qcs404_vddmx_ao, 187 [QCS404_VDDMX_VFL] = &qcs404_vddmx_vfl, 188 [QCS404_LPICX] = &qcs404_vdd_lpicx, 189 [QCS404_LPICX_VFL] = &qcs404_vdd_lpicx_vfl, 190 [QCS404_LPIMX] = &qcs404_vdd_lpimx, 191 [QCS404_LPIMX_VFL] = &qcs404_vdd_lpimx_vfl, 192}; 193 194static const struct rpmpd_desc qcs404_desc = { 195 .rpmpds = qcs404_rpmpds, 196 .num_pds = ARRAY_SIZE(qcs404_rpmpds), 197 .max_state = RPM_SMD_LEVEL_BINNING, 198}; 199 200static const struct of_device_id rpmpd_match_table[] = { 201 { .compatible = "qcom,msm8996-rpmpd", .data = &msm8996_desc }, 202 { .compatible = "qcom,msm8998-rpmpd", .data = &msm8998_desc }, 203 { .compatible = "qcom,qcs404-rpmpd", .data = &qcs404_desc }, 204 { } 205}; 206 207static int rpmpd_send_enable(struct rpmpd *pd, bool enable) 208{ 209 struct rpmpd_req req = { 210 .key = KEY_ENABLE, 211 .nbytes = cpu_to_le32(sizeof(u32)), 212 .value = cpu_to_le32(enable), 213 }; 214 215 return qcom_rpm_smd_write(pd->rpm, QCOM_SMD_RPM_ACTIVE_STATE, 216 pd->res_type, pd->res_id, &req, sizeof(req)); 217} 218 219static int rpmpd_send_corner(struct rpmpd *pd, int state, unsigned int corner) 220{ 221 struct rpmpd_req req = { 222 .key = pd->key, 223 .nbytes = cpu_to_le32(sizeof(u32)), 224 .value = cpu_to_le32(corner), 225 }; 226 227 return qcom_rpm_smd_write(pd->rpm, state, pd->res_type, pd->res_id, 228 &req, sizeof(req)); 229}; 230 231static void to_active_sleep(struct rpmpd *pd, unsigned int corner, 232 unsigned int *active, unsigned int *sleep) 233{ 234 *active = corner; 235 236 if (pd->active_only) 237 *sleep = 0; 238 else 239 *sleep = *active; 240} 241 242static int rpmpd_aggregate_corner(struct rpmpd *pd) 243{ 244 int ret; 245 struct rpmpd *peer = pd->peer; 246 unsigned int active_corner, sleep_corner; 247 unsigned int this_active_corner = 0, this_sleep_corner = 0; 248 unsigned int peer_active_corner = 0, peer_sleep_corner = 0; 249 250 to_active_sleep(pd, pd->corner, &this_active_corner, &this_sleep_corner); 251 252 if (peer && peer->enabled) 253 to_active_sleep(peer, peer->corner, &peer_active_corner, 254 &peer_sleep_corner); 255 256 active_corner = max(this_active_corner, peer_active_corner); 257 258 ret = rpmpd_send_corner(pd, QCOM_SMD_RPM_ACTIVE_STATE, active_corner); 259 if (ret) 260 return ret; 261 262 sleep_corner = max(this_sleep_corner, peer_sleep_corner); 263 264 return rpmpd_send_corner(pd, QCOM_SMD_RPM_SLEEP_STATE, sleep_corner); 265} 266 267static int rpmpd_power_on(struct generic_pm_domain *domain) 268{ 269 int ret; 270 struct rpmpd *pd = domain_to_rpmpd(domain); 271 272 mutex_lock(&rpmpd_lock); 273 274 ret = rpmpd_send_enable(pd, true); 275 if (ret) 276 goto out; 277 278 pd->enabled = true; 279 280 if (pd->corner) 281 ret = rpmpd_aggregate_corner(pd); 282 283out: 284 mutex_unlock(&rpmpd_lock); 285 286 return ret; 287} 288 289static int rpmpd_power_off(struct generic_pm_domain *domain) 290{ 291 int ret; 292 struct rpmpd *pd = domain_to_rpmpd(domain); 293 294 mutex_lock(&rpmpd_lock); 295 296 ret = rpmpd_send_enable(pd, false); 297 if (!ret) 298 pd->enabled = false; 299 300 mutex_unlock(&rpmpd_lock); 301 302 return ret; 303} 304 305static int rpmpd_set_performance(struct generic_pm_domain *domain, 306 unsigned int state) 307{ 308 int ret = 0; 309 struct rpmpd *pd = domain_to_rpmpd(domain); 310 311 if (state > pd->max_state) 312 state = pd->max_state; 313 314 mutex_lock(&rpmpd_lock); 315 316 pd->corner = state; 317 318 /* Always send updates for vfc and vfl */ 319 if (!pd->enabled && pd->key != KEY_FLOOR_CORNER && 320 pd->key != KEY_FLOOR_LEVEL) 321 goto out; 322 323 ret = rpmpd_aggregate_corner(pd); 324 325out: 326 mutex_unlock(&rpmpd_lock); 327 328 return ret; 329} 330 331static unsigned int rpmpd_get_performance(struct generic_pm_domain *genpd, 332 struct dev_pm_opp *opp) 333{ 334 return dev_pm_opp_get_level(opp); 335} 336 337static int rpmpd_probe(struct platform_device *pdev) 338{ 339 int i; 340 size_t num; 341 struct genpd_onecell_data *data; 342 struct qcom_smd_rpm *rpm; 343 struct rpmpd **rpmpds; 344 const struct rpmpd_desc *desc; 345 346 rpm = dev_get_drvdata(pdev->dev.parent); 347 if (!rpm) { 348 dev_err(&pdev->dev, "Unable to retrieve handle to RPM\n"); 349 return -ENODEV; 350 } 351 352 desc = of_device_get_match_data(&pdev->dev); 353 if (!desc) 354 return -EINVAL; 355 356 rpmpds = desc->rpmpds; 357 num = desc->num_pds; 358 359 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 360 if (!data) 361 return -ENOMEM; 362 363 data->domains = devm_kcalloc(&pdev->dev, num, sizeof(*data->domains), 364 GFP_KERNEL); 365 data->num_domains = num; 366 367 for (i = 0; i < num; i++) { 368 if (!rpmpds[i]) { 369 dev_warn(&pdev->dev, "rpmpds[] with empty entry at index=%d\n", 370 i); 371 continue; 372 } 373 374 rpmpds[i]->rpm = rpm; 375 rpmpds[i]->max_state = desc->max_state; 376 rpmpds[i]->pd.power_off = rpmpd_power_off; 377 rpmpds[i]->pd.power_on = rpmpd_power_on; 378 rpmpds[i]->pd.set_performance_state = rpmpd_set_performance; 379 rpmpds[i]->pd.opp_to_performance_state = rpmpd_get_performance; 380 pm_genpd_init(&rpmpds[i]->pd, NULL, true); 381 382 data->domains[i] = &rpmpds[i]->pd; 383 } 384 385 return of_genpd_add_provider_onecell(pdev->dev.of_node, data); 386} 387 388static struct platform_driver rpmpd_driver = { 389 .driver = { 390 .name = "qcom-rpmpd", 391 .of_match_table = rpmpd_match_table, 392 .suppress_bind_attrs = true, 393 }, 394 .probe = rpmpd_probe, 395}; 396 397static int __init rpmpd_init(void) 398{ 399 return platform_driver_register(&rpmpd_driver); 400} 401core_initcall(rpmpd_init);