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