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