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