162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright 2012 Advanced Micro Devices, Inc. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 562306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 662306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation 762306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 862306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 962306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 1262306a36Sopenharmony_ci * all copies or substantial portions of the Software. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1562306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1662306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1762306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 1862306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 1962306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2062306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include "radeon.h" 2562306a36Sopenharmony_ci#include "radeon_asic.h" 2662306a36Sopenharmony_ci#include "sumod.h" 2762306a36Sopenharmony_ci#include "r600_dpm.h" 2862306a36Sopenharmony_ci#include "cypress_dpm.h" 2962306a36Sopenharmony_ci#include "sumo_dpm.h" 3062306a36Sopenharmony_ci#include <linux/seq_file.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define SUMO_MAX_DEEPSLEEP_DIVIDER_ID 5 3362306a36Sopenharmony_ci#define SUMO_MINIMUM_ENGINE_CLOCK 800 3462306a36Sopenharmony_ci#define BOOST_DPM_LEVEL 7 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic const u32 sumo_utc[SUMO_PM_NUMBER_OF_TC] = 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci SUMO_UTC_DFLT_00, 3962306a36Sopenharmony_ci SUMO_UTC_DFLT_01, 4062306a36Sopenharmony_ci SUMO_UTC_DFLT_02, 4162306a36Sopenharmony_ci SUMO_UTC_DFLT_03, 4262306a36Sopenharmony_ci SUMO_UTC_DFLT_04, 4362306a36Sopenharmony_ci SUMO_UTC_DFLT_05, 4462306a36Sopenharmony_ci SUMO_UTC_DFLT_06, 4562306a36Sopenharmony_ci SUMO_UTC_DFLT_07, 4662306a36Sopenharmony_ci SUMO_UTC_DFLT_08, 4762306a36Sopenharmony_ci SUMO_UTC_DFLT_09, 4862306a36Sopenharmony_ci SUMO_UTC_DFLT_10, 4962306a36Sopenharmony_ci SUMO_UTC_DFLT_11, 5062306a36Sopenharmony_ci SUMO_UTC_DFLT_12, 5162306a36Sopenharmony_ci SUMO_UTC_DFLT_13, 5262306a36Sopenharmony_ci SUMO_UTC_DFLT_14, 5362306a36Sopenharmony_ci}; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic const u32 sumo_dtc[SUMO_PM_NUMBER_OF_TC] = 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci SUMO_DTC_DFLT_00, 5862306a36Sopenharmony_ci SUMO_DTC_DFLT_01, 5962306a36Sopenharmony_ci SUMO_DTC_DFLT_02, 6062306a36Sopenharmony_ci SUMO_DTC_DFLT_03, 6162306a36Sopenharmony_ci SUMO_DTC_DFLT_04, 6262306a36Sopenharmony_ci SUMO_DTC_DFLT_05, 6362306a36Sopenharmony_ci SUMO_DTC_DFLT_06, 6462306a36Sopenharmony_ci SUMO_DTC_DFLT_07, 6562306a36Sopenharmony_ci SUMO_DTC_DFLT_08, 6662306a36Sopenharmony_ci SUMO_DTC_DFLT_09, 6762306a36Sopenharmony_ci SUMO_DTC_DFLT_10, 6862306a36Sopenharmony_ci SUMO_DTC_DFLT_11, 6962306a36Sopenharmony_ci SUMO_DTC_DFLT_12, 7062306a36Sopenharmony_ci SUMO_DTC_DFLT_13, 7162306a36Sopenharmony_ci SUMO_DTC_DFLT_14, 7262306a36Sopenharmony_ci}; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic struct sumo_ps *sumo_get_ps(struct radeon_ps *rps) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci struct sumo_ps *ps = rps->ps_priv; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci return ps; 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistruct sumo_power_info *sumo_get_pi(struct radeon_device *rdev) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci struct sumo_power_info *pi = rdev->pm.dpm.priv; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci return pi; 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic void sumo_gfx_clockgating_enable(struct radeon_device *rdev, bool enable) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci if (enable) 9162306a36Sopenharmony_ci WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN); 9262306a36Sopenharmony_ci else { 9362306a36Sopenharmony_ci WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN); 9462306a36Sopenharmony_ci WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON); 9562306a36Sopenharmony_ci WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON); 9662306a36Sopenharmony_ci RREG32(GB_ADDR_CONFIG); 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci#define CGCG_CGTT_LOCAL0_MASK 0xE5BFFFFF 10162306a36Sopenharmony_ci#define CGCG_CGTT_LOCAL1_MASK 0xEFFF07FF 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic void sumo_mg_clockgating_enable(struct radeon_device *rdev, bool enable) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci u32 local0; 10662306a36Sopenharmony_ci u32 local1; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci local0 = RREG32(CG_CGTT_LOCAL_0); 10962306a36Sopenharmony_ci local1 = RREG32(CG_CGTT_LOCAL_1); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (enable) { 11262306a36Sopenharmony_ci WREG32(CG_CGTT_LOCAL_0, (0 & CGCG_CGTT_LOCAL0_MASK) | (local0 & ~CGCG_CGTT_LOCAL0_MASK) ); 11362306a36Sopenharmony_ci WREG32(CG_CGTT_LOCAL_1, (0 & CGCG_CGTT_LOCAL1_MASK) | (local1 & ~CGCG_CGTT_LOCAL1_MASK) ); 11462306a36Sopenharmony_ci } else { 11562306a36Sopenharmony_ci WREG32(CG_CGTT_LOCAL_0, (0xFFFFFFFF & CGCG_CGTT_LOCAL0_MASK) | (local0 & ~CGCG_CGTT_LOCAL0_MASK) ); 11662306a36Sopenharmony_ci WREG32(CG_CGTT_LOCAL_1, (0xFFFFCFFF & CGCG_CGTT_LOCAL1_MASK) | (local1 & ~CGCG_CGTT_LOCAL1_MASK) ); 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic void sumo_program_git(struct radeon_device *rdev) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci u32 p, u; 12362306a36Sopenharmony_ci u32 xclk = radeon_get_xclk(rdev); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci r600_calculate_u_and_p(SUMO_GICST_DFLT, 12662306a36Sopenharmony_ci xclk, 16, &p, &u); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci WREG32_P(CG_GIT, CG_GICST(p), ~CG_GICST_MASK); 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic void sumo_program_grsd(struct radeon_device *rdev) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci u32 p, u; 13462306a36Sopenharmony_ci u32 xclk = radeon_get_xclk(rdev); 13562306a36Sopenharmony_ci u32 grs = 256 * 25 / 100; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci r600_calculate_u_and_p(1, xclk, 14, &p, &u); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci WREG32(CG_GCOOR, PHC(grs) | SDC(p) | SU(u)); 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_civoid sumo_gfx_clockgating_initialize(struct radeon_device *rdev) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci sumo_program_git(rdev); 14562306a36Sopenharmony_ci sumo_program_grsd(rdev); 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic void sumo_gfx_powergating_initialize(struct radeon_device *rdev) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci u32 rcu_pwr_gating_cntl; 15162306a36Sopenharmony_ci u32 p, u; 15262306a36Sopenharmony_ci u32 p_c, p_p, d_p; 15362306a36Sopenharmony_ci u32 r_t, i_t; 15462306a36Sopenharmony_ci u32 xclk = radeon_get_xclk(rdev); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (rdev->family == CHIP_PALM) { 15762306a36Sopenharmony_ci p_c = 4; 15862306a36Sopenharmony_ci d_p = 10; 15962306a36Sopenharmony_ci r_t = 10; 16062306a36Sopenharmony_ci i_t = 4; 16162306a36Sopenharmony_ci p_p = 50 + 1000/200 + 6 * 32; 16262306a36Sopenharmony_ci } else { 16362306a36Sopenharmony_ci p_c = 16; 16462306a36Sopenharmony_ci d_p = 50; 16562306a36Sopenharmony_ci r_t = 50; 16662306a36Sopenharmony_ci i_t = 50; 16762306a36Sopenharmony_ci p_p = 113; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci WREG32(CG_SCRATCH2, 0x01B60A17); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci r600_calculate_u_and_p(SUMO_GFXPOWERGATINGT_DFLT, 17362306a36Sopenharmony_ci xclk, 16, &p, &u); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci WREG32_P(CG_PWR_GATING_CNTL, PGP(p) | PGU(u), 17662306a36Sopenharmony_ci ~(PGP_MASK | PGU_MASK)); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci r600_calculate_u_and_p(SUMO_VOLTAGEDROPT_DFLT, 17962306a36Sopenharmony_ci xclk, 16, &p, &u); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci WREG32_P(CG_CG_VOLTAGE_CNTL, PGP(p) | PGU(u), 18262306a36Sopenharmony_ci ~(PGP_MASK | PGU_MASK)); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (rdev->family == CHIP_PALM) { 18562306a36Sopenharmony_ci WREG32_RCU(RCU_PWR_GATING_SEQ0, 0x10103210); 18662306a36Sopenharmony_ci WREG32_RCU(RCU_PWR_GATING_SEQ1, 0x10101010); 18762306a36Sopenharmony_ci } else { 18862306a36Sopenharmony_ci WREG32_RCU(RCU_PWR_GATING_SEQ0, 0x76543210); 18962306a36Sopenharmony_ci WREG32_RCU(RCU_PWR_GATING_SEQ1, 0xFEDCBA98); 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL); 19362306a36Sopenharmony_ci rcu_pwr_gating_cntl &= 19462306a36Sopenharmony_ci ~(RSVD_MASK | PCV_MASK | PGS_MASK); 19562306a36Sopenharmony_ci rcu_pwr_gating_cntl |= PCV(p_c) | PGS(1) | PWR_GATING_EN; 19662306a36Sopenharmony_ci if (rdev->family == CHIP_PALM) { 19762306a36Sopenharmony_ci rcu_pwr_gating_cntl &= ~PCP_MASK; 19862306a36Sopenharmony_ci rcu_pwr_gating_cntl |= PCP(0x77); 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci WREG32_RCU(RCU_PWR_GATING_CNTL, rcu_pwr_gating_cntl); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_2); 20362306a36Sopenharmony_ci rcu_pwr_gating_cntl &= ~(MPPU_MASK | MPPD_MASK); 20462306a36Sopenharmony_ci rcu_pwr_gating_cntl |= MPPU(p_p) | MPPD(50); 20562306a36Sopenharmony_ci WREG32_RCU(RCU_PWR_GATING_CNTL_2, rcu_pwr_gating_cntl); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_3); 20862306a36Sopenharmony_ci rcu_pwr_gating_cntl &= ~(DPPU_MASK | DPPD_MASK); 20962306a36Sopenharmony_ci rcu_pwr_gating_cntl |= DPPU(d_p) | DPPD(50); 21062306a36Sopenharmony_ci WREG32_RCU(RCU_PWR_GATING_CNTL_3, rcu_pwr_gating_cntl); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_4); 21362306a36Sopenharmony_ci rcu_pwr_gating_cntl &= ~(RT_MASK | IT_MASK); 21462306a36Sopenharmony_ci rcu_pwr_gating_cntl |= RT(r_t) | IT(i_t); 21562306a36Sopenharmony_ci WREG32_RCU(RCU_PWR_GATING_CNTL_4, rcu_pwr_gating_cntl); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (rdev->family == CHIP_PALM) 21862306a36Sopenharmony_ci WREG32_RCU(RCU_PWR_GATING_CNTL_5, 0xA02); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci sumo_smu_pg_init(rdev); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL); 22362306a36Sopenharmony_ci rcu_pwr_gating_cntl &= 22462306a36Sopenharmony_ci ~(RSVD_MASK | PCV_MASK | PGS_MASK); 22562306a36Sopenharmony_ci rcu_pwr_gating_cntl |= PCV(p_c) | PGS(4) | PWR_GATING_EN; 22662306a36Sopenharmony_ci if (rdev->family == CHIP_PALM) { 22762306a36Sopenharmony_ci rcu_pwr_gating_cntl &= ~PCP_MASK; 22862306a36Sopenharmony_ci rcu_pwr_gating_cntl |= PCP(0x77); 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci WREG32_RCU(RCU_PWR_GATING_CNTL, rcu_pwr_gating_cntl); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci if (rdev->family == CHIP_PALM) { 23362306a36Sopenharmony_ci rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_2); 23462306a36Sopenharmony_ci rcu_pwr_gating_cntl &= ~(MPPU_MASK | MPPD_MASK); 23562306a36Sopenharmony_ci rcu_pwr_gating_cntl |= MPPU(113) | MPPD(50); 23662306a36Sopenharmony_ci WREG32_RCU(RCU_PWR_GATING_CNTL_2, rcu_pwr_gating_cntl); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_3); 23962306a36Sopenharmony_ci rcu_pwr_gating_cntl &= ~(DPPU_MASK | DPPD_MASK); 24062306a36Sopenharmony_ci rcu_pwr_gating_cntl |= DPPU(16) | DPPD(50); 24162306a36Sopenharmony_ci WREG32_RCU(RCU_PWR_GATING_CNTL_3, rcu_pwr_gating_cntl); 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci sumo_smu_pg_init(rdev); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL); 24762306a36Sopenharmony_ci rcu_pwr_gating_cntl &= 24862306a36Sopenharmony_ci ~(RSVD_MASK | PCV_MASK | PGS_MASK); 24962306a36Sopenharmony_ci rcu_pwr_gating_cntl |= PGS(5) | PWR_GATING_EN; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if (rdev->family == CHIP_PALM) { 25262306a36Sopenharmony_ci rcu_pwr_gating_cntl |= PCV(4); 25362306a36Sopenharmony_ci rcu_pwr_gating_cntl &= ~PCP_MASK; 25462306a36Sopenharmony_ci rcu_pwr_gating_cntl |= PCP(0x77); 25562306a36Sopenharmony_ci } else 25662306a36Sopenharmony_ci rcu_pwr_gating_cntl |= PCV(11); 25762306a36Sopenharmony_ci WREG32_RCU(RCU_PWR_GATING_CNTL, rcu_pwr_gating_cntl); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (rdev->family == CHIP_PALM) { 26062306a36Sopenharmony_ci rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_2); 26162306a36Sopenharmony_ci rcu_pwr_gating_cntl &= ~(MPPU_MASK | MPPD_MASK); 26262306a36Sopenharmony_ci rcu_pwr_gating_cntl |= MPPU(113) | MPPD(50); 26362306a36Sopenharmony_ci WREG32_RCU(RCU_PWR_GATING_CNTL_2, rcu_pwr_gating_cntl); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_3); 26662306a36Sopenharmony_ci rcu_pwr_gating_cntl &= ~(DPPU_MASK | DPPD_MASK); 26762306a36Sopenharmony_ci rcu_pwr_gating_cntl |= DPPU(22) | DPPD(50); 26862306a36Sopenharmony_ci WREG32_RCU(RCU_PWR_GATING_CNTL_3, rcu_pwr_gating_cntl); 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci sumo_smu_pg_init(rdev); 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic void sumo_gfx_powergating_enable(struct radeon_device *rdev, bool enable) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci if (enable) 27762306a36Sopenharmony_ci WREG32_P(CG_PWR_GATING_CNTL, DYN_PWR_DOWN_EN, ~DYN_PWR_DOWN_EN); 27862306a36Sopenharmony_ci else { 27962306a36Sopenharmony_ci WREG32_P(CG_PWR_GATING_CNTL, 0, ~DYN_PWR_DOWN_EN); 28062306a36Sopenharmony_ci RREG32(GB_ADDR_CONFIG); 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic int sumo_enable_clock_power_gating(struct radeon_device *rdev) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (pi->enable_gfx_clock_gating) 28962306a36Sopenharmony_ci sumo_gfx_clockgating_initialize(rdev); 29062306a36Sopenharmony_ci if (pi->enable_gfx_power_gating) 29162306a36Sopenharmony_ci sumo_gfx_powergating_initialize(rdev); 29262306a36Sopenharmony_ci if (pi->enable_mg_clock_gating) 29362306a36Sopenharmony_ci sumo_mg_clockgating_enable(rdev, true); 29462306a36Sopenharmony_ci if (pi->enable_gfx_clock_gating) 29562306a36Sopenharmony_ci sumo_gfx_clockgating_enable(rdev, true); 29662306a36Sopenharmony_ci if (pi->enable_gfx_power_gating) 29762306a36Sopenharmony_ci sumo_gfx_powergating_enable(rdev, true); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci return 0; 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic void sumo_disable_clock_power_gating(struct radeon_device *rdev) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (pi->enable_gfx_clock_gating) 30762306a36Sopenharmony_ci sumo_gfx_clockgating_enable(rdev, false); 30862306a36Sopenharmony_ci if (pi->enable_gfx_power_gating) 30962306a36Sopenharmony_ci sumo_gfx_powergating_enable(rdev, false); 31062306a36Sopenharmony_ci if (pi->enable_mg_clock_gating) 31162306a36Sopenharmony_ci sumo_mg_clockgating_enable(rdev, false); 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic void sumo_calculate_bsp(struct radeon_device *rdev, 31562306a36Sopenharmony_ci u32 high_clk) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 31862306a36Sopenharmony_ci u32 xclk = radeon_get_xclk(rdev); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci pi->pasi = 65535 * 100 / high_clk; 32162306a36Sopenharmony_ci pi->asi = 65535 * 100 / high_clk; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci r600_calculate_u_and_p(pi->asi, 32462306a36Sopenharmony_ci xclk, 16, &pi->bsp, &pi->bsu); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci r600_calculate_u_and_p(pi->pasi, 32762306a36Sopenharmony_ci xclk, 16, &pi->pbsp, &pi->pbsu); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci pi->dsp = BSP(pi->bsp) | BSU(pi->bsu); 33062306a36Sopenharmony_ci pi->psp = BSP(pi->pbsp) | BSU(pi->pbsu); 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic void sumo_init_bsp(struct radeon_device *rdev) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci WREG32(CG_BSP_0, pi->psp); 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic void sumo_program_bsp(struct radeon_device *rdev, 34262306a36Sopenharmony_ci struct radeon_ps *rps) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 34562306a36Sopenharmony_ci struct sumo_ps *ps = sumo_get_ps(rps); 34662306a36Sopenharmony_ci u32 i; 34762306a36Sopenharmony_ci u32 highest_engine_clock = ps->levels[ps->num_levels - 1].sclk; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci if (ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE) 35062306a36Sopenharmony_ci highest_engine_clock = pi->boost_pl.sclk; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci sumo_calculate_bsp(rdev, highest_engine_clock); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci for (i = 0; i < ps->num_levels - 1; i++) 35562306a36Sopenharmony_ci WREG32(CG_BSP_0 + (i * 4), pi->dsp); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci WREG32(CG_BSP_0 + (i * 4), pi->psp); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if (ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE) 36062306a36Sopenharmony_ci WREG32(CG_BSP_0 + (BOOST_DPM_LEVEL * 4), pi->psp); 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic void sumo_write_at(struct radeon_device *rdev, 36462306a36Sopenharmony_ci u32 index, u32 value) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci if (index == 0) 36762306a36Sopenharmony_ci WREG32(CG_AT_0, value); 36862306a36Sopenharmony_ci else if (index == 1) 36962306a36Sopenharmony_ci WREG32(CG_AT_1, value); 37062306a36Sopenharmony_ci else if (index == 2) 37162306a36Sopenharmony_ci WREG32(CG_AT_2, value); 37262306a36Sopenharmony_ci else if (index == 3) 37362306a36Sopenharmony_ci WREG32(CG_AT_3, value); 37462306a36Sopenharmony_ci else if (index == 4) 37562306a36Sopenharmony_ci WREG32(CG_AT_4, value); 37662306a36Sopenharmony_ci else if (index == 5) 37762306a36Sopenharmony_ci WREG32(CG_AT_5, value); 37862306a36Sopenharmony_ci else if (index == 6) 37962306a36Sopenharmony_ci WREG32(CG_AT_6, value); 38062306a36Sopenharmony_ci else if (index == 7) 38162306a36Sopenharmony_ci WREG32(CG_AT_7, value); 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic void sumo_program_at(struct radeon_device *rdev, 38562306a36Sopenharmony_ci struct radeon_ps *rps) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 38862306a36Sopenharmony_ci struct sumo_ps *ps = sumo_get_ps(rps); 38962306a36Sopenharmony_ci u32 asi; 39062306a36Sopenharmony_ci u32 i; 39162306a36Sopenharmony_ci u32 m_a; 39262306a36Sopenharmony_ci u32 a_t; 39362306a36Sopenharmony_ci u32 r[SUMO_MAX_HARDWARE_POWERLEVELS]; 39462306a36Sopenharmony_ci u32 l[SUMO_MAX_HARDWARE_POWERLEVELS]; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci r[0] = SUMO_R_DFLT0; 39762306a36Sopenharmony_ci r[1] = SUMO_R_DFLT1; 39862306a36Sopenharmony_ci r[2] = SUMO_R_DFLT2; 39962306a36Sopenharmony_ci r[3] = SUMO_R_DFLT3; 40062306a36Sopenharmony_ci r[4] = SUMO_R_DFLT4; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci l[0] = SUMO_L_DFLT0; 40362306a36Sopenharmony_ci l[1] = SUMO_L_DFLT1; 40462306a36Sopenharmony_ci l[2] = SUMO_L_DFLT2; 40562306a36Sopenharmony_ci l[3] = SUMO_L_DFLT3; 40662306a36Sopenharmony_ci l[4] = SUMO_L_DFLT4; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci for (i = 0; i < ps->num_levels; i++) { 40962306a36Sopenharmony_ci asi = (i == ps->num_levels - 1) ? pi->pasi : pi->asi; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci m_a = asi * ps->levels[i].sclk / 100; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci a_t = CG_R(m_a * r[i] / 100) | CG_L(m_a * l[i] / 100); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci sumo_write_at(rdev, i, a_t); 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci if (ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE) { 41962306a36Sopenharmony_ci asi = pi->pasi; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci m_a = asi * pi->boost_pl.sclk / 100; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci a_t = CG_R(m_a * r[ps->num_levels - 1] / 100) | 42462306a36Sopenharmony_ci CG_L(m_a * l[ps->num_levels - 1] / 100); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci sumo_write_at(rdev, BOOST_DPM_LEVEL, a_t); 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic void sumo_program_tp(struct radeon_device *rdev) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci int i; 43362306a36Sopenharmony_ci enum r600_td td = R600_TD_DFLT; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci for (i = 0; i < SUMO_PM_NUMBER_OF_TC; i++) { 43662306a36Sopenharmony_ci WREG32_P(CG_FFCT_0 + (i * 4), UTC_0(sumo_utc[i]), ~UTC_0_MASK); 43762306a36Sopenharmony_ci WREG32_P(CG_FFCT_0 + (i * 4), DTC_0(sumo_dtc[i]), ~DTC_0_MASK); 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (td == R600_TD_AUTO) 44162306a36Sopenharmony_ci WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_FORCE_TREND_SEL); 44262306a36Sopenharmony_ci else 44362306a36Sopenharmony_ci WREG32_P(SCLK_PWRMGT_CNTL, FIR_FORCE_TREND_SEL, ~FIR_FORCE_TREND_SEL); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci if (td == R600_TD_UP) 44662306a36Sopenharmony_ci WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_TREND_MODE); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci if (td == R600_TD_DOWN) 44962306a36Sopenharmony_ci WREG32_P(SCLK_PWRMGT_CNTL, FIR_TREND_MODE, ~FIR_TREND_MODE); 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_civoid sumo_program_vc(struct radeon_device *rdev, u32 vrc) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci WREG32(CG_FTV, vrc); 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_civoid sumo_clear_vc(struct radeon_device *rdev) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci WREG32(CG_FTV, 0); 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_civoid sumo_program_sstp(struct radeon_device *rdev) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci u32 p, u; 46562306a36Sopenharmony_ci u32 xclk = radeon_get_xclk(rdev); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci r600_calculate_u_and_p(SUMO_SST_DFLT, 46862306a36Sopenharmony_ci xclk, 16, &p, &u); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci WREG32(CG_SSP, SSTU(u) | SST(p)); 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cistatic void sumo_set_divider_value(struct radeon_device *rdev, 47462306a36Sopenharmony_ci u32 index, u32 divider) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci u32 reg_index = index / 4; 47762306a36Sopenharmony_ci u32 field_index = index % 4; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci if (field_index == 0) 48062306a36Sopenharmony_ci WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4), 48162306a36Sopenharmony_ci SCLK_FSTATE_0_DIV(divider), ~SCLK_FSTATE_0_DIV_MASK); 48262306a36Sopenharmony_ci else if (field_index == 1) 48362306a36Sopenharmony_ci WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4), 48462306a36Sopenharmony_ci SCLK_FSTATE_1_DIV(divider), ~SCLK_FSTATE_1_DIV_MASK); 48562306a36Sopenharmony_ci else if (field_index == 2) 48662306a36Sopenharmony_ci WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4), 48762306a36Sopenharmony_ci SCLK_FSTATE_2_DIV(divider), ~SCLK_FSTATE_2_DIV_MASK); 48862306a36Sopenharmony_ci else if (field_index == 3) 48962306a36Sopenharmony_ci WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4), 49062306a36Sopenharmony_ci SCLK_FSTATE_3_DIV(divider), ~SCLK_FSTATE_3_DIV_MASK); 49162306a36Sopenharmony_ci} 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic void sumo_set_ds_dividers(struct radeon_device *rdev, 49462306a36Sopenharmony_ci u32 index, u32 divider) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci if (pi->enable_sclk_ds) { 49962306a36Sopenharmony_ci u32 dpm_ctrl = RREG32(CG_SCLK_DPM_CTRL_6); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci dpm_ctrl &= ~(0x7 << (index * 3)); 50262306a36Sopenharmony_ci dpm_ctrl |= (divider << (index * 3)); 50362306a36Sopenharmony_ci WREG32(CG_SCLK_DPM_CTRL_6, dpm_ctrl); 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci} 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_cistatic void sumo_set_ss_dividers(struct radeon_device *rdev, 50862306a36Sopenharmony_ci u32 index, u32 divider) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci if (pi->enable_sclk_ds) { 51362306a36Sopenharmony_ci u32 dpm_ctrl = RREG32(CG_SCLK_DPM_CTRL_11); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci dpm_ctrl &= ~(0x7 << (index * 3)); 51662306a36Sopenharmony_ci dpm_ctrl |= (divider << (index * 3)); 51762306a36Sopenharmony_ci WREG32(CG_SCLK_DPM_CTRL_11, dpm_ctrl); 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic void sumo_set_vid(struct radeon_device *rdev, u32 index, u32 vid) 52262306a36Sopenharmony_ci{ 52362306a36Sopenharmony_ci u32 voltage_cntl = RREG32(CG_DPM_VOLTAGE_CNTL); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci voltage_cntl &= ~(DPM_STATE0_LEVEL_MASK << (index * 2)); 52662306a36Sopenharmony_ci voltage_cntl |= (vid << (DPM_STATE0_LEVEL_SHIFT + index * 2)); 52762306a36Sopenharmony_ci WREG32(CG_DPM_VOLTAGE_CNTL, voltage_cntl); 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cistatic void sumo_set_allos_gnb_slow(struct radeon_device *rdev, u32 index, u32 gnb_slow) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 53362306a36Sopenharmony_ci u32 temp = gnb_slow; 53462306a36Sopenharmony_ci u32 cg_sclk_dpm_ctrl_3; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci if (pi->driver_nbps_policy_disable) 53762306a36Sopenharmony_ci temp = 1; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci cg_sclk_dpm_ctrl_3 = RREG32(CG_SCLK_DPM_CTRL_3); 54062306a36Sopenharmony_ci cg_sclk_dpm_ctrl_3 &= ~(GNB_SLOW_FSTATE_0_MASK << index); 54162306a36Sopenharmony_ci cg_sclk_dpm_ctrl_3 |= (temp << (GNB_SLOW_FSTATE_0_SHIFT + index)); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci WREG32(CG_SCLK_DPM_CTRL_3, cg_sclk_dpm_ctrl_3); 54462306a36Sopenharmony_ci} 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_cistatic void sumo_program_power_level(struct radeon_device *rdev, 54762306a36Sopenharmony_ci struct sumo_pl *pl, u32 index) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 55062306a36Sopenharmony_ci int ret; 55162306a36Sopenharmony_ci struct atom_clock_dividers dividers; 55262306a36Sopenharmony_ci u32 ds_en = RREG32(DEEP_SLEEP_CNTL) & ENABLE_DS; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, 55562306a36Sopenharmony_ci pl->sclk, false, ÷rs); 55662306a36Sopenharmony_ci if (ret) 55762306a36Sopenharmony_ci return; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci sumo_set_divider_value(rdev, index, dividers.post_div); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci sumo_set_vid(rdev, index, pl->vddc_index); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci if (pl->ss_divider_index == 0 || pl->ds_divider_index == 0) { 56462306a36Sopenharmony_ci if (ds_en) 56562306a36Sopenharmony_ci WREG32_P(DEEP_SLEEP_CNTL, 0, ~ENABLE_DS); 56662306a36Sopenharmony_ci } else { 56762306a36Sopenharmony_ci sumo_set_ss_dividers(rdev, index, pl->ss_divider_index); 56862306a36Sopenharmony_ci sumo_set_ds_dividers(rdev, index, pl->ds_divider_index); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci if (!ds_en) 57162306a36Sopenharmony_ci WREG32_P(DEEP_SLEEP_CNTL, ENABLE_DS, ~ENABLE_DS); 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci sumo_set_allos_gnb_slow(rdev, index, pl->allow_gnb_slow); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if (pi->enable_boost) 57762306a36Sopenharmony_ci sumo_set_tdp_limit(rdev, index, pl->sclk_dpm_tdp_limit); 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_cistatic void sumo_power_level_enable(struct radeon_device *rdev, u32 index, bool enable) 58162306a36Sopenharmony_ci{ 58262306a36Sopenharmony_ci u32 reg_index = index / 4; 58362306a36Sopenharmony_ci u32 field_index = index % 4; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci if (field_index == 0) 58662306a36Sopenharmony_ci WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4), 58762306a36Sopenharmony_ci enable ? SCLK_FSTATE_0_VLD : 0, ~SCLK_FSTATE_0_VLD); 58862306a36Sopenharmony_ci else if (field_index == 1) 58962306a36Sopenharmony_ci WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4), 59062306a36Sopenharmony_ci enable ? SCLK_FSTATE_1_VLD : 0, ~SCLK_FSTATE_1_VLD); 59162306a36Sopenharmony_ci else if (field_index == 2) 59262306a36Sopenharmony_ci WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4), 59362306a36Sopenharmony_ci enable ? SCLK_FSTATE_2_VLD : 0, ~SCLK_FSTATE_2_VLD); 59462306a36Sopenharmony_ci else if (field_index == 3) 59562306a36Sopenharmony_ci WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4), 59662306a36Sopenharmony_ci enable ? SCLK_FSTATE_3_VLD : 0, ~SCLK_FSTATE_3_VLD); 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_cistatic bool sumo_dpm_enabled(struct radeon_device *rdev) 60062306a36Sopenharmony_ci{ 60162306a36Sopenharmony_ci if (RREG32(CG_SCLK_DPM_CTRL_3) & DPM_SCLK_ENABLE) 60262306a36Sopenharmony_ci return true; 60362306a36Sopenharmony_ci else 60462306a36Sopenharmony_ci return false; 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic void sumo_start_dpm(struct radeon_device *rdev) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci WREG32_P(CG_SCLK_DPM_CTRL_3, DPM_SCLK_ENABLE, ~DPM_SCLK_ENABLE); 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_cistatic void sumo_stop_dpm(struct radeon_device *rdev) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci WREG32_P(CG_SCLK_DPM_CTRL_3, 0, ~DPM_SCLK_ENABLE); 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cistatic void sumo_set_forced_mode(struct radeon_device *rdev, bool enable) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci if (enable) 62062306a36Sopenharmony_ci WREG32_P(CG_SCLK_DPM_CTRL_3, FORCE_SCLK_STATE_EN, ~FORCE_SCLK_STATE_EN); 62162306a36Sopenharmony_ci else 62262306a36Sopenharmony_ci WREG32_P(CG_SCLK_DPM_CTRL_3, 0, ~FORCE_SCLK_STATE_EN); 62362306a36Sopenharmony_ci} 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_cistatic void sumo_set_forced_mode_enabled(struct radeon_device *rdev) 62662306a36Sopenharmony_ci{ 62762306a36Sopenharmony_ci int i; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci sumo_set_forced_mode(rdev, true); 63062306a36Sopenharmony_ci for (i = 0; i < rdev->usec_timeout; i++) { 63162306a36Sopenharmony_ci if (RREG32(CG_SCLK_STATUS) & SCLK_OVERCLK_DETECT) 63262306a36Sopenharmony_ci break; 63362306a36Sopenharmony_ci udelay(1); 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_cistatic void sumo_wait_for_level_0(struct radeon_device *rdev) 63862306a36Sopenharmony_ci{ 63962306a36Sopenharmony_ci int i; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci for (i = 0; i < rdev->usec_timeout; i++) { 64262306a36Sopenharmony_ci if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_SCLK_INDEX_MASK) == 0) 64362306a36Sopenharmony_ci break; 64462306a36Sopenharmony_ci udelay(1); 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci for (i = 0; i < rdev->usec_timeout; i++) { 64762306a36Sopenharmony_ci if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_INDEX_MASK) == 0) 64862306a36Sopenharmony_ci break; 64962306a36Sopenharmony_ci udelay(1); 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci} 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_cistatic void sumo_set_forced_mode_disabled(struct radeon_device *rdev) 65462306a36Sopenharmony_ci{ 65562306a36Sopenharmony_ci sumo_set_forced_mode(rdev, false); 65662306a36Sopenharmony_ci} 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_cistatic void sumo_enable_power_level_0(struct radeon_device *rdev) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci sumo_power_level_enable(rdev, 0, true); 66162306a36Sopenharmony_ci} 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_cistatic void sumo_patch_boost_state(struct radeon_device *rdev, 66462306a36Sopenharmony_ci struct radeon_ps *rps) 66562306a36Sopenharmony_ci{ 66662306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 66762306a36Sopenharmony_ci struct sumo_ps *new_ps = sumo_get_ps(rps); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci if (new_ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE) { 67062306a36Sopenharmony_ci pi->boost_pl = new_ps->levels[new_ps->num_levels - 1]; 67162306a36Sopenharmony_ci pi->boost_pl.sclk = pi->sys_info.boost_sclk; 67262306a36Sopenharmony_ci pi->boost_pl.vddc_index = pi->sys_info.boost_vid_2bit; 67362306a36Sopenharmony_ci pi->boost_pl.sclk_dpm_tdp_limit = pi->sys_info.sclk_dpm_tdp_limit_boost; 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci} 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_cistatic void sumo_pre_notify_alt_vddnb_change(struct radeon_device *rdev, 67862306a36Sopenharmony_ci struct radeon_ps *new_rps, 67962306a36Sopenharmony_ci struct radeon_ps *old_rps) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci struct sumo_ps *new_ps = sumo_get_ps(new_rps); 68262306a36Sopenharmony_ci struct sumo_ps *old_ps = sumo_get_ps(old_rps); 68362306a36Sopenharmony_ci u32 nbps1_old = 0; 68462306a36Sopenharmony_ci u32 nbps1_new = 0; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (old_ps != NULL) 68762306a36Sopenharmony_ci nbps1_old = (old_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE) ? 1 : 0; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci nbps1_new = (new_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE) ? 1 : 0; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci if (nbps1_old == 1 && nbps1_new == 0) 69262306a36Sopenharmony_ci sumo_smu_notify_alt_vddnb_change(rdev, 0, 0); 69362306a36Sopenharmony_ci} 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_cistatic void sumo_post_notify_alt_vddnb_change(struct radeon_device *rdev, 69662306a36Sopenharmony_ci struct radeon_ps *new_rps, 69762306a36Sopenharmony_ci struct radeon_ps *old_rps) 69862306a36Sopenharmony_ci{ 69962306a36Sopenharmony_ci struct sumo_ps *new_ps = sumo_get_ps(new_rps); 70062306a36Sopenharmony_ci struct sumo_ps *old_ps = sumo_get_ps(old_rps); 70162306a36Sopenharmony_ci u32 nbps1_old = 0; 70262306a36Sopenharmony_ci u32 nbps1_new = 0; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci if (old_ps != NULL) 70562306a36Sopenharmony_ci nbps1_old = (old_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE)? 1 : 0; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci nbps1_new = (new_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE)? 1 : 0; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci if (nbps1_old == 0 && nbps1_new == 1) 71062306a36Sopenharmony_ci sumo_smu_notify_alt_vddnb_change(rdev, 1, 1); 71162306a36Sopenharmony_ci} 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_cistatic void sumo_enable_boost(struct radeon_device *rdev, 71462306a36Sopenharmony_ci struct radeon_ps *rps, 71562306a36Sopenharmony_ci bool enable) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci struct sumo_ps *new_ps = sumo_get_ps(rps); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci if (enable) { 72062306a36Sopenharmony_ci if (new_ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE) 72162306a36Sopenharmony_ci sumo_boost_state_enable(rdev, true); 72262306a36Sopenharmony_ci } else 72362306a36Sopenharmony_ci sumo_boost_state_enable(rdev, false); 72462306a36Sopenharmony_ci} 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_cistatic void sumo_set_forced_level(struct radeon_device *rdev, u32 index) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci WREG32_P(CG_SCLK_DPM_CTRL_3, FORCE_SCLK_STATE(index), ~FORCE_SCLK_STATE_MASK); 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic void sumo_set_forced_level_0(struct radeon_device *rdev) 73262306a36Sopenharmony_ci{ 73362306a36Sopenharmony_ci sumo_set_forced_level(rdev, 0); 73462306a36Sopenharmony_ci} 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_cistatic void sumo_program_wl(struct radeon_device *rdev, 73762306a36Sopenharmony_ci struct radeon_ps *rps) 73862306a36Sopenharmony_ci{ 73962306a36Sopenharmony_ci struct sumo_ps *new_ps = sumo_get_ps(rps); 74062306a36Sopenharmony_ci u32 dpm_ctrl4 = RREG32(CG_SCLK_DPM_CTRL_4); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci dpm_ctrl4 &= 0xFFFFFF00; 74362306a36Sopenharmony_ci dpm_ctrl4 |= (1 << (new_ps->num_levels - 1)); 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci if (new_ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE) 74662306a36Sopenharmony_ci dpm_ctrl4 |= (1 << BOOST_DPM_LEVEL); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci WREG32(CG_SCLK_DPM_CTRL_4, dpm_ctrl4); 74962306a36Sopenharmony_ci} 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_cistatic void sumo_program_power_levels_0_to_n(struct radeon_device *rdev, 75262306a36Sopenharmony_ci struct radeon_ps *new_rps, 75362306a36Sopenharmony_ci struct radeon_ps *old_rps) 75462306a36Sopenharmony_ci{ 75562306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 75662306a36Sopenharmony_ci struct sumo_ps *new_ps = sumo_get_ps(new_rps); 75762306a36Sopenharmony_ci struct sumo_ps *old_ps = sumo_get_ps(old_rps); 75862306a36Sopenharmony_ci u32 i; 75962306a36Sopenharmony_ci u32 n_current_state_levels = (old_ps == NULL) ? 1 : old_ps->num_levels; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci for (i = 0; i < new_ps->num_levels; i++) { 76262306a36Sopenharmony_ci sumo_program_power_level(rdev, &new_ps->levels[i], i); 76362306a36Sopenharmony_ci sumo_power_level_enable(rdev, i, true); 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci for (i = new_ps->num_levels; i < n_current_state_levels; i++) 76762306a36Sopenharmony_ci sumo_power_level_enable(rdev, i, false); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci if (new_ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE) 77062306a36Sopenharmony_ci sumo_program_power_level(rdev, &pi->boost_pl, BOOST_DPM_LEVEL); 77162306a36Sopenharmony_ci} 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_cistatic void sumo_enable_acpi_pm(struct radeon_device *rdev) 77462306a36Sopenharmony_ci{ 77562306a36Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, STATIC_PM_EN, ~STATIC_PM_EN); 77662306a36Sopenharmony_ci} 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_cistatic void sumo_program_power_level_enter_state(struct radeon_device *rdev) 77962306a36Sopenharmony_ci{ 78062306a36Sopenharmony_ci WREG32_P(CG_SCLK_DPM_CTRL_5, SCLK_FSTATE_BOOTUP(0), ~SCLK_FSTATE_BOOTUP_MASK); 78162306a36Sopenharmony_ci} 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_cistatic void sumo_program_acpi_power_level(struct radeon_device *rdev) 78462306a36Sopenharmony_ci{ 78562306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 78662306a36Sopenharmony_ci struct atom_clock_dividers dividers; 78762306a36Sopenharmony_ci int ret; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, 79062306a36Sopenharmony_ci pi->acpi_pl.sclk, 79162306a36Sopenharmony_ci false, ÷rs); 79262306a36Sopenharmony_ci if (ret) 79362306a36Sopenharmony_ci return; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci WREG32_P(CG_ACPI_CNTL, SCLK_ACPI_DIV(dividers.post_div), ~SCLK_ACPI_DIV_MASK); 79662306a36Sopenharmony_ci WREG32_P(CG_ACPI_VOLTAGE_CNTL, 0, ~ACPI_VOLTAGE_EN); 79762306a36Sopenharmony_ci} 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_cistatic void sumo_program_bootup_state(struct radeon_device *rdev) 80062306a36Sopenharmony_ci{ 80162306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 80262306a36Sopenharmony_ci u32 dpm_ctrl4 = RREG32(CG_SCLK_DPM_CTRL_4); 80362306a36Sopenharmony_ci u32 i; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci sumo_program_power_level(rdev, &pi->boot_pl, 0); 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci dpm_ctrl4 &= 0xFFFFFF00; 80862306a36Sopenharmony_ci WREG32(CG_SCLK_DPM_CTRL_4, dpm_ctrl4); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci for (i = 1; i < 8; i++) 81162306a36Sopenharmony_ci sumo_power_level_enable(rdev, i, false); 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cistatic void sumo_setup_uvd_clocks(struct radeon_device *rdev, 81562306a36Sopenharmony_ci struct radeon_ps *new_rps, 81662306a36Sopenharmony_ci struct radeon_ps *old_rps) 81762306a36Sopenharmony_ci{ 81862306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci if (pi->enable_gfx_power_gating) { 82162306a36Sopenharmony_ci sumo_gfx_powergating_enable(rdev, false); 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci if (pi->enable_gfx_power_gating) { 82762306a36Sopenharmony_ci if (!pi->disable_gfx_power_gating_in_uvd || 82862306a36Sopenharmony_ci !r600_is_uvd_state(new_rps->class, new_rps->class2)) 82962306a36Sopenharmony_ci sumo_gfx_powergating_enable(rdev, true); 83062306a36Sopenharmony_ci } 83162306a36Sopenharmony_ci} 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_cistatic void sumo_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev, 83462306a36Sopenharmony_ci struct radeon_ps *new_rps, 83562306a36Sopenharmony_ci struct radeon_ps *old_rps) 83662306a36Sopenharmony_ci{ 83762306a36Sopenharmony_ci struct sumo_ps *new_ps = sumo_get_ps(new_rps); 83862306a36Sopenharmony_ci struct sumo_ps *current_ps = sumo_get_ps(old_rps); 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci if ((new_rps->vclk == old_rps->vclk) && 84162306a36Sopenharmony_ci (new_rps->dclk == old_rps->dclk)) 84262306a36Sopenharmony_ci return; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci if (new_ps->levels[new_ps->num_levels - 1].sclk >= 84562306a36Sopenharmony_ci current_ps->levels[current_ps->num_levels - 1].sclk) 84662306a36Sopenharmony_ci return; 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci sumo_setup_uvd_clocks(rdev, new_rps, old_rps); 84962306a36Sopenharmony_ci} 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_cistatic void sumo_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev, 85262306a36Sopenharmony_ci struct radeon_ps *new_rps, 85362306a36Sopenharmony_ci struct radeon_ps *old_rps) 85462306a36Sopenharmony_ci{ 85562306a36Sopenharmony_ci struct sumo_ps *new_ps = sumo_get_ps(new_rps); 85662306a36Sopenharmony_ci struct sumo_ps *current_ps = sumo_get_ps(old_rps); 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci if ((new_rps->vclk == old_rps->vclk) && 85962306a36Sopenharmony_ci (new_rps->dclk == old_rps->dclk)) 86062306a36Sopenharmony_ci return; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci if (new_ps->levels[new_ps->num_levels - 1].sclk < 86362306a36Sopenharmony_ci current_ps->levels[current_ps->num_levels - 1].sclk) 86462306a36Sopenharmony_ci return; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci sumo_setup_uvd_clocks(rdev, new_rps, old_rps); 86762306a36Sopenharmony_ci} 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_civoid sumo_take_smu_control(struct radeon_device *rdev, bool enable) 87062306a36Sopenharmony_ci{ 87162306a36Sopenharmony_ci/* This bit selects who handles display phy powergating. 87262306a36Sopenharmony_ci * Clear the bit to let atom handle it. 87362306a36Sopenharmony_ci * Set it to let the driver handle it. 87462306a36Sopenharmony_ci * For now we just let atom handle it. 87562306a36Sopenharmony_ci */ 87662306a36Sopenharmony_ci#if 0 87762306a36Sopenharmony_ci u32 v = RREG32(DOUT_SCRATCH3); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci if (enable) 88062306a36Sopenharmony_ci v |= 0x4; 88162306a36Sopenharmony_ci else 88262306a36Sopenharmony_ci v &= 0xFFFFFFFB; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci WREG32(DOUT_SCRATCH3, v); 88562306a36Sopenharmony_ci#endif 88662306a36Sopenharmony_ci} 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_cistatic void sumo_enable_sclk_ds(struct radeon_device *rdev, bool enable) 88962306a36Sopenharmony_ci{ 89062306a36Sopenharmony_ci if (enable) { 89162306a36Sopenharmony_ci u32 deep_sleep_cntl = RREG32(DEEP_SLEEP_CNTL); 89262306a36Sopenharmony_ci u32 deep_sleep_cntl2 = RREG32(DEEP_SLEEP_CNTL2); 89362306a36Sopenharmony_ci u32 t = 1; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci deep_sleep_cntl &= ~R_DIS; 89662306a36Sopenharmony_ci deep_sleep_cntl &= ~HS_MASK; 89762306a36Sopenharmony_ci deep_sleep_cntl |= HS(t > 4095 ? 4095 : t); 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci deep_sleep_cntl2 |= LB_UFP_EN; 90062306a36Sopenharmony_ci deep_sleep_cntl2 &= INOUT_C_MASK; 90162306a36Sopenharmony_ci deep_sleep_cntl2 |= INOUT_C(0xf); 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci WREG32(DEEP_SLEEP_CNTL2, deep_sleep_cntl2); 90462306a36Sopenharmony_ci WREG32(DEEP_SLEEP_CNTL, deep_sleep_cntl); 90562306a36Sopenharmony_ci } else 90662306a36Sopenharmony_ci WREG32_P(DEEP_SLEEP_CNTL, 0, ~ENABLE_DS); 90762306a36Sopenharmony_ci} 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_cistatic void sumo_program_bootup_at(struct radeon_device *rdev) 91062306a36Sopenharmony_ci{ 91162306a36Sopenharmony_ci WREG32_P(CG_AT_0, CG_R(0xffff), ~CG_R_MASK); 91262306a36Sopenharmony_ci WREG32_P(CG_AT_0, CG_L(0), ~CG_L_MASK); 91362306a36Sopenharmony_ci} 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_cistatic void sumo_reset_am(struct radeon_device *rdev) 91662306a36Sopenharmony_ci{ 91762306a36Sopenharmony_ci WREG32_P(SCLK_PWRMGT_CNTL, FIR_RESET, ~FIR_RESET); 91862306a36Sopenharmony_ci} 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_cistatic void sumo_start_am(struct radeon_device *rdev) 92162306a36Sopenharmony_ci{ 92262306a36Sopenharmony_ci WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_RESET); 92362306a36Sopenharmony_ci} 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_cistatic void sumo_program_ttp(struct radeon_device *rdev) 92662306a36Sopenharmony_ci{ 92762306a36Sopenharmony_ci u32 xclk = radeon_get_xclk(rdev); 92862306a36Sopenharmony_ci u32 p, u; 92962306a36Sopenharmony_ci u32 cg_sclk_dpm_ctrl_5 = RREG32(CG_SCLK_DPM_CTRL_5); 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci r600_calculate_u_and_p(1000, 93262306a36Sopenharmony_ci xclk, 16, &p, &u); 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci cg_sclk_dpm_ctrl_5 &= ~(TT_TP_MASK | TT_TU_MASK); 93562306a36Sopenharmony_ci cg_sclk_dpm_ctrl_5 |= TT_TP(p) | TT_TU(u); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci WREG32(CG_SCLK_DPM_CTRL_5, cg_sclk_dpm_ctrl_5); 93862306a36Sopenharmony_ci} 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_cistatic void sumo_program_ttt(struct radeon_device *rdev) 94162306a36Sopenharmony_ci{ 94262306a36Sopenharmony_ci u32 cg_sclk_dpm_ctrl_3 = RREG32(CG_SCLK_DPM_CTRL_3); 94362306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci cg_sclk_dpm_ctrl_3 &= ~(GNB_TT_MASK | GNB_THERMTHRO_MASK); 94662306a36Sopenharmony_ci cg_sclk_dpm_ctrl_3 |= GNB_TT(pi->thermal_auto_throttling + 49); 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci WREG32(CG_SCLK_DPM_CTRL_3, cg_sclk_dpm_ctrl_3); 94962306a36Sopenharmony_ci} 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_cistatic void sumo_enable_voltage_scaling(struct radeon_device *rdev, bool enable) 95362306a36Sopenharmony_ci{ 95462306a36Sopenharmony_ci if (enable) { 95562306a36Sopenharmony_ci WREG32_P(CG_DPM_VOLTAGE_CNTL, DPM_VOLTAGE_EN, ~DPM_VOLTAGE_EN); 95662306a36Sopenharmony_ci WREG32_P(CG_CG_VOLTAGE_CNTL, 0, ~CG_VOLTAGE_EN); 95762306a36Sopenharmony_ci } else { 95862306a36Sopenharmony_ci WREG32_P(CG_CG_VOLTAGE_CNTL, CG_VOLTAGE_EN, ~CG_VOLTAGE_EN); 95962306a36Sopenharmony_ci WREG32_P(CG_DPM_VOLTAGE_CNTL, 0, ~DPM_VOLTAGE_EN); 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci} 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_cistatic void sumo_override_cnb_thermal_events(struct radeon_device *rdev) 96462306a36Sopenharmony_ci{ 96562306a36Sopenharmony_ci WREG32_P(CG_SCLK_DPM_CTRL_3, CNB_THERMTHRO_MASK_SCLK, 96662306a36Sopenharmony_ci ~CNB_THERMTHRO_MASK_SCLK); 96762306a36Sopenharmony_ci} 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_cistatic void sumo_program_dc_hto(struct radeon_device *rdev) 97062306a36Sopenharmony_ci{ 97162306a36Sopenharmony_ci u32 cg_sclk_dpm_ctrl_4 = RREG32(CG_SCLK_DPM_CTRL_4); 97262306a36Sopenharmony_ci u32 p, u; 97362306a36Sopenharmony_ci u32 xclk = radeon_get_xclk(rdev); 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci r600_calculate_u_and_p(100000, 97662306a36Sopenharmony_ci xclk, 14, &p, &u); 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci cg_sclk_dpm_ctrl_4 &= ~(DC_HDC_MASK | DC_HU_MASK); 97962306a36Sopenharmony_ci cg_sclk_dpm_ctrl_4 |= DC_HDC(p) | DC_HU(u); 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci WREG32(CG_SCLK_DPM_CTRL_4, cg_sclk_dpm_ctrl_4); 98262306a36Sopenharmony_ci} 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_cistatic void sumo_force_nbp_state(struct radeon_device *rdev, 98562306a36Sopenharmony_ci struct radeon_ps *rps) 98662306a36Sopenharmony_ci{ 98762306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 98862306a36Sopenharmony_ci struct sumo_ps *new_ps = sumo_get_ps(rps); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci if (!pi->driver_nbps_policy_disable) { 99162306a36Sopenharmony_ci if (new_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE) 99262306a36Sopenharmony_ci WREG32_P(CG_SCLK_DPM_CTRL_3, FORCE_NB_PSTATE_1, ~FORCE_NB_PSTATE_1); 99362306a36Sopenharmony_ci else 99462306a36Sopenharmony_ci WREG32_P(CG_SCLK_DPM_CTRL_3, 0, ~FORCE_NB_PSTATE_1); 99562306a36Sopenharmony_ci } 99662306a36Sopenharmony_ci} 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ciu32 sumo_get_sleep_divider_from_id(u32 id) 99962306a36Sopenharmony_ci{ 100062306a36Sopenharmony_ci return 1 << id; 100162306a36Sopenharmony_ci} 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ciu32 sumo_get_sleep_divider_id_from_clock(struct radeon_device *rdev, 100462306a36Sopenharmony_ci u32 sclk, 100562306a36Sopenharmony_ci u32 min_sclk_in_sr) 100662306a36Sopenharmony_ci{ 100762306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 100862306a36Sopenharmony_ci u32 i; 100962306a36Sopenharmony_ci u32 temp; 101062306a36Sopenharmony_ci u32 min = (min_sclk_in_sr > SUMO_MINIMUM_ENGINE_CLOCK) ? 101162306a36Sopenharmony_ci min_sclk_in_sr : SUMO_MINIMUM_ENGINE_CLOCK; 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci if (sclk < min) 101462306a36Sopenharmony_ci return 0; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci if (!pi->enable_sclk_ds) 101762306a36Sopenharmony_ci return 0; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci for (i = SUMO_MAX_DEEPSLEEP_DIVIDER_ID; ; i--) { 102062306a36Sopenharmony_ci temp = sclk / sumo_get_sleep_divider_from_id(i); 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci if (temp >= min || i == 0) 102362306a36Sopenharmony_ci break; 102462306a36Sopenharmony_ci } 102562306a36Sopenharmony_ci return i; 102662306a36Sopenharmony_ci} 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_cistatic u32 sumo_get_valid_engine_clock(struct radeon_device *rdev, 102962306a36Sopenharmony_ci u32 lower_limit) 103062306a36Sopenharmony_ci{ 103162306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 103262306a36Sopenharmony_ci u32 i; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci for (i = 0; i < pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries; i++) { 103562306a36Sopenharmony_ci if (pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency >= lower_limit) 103662306a36Sopenharmony_ci return pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency; 103762306a36Sopenharmony_ci } 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci return pi->sys_info.sclk_voltage_mapping_table.entries[pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries - 1].sclk_frequency; 104062306a36Sopenharmony_ci} 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_cistatic void sumo_patch_thermal_state(struct radeon_device *rdev, 104362306a36Sopenharmony_ci struct sumo_ps *ps, 104462306a36Sopenharmony_ci struct sumo_ps *current_ps) 104562306a36Sopenharmony_ci{ 104662306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 104762306a36Sopenharmony_ci u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */ 104862306a36Sopenharmony_ci u32 current_vddc; 104962306a36Sopenharmony_ci u32 current_sclk; 105062306a36Sopenharmony_ci u32 current_index = 0; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci if (current_ps) { 105362306a36Sopenharmony_ci current_vddc = current_ps->levels[current_index].vddc_index; 105462306a36Sopenharmony_ci current_sclk = current_ps->levels[current_index].sclk; 105562306a36Sopenharmony_ci } else { 105662306a36Sopenharmony_ci current_vddc = pi->boot_pl.vddc_index; 105762306a36Sopenharmony_ci current_sclk = pi->boot_pl.sclk; 105862306a36Sopenharmony_ci } 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci ps->levels[0].vddc_index = current_vddc; 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci if (ps->levels[0].sclk > current_sclk) 106362306a36Sopenharmony_ci ps->levels[0].sclk = current_sclk; 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci ps->levels[0].ss_divider_index = 106662306a36Sopenharmony_ci sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[0].sclk, sclk_in_sr); 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci ps->levels[0].ds_divider_index = 106962306a36Sopenharmony_ci sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[0].sclk, SUMO_MINIMUM_ENGINE_CLOCK); 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci if (ps->levels[0].ds_divider_index > ps->levels[0].ss_divider_index + 1) 107262306a36Sopenharmony_ci ps->levels[0].ds_divider_index = ps->levels[0].ss_divider_index + 1; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci if (ps->levels[0].ss_divider_index == ps->levels[0].ds_divider_index) { 107562306a36Sopenharmony_ci if (ps->levels[0].ss_divider_index > 1) 107662306a36Sopenharmony_ci ps->levels[0].ss_divider_index = ps->levels[0].ss_divider_index - 1; 107762306a36Sopenharmony_ci } 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci if (ps->levels[0].ss_divider_index == 0) 108062306a36Sopenharmony_ci ps->levels[0].ds_divider_index = 0; 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci if (ps->levels[0].ds_divider_index == 0) 108362306a36Sopenharmony_ci ps->levels[0].ss_divider_index = 0; 108462306a36Sopenharmony_ci} 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_cistatic void sumo_apply_state_adjust_rules(struct radeon_device *rdev, 108762306a36Sopenharmony_ci struct radeon_ps *new_rps, 108862306a36Sopenharmony_ci struct radeon_ps *old_rps) 108962306a36Sopenharmony_ci{ 109062306a36Sopenharmony_ci struct sumo_ps *ps = sumo_get_ps(new_rps); 109162306a36Sopenharmony_ci struct sumo_ps *current_ps = sumo_get_ps(old_rps); 109262306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 109362306a36Sopenharmony_ci u32 min_voltage = 0; /* ??? */ 109462306a36Sopenharmony_ci u32 min_sclk = pi->sys_info.min_sclk; /* XXX check against disp reqs */ 109562306a36Sopenharmony_ci u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */ 109662306a36Sopenharmony_ci u32 i; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci if (new_rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL) 109962306a36Sopenharmony_ci return sumo_patch_thermal_state(rdev, ps, current_ps); 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci if (pi->enable_boost) { 110262306a36Sopenharmony_ci if (new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) 110362306a36Sopenharmony_ci ps->flags |= SUMO_POWERSTATE_FLAGS_BOOST_STATE; 110462306a36Sopenharmony_ci } 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci if ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) || 110762306a36Sopenharmony_ci (new_rps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) || 110862306a36Sopenharmony_ci (new_rps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE)) 110962306a36Sopenharmony_ci ps->flags |= SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci for (i = 0; i < ps->num_levels; i++) { 111262306a36Sopenharmony_ci if (ps->levels[i].vddc_index < min_voltage) 111362306a36Sopenharmony_ci ps->levels[i].vddc_index = min_voltage; 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci if (ps->levels[i].sclk < min_sclk) 111662306a36Sopenharmony_ci ps->levels[i].sclk = 111762306a36Sopenharmony_ci sumo_get_valid_engine_clock(rdev, min_sclk); 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci ps->levels[i].ss_divider_index = 112062306a36Sopenharmony_ci sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[i].sclk, sclk_in_sr); 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci ps->levels[i].ds_divider_index = 112362306a36Sopenharmony_ci sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[i].sclk, SUMO_MINIMUM_ENGINE_CLOCK); 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci if (ps->levels[i].ds_divider_index > ps->levels[i].ss_divider_index + 1) 112662306a36Sopenharmony_ci ps->levels[i].ds_divider_index = ps->levels[i].ss_divider_index + 1; 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci if (ps->levels[i].ss_divider_index == ps->levels[i].ds_divider_index) { 112962306a36Sopenharmony_ci if (ps->levels[i].ss_divider_index > 1) 113062306a36Sopenharmony_ci ps->levels[i].ss_divider_index = ps->levels[i].ss_divider_index - 1; 113162306a36Sopenharmony_ci } 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci if (ps->levels[i].ss_divider_index == 0) 113462306a36Sopenharmony_ci ps->levels[i].ds_divider_index = 0; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci if (ps->levels[i].ds_divider_index == 0) 113762306a36Sopenharmony_ci ps->levels[i].ss_divider_index = 0; 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci if (ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE) 114062306a36Sopenharmony_ci ps->levels[i].allow_gnb_slow = 1; 114162306a36Sopenharmony_ci else if ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) || 114262306a36Sopenharmony_ci (new_rps->class2 & ATOM_PPLIB_CLASSIFICATION2_MVC)) 114362306a36Sopenharmony_ci ps->levels[i].allow_gnb_slow = 0; 114462306a36Sopenharmony_ci else if (i == ps->num_levels - 1) 114562306a36Sopenharmony_ci ps->levels[i].allow_gnb_slow = 0; 114662306a36Sopenharmony_ci else 114762306a36Sopenharmony_ci ps->levels[i].allow_gnb_slow = 1; 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci} 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_cistatic void sumo_cleanup_asic(struct radeon_device *rdev) 115262306a36Sopenharmony_ci{ 115362306a36Sopenharmony_ci sumo_take_smu_control(rdev, false); 115462306a36Sopenharmony_ci} 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_cistatic int sumo_set_thermal_temperature_range(struct radeon_device *rdev, 115762306a36Sopenharmony_ci int min_temp, int max_temp) 115862306a36Sopenharmony_ci{ 115962306a36Sopenharmony_ci int low_temp = 0 * 1000; 116062306a36Sopenharmony_ci int high_temp = 255 * 1000; 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci if (low_temp < min_temp) 116362306a36Sopenharmony_ci low_temp = min_temp; 116462306a36Sopenharmony_ci if (high_temp > max_temp) 116562306a36Sopenharmony_ci high_temp = max_temp; 116662306a36Sopenharmony_ci if (high_temp < low_temp) { 116762306a36Sopenharmony_ci DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp); 116862306a36Sopenharmony_ci return -EINVAL; 116962306a36Sopenharmony_ci } 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci WREG32_P(CG_THERMAL_INT, DIG_THERM_INTH(49 + (high_temp / 1000)), ~DIG_THERM_INTH_MASK); 117262306a36Sopenharmony_ci WREG32_P(CG_THERMAL_INT, DIG_THERM_INTL(49 + (low_temp / 1000)), ~DIG_THERM_INTL_MASK); 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci rdev->pm.dpm.thermal.min_temp = low_temp; 117562306a36Sopenharmony_ci rdev->pm.dpm.thermal.max_temp = high_temp; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci return 0; 117862306a36Sopenharmony_ci} 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_cistatic void sumo_update_current_ps(struct radeon_device *rdev, 118162306a36Sopenharmony_ci struct radeon_ps *rps) 118262306a36Sopenharmony_ci{ 118362306a36Sopenharmony_ci struct sumo_ps *new_ps = sumo_get_ps(rps); 118462306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci pi->current_rps = *rps; 118762306a36Sopenharmony_ci pi->current_ps = *new_ps; 118862306a36Sopenharmony_ci pi->current_rps.ps_priv = &pi->current_ps; 118962306a36Sopenharmony_ci} 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_cistatic void sumo_update_requested_ps(struct radeon_device *rdev, 119262306a36Sopenharmony_ci struct radeon_ps *rps) 119362306a36Sopenharmony_ci{ 119462306a36Sopenharmony_ci struct sumo_ps *new_ps = sumo_get_ps(rps); 119562306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci pi->requested_rps = *rps; 119862306a36Sopenharmony_ci pi->requested_ps = *new_ps; 119962306a36Sopenharmony_ci pi->requested_rps.ps_priv = &pi->requested_ps; 120062306a36Sopenharmony_ci} 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ciint sumo_dpm_enable(struct radeon_device *rdev) 120362306a36Sopenharmony_ci{ 120462306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci if (sumo_dpm_enabled(rdev)) 120762306a36Sopenharmony_ci return -EINVAL; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci sumo_program_bootup_state(rdev); 121062306a36Sopenharmony_ci sumo_init_bsp(rdev); 121162306a36Sopenharmony_ci sumo_reset_am(rdev); 121262306a36Sopenharmony_ci sumo_program_tp(rdev); 121362306a36Sopenharmony_ci sumo_program_bootup_at(rdev); 121462306a36Sopenharmony_ci sumo_start_am(rdev); 121562306a36Sopenharmony_ci if (pi->enable_auto_thermal_throttling) { 121662306a36Sopenharmony_ci sumo_program_ttp(rdev); 121762306a36Sopenharmony_ci sumo_program_ttt(rdev); 121862306a36Sopenharmony_ci } 121962306a36Sopenharmony_ci sumo_program_dc_hto(rdev); 122062306a36Sopenharmony_ci sumo_program_power_level_enter_state(rdev); 122162306a36Sopenharmony_ci sumo_enable_voltage_scaling(rdev, true); 122262306a36Sopenharmony_ci sumo_program_sstp(rdev); 122362306a36Sopenharmony_ci sumo_program_vc(rdev, SUMO_VRC_DFLT); 122462306a36Sopenharmony_ci sumo_override_cnb_thermal_events(rdev); 122562306a36Sopenharmony_ci sumo_start_dpm(rdev); 122662306a36Sopenharmony_ci sumo_wait_for_level_0(rdev); 122762306a36Sopenharmony_ci if (pi->enable_sclk_ds) 122862306a36Sopenharmony_ci sumo_enable_sclk_ds(rdev, true); 122962306a36Sopenharmony_ci if (pi->enable_boost) 123062306a36Sopenharmony_ci sumo_enable_boost_timer(rdev); 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci sumo_update_current_ps(rdev, rdev->pm.dpm.boot_ps); 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci return 0; 123562306a36Sopenharmony_ci} 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ciint sumo_dpm_late_enable(struct radeon_device *rdev) 123862306a36Sopenharmony_ci{ 123962306a36Sopenharmony_ci int ret; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci ret = sumo_enable_clock_power_gating(rdev); 124262306a36Sopenharmony_ci if (ret) 124362306a36Sopenharmony_ci return ret; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci if (rdev->irq.installed && 124662306a36Sopenharmony_ci r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { 124762306a36Sopenharmony_ci ret = sumo_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); 124862306a36Sopenharmony_ci if (ret) 124962306a36Sopenharmony_ci return ret; 125062306a36Sopenharmony_ci rdev->irq.dpm_thermal = true; 125162306a36Sopenharmony_ci radeon_irq_set(rdev); 125262306a36Sopenharmony_ci } 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci return 0; 125562306a36Sopenharmony_ci} 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_civoid sumo_dpm_disable(struct radeon_device *rdev) 125862306a36Sopenharmony_ci{ 125962306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci if (!sumo_dpm_enabled(rdev)) 126262306a36Sopenharmony_ci return; 126362306a36Sopenharmony_ci sumo_disable_clock_power_gating(rdev); 126462306a36Sopenharmony_ci if (pi->enable_sclk_ds) 126562306a36Sopenharmony_ci sumo_enable_sclk_ds(rdev, false); 126662306a36Sopenharmony_ci sumo_clear_vc(rdev); 126762306a36Sopenharmony_ci sumo_wait_for_level_0(rdev); 126862306a36Sopenharmony_ci sumo_stop_dpm(rdev); 126962306a36Sopenharmony_ci sumo_enable_voltage_scaling(rdev, false); 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci if (rdev->irq.installed && 127262306a36Sopenharmony_ci r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { 127362306a36Sopenharmony_ci rdev->irq.dpm_thermal = false; 127462306a36Sopenharmony_ci radeon_irq_set(rdev); 127562306a36Sopenharmony_ci } 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci sumo_update_current_ps(rdev, rdev->pm.dpm.boot_ps); 127862306a36Sopenharmony_ci} 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ciint sumo_dpm_pre_set_power_state(struct radeon_device *rdev) 128162306a36Sopenharmony_ci{ 128262306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 128362306a36Sopenharmony_ci struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps; 128462306a36Sopenharmony_ci struct radeon_ps *new_ps = &requested_ps; 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci sumo_update_requested_ps(rdev, new_ps); 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci if (pi->enable_dynamic_patch_ps) 128962306a36Sopenharmony_ci sumo_apply_state_adjust_rules(rdev, 129062306a36Sopenharmony_ci &pi->requested_rps, 129162306a36Sopenharmony_ci &pi->current_rps); 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci return 0; 129462306a36Sopenharmony_ci} 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ciint sumo_dpm_set_power_state(struct radeon_device *rdev) 129762306a36Sopenharmony_ci{ 129862306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 129962306a36Sopenharmony_ci struct radeon_ps *new_ps = &pi->requested_rps; 130062306a36Sopenharmony_ci struct radeon_ps *old_ps = &pi->current_rps; 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci if (pi->enable_dpm) 130362306a36Sopenharmony_ci sumo_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps); 130462306a36Sopenharmony_ci if (pi->enable_boost) { 130562306a36Sopenharmony_ci sumo_enable_boost(rdev, new_ps, false); 130662306a36Sopenharmony_ci sumo_patch_boost_state(rdev, new_ps); 130762306a36Sopenharmony_ci } 130862306a36Sopenharmony_ci if (pi->enable_dpm) { 130962306a36Sopenharmony_ci sumo_pre_notify_alt_vddnb_change(rdev, new_ps, old_ps); 131062306a36Sopenharmony_ci sumo_enable_power_level_0(rdev); 131162306a36Sopenharmony_ci sumo_set_forced_level_0(rdev); 131262306a36Sopenharmony_ci sumo_set_forced_mode_enabled(rdev); 131362306a36Sopenharmony_ci sumo_wait_for_level_0(rdev); 131462306a36Sopenharmony_ci sumo_program_power_levels_0_to_n(rdev, new_ps, old_ps); 131562306a36Sopenharmony_ci sumo_program_wl(rdev, new_ps); 131662306a36Sopenharmony_ci sumo_program_bsp(rdev, new_ps); 131762306a36Sopenharmony_ci sumo_program_at(rdev, new_ps); 131862306a36Sopenharmony_ci sumo_force_nbp_state(rdev, new_ps); 131962306a36Sopenharmony_ci sumo_set_forced_mode_disabled(rdev); 132062306a36Sopenharmony_ci sumo_set_forced_mode_enabled(rdev); 132162306a36Sopenharmony_ci sumo_set_forced_mode_disabled(rdev); 132262306a36Sopenharmony_ci sumo_post_notify_alt_vddnb_change(rdev, new_ps, old_ps); 132362306a36Sopenharmony_ci } 132462306a36Sopenharmony_ci if (pi->enable_boost) 132562306a36Sopenharmony_ci sumo_enable_boost(rdev, new_ps, true); 132662306a36Sopenharmony_ci if (pi->enable_dpm) 132762306a36Sopenharmony_ci sumo_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps); 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci return 0; 133062306a36Sopenharmony_ci} 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_civoid sumo_dpm_post_set_power_state(struct radeon_device *rdev) 133362306a36Sopenharmony_ci{ 133462306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 133562306a36Sopenharmony_ci struct radeon_ps *new_ps = &pi->requested_rps; 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci sumo_update_current_ps(rdev, new_ps); 133862306a36Sopenharmony_ci} 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci#if 0 134162306a36Sopenharmony_civoid sumo_dpm_reset_asic(struct radeon_device *rdev) 134262306a36Sopenharmony_ci{ 134362306a36Sopenharmony_ci sumo_program_bootup_state(rdev); 134462306a36Sopenharmony_ci sumo_enable_power_level_0(rdev); 134562306a36Sopenharmony_ci sumo_set_forced_level_0(rdev); 134662306a36Sopenharmony_ci sumo_set_forced_mode_enabled(rdev); 134762306a36Sopenharmony_ci sumo_wait_for_level_0(rdev); 134862306a36Sopenharmony_ci sumo_set_forced_mode_disabled(rdev); 134962306a36Sopenharmony_ci sumo_set_forced_mode_enabled(rdev); 135062306a36Sopenharmony_ci sumo_set_forced_mode_disabled(rdev); 135162306a36Sopenharmony_ci} 135262306a36Sopenharmony_ci#endif 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_civoid sumo_dpm_setup_asic(struct radeon_device *rdev) 135562306a36Sopenharmony_ci{ 135662306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci sumo_initialize_m3_arb(rdev); 135962306a36Sopenharmony_ci pi->fw_version = sumo_get_running_fw_version(rdev); 136062306a36Sopenharmony_ci DRM_INFO("Found smc ucode version: 0x%08x\n", pi->fw_version); 136162306a36Sopenharmony_ci sumo_program_acpi_power_level(rdev); 136262306a36Sopenharmony_ci sumo_enable_acpi_pm(rdev); 136362306a36Sopenharmony_ci sumo_take_smu_control(rdev, true); 136462306a36Sopenharmony_ci} 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_civoid sumo_dpm_display_configuration_changed(struct radeon_device *rdev) 136762306a36Sopenharmony_ci{ 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci} 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ciunion power_info { 137262306a36Sopenharmony_ci struct _ATOM_POWERPLAY_INFO info; 137362306a36Sopenharmony_ci struct _ATOM_POWERPLAY_INFO_V2 info_2; 137462306a36Sopenharmony_ci struct _ATOM_POWERPLAY_INFO_V3 info_3; 137562306a36Sopenharmony_ci struct _ATOM_PPLIB_POWERPLAYTABLE pplib; 137662306a36Sopenharmony_ci struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2; 137762306a36Sopenharmony_ci struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3; 137862306a36Sopenharmony_ci}; 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ciunion pplib_clock_info { 138162306a36Sopenharmony_ci struct _ATOM_PPLIB_R600_CLOCK_INFO r600; 138262306a36Sopenharmony_ci struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780; 138362306a36Sopenharmony_ci struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen; 138462306a36Sopenharmony_ci struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo; 138562306a36Sopenharmony_ci}; 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ciunion pplib_power_state { 138862306a36Sopenharmony_ci struct _ATOM_PPLIB_STATE v1; 138962306a36Sopenharmony_ci struct _ATOM_PPLIB_STATE_V2 v2; 139062306a36Sopenharmony_ci}; 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_cistatic void sumo_patch_boot_state(struct radeon_device *rdev, 139362306a36Sopenharmony_ci struct sumo_ps *ps) 139462306a36Sopenharmony_ci{ 139562306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci ps->num_levels = 1; 139862306a36Sopenharmony_ci ps->flags = 0; 139962306a36Sopenharmony_ci ps->levels[0] = pi->boot_pl; 140062306a36Sopenharmony_ci} 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_cistatic void sumo_parse_pplib_non_clock_info(struct radeon_device *rdev, 140362306a36Sopenharmony_ci struct radeon_ps *rps, 140462306a36Sopenharmony_ci struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info, 140562306a36Sopenharmony_ci u8 table_rev) 140662306a36Sopenharmony_ci{ 140762306a36Sopenharmony_ci struct sumo_ps *ps = sumo_get_ps(rps); 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings); 141062306a36Sopenharmony_ci rps->class = le16_to_cpu(non_clock_info->usClassification); 141162306a36Sopenharmony_ci rps->class2 = le16_to_cpu(non_clock_info->usClassification2); 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) { 141462306a36Sopenharmony_ci rps->vclk = le32_to_cpu(non_clock_info->ulVCLK); 141562306a36Sopenharmony_ci rps->dclk = le32_to_cpu(non_clock_info->ulDCLK); 141662306a36Sopenharmony_ci } else { 141762306a36Sopenharmony_ci rps->vclk = 0; 141862306a36Sopenharmony_ci rps->dclk = 0; 141962306a36Sopenharmony_ci } 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) { 142262306a36Sopenharmony_ci rdev->pm.dpm.boot_ps = rps; 142362306a36Sopenharmony_ci sumo_patch_boot_state(rdev, ps); 142462306a36Sopenharmony_ci } 142562306a36Sopenharmony_ci if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) 142662306a36Sopenharmony_ci rdev->pm.dpm.uvd_ps = rps; 142762306a36Sopenharmony_ci} 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_cistatic void sumo_parse_pplib_clock_info(struct radeon_device *rdev, 143062306a36Sopenharmony_ci struct radeon_ps *rps, int index, 143162306a36Sopenharmony_ci union pplib_clock_info *clock_info) 143262306a36Sopenharmony_ci{ 143362306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 143462306a36Sopenharmony_ci struct sumo_ps *ps = sumo_get_ps(rps); 143562306a36Sopenharmony_ci struct sumo_pl *pl = &ps->levels[index]; 143662306a36Sopenharmony_ci u32 sclk; 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow); 143962306a36Sopenharmony_ci sclk |= clock_info->sumo.ucEngineClockHigh << 16; 144062306a36Sopenharmony_ci pl->sclk = sclk; 144162306a36Sopenharmony_ci pl->vddc_index = clock_info->sumo.vddcIndex; 144262306a36Sopenharmony_ci pl->sclk_dpm_tdp_limit = clock_info->sumo.tdpLimit; 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci ps->num_levels = index + 1; 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci if (pi->enable_sclk_ds) { 144762306a36Sopenharmony_ci pl->ds_divider_index = 5; 144862306a36Sopenharmony_ci pl->ss_divider_index = 4; 144962306a36Sopenharmony_ci } 145062306a36Sopenharmony_ci} 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_cistatic int sumo_parse_power_table(struct radeon_device *rdev) 145362306a36Sopenharmony_ci{ 145462306a36Sopenharmony_ci struct radeon_mode_info *mode_info = &rdev->mode_info; 145562306a36Sopenharmony_ci struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; 145662306a36Sopenharmony_ci union pplib_power_state *power_state; 145762306a36Sopenharmony_ci int i, j, k, non_clock_array_index, clock_array_index; 145862306a36Sopenharmony_ci union pplib_clock_info *clock_info; 145962306a36Sopenharmony_ci struct _StateArray *state_array; 146062306a36Sopenharmony_ci struct _ClockInfoArray *clock_info_array; 146162306a36Sopenharmony_ci struct _NonClockInfoArray *non_clock_info_array; 146262306a36Sopenharmony_ci union power_info *power_info; 146362306a36Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); 146462306a36Sopenharmony_ci u16 data_offset; 146562306a36Sopenharmony_ci u8 frev, crev; 146662306a36Sopenharmony_ci u8 *power_state_offset; 146762306a36Sopenharmony_ci struct sumo_ps *ps; 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci if (!atom_parse_data_header(mode_info->atom_context, index, NULL, 147062306a36Sopenharmony_ci &frev, &crev, &data_offset)) 147162306a36Sopenharmony_ci return -EINVAL; 147262306a36Sopenharmony_ci power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci state_array = (struct _StateArray *) 147562306a36Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 147662306a36Sopenharmony_ci le16_to_cpu(power_info->pplib.usStateArrayOffset)); 147762306a36Sopenharmony_ci clock_info_array = (struct _ClockInfoArray *) 147862306a36Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 147962306a36Sopenharmony_ci le16_to_cpu(power_info->pplib.usClockInfoArrayOffset)); 148062306a36Sopenharmony_ci non_clock_info_array = (struct _NonClockInfoArray *) 148162306a36Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 148262306a36Sopenharmony_ci le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci rdev->pm.dpm.ps = kcalloc(state_array->ucNumEntries, 148562306a36Sopenharmony_ci sizeof(struct radeon_ps), 148662306a36Sopenharmony_ci GFP_KERNEL); 148762306a36Sopenharmony_ci if (!rdev->pm.dpm.ps) 148862306a36Sopenharmony_ci return -ENOMEM; 148962306a36Sopenharmony_ci power_state_offset = (u8 *)state_array->states; 149062306a36Sopenharmony_ci for (i = 0; i < state_array->ucNumEntries; i++) { 149162306a36Sopenharmony_ci u8 *idx; 149262306a36Sopenharmony_ci power_state = (union pplib_power_state *)power_state_offset; 149362306a36Sopenharmony_ci non_clock_array_index = power_state->v2.nonClockInfoIndex; 149462306a36Sopenharmony_ci non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) 149562306a36Sopenharmony_ci &non_clock_info_array->nonClockInfo[non_clock_array_index]; 149662306a36Sopenharmony_ci if (!rdev->pm.power_state[i].clock_info) { 149762306a36Sopenharmony_ci kfree(rdev->pm.dpm.ps); 149862306a36Sopenharmony_ci return -EINVAL; 149962306a36Sopenharmony_ci } 150062306a36Sopenharmony_ci ps = kzalloc(sizeof(struct sumo_ps), GFP_KERNEL); 150162306a36Sopenharmony_ci if (ps == NULL) { 150262306a36Sopenharmony_ci kfree(rdev->pm.dpm.ps); 150362306a36Sopenharmony_ci return -ENOMEM; 150462306a36Sopenharmony_ci } 150562306a36Sopenharmony_ci rdev->pm.dpm.ps[i].ps_priv = ps; 150662306a36Sopenharmony_ci k = 0; 150762306a36Sopenharmony_ci idx = (u8 *)&power_state->v2.clockInfoIndex[0]; 150862306a36Sopenharmony_ci for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) { 150962306a36Sopenharmony_ci clock_array_index = idx[j]; 151062306a36Sopenharmony_ci if (k >= SUMO_MAX_HARDWARE_POWERLEVELS) 151162306a36Sopenharmony_ci break; 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci clock_info = (union pplib_clock_info *) 151462306a36Sopenharmony_ci ((u8 *)&clock_info_array->clockInfo[0] + 151562306a36Sopenharmony_ci (clock_array_index * clock_info_array->ucEntrySize)); 151662306a36Sopenharmony_ci sumo_parse_pplib_clock_info(rdev, 151762306a36Sopenharmony_ci &rdev->pm.dpm.ps[i], k, 151862306a36Sopenharmony_ci clock_info); 151962306a36Sopenharmony_ci k++; 152062306a36Sopenharmony_ci } 152162306a36Sopenharmony_ci sumo_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i], 152262306a36Sopenharmony_ci non_clock_info, 152362306a36Sopenharmony_ci non_clock_info_array->ucEntrySize); 152462306a36Sopenharmony_ci power_state_offset += 2 + power_state->v2.ucNumDPMLevels; 152562306a36Sopenharmony_ci } 152662306a36Sopenharmony_ci rdev->pm.dpm.num_ps = state_array->ucNumEntries; 152762306a36Sopenharmony_ci return 0; 152862306a36Sopenharmony_ci} 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ciu32 sumo_convert_vid2_to_vid7(struct radeon_device *rdev, 153162306a36Sopenharmony_ci struct sumo_vid_mapping_table *vid_mapping_table, 153262306a36Sopenharmony_ci u32 vid_2bit) 153362306a36Sopenharmony_ci{ 153462306a36Sopenharmony_ci u32 i; 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci for (i = 0; i < vid_mapping_table->num_entries; i++) { 153762306a36Sopenharmony_ci if (vid_mapping_table->entries[i].vid_2bit == vid_2bit) 153862306a36Sopenharmony_ci return vid_mapping_table->entries[i].vid_7bit; 153962306a36Sopenharmony_ci } 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci return vid_mapping_table->entries[vid_mapping_table->num_entries - 1].vid_7bit; 154262306a36Sopenharmony_ci} 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci#if 0 154562306a36Sopenharmony_ciu32 sumo_convert_vid7_to_vid2(struct radeon_device *rdev, 154662306a36Sopenharmony_ci struct sumo_vid_mapping_table *vid_mapping_table, 154762306a36Sopenharmony_ci u32 vid_7bit) 154862306a36Sopenharmony_ci{ 154962306a36Sopenharmony_ci u32 i; 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci for (i = 0; i < vid_mapping_table->num_entries; i++) { 155262306a36Sopenharmony_ci if (vid_mapping_table->entries[i].vid_7bit == vid_7bit) 155362306a36Sopenharmony_ci return vid_mapping_table->entries[i].vid_2bit; 155462306a36Sopenharmony_ci } 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci return vid_mapping_table->entries[vid_mapping_table->num_entries - 1].vid_2bit; 155762306a36Sopenharmony_ci} 155862306a36Sopenharmony_ci#endif 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_cistatic u16 sumo_convert_voltage_index_to_value(struct radeon_device *rdev, 156162306a36Sopenharmony_ci u32 vid_2bit) 156262306a36Sopenharmony_ci{ 156362306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 156462306a36Sopenharmony_ci u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, &pi->sys_info.vid_mapping_table, vid_2bit); 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci if (vid_7bit > 0x7C) 156762306a36Sopenharmony_ci return 0; 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci return (15500 - vid_7bit * 125 + 5) / 10; 157062306a36Sopenharmony_ci} 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_cistatic void sumo_construct_display_voltage_mapping_table(struct radeon_device *rdev, 157362306a36Sopenharmony_ci struct sumo_disp_clock_voltage_mapping_table *disp_clk_voltage_mapping_table, 157462306a36Sopenharmony_ci ATOM_CLK_VOLT_CAPABILITY *table) 157562306a36Sopenharmony_ci{ 157662306a36Sopenharmony_ci u32 i; 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci for (i = 0; i < SUMO_MAX_NUMBER_VOLTAGES; i++) { 157962306a36Sopenharmony_ci if (table[i].ulMaximumSupportedCLK == 0) 158062306a36Sopenharmony_ci break; 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci disp_clk_voltage_mapping_table->display_clock_frequency[i] = 158362306a36Sopenharmony_ci table[i].ulMaximumSupportedCLK; 158462306a36Sopenharmony_ci } 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci disp_clk_voltage_mapping_table->num_max_voltage_levels = i; 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci if (disp_clk_voltage_mapping_table->num_max_voltage_levels == 0) { 158962306a36Sopenharmony_ci disp_clk_voltage_mapping_table->display_clock_frequency[0] = 80000; 159062306a36Sopenharmony_ci disp_clk_voltage_mapping_table->num_max_voltage_levels = 1; 159162306a36Sopenharmony_ci } 159262306a36Sopenharmony_ci} 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_civoid sumo_construct_sclk_voltage_mapping_table(struct radeon_device *rdev, 159562306a36Sopenharmony_ci struct sumo_sclk_voltage_mapping_table *sclk_voltage_mapping_table, 159662306a36Sopenharmony_ci ATOM_AVAILABLE_SCLK_LIST *table) 159762306a36Sopenharmony_ci{ 159862306a36Sopenharmony_ci u32 i; 159962306a36Sopenharmony_ci u32 n = 0; 160062306a36Sopenharmony_ci u32 prev_sclk = 0; 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_ci for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) { 160362306a36Sopenharmony_ci if (table[i].ulSupportedSCLK > prev_sclk) { 160462306a36Sopenharmony_ci sclk_voltage_mapping_table->entries[n].sclk_frequency = 160562306a36Sopenharmony_ci table[i].ulSupportedSCLK; 160662306a36Sopenharmony_ci sclk_voltage_mapping_table->entries[n].vid_2bit = 160762306a36Sopenharmony_ci table[i].usVoltageIndex; 160862306a36Sopenharmony_ci prev_sclk = table[i].ulSupportedSCLK; 160962306a36Sopenharmony_ci n++; 161062306a36Sopenharmony_ci } 161162306a36Sopenharmony_ci } 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci sclk_voltage_mapping_table->num_max_dpm_entries = n; 161462306a36Sopenharmony_ci} 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_civoid sumo_construct_vid_mapping_table(struct radeon_device *rdev, 161762306a36Sopenharmony_ci struct sumo_vid_mapping_table *vid_mapping_table, 161862306a36Sopenharmony_ci ATOM_AVAILABLE_SCLK_LIST *table) 161962306a36Sopenharmony_ci{ 162062306a36Sopenharmony_ci u32 i, j; 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) { 162362306a36Sopenharmony_ci if (table[i].ulSupportedSCLK != 0) { 162462306a36Sopenharmony_ci vid_mapping_table->entries[table[i].usVoltageIndex].vid_7bit = 162562306a36Sopenharmony_ci table[i].usVoltageID; 162662306a36Sopenharmony_ci vid_mapping_table->entries[table[i].usVoltageIndex].vid_2bit = 162762306a36Sopenharmony_ci table[i].usVoltageIndex; 162862306a36Sopenharmony_ci } 162962306a36Sopenharmony_ci } 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci for (i = 0; i < SUMO_MAX_NUMBER_VOLTAGES; i++) { 163262306a36Sopenharmony_ci if (vid_mapping_table->entries[i].vid_7bit == 0) { 163362306a36Sopenharmony_ci for (j = i + 1; j < SUMO_MAX_NUMBER_VOLTAGES; j++) { 163462306a36Sopenharmony_ci if (vid_mapping_table->entries[j].vid_7bit != 0) { 163562306a36Sopenharmony_ci vid_mapping_table->entries[i] = 163662306a36Sopenharmony_ci vid_mapping_table->entries[j]; 163762306a36Sopenharmony_ci vid_mapping_table->entries[j].vid_7bit = 0; 163862306a36Sopenharmony_ci break; 163962306a36Sopenharmony_ci } 164062306a36Sopenharmony_ci } 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci if (j == SUMO_MAX_NUMBER_VOLTAGES) 164362306a36Sopenharmony_ci break; 164462306a36Sopenharmony_ci } 164562306a36Sopenharmony_ci } 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci vid_mapping_table->num_entries = i; 164862306a36Sopenharmony_ci} 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ciunion igp_info { 165162306a36Sopenharmony_ci struct _ATOM_INTEGRATED_SYSTEM_INFO info; 165262306a36Sopenharmony_ci struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2; 165362306a36Sopenharmony_ci struct _ATOM_INTEGRATED_SYSTEM_INFO_V5 info_5; 165462306a36Sopenharmony_ci struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6; 165562306a36Sopenharmony_ci}; 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_cistatic int sumo_parse_sys_info_table(struct radeon_device *rdev) 165862306a36Sopenharmony_ci{ 165962306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 166062306a36Sopenharmony_ci struct radeon_mode_info *mode_info = &rdev->mode_info; 166162306a36Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo); 166262306a36Sopenharmony_ci union igp_info *igp_info; 166362306a36Sopenharmony_ci u8 frev, crev; 166462306a36Sopenharmony_ci u16 data_offset; 166562306a36Sopenharmony_ci int i; 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci if (atom_parse_data_header(mode_info->atom_context, index, NULL, 166862306a36Sopenharmony_ci &frev, &crev, &data_offset)) { 166962306a36Sopenharmony_ci igp_info = (union igp_info *)(mode_info->atom_context->bios + 167062306a36Sopenharmony_ci data_offset); 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci if (crev != 6) { 167362306a36Sopenharmony_ci DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev); 167462306a36Sopenharmony_ci return -EINVAL; 167562306a36Sopenharmony_ci } 167662306a36Sopenharmony_ci pi->sys_info.bootup_sclk = le32_to_cpu(igp_info->info_6.ulBootUpEngineClock); 167762306a36Sopenharmony_ci pi->sys_info.min_sclk = le32_to_cpu(igp_info->info_6.ulMinEngineClock); 167862306a36Sopenharmony_ci pi->sys_info.bootup_uma_clk = le32_to_cpu(igp_info->info_6.ulBootUpUMAClock); 167962306a36Sopenharmony_ci pi->sys_info.bootup_nb_voltage_index = 168062306a36Sopenharmony_ci le16_to_cpu(igp_info->info_6.usBootUpNBVoltage); 168162306a36Sopenharmony_ci if (igp_info->info_6.ucHtcTmpLmt == 0) 168262306a36Sopenharmony_ci pi->sys_info.htc_tmp_lmt = 203; 168362306a36Sopenharmony_ci else 168462306a36Sopenharmony_ci pi->sys_info.htc_tmp_lmt = igp_info->info_6.ucHtcTmpLmt; 168562306a36Sopenharmony_ci if (igp_info->info_6.ucHtcHystLmt == 0) 168662306a36Sopenharmony_ci pi->sys_info.htc_hyst_lmt = 5; 168762306a36Sopenharmony_ci else 168862306a36Sopenharmony_ci pi->sys_info.htc_hyst_lmt = igp_info->info_6.ucHtcHystLmt; 168962306a36Sopenharmony_ci if (pi->sys_info.htc_tmp_lmt <= pi->sys_info.htc_hyst_lmt) { 169062306a36Sopenharmony_ci DRM_ERROR("The htcTmpLmt should be larger than htcHystLmt.\n"); 169162306a36Sopenharmony_ci } 169262306a36Sopenharmony_ci for (i = 0; i < NUMBER_OF_M3ARB_PARAM_SETS; i++) { 169362306a36Sopenharmony_ci pi->sys_info.csr_m3_arb_cntl_default[i] = 169462306a36Sopenharmony_ci le32_to_cpu(igp_info->info_6.ulCSR_M3_ARB_CNTL_DEFAULT[i]); 169562306a36Sopenharmony_ci pi->sys_info.csr_m3_arb_cntl_uvd[i] = 169662306a36Sopenharmony_ci le32_to_cpu(igp_info->info_6.ulCSR_M3_ARB_CNTL_UVD[i]); 169762306a36Sopenharmony_ci pi->sys_info.csr_m3_arb_cntl_fs3d[i] = 169862306a36Sopenharmony_ci le32_to_cpu(igp_info->info_6.ulCSR_M3_ARB_CNTL_FS3D[i]); 169962306a36Sopenharmony_ci } 170062306a36Sopenharmony_ci pi->sys_info.sclk_dpm_boost_margin = 170162306a36Sopenharmony_ci le32_to_cpu(igp_info->info_6.SclkDpmBoostMargin); 170262306a36Sopenharmony_ci pi->sys_info.sclk_dpm_throttle_margin = 170362306a36Sopenharmony_ci le32_to_cpu(igp_info->info_6.SclkDpmThrottleMargin); 170462306a36Sopenharmony_ci pi->sys_info.sclk_dpm_tdp_limit_pg = 170562306a36Sopenharmony_ci le16_to_cpu(igp_info->info_6.SclkDpmTdpLimitPG); 170662306a36Sopenharmony_ci pi->sys_info.gnb_tdp_limit = le16_to_cpu(igp_info->info_6.GnbTdpLimit); 170762306a36Sopenharmony_ci pi->sys_info.sclk_dpm_tdp_limit_boost = 170862306a36Sopenharmony_ci le16_to_cpu(igp_info->info_6.SclkDpmTdpLimitBoost); 170962306a36Sopenharmony_ci pi->sys_info.boost_sclk = le32_to_cpu(igp_info->info_6.ulBoostEngineCLock); 171062306a36Sopenharmony_ci pi->sys_info.boost_vid_2bit = igp_info->info_6.ulBoostVid_2bit; 171162306a36Sopenharmony_ci if (igp_info->info_6.EnableBoost) 171262306a36Sopenharmony_ci pi->sys_info.enable_boost = true; 171362306a36Sopenharmony_ci else 171462306a36Sopenharmony_ci pi->sys_info.enable_boost = false; 171562306a36Sopenharmony_ci sumo_construct_display_voltage_mapping_table(rdev, 171662306a36Sopenharmony_ci &pi->sys_info.disp_clk_voltage_mapping_table, 171762306a36Sopenharmony_ci igp_info->info_6.sDISPCLK_Voltage); 171862306a36Sopenharmony_ci sumo_construct_sclk_voltage_mapping_table(rdev, 171962306a36Sopenharmony_ci &pi->sys_info.sclk_voltage_mapping_table, 172062306a36Sopenharmony_ci igp_info->info_6.sAvail_SCLK); 172162306a36Sopenharmony_ci sumo_construct_vid_mapping_table(rdev, &pi->sys_info.vid_mapping_table, 172262306a36Sopenharmony_ci igp_info->info_6.sAvail_SCLK); 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci } 172562306a36Sopenharmony_ci return 0; 172662306a36Sopenharmony_ci} 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_cistatic void sumo_construct_boot_and_acpi_state(struct radeon_device *rdev) 172962306a36Sopenharmony_ci{ 173062306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ci pi->boot_pl.sclk = pi->sys_info.bootup_sclk; 173362306a36Sopenharmony_ci pi->boot_pl.vddc_index = pi->sys_info.bootup_nb_voltage_index; 173462306a36Sopenharmony_ci pi->boot_pl.ds_divider_index = 0; 173562306a36Sopenharmony_ci pi->boot_pl.ss_divider_index = 0; 173662306a36Sopenharmony_ci pi->boot_pl.allow_gnb_slow = 1; 173762306a36Sopenharmony_ci pi->acpi_pl = pi->boot_pl; 173862306a36Sopenharmony_ci pi->current_ps.num_levels = 1; 173962306a36Sopenharmony_ci pi->current_ps.levels[0] = pi->boot_pl; 174062306a36Sopenharmony_ci} 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ciint sumo_dpm_init(struct radeon_device *rdev) 174362306a36Sopenharmony_ci{ 174462306a36Sopenharmony_ci struct sumo_power_info *pi; 174562306a36Sopenharmony_ci u32 hw_rev = (RREG32(HW_REV) & ATI_REV_ID_MASK) >> ATI_REV_ID_SHIFT; 174662306a36Sopenharmony_ci int ret; 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci pi = kzalloc(sizeof(struct sumo_power_info), GFP_KERNEL); 174962306a36Sopenharmony_ci if (pi == NULL) 175062306a36Sopenharmony_ci return -ENOMEM; 175162306a36Sopenharmony_ci rdev->pm.dpm.priv = pi; 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci pi->driver_nbps_policy_disable = false; 175462306a36Sopenharmony_ci if ((rdev->family == CHIP_PALM) && (hw_rev < 3)) 175562306a36Sopenharmony_ci pi->disable_gfx_power_gating_in_uvd = true; 175662306a36Sopenharmony_ci else 175762306a36Sopenharmony_ci pi->disable_gfx_power_gating_in_uvd = false; 175862306a36Sopenharmony_ci pi->enable_alt_vddnb = true; 175962306a36Sopenharmony_ci pi->enable_sclk_ds = true; 176062306a36Sopenharmony_ci pi->enable_dynamic_m3_arbiter = false; 176162306a36Sopenharmony_ci pi->enable_dynamic_patch_ps = true; 176262306a36Sopenharmony_ci /* Some PALM chips don't seem to properly ungate gfx when UVD is in use; 176362306a36Sopenharmony_ci * for now just disable gfx PG. 176462306a36Sopenharmony_ci */ 176562306a36Sopenharmony_ci if (rdev->family == CHIP_PALM) 176662306a36Sopenharmony_ci pi->enable_gfx_power_gating = false; 176762306a36Sopenharmony_ci else 176862306a36Sopenharmony_ci pi->enable_gfx_power_gating = true; 176962306a36Sopenharmony_ci pi->enable_gfx_clock_gating = true; 177062306a36Sopenharmony_ci pi->enable_mg_clock_gating = true; 177162306a36Sopenharmony_ci pi->enable_auto_thermal_throttling = true; 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_ci ret = sumo_parse_sys_info_table(rdev); 177462306a36Sopenharmony_ci if (ret) 177562306a36Sopenharmony_ci return ret; 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_ci sumo_construct_boot_and_acpi_state(rdev); 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci ret = r600_get_platform_caps(rdev); 178062306a36Sopenharmony_ci if (ret) 178162306a36Sopenharmony_ci return ret; 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_ci ret = sumo_parse_power_table(rdev); 178462306a36Sopenharmony_ci if (ret) 178562306a36Sopenharmony_ci return ret; 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci pi->pasi = CYPRESS_HASI_DFLT; 178862306a36Sopenharmony_ci pi->asi = RV770_ASI_DFLT; 178962306a36Sopenharmony_ci pi->thermal_auto_throttling = pi->sys_info.htc_tmp_lmt; 179062306a36Sopenharmony_ci pi->enable_boost = pi->sys_info.enable_boost; 179162306a36Sopenharmony_ci pi->enable_dpm = true; 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci return 0; 179462306a36Sopenharmony_ci} 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_civoid sumo_dpm_print_power_state(struct radeon_device *rdev, 179762306a36Sopenharmony_ci struct radeon_ps *rps) 179862306a36Sopenharmony_ci{ 179962306a36Sopenharmony_ci int i; 180062306a36Sopenharmony_ci struct sumo_ps *ps = sumo_get_ps(rps); 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ci r600_dpm_print_class_info(rps->class, rps->class2); 180362306a36Sopenharmony_ci r600_dpm_print_cap_info(rps->caps); 180462306a36Sopenharmony_ci printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); 180562306a36Sopenharmony_ci for (i = 0; i < ps->num_levels; i++) { 180662306a36Sopenharmony_ci struct sumo_pl *pl = &ps->levels[i]; 180762306a36Sopenharmony_ci printk("\t\tpower level %d sclk: %u vddc: %u\n", 180862306a36Sopenharmony_ci i, pl->sclk, 180962306a36Sopenharmony_ci sumo_convert_voltage_index_to_value(rdev, pl->vddc_index)); 181062306a36Sopenharmony_ci } 181162306a36Sopenharmony_ci r600_dpm_print_ps_status(rdev, rps); 181262306a36Sopenharmony_ci} 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_civoid sumo_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, 181562306a36Sopenharmony_ci struct seq_file *m) 181662306a36Sopenharmony_ci{ 181762306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 181862306a36Sopenharmony_ci struct radeon_ps *rps = &pi->current_rps; 181962306a36Sopenharmony_ci struct sumo_ps *ps = sumo_get_ps(rps); 182062306a36Sopenharmony_ci struct sumo_pl *pl; 182162306a36Sopenharmony_ci u32 current_index = 182262306a36Sopenharmony_ci (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_INDEX_MASK) >> 182362306a36Sopenharmony_ci CURR_INDEX_SHIFT; 182462306a36Sopenharmony_ci 182562306a36Sopenharmony_ci if (current_index == BOOST_DPM_LEVEL) { 182662306a36Sopenharmony_ci pl = &pi->boost_pl; 182762306a36Sopenharmony_ci seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); 182862306a36Sopenharmony_ci seq_printf(m, "power level %d sclk: %u vddc: %u\n", 182962306a36Sopenharmony_ci current_index, pl->sclk, 183062306a36Sopenharmony_ci sumo_convert_voltage_index_to_value(rdev, pl->vddc_index)); 183162306a36Sopenharmony_ci } else if (current_index >= ps->num_levels) { 183262306a36Sopenharmony_ci seq_printf(m, "invalid dpm profile %d\n", current_index); 183362306a36Sopenharmony_ci } else { 183462306a36Sopenharmony_ci pl = &ps->levels[current_index]; 183562306a36Sopenharmony_ci seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); 183662306a36Sopenharmony_ci seq_printf(m, "power level %d sclk: %u vddc: %u\n", 183762306a36Sopenharmony_ci current_index, pl->sclk, 183862306a36Sopenharmony_ci sumo_convert_voltage_index_to_value(rdev, pl->vddc_index)); 183962306a36Sopenharmony_ci } 184062306a36Sopenharmony_ci} 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ciu32 sumo_dpm_get_current_sclk(struct radeon_device *rdev) 184362306a36Sopenharmony_ci{ 184462306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 184562306a36Sopenharmony_ci struct radeon_ps *rps = &pi->current_rps; 184662306a36Sopenharmony_ci struct sumo_ps *ps = sumo_get_ps(rps); 184762306a36Sopenharmony_ci struct sumo_pl *pl; 184862306a36Sopenharmony_ci u32 current_index = 184962306a36Sopenharmony_ci (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_INDEX_MASK) >> 185062306a36Sopenharmony_ci CURR_INDEX_SHIFT; 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_ci if (current_index == BOOST_DPM_LEVEL) { 185362306a36Sopenharmony_ci pl = &pi->boost_pl; 185462306a36Sopenharmony_ci return pl->sclk; 185562306a36Sopenharmony_ci } else if (current_index >= ps->num_levels) { 185662306a36Sopenharmony_ci return 0; 185762306a36Sopenharmony_ci } else { 185862306a36Sopenharmony_ci pl = &ps->levels[current_index]; 185962306a36Sopenharmony_ci return pl->sclk; 186062306a36Sopenharmony_ci } 186162306a36Sopenharmony_ci} 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_ciu32 sumo_dpm_get_current_mclk(struct radeon_device *rdev) 186462306a36Sopenharmony_ci{ 186562306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_ci return pi->sys_info.bootup_uma_clk; 186862306a36Sopenharmony_ci} 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ciu16 sumo_dpm_get_current_vddc(struct radeon_device *rdev) 187162306a36Sopenharmony_ci{ 187262306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 187362306a36Sopenharmony_ci struct radeon_ps *rps = &pi->current_rps; 187462306a36Sopenharmony_ci struct sumo_ps *ps = sumo_get_ps(rps); 187562306a36Sopenharmony_ci struct sumo_pl *pl; 187662306a36Sopenharmony_ci u32 current_index = 187762306a36Sopenharmony_ci (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_INDEX_MASK) >> 187862306a36Sopenharmony_ci CURR_INDEX_SHIFT; 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci if (current_index == BOOST_DPM_LEVEL) { 188162306a36Sopenharmony_ci pl = &pi->boost_pl; 188262306a36Sopenharmony_ci } else if (current_index >= ps->num_levels) { 188362306a36Sopenharmony_ci return 0; 188462306a36Sopenharmony_ci } else { 188562306a36Sopenharmony_ci pl = &ps->levels[current_index]; 188662306a36Sopenharmony_ci } 188762306a36Sopenharmony_ci return sumo_convert_voltage_index_to_value(rdev, pl->vddc_index); 188862306a36Sopenharmony_ci} 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_civoid sumo_dpm_fini(struct radeon_device *rdev) 189162306a36Sopenharmony_ci{ 189262306a36Sopenharmony_ci int i; 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci sumo_cleanup_asic(rdev); /* ??? */ 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_ci for (i = 0; i < rdev->pm.dpm.num_ps; i++) { 189762306a36Sopenharmony_ci kfree(rdev->pm.dpm.ps[i].ps_priv); 189862306a36Sopenharmony_ci } 189962306a36Sopenharmony_ci kfree(rdev->pm.dpm.ps); 190062306a36Sopenharmony_ci kfree(rdev->pm.dpm.priv); 190162306a36Sopenharmony_ci} 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ciu32 sumo_dpm_get_sclk(struct radeon_device *rdev, bool low) 190462306a36Sopenharmony_ci{ 190562306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 190662306a36Sopenharmony_ci struct sumo_ps *requested_state = sumo_get_ps(&pi->requested_rps); 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_ci if (low) 190962306a36Sopenharmony_ci return requested_state->levels[0].sclk; 191062306a36Sopenharmony_ci else 191162306a36Sopenharmony_ci return requested_state->levels[requested_state->num_levels - 1].sclk; 191262306a36Sopenharmony_ci} 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ciu32 sumo_dpm_get_mclk(struct radeon_device *rdev, bool low) 191562306a36Sopenharmony_ci{ 191662306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci return pi->sys_info.bootup_uma_clk; 191962306a36Sopenharmony_ci} 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_ciint sumo_dpm_force_performance_level(struct radeon_device *rdev, 192262306a36Sopenharmony_ci enum radeon_dpm_forced_level level) 192362306a36Sopenharmony_ci{ 192462306a36Sopenharmony_ci struct sumo_power_info *pi = sumo_get_pi(rdev); 192562306a36Sopenharmony_ci struct radeon_ps *rps = &pi->current_rps; 192662306a36Sopenharmony_ci struct sumo_ps *ps = sumo_get_ps(rps); 192762306a36Sopenharmony_ci int i; 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci if (ps->num_levels <= 1) 193062306a36Sopenharmony_ci return 0; 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { 193362306a36Sopenharmony_ci if (pi->enable_boost) 193462306a36Sopenharmony_ci sumo_enable_boost(rdev, rps, false); 193562306a36Sopenharmony_ci sumo_power_level_enable(rdev, ps->num_levels - 1, true); 193662306a36Sopenharmony_ci sumo_set_forced_level(rdev, ps->num_levels - 1); 193762306a36Sopenharmony_ci sumo_set_forced_mode_enabled(rdev); 193862306a36Sopenharmony_ci for (i = 0; i < ps->num_levels - 1; i++) { 193962306a36Sopenharmony_ci sumo_power_level_enable(rdev, i, false); 194062306a36Sopenharmony_ci } 194162306a36Sopenharmony_ci sumo_set_forced_mode(rdev, false); 194262306a36Sopenharmony_ci sumo_set_forced_mode_enabled(rdev); 194362306a36Sopenharmony_ci sumo_set_forced_mode(rdev, false); 194462306a36Sopenharmony_ci } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) { 194562306a36Sopenharmony_ci if (pi->enable_boost) 194662306a36Sopenharmony_ci sumo_enable_boost(rdev, rps, false); 194762306a36Sopenharmony_ci sumo_power_level_enable(rdev, 0, true); 194862306a36Sopenharmony_ci sumo_set_forced_level(rdev, 0); 194962306a36Sopenharmony_ci sumo_set_forced_mode_enabled(rdev); 195062306a36Sopenharmony_ci for (i = 1; i < ps->num_levels; i++) { 195162306a36Sopenharmony_ci sumo_power_level_enable(rdev, i, false); 195262306a36Sopenharmony_ci } 195362306a36Sopenharmony_ci sumo_set_forced_mode(rdev, false); 195462306a36Sopenharmony_ci sumo_set_forced_mode_enabled(rdev); 195562306a36Sopenharmony_ci sumo_set_forced_mode(rdev, false); 195662306a36Sopenharmony_ci } else { 195762306a36Sopenharmony_ci for (i = 0; i < ps->num_levels; i++) { 195862306a36Sopenharmony_ci sumo_power_level_enable(rdev, i, true); 195962306a36Sopenharmony_ci } 196062306a36Sopenharmony_ci if (pi->enable_boost) 196162306a36Sopenharmony_ci sumo_enable_boost(rdev, rps, true); 196262306a36Sopenharmony_ci } 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci rdev->pm.dpm.forced_level = level; 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_ci return 0; 196762306a36Sopenharmony_ci} 1968