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/module.h> 8#include <linux/mutex.h> 9#include <linux/pm_domain.h> 10#include <linux/of.h> 11#include <linux/of_device.h> 12#include <linux/platform_device.h> 13#include <linux/pm_opp.h> 14#include <linux/soc/qcom/smd-rpm.h> 15 16#include <dt-bindings/power/qcom-rpmpd.h> 17 18#define domain_to_rpmpd(domain) container_of(domain, struct rpmpd, pd) 19 20/* Resource types: 21 * RPMPD_X is X encoded as a little-endian, lower-case, ASCII string */ 22#define RPMPD_SMPA 0x61706d73 23#define RPMPD_LDOA 0x616f646c 24#define RPMPD_RWCX 0x78637772 25#define RPMPD_RWMX 0x786d7772 26#define RPMPD_RWLC 0x636c7772 27#define RPMPD_RWLM 0x6d6c7772 28#define RPMPD_RWSC 0x63737772 29#define RPMPD_RWSM 0x6d737772 30 31/* Operation Keys */ 32#define KEY_CORNER 0x6e726f63 /* corn */ 33#define KEY_ENABLE 0x6e657773 /* swen */ 34#define KEY_FLOOR_CORNER 0x636676 /* vfc */ 35#define KEY_FLOOR_LEVEL 0x6c6676 /* vfl */ 36#define KEY_LEVEL 0x6c766c76 /* vlvl */ 37 38#define MAX_8996_RPMPD_STATE 6 39 40#define DEFINE_RPMPD_PAIR(_platform, _name, _active, r_type, r_key, \ 41 r_id) \ 42 static struct rpmpd _platform##_##_active; \ 43 static struct rpmpd _platform##_##_name = { \ 44 .pd = { .name = #_name, }, \ 45 .peer = &_platform##_##_active, \ 46 .res_type = RPMPD_##r_type, \ 47 .res_id = r_id, \ 48 .key = KEY_##r_key, \ 49 }; \ 50 static struct rpmpd _platform##_##_active = { \ 51 .pd = { .name = #_active, }, \ 52 .peer = &_platform##_##_name, \ 53 .active_only = true, \ 54 .res_type = RPMPD_##r_type, \ 55 .res_id = r_id, \ 56 .key = KEY_##r_key, \ 57 } 58 59#define DEFINE_RPMPD_CORNER(_platform, _name, r_type, r_id) \ 60 static struct rpmpd _platform##_##_name = { \ 61 .pd = { .name = #_name, }, \ 62 .res_type = RPMPD_##r_type, \ 63 .res_id = r_id, \ 64 .key = KEY_CORNER, \ 65 } 66 67#define DEFINE_RPMPD_LEVEL(_platform, _name, r_type, r_id) \ 68 static struct rpmpd _platform##_##_name = { \ 69 .pd = { .name = #_name, }, \ 70 .res_type = RPMPD_##r_type, \ 71 .res_id = r_id, \ 72 .key = KEY_LEVEL, \ 73 } 74 75#define DEFINE_RPMPD_VFC(_platform, _name, r_type, r_id) \ 76 static struct rpmpd _platform##_##_name = { \ 77 .pd = { .name = #_name, }, \ 78 .res_type = RPMPD_##r_type, \ 79 .res_id = r_id, \ 80 .key = KEY_FLOOR_CORNER, \ 81 } 82 83#define DEFINE_RPMPD_VFL(_platform, _name, r_type, r_id) \ 84 static struct rpmpd _platform##_##_name = { \ 85 .pd = { .name = #_name, }, \ 86 .res_type = RPMPD_##r_type, \ 87 .res_id = r_id, \ 88 .key = KEY_FLOOR_LEVEL, \ 89 } 90 91struct rpmpd_req { 92 __le32 key; 93 __le32 nbytes; 94 __le32 value; 95}; 96 97struct rpmpd { 98 struct generic_pm_domain pd; 99 struct rpmpd *peer; 100 const bool active_only; 101 unsigned int corner; 102 bool enabled; 103 const char *res_name; 104 const int res_type; 105 const int res_id; 106 struct qcom_smd_rpm *rpm; 107 unsigned int max_state; 108 __le32 key; 109}; 110 111struct rpmpd_desc { 112 struct rpmpd **rpmpds; 113 size_t num_pds; 114 unsigned int max_state; 115}; 116 117static DEFINE_MUTEX(rpmpd_lock); 118 119/* msm8976 RPM Power Domains */ 120DEFINE_RPMPD_PAIR(msm8976, vddcx, vddcx_ao, SMPA, LEVEL, 2); 121DEFINE_RPMPD_PAIR(msm8976, vddmx, vddmx_ao, SMPA, LEVEL, 6); 122 123DEFINE_RPMPD_VFL(msm8976, vddcx_vfl, RWSC, 2); 124DEFINE_RPMPD_VFL(msm8976, vddmx_vfl, RWSM, 6); 125 126static struct rpmpd *msm8976_rpmpds[] = { 127 [MSM8976_VDDCX] = &msm8976_vddcx, 128 [MSM8976_VDDCX_AO] = &msm8976_vddcx_ao, 129 [MSM8976_VDDCX_VFL] = &msm8976_vddcx_vfl, 130 [MSM8976_VDDMX] = &msm8976_vddmx, 131 [MSM8976_VDDMX_AO] = &msm8976_vddmx_ao, 132 [MSM8976_VDDMX_VFL] = &msm8976_vddmx_vfl, 133}; 134 135static const struct rpmpd_desc msm8976_desc = { 136 .rpmpds = msm8976_rpmpds, 137 .num_pds = ARRAY_SIZE(msm8976_rpmpds), 138 .max_state = RPM_SMD_LEVEL_TURBO_HIGH, 139}; 140 141/* msm8996 RPM Power domains */ 142DEFINE_RPMPD_PAIR(msm8996, vddcx, vddcx_ao, SMPA, CORNER, 1); 143DEFINE_RPMPD_PAIR(msm8996, vddmx, vddmx_ao, SMPA, CORNER, 2); 144DEFINE_RPMPD_CORNER(msm8996, vddsscx, LDOA, 26); 145 146DEFINE_RPMPD_VFC(msm8996, vddcx_vfc, SMPA, 1); 147DEFINE_RPMPD_VFC(msm8996, vddsscx_vfc, LDOA, 26); 148 149static struct rpmpd *msm8996_rpmpds[] = { 150 [MSM8996_VDDCX] = &msm8996_vddcx, 151 [MSM8996_VDDCX_AO] = &msm8996_vddcx_ao, 152 [MSM8996_VDDCX_VFC] = &msm8996_vddcx_vfc, 153 [MSM8996_VDDMX] = &msm8996_vddmx, 154 [MSM8996_VDDMX_AO] = &msm8996_vddmx_ao, 155 [MSM8996_VDDSSCX] = &msm8996_vddsscx, 156 [MSM8996_VDDSSCX_VFC] = &msm8996_vddsscx_vfc, 157}; 158 159static const struct rpmpd_desc msm8996_desc = { 160 .rpmpds = msm8996_rpmpds, 161 .num_pds = ARRAY_SIZE(msm8996_rpmpds), 162 .max_state = MAX_8996_RPMPD_STATE, 163}; 164 165/* msm8998 RPM Power domains */ 166DEFINE_RPMPD_PAIR(msm8998, vddcx, vddcx_ao, RWCX, LEVEL, 0); 167DEFINE_RPMPD_VFL(msm8998, vddcx_vfl, RWCX, 0); 168 169DEFINE_RPMPD_PAIR(msm8998, vddmx, vddmx_ao, RWMX, LEVEL, 0); 170DEFINE_RPMPD_VFL(msm8998, vddmx_vfl, RWMX, 0); 171 172DEFINE_RPMPD_LEVEL(msm8998, vdd_ssccx, RWSC, 0); 173DEFINE_RPMPD_VFL(msm8998, vdd_ssccx_vfl, RWSC, 0); 174 175DEFINE_RPMPD_LEVEL(msm8998, vdd_sscmx, RWSM, 0); 176DEFINE_RPMPD_VFL(msm8998, vdd_sscmx_vfl, RWSM, 0); 177 178static struct rpmpd *msm8998_rpmpds[] = { 179 [MSM8998_VDDCX] = &msm8998_vddcx, 180 [MSM8998_VDDCX_AO] = &msm8998_vddcx_ao, 181 [MSM8998_VDDCX_VFL] = &msm8998_vddcx_vfl, 182 [MSM8998_VDDMX] = &msm8998_vddmx, 183 [MSM8998_VDDMX_AO] = &msm8998_vddmx_ao, 184 [MSM8998_VDDMX_VFL] = &msm8998_vddmx_vfl, 185 [MSM8998_SSCCX] = &msm8998_vdd_ssccx, 186 [MSM8998_SSCCX_VFL] = &msm8998_vdd_ssccx_vfl, 187 [MSM8998_SSCMX] = &msm8998_vdd_sscmx, 188 [MSM8998_SSCMX_VFL] = &msm8998_vdd_sscmx_vfl, 189}; 190 191static const struct rpmpd_desc msm8998_desc = { 192 .rpmpds = msm8998_rpmpds, 193 .num_pds = ARRAY_SIZE(msm8998_rpmpds), 194 .max_state = RPM_SMD_LEVEL_BINNING, 195}; 196 197/* qcs404 RPM Power domains */ 198DEFINE_RPMPD_PAIR(qcs404, vddmx, vddmx_ao, RWMX, LEVEL, 0); 199DEFINE_RPMPD_VFL(qcs404, vddmx_vfl, RWMX, 0); 200 201DEFINE_RPMPD_LEVEL(qcs404, vdd_lpicx, RWLC, 0); 202DEFINE_RPMPD_VFL(qcs404, vdd_lpicx_vfl, RWLC, 0); 203 204DEFINE_RPMPD_LEVEL(qcs404, vdd_lpimx, RWLM, 0); 205DEFINE_RPMPD_VFL(qcs404, vdd_lpimx_vfl, RWLM, 0); 206 207static struct rpmpd *qcs404_rpmpds[] = { 208 [QCS404_VDDMX] = &qcs404_vddmx, 209 [QCS404_VDDMX_AO] = &qcs404_vddmx_ao, 210 [QCS404_VDDMX_VFL] = &qcs404_vddmx_vfl, 211 [QCS404_LPICX] = &qcs404_vdd_lpicx, 212 [QCS404_LPICX_VFL] = &qcs404_vdd_lpicx_vfl, 213 [QCS404_LPIMX] = &qcs404_vdd_lpimx, 214 [QCS404_LPIMX_VFL] = &qcs404_vdd_lpimx_vfl, 215}; 216 217static const struct rpmpd_desc qcs404_desc = { 218 .rpmpds = qcs404_rpmpds, 219 .num_pds = ARRAY_SIZE(qcs404_rpmpds), 220 .max_state = RPM_SMD_LEVEL_BINNING, 221}; 222 223static const struct of_device_id rpmpd_match_table[] = { 224 { .compatible = "qcom,msm8976-rpmpd", .data = &msm8976_desc }, 225 { .compatible = "qcom,msm8996-rpmpd", .data = &msm8996_desc }, 226 { .compatible = "qcom,msm8998-rpmpd", .data = &msm8998_desc }, 227 { .compatible = "qcom,qcs404-rpmpd", .data = &qcs404_desc }, 228 { } 229}; 230MODULE_DEVICE_TABLE(of, rpmpd_match_table); 231 232static int rpmpd_send_enable(struct rpmpd *pd, bool enable) 233{ 234 struct rpmpd_req req = { 235 .key = KEY_ENABLE, 236 .nbytes = cpu_to_le32(sizeof(u32)), 237 .value = cpu_to_le32(enable), 238 }; 239 240 return qcom_rpm_smd_write(pd->rpm, QCOM_SMD_RPM_ACTIVE_STATE, 241 pd->res_type, pd->res_id, &req, sizeof(req)); 242} 243 244static int rpmpd_send_corner(struct rpmpd *pd, int state, unsigned int corner) 245{ 246 struct rpmpd_req req = { 247 .key = pd->key, 248 .nbytes = cpu_to_le32(sizeof(u32)), 249 .value = cpu_to_le32(corner), 250 }; 251 252 return qcom_rpm_smd_write(pd->rpm, state, pd->res_type, pd->res_id, 253 &req, sizeof(req)); 254}; 255 256static void to_active_sleep(struct rpmpd *pd, unsigned int corner, 257 unsigned int *active, unsigned int *sleep) 258{ 259 *active = corner; 260 261 if (pd->active_only) 262 *sleep = 0; 263 else 264 *sleep = *active; 265} 266 267static int rpmpd_aggregate_corner(struct rpmpd *pd) 268{ 269 int ret; 270 struct rpmpd *peer = pd->peer; 271 unsigned int active_corner, sleep_corner; 272 unsigned int this_active_corner = 0, this_sleep_corner = 0; 273 unsigned int peer_active_corner = 0, peer_sleep_corner = 0; 274 275 to_active_sleep(pd, pd->corner, &this_active_corner, &this_sleep_corner); 276 277 if (peer && peer->enabled) 278 to_active_sleep(peer, peer->corner, &peer_active_corner, 279 &peer_sleep_corner); 280 281 active_corner = max(this_active_corner, peer_active_corner); 282 283 ret = rpmpd_send_corner(pd, QCOM_SMD_RPM_ACTIVE_STATE, active_corner); 284 if (ret) 285 return ret; 286 287 sleep_corner = max(this_sleep_corner, peer_sleep_corner); 288 289 return rpmpd_send_corner(pd, QCOM_SMD_RPM_SLEEP_STATE, sleep_corner); 290} 291 292static int rpmpd_power_on(struct generic_pm_domain *domain) 293{ 294 int ret; 295 struct rpmpd *pd = domain_to_rpmpd(domain); 296 297 mutex_lock(&rpmpd_lock); 298 299 ret = rpmpd_send_enable(pd, true); 300 if (ret) 301 goto out; 302 303 pd->enabled = true; 304 305 if (pd->corner) 306 ret = rpmpd_aggregate_corner(pd); 307 308out: 309 mutex_unlock(&rpmpd_lock); 310 311 return ret; 312} 313 314static int rpmpd_power_off(struct generic_pm_domain *domain) 315{ 316 int ret; 317 struct rpmpd *pd = domain_to_rpmpd(domain); 318 319 mutex_lock(&rpmpd_lock); 320 321 ret = rpmpd_send_enable(pd, false); 322 if (!ret) 323 pd->enabled = false; 324 325 mutex_unlock(&rpmpd_lock); 326 327 return ret; 328} 329 330static int rpmpd_set_performance(struct generic_pm_domain *domain, 331 unsigned int state) 332{ 333 int ret = 0; 334 struct rpmpd *pd = domain_to_rpmpd(domain); 335 336 if (state > pd->max_state) 337 state = pd->max_state; 338 339 mutex_lock(&rpmpd_lock); 340 341 pd->corner = state; 342 343 /* Always send updates for vfc and vfl */ 344 if (!pd->enabled && pd->key != KEY_FLOOR_CORNER && 345 pd->key != KEY_FLOOR_LEVEL) 346 goto out; 347 348 ret = rpmpd_aggregate_corner(pd); 349 350out: 351 mutex_unlock(&rpmpd_lock); 352 353 return ret; 354} 355 356static unsigned int rpmpd_get_performance(struct generic_pm_domain *genpd, 357 struct dev_pm_opp *opp) 358{ 359 return dev_pm_opp_get_level(opp); 360} 361 362static int rpmpd_probe(struct platform_device *pdev) 363{ 364 int i; 365 size_t num; 366 struct genpd_onecell_data *data; 367 struct qcom_smd_rpm *rpm; 368 struct rpmpd **rpmpds; 369 const struct rpmpd_desc *desc; 370 371 rpm = dev_get_drvdata(pdev->dev.parent); 372 if (!rpm) { 373 dev_err(&pdev->dev, "Unable to retrieve handle to RPM\n"); 374 return -ENODEV; 375 } 376 377 desc = of_device_get_match_data(&pdev->dev); 378 if (!desc) 379 return -EINVAL; 380 381 rpmpds = desc->rpmpds; 382 num = desc->num_pds; 383 384 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 385 if (!data) 386 return -ENOMEM; 387 388 data->domains = devm_kcalloc(&pdev->dev, num, sizeof(*data->domains), 389 GFP_KERNEL); 390 if (!data->domains) 391 return -ENOMEM; 392 393 data->num_domains = num; 394 395 for (i = 0; i < num; i++) { 396 if (!rpmpds[i]) { 397 dev_warn(&pdev->dev, "rpmpds[] with empty entry at index=%d\n", 398 i); 399 continue; 400 } 401 402 rpmpds[i]->rpm = rpm; 403 rpmpds[i]->max_state = desc->max_state; 404 rpmpds[i]->pd.power_off = rpmpd_power_off; 405 rpmpds[i]->pd.power_on = rpmpd_power_on; 406 rpmpds[i]->pd.set_performance_state = rpmpd_set_performance; 407 rpmpds[i]->pd.opp_to_performance_state = rpmpd_get_performance; 408 pm_genpd_init(&rpmpds[i]->pd, NULL, true); 409 410 data->domains[i] = &rpmpds[i]->pd; 411 } 412 413 return of_genpd_add_provider_onecell(pdev->dev.of_node, data); 414} 415 416static struct platform_driver rpmpd_driver = { 417 .driver = { 418 .name = "qcom-rpmpd", 419 .of_match_table = rpmpd_match_table, 420 .suppress_bind_attrs = true, 421 }, 422 .probe = rpmpd_probe, 423}; 424 425static int __init rpmpd_init(void) 426{ 427 return platform_driver_register(&rpmpd_driver); 428} 429core_initcall(rpmpd_init); 430 431MODULE_DESCRIPTION("Qualcomm Technologies, Inc. RPM Power Domain Driver"); 432MODULE_LICENSE("GPL v2"); 433