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