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