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