FILE
rpmpd.c
File preview with syntax highlighting.
linux-6.19.14/drivers/pmdomain/qcom/rpmpd.c
1// SPDX-License-Identifier: GPL-2.0 2/* Copyright (c) 2017-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/of.h> 12#include <linux/platform_device.h> 13#include <linux/pm_opp.h> 14#include <linux/soc/qcom/smd-rpm.h> 15 16#include <dt-bindings/power/qcom-rpmpd.h> 17 18#define domain_to_rpmpd(domain) container_of(domain, struct rpmpd, pd) 19 20static struct qcom_smd_rpm *rpmpd_smd_rpm; 21 22/* Resource types: 23 * RPMPD_X is X encoded as a little-endian, lower-case, ASCII string */ 24#define RPMPD_SMPA 0x61706d73 25#define RPMPD_LDOA 0x616f646c 26#define RPMPD_SMPB 0x62706d73 27#define RPMPD_LDOB 0x626f646c 28#define RPMPD_RWCX 0x78637772 29#define RPMPD_RWMX 0x786d7772 30#define RPMPD_RWLC 0x636c7772 31#define RPMPD_RWLM 0x6d6c7772 32#define RPMPD_RWSC 0x63737772 33#define RPMPD_RWSM 0x6d737772 34#define RPMPD_RWGX 0x78677772 35 36/* Operation Keys */ 37#define KEY_CORNER 0x6e726f63 /* corn */ 38#define KEY_ENABLE 0x6e657773 /* swen */ 39#define KEY_FLOOR_CORNER 0x636676 /* vfc */ 40#define KEY_FLOOR_LEVEL 0x6c6676 /* vfl */ 41#define KEY_LEVEL 0x6c766c76 /* vlvl */ 42 43#define MAX_CORNER_RPMPD_STATE 6 44 45struct rpmpd_req { 46 __le32 key; 47 __le32 nbytes; 48 __le32 value; 49}; 50 51struct rpmpd { 52 struct generic_pm_domain pd; 53 struct generic_pm_domain *parent; 54 struct rpmpd *peer; 55 const bool active_only; 56 unsigned int corner; 57 bool enabled; 58 const int res_type; 59 const int res_id; 60 unsigned int max_state; 61 __le32 key; 62 bool state_synced; 63}; 64 65struct rpmpd_desc { 66 struct rpmpd **rpmpds; 67 size_t num_pds; 68 unsigned int max_state; 69}; 70 71static DEFINE_MUTEX(rpmpd_lock); 72 73/* CX */ 74static struct rpmpd cx_rwcx0_lvl_ao; 75static struct rpmpd cx_rwcx0_lvl = { 76 .pd = { .name = "cx", }, 77 .peer = &cx_rwcx0_lvl_ao, 78 .res_type = RPMPD_RWCX, 79 .res_id = 0, 80 .key = KEY_LEVEL, 81}; 82 83static struct rpmpd cx_rwcx0_lvl_ao = { 84 .pd = { .name = "cx_ao", }, 85 .peer = &cx_rwcx0_lvl, 86 .active_only = true, 87 .res_type = RPMPD_RWCX, 88 .res_id = 0, 89 .key = KEY_LEVEL, 90}; 91 92static struct rpmpd cx_s1a_corner_ao; 93static struct rpmpd cx_s1a_corner = { 94 .pd = { .name = "cx", }, 95 .peer = &cx_s1a_corner_ao, 96 .res_type = RPMPD_SMPA, 97 .res_id = 1, 98 .key = KEY_CORNER, 99}; 100 101static struct rpmpd cx_s1a_corner_ao = { 102 .pd = { .name = "cx_ao", }, 103 .peer = &cx_s1a_corner, 104 .active_only = true, 105 .res_type = RPMPD_SMPA, 106 .res_id = 1, 107 .key = KEY_CORNER, 108}; 109 110static struct rpmpd cx_s1a_lvl_ao; 111static struct rpmpd cx_s1a_lvl = { 112 .pd = { .name = "cx", }, 113 .peer = &cx_s1a_lvl_ao, 114 .res_type = RPMPD_SMPA, 115 .res_id = 1, 116 .key = KEY_LEVEL, 117}; 118 119static struct rpmpd cx_s1a_lvl_ao = { 120 .pd = { .name = "cx_ao", }, 121 .peer = &cx_s1a_lvl, 122 .active_only = true, 123 .res_type = RPMPD_SMPA, 124 .res_id = 1, 125 .key = KEY_LEVEL, 126}; 127 128static struct rpmpd cx_s2a_corner_ao; 129static struct rpmpd cx_s2a_corner = { 130 .pd = { .name = "cx", }, 131 .peer = &cx_s2a_corner_ao, 132 .res_type = RPMPD_SMPA, 133 .res_id = 2, 134 .key = KEY_CORNER, 135}; 136 137static struct rpmpd cx_s2a_corner_ao = { 138 .pd = { .name = "cx_ao", }, 139 .peer = &cx_s2a_corner, 140 .active_only = true, 141 .res_type = RPMPD_SMPA, 142 .res_id = 2, 143 .key = KEY_CORNER, 144}; 145 146static struct rpmpd cx_s2a_lvl_ao; 147static struct rpmpd cx_s2a_lvl = { 148 .pd = { .name = "cx", }, 149 .peer = &cx_s2a_lvl_ao, 150 .res_type = RPMPD_SMPA, 151 .res_id = 2, 152 .key = KEY_LEVEL, 153}; 154 155static struct rpmpd cx_s2a_lvl_ao = { 156 .pd = { .name = "cx_ao", }, 157 .peer = &cx_s2a_lvl, 158 .active_only = true, 159 .res_type = RPMPD_SMPA, 160 .res_id = 2, 161 .key = KEY_LEVEL, 162}; 163 164static struct rpmpd cx_s3a_lvl_ao; 165static struct rpmpd cx_s3a_lvl = { 166 .pd = { .name = "cx", }, 167 .peer = &cx_s3a_lvl_ao, 168 .res_type = RPMPD_SMPA, 169 .res_id = 3, 170 .key = KEY_LEVEL, 171}; 172 173static struct rpmpd cx_s3a_lvl_ao = { 174 .pd = { .name = "cx_ao", }, 175 .peer = &cx_s3a_lvl, 176 .active_only = true, 177 .res_type = RPMPD_SMPA, 178 .res_id = 3, 179 .key = KEY_LEVEL, 180}; 181 182static struct rpmpd cx_rwcx0_vfl = { 183 .pd = { .name = "cx_vfl", }, 184 .res_type = RPMPD_RWCX, 185 .res_id = 0, 186 .key = KEY_FLOOR_LEVEL, 187}; 188 189static struct rpmpd cx_rwsc2_vfl = { 190 .pd = { .name = "cx_vfl", }, 191 .res_type = RPMPD_RWSC, 192 .res_id = 2, 193 .key = KEY_FLOOR_LEVEL, 194}; 195 196static struct rpmpd cx_s1a_vfc = { 197 .pd = { .name = "cx_vfc", }, 198 .res_type = RPMPD_SMPA, 199 .res_id = 1, 200 .key = KEY_FLOOR_CORNER, 201}; 202 203static struct rpmpd cx_s1a_vfl = { 204 .pd = { .name = "cx_vfl", }, 205 .res_type = RPMPD_SMPA, 206 .res_id = 1, 207 .key = KEY_FLOOR_LEVEL, 208}; 209 210static struct rpmpd cx_s2a_vfc = { 211 .pd = { .name = "cx_vfc", }, 212 .res_type = RPMPD_SMPA, 213 .res_id = 2, 214 .key = KEY_FLOOR_CORNER, 215}; 216 217static struct rpmpd cx_s2a_vfl = { 218 .pd = { .name = "cx_vfl", }, 219 .res_type = RPMPD_SMPA, 220 .res_id = 2, 221 .key = KEY_FLOOR_LEVEL, 222}; 223 224static struct rpmpd cx_s3a_vfl = { 225 .pd = { .name = "cx_vfl", }, 226 .res_type = RPMPD_SMPA, 227 .res_id = 3, 228 .key = KEY_FLOOR_LEVEL, 229}; 230 231static struct rpmpd cx_s2b_corner_ao; 232static struct rpmpd cx_s2b_corner = { 233 .pd = { .name = "cx", }, 234 .peer = &cx_s2b_corner_ao, 235 .res_type = RPMPD_SMPB, 236 .res_id = 2, 237 .key = KEY_CORNER, 238}; 239 240static struct rpmpd cx_s2b_corner_ao = { 241 .pd = { .name = "cx_ao", }, 242 .peer = &cx_s2b_corner, 243 .active_only = true, 244 .res_type = RPMPD_SMPB, 245 .res_id = 2, 246 .key = KEY_CORNER, 247}; 248 249static struct rpmpd cx_s2b_vfc = { 250 .pd = { .name = "cx_vfc", }, 251 .res_type = RPMPD_SMPB, 252 .res_id = 2, 253 .key = KEY_FLOOR_CORNER, 254}; 255 256/* G(F)X */ 257static struct rpmpd gfx_s7a_corner = { 258 .pd = { .name = "gfx", }, 259 .res_type = RPMPD_SMPA, 260 .res_id = 7, 261 .key = KEY_CORNER, 262}; 263 264static struct rpmpd gfx_s7a_vfc = { 265 .pd = { .name = "gfx_vfc", }, 266 .res_type = RPMPD_SMPA, 267 .res_id = 7, 268 .key = KEY_FLOOR_CORNER, 269}; 270 271static struct rpmpd gfx_s2b_corner = { 272 .pd = { .name = "gfx", }, 273 .res_type = RPMPD_SMPB, 274 .res_id = 2, 275 .key = KEY_CORNER, 276}; 277 278static struct rpmpd gfx_s2b_vfc = { 279 .pd = { .name = "gfx_vfc", }, 280 .res_type = RPMPD_SMPB, 281 .res_id = 2, 282 .key = KEY_FLOOR_CORNER, 283}; 284 285static struct rpmpd gfx_s4b_corner = { 286 .pd = { .name = "gfx", }, 287 .res_type = RPMPD_SMPB, 288 .res_id = 4, 289 .key = KEY_CORNER, 290}; 291 292static struct rpmpd gfx_s4b_vfc = { 293 .pd = { .name = "gfx_vfc", }, 294 .res_type = RPMPD_SMPB, 295 .res_id = 4, 296 .key = KEY_FLOOR_CORNER, 297}; 298 299static struct rpmpd mx_rwmx0_lvl; 300static struct rpmpd gx_rwgx0_lvl_ao; 301static struct rpmpd gx_rwgx0_lvl = { 302 .pd = { .name = "gx", }, 303 .peer = &gx_rwgx0_lvl_ao, 304 .res_type = RPMPD_RWGX, 305 .parent = &mx_rwmx0_lvl.pd, 306 .res_id = 0, 307 .key = KEY_LEVEL, 308}; 309 310static struct rpmpd mx_rwmx0_lvl_ao; 311static struct rpmpd gx_rwgx0_lvl_ao = { 312 .pd = { .name = "gx_ao", }, 313 .peer = &gx_rwgx0_lvl, 314 .parent = &mx_rwmx0_lvl_ao.pd, 315 .active_only = true, 316 .res_type = RPMPD_RWGX, 317 .res_id = 0, 318 .key = KEY_LEVEL, 319}; 320 321/* MX */ 322static struct rpmpd mx_l2a_lvl_ao; 323static struct rpmpd mx_l2a_lvl = { 324 .pd = { .name = "mx", }, 325 .peer = &mx_l2a_lvl_ao, 326 .res_type = RPMPD_LDOA, 327 .res_id = 2, 328 .key = KEY_LEVEL, 329}; 330 331static struct rpmpd mx_l2a_lvl_ao = { 332 .pd = { .name = "mx_ao", }, 333 .peer = &mx_l2a_lvl, 334 .active_only = true, 335 .res_type = RPMPD_LDOA, 336 .res_id = 2, 337 .key = KEY_LEVEL, 338}; 339 340static struct rpmpd mx_l3a_corner_ao; 341static struct rpmpd mx_l3a_corner = { 342 .pd = { .name = "mx", }, 343 .peer = &mx_l3a_corner_ao, 344 .res_type = RPMPD_LDOA, 345 .res_id = 3, 346 .key = KEY_CORNER, 347}; 348 349static struct rpmpd mx_l3a_corner_ao = { 350 .pd = { .name = "mx_ao", }, 351 .peer = &mx_l3a_corner, 352 .active_only = true, 353 .res_type = RPMPD_LDOA, 354 .res_id = 3, 355 .key = KEY_CORNER, 356}; 357 358static struct rpmpd mx_l3a_lvl_ao; 359static struct rpmpd mx_l3a_lvl = { 360 .pd = { .name = "mx", }, 361 .peer = &mx_l3a_lvl_ao, 362 .res_type = RPMPD_LDOA, 363 .res_id = 3, 364 .key = KEY_LEVEL, 365}; 366 367static struct rpmpd mx_l3a_lvl_ao = { 368 .pd = { .name = "mx_ao", }, 369 .peer = &mx_l3a_lvl, 370 .active_only = true, 371 .res_type = RPMPD_LDOA, 372 .res_id = 3, 373 .key = KEY_LEVEL, 374}; 375 376static struct rpmpd mx_l12a_lvl_ao; 377static struct rpmpd mx_l12a_lvl = { 378 .pd = { .name = "mx", }, 379 .peer = &mx_l12a_lvl_ao, 380 .res_type = RPMPD_LDOA, 381 .res_id = 12, 382 .key = KEY_LEVEL, 383}; 384 385static struct rpmpd mx_l12a_lvl_ao = { 386 .pd = { .name = "mx_ao", }, 387 .peer = &mx_l12a_lvl, 388 .active_only = true, 389 .res_type = RPMPD_LDOA, 390 .res_id = 12, 391 .key = KEY_LEVEL, 392}; 393 394static struct rpmpd mx_s2a_corner_ao; 395static struct rpmpd mx_s2a_corner = { 396 .pd = { .name = "mx", }, 397 .peer = &mx_s2a_corner_ao, 398 .res_type = RPMPD_SMPA, 399 .res_id = 2, 400 .key = KEY_CORNER, 401}; 402 403static struct rpmpd mx_s2a_corner_ao = { 404 .pd = { .name = "mx_ao", }, 405 .peer = &mx_s2a_corner, 406 .active_only = true, 407 .res_type = RPMPD_SMPA, 408 .res_id = 2, 409 .key = KEY_CORNER, 410}; 411 412static struct rpmpd mx_rwmx0_lvl_ao; 413static struct rpmpd mx_rwmx0_lvl = { 414 .pd = { .name = "mx", }, 415 .peer = &mx_rwmx0_lvl_ao, 416 .res_type = RPMPD_RWMX, 417 .res_id = 0, 418 .key = KEY_LEVEL, 419}; 420 421static struct rpmpd mx_rwmx0_lvl_ao = { 422 .pd = { .name = "mx_ao", }, 423 .peer = &mx_rwmx0_lvl, 424 .active_only = true, 425 .res_type = RPMPD_RWMX, 426 .res_id = 0, 427 .key = KEY_LEVEL, 428}; 429 430static struct rpmpd mx_s6a_lvl_ao; 431static struct rpmpd mx_s6a_lvl = { 432 .pd = { .name = "mx", }, 433 .peer = &mx_s6a_lvl_ao, 434 .res_type = RPMPD_SMPA, 435 .res_id = 6, 436 .key = KEY_LEVEL, 437}; 438 439static struct rpmpd mx_s6a_lvl_ao = { 440 .pd = { .name = "mx_ao", }, 441 .peer = &mx_s6a_lvl, 442 .active_only = true, 443 .res_type = RPMPD_SMPA, 444 .res_id = 6, 445 .key = KEY_LEVEL, 446}; 447 448static struct rpmpd mx_s7a_lvl_ao; 449static struct rpmpd mx_s7a_lvl = { 450 .pd = { .name = "mx", }, 451 .peer = &mx_s7a_lvl_ao, 452 .res_type = RPMPD_SMPA, 453 .res_id = 7, 454 .key = KEY_LEVEL, 455}; 456 457static struct rpmpd mx_s7a_lvl_ao = { 458 .pd = { .name = "mx_ao", }, 459 .peer = &mx_s7a_lvl, 460 .active_only = true, 461 .res_type = RPMPD_SMPA, 462 .res_id = 7, 463 .key = KEY_LEVEL, 464}; 465 466static struct rpmpd mx_l12a_vfl = { 467 .pd = { .name = "mx_vfl", }, 468 .res_type = RPMPD_LDOA, 469 .res_id = 12, 470 .key = KEY_FLOOR_LEVEL, 471}; 472 473static struct rpmpd mx_rwmx0_vfl = { 474 .pd = { .name = "mx_vfl", }, 475 .res_type = RPMPD_RWMX, 476 .res_id = 0, 477 .key = KEY_FLOOR_LEVEL, 478}; 479 480static struct rpmpd mx_rwsm6_vfl = { 481 .pd = { .name = "mx_vfl", }, 482 .res_type = RPMPD_RWSM, 483 .res_id = 6, 484 .key = KEY_FLOOR_LEVEL, 485}; 486 487/* MD */ 488static struct rpmpd md_s1a_corner_ao; 489static struct rpmpd md_s1a_corner = { 490 .pd = { .name = "md", }, 491 .peer = &md_s1a_corner_ao, 492 .res_type = RPMPD_SMPA, 493 .res_id = 1, 494 .key = KEY_CORNER, 495}; 496 497static struct rpmpd md_s1a_corner_ao = { 498 .pd = { .name = "md_ao", }, 499 .peer = &md_s1a_corner, 500 .active_only = true, 501 .res_type = RPMPD_SMPA, 502 .res_id = 1, 503 .key = KEY_CORNER, 504}; 505 506static struct rpmpd md_s1a_lvl_ao; 507static struct rpmpd md_s1a_lvl = { 508 .pd = { .name = "md", }, 509 .peer = &md_s1a_lvl_ao, 510 .res_type = RPMPD_SMPA, 511 .res_id = 1, 512 .key = KEY_LEVEL, 513}; 514 515static struct rpmpd md_s1a_lvl_ao = { 516 .pd = { .name = "md_ao", }, 517 .peer = &md_s1a_lvl, 518 .active_only = true, 519 .res_type = RPMPD_SMPA, 520 .res_id = 1, 521 .key = KEY_LEVEL, 522}; 523 524static struct rpmpd md_s1a_vfc = { 525 .pd = { .name = "md_vfc", }, 526 .res_type = RPMPD_SMPA, 527 .res_id = 1, 528 .key = KEY_FLOOR_CORNER, 529}; 530 531/* LPI_CX */ 532static struct rpmpd lpi_cx_rwlc0_lvl = { 533 .pd = { .name = "lpi_cx", }, 534 .res_type = RPMPD_RWLC, 535 .res_id = 0, 536 .key = KEY_LEVEL, 537}; 538 539static struct rpmpd lpi_cx_rwlc0_vfl = { 540 .pd = { .name = "lpi_cx_vfl", }, 541 .res_type = RPMPD_RWLC, 542 .res_id = 0, 543 .key = KEY_FLOOR_LEVEL, 544}; 545 546/* LPI_MX */ 547static struct rpmpd lpi_mx_rwlm0_lvl = { 548 .pd = { .name = "lpi_mx", }, 549 .res_type = RPMPD_RWLM, 550 .res_id = 0, 551 .key = KEY_LEVEL, 552}; 553 554static struct rpmpd lpi_mx_rwlm0_vfl = { 555 .pd = { .name = "lpi_mx_vfl", }, 556 .res_type = RPMPD_RWLM, 557 .res_id = 0, 558 .key = KEY_FLOOR_LEVEL, 559}; 560 561/* SSC_CX */ 562static struct rpmpd ssc_cx_l26a_corner = { 563 .pd = { .name = "ssc_cx", }, 564 .res_type = RPMPD_LDOA, 565 .res_id = 26, 566 .key = KEY_CORNER, 567}; 568 569static struct rpmpd ssc_cx_rwlc0_lvl = { 570 .pd = { .name = "ssc_cx", }, 571 .res_type = RPMPD_RWLC, 572 .res_id = 0, 573 .key = KEY_LEVEL, 574}; 575 576static struct rpmpd ssc_cx_rwsc0_lvl = { 577 .pd = { .name = "ssc_cx", }, 578 .res_type = RPMPD_RWSC, 579 .res_id = 0, 580 .key = KEY_LEVEL, 581}; 582 583static struct rpmpd ssc_cx_l26a_vfc = { 584 .pd = { .name = "ssc_cx_vfc", }, 585 .res_type = RPMPD_LDOA, 586 .res_id = 26, 587 .key = KEY_FLOOR_CORNER, 588}; 589 590static struct rpmpd ssc_cx_rwlc0_vfl = { 591 .pd = { .name = "ssc_cx_vfl", }, 592 .res_type = RPMPD_RWLC, 593 .res_id = 0, 594 .key = KEY_FLOOR_LEVEL, 595}; 596 597static struct rpmpd ssc_cx_rwsc0_vfl = { 598 .pd = { .name = "ssc_cx_vfl", }, 599 .res_type = RPMPD_RWSC, 600 .res_id = 0, 601 .key = KEY_FLOOR_LEVEL, 602}; 603 604/* SSC_MX */ 605static struct rpmpd ssc_mx_rwlm0_lvl = { 606 .pd = { .name = "ssc_mx", }, 607 .res_type = RPMPD_RWLM, 608 .res_id = 0, 609 .key = KEY_LEVEL, 610}; 611 612static struct rpmpd ssc_mx_rwsm0_lvl = { 613 .pd = { .name = "ssc_mx", }, 614 .res_type = RPMPD_RWSM, 615 .res_id = 0, 616 .key = KEY_LEVEL, 617}; 618 619static struct rpmpd ssc_mx_rwlm0_vfl = { 620 .pd = { .name = "ssc_mx_vfl", }, 621 .res_type = RPMPD_RWLM, 622 .res_id = 0, 623 .key = KEY_FLOOR_LEVEL, 624}; 625 626static struct rpmpd ssc_mx_rwsm0_vfl = { 627 .pd = { .name = "ssc_mx_vfl", }, 628 .res_type = RPMPD_RWSM, 629 .res_id = 0, 630 .key = KEY_FLOOR_LEVEL, 631}; 632 633static struct rpmpd *mdm9607_rpmpds[] = { 634 [RPMPD_VDDCX] = &cx_s3a_lvl, 635 [RPMPD_VDDCX_AO] = &cx_s3a_lvl_ao, 636 [RPMPD_VDDCX_VFL] = &cx_s3a_vfl, 637 [RPMPD_VDDMX] = &mx_l12a_lvl, 638 [RPMPD_VDDMX_AO] = &mx_l12a_lvl_ao, 639 [RPMPD_VDDMX_VFL] = &mx_l12a_vfl, 640}; 641 642static const struct rpmpd_desc mdm9607_desc = { 643 .rpmpds = mdm9607_rpmpds, 644 .num_pds = ARRAY_SIZE(mdm9607_rpmpds), 645 .max_state = RPM_SMD_LEVEL_TURBO, 646}; 647 648static struct rpmpd *msm8226_rpmpds[] = { 649 [RPMPD_VDDCX] = &cx_s1a_corner, 650 [RPMPD_VDDCX_AO] = &cx_s1a_corner_ao, 651 [RPMPD_VDDCX_VFC] = &cx_s1a_vfc, 652}; 653 654static const struct rpmpd_desc msm8226_desc = { 655 .rpmpds = msm8226_rpmpds, 656 .num_pds = ARRAY_SIZE(msm8226_rpmpds), 657 .max_state = MAX_CORNER_RPMPD_STATE, 658}; 659 660static struct rpmpd *msm8939_rpmpds[] = { 661 [MSM8939_VDDMDCX] = &md_s1a_corner, 662 [MSM8939_VDDMDCX_AO] = &md_s1a_corner_ao, 663 [MSM8939_VDDMDCX_VFC] = &md_s1a_vfc, 664 [MSM8939_VDDCX] = &cx_s2a_corner, 665 [MSM8939_VDDCX_AO] = &cx_s2a_corner_ao, 666 [MSM8939_VDDCX_VFC] = &cx_s2a_vfc, 667 [MSM8939_VDDMX] = &mx_l3a_corner, 668 [MSM8939_VDDMX_AO] = &mx_l3a_corner_ao, 669}; 670 671static const struct rpmpd_desc msm8939_desc = { 672 .rpmpds = msm8939_rpmpds, 673 .num_pds = ARRAY_SIZE(msm8939_rpmpds), 674 .max_state = MAX_CORNER_RPMPD_STATE, 675}; 676 677static struct rpmpd *msm8916_rpmpds[] = { 678 [RPMPD_VDDCX] = &cx_s1a_corner, 679 [RPMPD_VDDCX_AO] = &cx_s1a_corner_ao, 680 [RPMPD_VDDCX_VFC] = &cx_s1a_vfc, 681 [RPMPD_VDDMX] = &mx_l3a_corner, 682 [RPMPD_VDDMX_AO] = &mx_l3a_corner_ao, 683}; 684 685static const struct rpmpd_desc msm8916_desc = { 686 .rpmpds = msm8916_rpmpds, 687 .num_pds = ARRAY_SIZE(msm8916_rpmpds), 688 .max_state = MAX_CORNER_RPMPD_STATE, 689}; 690 691static struct rpmpd *msm8917_rpmpds[] = { 692 [RPMPD_VDDCX] = &cx_s2a_lvl, 693 [RPMPD_VDDCX_AO] = &cx_s2a_lvl_ao, 694 [RPMPD_VDDCX_VFL] = &cx_s2a_vfl, 695 [RPMPD_VDDMX] = &mx_l3a_lvl, 696 [RPMPD_VDDMX_AO] = &mx_l3a_lvl_ao, 697}; 698 699static const struct rpmpd_desc msm8917_desc = { 700 .rpmpds = msm8917_rpmpds, 701 .num_pds = ARRAY_SIZE(msm8917_rpmpds), 702 .max_state = RPM_SMD_LEVEL_TURBO, 703}; 704 705static struct rpmpd *msm8953_rpmpds[] = { 706 [MSM8953_VDDMD] = &md_s1a_lvl, 707 [MSM8953_VDDMD_AO] = &md_s1a_lvl_ao, 708 [MSM8953_VDDCX] = &cx_s2a_lvl, 709 [MSM8953_VDDCX_AO] = &cx_s2a_lvl_ao, 710 [MSM8953_VDDCX_VFL] = &cx_s2a_vfl, 711 [MSM8953_VDDMX] = &mx_s7a_lvl, 712 [MSM8953_VDDMX_AO] = &mx_s7a_lvl_ao, 713}; 714 715static const struct rpmpd_desc msm8953_desc = { 716 .rpmpds = msm8953_rpmpds, 717 .num_pds = ARRAY_SIZE(msm8953_rpmpds), 718 .max_state = RPM_SMD_LEVEL_TURBO, 719}; 720 721static struct rpmpd *msm8974_rpmpds[] = { 722 [MSM8974_VDDCX] = &cx_s2b_corner, 723 [MSM8974_VDDCX_AO] = &cx_s2b_corner_ao, 724 [MSM8974_VDDCX_VFC] = &cx_s2b_vfc, 725 [MSM8974_VDDGFX] = &gfx_s4b_corner, 726 [MSM8974_VDDGFX_VFC] = &gfx_s4b_vfc, 727}; 728 729static const struct rpmpd_desc msm8974_desc = { 730 .rpmpds = msm8974_rpmpds, 731 .num_pds = ARRAY_SIZE(msm8974_rpmpds), 732 .max_state = MAX_CORNER_RPMPD_STATE, 733}; 734 735static struct rpmpd *msm8974pro_pma8084_rpmpds[] = { 736 [MSM8974_VDDCX] = &cx_s2a_corner, 737 [MSM8974_VDDCX_AO] = &cx_s2a_corner_ao, 738 [MSM8974_VDDCX_VFC] = &cx_s2a_vfc, 739 [MSM8974_VDDGFX] = &gfx_s7a_corner, 740 [MSM8974_VDDGFX_VFC] = &gfx_s7a_vfc, 741}; 742 743static const struct rpmpd_desc msm8974pro_pma8084_desc = { 744 .rpmpds = msm8974pro_pma8084_rpmpds, 745 .num_pds = ARRAY_SIZE(msm8974pro_pma8084_rpmpds), 746 .max_state = MAX_CORNER_RPMPD_STATE, 747}; 748 749static struct rpmpd *msm8976_rpmpds[] = { 750 [RPMPD_VDDCX] = &cx_s2a_lvl, 751 [RPMPD_VDDCX_AO] = &cx_s2a_lvl_ao, 752 [RPMPD_VDDCX_VFL] = &cx_rwsc2_vfl, 753 [RPMPD_VDDMX] = &mx_s6a_lvl, 754 [RPMPD_VDDMX_AO] = &mx_s6a_lvl_ao, 755 [RPMPD_VDDMX_VFL] = &mx_rwsm6_vfl, 756}; 757 758static const struct rpmpd_desc msm8976_desc = { 759 .rpmpds = msm8976_rpmpds, 760 .num_pds = ARRAY_SIZE(msm8976_rpmpds), 761 .max_state = RPM_SMD_LEVEL_TURBO_HIGH, 762}; 763 764static struct rpmpd *msm8994_rpmpds[] = { 765 [MSM8994_VDDCX] = &cx_s1a_corner, 766 [MSM8994_VDDCX_AO] = &cx_s1a_corner_ao, 767 [MSM8994_VDDCX_VFC] = &cx_s1a_vfc, 768 [MSM8994_VDDMX] = &mx_s2a_corner, 769 [MSM8994_VDDMX_AO] = &mx_s2a_corner_ao, 770 771 /* Attention! *Some* 8994 boards with pm8004 may use SMPC here! */ 772 [MSM8994_VDDGFX] = &gfx_s2b_corner, 773 [MSM8994_VDDGFX_VFC] = &gfx_s2b_vfc, 774}; 775 776static const struct rpmpd_desc msm8994_desc = { 777 .rpmpds = msm8994_rpmpds, 778 .num_pds = ARRAY_SIZE(msm8994_rpmpds), 779 .max_state = MAX_CORNER_RPMPD_STATE, 780}; 781 782static struct rpmpd *msm8996_rpmpds[] = { 783 [MSM8996_VDDCX] = &cx_s1a_corner, 784 [MSM8996_VDDCX_AO] = &cx_s1a_corner_ao, 785 [MSM8996_VDDCX_VFC] = &cx_s1a_vfc, 786 [MSM8996_VDDMX] = &mx_s2a_corner, 787 [MSM8996_VDDMX_AO] = &mx_s2a_corner_ao, 788 [MSM8996_VDDSSCX] = &ssc_cx_l26a_corner, 789 [MSM8996_VDDSSCX_VFC] = &ssc_cx_l26a_vfc, 790}; 791 792static const struct rpmpd_desc msm8996_desc = { 793 .rpmpds = msm8996_rpmpds, 794 .num_pds = ARRAY_SIZE(msm8996_rpmpds), 795 .max_state = MAX_CORNER_RPMPD_STATE, 796}; 797 798static struct rpmpd *msm8998_rpmpds[] = { 799 [RPMPD_VDDCX] = &cx_rwcx0_lvl, 800 [RPMPD_VDDCX_AO] = &cx_rwcx0_lvl_ao, 801 [RPMPD_VDDCX_VFL] = &cx_rwcx0_vfl, 802 [RPMPD_VDDMX] = &mx_rwmx0_lvl, 803 [RPMPD_VDDMX_AO] = &mx_rwmx0_lvl_ao, 804 [RPMPD_VDDMX_VFL] = &mx_rwmx0_vfl, 805 [RPMPD_SSCCX] = &ssc_cx_rwsc0_lvl, 806 [RPMPD_SSCCX_VFL] = &ssc_cx_rwsc0_vfl, 807 [RPMPD_SSCMX] = &ssc_mx_rwsm0_lvl, 808 [RPMPD_SSCMX_VFL] = &ssc_mx_rwsm0_vfl, 809}; 810 811static const struct rpmpd_desc msm8998_desc = { 812 .rpmpds = msm8998_rpmpds, 813 .num_pds = ARRAY_SIZE(msm8998_rpmpds), 814 .max_state = RPM_SMD_LEVEL_BINNING, 815}; 816 817static struct rpmpd *qcs404_rpmpds[] = { 818 [QCS404_VDDMX] = &mx_rwmx0_lvl, 819 [QCS404_VDDMX_AO] = &mx_rwmx0_lvl_ao, 820 [QCS404_VDDMX_VFL] = &mx_rwmx0_vfl, 821 [QCS404_LPICX] = &lpi_cx_rwlc0_lvl, 822 [QCS404_LPICX_VFL] = &lpi_cx_rwlc0_vfl, 823 [QCS404_LPIMX] = &lpi_mx_rwlm0_lvl, 824 [QCS404_LPIMX_VFL] = &lpi_mx_rwlm0_vfl, 825}; 826 827static const struct rpmpd_desc qcs404_desc = { 828 .rpmpds = qcs404_rpmpds, 829 .num_pds = ARRAY_SIZE(qcs404_rpmpds), 830 .max_state = RPM_SMD_LEVEL_BINNING, 831}; 832 833static struct rpmpd *qm215_rpmpds[] = { 834 [RPMPD_VDDCX] = &cx_s1a_lvl, 835 [RPMPD_VDDCX_AO] = &cx_s1a_lvl_ao, 836 [RPMPD_VDDCX_VFL] = &cx_s1a_vfl, 837 [RPMPD_VDDMX] = &mx_l2a_lvl, 838 [RPMPD_VDDMX_AO] = &mx_l2a_lvl_ao, 839}; 840 841static const struct rpmpd_desc qm215_desc = { 842 .rpmpds = qm215_rpmpds, 843 .num_pds = ARRAY_SIZE(qm215_rpmpds), 844 .max_state = RPM_SMD_LEVEL_TURBO, 845}; 846 847static struct rpmpd *sdm660_rpmpds[] = { 848 [RPMPD_VDDCX] = &cx_rwcx0_lvl, 849 [RPMPD_VDDCX_AO] = &cx_rwcx0_lvl_ao, 850 [RPMPD_VDDCX_VFL] = &cx_rwcx0_vfl, 851 [RPMPD_VDDMX] = &mx_rwmx0_lvl, 852 [RPMPD_VDDMX_AO] = &mx_rwmx0_lvl_ao, 853 [RPMPD_VDDMX_VFL] = &mx_rwmx0_vfl, 854 [RPMPD_SSCCX] = &ssc_cx_rwlc0_lvl, 855 [RPMPD_SSCCX_VFL] = &ssc_cx_rwlc0_vfl, 856 [RPMPD_SSCMX] = &ssc_mx_rwlm0_lvl, 857 [RPMPD_SSCMX_VFL] = &ssc_mx_rwlm0_vfl, 858}; 859 860static const struct rpmpd_desc sdm660_desc = { 861 .rpmpds = sdm660_rpmpds, 862 .num_pds = ARRAY_SIZE(sdm660_rpmpds), 863 .max_state = RPM_SMD_LEVEL_TURBO, 864}; 865 866static struct rpmpd *sm6115_rpmpds[] = { 867 [SM6115_VDDCX] = &cx_rwcx0_lvl, 868 [SM6115_VDDCX_AO] = &cx_rwcx0_lvl_ao, 869 [SM6115_VDDCX_VFL] = &cx_rwcx0_vfl, 870 [SM6115_VDDMX] = &mx_rwmx0_lvl, 871 [SM6115_VDDMX_AO] = &mx_rwmx0_lvl_ao, 872 [SM6115_VDDMX_VFL] = &mx_rwmx0_vfl, 873 [SM6115_VDD_LPI_CX] = &lpi_cx_rwlc0_lvl, 874 [SM6115_VDD_LPI_MX] = &lpi_mx_rwlm0_lvl, 875}; 876 877static const struct rpmpd_desc sm6115_desc = { 878 .rpmpds = sm6115_rpmpds, 879 .num_pds = ARRAY_SIZE(sm6115_rpmpds), 880 .max_state = RPM_SMD_LEVEL_TURBO_NO_CPR, 881}; 882 883static struct rpmpd *sm6125_rpmpds[] = { 884 [RPMPD_VDDCX] = &cx_rwcx0_lvl, 885 [RPMPD_VDDCX_AO] = &cx_rwcx0_lvl_ao, 886 [RPMPD_VDDCX_VFL] = &cx_rwcx0_vfl, 887 [RPMPD_VDDMX] = &mx_rwmx0_lvl, 888 [RPMPD_VDDMX_AO] = &mx_rwmx0_lvl_ao, 889 [RPMPD_VDDMX_VFL] = &mx_rwmx0_vfl, 890}; 891 892static const struct rpmpd_desc sm6125_desc = { 893 .rpmpds = sm6125_rpmpds, 894 .num_pds = ARRAY_SIZE(sm6125_rpmpds), 895 .max_state = RPM_SMD_LEVEL_BINNING, 896}; 897 898static struct rpmpd *sm6375_rpmpds[] = { 899 [SM6375_VDDCX] = &cx_rwcx0_lvl, 900 [SM6375_VDDCX_AO] = &cx_rwcx0_lvl_ao, 901 [SM6375_VDDCX_VFL] = &cx_rwcx0_vfl, 902 [SM6375_VDDMX] = &mx_rwmx0_lvl, 903 [SM6375_VDDMX_AO] = &mx_rwmx0_lvl_ao, 904 [SM6375_VDDMX_VFL] = &mx_rwmx0_vfl, 905 [SM6375_VDDGX] = &gx_rwgx0_lvl, 906 [SM6375_VDDGX_AO] = &gx_rwgx0_lvl_ao, 907 [SM6375_VDD_LPI_CX] = &lpi_cx_rwlc0_lvl, 908 [SM6375_VDD_LPI_MX] = &lpi_mx_rwlm0_lvl, 909}; 910 911static const struct rpmpd_desc sm6375_desc = { 912 .rpmpds = sm6375_rpmpds, 913 .num_pds = ARRAY_SIZE(sm6375_rpmpds), 914 .max_state = RPM_SMD_LEVEL_TURBO_NO_CPR, 915}; 916 917static struct rpmpd *qcm2290_rpmpds[] = { 918 [QCM2290_VDDCX] = &cx_rwcx0_lvl, 919 [QCM2290_VDDCX_AO] = &cx_rwcx0_lvl_ao, 920 [QCM2290_VDDCX_VFL] = &cx_rwcx0_vfl, 921 [QCM2290_VDDMX] = &mx_rwmx0_lvl, 922 [QCM2290_VDDMX_AO] = &mx_rwmx0_lvl_ao, 923 [QCM2290_VDDMX_VFL] = &mx_rwmx0_vfl, 924 [QCM2290_VDD_LPI_CX] = &lpi_cx_rwlc0_lvl, 925 [QCM2290_VDD_LPI_MX] = &lpi_mx_rwlm0_lvl, 926}; 927 928static const struct rpmpd_desc qcm2290_desc = { 929 .rpmpds = qcm2290_rpmpds, 930 .num_pds = ARRAY_SIZE(qcm2290_rpmpds), 931 .max_state = RPM_SMD_LEVEL_TURBO_NO_CPR, 932}; 933 934static const struct of_device_id rpmpd_match_table[] = { 935 { .compatible = "qcom,mdm9607-rpmpd", .data = &mdm9607_desc }, 936 { .compatible = "qcom,msm8226-rpmpd", .data = &msm8226_desc }, 937 { .compatible = "qcom,msm8909-rpmpd", .data = &msm8916_desc }, 938 { .compatible = "qcom,msm8916-rpmpd", .data = &msm8916_desc }, 939 { .compatible = "qcom,msm8917-rpmpd", .data = &msm8917_desc }, 940 { .compatible = "qcom,msm8939-rpmpd", .data = &msm8939_desc }, 941 { .compatible = "qcom,msm8953-rpmpd", .data = &msm8953_desc }, 942 { .compatible = "qcom,msm8974-rpmpd", .data = &msm8974_desc }, 943 { .compatible = "qcom,msm8974pro-pma8084-rpmpd", .data = &msm8974pro_pma8084_desc }, 944 { .compatible = "qcom,msm8976-rpmpd", .data = &msm8976_desc }, 945 { .compatible = "qcom,msm8994-rpmpd", .data = &msm8994_desc }, 946 { .compatible = "qcom,msm8996-rpmpd", .data = &msm8996_desc }, 947 { .compatible = "qcom,msm8998-rpmpd", .data = &msm8998_desc }, 948 { .compatible = "qcom,qcm2290-rpmpd", .data = &qcm2290_desc }, 949 { .compatible = "qcom,qcs404-rpmpd", .data = &qcs404_desc }, 950 { .compatible = "qcom,qm215-rpmpd", .data = &qm215_desc }, 951 { .compatible = "qcom,sdm660-rpmpd", .data = &sdm660_desc }, 952 { .compatible = "qcom,sm6115-rpmpd", .data = &sm6115_desc }, 953 { .compatible = "qcom,sm6125-rpmpd", .data = &sm6125_desc }, 954 { .compatible = "qcom,sm6375-rpmpd", .data = &sm6375_desc }, 955 { } 956}; 957MODULE_DEVICE_TABLE(of, rpmpd_match_table); 958 959static int rpmpd_send_enable(struct rpmpd *pd, bool enable) 960{ 961 struct rpmpd_req req = { 962 .key = KEY_ENABLE, 963 .nbytes = cpu_to_le32(sizeof(u32)), 964 .value = cpu_to_le32(enable), 965 }; 966 967 return qcom_rpm_smd_write(rpmpd_smd_rpm, QCOM_SMD_RPM_ACTIVE_STATE, 968 pd->res_type, pd->res_id, &req, sizeof(req)); 969} 970 971static int rpmpd_send_corner(struct rpmpd *pd, int state, unsigned int corner) 972{ 973 struct rpmpd_req req = { 974 .key = pd->key, 975 .nbytes = cpu_to_le32(sizeof(u32)), 976 .value = cpu_to_le32(corner), 977 }; 978 979 return qcom_rpm_smd_write(rpmpd_smd_rpm, state, pd->res_type, pd->res_id, 980 &req, sizeof(req)); 981}; 982 983static void to_active_sleep(struct rpmpd *pd, unsigned int corner, 984 unsigned int *active, unsigned int *sleep) 985{ 986 *active = corner; 987 988 if (pd->active_only) 989 *sleep = 0; 990 else 991 *sleep = *active; 992} 993 994static int rpmpd_aggregate_corner(struct rpmpd *pd) 995{ 996 int ret; 997 struct rpmpd *peer = pd->peer; 998 unsigned int active_corner, sleep_corner; 999 unsigned int this_active_corner = 0, this_sleep_corner = 0; 1000 unsigned int peer_active_corner = 0, peer_sleep_corner = 0; 1001 1002 /* Clamp to the highest corner/level if sync_state isn't done yet */ 1003 if (!pd->state_synced) 1004 this_active_corner = this_sleep_corner = pd->max_state; 1005 else 1006 to_active_sleep(pd, pd->corner, &this_active_corner, &this_sleep_corner); 1007 1008 if (peer && peer->enabled) 1009 to_active_sleep(peer, peer->corner, &peer_active_corner, 1010 &peer_sleep_corner); 1011 1012 active_corner = max(this_active_corner, peer_active_corner); 1013 1014 ret = rpmpd_send_corner(pd, QCOM_SMD_RPM_ACTIVE_STATE, active_corner); 1015 if (ret) 1016 return ret; 1017 1018 sleep_corner = max(this_sleep_corner, peer_sleep_corner); 1019 1020 return rpmpd_send_corner(pd, QCOM_SMD_RPM_SLEEP_STATE, sleep_corner); 1021} 1022 1023static int rpmpd_power_on(struct generic_pm_domain *domain) 1024{ 1025 int ret; 1026 struct rpmpd *pd = domain_to_rpmpd(domain); 1027 1028 guard(mutex)(&rpmpd_lock); 1029 1030 ret = rpmpd_send_enable(pd, true); 1031 if (ret) 1032 return ret; 1033 1034 pd->enabled = true; 1035 1036 if (pd->corner) 1037 ret = rpmpd_aggregate_corner(pd); 1038 1039 return ret; 1040} 1041 1042static int rpmpd_power_off(struct generic_pm_domain *domain) 1043{ 1044 int ret; 1045 struct rpmpd *pd = domain_to_rpmpd(domain); 1046 1047 mutex_lock(&rpmpd_lock); 1048 1049 ret = rpmpd_send_enable(pd, false); 1050 if (!ret) 1051 pd->enabled = false; 1052 1053 mutex_unlock(&rpmpd_lock); 1054 1055 return ret; 1056} 1057 1058static int rpmpd_set_performance(struct generic_pm_domain *domain, 1059 unsigned int state) 1060{ 1061 struct rpmpd *pd = domain_to_rpmpd(domain); 1062 1063 if (state > pd->max_state) 1064 state = pd->max_state; 1065 1066 guard(mutex)(&rpmpd_lock); 1067 1068 pd->corner = state; 1069 1070 /* Always send updates for vfc and vfl */ 1071 if (!pd->enabled && pd->key != cpu_to_le32(KEY_FLOOR_CORNER) && 1072 pd->key != cpu_to_le32(KEY_FLOOR_LEVEL)) 1073 return 0; 1074 1075 return rpmpd_aggregate_corner(pd); 1076} 1077 1078static int rpmpd_probe(struct platform_device *pdev) 1079{ 1080 int i; 1081 size_t num; 1082 struct genpd_onecell_data *data; 1083 struct rpmpd **rpmpds; 1084 const struct rpmpd_desc *desc; 1085 1086 rpmpd_smd_rpm = dev_get_drvdata(pdev->dev.parent); 1087 if (!rpmpd_smd_rpm) { 1088 dev_err(&pdev->dev, "Unable to retrieve handle to RPM\n"); 1089 return -ENODEV; 1090 } 1091 1092 desc = of_device_get_match_data(&pdev->dev); 1093 if (!desc) 1094 return -EINVAL; 1095 1096 rpmpds = desc->rpmpds; 1097 num = desc->num_pds; 1098 1099 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 1100 if (!data) 1101 return -ENOMEM; 1102 1103 data->domains = devm_kcalloc(&pdev->dev, num, sizeof(*data->domains), 1104 GFP_KERNEL); 1105 if (!data->domains) 1106 return -ENOMEM; 1107 1108 data->num_domains = num; 1109 1110 for (i = 0; i < num; i++) { 1111 if (!rpmpds[i]) { 1112 dev_warn(&pdev->dev, "rpmpds[] with empty entry at index=%d\n", 1113 i); 1114 continue; 1115 } 1116 1117 rpmpds[i]->max_state = desc->max_state; 1118 rpmpds[i]->pd.power_off = rpmpd_power_off; 1119 rpmpds[i]->pd.power_on = rpmpd_power_on; 1120 rpmpds[i]->pd.set_performance_state = rpmpd_set_performance; 1121 rpmpds[i]->pd.flags = GENPD_FLAG_ACTIVE_WAKEUP; 1122 pm_genpd_init(&rpmpds[i]->pd, NULL, true); 1123 1124 data->domains[i] = &rpmpds[i]->pd; 1125 } 1126 1127 /* Add subdomains */ 1128 for (i = 0; i < num; i++) { 1129 if (!rpmpds[i]) 1130 continue; 1131 1132 if (rpmpds[i]->parent) 1133 pm_genpd_add_subdomain(rpmpds[i]->parent, &rpmpds[i]->pd); 1134 } 1135 1136 return of_genpd_add_provider_onecell(pdev->dev.of_node, data); 1137} 1138 1139static void rpmpd_sync_state(struct device *dev) 1140{ 1141 const struct rpmpd_desc *desc = of_device_get_match_data(dev); 1142 struct rpmpd **rpmpds = desc->rpmpds; 1143 struct rpmpd *pd; 1144 unsigned int i; 1145 int ret; 1146 1147 of_genpd_sync_state(dev->of_node); 1148 1149 mutex_lock(&rpmpd_lock); 1150 for (i = 0; i < desc->num_pds; i++) { 1151 pd = rpmpds[i]; 1152 if (!pd) 1153 continue; 1154 1155 pd->state_synced = true; 1156 1157 if (!pd->enabled) 1158 pd->corner = 0; 1159 1160 ret = rpmpd_aggregate_corner(pd); 1161 if (ret) 1162 dev_err(dev, "failed to sync %s: %d\n", pd->pd.name, ret); 1163 } 1164 mutex_unlock(&rpmpd_lock); 1165} 1166 1167static struct platform_driver rpmpd_driver = { 1168 .driver = { 1169 .name = "qcom-rpmpd", 1170 .of_match_table = rpmpd_match_table, 1171 .suppress_bind_attrs = true, 1172 .sync_state = rpmpd_sync_state, 1173 }, 1174 .probe = rpmpd_probe, 1175}; 1176 1177static int __init rpmpd_init(void) 1178{ 1179 return platform_driver_register(&rpmpd_driver); 1180} 1181core_initcall(rpmpd_init); 1182 1183MODULE_DESCRIPTION("Qualcomm Technologies, Inc. RPM Power Domain Driver"); 1184MODULE_LICENSE("GPL v2");
~/
Read-only file preview.