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