162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright (c) 2018, The Linux Foundation. All rights reserved.*/ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/err.h> 562306a36Sopenharmony_ci#include <linux/init.h> 662306a36Sopenharmony_ci#include <linux/kernel.h> 762306a36Sopenharmony_ci#include <linux/module.h> 862306a36Sopenharmony_ci#include <linux/mutex.h> 962306a36Sopenharmony_ci#include <linux/pm_domain.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include <linux/of.h> 1262306a36Sopenharmony_ci#include <linux/platform_device.h> 1362306a36Sopenharmony_ci#include <linux/pm_opp.h> 1462306a36Sopenharmony_ci#include <soc/qcom/cmd-db.h> 1562306a36Sopenharmony_ci#include <soc/qcom/rpmh.h> 1662306a36Sopenharmony_ci#include <dt-bindings/power/qcom-rpmpd.h> 1762306a36Sopenharmony_ci#include <dt-bindings/power/qcom,rpmhpd.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define domain_to_rpmhpd(domain) container_of(domain, struct rpmhpd, pd) 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define RPMH_ARC_MAX_LEVELS 16 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/** 2462306a36Sopenharmony_ci * struct rpmhpd - top level RPMh power domain resource data structure 2562306a36Sopenharmony_ci * @dev: rpmh power domain controller device 2662306a36Sopenharmony_ci * @pd: generic_pm_domain corresponding to the power domain 2762306a36Sopenharmony_ci * @parent: generic_pm_domain corresponding to the parent's power domain 2862306a36Sopenharmony_ci * @peer: A peer power domain in case Active only Voting is 2962306a36Sopenharmony_ci * supported 3062306a36Sopenharmony_ci * @active_only: True if it represents an Active only peer 3162306a36Sopenharmony_ci * @corner: current corner 3262306a36Sopenharmony_ci * @active_corner: current active corner 3362306a36Sopenharmony_ci * @enable_corner: lowest non-zero corner 3462306a36Sopenharmony_ci * @level: An array of level (vlvl) to corner (hlvl) mappings 3562306a36Sopenharmony_ci * derived from cmd-db 3662306a36Sopenharmony_ci * @level_count: Number of levels supported by the power domain. max 3762306a36Sopenharmony_ci * being 16 (0 - 15) 3862306a36Sopenharmony_ci * @enabled: true if the power domain is enabled 3962306a36Sopenharmony_ci * @res_name: Resource name used for cmd-db lookup 4062306a36Sopenharmony_ci * @addr: Resource address as looped up using resource name from 4162306a36Sopenharmony_ci * cmd-db 4262306a36Sopenharmony_ci * @state_synced: Indicator that sync_state has been invoked for the rpmhpd resource 4362306a36Sopenharmony_ci */ 4462306a36Sopenharmony_cistruct rpmhpd { 4562306a36Sopenharmony_ci struct device *dev; 4662306a36Sopenharmony_ci struct generic_pm_domain pd; 4762306a36Sopenharmony_ci struct generic_pm_domain *parent; 4862306a36Sopenharmony_ci struct rpmhpd *peer; 4962306a36Sopenharmony_ci const bool active_only; 5062306a36Sopenharmony_ci unsigned int corner; 5162306a36Sopenharmony_ci unsigned int active_corner; 5262306a36Sopenharmony_ci unsigned int enable_corner; 5362306a36Sopenharmony_ci u32 level[RPMH_ARC_MAX_LEVELS]; 5462306a36Sopenharmony_ci size_t level_count; 5562306a36Sopenharmony_ci bool enabled; 5662306a36Sopenharmony_ci const char *res_name; 5762306a36Sopenharmony_ci u32 addr; 5862306a36Sopenharmony_ci bool state_synced; 5962306a36Sopenharmony_ci}; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistruct rpmhpd_desc { 6262306a36Sopenharmony_ci struct rpmhpd **rpmhpds; 6362306a36Sopenharmony_ci size_t num_pds; 6462306a36Sopenharmony_ci}; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic DEFINE_MUTEX(rpmhpd_lock); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* RPMH powerdomains */ 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic struct rpmhpd cx_ao; 7162306a36Sopenharmony_cistatic struct rpmhpd mx; 7262306a36Sopenharmony_cistatic struct rpmhpd mx_ao; 7362306a36Sopenharmony_cistatic struct rpmhpd cx = { 7462306a36Sopenharmony_ci .pd = { .name = "cx", }, 7562306a36Sopenharmony_ci .peer = &cx_ao, 7662306a36Sopenharmony_ci .res_name = "cx.lvl", 7762306a36Sopenharmony_ci}; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic struct rpmhpd cx_ao = { 8062306a36Sopenharmony_ci .pd = { .name = "cx_ao", }, 8162306a36Sopenharmony_ci .active_only = true, 8262306a36Sopenharmony_ci .peer = &cx, 8362306a36Sopenharmony_ci .res_name = "cx.lvl", 8462306a36Sopenharmony_ci}; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic struct rpmhpd cx_ao_w_mx_parent; 8762306a36Sopenharmony_cistatic struct rpmhpd cx_w_mx_parent = { 8862306a36Sopenharmony_ci .pd = { .name = "cx", }, 8962306a36Sopenharmony_ci .peer = &cx_ao_w_mx_parent, 9062306a36Sopenharmony_ci .parent = &mx.pd, 9162306a36Sopenharmony_ci .res_name = "cx.lvl", 9262306a36Sopenharmony_ci}; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic struct rpmhpd cx_ao_w_mx_parent = { 9562306a36Sopenharmony_ci .pd = { .name = "cx_ao", }, 9662306a36Sopenharmony_ci .active_only = true, 9762306a36Sopenharmony_ci .peer = &cx_w_mx_parent, 9862306a36Sopenharmony_ci .parent = &mx_ao.pd, 9962306a36Sopenharmony_ci .res_name = "cx.lvl", 10062306a36Sopenharmony_ci}; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic struct rpmhpd ebi = { 10362306a36Sopenharmony_ci .pd = { .name = "ebi", }, 10462306a36Sopenharmony_ci .res_name = "ebi.lvl", 10562306a36Sopenharmony_ci}; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic struct rpmhpd gfx = { 10862306a36Sopenharmony_ci .pd = { .name = "gfx", }, 10962306a36Sopenharmony_ci .res_name = "gfx.lvl", 11062306a36Sopenharmony_ci}; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic struct rpmhpd lcx = { 11362306a36Sopenharmony_ci .pd = { .name = "lcx", }, 11462306a36Sopenharmony_ci .res_name = "lcx.lvl", 11562306a36Sopenharmony_ci}; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic struct rpmhpd lmx = { 11862306a36Sopenharmony_ci .pd = { .name = "lmx", }, 11962306a36Sopenharmony_ci .res_name = "lmx.lvl", 12062306a36Sopenharmony_ci}; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic struct rpmhpd mmcx_ao; 12362306a36Sopenharmony_cistatic struct rpmhpd mmcx = { 12462306a36Sopenharmony_ci .pd = { .name = "mmcx", }, 12562306a36Sopenharmony_ci .peer = &mmcx_ao, 12662306a36Sopenharmony_ci .res_name = "mmcx.lvl", 12762306a36Sopenharmony_ci}; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic struct rpmhpd mmcx_ao = { 13062306a36Sopenharmony_ci .pd = { .name = "mmcx_ao", }, 13162306a36Sopenharmony_ci .active_only = true, 13262306a36Sopenharmony_ci .peer = &mmcx, 13362306a36Sopenharmony_ci .res_name = "mmcx.lvl", 13462306a36Sopenharmony_ci}; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic struct rpmhpd mmcx_ao_w_cx_parent; 13762306a36Sopenharmony_cistatic struct rpmhpd mmcx_w_cx_parent = { 13862306a36Sopenharmony_ci .pd = { .name = "mmcx", }, 13962306a36Sopenharmony_ci .peer = &mmcx_ao_w_cx_parent, 14062306a36Sopenharmony_ci .parent = &cx.pd, 14162306a36Sopenharmony_ci .res_name = "mmcx.lvl", 14262306a36Sopenharmony_ci}; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic struct rpmhpd mmcx_ao_w_cx_parent = { 14562306a36Sopenharmony_ci .pd = { .name = "mmcx_ao", }, 14662306a36Sopenharmony_ci .active_only = true, 14762306a36Sopenharmony_ci .peer = &mmcx_w_cx_parent, 14862306a36Sopenharmony_ci .parent = &cx_ao.pd, 14962306a36Sopenharmony_ci .res_name = "mmcx.lvl", 15062306a36Sopenharmony_ci}; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic struct rpmhpd mss = { 15362306a36Sopenharmony_ci .pd = { .name = "mss", }, 15462306a36Sopenharmony_ci .res_name = "mss.lvl", 15562306a36Sopenharmony_ci}; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic struct rpmhpd mx_ao; 15862306a36Sopenharmony_cistatic struct rpmhpd mx = { 15962306a36Sopenharmony_ci .pd = { .name = "mx", }, 16062306a36Sopenharmony_ci .peer = &mx_ao, 16162306a36Sopenharmony_ci .res_name = "mx.lvl", 16262306a36Sopenharmony_ci}; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic struct rpmhpd mx_ao = { 16562306a36Sopenharmony_ci .pd = { .name = "mx_ao", }, 16662306a36Sopenharmony_ci .active_only = true, 16762306a36Sopenharmony_ci .peer = &mx, 16862306a36Sopenharmony_ci .res_name = "mx.lvl", 16962306a36Sopenharmony_ci}; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic struct rpmhpd mxc_ao; 17262306a36Sopenharmony_cistatic struct rpmhpd mxc = { 17362306a36Sopenharmony_ci .pd = { .name = "mxc", }, 17462306a36Sopenharmony_ci .peer = &mxc_ao, 17562306a36Sopenharmony_ci .res_name = "mxc.lvl", 17662306a36Sopenharmony_ci}; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic struct rpmhpd mxc_ao = { 17962306a36Sopenharmony_ci .pd = { .name = "mxc_ao", }, 18062306a36Sopenharmony_ci .active_only = true, 18162306a36Sopenharmony_ci .peer = &mxc, 18262306a36Sopenharmony_ci .res_name = "mxc.lvl", 18362306a36Sopenharmony_ci}; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic struct rpmhpd nsp = { 18662306a36Sopenharmony_ci .pd = { .name = "nsp", }, 18762306a36Sopenharmony_ci .res_name = "nsp.lvl", 18862306a36Sopenharmony_ci}; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic struct rpmhpd nsp0 = { 19162306a36Sopenharmony_ci .pd = { .name = "nsp0", }, 19262306a36Sopenharmony_ci .res_name = "nsp0.lvl", 19362306a36Sopenharmony_ci}; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic struct rpmhpd nsp1 = { 19662306a36Sopenharmony_ci .pd = { .name = "nsp1", }, 19762306a36Sopenharmony_ci .res_name = "nsp1.lvl", 19862306a36Sopenharmony_ci}; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic struct rpmhpd qphy = { 20162306a36Sopenharmony_ci .pd = { .name = "qphy", }, 20262306a36Sopenharmony_ci .res_name = "qphy.lvl", 20362306a36Sopenharmony_ci}; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci/* SA8540P RPMH powerdomains */ 20662306a36Sopenharmony_cistatic struct rpmhpd *sa8540p_rpmhpds[] = { 20762306a36Sopenharmony_ci [SC8280XP_CX] = &cx, 20862306a36Sopenharmony_ci [SC8280XP_CX_AO] = &cx_ao, 20962306a36Sopenharmony_ci [SC8280XP_EBI] = &ebi, 21062306a36Sopenharmony_ci [SC8280XP_LCX] = &lcx, 21162306a36Sopenharmony_ci [SC8280XP_LMX] = &lmx, 21262306a36Sopenharmony_ci [SC8280XP_MMCX] = &mmcx, 21362306a36Sopenharmony_ci [SC8280XP_MMCX_AO] = &mmcx_ao, 21462306a36Sopenharmony_ci [SC8280XP_MX] = &mx, 21562306a36Sopenharmony_ci [SC8280XP_MX_AO] = &mx_ao, 21662306a36Sopenharmony_ci [SC8280XP_NSP] = &nsp, 21762306a36Sopenharmony_ci}; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic const struct rpmhpd_desc sa8540p_desc = { 22062306a36Sopenharmony_ci .rpmhpds = sa8540p_rpmhpds, 22162306a36Sopenharmony_ci .num_pds = ARRAY_SIZE(sa8540p_rpmhpds), 22262306a36Sopenharmony_ci}; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci/* SA8775P RPMH power domains */ 22562306a36Sopenharmony_cistatic struct rpmhpd *sa8775p_rpmhpds[] = { 22662306a36Sopenharmony_ci [SA8775P_CX] = &cx, 22762306a36Sopenharmony_ci [SA8775P_CX_AO] = &cx_ao, 22862306a36Sopenharmony_ci [SA8775P_EBI] = &ebi, 22962306a36Sopenharmony_ci [SA8775P_GFX] = &gfx, 23062306a36Sopenharmony_ci [SA8775P_LCX] = &lcx, 23162306a36Sopenharmony_ci [SA8775P_LMX] = &lmx, 23262306a36Sopenharmony_ci [SA8775P_MMCX] = &mmcx, 23362306a36Sopenharmony_ci [SA8775P_MMCX_AO] = &mmcx_ao, 23462306a36Sopenharmony_ci [SA8775P_MXC] = &mxc, 23562306a36Sopenharmony_ci [SA8775P_MXC_AO] = &mxc_ao, 23662306a36Sopenharmony_ci [SA8775P_MX] = &mx, 23762306a36Sopenharmony_ci [SA8775P_MX_AO] = &mx_ao, 23862306a36Sopenharmony_ci [SA8775P_NSP0] = &nsp0, 23962306a36Sopenharmony_ci [SA8775P_NSP1] = &nsp1, 24062306a36Sopenharmony_ci}; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic const struct rpmhpd_desc sa8775p_desc = { 24362306a36Sopenharmony_ci .rpmhpds = sa8775p_rpmhpds, 24462306a36Sopenharmony_ci .num_pds = ARRAY_SIZE(sa8775p_rpmhpds), 24562306a36Sopenharmony_ci}; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci/* SDM670 RPMH powerdomains */ 24862306a36Sopenharmony_cistatic struct rpmhpd *sdm670_rpmhpds[] = { 24962306a36Sopenharmony_ci [SDM670_CX] = &cx_w_mx_parent, 25062306a36Sopenharmony_ci [SDM670_CX_AO] = &cx_ao_w_mx_parent, 25162306a36Sopenharmony_ci [SDM670_GFX] = &gfx, 25262306a36Sopenharmony_ci [SDM670_LCX] = &lcx, 25362306a36Sopenharmony_ci [SDM670_LMX] = &lmx, 25462306a36Sopenharmony_ci [SDM670_MSS] = &mss, 25562306a36Sopenharmony_ci [SDM670_MX] = &mx, 25662306a36Sopenharmony_ci [SDM670_MX_AO] = &mx_ao, 25762306a36Sopenharmony_ci}; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic const struct rpmhpd_desc sdm670_desc = { 26062306a36Sopenharmony_ci .rpmhpds = sdm670_rpmhpds, 26162306a36Sopenharmony_ci .num_pds = ARRAY_SIZE(sdm670_rpmhpds), 26262306a36Sopenharmony_ci}; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci/* SDM845 RPMH powerdomains */ 26562306a36Sopenharmony_cistatic struct rpmhpd *sdm845_rpmhpds[] = { 26662306a36Sopenharmony_ci [SDM845_CX] = &cx_w_mx_parent, 26762306a36Sopenharmony_ci [SDM845_CX_AO] = &cx_ao_w_mx_parent, 26862306a36Sopenharmony_ci [SDM845_EBI] = &ebi, 26962306a36Sopenharmony_ci [SDM845_GFX] = &gfx, 27062306a36Sopenharmony_ci [SDM845_LCX] = &lcx, 27162306a36Sopenharmony_ci [SDM845_LMX] = &lmx, 27262306a36Sopenharmony_ci [SDM845_MSS] = &mss, 27362306a36Sopenharmony_ci [SDM845_MX] = &mx, 27462306a36Sopenharmony_ci [SDM845_MX_AO] = &mx_ao, 27562306a36Sopenharmony_ci}; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic const struct rpmhpd_desc sdm845_desc = { 27862306a36Sopenharmony_ci .rpmhpds = sdm845_rpmhpds, 27962306a36Sopenharmony_ci .num_pds = ARRAY_SIZE(sdm845_rpmhpds), 28062306a36Sopenharmony_ci}; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci/* SDX55 RPMH powerdomains */ 28362306a36Sopenharmony_cistatic struct rpmhpd *sdx55_rpmhpds[] = { 28462306a36Sopenharmony_ci [SDX55_CX] = &cx_w_mx_parent, 28562306a36Sopenharmony_ci [SDX55_MSS] = &mss, 28662306a36Sopenharmony_ci [SDX55_MX] = &mx, 28762306a36Sopenharmony_ci}; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic const struct rpmhpd_desc sdx55_desc = { 29062306a36Sopenharmony_ci .rpmhpds = sdx55_rpmhpds, 29162306a36Sopenharmony_ci .num_pds = ARRAY_SIZE(sdx55_rpmhpds), 29262306a36Sopenharmony_ci}; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci/* SDX65 RPMH powerdomains */ 29562306a36Sopenharmony_cistatic struct rpmhpd *sdx65_rpmhpds[] = { 29662306a36Sopenharmony_ci [SDX65_CX] = &cx_w_mx_parent, 29762306a36Sopenharmony_ci [SDX65_CX_AO] = &cx_ao_w_mx_parent, 29862306a36Sopenharmony_ci [SDX65_MSS] = &mss, 29962306a36Sopenharmony_ci [SDX65_MX] = &mx, 30062306a36Sopenharmony_ci [SDX65_MX_AO] = &mx_ao, 30162306a36Sopenharmony_ci [SDX65_MXC] = &mxc, 30262306a36Sopenharmony_ci}; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic const struct rpmhpd_desc sdx65_desc = { 30562306a36Sopenharmony_ci .rpmhpds = sdx65_rpmhpds, 30662306a36Sopenharmony_ci .num_pds = ARRAY_SIZE(sdx65_rpmhpds), 30762306a36Sopenharmony_ci}; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci/* SDX75 RPMH powerdomains */ 31062306a36Sopenharmony_cistatic struct rpmhpd *sdx75_rpmhpds[] = { 31162306a36Sopenharmony_ci [RPMHPD_CX] = &cx, 31262306a36Sopenharmony_ci [RPMHPD_CX_AO] = &cx_ao, 31362306a36Sopenharmony_ci [RPMHPD_MSS] = &mss, 31462306a36Sopenharmony_ci [RPMHPD_MX] = &mx, 31562306a36Sopenharmony_ci [RPMHPD_MX_AO] = &mx_ao, 31662306a36Sopenharmony_ci [RPMHPD_MXC] = &mxc, 31762306a36Sopenharmony_ci}; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic const struct rpmhpd_desc sdx75_desc = { 32062306a36Sopenharmony_ci .rpmhpds = sdx75_rpmhpds, 32162306a36Sopenharmony_ci .num_pds = ARRAY_SIZE(sdx75_rpmhpds), 32262306a36Sopenharmony_ci}; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci/* SM6350 RPMH powerdomains */ 32562306a36Sopenharmony_cistatic struct rpmhpd *sm6350_rpmhpds[] = { 32662306a36Sopenharmony_ci [SM6350_CX] = &cx_w_mx_parent, 32762306a36Sopenharmony_ci [SM6350_GFX] = &gfx, 32862306a36Sopenharmony_ci [SM6350_LCX] = &lcx, 32962306a36Sopenharmony_ci [SM6350_LMX] = &lmx, 33062306a36Sopenharmony_ci [SM6350_MSS] = &mss, 33162306a36Sopenharmony_ci [SM6350_MX] = &mx, 33262306a36Sopenharmony_ci}; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic const struct rpmhpd_desc sm6350_desc = { 33562306a36Sopenharmony_ci .rpmhpds = sm6350_rpmhpds, 33662306a36Sopenharmony_ci .num_pds = ARRAY_SIZE(sm6350_rpmhpds), 33762306a36Sopenharmony_ci}; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci/* SM8150 RPMH powerdomains */ 34062306a36Sopenharmony_cistatic struct rpmhpd *sm8150_rpmhpds[] = { 34162306a36Sopenharmony_ci [SM8150_CX] = &cx_w_mx_parent, 34262306a36Sopenharmony_ci [SM8150_CX_AO] = &cx_ao_w_mx_parent, 34362306a36Sopenharmony_ci [SM8150_EBI] = &ebi, 34462306a36Sopenharmony_ci [SM8150_GFX] = &gfx, 34562306a36Sopenharmony_ci [SM8150_LCX] = &lcx, 34662306a36Sopenharmony_ci [SM8150_LMX] = &lmx, 34762306a36Sopenharmony_ci [SM8150_MMCX] = &mmcx, 34862306a36Sopenharmony_ci [SM8150_MMCX_AO] = &mmcx_ao, 34962306a36Sopenharmony_ci [SM8150_MSS] = &mss, 35062306a36Sopenharmony_ci [SM8150_MX] = &mx, 35162306a36Sopenharmony_ci [SM8150_MX_AO] = &mx_ao, 35262306a36Sopenharmony_ci}; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistatic const struct rpmhpd_desc sm8150_desc = { 35562306a36Sopenharmony_ci .rpmhpds = sm8150_rpmhpds, 35662306a36Sopenharmony_ci .num_pds = ARRAY_SIZE(sm8150_rpmhpds), 35762306a36Sopenharmony_ci}; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_cistatic struct rpmhpd *sa8155p_rpmhpds[] = { 36062306a36Sopenharmony_ci [SA8155P_CX] = &cx_w_mx_parent, 36162306a36Sopenharmony_ci [SA8155P_CX_AO] = &cx_ao_w_mx_parent, 36262306a36Sopenharmony_ci [SA8155P_EBI] = &ebi, 36362306a36Sopenharmony_ci [SA8155P_GFX] = &gfx, 36462306a36Sopenharmony_ci [SA8155P_MSS] = &mss, 36562306a36Sopenharmony_ci [SA8155P_MX] = &mx, 36662306a36Sopenharmony_ci [SA8155P_MX_AO] = &mx_ao, 36762306a36Sopenharmony_ci}; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic const struct rpmhpd_desc sa8155p_desc = { 37062306a36Sopenharmony_ci .rpmhpds = sa8155p_rpmhpds, 37162306a36Sopenharmony_ci .num_pds = ARRAY_SIZE(sa8155p_rpmhpds), 37262306a36Sopenharmony_ci}; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci/* SM8250 RPMH powerdomains */ 37562306a36Sopenharmony_cistatic struct rpmhpd *sm8250_rpmhpds[] = { 37662306a36Sopenharmony_ci [RPMHPD_CX] = &cx_w_mx_parent, 37762306a36Sopenharmony_ci [RPMHPD_CX_AO] = &cx_ao_w_mx_parent, 37862306a36Sopenharmony_ci [RPMHPD_EBI] = &ebi, 37962306a36Sopenharmony_ci [RPMHPD_GFX] = &gfx, 38062306a36Sopenharmony_ci [RPMHPD_LCX] = &lcx, 38162306a36Sopenharmony_ci [RPMHPD_LMX] = &lmx, 38262306a36Sopenharmony_ci [RPMHPD_MMCX] = &mmcx, 38362306a36Sopenharmony_ci [RPMHPD_MMCX_AO] = &mmcx_ao, 38462306a36Sopenharmony_ci [RPMHPD_MX] = &mx, 38562306a36Sopenharmony_ci [RPMHPD_MX_AO] = &mx_ao, 38662306a36Sopenharmony_ci}; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic const struct rpmhpd_desc sm8250_desc = { 38962306a36Sopenharmony_ci .rpmhpds = sm8250_rpmhpds, 39062306a36Sopenharmony_ci .num_pds = ARRAY_SIZE(sm8250_rpmhpds), 39162306a36Sopenharmony_ci}; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci/* SM8350 Power domains */ 39462306a36Sopenharmony_cistatic struct rpmhpd *sm8350_rpmhpds[] = { 39562306a36Sopenharmony_ci [RPMHPD_CX] = &cx_w_mx_parent, 39662306a36Sopenharmony_ci [RPMHPD_CX_AO] = &cx_ao_w_mx_parent, 39762306a36Sopenharmony_ci [RPMHPD_EBI] = &ebi, 39862306a36Sopenharmony_ci [RPMHPD_GFX] = &gfx, 39962306a36Sopenharmony_ci [RPMHPD_LCX] = &lcx, 40062306a36Sopenharmony_ci [RPMHPD_LMX] = &lmx, 40162306a36Sopenharmony_ci [RPMHPD_MMCX] = &mmcx, 40262306a36Sopenharmony_ci [RPMHPD_MMCX_AO] = &mmcx_ao, 40362306a36Sopenharmony_ci [RPMHPD_MSS] = &mss, 40462306a36Sopenharmony_ci [RPMHPD_MX] = &mx, 40562306a36Sopenharmony_ci [RPMHPD_MX_AO] = &mx_ao, 40662306a36Sopenharmony_ci [RPMHPD_MXC] = &mxc, 40762306a36Sopenharmony_ci [RPMHPD_MXC_AO] = &mxc_ao, 40862306a36Sopenharmony_ci}; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistatic const struct rpmhpd_desc sm8350_desc = { 41162306a36Sopenharmony_ci .rpmhpds = sm8350_rpmhpds, 41262306a36Sopenharmony_ci .num_pds = ARRAY_SIZE(sm8350_rpmhpds), 41362306a36Sopenharmony_ci}; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci/* SM8450 RPMH powerdomains */ 41662306a36Sopenharmony_cistatic struct rpmhpd *sm8450_rpmhpds[] = { 41762306a36Sopenharmony_ci [RPMHPD_CX] = &cx, 41862306a36Sopenharmony_ci [RPMHPD_CX_AO] = &cx_ao, 41962306a36Sopenharmony_ci [RPMHPD_EBI] = &ebi, 42062306a36Sopenharmony_ci [RPMHPD_GFX] = &gfx, 42162306a36Sopenharmony_ci [RPMHPD_LCX] = &lcx, 42262306a36Sopenharmony_ci [RPMHPD_LMX] = &lmx, 42362306a36Sopenharmony_ci [RPMHPD_MMCX] = &mmcx_w_cx_parent, 42462306a36Sopenharmony_ci [RPMHPD_MMCX_AO] = &mmcx_ao_w_cx_parent, 42562306a36Sopenharmony_ci [RPMHPD_MSS] = &mss, 42662306a36Sopenharmony_ci [RPMHPD_MX] = &mx, 42762306a36Sopenharmony_ci [RPMHPD_MX_AO] = &mx_ao, 42862306a36Sopenharmony_ci [RPMHPD_MXC] = &mxc, 42962306a36Sopenharmony_ci [RPMHPD_MXC_AO] = &mxc_ao, 43062306a36Sopenharmony_ci}; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cistatic const struct rpmhpd_desc sm8450_desc = { 43362306a36Sopenharmony_ci .rpmhpds = sm8450_rpmhpds, 43462306a36Sopenharmony_ci .num_pds = ARRAY_SIZE(sm8450_rpmhpds), 43562306a36Sopenharmony_ci}; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci/* SM8550 RPMH powerdomains */ 43862306a36Sopenharmony_cistatic struct rpmhpd *sm8550_rpmhpds[] = { 43962306a36Sopenharmony_ci [RPMHPD_CX] = &cx, 44062306a36Sopenharmony_ci [RPMHPD_CX_AO] = &cx_ao, 44162306a36Sopenharmony_ci [RPMHPD_EBI] = &ebi, 44262306a36Sopenharmony_ci [RPMHPD_GFX] = &gfx, 44362306a36Sopenharmony_ci [RPMHPD_LCX] = &lcx, 44462306a36Sopenharmony_ci [RPMHPD_LMX] = &lmx, 44562306a36Sopenharmony_ci [RPMHPD_MMCX] = &mmcx_w_cx_parent, 44662306a36Sopenharmony_ci [RPMHPD_MMCX_AO] = &mmcx_ao_w_cx_parent, 44762306a36Sopenharmony_ci [RPMHPD_MSS] = &mss, 44862306a36Sopenharmony_ci [RPMHPD_MX] = &mx, 44962306a36Sopenharmony_ci [RPMHPD_MX_AO] = &mx_ao, 45062306a36Sopenharmony_ci [RPMHPD_MXC] = &mxc, 45162306a36Sopenharmony_ci [RPMHPD_MXC_AO] = &mxc_ao, 45262306a36Sopenharmony_ci [RPMHPD_NSP] = &nsp, 45362306a36Sopenharmony_ci}; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic const struct rpmhpd_desc sm8550_desc = { 45662306a36Sopenharmony_ci .rpmhpds = sm8550_rpmhpds, 45762306a36Sopenharmony_ci .num_pds = ARRAY_SIZE(sm8550_rpmhpds), 45862306a36Sopenharmony_ci}; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci/* QDU1000/QRU1000 RPMH powerdomains */ 46162306a36Sopenharmony_cistatic struct rpmhpd *qdu1000_rpmhpds[] = { 46262306a36Sopenharmony_ci [QDU1000_CX] = &cx, 46362306a36Sopenharmony_ci [QDU1000_EBI] = &ebi, 46462306a36Sopenharmony_ci [QDU1000_MSS] = &mss, 46562306a36Sopenharmony_ci [QDU1000_MX] = &mx, 46662306a36Sopenharmony_ci}; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cistatic const struct rpmhpd_desc qdu1000_desc = { 46962306a36Sopenharmony_ci .rpmhpds = qdu1000_rpmhpds, 47062306a36Sopenharmony_ci .num_pds = ARRAY_SIZE(qdu1000_rpmhpds), 47162306a36Sopenharmony_ci}; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci/* SC7180 RPMH powerdomains */ 47462306a36Sopenharmony_cistatic struct rpmhpd *sc7180_rpmhpds[] = { 47562306a36Sopenharmony_ci [SC7180_CX] = &cx_w_mx_parent, 47662306a36Sopenharmony_ci [SC7180_CX_AO] = &cx_ao_w_mx_parent, 47762306a36Sopenharmony_ci [SC7180_GFX] = &gfx, 47862306a36Sopenharmony_ci [SC7180_LCX] = &lcx, 47962306a36Sopenharmony_ci [SC7180_LMX] = &lmx, 48062306a36Sopenharmony_ci [SC7180_MSS] = &mss, 48162306a36Sopenharmony_ci [SC7180_MX] = &mx, 48262306a36Sopenharmony_ci [SC7180_MX_AO] = &mx_ao, 48362306a36Sopenharmony_ci}; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_cistatic const struct rpmhpd_desc sc7180_desc = { 48662306a36Sopenharmony_ci .rpmhpds = sc7180_rpmhpds, 48762306a36Sopenharmony_ci .num_pds = ARRAY_SIZE(sc7180_rpmhpds), 48862306a36Sopenharmony_ci}; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci/* SC7280 RPMH powerdomains */ 49162306a36Sopenharmony_cistatic struct rpmhpd *sc7280_rpmhpds[] = { 49262306a36Sopenharmony_ci [SC7280_CX] = &cx, 49362306a36Sopenharmony_ci [SC7280_CX_AO] = &cx_ao, 49462306a36Sopenharmony_ci [SC7280_EBI] = &ebi, 49562306a36Sopenharmony_ci [SC7280_GFX] = &gfx, 49662306a36Sopenharmony_ci [SC7280_LCX] = &lcx, 49762306a36Sopenharmony_ci [SC7280_LMX] = &lmx, 49862306a36Sopenharmony_ci [SC7280_MSS] = &mss, 49962306a36Sopenharmony_ci [SC7280_MX] = &mx, 50062306a36Sopenharmony_ci [SC7280_MX_AO] = &mx_ao, 50162306a36Sopenharmony_ci}; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_cistatic const struct rpmhpd_desc sc7280_desc = { 50462306a36Sopenharmony_ci .rpmhpds = sc7280_rpmhpds, 50562306a36Sopenharmony_ci .num_pds = ARRAY_SIZE(sc7280_rpmhpds), 50662306a36Sopenharmony_ci}; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci/* SC8180x RPMH powerdomains */ 50962306a36Sopenharmony_cistatic struct rpmhpd *sc8180x_rpmhpds[] = { 51062306a36Sopenharmony_ci [SC8180X_CX] = &cx_w_mx_parent, 51162306a36Sopenharmony_ci [SC8180X_CX_AO] = &cx_ao_w_mx_parent, 51262306a36Sopenharmony_ci [SC8180X_EBI] = &ebi, 51362306a36Sopenharmony_ci [SC8180X_GFX] = &gfx, 51462306a36Sopenharmony_ci [SC8180X_LCX] = &lcx, 51562306a36Sopenharmony_ci [SC8180X_LMX] = &lmx, 51662306a36Sopenharmony_ci [SC8180X_MMCX] = &mmcx, 51762306a36Sopenharmony_ci [SC8180X_MMCX_AO] = &mmcx_ao, 51862306a36Sopenharmony_ci [SC8180X_MSS] = &mss, 51962306a36Sopenharmony_ci [SC8180X_MX] = &mx, 52062306a36Sopenharmony_ci [SC8180X_MX_AO] = &mx_ao, 52162306a36Sopenharmony_ci}; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic const struct rpmhpd_desc sc8180x_desc = { 52462306a36Sopenharmony_ci .rpmhpds = sc8180x_rpmhpds, 52562306a36Sopenharmony_ci .num_pds = ARRAY_SIZE(sc8180x_rpmhpds), 52662306a36Sopenharmony_ci}; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci/* SC8280xp RPMH powerdomains */ 52962306a36Sopenharmony_cistatic struct rpmhpd *sc8280xp_rpmhpds[] = { 53062306a36Sopenharmony_ci [SC8280XP_CX] = &cx, 53162306a36Sopenharmony_ci [SC8280XP_CX_AO] = &cx_ao, 53262306a36Sopenharmony_ci [SC8280XP_EBI] = &ebi, 53362306a36Sopenharmony_ci [SC8280XP_GFX] = &gfx, 53462306a36Sopenharmony_ci [SC8280XP_LCX] = &lcx, 53562306a36Sopenharmony_ci [SC8280XP_LMX] = &lmx, 53662306a36Sopenharmony_ci [SC8280XP_MMCX] = &mmcx, 53762306a36Sopenharmony_ci [SC8280XP_MMCX_AO] = &mmcx_ao, 53862306a36Sopenharmony_ci [SC8280XP_MX] = &mx, 53962306a36Sopenharmony_ci [SC8280XP_MX_AO] = &mx_ao, 54062306a36Sopenharmony_ci [SC8280XP_NSP] = &nsp, 54162306a36Sopenharmony_ci [SC8280XP_QPHY] = &qphy, 54262306a36Sopenharmony_ci}; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_cistatic const struct rpmhpd_desc sc8280xp_desc = { 54562306a36Sopenharmony_ci .rpmhpds = sc8280xp_rpmhpds, 54662306a36Sopenharmony_ci .num_pds = ARRAY_SIZE(sc8280xp_rpmhpds), 54762306a36Sopenharmony_ci}; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_cistatic const struct of_device_id rpmhpd_match_table[] = { 55062306a36Sopenharmony_ci { .compatible = "qcom,qdu1000-rpmhpd", .data = &qdu1000_desc }, 55162306a36Sopenharmony_ci { .compatible = "qcom,sa8155p-rpmhpd", .data = &sa8155p_desc }, 55262306a36Sopenharmony_ci { .compatible = "qcom,sa8540p-rpmhpd", .data = &sa8540p_desc }, 55362306a36Sopenharmony_ci { .compatible = "qcom,sa8775p-rpmhpd", .data = &sa8775p_desc }, 55462306a36Sopenharmony_ci { .compatible = "qcom,sc7180-rpmhpd", .data = &sc7180_desc }, 55562306a36Sopenharmony_ci { .compatible = "qcom,sc7280-rpmhpd", .data = &sc7280_desc }, 55662306a36Sopenharmony_ci { .compatible = "qcom,sc8180x-rpmhpd", .data = &sc8180x_desc }, 55762306a36Sopenharmony_ci { .compatible = "qcom,sc8280xp-rpmhpd", .data = &sc8280xp_desc }, 55862306a36Sopenharmony_ci { .compatible = "qcom,sdm670-rpmhpd", .data = &sdm670_desc }, 55962306a36Sopenharmony_ci { .compatible = "qcom,sdm845-rpmhpd", .data = &sdm845_desc }, 56062306a36Sopenharmony_ci { .compatible = "qcom,sdx55-rpmhpd", .data = &sdx55_desc}, 56162306a36Sopenharmony_ci { .compatible = "qcom,sdx65-rpmhpd", .data = &sdx65_desc}, 56262306a36Sopenharmony_ci { .compatible = "qcom,sdx75-rpmhpd", .data = &sdx75_desc}, 56362306a36Sopenharmony_ci { .compatible = "qcom,sm6350-rpmhpd", .data = &sm6350_desc }, 56462306a36Sopenharmony_ci { .compatible = "qcom,sm8150-rpmhpd", .data = &sm8150_desc }, 56562306a36Sopenharmony_ci { .compatible = "qcom,sm8250-rpmhpd", .data = &sm8250_desc }, 56662306a36Sopenharmony_ci { .compatible = "qcom,sm8350-rpmhpd", .data = &sm8350_desc }, 56762306a36Sopenharmony_ci { .compatible = "qcom,sm8450-rpmhpd", .data = &sm8450_desc }, 56862306a36Sopenharmony_ci { .compatible = "qcom,sm8550-rpmhpd", .data = &sm8550_desc }, 56962306a36Sopenharmony_ci { } 57062306a36Sopenharmony_ci}; 57162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, rpmhpd_match_table); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_cistatic int rpmhpd_send_corner(struct rpmhpd *pd, int state, 57462306a36Sopenharmony_ci unsigned int corner, bool sync) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci struct tcs_cmd cmd = { 57762306a36Sopenharmony_ci .addr = pd->addr, 57862306a36Sopenharmony_ci .data = corner, 57962306a36Sopenharmony_ci }; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci /* 58262306a36Sopenharmony_ci * Wait for an ack only when we are increasing the 58362306a36Sopenharmony_ci * perf state of the power domain 58462306a36Sopenharmony_ci */ 58562306a36Sopenharmony_ci if (sync) 58662306a36Sopenharmony_ci return rpmh_write(pd->dev, state, &cmd, 1); 58762306a36Sopenharmony_ci else 58862306a36Sopenharmony_ci return rpmh_write_async(pd->dev, state, &cmd, 1); 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_cistatic void to_active_sleep(struct rpmhpd *pd, unsigned int corner, 59262306a36Sopenharmony_ci unsigned int *active, unsigned int *sleep) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci *active = corner; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci if (pd->active_only) 59762306a36Sopenharmony_ci *sleep = 0; 59862306a36Sopenharmony_ci else 59962306a36Sopenharmony_ci *sleep = *active; 60062306a36Sopenharmony_ci} 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci/* 60362306a36Sopenharmony_ci * This function is used to aggregate the votes across the active only 60462306a36Sopenharmony_ci * resources and its peers. The aggregated votes are sent to RPMh as 60562306a36Sopenharmony_ci * ACTIVE_ONLY votes (which take effect immediately), as WAKE_ONLY votes 60662306a36Sopenharmony_ci * (applied by RPMh on system wakeup) and as SLEEP votes (applied by RPMh 60762306a36Sopenharmony_ci * on system sleep). 60862306a36Sopenharmony_ci * We send ACTIVE_ONLY votes for resources without any peers. For others, 60962306a36Sopenharmony_ci * which have an active only peer, all 3 votes are sent. 61062306a36Sopenharmony_ci */ 61162306a36Sopenharmony_cistatic int rpmhpd_aggregate_corner(struct rpmhpd *pd, unsigned int corner) 61262306a36Sopenharmony_ci{ 61362306a36Sopenharmony_ci int ret; 61462306a36Sopenharmony_ci struct rpmhpd *peer = pd->peer; 61562306a36Sopenharmony_ci unsigned int active_corner, sleep_corner; 61662306a36Sopenharmony_ci unsigned int this_active_corner = 0, this_sleep_corner = 0; 61762306a36Sopenharmony_ci unsigned int peer_active_corner = 0, peer_sleep_corner = 0; 61862306a36Sopenharmony_ci unsigned int peer_enabled_corner; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci if (pd->state_synced) { 62162306a36Sopenharmony_ci to_active_sleep(pd, corner, &this_active_corner, &this_sleep_corner); 62262306a36Sopenharmony_ci } else { 62362306a36Sopenharmony_ci /* Clamp to highest corner if sync_state hasn't happened */ 62462306a36Sopenharmony_ci this_active_corner = pd->level_count - 1; 62562306a36Sopenharmony_ci this_sleep_corner = pd->level_count - 1; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci if (peer && peer->enabled) { 62962306a36Sopenharmony_ci peer_enabled_corner = max(peer->corner, peer->enable_corner); 63062306a36Sopenharmony_ci to_active_sleep(peer, peer_enabled_corner, &peer_active_corner, 63162306a36Sopenharmony_ci &peer_sleep_corner); 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci active_corner = max(this_active_corner, peer_active_corner); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci ret = rpmhpd_send_corner(pd, RPMH_ACTIVE_ONLY_STATE, active_corner, 63762306a36Sopenharmony_ci active_corner > pd->active_corner); 63862306a36Sopenharmony_ci if (ret) 63962306a36Sopenharmony_ci return ret; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci pd->active_corner = active_corner; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci if (peer) { 64462306a36Sopenharmony_ci peer->active_corner = active_corner; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci ret = rpmhpd_send_corner(pd, RPMH_WAKE_ONLY_STATE, 64762306a36Sopenharmony_ci active_corner, false); 64862306a36Sopenharmony_ci if (ret) 64962306a36Sopenharmony_ci return ret; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci sleep_corner = max(this_sleep_corner, peer_sleep_corner); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci return rpmhpd_send_corner(pd, RPMH_SLEEP_STATE, sleep_corner, 65462306a36Sopenharmony_ci false); 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci return ret; 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_cistatic int rpmhpd_power_on(struct generic_pm_domain *domain) 66162306a36Sopenharmony_ci{ 66262306a36Sopenharmony_ci struct rpmhpd *pd = domain_to_rpmhpd(domain); 66362306a36Sopenharmony_ci unsigned int corner; 66462306a36Sopenharmony_ci int ret; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci mutex_lock(&rpmhpd_lock); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci corner = max(pd->corner, pd->enable_corner); 66962306a36Sopenharmony_ci ret = rpmhpd_aggregate_corner(pd, corner); 67062306a36Sopenharmony_ci if (!ret) 67162306a36Sopenharmony_ci pd->enabled = true; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci mutex_unlock(&rpmhpd_lock); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci return ret; 67662306a36Sopenharmony_ci} 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_cistatic int rpmhpd_power_off(struct generic_pm_domain *domain) 67962306a36Sopenharmony_ci{ 68062306a36Sopenharmony_ci struct rpmhpd *pd = domain_to_rpmhpd(domain); 68162306a36Sopenharmony_ci int ret; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci mutex_lock(&rpmhpd_lock); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci ret = rpmhpd_aggregate_corner(pd, 0); 68662306a36Sopenharmony_ci if (!ret) 68762306a36Sopenharmony_ci pd->enabled = false; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci mutex_unlock(&rpmhpd_lock); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci return ret; 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cistatic int rpmhpd_set_performance_state(struct generic_pm_domain *domain, 69562306a36Sopenharmony_ci unsigned int level) 69662306a36Sopenharmony_ci{ 69762306a36Sopenharmony_ci struct rpmhpd *pd = domain_to_rpmhpd(domain); 69862306a36Sopenharmony_ci int ret = 0, i; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci mutex_lock(&rpmhpd_lock); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci for (i = 0; i < pd->level_count; i++) 70362306a36Sopenharmony_ci if (level <= pd->level[i]) 70462306a36Sopenharmony_ci break; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci /* 70762306a36Sopenharmony_ci * If the level requested is more than that supported by the 70862306a36Sopenharmony_ci * max corner, just set it to max anyway. 70962306a36Sopenharmony_ci */ 71062306a36Sopenharmony_ci if (i == pd->level_count) 71162306a36Sopenharmony_ci i--; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci if (pd->enabled) { 71462306a36Sopenharmony_ci /* Ensure that the domain isn't turn off */ 71562306a36Sopenharmony_ci if (i < pd->enable_corner) 71662306a36Sopenharmony_ci i = pd->enable_corner; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci ret = rpmhpd_aggregate_corner(pd, i); 71962306a36Sopenharmony_ci if (ret) 72062306a36Sopenharmony_ci goto out; 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci pd->corner = i; 72462306a36Sopenharmony_ciout: 72562306a36Sopenharmony_ci mutex_unlock(&rpmhpd_lock); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci return ret; 72862306a36Sopenharmony_ci} 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_cistatic unsigned int rpmhpd_get_performance_state(struct generic_pm_domain *genpd, 73162306a36Sopenharmony_ci struct dev_pm_opp *opp) 73262306a36Sopenharmony_ci{ 73362306a36Sopenharmony_ci return dev_pm_opp_get_level(opp); 73462306a36Sopenharmony_ci} 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_cistatic int rpmhpd_update_level_mapping(struct rpmhpd *rpmhpd) 73762306a36Sopenharmony_ci{ 73862306a36Sopenharmony_ci int i; 73962306a36Sopenharmony_ci const u16 *buf; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci buf = cmd_db_read_aux_data(rpmhpd->res_name, &rpmhpd->level_count); 74262306a36Sopenharmony_ci if (IS_ERR(buf)) 74362306a36Sopenharmony_ci return PTR_ERR(buf); 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci /* 2 bytes used for each command DB aux data entry */ 74662306a36Sopenharmony_ci rpmhpd->level_count >>= 1; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci if (rpmhpd->level_count > RPMH_ARC_MAX_LEVELS) 74962306a36Sopenharmony_ci return -EINVAL; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci for (i = 0; i < rpmhpd->level_count; i++) { 75262306a36Sopenharmony_ci rpmhpd->level[i] = buf[i]; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci /* Remember the first corner with non-zero level */ 75562306a36Sopenharmony_ci if (!rpmhpd->level[rpmhpd->enable_corner] && rpmhpd->level[i]) 75662306a36Sopenharmony_ci rpmhpd->enable_corner = i; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci /* 75962306a36Sopenharmony_ci * The AUX data may be zero padded. These 0 valued entries at 76062306a36Sopenharmony_ci * the end of the map must be ignored. 76162306a36Sopenharmony_ci */ 76262306a36Sopenharmony_ci if (i > 0 && rpmhpd->level[i] == 0) { 76362306a36Sopenharmony_ci rpmhpd->level_count = i; 76462306a36Sopenharmony_ci break; 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci pr_debug("%s: ARC hlvl=%2d --> vlvl=%4u\n", rpmhpd->res_name, i, 76762306a36Sopenharmony_ci rpmhpd->level[i]); 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci return 0; 77162306a36Sopenharmony_ci} 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_cistatic int rpmhpd_probe(struct platform_device *pdev) 77462306a36Sopenharmony_ci{ 77562306a36Sopenharmony_ci int i, ret; 77662306a36Sopenharmony_ci size_t num_pds; 77762306a36Sopenharmony_ci struct device *dev = &pdev->dev; 77862306a36Sopenharmony_ci struct genpd_onecell_data *data; 77962306a36Sopenharmony_ci struct rpmhpd **rpmhpds; 78062306a36Sopenharmony_ci const struct rpmhpd_desc *desc; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci desc = of_device_get_match_data(dev); 78362306a36Sopenharmony_ci if (!desc) 78462306a36Sopenharmony_ci return -EINVAL; 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci rpmhpds = desc->rpmhpds; 78762306a36Sopenharmony_ci num_pds = desc->num_pds; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 79062306a36Sopenharmony_ci if (!data) 79162306a36Sopenharmony_ci return -ENOMEM; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci data->domains = devm_kcalloc(dev, num_pds, sizeof(*data->domains), 79462306a36Sopenharmony_ci GFP_KERNEL); 79562306a36Sopenharmony_ci if (!data->domains) 79662306a36Sopenharmony_ci return -ENOMEM; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci data->num_domains = num_pds; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci for (i = 0; i < num_pds; i++) { 80162306a36Sopenharmony_ci if (!rpmhpds[i]) 80262306a36Sopenharmony_ci continue; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci rpmhpds[i]->dev = dev; 80562306a36Sopenharmony_ci rpmhpds[i]->addr = cmd_db_read_addr(rpmhpds[i]->res_name); 80662306a36Sopenharmony_ci if (!rpmhpds[i]->addr) { 80762306a36Sopenharmony_ci dev_err(dev, "Could not find RPMh address for resource %s\n", 80862306a36Sopenharmony_ci rpmhpds[i]->res_name); 80962306a36Sopenharmony_ci return -ENODEV; 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci ret = cmd_db_read_slave_id(rpmhpds[i]->res_name); 81362306a36Sopenharmony_ci if (ret != CMD_DB_HW_ARC) { 81462306a36Sopenharmony_ci dev_err(dev, "RPMh slave ID mismatch\n"); 81562306a36Sopenharmony_ci return -EINVAL; 81662306a36Sopenharmony_ci } 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci ret = rpmhpd_update_level_mapping(rpmhpds[i]); 81962306a36Sopenharmony_ci if (ret) 82062306a36Sopenharmony_ci return ret; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci rpmhpds[i]->pd.power_off = rpmhpd_power_off; 82362306a36Sopenharmony_ci rpmhpds[i]->pd.power_on = rpmhpd_power_on; 82462306a36Sopenharmony_ci rpmhpds[i]->pd.set_performance_state = rpmhpd_set_performance_state; 82562306a36Sopenharmony_ci rpmhpds[i]->pd.opp_to_performance_state = rpmhpd_get_performance_state; 82662306a36Sopenharmony_ci pm_genpd_init(&rpmhpds[i]->pd, NULL, true); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci data->domains[i] = &rpmhpds[i]->pd; 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci /* Add subdomains */ 83262306a36Sopenharmony_ci for (i = 0; i < num_pds; i++) { 83362306a36Sopenharmony_ci if (!rpmhpds[i]) 83462306a36Sopenharmony_ci continue; 83562306a36Sopenharmony_ci if (rpmhpds[i]->parent) 83662306a36Sopenharmony_ci pm_genpd_add_subdomain(rpmhpds[i]->parent, 83762306a36Sopenharmony_ci &rpmhpds[i]->pd); 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci return of_genpd_add_provider_onecell(pdev->dev.of_node, data); 84162306a36Sopenharmony_ci} 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_cistatic void rpmhpd_sync_state(struct device *dev) 84462306a36Sopenharmony_ci{ 84562306a36Sopenharmony_ci const struct rpmhpd_desc *desc = of_device_get_match_data(dev); 84662306a36Sopenharmony_ci struct rpmhpd **rpmhpds = desc->rpmhpds; 84762306a36Sopenharmony_ci unsigned int corner; 84862306a36Sopenharmony_ci struct rpmhpd *pd; 84962306a36Sopenharmony_ci unsigned int i; 85062306a36Sopenharmony_ci int ret; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci mutex_lock(&rpmhpd_lock); 85362306a36Sopenharmony_ci for (i = 0; i < desc->num_pds; i++) { 85462306a36Sopenharmony_ci pd = rpmhpds[i]; 85562306a36Sopenharmony_ci if (!pd) 85662306a36Sopenharmony_ci continue; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci pd->state_synced = true; 85962306a36Sopenharmony_ci if (pd->enabled) 86062306a36Sopenharmony_ci corner = max(pd->corner, pd->enable_corner); 86162306a36Sopenharmony_ci else 86262306a36Sopenharmony_ci corner = 0; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci ret = rpmhpd_aggregate_corner(pd, corner); 86562306a36Sopenharmony_ci if (ret) 86662306a36Sopenharmony_ci dev_err(dev, "failed to sync %s\n", pd->res_name); 86762306a36Sopenharmony_ci } 86862306a36Sopenharmony_ci mutex_unlock(&rpmhpd_lock); 86962306a36Sopenharmony_ci} 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_cistatic struct platform_driver rpmhpd_driver = { 87262306a36Sopenharmony_ci .driver = { 87362306a36Sopenharmony_ci .name = "qcom-rpmhpd", 87462306a36Sopenharmony_ci .of_match_table = rpmhpd_match_table, 87562306a36Sopenharmony_ci .suppress_bind_attrs = true, 87662306a36Sopenharmony_ci .sync_state = rpmhpd_sync_state, 87762306a36Sopenharmony_ci }, 87862306a36Sopenharmony_ci .probe = rpmhpd_probe, 87962306a36Sopenharmony_ci}; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_cistatic int __init rpmhpd_init(void) 88262306a36Sopenharmony_ci{ 88362306a36Sopenharmony_ci return platform_driver_register(&rpmhpd_driver); 88462306a36Sopenharmony_ci} 88562306a36Sopenharmony_cicore_initcall(rpmhpd_init); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ciMODULE_DESCRIPTION("Qualcomm Technologies, Inc. RPMh Power Domain Driver"); 88862306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 889