Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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