162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Rockchip Generic power domain support. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2015 ROCKCHIP, Co. Ltd. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/io.h> 962306a36Sopenharmony_ci#include <linux/iopoll.h> 1062306a36Sopenharmony_ci#include <linux/err.h> 1162306a36Sopenharmony_ci#include <linux/mutex.h> 1262306a36Sopenharmony_ci#include <linux/pm_clock.h> 1362306a36Sopenharmony_ci#include <linux/pm_domain.h> 1462306a36Sopenharmony_ci#include <linux/of_address.h> 1562306a36Sopenharmony_ci#include <linux/of_clk.h> 1662306a36Sopenharmony_ci#include <linux/of_platform.h> 1762306a36Sopenharmony_ci#include <linux/clk.h> 1862306a36Sopenharmony_ci#include <linux/regmap.h> 1962306a36Sopenharmony_ci#include <linux/mfd/syscon.h> 2062306a36Sopenharmony_ci#include <soc/rockchip/pm_domains.h> 2162306a36Sopenharmony_ci#include <dt-bindings/power/px30-power.h> 2262306a36Sopenharmony_ci#include <dt-bindings/power/rockchip,rv1126-power.h> 2362306a36Sopenharmony_ci#include <dt-bindings/power/rk3036-power.h> 2462306a36Sopenharmony_ci#include <dt-bindings/power/rk3066-power.h> 2562306a36Sopenharmony_ci#include <dt-bindings/power/rk3128-power.h> 2662306a36Sopenharmony_ci#include <dt-bindings/power/rk3188-power.h> 2762306a36Sopenharmony_ci#include <dt-bindings/power/rk3228-power.h> 2862306a36Sopenharmony_ci#include <dt-bindings/power/rk3288-power.h> 2962306a36Sopenharmony_ci#include <dt-bindings/power/rk3328-power.h> 3062306a36Sopenharmony_ci#include <dt-bindings/power/rk3366-power.h> 3162306a36Sopenharmony_ci#include <dt-bindings/power/rk3368-power.h> 3262306a36Sopenharmony_ci#include <dt-bindings/power/rk3399-power.h> 3362306a36Sopenharmony_ci#include <dt-bindings/power/rk3568-power.h> 3462306a36Sopenharmony_ci#include <dt-bindings/power/rk3588-power.h> 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistruct rockchip_domain_info { 3762306a36Sopenharmony_ci const char *name; 3862306a36Sopenharmony_ci int pwr_mask; 3962306a36Sopenharmony_ci int status_mask; 4062306a36Sopenharmony_ci int req_mask; 4162306a36Sopenharmony_ci int idle_mask; 4262306a36Sopenharmony_ci int ack_mask; 4362306a36Sopenharmony_ci bool active_wakeup; 4462306a36Sopenharmony_ci int pwr_w_mask; 4562306a36Sopenharmony_ci int req_w_mask; 4662306a36Sopenharmony_ci int mem_status_mask; 4762306a36Sopenharmony_ci int repair_status_mask; 4862306a36Sopenharmony_ci u32 pwr_offset; 4962306a36Sopenharmony_ci u32 mem_offset; 5062306a36Sopenharmony_ci u32 req_offset; 5162306a36Sopenharmony_ci}; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistruct rockchip_pmu_info { 5462306a36Sopenharmony_ci u32 pwr_offset; 5562306a36Sopenharmony_ci u32 status_offset; 5662306a36Sopenharmony_ci u32 req_offset; 5762306a36Sopenharmony_ci u32 idle_offset; 5862306a36Sopenharmony_ci u32 ack_offset; 5962306a36Sopenharmony_ci u32 mem_pwr_offset; 6062306a36Sopenharmony_ci u32 chain_status_offset; 6162306a36Sopenharmony_ci u32 mem_status_offset; 6262306a36Sopenharmony_ci u32 repair_status_offset; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci u32 core_pwrcnt_offset; 6562306a36Sopenharmony_ci u32 gpu_pwrcnt_offset; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci unsigned int core_power_transition_time; 6862306a36Sopenharmony_ci unsigned int gpu_power_transition_time; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci int num_domains; 7162306a36Sopenharmony_ci const struct rockchip_domain_info *domain_info; 7262306a36Sopenharmony_ci}; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci#define MAX_QOS_REGS_NUM 5 7562306a36Sopenharmony_ci#define QOS_PRIORITY 0x08 7662306a36Sopenharmony_ci#define QOS_MODE 0x0c 7762306a36Sopenharmony_ci#define QOS_BANDWIDTH 0x10 7862306a36Sopenharmony_ci#define QOS_SATURATION 0x14 7962306a36Sopenharmony_ci#define QOS_EXTCONTROL 0x18 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistruct rockchip_pm_domain { 8262306a36Sopenharmony_ci struct generic_pm_domain genpd; 8362306a36Sopenharmony_ci const struct rockchip_domain_info *info; 8462306a36Sopenharmony_ci struct rockchip_pmu *pmu; 8562306a36Sopenharmony_ci int num_qos; 8662306a36Sopenharmony_ci struct regmap **qos_regmap; 8762306a36Sopenharmony_ci u32 *qos_save_regs[MAX_QOS_REGS_NUM]; 8862306a36Sopenharmony_ci int num_clks; 8962306a36Sopenharmony_ci struct clk_bulk_data *clks; 9062306a36Sopenharmony_ci}; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistruct rockchip_pmu { 9362306a36Sopenharmony_ci struct device *dev; 9462306a36Sopenharmony_ci struct regmap *regmap; 9562306a36Sopenharmony_ci const struct rockchip_pmu_info *info; 9662306a36Sopenharmony_ci struct mutex mutex; /* mutex lock for pmu */ 9762306a36Sopenharmony_ci struct genpd_onecell_data genpd_data; 9862306a36Sopenharmony_ci struct generic_pm_domain *domains[]; 9962306a36Sopenharmony_ci}; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci#define to_rockchip_pd(gpd) container_of(gpd, struct rockchip_pm_domain, genpd) 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci#define DOMAIN(_name, pwr, status, req, idle, ack, wakeup) \ 10462306a36Sopenharmony_ci{ \ 10562306a36Sopenharmony_ci .name = _name, \ 10662306a36Sopenharmony_ci .pwr_mask = (pwr), \ 10762306a36Sopenharmony_ci .status_mask = (status), \ 10862306a36Sopenharmony_ci .req_mask = (req), \ 10962306a36Sopenharmony_ci .idle_mask = (idle), \ 11062306a36Sopenharmony_ci .ack_mask = (ack), \ 11162306a36Sopenharmony_ci .active_wakeup = (wakeup), \ 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci#define DOMAIN_M(_name, pwr, status, req, idle, ack, wakeup) \ 11562306a36Sopenharmony_ci{ \ 11662306a36Sopenharmony_ci .name = _name, \ 11762306a36Sopenharmony_ci .pwr_w_mask = (pwr) << 16, \ 11862306a36Sopenharmony_ci .pwr_mask = (pwr), \ 11962306a36Sopenharmony_ci .status_mask = (status), \ 12062306a36Sopenharmony_ci .req_w_mask = (req) << 16, \ 12162306a36Sopenharmony_ci .req_mask = (req), \ 12262306a36Sopenharmony_ci .idle_mask = (idle), \ 12362306a36Sopenharmony_ci .ack_mask = (ack), \ 12462306a36Sopenharmony_ci .active_wakeup = wakeup, \ 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci#define DOMAIN_M_O_R(_name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, ack, wakeup) \ 12862306a36Sopenharmony_ci{ \ 12962306a36Sopenharmony_ci .name = _name, \ 13062306a36Sopenharmony_ci .pwr_offset = p_offset, \ 13162306a36Sopenharmony_ci .pwr_w_mask = (pwr) << 16, \ 13262306a36Sopenharmony_ci .pwr_mask = (pwr), \ 13362306a36Sopenharmony_ci .status_mask = (status), \ 13462306a36Sopenharmony_ci .mem_offset = m_offset, \ 13562306a36Sopenharmony_ci .mem_status_mask = (m_status), \ 13662306a36Sopenharmony_ci .repair_status_mask = (r_status), \ 13762306a36Sopenharmony_ci .req_offset = r_offset, \ 13862306a36Sopenharmony_ci .req_w_mask = (req) << 16, \ 13962306a36Sopenharmony_ci .req_mask = (req), \ 14062306a36Sopenharmony_ci .idle_mask = (idle), \ 14162306a36Sopenharmony_ci .ack_mask = (ack), \ 14262306a36Sopenharmony_ci .active_wakeup = wakeup, \ 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci#define DOMAIN_RK3036(_name, req, ack, idle, wakeup) \ 14662306a36Sopenharmony_ci{ \ 14762306a36Sopenharmony_ci .name = _name, \ 14862306a36Sopenharmony_ci .req_mask = (req), \ 14962306a36Sopenharmony_ci .req_w_mask = (req) << 16, \ 15062306a36Sopenharmony_ci .ack_mask = (ack), \ 15162306a36Sopenharmony_ci .idle_mask = (idle), \ 15262306a36Sopenharmony_ci .active_wakeup = wakeup, \ 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci#define DOMAIN_PX30(name, pwr, status, req, wakeup) \ 15662306a36Sopenharmony_ci DOMAIN_M(name, pwr, status, req, (req) << 16, req, wakeup) 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci#define DOMAIN_RV1126(name, pwr, req, idle, wakeup) \ 15962306a36Sopenharmony_ci DOMAIN_M(name, pwr, pwr, req, idle, idle, wakeup) 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci#define DOMAIN_RK3288(name, pwr, status, req, wakeup) \ 16262306a36Sopenharmony_ci DOMAIN(name, pwr, status, req, req, (req) << 16, wakeup) 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci#define DOMAIN_RK3328(name, pwr, status, req, wakeup) \ 16562306a36Sopenharmony_ci DOMAIN_M(name, pwr, pwr, req, (req) << 10, req, wakeup) 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci#define DOMAIN_RK3368(name, pwr, status, req, wakeup) \ 16862306a36Sopenharmony_ci DOMAIN(name, pwr, status, req, (req) << 16, req, wakeup) 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci#define DOMAIN_RK3399(name, pwr, status, req, wakeup) \ 17162306a36Sopenharmony_ci DOMAIN(name, pwr, status, req, req, req, wakeup) 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci#define DOMAIN_RK3568(name, pwr, req, wakeup) \ 17462306a36Sopenharmony_ci DOMAIN_M(name, pwr, pwr, req, req, req, wakeup) 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci/* 17762306a36Sopenharmony_ci * Dynamic Memory Controller may need to coordinate with us -- see 17862306a36Sopenharmony_ci * rockchip_pmu_block(). 17962306a36Sopenharmony_ci * 18062306a36Sopenharmony_ci * dmc_pmu_mutex protects registration-time races, so DMC driver doesn't try to 18162306a36Sopenharmony_ci * block() while we're initializing the PMU. 18262306a36Sopenharmony_ci */ 18362306a36Sopenharmony_cistatic DEFINE_MUTEX(dmc_pmu_mutex); 18462306a36Sopenharmony_cistatic struct rockchip_pmu *dmc_pmu; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci/* 18762306a36Sopenharmony_ci * Block PMU transitions and make sure they don't interfere with ARM Trusted 18862306a36Sopenharmony_ci * Firmware operations. There are two conflicts, noted in the comments below. 18962306a36Sopenharmony_ci * 19062306a36Sopenharmony_ci * Caller must unblock PMU transitions via rockchip_pmu_unblock(). 19162306a36Sopenharmony_ci */ 19262306a36Sopenharmony_ciint rockchip_pmu_block(void) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci struct rockchip_pmu *pmu; 19562306a36Sopenharmony_ci struct generic_pm_domain *genpd; 19662306a36Sopenharmony_ci struct rockchip_pm_domain *pd; 19762306a36Sopenharmony_ci int i, ret; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci mutex_lock(&dmc_pmu_mutex); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci /* No PMU (yet)? Then we just block rockchip_pmu_probe(). */ 20262306a36Sopenharmony_ci if (!dmc_pmu) 20362306a36Sopenharmony_ci return 0; 20462306a36Sopenharmony_ci pmu = dmc_pmu; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* 20762306a36Sopenharmony_ci * mutex blocks all idle transitions: we can't touch the 20862306a36Sopenharmony_ci * PMU_BUS_IDLE_REQ (our ".idle_offset") register while ARM Trusted 20962306a36Sopenharmony_ci * Firmware might be using it. 21062306a36Sopenharmony_ci */ 21162306a36Sopenharmony_ci mutex_lock(&pmu->mutex); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci /* 21462306a36Sopenharmony_ci * Power domain clocks: Per Rockchip, we *must* keep certain clocks 21562306a36Sopenharmony_ci * enabled for the duration of power-domain transitions. Most 21662306a36Sopenharmony_ci * transitions are handled by this driver, but some cases (in 21762306a36Sopenharmony_ci * particular, DRAM DVFS / memory-controller idle) must be handled by 21862306a36Sopenharmony_ci * firmware. Firmware can handle most clock management via a special 21962306a36Sopenharmony_ci * "ungate" register (PMU_CRU_GATEDIS_CON0), but unfortunately, this 22062306a36Sopenharmony_ci * doesn't handle PLLs. We can assist this transition by doing the 22162306a36Sopenharmony_ci * clock management on behalf of firmware. 22262306a36Sopenharmony_ci */ 22362306a36Sopenharmony_ci for (i = 0; i < pmu->genpd_data.num_domains; i++) { 22462306a36Sopenharmony_ci genpd = pmu->genpd_data.domains[i]; 22562306a36Sopenharmony_ci if (genpd) { 22662306a36Sopenharmony_ci pd = to_rockchip_pd(genpd); 22762306a36Sopenharmony_ci ret = clk_bulk_enable(pd->num_clks, pd->clks); 22862306a36Sopenharmony_ci if (ret < 0) { 22962306a36Sopenharmony_ci dev_err(pmu->dev, 23062306a36Sopenharmony_ci "failed to enable clks for domain '%s': %d\n", 23162306a36Sopenharmony_ci genpd->name, ret); 23262306a36Sopenharmony_ci goto err; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci return 0; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cierr: 24062306a36Sopenharmony_ci for (i = i - 1; i >= 0; i--) { 24162306a36Sopenharmony_ci genpd = pmu->genpd_data.domains[i]; 24262306a36Sopenharmony_ci if (genpd) { 24362306a36Sopenharmony_ci pd = to_rockchip_pd(genpd); 24462306a36Sopenharmony_ci clk_bulk_disable(pd->num_clks, pd->clks); 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci mutex_unlock(&pmu->mutex); 24862306a36Sopenharmony_ci mutex_unlock(&dmc_pmu_mutex); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci return ret; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rockchip_pmu_block); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci/* Unblock PMU transitions. */ 25562306a36Sopenharmony_civoid rockchip_pmu_unblock(void) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci struct rockchip_pmu *pmu; 25862306a36Sopenharmony_ci struct generic_pm_domain *genpd; 25962306a36Sopenharmony_ci struct rockchip_pm_domain *pd; 26062306a36Sopenharmony_ci int i; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (dmc_pmu) { 26362306a36Sopenharmony_ci pmu = dmc_pmu; 26462306a36Sopenharmony_ci for (i = 0; i < pmu->genpd_data.num_domains; i++) { 26562306a36Sopenharmony_ci genpd = pmu->genpd_data.domains[i]; 26662306a36Sopenharmony_ci if (genpd) { 26762306a36Sopenharmony_ci pd = to_rockchip_pd(genpd); 26862306a36Sopenharmony_ci clk_bulk_disable(pd->num_clks, pd->clks); 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci mutex_unlock(&pmu->mutex); 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci mutex_unlock(&dmc_pmu_mutex); 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rockchip_pmu_unblock); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci#define DOMAIN_RK3588(name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, wakeup) \ 28062306a36Sopenharmony_ci DOMAIN_M_O_R(name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, idle, wakeup) 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_cistatic bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci struct rockchip_pmu *pmu = pd->pmu; 28562306a36Sopenharmony_ci const struct rockchip_domain_info *pd_info = pd->info; 28662306a36Sopenharmony_ci unsigned int val; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci regmap_read(pmu->regmap, pmu->info->idle_offset, &val); 28962306a36Sopenharmony_ci return (val & pd_info->idle_mask) == pd_info->idle_mask; 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cistatic unsigned int rockchip_pmu_read_ack(struct rockchip_pmu *pmu) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci unsigned int val; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci regmap_read(pmu->regmap, pmu->info->ack_offset, &val); 29762306a36Sopenharmony_ci return val; 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd, 30162306a36Sopenharmony_ci bool idle) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci const struct rockchip_domain_info *pd_info = pd->info; 30462306a36Sopenharmony_ci struct generic_pm_domain *genpd = &pd->genpd; 30562306a36Sopenharmony_ci struct rockchip_pmu *pmu = pd->pmu; 30662306a36Sopenharmony_ci u32 pd_req_offset = pd_info->req_offset; 30762306a36Sopenharmony_ci unsigned int target_ack; 30862306a36Sopenharmony_ci unsigned int val; 30962306a36Sopenharmony_ci bool is_idle; 31062306a36Sopenharmony_ci int ret; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if (pd_info->req_mask == 0) 31362306a36Sopenharmony_ci return 0; 31462306a36Sopenharmony_ci else if (pd_info->req_w_mask) 31562306a36Sopenharmony_ci regmap_write(pmu->regmap, pmu->info->req_offset + pd_req_offset, 31662306a36Sopenharmony_ci idle ? (pd_info->req_mask | pd_info->req_w_mask) : 31762306a36Sopenharmony_ci pd_info->req_w_mask); 31862306a36Sopenharmony_ci else 31962306a36Sopenharmony_ci regmap_update_bits(pmu->regmap, pmu->info->req_offset + pd_req_offset, 32062306a36Sopenharmony_ci pd_info->req_mask, idle ? -1U : 0); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci wmb(); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci /* Wait util idle_ack = 1 */ 32562306a36Sopenharmony_ci target_ack = idle ? pd_info->ack_mask : 0; 32662306a36Sopenharmony_ci ret = readx_poll_timeout_atomic(rockchip_pmu_read_ack, pmu, val, 32762306a36Sopenharmony_ci (val & pd_info->ack_mask) == target_ack, 32862306a36Sopenharmony_ci 0, 10000); 32962306a36Sopenharmony_ci if (ret) { 33062306a36Sopenharmony_ci dev_err(pmu->dev, 33162306a36Sopenharmony_ci "failed to get ack on domain '%s', val=0x%x\n", 33262306a36Sopenharmony_ci genpd->name, val); 33362306a36Sopenharmony_ci return ret; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci ret = readx_poll_timeout_atomic(rockchip_pmu_domain_is_idle, pd, 33762306a36Sopenharmony_ci is_idle, is_idle == idle, 0, 10000); 33862306a36Sopenharmony_ci if (ret) { 33962306a36Sopenharmony_ci dev_err(pmu->dev, 34062306a36Sopenharmony_ci "failed to set idle on domain '%s', val=%d\n", 34162306a36Sopenharmony_ci genpd->name, is_idle); 34262306a36Sopenharmony_ci return ret; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci return 0; 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic int rockchip_pmu_save_qos(struct rockchip_pm_domain *pd) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci int i; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci for (i = 0; i < pd->num_qos; i++) { 35362306a36Sopenharmony_ci regmap_read(pd->qos_regmap[i], 35462306a36Sopenharmony_ci QOS_PRIORITY, 35562306a36Sopenharmony_ci &pd->qos_save_regs[0][i]); 35662306a36Sopenharmony_ci regmap_read(pd->qos_regmap[i], 35762306a36Sopenharmony_ci QOS_MODE, 35862306a36Sopenharmony_ci &pd->qos_save_regs[1][i]); 35962306a36Sopenharmony_ci regmap_read(pd->qos_regmap[i], 36062306a36Sopenharmony_ci QOS_BANDWIDTH, 36162306a36Sopenharmony_ci &pd->qos_save_regs[2][i]); 36262306a36Sopenharmony_ci regmap_read(pd->qos_regmap[i], 36362306a36Sopenharmony_ci QOS_SATURATION, 36462306a36Sopenharmony_ci &pd->qos_save_regs[3][i]); 36562306a36Sopenharmony_ci regmap_read(pd->qos_regmap[i], 36662306a36Sopenharmony_ci QOS_EXTCONTROL, 36762306a36Sopenharmony_ci &pd->qos_save_regs[4][i]); 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci return 0; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic int rockchip_pmu_restore_qos(struct rockchip_pm_domain *pd) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci int i; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci for (i = 0; i < pd->num_qos; i++) { 37762306a36Sopenharmony_ci regmap_write(pd->qos_regmap[i], 37862306a36Sopenharmony_ci QOS_PRIORITY, 37962306a36Sopenharmony_ci pd->qos_save_regs[0][i]); 38062306a36Sopenharmony_ci regmap_write(pd->qos_regmap[i], 38162306a36Sopenharmony_ci QOS_MODE, 38262306a36Sopenharmony_ci pd->qos_save_regs[1][i]); 38362306a36Sopenharmony_ci regmap_write(pd->qos_regmap[i], 38462306a36Sopenharmony_ci QOS_BANDWIDTH, 38562306a36Sopenharmony_ci pd->qos_save_regs[2][i]); 38662306a36Sopenharmony_ci regmap_write(pd->qos_regmap[i], 38762306a36Sopenharmony_ci QOS_SATURATION, 38862306a36Sopenharmony_ci pd->qos_save_regs[3][i]); 38962306a36Sopenharmony_ci regmap_write(pd->qos_regmap[i], 39062306a36Sopenharmony_ci QOS_EXTCONTROL, 39162306a36Sopenharmony_ci pd->qos_save_regs[4][i]); 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci return 0; 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_cistatic bool rockchip_pmu_domain_is_on(struct rockchip_pm_domain *pd) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci struct rockchip_pmu *pmu = pd->pmu; 40062306a36Sopenharmony_ci unsigned int val; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (pd->info->repair_status_mask) { 40362306a36Sopenharmony_ci regmap_read(pmu->regmap, pmu->info->repair_status_offset, &val); 40462306a36Sopenharmony_ci /* 1'b1: power on, 1'b0: power off */ 40562306a36Sopenharmony_ci return val & pd->info->repair_status_mask; 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci /* check idle status for idle-only domains */ 40962306a36Sopenharmony_ci if (pd->info->status_mask == 0) 41062306a36Sopenharmony_ci return !rockchip_pmu_domain_is_idle(pd); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci regmap_read(pmu->regmap, pmu->info->status_offset, &val); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci /* 1'b0: power on, 1'b1: power off */ 41562306a36Sopenharmony_ci return !(val & pd->info->status_mask); 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic bool rockchip_pmu_domain_is_mem_on(struct rockchip_pm_domain *pd) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci struct rockchip_pmu *pmu = pd->pmu; 42162306a36Sopenharmony_ci unsigned int val; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci regmap_read(pmu->regmap, 42462306a36Sopenharmony_ci pmu->info->mem_status_offset + pd->info->mem_offset, &val); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci /* 1'b0: power on, 1'b1: power off */ 42762306a36Sopenharmony_ci return !(val & pd->info->mem_status_mask); 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic bool rockchip_pmu_domain_is_chain_on(struct rockchip_pm_domain *pd) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci struct rockchip_pmu *pmu = pd->pmu; 43362306a36Sopenharmony_ci unsigned int val; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci regmap_read(pmu->regmap, 43662306a36Sopenharmony_ci pmu->info->chain_status_offset + pd->info->mem_offset, &val); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* 1'b1: power on, 1'b0: power off */ 43962306a36Sopenharmony_ci return val & pd->info->mem_status_mask; 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic int rockchip_pmu_domain_mem_reset(struct rockchip_pm_domain *pd) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci struct rockchip_pmu *pmu = pd->pmu; 44562306a36Sopenharmony_ci struct generic_pm_domain *genpd = &pd->genpd; 44662306a36Sopenharmony_ci bool is_on; 44762306a36Sopenharmony_ci int ret = 0; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci ret = readx_poll_timeout_atomic(rockchip_pmu_domain_is_chain_on, pd, is_on, 45062306a36Sopenharmony_ci is_on == true, 0, 10000); 45162306a36Sopenharmony_ci if (ret) { 45262306a36Sopenharmony_ci dev_err(pmu->dev, 45362306a36Sopenharmony_ci "failed to get chain status '%s', target_on=1, val=%d\n", 45462306a36Sopenharmony_ci genpd->name, is_on); 45562306a36Sopenharmony_ci goto error; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci udelay(20); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci regmap_write(pmu->regmap, pmu->info->mem_pwr_offset + pd->info->pwr_offset, 46162306a36Sopenharmony_ci (pd->info->pwr_mask | pd->info->pwr_w_mask)); 46262306a36Sopenharmony_ci wmb(); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci ret = readx_poll_timeout_atomic(rockchip_pmu_domain_is_mem_on, pd, is_on, 46562306a36Sopenharmony_ci is_on == false, 0, 10000); 46662306a36Sopenharmony_ci if (ret) { 46762306a36Sopenharmony_ci dev_err(pmu->dev, 46862306a36Sopenharmony_ci "failed to get mem status '%s', target_on=0, val=%d\n", 46962306a36Sopenharmony_ci genpd->name, is_on); 47062306a36Sopenharmony_ci goto error; 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci regmap_write(pmu->regmap, pmu->info->mem_pwr_offset + pd->info->pwr_offset, 47462306a36Sopenharmony_ci pd->info->pwr_w_mask); 47562306a36Sopenharmony_ci wmb(); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci ret = readx_poll_timeout_atomic(rockchip_pmu_domain_is_mem_on, pd, is_on, 47862306a36Sopenharmony_ci is_on == true, 0, 10000); 47962306a36Sopenharmony_ci if (ret) { 48062306a36Sopenharmony_ci dev_err(pmu->dev, 48162306a36Sopenharmony_ci "failed to get mem status '%s', target_on=1, val=%d\n", 48262306a36Sopenharmony_ci genpd->name, is_on); 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_cierror: 48662306a36Sopenharmony_ci return ret; 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistatic void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd, 49062306a36Sopenharmony_ci bool on) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci struct rockchip_pmu *pmu = pd->pmu; 49362306a36Sopenharmony_ci struct generic_pm_domain *genpd = &pd->genpd; 49462306a36Sopenharmony_ci u32 pd_pwr_offset = pd->info->pwr_offset; 49562306a36Sopenharmony_ci bool is_on, is_mem_on = false; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (pd->info->pwr_mask == 0) 49862306a36Sopenharmony_ci return; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci if (on && pd->info->mem_status_mask) 50162306a36Sopenharmony_ci is_mem_on = rockchip_pmu_domain_is_mem_on(pd); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci if (pd->info->pwr_w_mask) 50462306a36Sopenharmony_ci regmap_write(pmu->regmap, pmu->info->pwr_offset + pd_pwr_offset, 50562306a36Sopenharmony_ci on ? pd->info->pwr_w_mask : 50662306a36Sopenharmony_ci (pd->info->pwr_mask | pd->info->pwr_w_mask)); 50762306a36Sopenharmony_ci else 50862306a36Sopenharmony_ci regmap_update_bits(pmu->regmap, pmu->info->pwr_offset + pd_pwr_offset, 50962306a36Sopenharmony_ci pd->info->pwr_mask, on ? 0 : -1U); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci wmb(); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci if (is_mem_on && rockchip_pmu_domain_mem_reset(pd)) 51462306a36Sopenharmony_ci return; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci if (readx_poll_timeout_atomic(rockchip_pmu_domain_is_on, pd, is_on, 51762306a36Sopenharmony_ci is_on == on, 0, 10000)) { 51862306a36Sopenharmony_ci dev_err(pmu->dev, 51962306a36Sopenharmony_ci "failed to set domain '%s', val=%d\n", 52062306a36Sopenharmony_ci genpd->name, is_on); 52162306a36Sopenharmony_ci return; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci} 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_cistatic int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci struct rockchip_pmu *pmu = pd->pmu; 52862306a36Sopenharmony_ci int ret; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci mutex_lock(&pmu->mutex); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci if (rockchip_pmu_domain_is_on(pd) != power_on) { 53362306a36Sopenharmony_ci ret = clk_bulk_enable(pd->num_clks, pd->clks); 53462306a36Sopenharmony_ci if (ret < 0) { 53562306a36Sopenharmony_ci dev_err(pmu->dev, "failed to enable clocks\n"); 53662306a36Sopenharmony_ci mutex_unlock(&pmu->mutex); 53762306a36Sopenharmony_ci return ret; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci if (!power_on) { 54162306a36Sopenharmony_ci rockchip_pmu_save_qos(pd); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci /* if powering down, idle request to NIU first */ 54462306a36Sopenharmony_ci rockchip_pmu_set_idle_request(pd, true); 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci rockchip_do_pmu_set_power_domain(pd, power_on); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci if (power_on) { 55062306a36Sopenharmony_ci /* if powering up, leave idle mode */ 55162306a36Sopenharmony_ci rockchip_pmu_set_idle_request(pd, false); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci rockchip_pmu_restore_qos(pd); 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci clk_bulk_disable(pd->num_clks, pd->clks); 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci mutex_unlock(&pmu->mutex); 56062306a36Sopenharmony_ci return 0; 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_cistatic int rockchip_pd_power_on(struct generic_pm_domain *domain) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci struct rockchip_pm_domain *pd = to_rockchip_pd(domain); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci return rockchip_pd_power(pd, true); 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_cistatic int rockchip_pd_power_off(struct generic_pm_domain *domain) 57162306a36Sopenharmony_ci{ 57262306a36Sopenharmony_ci struct rockchip_pm_domain *pd = to_rockchip_pd(domain); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci return rockchip_pd_power(pd, false); 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_cistatic int rockchip_pd_attach_dev(struct generic_pm_domain *genpd, 57862306a36Sopenharmony_ci struct device *dev) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci struct clk *clk; 58162306a36Sopenharmony_ci int i; 58262306a36Sopenharmony_ci int error; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci dev_dbg(dev, "attaching to power domain '%s'\n", genpd->name); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci error = pm_clk_create(dev); 58762306a36Sopenharmony_ci if (error) { 58862306a36Sopenharmony_ci dev_err(dev, "pm_clk_create failed %d\n", error); 58962306a36Sopenharmony_ci return error; 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci i = 0; 59362306a36Sopenharmony_ci while ((clk = of_clk_get(dev->of_node, i++)) && !IS_ERR(clk)) { 59462306a36Sopenharmony_ci dev_dbg(dev, "adding clock '%pC' to list of PM clocks\n", clk); 59562306a36Sopenharmony_ci error = pm_clk_add_clk(dev, clk); 59662306a36Sopenharmony_ci if (error) { 59762306a36Sopenharmony_ci dev_err(dev, "pm_clk_add_clk failed %d\n", error); 59862306a36Sopenharmony_ci clk_put(clk); 59962306a36Sopenharmony_ci pm_clk_destroy(dev); 60062306a36Sopenharmony_ci return error; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci return 0; 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic void rockchip_pd_detach_dev(struct generic_pm_domain *genpd, 60862306a36Sopenharmony_ci struct device *dev) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci dev_dbg(dev, "detaching from power domain '%s'\n", genpd->name); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci pm_clk_destroy(dev); 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_cistatic int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu, 61662306a36Sopenharmony_ci struct device_node *node) 61762306a36Sopenharmony_ci{ 61862306a36Sopenharmony_ci const struct rockchip_domain_info *pd_info; 61962306a36Sopenharmony_ci struct rockchip_pm_domain *pd; 62062306a36Sopenharmony_ci struct device_node *qos_node; 62162306a36Sopenharmony_ci int i, j; 62262306a36Sopenharmony_ci u32 id; 62362306a36Sopenharmony_ci int error; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci error = of_property_read_u32(node, "reg", &id); 62662306a36Sopenharmony_ci if (error) { 62762306a36Sopenharmony_ci dev_err(pmu->dev, 62862306a36Sopenharmony_ci "%pOFn: failed to retrieve domain id (reg): %d\n", 62962306a36Sopenharmony_ci node, error); 63062306a36Sopenharmony_ci return -EINVAL; 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci if (id >= pmu->info->num_domains) { 63462306a36Sopenharmony_ci dev_err(pmu->dev, "%pOFn: invalid domain id %d\n", 63562306a36Sopenharmony_ci node, id); 63662306a36Sopenharmony_ci return -EINVAL; 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci /* RK3588 has domains with two parents (RKVDEC0/RKVDEC1) */ 63962306a36Sopenharmony_ci if (pmu->genpd_data.domains[id]) 64062306a36Sopenharmony_ci return 0; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci pd_info = &pmu->info->domain_info[id]; 64362306a36Sopenharmony_ci if (!pd_info) { 64462306a36Sopenharmony_ci dev_err(pmu->dev, "%pOFn: undefined domain id %d\n", 64562306a36Sopenharmony_ci node, id); 64662306a36Sopenharmony_ci return -EINVAL; 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci pd = devm_kzalloc(pmu->dev, sizeof(*pd), GFP_KERNEL); 65062306a36Sopenharmony_ci if (!pd) 65162306a36Sopenharmony_ci return -ENOMEM; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci pd->info = pd_info; 65462306a36Sopenharmony_ci pd->pmu = pmu; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci pd->num_clks = of_clk_get_parent_count(node); 65762306a36Sopenharmony_ci if (pd->num_clks > 0) { 65862306a36Sopenharmony_ci pd->clks = devm_kcalloc(pmu->dev, pd->num_clks, 65962306a36Sopenharmony_ci sizeof(*pd->clks), GFP_KERNEL); 66062306a36Sopenharmony_ci if (!pd->clks) 66162306a36Sopenharmony_ci return -ENOMEM; 66262306a36Sopenharmony_ci } else { 66362306a36Sopenharmony_ci dev_dbg(pmu->dev, "%pOFn: doesn't have clocks: %d\n", 66462306a36Sopenharmony_ci node, pd->num_clks); 66562306a36Sopenharmony_ci pd->num_clks = 0; 66662306a36Sopenharmony_ci } 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci for (i = 0; i < pd->num_clks; i++) { 66962306a36Sopenharmony_ci pd->clks[i].clk = of_clk_get(node, i); 67062306a36Sopenharmony_ci if (IS_ERR(pd->clks[i].clk)) { 67162306a36Sopenharmony_ci error = PTR_ERR(pd->clks[i].clk); 67262306a36Sopenharmony_ci dev_err(pmu->dev, 67362306a36Sopenharmony_ci "%pOFn: failed to get clk at index %d: %d\n", 67462306a36Sopenharmony_ci node, i, error); 67562306a36Sopenharmony_ci return error; 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci error = clk_bulk_prepare(pd->num_clks, pd->clks); 68062306a36Sopenharmony_ci if (error) 68162306a36Sopenharmony_ci goto err_put_clocks; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci pd->num_qos = of_count_phandle_with_args(node, "pm_qos", 68462306a36Sopenharmony_ci NULL); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (pd->num_qos > 0) { 68762306a36Sopenharmony_ci pd->qos_regmap = devm_kcalloc(pmu->dev, pd->num_qos, 68862306a36Sopenharmony_ci sizeof(*pd->qos_regmap), 68962306a36Sopenharmony_ci GFP_KERNEL); 69062306a36Sopenharmony_ci if (!pd->qos_regmap) { 69162306a36Sopenharmony_ci error = -ENOMEM; 69262306a36Sopenharmony_ci goto err_unprepare_clocks; 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci for (j = 0; j < MAX_QOS_REGS_NUM; j++) { 69662306a36Sopenharmony_ci pd->qos_save_regs[j] = devm_kcalloc(pmu->dev, 69762306a36Sopenharmony_ci pd->num_qos, 69862306a36Sopenharmony_ci sizeof(u32), 69962306a36Sopenharmony_ci GFP_KERNEL); 70062306a36Sopenharmony_ci if (!pd->qos_save_regs[j]) { 70162306a36Sopenharmony_ci error = -ENOMEM; 70262306a36Sopenharmony_ci goto err_unprepare_clocks; 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci for (j = 0; j < pd->num_qos; j++) { 70762306a36Sopenharmony_ci qos_node = of_parse_phandle(node, "pm_qos", j); 70862306a36Sopenharmony_ci if (!qos_node) { 70962306a36Sopenharmony_ci error = -ENODEV; 71062306a36Sopenharmony_ci goto err_unprepare_clocks; 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci pd->qos_regmap[j] = syscon_node_to_regmap(qos_node); 71362306a36Sopenharmony_ci if (IS_ERR(pd->qos_regmap[j])) { 71462306a36Sopenharmony_ci error = -ENODEV; 71562306a36Sopenharmony_ci of_node_put(qos_node); 71662306a36Sopenharmony_ci goto err_unprepare_clocks; 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci of_node_put(qos_node); 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci if (pd->info->name) 72362306a36Sopenharmony_ci pd->genpd.name = pd->info->name; 72462306a36Sopenharmony_ci else 72562306a36Sopenharmony_ci pd->genpd.name = kbasename(node->full_name); 72662306a36Sopenharmony_ci pd->genpd.power_off = rockchip_pd_power_off; 72762306a36Sopenharmony_ci pd->genpd.power_on = rockchip_pd_power_on; 72862306a36Sopenharmony_ci pd->genpd.attach_dev = rockchip_pd_attach_dev; 72962306a36Sopenharmony_ci pd->genpd.detach_dev = rockchip_pd_detach_dev; 73062306a36Sopenharmony_ci pd->genpd.flags = GENPD_FLAG_PM_CLK; 73162306a36Sopenharmony_ci if (pd_info->active_wakeup) 73262306a36Sopenharmony_ci pd->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP; 73362306a36Sopenharmony_ci pm_genpd_init(&pd->genpd, NULL, 73462306a36Sopenharmony_ci !rockchip_pmu_domain_is_on(pd) || 73562306a36Sopenharmony_ci (pd->info->mem_status_mask && !rockchip_pmu_domain_is_mem_on(pd))); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci pmu->genpd_data.domains[id] = &pd->genpd; 73862306a36Sopenharmony_ci return 0; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_cierr_unprepare_clocks: 74162306a36Sopenharmony_ci clk_bulk_unprepare(pd->num_clks, pd->clks); 74262306a36Sopenharmony_cierr_put_clocks: 74362306a36Sopenharmony_ci clk_bulk_put(pd->num_clks, pd->clks); 74462306a36Sopenharmony_ci return error; 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_cistatic void rockchip_pm_remove_one_domain(struct rockchip_pm_domain *pd) 74862306a36Sopenharmony_ci{ 74962306a36Sopenharmony_ci int ret; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci /* 75262306a36Sopenharmony_ci * We're in the error cleanup already, so we only complain, 75362306a36Sopenharmony_ci * but won't emit another error on top of the original one. 75462306a36Sopenharmony_ci */ 75562306a36Sopenharmony_ci ret = pm_genpd_remove(&pd->genpd); 75662306a36Sopenharmony_ci if (ret < 0) 75762306a36Sopenharmony_ci dev_err(pd->pmu->dev, "failed to remove domain '%s' : %d - state may be inconsistent\n", 75862306a36Sopenharmony_ci pd->genpd.name, ret); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci clk_bulk_unprepare(pd->num_clks, pd->clks); 76162306a36Sopenharmony_ci clk_bulk_put(pd->num_clks, pd->clks); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci /* protect the zeroing of pm->num_clks */ 76462306a36Sopenharmony_ci mutex_lock(&pd->pmu->mutex); 76562306a36Sopenharmony_ci pd->num_clks = 0; 76662306a36Sopenharmony_ci mutex_unlock(&pd->pmu->mutex); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci /* devm will free our memory */ 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_cistatic void rockchip_pm_domain_cleanup(struct rockchip_pmu *pmu) 77262306a36Sopenharmony_ci{ 77362306a36Sopenharmony_ci struct generic_pm_domain *genpd; 77462306a36Sopenharmony_ci struct rockchip_pm_domain *pd; 77562306a36Sopenharmony_ci int i; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci for (i = 0; i < pmu->genpd_data.num_domains; i++) { 77862306a36Sopenharmony_ci genpd = pmu->genpd_data.domains[i]; 77962306a36Sopenharmony_ci if (genpd) { 78062306a36Sopenharmony_ci pd = to_rockchip_pd(genpd); 78162306a36Sopenharmony_ci rockchip_pm_remove_one_domain(pd); 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci /* devm will free our memory */ 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_cistatic void rockchip_configure_pd_cnt(struct rockchip_pmu *pmu, 78962306a36Sopenharmony_ci u32 domain_reg_offset, 79062306a36Sopenharmony_ci unsigned int count) 79162306a36Sopenharmony_ci{ 79262306a36Sopenharmony_ci /* First configure domain power down transition count ... */ 79362306a36Sopenharmony_ci regmap_write(pmu->regmap, domain_reg_offset, count); 79462306a36Sopenharmony_ci /* ... and then power up count. */ 79562306a36Sopenharmony_ci regmap_write(pmu->regmap, domain_reg_offset + 4, count); 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_cistatic int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu, 79962306a36Sopenharmony_ci struct device_node *parent) 80062306a36Sopenharmony_ci{ 80162306a36Sopenharmony_ci struct device_node *np; 80262306a36Sopenharmony_ci struct generic_pm_domain *child_domain, *parent_domain; 80362306a36Sopenharmony_ci int error; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci for_each_child_of_node(parent, np) { 80662306a36Sopenharmony_ci u32 idx; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci error = of_property_read_u32(parent, "reg", &idx); 80962306a36Sopenharmony_ci if (error) { 81062306a36Sopenharmony_ci dev_err(pmu->dev, 81162306a36Sopenharmony_ci "%pOFn: failed to retrieve domain id (reg): %d\n", 81262306a36Sopenharmony_ci parent, error); 81362306a36Sopenharmony_ci goto err_out; 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci parent_domain = pmu->genpd_data.domains[idx]; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci error = rockchip_pm_add_one_domain(pmu, np); 81862306a36Sopenharmony_ci if (error) { 81962306a36Sopenharmony_ci dev_err(pmu->dev, "failed to handle node %pOFn: %d\n", 82062306a36Sopenharmony_ci np, error); 82162306a36Sopenharmony_ci goto err_out; 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci error = of_property_read_u32(np, "reg", &idx); 82562306a36Sopenharmony_ci if (error) { 82662306a36Sopenharmony_ci dev_err(pmu->dev, 82762306a36Sopenharmony_ci "%pOFn: failed to retrieve domain id (reg): %d\n", 82862306a36Sopenharmony_ci np, error); 82962306a36Sopenharmony_ci goto err_out; 83062306a36Sopenharmony_ci } 83162306a36Sopenharmony_ci child_domain = pmu->genpd_data.domains[idx]; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci error = pm_genpd_add_subdomain(parent_domain, child_domain); 83462306a36Sopenharmony_ci if (error) { 83562306a36Sopenharmony_ci dev_err(pmu->dev, "%s failed to add subdomain %s: %d\n", 83662306a36Sopenharmony_ci parent_domain->name, child_domain->name, error); 83762306a36Sopenharmony_ci goto err_out; 83862306a36Sopenharmony_ci } else { 83962306a36Sopenharmony_ci dev_dbg(pmu->dev, "%s add subdomain: %s\n", 84062306a36Sopenharmony_ci parent_domain->name, child_domain->name); 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci rockchip_pm_add_subdomain(pmu, np); 84462306a36Sopenharmony_ci } 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci return 0; 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_cierr_out: 84962306a36Sopenharmony_ci of_node_put(np); 85062306a36Sopenharmony_ci return error; 85162306a36Sopenharmony_ci} 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_cistatic int rockchip_pm_domain_probe(struct platform_device *pdev) 85462306a36Sopenharmony_ci{ 85562306a36Sopenharmony_ci struct device *dev = &pdev->dev; 85662306a36Sopenharmony_ci struct device_node *np = dev->of_node; 85762306a36Sopenharmony_ci struct device_node *node; 85862306a36Sopenharmony_ci struct device *parent; 85962306a36Sopenharmony_ci struct rockchip_pmu *pmu; 86062306a36Sopenharmony_ci const struct of_device_id *match; 86162306a36Sopenharmony_ci const struct rockchip_pmu_info *pmu_info; 86262306a36Sopenharmony_ci int error; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci if (!np) { 86562306a36Sopenharmony_ci dev_err(dev, "device tree node not found\n"); 86662306a36Sopenharmony_ci return -ENODEV; 86762306a36Sopenharmony_ci } 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci match = of_match_device(dev->driver->of_match_table, dev); 87062306a36Sopenharmony_ci if (!match || !match->data) { 87162306a36Sopenharmony_ci dev_err(dev, "missing pmu data\n"); 87262306a36Sopenharmony_ci return -EINVAL; 87362306a36Sopenharmony_ci } 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci pmu_info = match->data; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci pmu = devm_kzalloc(dev, 87862306a36Sopenharmony_ci struct_size(pmu, domains, pmu_info->num_domains), 87962306a36Sopenharmony_ci GFP_KERNEL); 88062306a36Sopenharmony_ci if (!pmu) 88162306a36Sopenharmony_ci return -ENOMEM; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci pmu->dev = &pdev->dev; 88462306a36Sopenharmony_ci mutex_init(&pmu->mutex); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci pmu->info = pmu_info; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci pmu->genpd_data.domains = pmu->domains; 88962306a36Sopenharmony_ci pmu->genpd_data.num_domains = pmu_info->num_domains; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci parent = dev->parent; 89262306a36Sopenharmony_ci if (!parent) { 89362306a36Sopenharmony_ci dev_err(dev, "no parent for syscon devices\n"); 89462306a36Sopenharmony_ci return -ENODEV; 89562306a36Sopenharmony_ci } 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci pmu->regmap = syscon_node_to_regmap(parent->of_node); 89862306a36Sopenharmony_ci if (IS_ERR(pmu->regmap)) { 89962306a36Sopenharmony_ci dev_err(dev, "no regmap available\n"); 90062306a36Sopenharmony_ci return PTR_ERR(pmu->regmap); 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci /* 90462306a36Sopenharmony_ci * Configure power up and down transition delays for CORE 90562306a36Sopenharmony_ci * and GPU domains. 90662306a36Sopenharmony_ci */ 90762306a36Sopenharmony_ci if (pmu_info->core_power_transition_time) 90862306a36Sopenharmony_ci rockchip_configure_pd_cnt(pmu, pmu_info->core_pwrcnt_offset, 90962306a36Sopenharmony_ci pmu_info->core_power_transition_time); 91062306a36Sopenharmony_ci if (pmu_info->gpu_pwrcnt_offset) 91162306a36Sopenharmony_ci rockchip_configure_pd_cnt(pmu, pmu_info->gpu_pwrcnt_offset, 91262306a36Sopenharmony_ci pmu_info->gpu_power_transition_time); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci error = -ENODEV; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci /* 91762306a36Sopenharmony_ci * Prevent any rockchip_pmu_block() from racing with the remainder of 91862306a36Sopenharmony_ci * setup (clocks, register initialization). 91962306a36Sopenharmony_ci */ 92062306a36Sopenharmony_ci mutex_lock(&dmc_pmu_mutex); 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci for_each_available_child_of_node(np, node) { 92362306a36Sopenharmony_ci error = rockchip_pm_add_one_domain(pmu, node); 92462306a36Sopenharmony_ci if (error) { 92562306a36Sopenharmony_ci dev_err(dev, "failed to handle node %pOFn: %d\n", 92662306a36Sopenharmony_ci node, error); 92762306a36Sopenharmony_ci of_node_put(node); 92862306a36Sopenharmony_ci goto err_out; 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci error = rockchip_pm_add_subdomain(pmu, node); 93262306a36Sopenharmony_ci if (error < 0) { 93362306a36Sopenharmony_ci dev_err(dev, "failed to handle subdomain node %pOFn: %d\n", 93462306a36Sopenharmony_ci node, error); 93562306a36Sopenharmony_ci of_node_put(node); 93662306a36Sopenharmony_ci goto err_out; 93762306a36Sopenharmony_ci } 93862306a36Sopenharmony_ci } 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci if (error) { 94162306a36Sopenharmony_ci dev_dbg(dev, "no power domains defined\n"); 94262306a36Sopenharmony_ci goto err_out; 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci error = of_genpd_add_provider_onecell(np, &pmu->genpd_data); 94662306a36Sopenharmony_ci if (error) { 94762306a36Sopenharmony_ci dev_err(dev, "failed to add provider: %d\n", error); 94862306a36Sopenharmony_ci goto err_out; 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci /* We only expect one PMU. */ 95262306a36Sopenharmony_ci if (!WARN_ON_ONCE(dmc_pmu)) 95362306a36Sopenharmony_ci dmc_pmu = pmu; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci mutex_unlock(&dmc_pmu_mutex); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci return 0; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_cierr_out: 96062306a36Sopenharmony_ci rockchip_pm_domain_cleanup(pmu); 96162306a36Sopenharmony_ci mutex_unlock(&dmc_pmu_mutex); 96262306a36Sopenharmony_ci return error; 96362306a36Sopenharmony_ci} 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_cistatic const struct rockchip_domain_info px30_pm_domains[] = { 96662306a36Sopenharmony_ci [PX30_PD_USB] = DOMAIN_PX30("usb", BIT(5), BIT(5), BIT(10), false), 96762306a36Sopenharmony_ci [PX30_PD_SDCARD] = DOMAIN_PX30("sdcard", BIT(8), BIT(8), BIT(9), false), 96862306a36Sopenharmony_ci [PX30_PD_GMAC] = DOMAIN_PX30("gmac", BIT(10), BIT(10), BIT(6), false), 96962306a36Sopenharmony_ci [PX30_PD_MMC_NAND] = DOMAIN_PX30("mmc_nand", BIT(11), BIT(11), BIT(5), false), 97062306a36Sopenharmony_ci [PX30_PD_VPU] = DOMAIN_PX30("vpu", BIT(12), BIT(12), BIT(14), false), 97162306a36Sopenharmony_ci [PX30_PD_VO] = DOMAIN_PX30("vo", BIT(13), BIT(13), BIT(7), false), 97262306a36Sopenharmony_ci [PX30_PD_VI] = DOMAIN_PX30("vi", BIT(14), BIT(14), BIT(8), false), 97362306a36Sopenharmony_ci [PX30_PD_GPU] = DOMAIN_PX30("gpu", BIT(15), BIT(15), BIT(2), false), 97462306a36Sopenharmony_ci}; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_cistatic const struct rockchip_domain_info rv1126_pm_domains[] = { 97762306a36Sopenharmony_ci [RV1126_PD_VEPU] = DOMAIN_RV1126("vepu", BIT(2), BIT(9), BIT(9), false), 97862306a36Sopenharmony_ci [RV1126_PD_VI] = DOMAIN_RV1126("vi", BIT(4), BIT(6), BIT(6), false), 97962306a36Sopenharmony_ci [RV1126_PD_VO] = DOMAIN_RV1126("vo", BIT(5), BIT(7), BIT(7), false), 98062306a36Sopenharmony_ci [RV1126_PD_ISPP] = DOMAIN_RV1126("ispp", BIT(1), BIT(8), BIT(8), false), 98162306a36Sopenharmony_ci [RV1126_PD_VDPU] = DOMAIN_RV1126("vdpu", BIT(3), BIT(10), BIT(10), false), 98262306a36Sopenharmony_ci [RV1126_PD_NVM] = DOMAIN_RV1126("nvm", BIT(7), BIT(11), BIT(11), false), 98362306a36Sopenharmony_ci [RV1126_PD_SDIO] = DOMAIN_RV1126("sdio", BIT(8), BIT(13), BIT(13), false), 98462306a36Sopenharmony_ci [RV1126_PD_USB] = DOMAIN_RV1126("usb", BIT(9), BIT(15), BIT(15), false), 98562306a36Sopenharmony_ci}; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_cistatic const struct rockchip_domain_info rk3036_pm_domains[] = { 98862306a36Sopenharmony_ci [RK3036_PD_MSCH] = DOMAIN_RK3036("msch", BIT(14), BIT(23), BIT(30), true), 98962306a36Sopenharmony_ci [RK3036_PD_CORE] = DOMAIN_RK3036("core", BIT(13), BIT(17), BIT(24), false), 99062306a36Sopenharmony_ci [RK3036_PD_PERI] = DOMAIN_RK3036("peri", BIT(12), BIT(18), BIT(25), false), 99162306a36Sopenharmony_ci [RK3036_PD_VIO] = DOMAIN_RK3036("vio", BIT(11), BIT(19), BIT(26), false), 99262306a36Sopenharmony_ci [RK3036_PD_VPU] = DOMAIN_RK3036("vpu", BIT(10), BIT(20), BIT(27), false), 99362306a36Sopenharmony_ci [RK3036_PD_GPU] = DOMAIN_RK3036("gpu", BIT(9), BIT(21), BIT(28), false), 99462306a36Sopenharmony_ci [RK3036_PD_SYS] = DOMAIN_RK3036("sys", BIT(8), BIT(22), BIT(29), false), 99562306a36Sopenharmony_ci}; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_cistatic const struct rockchip_domain_info rk3066_pm_domains[] = { 99862306a36Sopenharmony_ci [RK3066_PD_GPU] = DOMAIN("gpu", BIT(9), BIT(9), BIT(3), BIT(24), BIT(29), false), 99962306a36Sopenharmony_ci [RK3066_PD_VIDEO] = DOMAIN("video", BIT(8), BIT(8), BIT(4), BIT(23), BIT(28), false), 100062306a36Sopenharmony_ci [RK3066_PD_VIO] = DOMAIN("vio", BIT(7), BIT(7), BIT(5), BIT(22), BIT(27), false), 100162306a36Sopenharmony_ci [RK3066_PD_PERI] = DOMAIN("peri", BIT(6), BIT(6), BIT(2), BIT(25), BIT(30), false), 100262306a36Sopenharmony_ci [RK3066_PD_CPU] = DOMAIN("cpu", 0, BIT(5), BIT(1), BIT(26), BIT(31), false), 100362306a36Sopenharmony_ci}; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_cistatic const struct rockchip_domain_info rk3128_pm_domains[] = { 100662306a36Sopenharmony_ci [RK3128_PD_CORE] = DOMAIN_RK3288("core", BIT(0), BIT(0), BIT(4), false), 100762306a36Sopenharmony_ci [RK3128_PD_MSCH] = DOMAIN_RK3288("msch", 0, 0, BIT(6), true), 100862306a36Sopenharmony_ci [RK3128_PD_VIO] = DOMAIN_RK3288("vio", BIT(3), BIT(3), BIT(2), false), 100962306a36Sopenharmony_ci [RK3128_PD_VIDEO] = DOMAIN_RK3288("video", BIT(2), BIT(2), BIT(1), false), 101062306a36Sopenharmony_ci [RK3128_PD_GPU] = DOMAIN_RK3288("gpu", BIT(1), BIT(1), BIT(3), false), 101162306a36Sopenharmony_ci}; 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_cistatic const struct rockchip_domain_info rk3188_pm_domains[] = { 101462306a36Sopenharmony_ci [RK3188_PD_GPU] = DOMAIN("gpu", BIT(9), BIT(9), BIT(3), BIT(24), BIT(29), false), 101562306a36Sopenharmony_ci [RK3188_PD_VIDEO] = DOMAIN("video", BIT(8), BIT(8), BIT(4), BIT(23), BIT(28), false), 101662306a36Sopenharmony_ci [RK3188_PD_VIO] = DOMAIN("vio", BIT(7), BIT(7), BIT(5), BIT(22), BIT(27), false), 101762306a36Sopenharmony_ci [RK3188_PD_PERI] = DOMAIN("peri", BIT(6), BIT(6), BIT(2), BIT(25), BIT(30), false), 101862306a36Sopenharmony_ci [RK3188_PD_CPU] = DOMAIN("cpu", BIT(5), BIT(5), BIT(1), BIT(26), BIT(31), false), 101962306a36Sopenharmony_ci}; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_cistatic const struct rockchip_domain_info rk3228_pm_domains[] = { 102262306a36Sopenharmony_ci [RK3228_PD_CORE] = DOMAIN_RK3036("core", BIT(0), BIT(0), BIT(16), true), 102362306a36Sopenharmony_ci [RK3228_PD_MSCH] = DOMAIN_RK3036("msch", BIT(1), BIT(1), BIT(17), true), 102462306a36Sopenharmony_ci [RK3228_PD_BUS] = DOMAIN_RK3036("bus", BIT(2), BIT(2), BIT(18), true), 102562306a36Sopenharmony_ci [RK3228_PD_SYS] = DOMAIN_RK3036("sys", BIT(3), BIT(3), BIT(19), true), 102662306a36Sopenharmony_ci [RK3228_PD_VIO] = DOMAIN_RK3036("vio", BIT(4), BIT(4), BIT(20), false), 102762306a36Sopenharmony_ci [RK3228_PD_VOP] = DOMAIN_RK3036("vop", BIT(5), BIT(5), BIT(21), false), 102862306a36Sopenharmony_ci [RK3228_PD_VPU] = DOMAIN_RK3036("vpu", BIT(6), BIT(6), BIT(22), false), 102962306a36Sopenharmony_ci [RK3228_PD_RKVDEC] = DOMAIN_RK3036("vdec", BIT(7), BIT(7), BIT(23), false), 103062306a36Sopenharmony_ci [RK3228_PD_GPU] = DOMAIN_RK3036("gpu", BIT(8), BIT(8), BIT(24), false), 103162306a36Sopenharmony_ci [RK3228_PD_PERI] = DOMAIN_RK3036("peri", BIT(9), BIT(9), BIT(25), true), 103262306a36Sopenharmony_ci [RK3228_PD_GMAC] = DOMAIN_RK3036("gmac", BIT(10), BIT(10), BIT(26), false), 103362306a36Sopenharmony_ci}; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_cistatic const struct rockchip_domain_info rk3288_pm_domains[] = { 103662306a36Sopenharmony_ci [RK3288_PD_VIO] = DOMAIN_RK3288("vio", BIT(7), BIT(7), BIT(4), false), 103762306a36Sopenharmony_ci [RK3288_PD_HEVC] = DOMAIN_RK3288("hevc", BIT(14), BIT(10), BIT(9), false), 103862306a36Sopenharmony_ci [RK3288_PD_VIDEO] = DOMAIN_RK3288("video", BIT(8), BIT(8), BIT(3), false), 103962306a36Sopenharmony_ci [RK3288_PD_GPU] = DOMAIN_RK3288("gpu", BIT(9), BIT(9), BIT(2), false), 104062306a36Sopenharmony_ci}; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_cistatic const struct rockchip_domain_info rk3328_pm_domains[] = { 104362306a36Sopenharmony_ci [RK3328_PD_CORE] = DOMAIN_RK3328("core", 0, BIT(0), BIT(0), false), 104462306a36Sopenharmony_ci [RK3328_PD_GPU] = DOMAIN_RK3328("gpu", 0, BIT(1), BIT(1), false), 104562306a36Sopenharmony_ci [RK3328_PD_BUS] = DOMAIN_RK3328("bus", 0, BIT(2), BIT(2), true), 104662306a36Sopenharmony_ci [RK3328_PD_MSCH] = DOMAIN_RK3328("msch", 0, BIT(3), BIT(3), true), 104762306a36Sopenharmony_ci [RK3328_PD_PERI] = DOMAIN_RK3328("peri", 0, BIT(4), BIT(4), true), 104862306a36Sopenharmony_ci [RK3328_PD_VIDEO] = DOMAIN_RK3328("video", 0, BIT(5), BIT(5), false), 104962306a36Sopenharmony_ci [RK3328_PD_HEVC] = DOMAIN_RK3328("hevc", 0, BIT(6), BIT(6), false), 105062306a36Sopenharmony_ci [RK3328_PD_VIO] = DOMAIN_RK3328("vio", 0, BIT(8), BIT(8), false), 105162306a36Sopenharmony_ci [RK3328_PD_VPU] = DOMAIN_RK3328("vpu", 0, BIT(9), BIT(9), false), 105262306a36Sopenharmony_ci}; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_cistatic const struct rockchip_domain_info rk3366_pm_domains[] = { 105562306a36Sopenharmony_ci [RK3366_PD_PERI] = DOMAIN_RK3368("peri", BIT(10), BIT(10), BIT(6), true), 105662306a36Sopenharmony_ci [RK3366_PD_VIO] = DOMAIN_RK3368("vio", BIT(14), BIT(14), BIT(8), false), 105762306a36Sopenharmony_ci [RK3366_PD_VIDEO] = DOMAIN_RK3368("video", BIT(13), BIT(13), BIT(7), false), 105862306a36Sopenharmony_ci [RK3366_PD_RKVDEC] = DOMAIN_RK3368("vdec", BIT(11), BIT(11), BIT(7), false), 105962306a36Sopenharmony_ci [RK3366_PD_WIFIBT] = DOMAIN_RK3368("wifibt", BIT(8), BIT(8), BIT(9), false), 106062306a36Sopenharmony_ci [RK3366_PD_VPU] = DOMAIN_RK3368("vpu", BIT(12), BIT(12), BIT(7), false), 106162306a36Sopenharmony_ci [RK3366_PD_GPU] = DOMAIN_RK3368("gpu", BIT(15), BIT(15), BIT(2), false), 106262306a36Sopenharmony_ci}; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_cistatic const struct rockchip_domain_info rk3368_pm_domains[] = { 106562306a36Sopenharmony_ci [RK3368_PD_PERI] = DOMAIN_RK3368("peri", BIT(13), BIT(12), BIT(6), true), 106662306a36Sopenharmony_ci [RK3368_PD_VIO] = DOMAIN_RK3368("vio", BIT(15), BIT(14), BIT(8), false), 106762306a36Sopenharmony_ci [RK3368_PD_VIDEO] = DOMAIN_RK3368("video", BIT(14), BIT(13), BIT(7), false), 106862306a36Sopenharmony_ci [RK3368_PD_GPU_0] = DOMAIN_RK3368("gpu_0", BIT(16), BIT(15), BIT(2), false), 106962306a36Sopenharmony_ci [RK3368_PD_GPU_1] = DOMAIN_RK3368("gpu_1", BIT(17), BIT(16), BIT(2), false), 107062306a36Sopenharmony_ci}; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_cistatic const struct rockchip_domain_info rk3399_pm_domains[] = { 107362306a36Sopenharmony_ci [RK3399_PD_TCPD0] = DOMAIN_RK3399("tcpd0", BIT(8), BIT(8), 0, false), 107462306a36Sopenharmony_ci [RK3399_PD_TCPD1] = DOMAIN_RK3399("tcpd1", BIT(9), BIT(9), 0, false), 107562306a36Sopenharmony_ci [RK3399_PD_CCI] = DOMAIN_RK3399("cci", BIT(10), BIT(10), 0, true), 107662306a36Sopenharmony_ci [RK3399_PD_CCI0] = DOMAIN_RK3399("cci0", 0, 0, BIT(15), true), 107762306a36Sopenharmony_ci [RK3399_PD_CCI1] = DOMAIN_RK3399("cci1", 0, 0, BIT(16), true), 107862306a36Sopenharmony_ci [RK3399_PD_PERILP] = DOMAIN_RK3399("perilp", BIT(11), BIT(11), BIT(1), true), 107962306a36Sopenharmony_ci [RK3399_PD_PERIHP] = DOMAIN_RK3399("perihp", BIT(12), BIT(12), BIT(2), true), 108062306a36Sopenharmony_ci [RK3399_PD_CENTER] = DOMAIN_RK3399("center", BIT(13), BIT(13), BIT(14), true), 108162306a36Sopenharmony_ci [RK3399_PD_VIO] = DOMAIN_RK3399("vio", BIT(14), BIT(14), BIT(17), false), 108262306a36Sopenharmony_ci [RK3399_PD_GPU] = DOMAIN_RK3399("gpu", BIT(15), BIT(15), BIT(0), false), 108362306a36Sopenharmony_ci [RK3399_PD_VCODEC] = DOMAIN_RK3399("vcodec", BIT(16), BIT(16), BIT(3), false), 108462306a36Sopenharmony_ci [RK3399_PD_VDU] = DOMAIN_RK3399("vdu", BIT(17), BIT(17), BIT(4), false), 108562306a36Sopenharmony_ci [RK3399_PD_RGA] = DOMAIN_RK3399("rga", BIT(18), BIT(18), BIT(5), false), 108662306a36Sopenharmony_ci [RK3399_PD_IEP] = DOMAIN_RK3399("iep", BIT(19), BIT(19), BIT(6), false), 108762306a36Sopenharmony_ci [RK3399_PD_VO] = DOMAIN_RK3399("vo", BIT(20), BIT(20), 0, false), 108862306a36Sopenharmony_ci [RK3399_PD_VOPB] = DOMAIN_RK3399("vopb", 0, 0, BIT(7), false), 108962306a36Sopenharmony_ci [RK3399_PD_VOPL] = DOMAIN_RK3399("vopl", 0, 0, BIT(8), false), 109062306a36Sopenharmony_ci [RK3399_PD_ISP0] = DOMAIN_RK3399("isp0", BIT(22), BIT(22), BIT(9), false), 109162306a36Sopenharmony_ci [RK3399_PD_ISP1] = DOMAIN_RK3399("isp1", BIT(23), BIT(23), BIT(10), false), 109262306a36Sopenharmony_ci [RK3399_PD_HDCP] = DOMAIN_RK3399("hdcp", BIT(24), BIT(24), BIT(11), false), 109362306a36Sopenharmony_ci [RK3399_PD_GMAC] = DOMAIN_RK3399("gmac", BIT(25), BIT(25), BIT(23), true), 109462306a36Sopenharmony_ci [RK3399_PD_EMMC] = DOMAIN_RK3399("emmc", BIT(26), BIT(26), BIT(24), true), 109562306a36Sopenharmony_ci [RK3399_PD_USB3] = DOMAIN_RK3399("usb3", BIT(27), BIT(27), BIT(12), true), 109662306a36Sopenharmony_ci [RK3399_PD_EDP] = DOMAIN_RK3399("edp", BIT(28), BIT(28), BIT(22), false), 109762306a36Sopenharmony_ci [RK3399_PD_GIC] = DOMAIN_RK3399("gic", BIT(29), BIT(29), BIT(27), true), 109862306a36Sopenharmony_ci [RK3399_PD_SD] = DOMAIN_RK3399("sd", BIT(30), BIT(30), BIT(28), true), 109962306a36Sopenharmony_ci [RK3399_PD_SDIOAUDIO] = DOMAIN_RK3399("sdioaudio", BIT(31), BIT(31), BIT(29), true), 110062306a36Sopenharmony_ci}; 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_cistatic const struct rockchip_domain_info rk3568_pm_domains[] = { 110362306a36Sopenharmony_ci [RK3568_PD_NPU] = DOMAIN_RK3568("npu", BIT(1), BIT(2), false), 110462306a36Sopenharmony_ci [RK3568_PD_GPU] = DOMAIN_RK3568("gpu", BIT(0), BIT(1), false), 110562306a36Sopenharmony_ci [RK3568_PD_VI] = DOMAIN_RK3568("vi", BIT(6), BIT(3), false), 110662306a36Sopenharmony_ci [RK3568_PD_VO] = DOMAIN_RK3568("vo", BIT(7), BIT(4), false), 110762306a36Sopenharmony_ci [RK3568_PD_RGA] = DOMAIN_RK3568("rga", BIT(5), BIT(5), false), 110862306a36Sopenharmony_ci [RK3568_PD_VPU] = DOMAIN_RK3568("vpu", BIT(2), BIT(6), false), 110962306a36Sopenharmony_ci [RK3568_PD_RKVDEC] = DOMAIN_RK3568("vdec", BIT(4), BIT(8), false), 111062306a36Sopenharmony_ci [RK3568_PD_RKVENC] = DOMAIN_RK3568("venc", BIT(3), BIT(7), false), 111162306a36Sopenharmony_ci [RK3568_PD_PIPE] = DOMAIN_RK3568("pipe", BIT(8), BIT(11), false), 111262306a36Sopenharmony_ci}; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_cistatic const struct rockchip_domain_info rk3588_pm_domains[] = { 111562306a36Sopenharmony_ci [RK3588_PD_GPU] = DOMAIN_RK3588("gpu", 0x0, BIT(0), 0, 0x0, 0, BIT(1), 0x0, BIT(0), BIT(0), false), 111662306a36Sopenharmony_ci [RK3588_PD_NPU] = DOMAIN_RK3588("npu", 0x0, BIT(1), BIT(1), 0x0, 0, 0, 0x0, 0, 0, false), 111762306a36Sopenharmony_ci [RK3588_PD_VCODEC] = DOMAIN_RK3588("vcodec", 0x0, BIT(2), BIT(2), 0x0, 0, 0, 0x0, 0, 0, false), 111862306a36Sopenharmony_ci [RK3588_PD_NPUTOP] = DOMAIN_RK3588("nputop", 0x0, BIT(3), 0, 0x0, BIT(11), BIT(2), 0x0, BIT(1), BIT(1), false), 111962306a36Sopenharmony_ci [RK3588_PD_NPU1] = DOMAIN_RK3588("npu1", 0x0, BIT(4), 0, 0x0, BIT(12), BIT(3), 0x0, BIT(2), BIT(2), false), 112062306a36Sopenharmony_ci [RK3588_PD_NPU2] = DOMAIN_RK3588("npu2", 0x0, BIT(5), 0, 0x0, BIT(13), BIT(4), 0x0, BIT(3), BIT(3), false), 112162306a36Sopenharmony_ci [RK3588_PD_VENC0] = DOMAIN_RK3588("venc0", 0x0, BIT(6), 0, 0x0, BIT(14), BIT(5), 0x0, BIT(4), BIT(4), false), 112262306a36Sopenharmony_ci [RK3588_PD_VENC1] = DOMAIN_RK3588("venc1", 0x0, BIT(7), 0, 0x0, BIT(15), BIT(6), 0x0, BIT(5), BIT(5), false), 112362306a36Sopenharmony_ci [RK3588_PD_RKVDEC0] = DOMAIN_RK3588("rkvdec0", 0x0, BIT(8), 0, 0x0, BIT(16), BIT(7), 0x0, BIT(6), BIT(6), false), 112462306a36Sopenharmony_ci [RK3588_PD_RKVDEC1] = DOMAIN_RK3588("rkvdec1", 0x0, BIT(9), 0, 0x0, BIT(17), BIT(8), 0x0, BIT(7), BIT(7), false), 112562306a36Sopenharmony_ci [RK3588_PD_VDPU] = DOMAIN_RK3588("vdpu", 0x0, BIT(10), 0, 0x0, BIT(18), BIT(9), 0x0, BIT(8), BIT(8), false), 112662306a36Sopenharmony_ci [RK3588_PD_RGA30] = DOMAIN_RK3588("rga30", 0x0, BIT(11), 0, 0x0, BIT(19), BIT(10), 0x0, 0, 0, false), 112762306a36Sopenharmony_ci [RK3588_PD_AV1] = DOMAIN_RK3588("av1", 0x0, BIT(12), 0, 0x0, BIT(20), BIT(11), 0x0, BIT(9), BIT(9), false), 112862306a36Sopenharmony_ci [RK3588_PD_VI] = DOMAIN_RK3588("vi", 0x0, BIT(13), 0, 0x0, BIT(21), BIT(12), 0x0, BIT(10), BIT(10), false), 112962306a36Sopenharmony_ci [RK3588_PD_FEC] = DOMAIN_RK3588("fec", 0x0, BIT(14), 0, 0x0, BIT(22), BIT(13), 0x0, 0, 0, false), 113062306a36Sopenharmony_ci [RK3588_PD_ISP1] = DOMAIN_RK3588("isp1", 0x0, BIT(15), 0, 0x0, BIT(23), BIT(14), 0x0, BIT(11), BIT(11), false), 113162306a36Sopenharmony_ci [RK3588_PD_RGA31] = DOMAIN_RK3588("rga31", 0x4, BIT(0), 0, 0x0, BIT(24), BIT(15), 0x0, BIT(12), BIT(12), false), 113262306a36Sopenharmony_ci [RK3588_PD_VOP] = DOMAIN_RK3588("vop", 0x4, BIT(1), 0, 0x0, BIT(25), BIT(16), 0x0, BIT(13) | BIT(14), BIT(13) | BIT(14), false), 113362306a36Sopenharmony_ci [RK3588_PD_VO0] = DOMAIN_RK3588("vo0", 0x4, BIT(2), 0, 0x0, BIT(26), BIT(17), 0x0, BIT(15), BIT(15), false), 113462306a36Sopenharmony_ci [RK3588_PD_VO1] = DOMAIN_RK3588("vo1", 0x4, BIT(3), 0, 0x0, BIT(27), BIT(18), 0x4, BIT(0), BIT(16), false), 113562306a36Sopenharmony_ci [RK3588_PD_AUDIO] = DOMAIN_RK3588("audio", 0x4, BIT(4), 0, 0x0, BIT(28), BIT(19), 0x4, BIT(1), BIT(17), false), 113662306a36Sopenharmony_ci [RK3588_PD_PHP] = DOMAIN_RK3588("php", 0x4, BIT(5), 0, 0x0, BIT(29), BIT(20), 0x4, BIT(5), BIT(21), false), 113762306a36Sopenharmony_ci [RK3588_PD_GMAC] = DOMAIN_RK3588("gmac", 0x4, BIT(6), 0, 0x0, BIT(30), BIT(21), 0x0, 0, 0, false), 113862306a36Sopenharmony_ci [RK3588_PD_PCIE] = DOMAIN_RK3588("pcie", 0x4, BIT(7), 0, 0x0, BIT(31), BIT(22), 0x0, 0, 0, true), 113962306a36Sopenharmony_ci [RK3588_PD_NVM] = DOMAIN_RK3588("nvm", 0x4, BIT(8), BIT(24), 0x4, 0, 0, 0x4, BIT(2), BIT(18), false), 114062306a36Sopenharmony_ci [RK3588_PD_NVM0] = DOMAIN_RK3588("nvm0", 0x4, BIT(9), 0, 0x4, BIT(1), BIT(23), 0x0, 0, 0, false), 114162306a36Sopenharmony_ci [RK3588_PD_SDIO] = DOMAIN_RK3588("sdio", 0x4, BIT(10), 0, 0x4, BIT(2), BIT(24), 0x4, BIT(3), BIT(19), false), 114262306a36Sopenharmony_ci [RK3588_PD_USB] = DOMAIN_RK3588("usb", 0x4, BIT(11), 0, 0x4, BIT(3), BIT(25), 0x4, BIT(4), BIT(20), true), 114362306a36Sopenharmony_ci [RK3588_PD_SDMMC] = DOMAIN_RK3588("sdmmc", 0x4, BIT(13), 0, 0x4, BIT(5), BIT(26), 0x0, 0, 0, false), 114462306a36Sopenharmony_ci}; 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_cistatic const struct rockchip_pmu_info px30_pmu = { 114762306a36Sopenharmony_ci .pwr_offset = 0x18, 114862306a36Sopenharmony_ci .status_offset = 0x20, 114962306a36Sopenharmony_ci .req_offset = 0x64, 115062306a36Sopenharmony_ci .idle_offset = 0x6c, 115162306a36Sopenharmony_ci .ack_offset = 0x6c, 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci .num_domains = ARRAY_SIZE(px30_pm_domains), 115462306a36Sopenharmony_ci .domain_info = px30_pm_domains, 115562306a36Sopenharmony_ci}; 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_cistatic const struct rockchip_pmu_info rk3036_pmu = { 115862306a36Sopenharmony_ci .req_offset = 0x148, 115962306a36Sopenharmony_ci .idle_offset = 0x14c, 116062306a36Sopenharmony_ci .ack_offset = 0x14c, 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci .num_domains = ARRAY_SIZE(rk3036_pm_domains), 116362306a36Sopenharmony_ci .domain_info = rk3036_pm_domains, 116462306a36Sopenharmony_ci}; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_cistatic const struct rockchip_pmu_info rk3066_pmu = { 116762306a36Sopenharmony_ci .pwr_offset = 0x08, 116862306a36Sopenharmony_ci .status_offset = 0x0c, 116962306a36Sopenharmony_ci .req_offset = 0x38, /* PMU_MISC_CON1 */ 117062306a36Sopenharmony_ci .idle_offset = 0x0c, 117162306a36Sopenharmony_ci .ack_offset = 0x0c, 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci .num_domains = ARRAY_SIZE(rk3066_pm_domains), 117462306a36Sopenharmony_ci .domain_info = rk3066_pm_domains, 117562306a36Sopenharmony_ci}; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_cistatic const struct rockchip_pmu_info rk3128_pmu = { 117862306a36Sopenharmony_ci .pwr_offset = 0x04, 117962306a36Sopenharmony_ci .status_offset = 0x08, 118062306a36Sopenharmony_ci .req_offset = 0x0c, 118162306a36Sopenharmony_ci .idle_offset = 0x10, 118262306a36Sopenharmony_ci .ack_offset = 0x10, 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci .num_domains = ARRAY_SIZE(rk3128_pm_domains), 118562306a36Sopenharmony_ci .domain_info = rk3128_pm_domains, 118662306a36Sopenharmony_ci}; 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_cistatic const struct rockchip_pmu_info rk3188_pmu = { 118962306a36Sopenharmony_ci .pwr_offset = 0x08, 119062306a36Sopenharmony_ci .status_offset = 0x0c, 119162306a36Sopenharmony_ci .req_offset = 0x38, /* PMU_MISC_CON1 */ 119262306a36Sopenharmony_ci .idle_offset = 0x0c, 119362306a36Sopenharmony_ci .ack_offset = 0x0c, 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci .num_domains = ARRAY_SIZE(rk3188_pm_domains), 119662306a36Sopenharmony_ci .domain_info = rk3188_pm_domains, 119762306a36Sopenharmony_ci}; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_cistatic const struct rockchip_pmu_info rk3228_pmu = { 120062306a36Sopenharmony_ci .req_offset = 0x40c, 120162306a36Sopenharmony_ci .idle_offset = 0x488, 120262306a36Sopenharmony_ci .ack_offset = 0x488, 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci .num_domains = ARRAY_SIZE(rk3228_pm_domains), 120562306a36Sopenharmony_ci .domain_info = rk3228_pm_domains, 120662306a36Sopenharmony_ci}; 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_cistatic const struct rockchip_pmu_info rk3288_pmu = { 120962306a36Sopenharmony_ci .pwr_offset = 0x08, 121062306a36Sopenharmony_ci .status_offset = 0x0c, 121162306a36Sopenharmony_ci .req_offset = 0x10, 121262306a36Sopenharmony_ci .idle_offset = 0x14, 121362306a36Sopenharmony_ci .ack_offset = 0x14, 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci .core_pwrcnt_offset = 0x34, 121662306a36Sopenharmony_ci .gpu_pwrcnt_offset = 0x3c, 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci .core_power_transition_time = 24, /* 1us */ 121962306a36Sopenharmony_ci .gpu_power_transition_time = 24, /* 1us */ 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci .num_domains = ARRAY_SIZE(rk3288_pm_domains), 122262306a36Sopenharmony_ci .domain_info = rk3288_pm_domains, 122362306a36Sopenharmony_ci}; 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_cistatic const struct rockchip_pmu_info rk3328_pmu = { 122662306a36Sopenharmony_ci .req_offset = 0x414, 122762306a36Sopenharmony_ci .idle_offset = 0x484, 122862306a36Sopenharmony_ci .ack_offset = 0x484, 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci .num_domains = ARRAY_SIZE(rk3328_pm_domains), 123162306a36Sopenharmony_ci .domain_info = rk3328_pm_domains, 123262306a36Sopenharmony_ci}; 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_cistatic const struct rockchip_pmu_info rk3366_pmu = { 123562306a36Sopenharmony_ci .pwr_offset = 0x0c, 123662306a36Sopenharmony_ci .status_offset = 0x10, 123762306a36Sopenharmony_ci .req_offset = 0x3c, 123862306a36Sopenharmony_ci .idle_offset = 0x40, 123962306a36Sopenharmony_ci .ack_offset = 0x40, 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci .core_pwrcnt_offset = 0x48, 124262306a36Sopenharmony_ci .gpu_pwrcnt_offset = 0x50, 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci .core_power_transition_time = 24, 124562306a36Sopenharmony_ci .gpu_power_transition_time = 24, 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci .num_domains = ARRAY_SIZE(rk3366_pm_domains), 124862306a36Sopenharmony_ci .domain_info = rk3366_pm_domains, 124962306a36Sopenharmony_ci}; 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_cistatic const struct rockchip_pmu_info rk3368_pmu = { 125262306a36Sopenharmony_ci .pwr_offset = 0x0c, 125362306a36Sopenharmony_ci .status_offset = 0x10, 125462306a36Sopenharmony_ci .req_offset = 0x3c, 125562306a36Sopenharmony_ci .idle_offset = 0x40, 125662306a36Sopenharmony_ci .ack_offset = 0x40, 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci .core_pwrcnt_offset = 0x48, 125962306a36Sopenharmony_ci .gpu_pwrcnt_offset = 0x50, 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci .core_power_transition_time = 24, 126262306a36Sopenharmony_ci .gpu_power_transition_time = 24, 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci .num_domains = ARRAY_SIZE(rk3368_pm_domains), 126562306a36Sopenharmony_ci .domain_info = rk3368_pm_domains, 126662306a36Sopenharmony_ci}; 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_cistatic const struct rockchip_pmu_info rk3399_pmu = { 126962306a36Sopenharmony_ci .pwr_offset = 0x14, 127062306a36Sopenharmony_ci .status_offset = 0x18, 127162306a36Sopenharmony_ci .req_offset = 0x60, 127262306a36Sopenharmony_ci .idle_offset = 0x64, 127362306a36Sopenharmony_ci .ack_offset = 0x68, 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci /* ARM Trusted Firmware manages power transition times */ 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci .num_domains = ARRAY_SIZE(rk3399_pm_domains), 127862306a36Sopenharmony_ci .domain_info = rk3399_pm_domains, 127962306a36Sopenharmony_ci}; 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_cistatic const struct rockchip_pmu_info rk3568_pmu = { 128262306a36Sopenharmony_ci .pwr_offset = 0xa0, 128362306a36Sopenharmony_ci .status_offset = 0x98, 128462306a36Sopenharmony_ci .req_offset = 0x50, 128562306a36Sopenharmony_ci .idle_offset = 0x68, 128662306a36Sopenharmony_ci .ack_offset = 0x60, 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci .num_domains = ARRAY_SIZE(rk3568_pm_domains), 128962306a36Sopenharmony_ci .domain_info = rk3568_pm_domains, 129062306a36Sopenharmony_ci}; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_cistatic const struct rockchip_pmu_info rk3588_pmu = { 129362306a36Sopenharmony_ci .pwr_offset = 0x14c, 129462306a36Sopenharmony_ci .status_offset = 0x180, 129562306a36Sopenharmony_ci .req_offset = 0x10c, 129662306a36Sopenharmony_ci .idle_offset = 0x120, 129762306a36Sopenharmony_ci .ack_offset = 0x118, 129862306a36Sopenharmony_ci .mem_pwr_offset = 0x1a0, 129962306a36Sopenharmony_ci .chain_status_offset = 0x1f0, 130062306a36Sopenharmony_ci .mem_status_offset = 0x1f8, 130162306a36Sopenharmony_ci .repair_status_offset = 0x290, 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci .num_domains = ARRAY_SIZE(rk3588_pm_domains), 130462306a36Sopenharmony_ci .domain_info = rk3588_pm_domains, 130562306a36Sopenharmony_ci}; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_cistatic const struct rockchip_pmu_info rv1126_pmu = { 130862306a36Sopenharmony_ci .pwr_offset = 0x110, 130962306a36Sopenharmony_ci .status_offset = 0x108, 131062306a36Sopenharmony_ci .req_offset = 0xc0, 131162306a36Sopenharmony_ci .idle_offset = 0xd8, 131262306a36Sopenharmony_ci .ack_offset = 0xd0, 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci .num_domains = ARRAY_SIZE(rv1126_pm_domains), 131562306a36Sopenharmony_ci .domain_info = rv1126_pm_domains, 131662306a36Sopenharmony_ci}; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_cistatic const struct of_device_id rockchip_pm_domain_dt_match[] = { 131962306a36Sopenharmony_ci { 132062306a36Sopenharmony_ci .compatible = "rockchip,px30-power-controller", 132162306a36Sopenharmony_ci .data = (void *)&px30_pmu, 132262306a36Sopenharmony_ci }, 132362306a36Sopenharmony_ci { 132462306a36Sopenharmony_ci .compatible = "rockchip,rk3036-power-controller", 132562306a36Sopenharmony_ci .data = (void *)&rk3036_pmu, 132662306a36Sopenharmony_ci }, 132762306a36Sopenharmony_ci { 132862306a36Sopenharmony_ci .compatible = "rockchip,rk3066-power-controller", 132962306a36Sopenharmony_ci .data = (void *)&rk3066_pmu, 133062306a36Sopenharmony_ci }, 133162306a36Sopenharmony_ci { 133262306a36Sopenharmony_ci .compatible = "rockchip,rk3128-power-controller", 133362306a36Sopenharmony_ci .data = (void *)&rk3128_pmu, 133462306a36Sopenharmony_ci }, 133562306a36Sopenharmony_ci { 133662306a36Sopenharmony_ci .compatible = "rockchip,rk3188-power-controller", 133762306a36Sopenharmony_ci .data = (void *)&rk3188_pmu, 133862306a36Sopenharmony_ci }, 133962306a36Sopenharmony_ci { 134062306a36Sopenharmony_ci .compatible = "rockchip,rk3228-power-controller", 134162306a36Sopenharmony_ci .data = (void *)&rk3228_pmu, 134262306a36Sopenharmony_ci }, 134362306a36Sopenharmony_ci { 134462306a36Sopenharmony_ci .compatible = "rockchip,rk3288-power-controller", 134562306a36Sopenharmony_ci .data = (void *)&rk3288_pmu, 134662306a36Sopenharmony_ci }, 134762306a36Sopenharmony_ci { 134862306a36Sopenharmony_ci .compatible = "rockchip,rk3328-power-controller", 134962306a36Sopenharmony_ci .data = (void *)&rk3328_pmu, 135062306a36Sopenharmony_ci }, 135162306a36Sopenharmony_ci { 135262306a36Sopenharmony_ci .compatible = "rockchip,rk3366-power-controller", 135362306a36Sopenharmony_ci .data = (void *)&rk3366_pmu, 135462306a36Sopenharmony_ci }, 135562306a36Sopenharmony_ci { 135662306a36Sopenharmony_ci .compatible = "rockchip,rk3368-power-controller", 135762306a36Sopenharmony_ci .data = (void *)&rk3368_pmu, 135862306a36Sopenharmony_ci }, 135962306a36Sopenharmony_ci { 136062306a36Sopenharmony_ci .compatible = "rockchip,rk3399-power-controller", 136162306a36Sopenharmony_ci .data = (void *)&rk3399_pmu, 136262306a36Sopenharmony_ci }, 136362306a36Sopenharmony_ci { 136462306a36Sopenharmony_ci .compatible = "rockchip,rk3568-power-controller", 136562306a36Sopenharmony_ci .data = (void *)&rk3568_pmu, 136662306a36Sopenharmony_ci }, 136762306a36Sopenharmony_ci { 136862306a36Sopenharmony_ci .compatible = "rockchip,rk3588-power-controller", 136962306a36Sopenharmony_ci .data = (void *)&rk3588_pmu, 137062306a36Sopenharmony_ci }, 137162306a36Sopenharmony_ci { 137262306a36Sopenharmony_ci .compatible = "rockchip,rv1126-power-controller", 137362306a36Sopenharmony_ci .data = (void *)&rv1126_pmu, 137462306a36Sopenharmony_ci }, 137562306a36Sopenharmony_ci { /* sentinel */ }, 137662306a36Sopenharmony_ci}; 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_cistatic struct platform_driver rockchip_pm_domain_driver = { 137962306a36Sopenharmony_ci .probe = rockchip_pm_domain_probe, 138062306a36Sopenharmony_ci .driver = { 138162306a36Sopenharmony_ci .name = "rockchip-pm-domain", 138262306a36Sopenharmony_ci .of_match_table = rockchip_pm_domain_dt_match, 138362306a36Sopenharmony_ci /* 138462306a36Sopenharmony_ci * We can't forcibly eject devices from the power 138562306a36Sopenharmony_ci * domain, so we can't really remove power domains 138662306a36Sopenharmony_ci * once they were added. 138762306a36Sopenharmony_ci */ 138862306a36Sopenharmony_ci .suppress_bind_attrs = true, 138962306a36Sopenharmony_ci }, 139062306a36Sopenharmony_ci}; 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_cistatic int __init rockchip_pm_domain_drv_register(void) 139362306a36Sopenharmony_ci{ 139462306a36Sopenharmony_ci return platform_driver_register(&rockchip_pm_domain_driver); 139562306a36Sopenharmony_ci} 139662306a36Sopenharmony_cipostcore_initcall(rockchip_pm_domain_drv_register); 1397