1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 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/slab.h> 11 #include <linux/of.h> 12 #include <linux/platform_device.h> 13 #include <linux/pm_opp.h> 14 #include <soc/qcom/cmd-db.h> 15 #include <soc/qcom/rpmh.h> 16 #include <dt-bindings/power/qcom-rpmpd.h> 17 #include <dt-bindings/power/qcom,rpmhpd.h> 18 19 #define domain_to_rpmhpd(domain) container_of(domain, struct rpmhpd, pd) 20 21 #define RPMH_ARC_MAX_LEVELS 16 22 23 /** 24 * struct rpmhpd - top level RPMh power domain resource data structure 25 * @dev: rpmh power domain controller device 26 * @pd: generic_pm_domain corresponding to the power domain 27 * @parent: generic_pm_domain corresponding to the parent's power domain 28 * @peer: A peer power domain in case Active only Voting is 29 * supported 30 * @active_only: True if it represents an Active only peer 31 * @corner: current corner 32 * @active_corner: current active corner 33 * @enable_corner: lowest non-zero corner 34 * @level: An array of level (vlvl) to corner (hlvl) mappings 35 * derived from cmd-db 36 * @level_count: Number of levels supported by the power domain. max 37 * being 16 (0 - 15) 38 * @enabled: true if the power domain is enabled 39 * @res_name: Resource name used for cmd-db lookup 40 * @addr: Resource address as looped up using resource name from 41 * cmd-db 42 * @state_synced: Indicator that sync_state has been invoked for the rpmhpd resource 43 * @skip_retention_level: Indicate that retention level should not be used for the power domain 44 */ 45 struct rpmhpd { 46 struct device *dev; 47 struct generic_pm_domain pd; 48 struct generic_pm_domain *parent; 49 struct rpmhpd *peer; 50 const bool active_only; 51 unsigned int corner; 52 unsigned int active_corner; 53 unsigned int enable_corner; 54 u32 level[RPMH_ARC_MAX_LEVELS]; 55 size_t level_count; 56 bool enabled; 57 const char *res_name; 58 u32 addr; 59 bool state_synced; 60 bool skip_retention_level; 61 }; 62 63 struct rpmhpd_desc { 64 struct rpmhpd **rpmhpds; 65 size_t num_pds; 66 }; 67 68 static DEFINE_MUTEX(rpmhpd_lock); 69 70 /* RPMH powerdomains */ 71 72 static struct rpmhpd cx_ao; 73 static struct rpmhpd mx; 74 static struct rpmhpd mx_ao; 75 static struct rpmhpd cx = { 76 .pd = { .name = "cx", }, 77 .peer = &cx_ao, 78 .res_name = "cx.lvl", 79 }; 80 81 static struct rpmhpd cx_ao = { 82 .pd = { .name = "cx_ao", }, 83 .active_only = true, 84 .peer = &cx, 85 .res_name = "cx.lvl", 86 }; 87 88 static struct rpmhpd cx_ao_w_mx_parent; 89 static struct rpmhpd cx_w_mx_parent = { 90 .pd = { .name = "cx", }, 91 .peer = &cx_ao_w_mx_parent, 92 .parent = &mx.pd, 93 .res_name = "cx.lvl", 94 }; 95 96 static struct rpmhpd cx_ao_w_mx_parent = { 97 .pd = { .name = "cx_ao", }, 98 .active_only = true, 99 .peer = &cx_w_mx_parent, 100 .parent = &mx_ao.pd, 101 .res_name = "cx.lvl", 102 }; 103 104 static struct rpmhpd ebi = { 105 .pd = { .name = "ebi", }, 106 .res_name = "ebi.lvl", 107 }; 108 109 static struct rpmhpd gfx = { 110 .pd = { .name = "gfx", }, 111 .res_name = "gfx.lvl", 112 }; 113 114 static struct rpmhpd lcx = { 115 .pd = { .name = "lcx", }, 116 .res_name = "lcx.lvl", 117 }; 118 119 static struct rpmhpd lmx = { 120 .pd = { .name = "lmx", }, 121 .res_name = "lmx.lvl", 122 }; 123 124 static struct rpmhpd mmcx_ao; 125 static struct rpmhpd mmcx = { 126 .pd = { .name = "mmcx", }, 127 .peer = &mmcx_ao, 128 .res_name = "mmcx.lvl", 129 }; 130 131 static struct rpmhpd mmcx_ao = { 132 .pd = { .name = "mmcx_ao", }, 133 .active_only = true, 134 .peer = &mmcx, 135 .res_name = "mmcx.lvl", 136 }; 137 138 static struct rpmhpd mmcx_ao_w_cx_parent; 139 static struct rpmhpd mmcx_w_cx_parent = { 140 .pd = { .name = "mmcx", }, 141 .peer = &mmcx_ao_w_cx_parent, 142 .parent = &cx.pd, 143 .res_name = "mmcx.lvl", 144 }; 145 146 static struct rpmhpd mmcx_ao_w_cx_parent = { 147 .pd = { .name = "mmcx_ao", }, 148 .active_only = true, 149 .peer = &mmcx_w_cx_parent, 150 .parent = &cx_ao.pd, 151 .res_name = "mmcx.lvl", 152 }; 153 154 static struct rpmhpd mss = { 155 .pd = { .name = "mss", }, 156 .res_name = "mss.lvl", 157 }; 158 159 static struct rpmhpd mx_ao; 160 static struct rpmhpd mx = { 161 .pd = { .name = "mx", }, 162 .peer = &mx_ao, 163 .res_name = "mx.lvl", 164 }; 165 166 static struct rpmhpd mx_ao = { 167 .pd = { .name = "mx_ao", }, 168 .active_only = true, 169 .peer = &mx, 170 .res_name = "mx.lvl", 171 }; 172 173 static struct rpmhpd mxc_ao; 174 static struct rpmhpd mxc = { 175 .pd = { .name = "mxc", }, 176 .peer = &mxc_ao, 177 .res_name = "mxc.lvl", 178 .skip_retention_level = true, 179 }; 180 181 static struct rpmhpd mxc_ao = { 182 .pd = { .name = "mxc_ao", }, 183 .active_only = true, 184 .peer = &mxc, 185 .res_name = "mxc.lvl", 186 .skip_retention_level = true, 187 }; 188 189 static struct rpmhpd nsp = { 190 .pd = { .name = "nsp", }, 191 .res_name = "nsp.lvl", 192 }; 193 194 static struct rpmhpd nsp0 = { 195 .pd = { .name = "nsp0", }, 196 .res_name = "nsp0.lvl", 197 }; 198 199 static struct rpmhpd nsp1 = { 200 .pd = { .name = "nsp1", }, 201 .res_name = "nsp1.lvl", 202 }; 203 204 static struct rpmhpd qphy = { 205 .pd = { .name = "qphy", }, 206 .res_name = "qphy.lvl", 207 }; 208 209 /* SA8540P RPMH powerdomains */ 210 static struct rpmhpd *sa8540p_rpmhpds[] = { 211 [SC8280XP_CX] = &cx, 212 [SC8280XP_CX_AO] = &cx_ao, 213 [SC8280XP_EBI] = &ebi, 214 [SC8280XP_LCX] = &lcx, 215 [SC8280XP_LMX] = &lmx, 216 [SC8280XP_MMCX] = &mmcx, 217 [SC8280XP_MMCX_AO] = &mmcx_ao, 218 [SC8280XP_MX] = &mx, 219 [SC8280XP_MX_AO] = &mx_ao, 220 [SC8280XP_NSP] = &nsp, 221 }; 222 223 static const struct rpmhpd_desc sa8540p_desc = { 224 .rpmhpds = sa8540p_rpmhpds, 225 .num_pds = ARRAY_SIZE(sa8540p_rpmhpds), 226 }; 227 228 /* SA8775P RPMH power domains */ 229 static struct rpmhpd *sa8775p_rpmhpds[] = { 230 [SA8775P_CX] = &cx, 231 [SA8775P_CX_AO] = &cx_ao, 232 [SA8775P_EBI] = &ebi, 233 [SA8775P_GFX] = &gfx, 234 [SA8775P_LCX] = &lcx, 235 [SA8775P_LMX] = &lmx, 236 [SA8775P_MMCX] = &mmcx, 237 [SA8775P_MMCX_AO] = &mmcx_ao, 238 [SA8775P_MXC] = &mxc, 239 [SA8775P_MXC_AO] = &mxc_ao, 240 [SA8775P_MX] = &mx, 241 [SA8775P_MX_AO] = &mx_ao, 242 [SA8775P_NSP0] = &nsp0, 243 [SA8775P_NSP1] = &nsp1, 244 }; 245 246 static const struct rpmhpd_desc sa8775p_desc = { 247 .rpmhpds = sa8775p_rpmhpds, 248 .num_pds = ARRAY_SIZE(sa8775p_rpmhpds), 249 }; 250 251 /* SDM670 RPMH powerdomains */ 252 static struct rpmhpd *sdm670_rpmhpds[] = { 253 [SDM670_CX] = &cx_w_mx_parent, 254 [SDM670_CX_AO] = &cx_ao_w_mx_parent, 255 [SDM670_GFX] = &gfx, 256 [SDM670_LCX] = &lcx, 257 [SDM670_LMX] = &lmx, 258 [SDM670_MSS] = &mss, 259 [SDM670_MX] = &mx, 260 [SDM670_MX_AO] = &mx_ao, 261 }; 262 263 static const struct rpmhpd_desc sdm670_desc = { 264 .rpmhpds = sdm670_rpmhpds, 265 .num_pds = ARRAY_SIZE(sdm670_rpmhpds), 266 }; 267 268 /* SDM845 RPMH powerdomains */ 269 static struct rpmhpd *sdm845_rpmhpds[] = { 270 [SDM845_CX] = &cx_w_mx_parent, 271 [SDM845_CX_AO] = &cx_ao_w_mx_parent, 272 [SDM845_EBI] = &ebi, 273 [SDM845_GFX] = &gfx, 274 [SDM845_LCX] = &lcx, 275 [SDM845_LMX] = &lmx, 276 [SDM845_MSS] = &mss, 277 [SDM845_MX] = &mx, 278 [SDM845_MX_AO] = &mx_ao, 279 }; 280 281 static const struct rpmhpd_desc sdm845_desc = { 282 .rpmhpds = sdm845_rpmhpds, 283 .num_pds = ARRAY_SIZE(sdm845_rpmhpds), 284 }; 285 286 /* SDX55 RPMH powerdomains */ 287 static struct rpmhpd *sdx55_rpmhpds[] = { 288 [SDX55_CX] = &cx_w_mx_parent, 289 [SDX55_MSS] = &mss, 290 [SDX55_MX] = &mx, 291 }; 292 293 static const struct rpmhpd_desc sdx55_desc = { 294 .rpmhpds = sdx55_rpmhpds, 295 .num_pds = ARRAY_SIZE(sdx55_rpmhpds), 296 }; 297 298 /* SDX65 RPMH powerdomains */ 299 static struct rpmhpd *sdx65_rpmhpds[] = { 300 [SDX65_CX] = &cx_w_mx_parent, 301 [SDX65_CX_AO] = &cx_ao_w_mx_parent, 302 [SDX65_MSS] = &mss, 303 [SDX65_MX] = &mx, 304 [SDX65_MX_AO] = &mx_ao, 305 [SDX65_MXC] = &mxc, 306 }; 307 308 static const struct rpmhpd_desc sdx65_desc = { 309 .rpmhpds = sdx65_rpmhpds, 310 .num_pds = ARRAY_SIZE(sdx65_rpmhpds), 311 }; 312 313 /* SDX75 RPMH powerdomains */ 314 static struct rpmhpd *sdx75_rpmhpds[] = { 315 [RPMHPD_CX] = &cx, 316 [RPMHPD_CX_AO] = &cx_ao, 317 [RPMHPD_MSS] = &mss, 318 [RPMHPD_MX] = &mx, 319 [RPMHPD_MX_AO] = &mx_ao, 320 [RPMHPD_MXC] = &mxc, 321 }; 322 323 static const struct rpmhpd_desc sdx75_desc = { 324 .rpmhpds = sdx75_rpmhpds, 325 .num_pds = ARRAY_SIZE(sdx75_rpmhpds), 326 }; 327 328 /* SM6350 RPMH powerdomains */ 329 static struct rpmhpd *sm6350_rpmhpds[] = { 330 [SM6350_CX] = &cx_w_mx_parent, 331 [SM6350_GFX] = &gfx, 332 [SM6350_LCX] = &lcx, 333 [SM6350_LMX] = &lmx, 334 [SM6350_MSS] = &mss, 335 [SM6350_MX] = &mx, 336 }; 337 338 static const struct rpmhpd_desc sm6350_desc = { 339 .rpmhpds = sm6350_rpmhpds, 340 .num_pds = ARRAY_SIZE(sm6350_rpmhpds), 341 }; 342 343 /* SM8150 RPMH powerdomains */ 344 static struct rpmhpd *sm8150_rpmhpds[] = { 345 [SM8150_CX] = &cx_w_mx_parent, 346 [SM8150_CX_AO] = &cx_ao_w_mx_parent, 347 [SM8150_EBI] = &ebi, 348 [SM8150_GFX] = &gfx, 349 [SM8150_LCX] = &lcx, 350 [SM8150_LMX] = &lmx, 351 [SM8150_MMCX] = &mmcx, 352 [SM8150_MMCX_AO] = &mmcx_ao, 353 [SM8150_MSS] = &mss, 354 [SM8150_MX] = &mx, 355 [SM8150_MX_AO] = &mx_ao, 356 }; 357 358 static const struct rpmhpd_desc sm8150_desc = { 359 .rpmhpds = sm8150_rpmhpds, 360 .num_pds = ARRAY_SIZE(sm8150_rpmhpds), 361 }; 362 363 static struct rpmhpd *sa8155p_rpmhpds[] = { 364 [SA8155P_CX] = &cx_w_mx_parent, 365 [SA8155P_CX_AO] = &cx_ao_w_mx_parent, 366 [SA8155P_EBI] = &ebi, 367 [SA8155P_GFX] = &gfx, 368 [SA8155P_MSS] = &mss, 369 [SA8155P_MX] = &mx, 370 [SA8155P_MX_AO] = &mx_ao, 371 }; 372 373 static const struct rpmhpd_desc sa8155p_desc = { 374 .rpmhpds = sa8155p_rpmhpds, 375 .num_pds = ARRAY_SIZE(sa8155p_rpmhpds), 376 }; 377 378 /* SM8250 RPMH powerdomains */ 379 static struct rpmhpd *sm8250_rpmhpds[] = { 380 [RPMHPD_CX] = &cx_w_mx_parent, 381 [RPMHPD_CX_AO] = &cx_ao_w_mx_parent, 382 [RPMHPD_EBI] = &ebi, 383 [RPMHPD_GFX] = &gfx, 384 [RPMHPD_LCX] = &lcx, 385 [RPMHPD_LMX] = &lmx, 386 [RPMHPD_MMCX] = &mmcx, 387 [RPMHPD_MMCX_AO] = &mmcx_ao, 388 [RPMHPD_MX] = &mx, 389 [RPMHPD_MX_AO] = &mx_ao, 390 }; 391 392 static const struct rpmhpd_desc sm8250_desc = { 393 .rpmhpds = sm8250_rpmhpds, 394 .num_pds = ARRAY_SIZE(sm8250_rpmhpds), 395 }; 396 397 /* SM8350 Power domains */ 398 static struct rpmhpd *sm8350_rpmhpds[] = { 399 [RPMHPD_CX] = &cx_w_mx_parent, 400 [RPMHPD_CX_AO] = &cx_ao_w_mx_parent, 401 [RPMHPD_EBI] = &ebi, 402 [RPMHPD_GFX] = &gfx, 403 [RPMHPD_LCX] = &lcx, 404 [RPMHPD_LMX] = &lmx, 405 [RPMHPD_MMCX] = &mmcx, 406 [RPMHPD_MMCX_AO] = &mmcx_ao, 407 [RPMHPD_MSS] = &mss, 408 [RPMHPD_MX] = &mx, 409 [RPMHPD_MX_AO] = &mx_ao, 410 [RPMHPD_MXC] = &mxc, 411 [RPMHPD_MXC_AO] = &mxc_ao, 412 }; 413 414 static const struct rpmhpd_desc sm8350_desc = { 415 .rpmhpds = sm8350_rpmhpds, 416 .num_pds = ARRAY_SIZE(sm8350_rpmhpds), 417 }; 418 419 /* SM8450 RPMH powerdomains */ 420 static struct rpmhpd *sm8450_rpmhpds[] = { 421 [RPMHPD_CX] = &cx, 422 [RPMHPD_CX_AO] = &cx_ao, 423 [RPMHPD_EBI] = &ebi, 424 [RPMHPD_GFX] = &gfx, 425 [RPMHPD_LCX] = &lcx, 426 [RPMHPD_LMX] = &lmx, 427 [RPMHPD_MMCX] = &mmcx_w_cx_parent, 428 [RPMHPD_MMCX_AO] = &mmcx_ao_w_cx_parent, 429 [RPMHPD_MSS] = &mss, 430 [RPMHPD_MX] = &mx, 431 [RPMHPD_MX_AO] = &mx_ao, 432 [RPMHPD_MXC] = &mxc, 433 [RPMHPD_MXC_AO] = &mxc_ao, 434 }; 435 436 static const struct rpmhpd_desc sm8450_desc = { 437 .rpmhpds = sm8450_rpmhpds, 438 .num_pds = ARRAY_SIZE(sm8450_rpmhpds), 439 }; 440 441 /* SM8550 RPMH powerdomains */ 442 static struct rpmhpd *sm8550_rpmhpds[] = { 443 [RPMHPD_CX] = &cx, 444 [RPMHPD_CX_AO] = &cx_ao, 445 [RPMHPD_EBI] = &ebi, 446 [RPMHPD_GFX] = &gfx, 447 [RPMHPD_LCX] = &lcx, 448 [RPMHPD_LMX] = &lmx, 449 [RPMHPD_MMCX] = &mmcx_w_cx_parent, 450 [RPMHPD_MMCX_AO] = &mmcx_ao_w_cx_parent, 451 [RPMHPD_MSS] = &mss, 452 [RPMHPD_MX] = &mx, 453 [RPMHPD_MX_AO] = &mx_ao, 454 [RPMHPD_MXC] = &mxc, 455 [RPMHPD_MXC_AO] = &mxc_ao, 456 [RPMHPD_NSP] = &nsp, 457 }; 458 459 static const struct rpmhpd_desc sm8550_desc = { 460 .rpmhpds = sm8550_rpmhpds, 461 .num_pds = ARRAY_SIZE(sm8550_rpmhpds), 462 }; 463 464 /* QDU1000/QRU1000 RPMH powerdomains */ 465 static struct rpmhpd *qdu1000_rpmhpds[] = { 466 [QDU1000_CX] = &cx, 467 [QDU1000_EBI] = &ebi, 468 [QDU1000_MSS] = &mss, 469 [QDU1000_MX] = &mx, 470 }; 471 472 static const struct rpmhpd_desc qdu1000_desc = { 473 .rpmhpds = qdu1000_rpmhpds, 474 .num_pds = ARRAY_SIZE(qdu1000_rpmhpds), 475 }; 476 477 /* SC7180 RPMH powerdomains */ 478 static struct rpmhpd *sc7180_rpmhpds[] = { 479 [SC7180_CX] = &cx_w_mx_parent, 480 [SC7180_CX_AO] = &cx_ao_w_mx_parent, 481 [SC7180_GFX] = &gfx, 482 [SC7180_LCX] = &lcx, 483 [SC7180_LMX] = &lmx, 484 [SC7180_MSS] = &mss, 485 [SC7180_MX] = &mx, 486 [SC7180_MX_AO] = &mx_ao, 487 }; 488 489 static const struct rpmhpd_desc sc7180_desc = { 490 .rpmhpds = sc7180_rpmhpds, 491 .num_pds = ARRAY_SIZE(sc7180_rpmhpds), 492 }; 493 494 /* SC7280 RPMH powerdomains */ 495 static struct rpmhpd *sc7280_rpmhpds[] = { 496 [SC7280_CX] = &cx, 497 [SC7280_CX_AO] = &cx_ao, 498 [SC7280_EBI] = &ebi, 499 [SC7280_GFX] = &gfx, 500 [SC7280_LCX] = &lcx, 501 [SC7280_LMX] = &lmx, 502 [SC7280_MSS] = &mss, 503 [SC7280_MX] = &mx, 504 [SC7280_MX_AO] = &mx_ao, 505 }; 506 507 static const struct rpmhpd_desc sc7280_desc = { 508 .rpmhpds = sc7280_rpmhpds, 509 .num_pds = ARRAY_SIZE(sc7280_rpmhpds), 510 }; 511 512 /* SC8180x RPMH powerdomains */ 513 static struct rpmhpd *sc8180x_rpmhpds[] = { 514 [SC8180X_CX] = &cx_w_mx_parent, 515 [SC8180X_CX_AO] = &cx_ao_w_mx_parent, 516 [SC8180X_EBI] = &ebi, 517 [SC8180X_GFX] = &gfx, 518 [SC8180X_LCX] = &lcx, 519 [SC8180X_LMX] = &lmx, 520 [SC8180X_MMCX] = &mmcx, 521 [SC8180X_MMCX_AO] = &mmcx_ao, 522 [SC8180X_MSS] = &mss, 523 [SC8180X_MX] = &mx, 524 [SC8180X_MX_AO] = &mx_ao, 525 }; 526 527 static const struct rpmhpd_desc sc8180x_desc = { 528 .rpmhpds = sc8180x_rpmhpds, 529 .num_pds = ARRAY_SIZE(sc8180x_rpmhpds), 530 }; 531 532 /* SC8280xp RPMH powerdomains */ 533 static struct rpmhpd *sc8280xp_rpmhpds[] = { 534 [SC8280XP_CX] = &cx, 535 [SC8280XP_CX_AO] = &cx_ao, 536 [SC8280XP_EBI] = &ebi, 537 [SC8280XP_GFX] = &gfx, 538 [SC8280XP_LCX] = &lcx, 539 [SC8280XP_LMX] = &lmx, 540 [SC8280XP_MMCX] = &mmcx, 541 [SC8280XP_MMCX_AO] = &mmcx_ao, 542 [SC8280XP_MX] = &mx, 543 [SC8280XP_MX_AO] = &mx_ao, 544 [SC8280XP_NSP] = &nsp, 545 [SC8280XP_QPHY] = &qphy, 546 }; 547 548 static const struct rpmhpd_desc sc8280xp_desc = { 549 .rpmhpds = sc8280xp_rpmhpds, 550 .num_pds = ARRAY_SIZE(sc8280xp_rpmhpds), 551 }; 552 553 static const struct of_device_id rpmhpd_match_table[] = { 554 { .compatible = "qcom,qdu1000-rpmhpd", .data = &qdu1000_desc }, 555 { .compatible = "qcom,sa8155p-rpmhpd", .data = &sa8155p_desc }, 556 { .compatible = "qcom,sa8540p-rpmhpd", .data = &sa8540p_desc }, 557 { .compatible = "qcom,sa8775p-rpmhpd", .data = &sa8775p_desc }, 558 { .compatible = "qcom,sc7180-rpmhpd", .data = &sc7180_desc }, 559 { .compatible = "qcom,sc7280-rpmhpd", .data = &sc7280_desc }, 560 { .compatible = "qcom,sc8180x-rpmhpd", .data = &sc8180x_desc }, 561 { .compatible = "qcom,sc8280xp-rpmhpd", .data = &sc8280xp_desc }, 562 { .compatible = "qcom,sdm670-rpmhpd", .data = &sdm670_desc }, 563 { .compatible = "qcom,sdm845-rpmhpd", .data = &sdm845_desc }, 564 { .compatible = "qcom,sdx55-rpmhpd", .data = &sdx55_desc}, 565 { .compatible = "qcom,sdx65-rpmhpd", .data = &sdx65_desc}, 566 { .compatible = "qcom,sdx75-rpmhpd", .data = &sdx75_desc}, 567 { .compatible = "qcom,sm6350-rpmhpd", .data = &sm6350_desc }, 568 { .compatible = "qcom,sm8150-rpmhpd", .data = &sm8150_desc }, 569 { .compatible = "qcom,sm8250-rpmhpd", .data = &sm8250_desc }, 570 { .compatible = "qcom,sm8350-rpmhpd", .data = &sm8350_desc }, 571 { .compatible = "qcom,sm8450-rpmhpd", .data = &sm8450_desc }, 572 { .compatible = "qcom,sm8550-rpmhpd", .data = &sm8550_desc }, 573 { } 574 }; 575 MODULE_DEVICE_TABLE(of, rpmhpd_match_table); 576 577 static int rpmhpd_send_corner(struct rpmhpd *pd, int state, 578 unsigned int corner, bool sync) 579 { 580 struct tcs_cmd cmd = { 581 .addr = pd->addr, 582 .data = corner, 583 }; 584 585 /* 586 * Wait for an ack only when we are increasing the 587 * perf state of the power domain 588 */ 589 if (sync) 590 return rpmh_write(pd->dev, state, &cmd, 1); 591 else 592 return rpmh_write_async(pd->dev, state, &cmd, 1); 593 } 594 595 static void to_active_sleep(struct rpmhpd *pd, unsigned int corner, 596 unsigned int *active, unsigned int *sleep) 597 { 598 *active = corner; 599 600 if (pd->active_only) 601 *sleep = 0; 602 else 603 *sleep = *active; 604 } 605 606 /* 607 * This function is used to aggregate the votes across the active only 608 * resources and its peers. The aggregated votes are sent to RPMh as 609 * ACTIVE_ONLY votes (which take effect immediately), as WAKE_ONLY votes 610 * (applied by RPMh on system wakeup) and as SLEEP votes (applied by RPMh 611 * on system sleep). 612 * We send ACTIVE_ONLY votes for resources without any peers. For others, 613 * which have an active only peer, all 3 votes are sent. 614 */ 615 static int rpmhpd_aggregate_corner(struct rpmhpd *pd, unsigned int corner) 616 { 617 int ret; 618 struct rpmhpd *peer = pd->peer; 619 unsigned int active_corner, sleep_corner; 620 unsigned int this_active_corner = 0, this_sleep_corner = 0; 621 unsigned int peer_active_corner = 0, peer_sleep_corner = 0; 622 unsigned int peer_enabled_corner; 623 624 if (pd->state_synced) { 625 to_active_sleep(pd, corner, &this_active_corner, &this_sleep_corner); 626 } else { 627 /* Clamp to highest corner if sync_state hasn't happened */ 628 this_active_corner = pd->level_count - 1; 629 this_sleep_corner = pd->level_count - 1; 630 } 631 632 if (peer && peer->enabled) { 633 peer_enabled_corner = max(peer->corner, peer->enable_corner); 634 to_active_sleep(peer, peer_enabled_corner, &peer_active_corner, 635 &peer_sleep_corner); 636 } 637 638 active_corner = max(this_active_corner, peer_active_corner); 639 640 ret = rpmhpd_send_corner(pd, RPMH_ACTIVE_ONLY_STATE, active_corner, 641 active_corner > pd->active_corner); 642 if (ret) 643 return ret; 644 645 pd->active_corner = active_corner; 646 647 if (peer) { 648 peer->active_corner = active_corner; 649 650 ret = rpmhpd_send_corner(pd, RPMH_WAKE_ONLY_STATE, 651 active_corner, false); 652 if (ret) 653 return ret; 654 655 sleep_corner = max(this_sleep_corner, peer_sleep_corner); 656 657 return rpmhpd_send_corner(pd, RPMH_SLEEP_STATE, sleep_corner, 658 false); 659 } 660 661 return ret; 662 } 663 664 static int rpmhpd_power_on(struct generic_pm_domain *domain) 665 { 666 struct rpmhpd *pd = domain_to_rpmhpd(domain); 667 unsigned int corner; 668 int ret; 669 670 mutex_lock(&rpmhpd_lock); 671 672 corner = max(pd->corner, pd->enable_corner); 673 ret = rpmhpd_aggregate_corner(pd, corner); 674 if (!ret) 675 pd->enabled = true; 676 677 mutex_unlock(&rpmhpd_lock); 678 679 return ret; 680 } 681 682 static int rpmhpd_power_off(struct generic_pm_domain *domain) 683 { 684 struct rpmhpd *pd = domain_to_rpmhpd(domain); 685 int ret; 686 687 mutex_lock(&rpmhpd_lock); 688 689 ret = rpmhpd_aggregate_corner(pd, 0); 690 if (!ret) 691 pd->enabled = false; 692 693 mutex_unlock(&rpmhpd_lock); 694 695 return ret; 696 } 697 698 static int rpmhpd_set_performance_state(struct generic_pm_domain *domain, 699 unsigned int level) 700 { 701 struct rpmhpd *pd = domain_to_rpmhpd(domain); 702 int ret = 0, i; 703 704 mutex_lock(&rpmhpd_lock); 705 706 for (i = 0; i < pd->level_count; i++) 707 if (level <= pd->level[i]) 708 break; 709 710 /* 711 * If the level requested is more than that supported by the 712 * max corner, just set it to max anyway. 713 */ 714 if (i == pd->level_count) 715 i--; 716 717 if (pd->enabled) { 718 /* Ensure that the domain isn't turn off */ 719 if (i < pd->enable_corner) 720 i = pd->enable_corner; 721 722 ret = rpmhpd_aggregate_corner(pd, i); 723 if (ret) 724 goto out; 725 } 726 727 pd->corner = i; 728 out: 729 mutex_unlock(&rpmhpd_lock); 730 731 return ret; 732 } 733 734 static unsigned int rpmhpd_get_performance_state(struct generic_pm_domain *genpd, 735 struct dev_pm_opp *opp) 736 { 737 return dev_pm_opp_get_level(opp); 738 } 739 740 static int rpmhpd_update_level_mapping(struct rpmhpd *rpmhpd) 741 { 742 int i; 743 const u16 *buf; 744 745 buf = cmd_db_read_aux_data(rpmhpd->res_name, &rpmhpd->level_count); 746 if (IS_ERR(buf)) 747 return PTR_ERR(buf); 748 749 /* 2 bytes used for each command DB aux data entry */ 750 rpmhpd->level_count >>= 1; 751 752 if (rpmhpd->level_count > RPMH_ARC_MAX_LEVELS) 753 return -EINVAL; 754 755 for (i = 0; i < rpmhpd->level_count; i++) { 756 if (rpmhpd->skip_retention_level && buf[i] == RPMH_REGULATOR_LEVEL_RETENTION) 757 continue; 758 759 rpmhpd->level[i] = buf[i]; 760 761 /* Remember the first corner with non-zero level */ 762 if (!rpmhpd->level[rpmhpd->enable_corner] && rpmhpd->level[i]) 763 rpmhpd->enable_corner = i; 764 765 /* 766 * The AUX data may be zero padded. These 0 valued entries at 767 * the end of the map must be ignored. 768 */ 769 if (i > 0 && rpmhpd->level[i] == 0) { 770 rpmhpd->level_count = i; 771 break; 772 } 773 pr_debug("%s: ARC hlvl=%2d --> vlvl=%4u\n", rpmhpd->res_name, i, 774 rpmhpd->level[i]); 775 } 776 777 return 0; 778 } 779 780 static int rpmhpd_probe(struct platform_device *pdev) 781 { 782 int i, ret; 783 size_t num_pds; 784 struct device *dev = &pdev->dev; 785 struct genpd_onecell_data *data; 786 struct rpmhpd **rpmhpds; 787 const struct rpmhpd_desc *desc; 788 789 desc = of_device_get_match_data(dev); 790 if (!desc) 791 return -EINVAL; 792 793 rpmhpds = desc->rpmhpds; 794 num_pds = desc->num_pds; 795 796 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 797 if (!data) 798 return -ENOMEM; 799 800 data->domains = devm_kcalloc(dev, num_pds, sizeof(*data->domains), 801 GFP_KERNEL); 802 if (!data->domains) 803 return -ENOMEM; 804 805 data->num_domains = num_pds; 806 807 for (i = 0; i < num_pds; i++) { 808 if (!rpmhpds[i]) 809 continue; 810 811 rpmhpds[i]->dev = dev; 812 rpmhpds[i]->addr = cmd_db_read_addr(rpmhpds[i]->res_name); 813 if (!rpmhpds[i]->addr) { 814 dev_err(dev, "Could not find RPMh address for resource %s\n", 815 rpmhpds[i]->res_name); 816 return -ENODEV; 817 } 818 819 ret = cmd_db_read_slave_id(rpmhpds[i]->res_name); 820 if (ret != CMD_DB_HW_ARC) { 821 dev_err(dev, "RPMh slave ID mismatch\n"); 822 return -EINVAL; 823 } 824 825 ret = rpmhpd_update_level_mapping(rpmhpds[i]); 826 if (ret) 827 return ret; 828 829 rpmhpds[i]->pd.power_off = rpmhpd_power_off; 830 rpmhpds[i]->pd.power_on = rpmhpd_power_on; 831 rpmhpds[i]->pd.set_performance_state = rpmhpd_set_performance_state; 832 rpmhpds[i]->pd.opp_to_performance_state = rpmhpd_get_performance_state; 833 pm_genpd_init(&rpmhpds[i]->pd, NULL, true); 834 835 data->domains[i] = &rpmhpds[i]->pd; 836 } 837 838 /* Add subdomains */ 839 for (i = 0; i < num_pds; i++) { 840 if (!rpmhpds[i]) 841 continue; 842 if (rpmhpds[i]->parent) 843 pm_genpd_add_subdomain(rpmhpds[i]->parent, 844 &rpmhpds[i]->pd); 845 } 846 847 return of_genpd_add_provider_onecell(pdev->dev.of_node, data); 848 } 849 850 static void rpmhpd_sync_state(struct device *dev) 851 { 852 const struct rpmhpd_desc *desc = of_device_get_match_data(dev); 853 struct rpmhpd **rpmhpds = desc->rpmhpds; 854 unsigned int corner; 855 struct rpmhpd *pd; 856 unsigned int i; 857 int ret; 858 859 mutex_lock(&rpmhpd_lock); 860 for (i = 0; i < desc->num_pds; i++) { 861 pd = rpmhpds[i]; 862 if (!pd) 863 continue; 864 865 pd->state_synced = true; 866 if (pd->enabled) 867 corner = max(pd->corner, pd->enable_corner); 868 else 869 corner = 0; 870 871 ret = rpmhpd_aggregate_corner(pd, corner); 872 if (ret) 873 dev_err(dev, "failed to sync %s\n", pd->res_name); 874 } 875 mutex_unlock(&rpmhpd_lock); 876 } 877 878 static struct platform_driver rpmhpd_driver = { 879 .driver = { 880 .name = "qcom-rpmhpd", 881 .of_match_table = rpmhpd_match_table, 882 .suppress_bind_attrs = true, 883 .sync_state = rpmhpd_sync_state, 884 }, 885 .probe = rpmhpd_probe, 886 }; 887 888 static int __init rpmhpd_init(void) 889 { 890 return platform_driver_register(&rpmhpd_driver); 891 } 892 core_initcall(rpmhpd_init); 893 894 MODULE_DESCRIPTION("Qualcomm Technologies, Inc. RPMh Power Domain Driver"); 895 MODULE_LICENSE("GPL v2"); 896