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