162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright 2011 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 * Authors: Alex Deucher 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include "radeon.h" 2662306a36Sopenharmony_ci#include "radeon_asic.h" 2762306a36Sopenharmony_ci#include "rv770.h" 2862306a36Sopenharmony_ci#include "rv770d.h" 2962306a36Sopenharmony_ci#include "r600_dpm.h" 3062306a36Sopenharmony_ci#include "rv770_dpm.h" 3162306a36Sopenharmony_ci#include "cypress_dpm.h" 3262306a36Sopenharmony_ci#include "atom.h" 3362306a36Sopenharmony_ci#include "evergreen.h" 3462306a36Sopenharmony_ci#include <linux/seq_file.h> 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define MC_CG_ARB_FREQ_F0 0x0a 3762306a36Sopenharmony_ci#define MC_CG_ARB_FREQ_F1 0x0b 3862306a36Sopenharmony_ci#define MC_CG_ARB_FREQ_F2 0x0c 3962306a36Sopenharmony_ci#define MC_CG_ARB_FREQ_F3 0x0d 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define MC_CG_SEQ_DRAMCONF_S0 0x05 4262306a36Sopenharmony_ci#define MC_CG_SEQ_DRAMCONF_S1 0x06 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define PCIE_BUS_CLK 10000 4562306a36Sopenharmony_ci#define TCLK (PCIE_BUS_CLK / 10) 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define SMC_RAM_END 0xC000 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistruct rv7xx_ps *rv770_get_ps(struct radeon_ps *rps) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci struct rv7xx_ps *ps = rps->ps_priv; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci return ps; 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistruct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci struct rv7xx_power_info *pi = rdev->pm.dpm.priv; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci return pi; 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistruct evergreen_power_info *evergreen_get_pi(struct radeon_device *rdev) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci struct evergreen_power_info *pi = rdev->pm.dpm.priv; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci return pi; 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic void rv770_enable_bif_dynamic_pcie_gen2(struct radeon_device *rdev, 7162306a36Sopenharmony_ci bool enable) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 7462306a36Sopenharmony_ci u32 tmp; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); 7762306a36Sopenharmony_ci if (enable) { 7862306a36Sopenharmony_ci tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK; 7962306a36Sopenharmony_ci tmp |= LC_HW_VOLTAGE_IF_CONTROL(1); 8062306a36Sopenharmony_ci tmp |= LC_GEN2_EN_STRAP; 8162306a36Sopenharmony_ci } else { 8262306a36Sopenharmony_ci if (!pi->boot_in_gen2) { 8362306a36Sopenharmony_ci tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK; 8462306a36Sopenharmony_ci tmp &= ~LC_GEN2_EN_STRAP; 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) || 8862306a36Sopenharmony_ci (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2)) 8962306a36Sopenharmony_ci WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic void rv770_enable_l0s(struct radeon_device *rdev) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci u32 tmp; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL) & ~LC_L0S_INACTIVITY_MASK; 9862306a36Sopenharmony_ci tmp |= LC_L0S_INACTIVITY(3); 9962306a36Sopenharmony_ci WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp); 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic void rv770_enable_l1(struct radeon_device *rdev) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci u32 tmp; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL); 10762306a36Sopenharmony_ci tmp &= ~LC_L1_INACTIVITY_MASK; 10862306a36Sopenharmony_ci tmp |= LC_L1_INACTIVITY(4); 10962306a36Sopenharmony_ci tmp &= ~LC_PMI_TO_L1_DIS; 11062306a36Sopenharmony_ci tmp &= ~LC_ASPM_TO_L1_DIS; 11162306a36Sopenharmony_ci WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp); 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic void rv770_enable_pll_sleep_in_l1(struct radeon_device *rdev) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci u32 tmp; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL) & ~LC_L1_INACTIVITY_MASK; 11962306a36Sopenharmony_ci tmp |= LC_L1_INACTIVITY(8); 12062306a36Sopenharmony_ci WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci /* NOTE, this is a PCIE indirect reg, not PCIE PORT */ 12362306a36Sopenharmony_ci tmp = RREG32_PCIE(PCIE_P_CNTL); 12462306a36Sopenharmony_ci tmp |= P_PLL_PWRDN_IN_L1L23; 12562306a36Sopenharmony_ci tmp &= ~P_PLL_BUF_PDNB; 12662306a36Sopenharmony_ci tmp &= ~P_PLL_PDNB; 12762306a36Sopenharmony_ci tmp |= P_ALLOW_PRX_FRONTEND_SHUTOFF; 12862306a36Sopenharmony_ci WREG32_PCIE(PCIE_P_CNTL, tmp); 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic void rv770_gfx_clock_gating_enable(struct radeon_device *rdev, 13262306a36Sopenharmony_ci bool enable) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci if (enable) 13562306a36Sopenharmony_ci WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN); 13662306a36Sopenharmony_ci else { 13762306a36Sopenharmony_ci WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN); 13862306a36Sopenharmony_ci WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON); 13962306a36Sopenharmony_ci WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON); 14062306a36Sopenharmony_ci RREG32(GB_TILING_CONFIG); 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic void rv770_mg_clock_gating_enable(struct radeon_device *rdev, 14562306a36Sopenharmony_ci bool enable) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci if (enable) { 15062306a36Sopenharmony_ci u32 mgcg_cgtt_local0; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci if (rdev->family == CHIP_RV770) 15362306a36Sopenharmony_ci mgcg_cgtt_local0 = RV770_MGCGTTLOCAL0_DFLT; 15462306a36Sopenharmony_ci else 15562306a36Sopenharmony_ci mgcg_cgtt_local0 = RV7XX_MGCGTTLOCAL0_DFLT; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci WREG32(CG_CGTT_LOCAL_0, mgcg_cgtt_local0); 15862306a36Sopenharmony_ci WREG32(CG_CGTT_LOCAL_1, (RV770_MGCGTTLOCAL1_DFLT & 0xFFFFCFFF)); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci if (pi->mgcgtssm) 16162306a36Sopenharmony_ci WREG32(CGTS_SM_CTRL_REG, RV770_MGCGCGTSSMCTRL_DFLT); 16262306a36Sopenharmony_ci } else { 16362306a36Sopenharmony_ci WREG32(CG_CGTT_LOCAL_0, 0xFFFFFFFF); 16462306a36Sopenharmony_ci WREG32(CG_CGTT_LOCAL_1, 0xFFFFCFFF); 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_civoid rv770_restore_cgcg(struct radeon_device *rdev) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci bool dpm_en = false, cg_en = false; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (RREG32(GENERAL_PWRMGT) & GLOBAL_PWRMGT_EN) 17362306a36Sopenharmony_ci dpm_en = true; 17462306a36Sopenharmony_ci if (RREG32(SCLK_PWRMGT_CNTL) & DYN_GFX_CLK_OFF_EN) 17562306a36Sopenharmony_ci cg_en = true; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci if (dpm_en && !cg_en) 17862306a36Sopenharmony_ci WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN); 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic void rv770_start_dpm(struct radeon_device *rdev) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci WREG32_P(SCLK_PWRMGT_CNTL, 0, ~SCLK_PWRMGT_OFF); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci WREG32_P(MCLK_PWRMGT_CNTL, 0, ~MPLL_PWRMGT_OFF); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN); 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_civoid rv770_stop_dpm(struct radeon_device *rdev) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci PPSMC_Result result; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_TwoLevelsDisabled); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (result != PPSMC_Result_OK) 19762306a36Sopenharmony_ci DRM_DEBUG("Could not force DPM to low.\n"); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci WREG32_P(SCLK_PWRMGT_CNTL, SCLK_PWRMGT_OFF, ~SCLK_PWRMGT_OFF); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci WREG32_P(MCLK_PWRMGT_CNTL, MPLL_PWRMGT_OFF, ~MPLL_PWRMGT_OFF); 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cibool rv770_dpm_enabled(struct radeon_device *rdev) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci if (RREG32(GENERAL_PWRMGT) & GLOBAL_PWRMGT_EN) 20962306a36Sopenharmony_ci return true; 21062306a36Sopenharmony_ci else 21162306a36Sopenharmony_ci return false; 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_civoid rv770_enable_thermal_protection(struct radeon_device *rdev, 21562306a36Sopenharmony_ci bool enable) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci if (enable) 21862306a36Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS); 21962306a36Sopenharmony_ci else 22062306a36Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS); 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_civoid rv770_enable_acpi_pm(struct radeon_device *rdev) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, STATIC_PM_EN, ~STATIC_PM_EN); 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ciu8 rv770_get_seq_value(struct radeon_device *rdev, 22962306a36Sopenharmony_ci struct rv7xx_pl *pl) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci return (pl->flags & ATOM_PPLIB_R600_FLAGS_LOWPOWER) ? 23262306a36Sopenharmony_ci MC_CG_SEQ_DRAMCONF_S0 : MC_CG_SEQ_DRAMCONF_S1; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci#if 0 23662306a36Sopenharmony_ciint rv770_read_smc_soft_register(struct radeon_device *rdev, 23762306a36Sopenharmony_ci u16 reg_offset, u32 *value) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci return rv770_read_smc_sram_dword(rdev, 24262306a36Sopenharmony_ci pi->soft_regs_start + reg_offset, 24362306a36Sopenharmony_ci value, pi->sram_end); 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci#endif 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ciint rv770_write_smc_soft_register(struct radeon_device *rdev, 24862306a36Sopenharmony_ci u16 reg_offset, u32 value) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci return rv770_write_smc_sram_dword(rdev, 25362306a36Sopenharmony_ci pi->soft_regs_start + reg_offset, 25462306a36Sopenharmony_ci value, pi->sram_end); 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ciint rv770_populate_smc_t(struct radeon_device *rdev, 25862306a36Sopenharmony_ci struct radeon_ps *radeon_state, 25962306a36Sopenharmony_ci RV770_SMC_SWSTATE *smc_state) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci struct rv7xx_ps *state = rv770_get_ps(radeon_state); 26262306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 26362306a36Sopenharmony_ci int i; 26462306a36Sopenharmony_ci int a_n; 26562306a36Sopenharmony_ci int a_d; 26662306a36Sopenharmony_ci u8 l[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE]; 26762306a36Sopenharmony_ci u8 r[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE]; 26862306a36Sopenharmony_ci u32 a_t; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci l[0] = 0; 27162306a36Sopenharmony_ci r[2] = 100; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci a_n = (int)state->medium.sclk * pi->lmp + 27462306a36Sopenharmony_ci (int)state->low.sclk * (R600_AH_DFLT - pi->rlp); 27562306a36Sopenharmony_ci a_d = (int)state->low.sclk * (100 - (int)pi->rlp) + 27662306a36Sopenharmony_ci (int)state->medium.sclk * pi->lmp; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci l[1] = (u8)(pi->lmp - (int)pi->lmp * a_n / a_d); 27962306a36Sopenharmony_ci r[0] = (u8)(pi->rlp + (100 - (int)pi->rlp) * a_n / a_d); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci a_n = (int)state->high.sclk * pi->lhp + (int)state->medium.sclk * 28262306a36Sopenharmony_ci (R600_AH_DFLT - pi->rmp); 28362306a36Sopenharmony_ci a_d = (int)state->medium.sclk * (100 - (int)pi->rmp) + 28462306a36Sopenharmony_ci (int)state->high.sclk * pi->lhp; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci l[2] = (u8)(pi->lhp - (int)pi->lhp * a_n / a_d); 28762306a36Sopenharmony_ci r[1] = (u8)(pi->rmp + (100 - (int)pi->rmp) * a_n / a_d); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci for (i = 0; i < (RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1); i++) { 29062306a36Sopenharmony_ci a_t = CG_R(r[i] * pi->bsp / 200) | CG_L(l[i] * pi->bsp / 200); 29162306a36Sopenharmony_ci smc_state->levels[i].aT = cpu_to_be32(a_t); 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci a_t = CG_R(r[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1] * pi->pbsp / 200) | 29562306a36Sopenharmony_ci CG_L(l[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1] * pi->pbsp / 200); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci smc_state->levels[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1].aT = 29862306a36Sopenharmony_ci cpu_to_be32(a_t); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci return 0; 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ciint rv770_populate_smc_sp(struct radeon_device *rdev, 30462306a36Sopenharmony_ci struct radeon_ps *radeon_state, 30562306a36Sopenharmony_ci RV770_SMC_SWSTATE *smc_state) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 30862306a36Sopenharmony_ci int i; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci for (i = 0; i < (RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1); i++) 31162306a36Sopenharmony_ci smc_state->levels[i].bSP = cpu_to_be32(pi->dsp); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci smc_state->levels[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1].bSP = 31462306a36Sopenharmony_ci cpu_to_be32(pi->psp); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci return 0; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic void rv770_calculate_fractional_mpll_feedback_divider(u32 memory_clock, 32062306a36Sopenharmony_ci u32 reference_clock, 32162306a36Sopenharmony_ci bool gddr5, 32262306a36Sopenharmony_ci struct atom_clock_dividers *dividers, 32362306a36Sopenharmony_ci u32 *clkf, 32462306a36Sopenharmony_ci u32 *clkfrac) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci u32 post_divider, reference_divider, feedback_divider8; 32762306a36Sopenharmony_ci u32 fyclk; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci if (gddr5) 33062306a36Sopenharmony_ci fyclk = (memory_clock * 8) / 2; 33162306a36Sopenharmony_ci else 33262306a36Sopenharmony_ci fyclk = (memory_clock * 4) / 2; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci post_divider = dividers->post_div; 33562306a36Sopenharmony_ci reference_divider = dividers->ref_div; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci feedback_divider8 = 33862306a36Sopenharmony_ci (8 * fyclk * reference_divider * post_divider) / reference_clock; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci *clkf = feedback_divider8 / 8; 34162306a36Sopenharmony_ci *clkfrac = feedback_divider8 % 8; 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic int rv770_encode_yclk_post_div(u32 postdiv, u32 *encoded_postdiv) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci int ret = 0; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci switch (postdiv) { 34962306a36Sopenharmony_ci case 1: 35062306a36Sopenharmony_ci *encoded_postdiv = 0; 35162306a36Sopenharmony_ci break; 35262306a36Sopenharmony_ci case 2: 35362306a36Sopenharmony_ci *encoded_postdiv = 1; 35462306a36Sopenharmony_ci break; 35562306a36Sopenharmony_ci case 4: 35662306a36Sopenharmony_ci *encoded_postdiv = 2; 35762306a36Sopenharmony_ci break; 35862306a36Sopenharmony_ci case 8: 35962306a36Sopenharmony_ci *encoded_postdiv = 3; 36062306a36Sopenharmony_ci break; 36162306a36Sopenharmony_ci case 16: 36262306a36Sopenharmony_ci *encoded_postdiv = 4; 36362306a36Sopenharmony_ci break; 36462306a36Sopenharmony_ci default: 36562306a36Sopenharmony_ci ret = -EINVAL; 36662306a36Sopenharmony_ci break; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci return ret; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ciu32 rv770_map_clkf_to_ibias(struct radeon_device *rdev, u32 clkf) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci if (clkf <= 0x10) 37562306a36Sopenharmony_ci return 0x4B; 37662306a36Sopenharmony_ci if (clkf <= 0x19) 37762306a36Sopenharmony_ci return 0x5B; 37862306a36Sopenharmony_ci if (clkf <= 0x21) 37962306a36Sopenharmony_ci return 0x2B; 38062306a36Sopenharmony_ci if (clkf <= 0x27) 38162306a36Sopenharmony_ci return 0x6C; 38262306a36Sopenharmony_ci if (clkf <= 0x31) 38362306a36Sopenharmony_ci return 0x9D; 38462306a36Sopenharmony_ci return 0xC6; 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic int rv770_populate_mclk_value(struct radeon_device *rdev, 38862306a36Sopenharmony_ci u32 engine_clock, u32 memory_clock, 38962306a36Sopenharmony_ci RV7XX_SMC_MCLK_VALUE *mclk) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 39262306a36Sopenharmony_ci u8 encoded_reference_dividers[] = { 0, 16, 17, 20, 21 }; 39362306a36Sopenharmony_ci u32 mpll_ad_func_cntl = 39462306a36Sopenharmony_ci pi->clk_regs.rv770.mpll_ad_func_cntl; 39562306a36Sopenharmony_ci u32 mpll_ad_func_cntl_2 = 39662306a36Sopenharmony_ci pi->clk_regs.rv770.mpll_ad_func_cntl_2; 39762306a36Sopenharmony_ci u32 mpll_dq_func_cntl = 39862306a36Sopenharmony_ci pi->clk_regs.rv770.mpll_dq_func_cntl; 39962306a36Sopenharmony_ci u32 mpll_dq_func_cntl_2 = 40062306a36Sopenharmony_ci pi->clk_regs.rv770.mpll_dq_func_cntl_2; 40162306a36Sopenharmony_ci u32 mclk_pwrmgt_cntl = 40262306a36Sopenharmony_ci pi->clk_regs.rv770.mclk_pwrmgt_cntl; 40362306a36Sopenharmony_ci u32 dll_cntl = pi->clk_regs.rv770.dll_cntl; 40462306a36Sopenharmony_ci struct atom_clock_dividers dividers; 40562306a36Sopenharmony_ci u32 reference_clock = rdev->clock.mpll.reference_freq; 40662306a36Sopenharmony_ci u32 clkf, clkfrac; 40762306a36Sopenharmony_ci u32 postdiv_yclk; 40862306a36Sopenharmony_ci u32 ibias; 40962306a36Sopenharmony_ci int ret; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM, 41262306a36Sopenharmony_ci memory_clock, false, ÷rs); 41362306a36Sopenharmony_ci if (ret) 41462306a36Sopenharmony_ci return ret; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci if ((dividers.ref_div < 1) || (dividers.ref_div > 5)) 41762306a36Sopenharmony_ci return -EINVAL; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci rv770_calculate_fractional_mpll_feedback_divider(memory_clock, reference_clock, 42062306a36Sopenharmony_ci pi->mem_gddr5, 42162306a36Sopenharmony_ci ÷rs, &clkf, &clkfrac); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci ret = rv770_encode_yclk_post_div(dividers.post_div, &postdiv_yclk); 42462306a36Sopenharmony_ci if (ret) 42562306a36Sopenharmony_ci return ret; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci ibias = rv770_map_clkf_to_ibias(rdev, clkf); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci mpll_ad_func_cntl &= ~(CLKR_MASK | 43062306a36Sopenharmony_ci YCLK_POST_DIV_MASK | 43162306a36Sopenharmony_ci CLKF_MASK | 43262306a36Sopenharmony_ci CLKFRAC_MASK | 43362306a36Sopenharmony_ci IBIAS_MASK); 43462306a36Sopenharmony_ci mpll_ad_func_cntl |= CLKR(encoded_reference_dividers[dividers.ref_div - 1]); 43562306a36Sopenharmony_ci mpll_ad_func_cntl |= YCLK_POST_DIV(postdiv_yclk); 43662306a36Sopenharmony_ci mpll_ad_func_cntl |= CLKF(clkf); 43762306a36Sopenharmony_ci mpll_ad_func_cntl |= CLKFRAC(clkfrac); 43862306a36Sopenharmony_ci mpll_ad_func_cntl |= IBIAS(ibias); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (dividers.vco_mode) 44162306a36Sopenharmony_ci mpll_ad_func_cntl_2 |= VCO_MODE; 44262306a36Sopenharmony_ci else 44362306a36Sopenharmony_ci mpll_ad_func_cntl_2 &= ~VCO_MODE; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci if (pi->mem_gddr5) { 44662306a36Sopenharmony_ci rv770_calculate_fractional_mpll_feedback_divider(memory_clock, 44762306a36Sopenharmony_ci reference_clock, 44862306a36Sopenharmony_ci pi->mem_gddr5, 44962306a36Sopenharmony_ci ÷rs, &clkf, &clkfrac); 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci ibias = rv770_map_clkf_to_ibias(rdev, clkf); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci ret = rv770_encode_yclk_post_div(dividers.post_div, &postdiv_yclk); 45462306a36Sopenharmony_ci if (ret) 45562306a36Sopenharmony_ci return ret; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci mpll_dq_func_cntl &= ~(CLKR_MASK | 45862306a36Sopenharmony_ci YCLK_POST_DIV_MASK | 45962306a36Sopenharmony_ci CLKF_MASK | 46062306a36Sopenharmony_ci CLKFRAC_MASK | 46162306a36Sopenharmony_ci IBIAS_MASK); 46262306a36Sopenharmony_ci mpll_dq_func_cntl |= CLKR(encoded_reference_dividers[dividers.ref_div - 1]); 46362306a36Sopenharmony_ci mpll_dq_func_cntl |= YCLK_POST_DIV(postdiv_yclk); 46462306a36Sopenharmony_ci mpll_dq_func_cntl |= CLKF(clkf); 46562306a36Sopenharmony_ci mpll_dq_func_cntl |= CLKFRAC(clkfrac); 46662306a36Sopenharmony_ci mpll_dq_func_cntl |= IBIAS(ibias); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci if (dividers.vco_mode) 46962306a36Sopenharmony_ci mpll_dq_func_cntl_2 |= VCO_MODE; 47062306a36Sopenharmony_ci else 47162306a36Sopenharmony_ci mpll_dq_func_cntl_2 &= ~VCO_MODE; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci mclk->mclk770.mclk_value = cpu_to_be32(memory_clock); 47562306a36Sopenharmony_ci mclk->mclk770.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl); 47662306a36Sopenharmony_ci mclk->mclk770.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2); 47762306a36Sopenharmony_ci mclk->mclk770.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl); 47862306a36Sopenharmony_ci mclk->mclk770.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2); 47962306a36Sopenharmony_ci mclk->mclk770.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl); 48062306a36Sopenharmony_ci mclk->mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci return 0; 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_cistatic int rv770_populate_sclk_value(struct radeon_device *rdev, 48662306a36Sopenharmony_ci u32 engine_clock, 48762306a36Sopenharmony_ci RV770_SMC_SCLK_VALUE *sclk) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 49062306a36Sopenharmony_ci struct atom_clock_dividers dividers; 49162306a36Sopenharmony_ci u32 spll_func_cntl = 49262306a36Sopenharmony_ci pi->clk_regs.rv770.cg_spll_func_cntl; 49362306a36Sopenharmony_ci u32 spll_func_cntl_2 = 49462306a36Sopenharmony_ci pi->clk_regs.rv770.cg_spll_func_cntl_2; 49562306a36Sopenharmony_ci u32 spll_func_cntl_3 = 49662306a36Sopenharmony_ci pi->clk_regs.rv770.cg_spll_func_cntl_3; 49762306a36Sopenharmony_ci u32 cg_spll_spread_spectrum = 49862306a36Sopenharmony_ci pi->clk_regs.rv770.cg_spll_spread_spectrum; 49962306a36Sopenharmony_ci u32 cg_spll_spread_spectrum_2 = 50062306a36Sopenharmony_ci pi->clk_regs.rv770.cg_spll_spread_spectrum_2; 50162306a36Sopenharmony_ci u64 tmp; 50262306a36Sopenharmony_ci u32 reference_clock = rdev->clock.spll.reference_freq; 50362306a36Sopenharmony_ci u32 reference_divider, post_divider; 50462306a36Sopenharmony_ci u32 fbdiv; 50562306a36Sopenharmony_ci int ret; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, 50862306a36Sopenharmony_ci engine_clock, false, ÷rs); 50962306a36Sopenharmony_ci if (ret) 51062306a36Sopenharmony_ci return ret; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci reference_divider = 1 + dividers.ref_div; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci if (dividers.enable_post_div) 51562306a36Sopenharmony_ci post_divider = (0x0f & (dividers.post_div >> 4)) + (0x0f & dividers.post_div) + 2; 51662306a36Sopenharmony_ci else 51762306a36Sopenharmony_ci post_divider = 1; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci tmp = (u64) engine_clock * reference_divider * post_divider * 16384; 52062306a36Sopenharmony_ci do_div(tmp, reference_clock); 52162306a36Sopenharmony_ci fbdiv = (u32) tmp; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci if (dividers.enable_post_div) 52462306a36Sopenharmony_ci spll_func_cntl |= SPLL_DIVEN; 52562306a36Sopenharmony_ci else 52662306a36Sopenharmony_ci spll_func_cntl &= ~SPLL_DIVEN; 52762306a36Sopenharmony_ci spll_func_cntl &= ~(SPLL_HILEN_MASK | SPLL_LOLEN_MASK | SPLL_REF_DIV_MASK); 52862306a36Sopenharmony_ci spll_func_cntl |= SPLL_REF_DIV(dividers.ref_div); 52962306a36Sopenharmony_ci spll_func_cntl |= SPLL_HILEN((dividers.post_div >> 4) & 0xf); 53062306a36Sopenharmony_ci spll_func_cntl |= SPLL_LOLEN(dividers.post_div & 0xf); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK; 53362306a36Sopenharmony_ci spll_func_cntl_2 |= SCLK_MUX_SEL(2); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci spll_func_cntl_3 &= ~SPLL_FB_DIV_MASK; 53662306a36Sopenharmony_ci spll_func_cntl_3 |= SPLL_FB_DIV(fbdiv); 53762306a36Sopenharmony_ci spll_func_cntl_3 |= SPLL_DITHEN; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci if (pi->sclk_ss) { 54062306a36Sopenharmony_ci struct radeon_atom_ss ss; 54162306a36Sopenharmony_ci u32 vco_freq = engine_clock * post_divider; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci if (radeon_atombios_get_asic_ss_info(rdev, &ss, 54462306a36Sopenharmony_ci ASIC_INTERNAL_ENGINE_SS, vco_freq)) { 54562306a36Sopenharmony_ci u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate); 54662306a36Sopenharmony_ci u32 clk_v = ss.percentage * fbdiv / (clk_s * 10000); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci cg_spll_spread_spectrum &= ~CLKS_MASK; 54962306a36Sopenharmony_ci cg_spll_spread_spectrum |= CLKS(clk_s); 55062306a36Sopenharmony_ci cg_spll_spread_spectrum |= SSEN; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci cg_spll_spread_spectrum_2 &= ~CLKV_MASK; 55362306a36Sopenharmony_ci cg_spll_spread_spectrum_2 |= CLKV(clk_v); 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci sclk->sclk_value = cpu_to_be32(engine_clock); 55862306a36Sopenharmony_ci sclk->vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl); 55962306a36Sopenharmony_ci sclk->vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2); 56062306a36Sopenharmony_ci sclk->vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3); 56162306a36Sopenharmony_ci sclk->vCG_SPLL_SPREAD_SPECTRUM = cpu_to_be32(cg_spll_spread_spectrum); 56262306a36Sopenharmony_ci sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cpu_to_be32(cg_spll_spread_spectrum_2); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci return 0; 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ciint rv770_populate_vddc_value(struct radeon_device *rdev, u16 vddc, 56862306a36Sopenharmony_ci RV770_SMC_VOLTAGE_VALUE *voltage) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 57162306a36Sopenharmony_ci int i; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (!pi->voltage_control) { 57462306a36Sopenharmony_ci voltage->index = 0; 57562306a36Sopenharmony_ci voltage->value = 0; 57662306a36Sopenharmony_ci return 0; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci for (i = 0; i < pi->valid_vddc_entries; i++) { 58062306a36Sopenharmony_ci if (vddc <= pi->vddc_table[i].vddc) { 58162306a36Sopenharmony_ci voltage->index = pi->vddc_table[i].vddc_index; 58262306a36Sopenharmony_ci voltage->value = cpu_to_be16(vddc); 58362306a36Sopenharmony_ci break; 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci if (i == pi->valid_vddc_entries) 58862306a36Sopenharmony_ci return -EINVAL; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci return 0; 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ciint rv770_populate_mvdd_value(struct radeon_device *rdev, u32 mclk, 59462306a36Sopenharmony_ci RV770_SMC_VOLTAGE_VALUE *voltage) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci if (!pi->mvdd_control) { 59962306a36Sopenharmony_ci voltage->index = MVDD_HIGH_INDEX; 60062306a36Sopenharmony_ci voltage->value = cpu_to_be16(MVDD_HIGH_VALUE); 60162306a36Sopenharmony_ci return 0; 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (mclk <= pi->mvdd_split_frequency) { 60562306a36Sopenharmony_ci voltage->index = MVDD_LOW_INDEX; 60662306a36Sopenharmony_ci voltage->value = cpu_to_be16(MVDD_LOW_VALUE); 60762306a36Sopenharmony_ci } else { 60862306a36Sopenharmony_ci voltage->index = MVDD_HIGH_INDEX; 60962306a36Sopenharmony_ci voltage->value = cpu_to_be16(MVDD_HIGH_VALUE); 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci return 0; 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_cistatic int rv770_convert_power_level_to_smc(struct radeon_device *rdev, 61662306a36Sopenharmony_ci struct rv7xx_pl *pl, 61762306a36Sopenharmony_ci RV770_SMC_HW_PERFORMANCE_LEVEL *level, 61862306a36Sopenharmony_ci u8 watermark_level) 61962306a36Sopenharmony_ci{ 62062306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 62162306a36Sopenharmony_ci int ret; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci level->gen2PCIE = pi->pcie_gen2 ? 62462306a36Sopenharmony_ci ((pl->flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? 1 : 0) : 0; 62562306a36Sopenharmony_ci level->gen2XSP = (pl->flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? 1 : 0; 62662306a36Sopenharmony_ci level->backbias = (pl->flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? 1 : 0; 62762306a36Sopenharmony_ci level->displayWatermark = watermark_level; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci if (rdev->family == CHIP_RV740) 63062306a36Sopenharmony_ci ret = rv740_populate_sclk_value(rdev, pl->sclk, 63162306a36Sopenharmony_ci &level->sclk); 63262306a36Sopenharmony_ci else if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710)) 63362306a36Sopenharmony_ci ret = rv730_populate_sclk_value(rdev, pl->sclk, 63462306a36Sopenharmony_ci &level->sclk); 63562306a36Sopenharmony_ci else 63662306a36Sopenharmony_ci ret = rv770_populate_sclk_value(rdev, pl->sclk, 63762306a36Sopenharmony_ci &level->sclk); 63862306a36Sopenharmony_ci if (ret) 63962306a36Sopenharmony_ci return ret; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci if (rdev->family == CHIP_RV740) { 64262306a36Sopenharmony_ci if (pi->mem_gddr5) { 64362306a36Sopenharmony_ci if (pl->mclk <= pi->mclk_strobe_mode_threshold) 64462306a36Sopenharmony_ci level->strobeMode = 64562306a36Sopenharmony_ci rv740_get_mclk_frequency_ratio(pl->mclk) | 0x10; 64662306a36Sopenharmony_ci else 64762306a36Sopenharmony_ci level->strobeMode = 0; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci if (pl->mclk > pi->mclk_edc_enable_threshold) 65062306a36Sopenharmony_ci level->mcFlags = SMC_MC_EDC_RD_FLAG | SMC_MC_EDC_WR_FLAG; 65162306a36Sopenharmony_ci else 65262306a36Sopenharmony_ci level->mcFlags = 0; 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci ret = rv740_populate_mclk_value(rdev, pl->sclk, 65562306a36Sopenharmony_ci pl->mclk, &level->mclk); 65662306a36Sopenharmony_ci } else if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710)) 65762306a36Sopenharmony_ci ret = rv730_populate_mclk_value(rdev, pl->sclk, 65862306a36Sopenharmony_ci pl->mclk, &level->mclk); 65962306a36Sopenharmony_ci else 66062306a36Sopenharmony_ci ret = rv770_populate_mclk_value(rdev, pl->sclk, 66162306a36Sopenharmony_ci pl->mclk, &level->mclk); 66262306a36Sopenharmony_ci if (ret) 66362306a36Sopenharmony_ci return ret; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci ret = rv770_populate_vddc_value(rdev, pl->vddc, 66662306a36Sopenharmony_ci &level->vddc); 66762306a36Sopenharmony_ci if (ret) 66862306a36Sopenharmony_ci return ret; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci ret = rv770_populate_mvdd_value(rdev, pl->mclk, &level->mvdd); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci return ret; 67362306a36Sopenharmony_ci} 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_cistatic int rv770_convert_power_state_to_smc(struct radeon_device *rdev, 67662306a36Sopenharmony_ci struct radeon_ps *radeon_state, 67762306a36Sopenharmony_ci RV770_SMC_SWSTATE *smc_state) 67862306a36Sopenharmony_ci{ 67962306a36Sopenharmony_ci struct rv7xx_ps *state = rv770_get_ps(radeon_state); 68062306a36Sopenharmony_ci int ret; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci if (!(radeon_state->caps & ATOM_PPLIB_DISALLOW_ON_DC)) 68362306a36Sopenharmony_ci smc_state->flags |= PPSMC_SWSTATE_FLAG_DC; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci ret = rv770_convert_power_level_to_smc(rdev, 68662306a36Sopenharmony_ci &state->low, 68762306a36Sopenharmony_ci &smc_state->levels[0], 68862306a36Sopenharmony_ci PPSMC_DISPLAY_WATERMARK_LOW); 68962306a36Sopenharmony_ci if (ret) 69062306a36Sopenharmony_ci return ret; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci ret = rv770_convert_power_level_to_smc(rdev, 69362306a36Sopenharmony_ci &state->medium, 69462306a36Sopenharmony_ci &smc_state->levels[1], 69562306a36Sopenharmony_ci PPSMC_DISPLAY_WATERMARK_LOW); 69662306a36Sopenharmony_ci if (ret) 69762306a36Sopenharmony_ci return ret; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci ret = rv770_convert_power_level_to_smc(rdev, 70062306a36Sopenharmony_ci &state->high, 70162306a36Sopenharmony_ci &smc_state->levels[2], 70262306a36Sopenharmony_ci PPSMC_DISPLAY_WATERMARK_HIGH); 70362306a36Sopenharmony_ci if (ret) 70462306a36Sopenharmony_ci return ret; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci smc_state->levels[0].arbValue = MC_CG_ARB_FREQ_F1; 70762306a36Sopenharmony_ci smc_state->levels[1].arbValue = MC_CG_ARB_FREQ_F2; 70862306a36Sopenharmony_ci smc_state->levels[2].arbValue = MC_CG_ARB_FREQ_F3; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci smc_state->levels[0].seqValue = rv770_get_seq_value(rdev, 71162306a36Sopenharmony_ci &state->low); 71262306a36Sopenharmony_ci smc_state->levels[1].seqValue = rv770_get_seq_value(rdev, 71362306a36Sopenharmony_ci &state->medium); 71462306a36Sopenharmony_ci smc_state->levels[2].seqValue = rv770_get_seq_value(rdev, 71562306a36Sopenharmony_ci &state->high); 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci rv770_populate_smc_sp(rdev, radeon_state, smc_state); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci return rv770_populate_smc_t(rdev, radeon_state, smc_state); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci} 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ciu32 rv770_calculate_memory_refresh_rate(struct radeon_device *rdev, 72462306a36Sopenharmony_ci u32 engine_clock) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci u32 dram_rows; 72762306a36Sopenharmony_ci u32 dram_refresh_rate; 72862306a36Sopenharmony_ci u32 mc_arb_rfsh_rate; 72962306a36Sopenharmony_ci u32 tmp; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci tmp = (RREG32(MC_ARB_RAMCFG) & NOOFROWS_MASK) >> NOOFROWS_SHIFT; 73262306a36Sopenharmony_ci dram_rows = 1 << (tmp + 10); 73362306a36Sopenharmony_ci tmp = RREG32(MC_SEQ_MISC0) & 3; 73462306a36Sopenharmony_ci dram_refresh_rate = 1 << (tmp + 3); 73562306a36Sopenharmony_ci mc_arb_rfsh_rate = ((engine_clock * 10) * dram_refresh_rate / dram_rows - 32) / 64; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci return mc_arb_rfsh_rate; 73862306a36Sopenharmony_ci} 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_cistatic void rv770_program_memory_timing_parameters(struct radeon_device *rdev, 74162306a36Sopenharmony_ci struct radeon_ps *radeon_state) 74262306a36Sopenharmony_ci{ 74362306a36Sopenharmony_ci struct rv7xx_ps *state = rv770_get_ps(radeon_state); 74462306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 74562306a36Sopenharmony_ci u32 sqm_ratio; 74662306a36Sopenharmony_ci u32 arb_refresh_rate; 74762306a36Sopenharmony_ci u32 high_clock; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci if (state->high.sclk < (state->low.sclk * 0xFF / 0x40)) 75062306a36Sopenharmony_ci high_clock = state->high.sclk; 75162306a36Sopenharmony_ci else 75262306a36Sopenharmony_ci high_clock = (state->low.sclk * 0xFF / 0x40); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci radeon_atom_set_engine_dram_timings(rdev, high_clock, 75562306a36Sopenharmony_ci state->high.mclk); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci sqm_ratio = 75862306a36Sopenharmony_ci STATE0(64 * high_clock / pi->boot_sclk) | 75962306a36Sopenharmony_ci STATE1(64 * high_clock / state->low.sclk) | 76062306a36Sopenharmony_ci STATE2(64 * high_clock / state->medium.sclk) | 76162306a36Sopenharmony_ci STATE3(64 * high_clock / state->high.sclk); 76262306a36Sopenharmony_ci WREG32(MC_ARB_SQM_RATIO, sqm_ratio); 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci arb_refresh_rate = 76562306a36Sopenharmony_ci POWERMODE0(rv770_calculate_memory_refresh_rate(rdev, pi->boot_sclk)) | 76662306a36Sopenharmony_ci POWERMODE1(rv770_calculate_memory_refresh_rate(rdev, state->low.sclk)) | 76762306a36Sopenharmony_ci POWERMODE2(rv770_calculate_memory_refresh_rate(rdev, state->medium.sclk)) | 76862306a36Sopenharmony_ci POWERMODE3(rv770_calculate_memory_refresh_rate(rdev, state->high.sclk)); 76962306a36Sopenharmony_ci WREG32(MC_ARB_RFSH_RATE, arb_refresh_rate); 77062306a36Sopenharmony_ci} 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_civoid rv770_enable_backbias(struct radeon_device *rdev, 77362306a36Sopenharmony_ci bool enable) 77462306a36Sopenharmony_ci{ 77562306a36Sopenharmony_ci if (enable) 77662306a36Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, BACKBIAS_PAD_EN, ~BACKBIAS_PAD_EN); 77762306a36Sopenharmony_ci else 77862306a36Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, 0, ~(BACKBIAS_VALUE | BACKBIAS_PAD_EN)); 77962306a36Sopenharmony_ci} 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_cistatic void rv770_enable_spread_spectrum(struct radeon_device *rdev, 78262306a36Sopenharmony_ci bool enable) 78362306a36Sopenharmony_ci{ 78462306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci if (enable) { 78762306a36Sopenharmony_ci if (pi->sclk_ss) 78862306a36Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, ~DYN_SPREAD_SPECTRUM_EN); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci if (pi->mclk_ss) { 79162306a36Sopenharmony_ci if (rdev->family == CHIP_RV740) 79262306a36Sopenharmony_ci rv740_enable_mclk_spread_spectrum(rdev, true); 79362306a36Sopenharmony_ci } 79462306a36Sopenharmony_ci } else { 79562306a36Sopenharmony_ci WREG32_P(CG_SPLL_SPREAD_SPECTRUM, 0, ~SSEN); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, 0, ~DYN_SPREAD_SPECTRUM_EN); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci WREG32_P(CG_MPLL_SPREAD_SPECTRUM, 0, ~SSEN); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci if (rdev->family == CHIP_RV740) 80262306a36Sopenharmony_ci rv740_enable_mclk_spread_spectrum(rdev, false); 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci} 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_cistatic void rv770_program_mpll_timing_parameters(struct radeon_device *rdev) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci if ((rdev->family == CHIP_RV770) && !pi->mem_gddr5) { 81162306a36Sopenharmony_ci WREG32(MPLL_TIME, 81262306a36Sopenharmony_ci (MPLL_LOCK_TIME(R600_MPLLLOCKTIME_DFLT * pi->ref_div) | 81362306a36Sopenharmony_ci MPLL_RESET_TIME(R600_MPLLRESETTIME_DFLT))); 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci} 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_civoid rv770_setup_bsp(struct radeon_device *rdev) 81862306a36Sopenharmony_ci{ 81962306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 82062306a36Sopenharmony_ci u32 xclk = radeon_get_xclk(rdev); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci r600_calculate_u_and_p(pi->asi, 82362306a36Sopenharmony_ci xclk, 82462306a36Sopenharmony_ci 16, 82562306a36Sopenharmony_ci &pi->bsp, 82662306a36Sopenharmony_ci &pi->bsu); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci r600_calculate_u_and_p(pi->pasi, 82962306a36Sopenharmony_ci xclk, 83062306a36Sopenharmony_ci 16, 83162306a36Sopenharmony_ci &pi->pbsp, 83262306a36Sopenharmony_ci &pi->pbsu); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci pi->dsp = BSP(pi->bsp) | BSU(pi->bsu); 83562306a36Sopenharmony_ci pi->psp = BSP(pi->pbsp) | BSU(pi->pbsu); 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci WREG32(CG_BSP, pi->dsp); 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci} 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_civoid rv770_program_git(struct radeon_device *rdev) 84262306a36Sopenharmony_ci{ 84362306a36Sopenharmony_ci WREG32_P(CG_GIT, CG_GICST(R600_GICST_DFLT), ~CG_GICST_MASK); 84462306a36Sopenharmony_ci} 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_civoid rv770_program_tp(struct radeon_device *rdev) 84762306a36Sopenharmony_ci{ 84862306a36Sopenharmony_ci int i; 84962306a36Sopenharmony_ci enum r600_td td = R600_TD_DFLT; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci for (i = 0; i < R600_PM_NUMBER_OF_TC; i++) 85262306a36Sopenharmony_ci WREG32(CG_FFCT_0 + (i * 4), (UTC_0(r600_utc[i]) | DTC_0(r600_dtc[i]))); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci if (td == R600_TD_AUTO) 85562306a36Sopenharmony_ci WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_FORCE_TREND_SEL); 85662306a36Sopenharmony_ci else 85762306a36Sopenharmony_ci WREG32_P(SCLK_PWRMGT_CNTL, FIR_FORCE_TREND_SEL, ~FIR_FORCE_TREND_SEL); 85862306a36Sopenharmony_ci if (td == R600_TD_UP) 85962306a36Sopenharmony_ci WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_TREND_MODE); 86062306a36Sopenharmony_ci if (td == R600_TD_DOWN) 86162306a36Sopenharmony_ci WREG32_P(SCLK_PWRMGT_CNTL, FIR_TREND_MODE, ~FIR_TREND_MODE); 86262306a36Sopenharmony_ci} 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_civoid rv770_program_tpp(struct radeon_device *rdev) 86562306a36Sopenharmony_ci{ 86662306a36Sopenharmony_ci WREG32(CG_TPC, R600_TPC_DFLT); 86762306a36Sopenharmony_ci} 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_civoid rv770_program_sstp(struct radeon_device *rdev) 87062306a36Sopenharmony_ci{ 87162306a36Sopenharmony_ci WREG32(CG_SSP, (SSTU(R600_SSTU_DFLT) | SST(R600_SST_DFLT))); 87262306a36Sopenharmony_ci} 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_civoid rv770_program_engine_speed_parameters(struct radeon_device *rdev) 87562306a36Sopenharmony_ci{ 87662306a36Sopenharmony_ci WREG32_P(SPLL_CNTL_MODE, SPLL_DIV_SYNC, ~SPLL_DIV_SYNC); 87762306a36Sopenharmony_ci} 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_cistatic void rv770_enable_display_gap(struct radeon_device *rdev) 88062306a36Sopenharmony_ci{ 88162306a36Sopenharmony_ci u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL); 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK); 88462306a36Sopenharmony_ci tmp |= (DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE) | 88562306a36Sopenharmony_ci DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE)); 88662306a36Sopenharmony_ci WREG32(CG_DISPLAY_GAP_CNTL, tmp); 88762306a36Sopenharmony_ci} 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_civoid rv770_program_vc(struct radeon_device *rdev) 89062306a36Sopenharmony_ci{ 89162306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci WREG32(CG_FTV, pi->vrc); 89462306a36Sopenharmony_ci} 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_civoid rv770_clear_vc(struct radeon_device *rdev) 89762306a36Sopenharmony_ci{ 89862306a36Sopenharmony_ci WREG32(CG_FTV, 0); 89962306a36Sopenharmony_ci} 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ciint rv770_upload_firmware(struct radeon_device *rdev) 90262306a36Sopenharmony_ci{ 90362306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 90462306a36Sopenharmony_ci int ret; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci rv770_reset_smc(rdev); 90762306a36Sopenharmony_ci rv770_stop_smc_clock(rdev); 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci ret = rv770_load_smc_ucode(rdev, pi->sram_end); 91062306a36Sopenharmony_ci if (ret) 91162306a36Sopenharmony_ci return ret; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci return 0; 91462306a36Sopenharmony_ci} 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_cistatic int rv770_populate_smc_acpi_state(struct radeon_device *rdev, 91762306a36Sopenharmony_ci RV770_SMC_STATETABLE *table) 91862306a36Sopenharmony_ci{ 91962306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci u32 mpll_ad_func_cntl = 92262306a36Sopenharmony_ci pi->clk_regs.rv770.mpll_ad_func_cntl; 92362306a36Sopenharmony_ci u32 mpll_ad_func_cntl_2 = 92462306a36Sopenharmony_ci pi->clk_regs.rv770.mpll_ad_func_cntl_2; 92562306a36Sopenharmony_ci u32 mpll_dq_func_cntl = 92662306a36Sopenharmony_ci pi->clk_regs.rv770.mpll_dq_func_cntl; 92762306a36Sopenharmony_ci u32 mpll_dq_func_cntl_2 = 92862306a36Sopenharmony_ci pi->clk_regs.rv770.mpll_dq_func_cntl_2; 92962306a36Sopenharmony_ci u32 spll_func_cntl = 93062306a36Sopenharmony_ci pi->clk_regs.rv770.cg_spll_func_cntl; 93162306a36Sopenharmony_ci u32 spll_func_cntl_2 = 93262306a36Sopenharmony_ci pi->clk_regs.rv770.cg_spll_func_cntl_2; 93362306a36Sopenharmony_ci u32 spll_func_cntl_3 = 93462306a36Sopenharmony_ci pi->clk_regs.rv770.cg_spll_func_cntl_3; 93562306a36Sopenharmony_ci u32 mclk_pwrmgt_cntl; 93662306a36Sopenharmony_ci u32 dll_cntl; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci table->ACPIState = table->initialState; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci table->ACPIState.flags &= ~PPSMC_SWSTATE_FLAG_DC; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci if (pi->acpi_vddc) { 94362306a36Sopenharmony_ci rv770_populate_vddc_value(rdev, pi->acpi_vddc, 94462306a36Sopenharmony_ci &table->ACPIState.levels[0].vddc); 94562306a36Sopenharmony_ci if (pi->pcie_gen2) { 94662306a36Sopenharmony_ci if (pi->acpi_pcie_gen2) 94762306a36Sopenharmony_ci table->ACPIState.levels[0].gen2PCIE = 1; 94862306a36Sopenharmony_ci else 94962306a36Sopenharmony_ci table->ACPIState.levels[0].gen2PCIE = 0; 95062306a36Sopenharmony_ci } else 95162306a36Sopenharmony_ci table->ACPIState.levels[0].gen2PCIE = 0; 95262306a36Sopenharmony_ci if (pi->acpi_pcie_gen2) 95362306a36Sopenharmony_ci table->ACPIState.levels[0].gen2XSP = 1; 95462306a36Sopenharmony_ci else 95562306a36Sopenharmony_ci table->ACPIState.levels[0].gen2XSP = 0; 95662306a36Sopenharmony_ci } else { 95762306a36Sopenharmony_ci rv770_populate_vddc_value(rdev, pi->min_vddc_in_table, 95862306a36Sopenharmony_ci &table->ACPIState.levels[0].vddc); 95962306a36Sopenharmony_ci table->ACPIState.levels[0].gen2PCIE = 0; 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci mpll_ad_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci mpll_dq_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN; 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci mclk_pwrmgt_cntl = (MRDCKA0_RESET | 96862306a36Sopenharmony_ci MRDCKA1_RESET | 96962306a36Sopenharmony_ci MRDCKB0_RESET | 97062306a36Sopenharmony_ci MRDCKB1_RESET | 97162306a36Sopenharmony_ci MRDCKC0_RESET | 97262306a36Sopenharmony_ci MRDCKC1_RESET | 97362306a36Sopenharmony_ci MRDCKD0_RESET | 97462306a36Sopenharmony_ci MRDCKD1_RESET); 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci dll_cntl = 0xff000000; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci spll_func_cntl |= SPLL_RESET | SPLL_SLEEP | SPLL_BYPASS_EN; 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK; 98162306a36Sopenharmony_ci spll_func_cntl_2 |= SCLK_MUX_SEL(4); 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl); 98462306a36Sopenharmony_ci table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2); 98562306a36Sopenharmony_ci table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl); 98662306a36Sopenharmony_ci table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2); 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci table->ACPIState.levels[0].mclk.mclk770.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl); 98962306a36Sopenharmony_ci table->ACPIState.levels[0].mclk.mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl); 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci table->ACPIState.levels[0].mclk.mclk770.mclk_value = 0; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl); 99462306a36Sopenharmony_ci table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2); 99562306a36Sopenharmony_ci table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci table->ACPIState.levels[0].sclk.sclk_value = 0; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci rv770_populate_mvdd_value(rdev, 0, &table->ACPIState.levels[0].mvdd); 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci table->ACPIState.levels[1] = table->ACPIState.levels[0]; 100262306a36Sopenharmony_ci table->ACPIState.levels[2] = table->ACPIState.levels[0]; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci return 0; 100562306a36Sopenharmony_ci} 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ciint rv770_populate_initial_mvdd_value(struct radeon_device *rdev, 100862306a36Sopenharmony_ci RV770_SMC_VOLTAGE_VALUE *voltage) 100962306a36Sopenharmony_ci{ 101062306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci if ((pi->s0_vid_lower_smio_cntl & pi->mvdd_mask_low) == 101362306a36Sopenharmony_ci (pi->mvdd_low_smio[MVDD_LOW_INDEX] & pi->mvdd_mask_low) ) { 101462306a36Sopenharmony_ci voltage->index = MVDD_LOW_INDEX; 101562306a36Sopenharmony_ci voltage->value = cpu_to_be16(MVDD_LOW_VALUE); 101662306a36Sopenharmony_ci } else { 101762306a36Sopenharmony_ci voltage->index = MVDD_HIGH_INDEX; 101862306a36Sopenharmony_ci voltage->value = cpu_to_be16(MVDD_HIGH_VALUE); 101962306a36Sopenharmony_ci } 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci return 0; 102262306a36Sopenharmony_ci} 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_cistatic int rv770_populate_smc_initial_state(struct radeon_device *rdev, 102562306a36Sopenharmony_ci struct radeon_ps *radeon_state, 102662306a36Sopenharmony_ci RV770_SMC_STATETABLE *table) 102762306a36Sopenharmony_ci{ 102862306a36Sopenharmony_ci struct rv7xx_ps *initial_state = rv770_get_ps(radeon_state); 102962306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 103062306a36Sopenharmony_ci u32 a_t; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci table->initialState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL = 103362306a36Sopenharmony_ci cpu_to_be32(pi->clk_regs.rv770.mpll_ad_func_cntl); 103462306a36Sopenharmony_ci table->initialState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL_2 = 103562306a36Sopenharmony_ci cpu_to_be32(pi->clk_regs.rv770.mpll_ad_func_cntl_2); 103662306a36Sopenharmony_ci table->initialState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL = 103762306a36Sopenharmony_ci cpu_to_be32(pi->clk_regs.rv770.mpll_dq_func_cntl); 103862306a36Sopenharmony_ci table->initialState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL_2 = 103962306a36Sopenharmony_ci cpu_to_be32(pi->clk_regs.rv770.mpll_dq_func_cntl_2); 104062306a36Sopenharmony_ci table->initialState.levels[0].mclk.mclk770.vMCLK_PWRMGT_CNTL = 104162306a36Sopenharmony_ci cpu_to_be32(pi->clk_regs.rv770.mclk_pwrmgt_cntl); 104262306a36Sopenharmony_ci table->initialState.levels[0].mclk.mclk770.vDLL_CNTL = 104362306a36Sopenharmony_ci cpu_to_be32(pi->clk_regs.rv770.dll_cntl); 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci table->initialState.levels[0].mclk.mclk770.vMPLL_SS = 104662306a36Sopenharmony_ci cpu_to_be32(pi->clk_regs.rv770.mpll_ss1); 104762306a36Sopenharmony_ci table->initialState.levels[0].mclk.mclk770.vMPLL_SS2 = 104862306a36Sopenharmony_ci cpu_to_be32(pi->clk_regs.rv770.mpll_ss2); 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci table->initialState.levels[0].mclk.mclk770.mclk_value = 105162306a36Sopenharmony_ci cpu_to_be32(initial_state->low.mclk); 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL = 105462306a36Sopenharmony_ci cpu_to_be32(pi->clk_regs.rv770.cg_spll_func_cntl); 105562306a36Sopenharmony_ci table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 = 105662306a36Sopenharmony_ci cpu_to_be32(pi->clk_regs.rv770.cg_spll_func_cntl_2); 105762306a36Sopenharmony_ci table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 = 105862306a36Sopenharmony_ci cpu_to_be32(pi->clk_regs.rv770.cg_spll_func_cntl_3); 105962306a36Sopenharmony_ci table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM = 106062306a36Sopenharmony_ci cpu_to_be32(pi->clk_regs.rv770.cg_spll_spread_spectrum); 106162306a36Sopenharmony_ci table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM_2 = 106262306a36Sopenharmony_ci cpu_to_be32(pi->clk_regs.rv770.cg_spll_spread_spectrum_2); 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci table->initialState.levels[0].sclk.sclk_value = 106562306a36Sopenharmony_ci cpu_to_be32(initial_state->low.sclk); 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci table->initialState.levels[0].arbValue = MC_CG_ARB_FREQ_F0; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci table->initialState.levels[0].seqValue = 107062306a36Sopenharmony_ci rv770_get_seq_value(rdev, &initial_state->low); 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci rv770_populate_vddc_value(rdev, 107362306a36Sopenharmony_ci initial_state->low.vddc, 107462306a36Sopenharmony_ci &table->initialState.levels[0].vddc); 107562306a36Sopenharmony_ci rv770_populate_initial_mvdd_value(rdev, 107662306a36Sopenharmony_ci &table->initialState.levels[0].mvdd); 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci a_t = CG_R(0xffff) | CG_L(0); 107962306a36Sopenharmony_ci table->initialState.levels[0].aT = cpu_to_be32(a_t); 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci table->initialState.levels[0].bSP = cpu_to_be32(pi->dsp); 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci if (pi->boot_in_gen2) 108462306a36Sopenharmony_ci table->initialState.levels[0].gen2PCIE = 1; 108562306a36Sopenharmony_ci else 108662306a36Sopenharmony_ci table->initialState.levels[0].gen2PCIE = 0; 108762306a36Sopenharmony_ci if (initial_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) 108862306a36Sopenharmony_ci table->initialState.levels[0].gen2XSP = 1; 108962306a36Sopenharmony_ci else 109062306a36Sopenharmony_ci table->initialState.levels[0].gen2XSP = 0; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci if (rdev->family == CHIP_RV740) { 109362306a36Sopenharmony_ci if (pi->mem_gddr5) { 109462306a36Sopenharmony_ci if (initial_state->low.mclk <= pi->mclk_strobe_mode_threshold) 109562306a36Sopenharmony_ci table->initialState.levels[0].strobeMode = 109662306a36Sopenharmony_ci rv740_get_mclk_frequency_ratio(initial_state->low.mclk) | 0x10; 109762306a36Sopenharmony_ci else 109862306a36Sopenharmony_ci table->initialState.levels[0].strobeMode = 0; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci if (initial_state->low.mclk >= pi->mclk_edc_enable_threshold) 110162306a36Sopenharmony_ci table->initialState.levels[0].mcFlags = SMC_MC_EDC_RD_FLAG | SMC_MC_EDC_WR_FLAG; 110262306a36Sopenharmony_ci else 110362306a36Sopenharmony_ci table->initialState.levels[0].mcFlags = 0; 110462306a36Sopenharmony_ci } 110562306a36Sopenharmony_ci } 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci table->initialState.levels[1] = table->initialState.levels[0]; 110862306a36Sopenharmony_ci table->initialState.levels[2] = table->initialState.levels[0]; 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci table->initialState.flags |= PPSMC_SWSTATE_FLAG_DC; 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci return 0; 111362306a36Sopenharmony_ci} 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_cistatic int rv770_populate_smc_vddc_table(struct radeon_device *rdev, 111662306a36Sopenharmony_ci RV770_SMC_STATETABLE *table) 111762306a36Sopenharmony_ci{ 111862306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 111962306a36Sopenharmony_ci int i; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci for (i = 0; i < pi->valid_vddc_entries; i++) { 112262306a36Sopenharmony_ci table->highSMIO[pi->vddc_table[i].vddc_index] = 112362306a36Sopenharmony_ci pi->vddc_table[i].high_smio; 112462306a36Sopenharmony_ci table->lowSMIO[pi->vddc_table[i].vddc_index] = 112562306a36Sopenharmony_ci cpu_to_be32(pi->vddc_table[i].low_smio); 112662306a36Sopenharmony_ci } 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci table->voltageMaskTable.highMask[RV770_SMC_VOLTAGEMASK_VDDC] = 0; 112962306a36Sopenharmony_ci table->voltageMaskTable.lowMask[RV770_SMC_VOLTAGEMASK_VDDC] = 113062306a36Sopenharmony_ci cpu_to_be32(pi->vddc_mask_low); 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci for (i = 0; 113362306a36Sopenharmony_ci ((i < pi->valid_vddc_entries) && 113462306a36Sopenharmony_ci (pi->max_vddc_in_table > 113562306a36Sopenharmony_ci pi->vddc_table[i].vddc)); 113662306a36Sopenharmony_ci i++); 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci table->maxVDDCIndexInPPTable = 113962306a36Sopenharmony_ci pi->vddc_table[i].vddc_index; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci return 0; 114262306a36Sopenharmony_ci} 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_cistatic int rv770_populate_smc_mvdd_table(struct radeon_device *rdev, 114562306a36Sopenharmony_ci RV770_SMC_STATETABLE *table) 114662306a36Sopenharmony_ci{ 114762306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci if (pi->mvdd_control) { 115062306a36Sopenharmony_ci table->lowSMIO[MVDD_HIGH_INDEX] |= 115162306a36Sopenharmony_ci cpu_to_be32(pi->mvdd_low_smio[MVDD_HIGH_INDEX]); 115262306a36Sopenharmony_ci table->lowSMIO[MVDD_LOW_INDEX] |= 115362306a36Sopenharmony_ci cpu_to_be32(pi->mvdd_low_smio[MVDD_LOW_INDEX]); 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci table->voltageMaskTable.highMask[RV770_SMC_VOLTAGEMASK_MVDD] = 0; 115662306a36Sopenharmony_ci table->voltageMaskTable.lowMask[RV770_SMC_VOLTAGEMASK_MVDD] = 115762306a36Sopenharmony_ci cpu_to_be32(pi->mvdd_mask_low); 115862306a36Sopenharmony_ci } 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci return 0; 116162306a36Sopenharmony_ci} 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_cistatic int rv770_init_smc_table(struct radeon_device *rdev, 116462306a36Sopenharmony_ci struct radeon_ps *radeon_boot_state) 116562306a36Sopenharmony_ci{ 116662306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 116762306a36Sopenharmony_ci struct rv7xx_ps *boot_state = rv770_get_ps(radeon_boot_state); 116862306a36Sopenharmony_ci RV770_SMC_STATETABLE *table = &pi->smc_statetable; 116962306a36Sopenharmony_ci int ret; 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci memset(table, 0, sizeof(RV770_SMC_STATETABLE)); 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci pi->boot_sclk = boot_state->low.sclk; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci rv770_populate_smc_vddc_table(rdev, table); 117662306a36Sopenharmony_ci rv770_populate_smc_mvdd_table(rdev, table); 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci switch (rdev->pm.int_thermal_type) { 117962306a36Sopenharmony_ci case THERMAL_TYPE_RV770: 118062306a36Sopenharmony_ci case THERMAL_TYPE_ADT7473_WITH_INTERNAL: 118162306a36Sopenharmony_ci table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_INTERNAL; 118262306a36Sopenharmony_ci break; 118362306a36Sopenharmony_ci case THERMAL_TYPE_NONE: 118462306a36Sopenharmony_ci table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_NONE; 118562306a36Sopenharmony_ci break; 118662306a36Sopenharmony_ci case THERMAL_TYPE_EXTERNAL_GPIO: 118762306a36Sopenharmony_ci default: 118862306a36Sopenharmony_ci table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL; 118962306a36Sopenharmony_ci break; 119062306a36Sopenharmony_ci } 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC) { 119362306a36Sopenharmony_ci table->systemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC; 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_DONT_WAIT_FOR_VBLANK_ON_ALERT) 119662306a36Sopenharmony_ci table->extraFlags |= PPSMC_EXTRAFLAGS_AC2DC_DONT_WAIT_FOR_VBLANK; 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_GOTO_BOOT_ON_ALERT) 119962306a36Sopenharmony_ci table->extraFlags |= PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTOINITIALSTATE; 120062306a36Sopenharmony_ci } 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC) 120362306a36Sopenharmony_ci table->systemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci if (pi->mem_gddr5) 120662306a36Sopenharmony_ci table->systemFlags |= PPSMC_SYSTEMFLAG_GDDR5; 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710)) 120962306a36Sopenharmony_ci ret = rv730_populate_smc_initial_state(rdev, radeon_boot_state, table); 121062306a36Sopenharmony_ci else 121162306a36Sopenharmony_ci ret = rv770_populate_smc_initial_state(rdev, radeon_boot_state, table); 121262306a36Sopenharmony_ci if (ret) 121362306a36Sopenharmony_ci return ret; 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci if (rdev->family == CHIP_RV740) 121662306a36Sopenharmony_ci ret = rv740_populate_smc_acpi_state(rdev, table); 121762306a36Sopenharmony_ci else if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710)) 121862306a36Sopenharmony_ci ret = rv730_populate_smc_acpi_state(rdev, table); 121962306a36Sopenharmony_ci else 122062306a36Sopenharmony_ci ret = rv770_populate_smc_acpi_state(rdev, table); 122162306a36Sopenharmony_ci if (ret) 122262306a36Sopenharmony_ci return ret; 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci table->driverState = table->initialState; 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci return rv770_copy_bytes_to_smc(rdev, 122762306a36Sopenharmony_ci pi->state_table_start, 122862306a36Sopenharmony_ci (const u8 *)table, 122962306a36Sopenharmony_ci sizeof(RV770_SMC_STATETABLE), 123062306a36Sopenharmony_ci pi->sram_end); 123162306a36Sopenharmony_ci} 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_cistatic int rv770_construct_vddc_table(struct radeon_device *rdev) 123462306a36Sopenharmony_ci{ 123562306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 123662306a36Sopenharmony_ci u16 min, max, step; 123762306a36Sopenharmony_ci u32 steps = 0; 123862306a36Sopenharmony_ci u8 vddc_index = 0; 123962306a36Sopenharmony_ci u32 i; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci radeon_atom_get_min_voltage(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, &min); 124262306a36Sopenharmony_ci radeon_atom_get_max_voltage(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, &max); 124362306a36Sopenharmony_ci radeon_atom_get_voltage_step(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, &step); 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci steps = (max - min) / step + 1; 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci if (steps > MAX_NO_VREG_STEPS) 124862306a36Sopenharmony_ci return -EINVAL; 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci for (i = 0; i < steps; i++) { 125162306a36Sopenharmony_ci u32 gpio_pins, gpio_mask; 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci pi->vddc_table[i].vddc = (u16)(min + i * step); 125462306a36Sopenharmony_ci radeon_atom_get_voltage_gpio_settings(rdev, 125562306a36Sopenharmony_ci pi->vddc_table[i].vddc, 125662306a36Sopenharmony_ci SET_VOLTAGE_TYPE_ASIC_VDDC, 125762306a36Sopenharmony_ci &gpio_pins, &gpio_mask); 125862306a36Sopenharmony_ci pi->vddc_table[i].low_smio = gpio_pins & gpio_mask; 125962306a36Sopenharmony_ci pi->vddc_table[i].high_smio = 0; 126062306a36Sopenharmony_ci pi->vddc_mask_low = gpio_mask; 126162306a36Sopenharmony_ci if (i > 0) { 126262306a36Sopenharmony_ci if ((pi->vddc_table[i].low_smio != 126362306a36Sopenharmony_ci pi->vddc_table[i - 1].low_smio ) || 126462306a36Sopenharmony_ci (pi->vddc_table[i].high_smio != 126562306a36Sopenharmony_ci pi->vddc_table[i - 1].high_smio)) 126662306a36Sopenharmony_ci vddc_index++; 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci pi->vddc_table[i].vddc_index = vddc_index; 126962306a36Sopenharmony_ci } 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci pi->valid_vddc_entries = (u8)steps; 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci return 0; 127462306a36Sopenharmony_ci} 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_cistatic u32 rv770_get_mclk_split_point(struct atom_memory_info *memory_info) 127762306a36Sopenharmony_ci{ 127862306a36Sopenharmony_ci if (memory_info->mem_type == MEM_TYPE_GDDR3) 127962306a36Sopenharmony_ci return 30000; 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci return 0; 128262306a36Sopenharmony_ci} 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_cistatic int rv770_get_mvdd_pin_configuration(struct radeon_device *rdev) 128562306a36Sopenharmony_ci{ 128662306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 128762306a36Sopenharmony_ci u32 gpio_pins, gpio_mask; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci radeon_atom_get_voltage_gpio_settings(rdev, 129062306a36Sopenharmony_ci MVDD_HIGH_VALUE, SET_VOLTAGE_TYPE_ASIC_MVDDC, 129162306a36Sopenharmony_ci &gpio_pins, &gpio_mask); 129262306a36Sopenharmony_ci pi->mvdd_mask_low = gpio_mask; 129362306a36Sopenharmony_ci pi->mvdd_low_smio[MVDD_HIGH_INDEX] = 129462306a36Sopenharmony_ci gpio_pins & gpio_mask; 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci radeon_atom_get_voltage_gpio_settings(rdev, 129762306a36Sopenharmony_ci MVDD_LOW_VALUE, SET_VOLTAGE_TYPE_ASIC_MVDDC, 129862306a36Sopenharmony_ci &gpio_pins, &gpio_mask); 129962306a36Sopenharmony_ci pi->mvdd_low_smio[MVDD_LOW_INDEX] = 130062306a36Sopenharmony_ci gpio_pins & gpio_mask; 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci return 0; 130362306a36Sopenharmony_ci} 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ciu8 rv770_get_memory_module_index(struct radeon_device *rdev) 130662306a36Sopenharmony_ci{ 130762306a36Sopenharmony_ci return (u8) ((RREG32(BIOS_SCRATCH_4) >> 16) & 0xff); 130862306a36Sopenharmony_ci} 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_cistatic int rv770_get_mvdd_configuration(struct radeon_device *rdev) 131162306a36Sopenharmony_ci{ 131262306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 131362306a36Sopenharmony_ci u8 memory_module_index; 131462306a36Sopenharmony_ci struct atom_memory_info memory_info; 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci memory_module_index = rv770_get_memory_module_index(rdev); 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci if (radeon_atom_get_memory_info(rdev, memory_module_index, &memory_info)) { 131962306a36Sopenharmony_ci pi->mvdd_control = false; 132062306a36Sopenharmony_ci return 0; 132162306a36Sopenharmony_ci } 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci pi->mvdd_split_frequency = 132462306a36Sopenharmony_ci rv770_get_mclk_split_point(&memory_info); 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci if (pi->mvdd_split_frequency == 0) { 132762306a36Sopenharmony_ci pi->mvdd_control = false; 132862306a36Sopenharmony_ci return 0; 132962306a36Sopenharmony_ci } 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci return rv770_get_mvdd_pin_configuration(rdev); 133262306a36Sopenharmony_ci} 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_civoid rv770_enable_voltage_control(struct radeon_device *rdev, 133562306a36Sopenharmony_ci bool enable) 133662306a36Sopenharmony_ci{ 133762306a36Sopenharmony_ci if (enable) 133862306a36Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, VOLT_PWRMGT_EN, ~VOLT_PWRMGT_EN); 133962306a36Sopenharmony_ci else 134062306a36Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, 0, ~VOLT_PWRMGT_EN); 134162306a36Sopenharmony_ci} 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_cistatic void rv770_program_display_gap(struct radeon_device *rdev) 134462306a36Sopenharmony_ci{ 134562306a36Sopenharmony_ci u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL); 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK); 134862306a36Sopenharmony_ci if (rdev->pm.dpm.new_active_crtcs & 1) { 134962306a36Sopenharmony_ci tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK); 135062306a36Sopenharmony_ci tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); 135162306a36Sopenharmony_ci } else if (rdev->pm.dpm.new_active_crtcs & 2) { 135262306a36Sopenharmony_ci tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); 135362306a36Sopenharmony_ci tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK); 135462306a36Sopenharmony_ci } else { 135562306a36Sopenharmony_ci tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); 135662306a36Sopenharmony_ci tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); 135762306a36Sopenharmony_ci } 135862306a36Sopenharmony_ci WREG32(CG_DISPLAY_GAP_CNTL, tmp); 135962306a36Sopenharmony_ci} 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_cistatic void rv770_enable_dynamic_pcie_gen2(struct radeon_device *rdev, 136262306a36Sopenharmony_ci bool enable) 136362306a36Sopenharmony_ci{ 136462306a36Sopenharmony_ci rv770_enable_bif_dynamic_pcie_gen2(rdev, enable); 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci if (enable) 136762306a36Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, ENABLE_GEN2PCIE, ~ENABLE_GEN2PCIE); 136862306a36Sopenharmony_ci else 136962306a36Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, 0, ~ENABLE_GEN2PCIE); 137062306a36Sopenharmony_ci} 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_cistatic void r7xx_program_memory_timing_parameters(struct radeon_device *rdev, 137362306a36Sopenharmony_ci struct radeon_ps *radeon_new_state) 137462306a36Sopenharmony_ci{ 137562306a36Sopenharmony_ci if ((rdev->family == CHIP_RV730) || 137662306a36Sopenharmony_ci (rdev->family == CHIP_RV710) || 137762306a36Sopenharmony_ci (rdev->family == CHIP_RV740)) 137862306a36Sopenharmony_ci rv730_program_memory_timing_parameters(rdev, radeon_new_state); 137962306a36Sopenharmony_ci else 138062306a36Sopenharmony_ci rv770_program_memory_timing_parameters(rdev, radeon_new_state); 138162306a36Sopenharmony_ci} 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_cistatic int rv770_upload_sw_state(struct radeon_device *rdev, 138462306a36Sopenharmony_ci struct radeon_ps *radeon_new_state) 138562306a36Sopenharmony_ci{ 138662306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 138762306a36Sopenharmony_ci u16 address = pi->state_table_start + 138862306a36Sopenharmony_ci offsetof(RV770_SMC_STATETABLE, driverState); 138962306a36Sopenharmony_ci RV770_SMC_SWSTATE state = { 0 }; 139062306a36Sopenharmony_ci int ret; 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci ret = rv770_convert_power_state_to_smc(rdev, radeon_new_state, &state); 139362306a36Sopenharmony_ci if (ret) 139462306a36Sopenharmony_ci return ret; 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci return rv770_copy_bytes_to_smc(rdev, address, (const u8 *)&state, 139762306a36Sopenharmony_ci sizeof(RV770_SMC_SWSTATE), 139862306a36Sopenharmony_ci pi->sram_end); 139962306a36Sopenharmony_ci} 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ciint rv770_halt_smc(struct radeon_device *rdev) 140262306a36Sopenharmony_ci{ 140362306a36Sopenharmony_ci if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_Halt) != PPSMC_Result_OK) 140462306a36Sopenharmony_ci return -EINVAL; 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci if (rv770_wait_for_smc_inactive(rdev) != PPSMC_Result_OK) 140762306a36Sopenharmony_ci return -EINVAL; 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci return 0; 141062306a36Sopenharmony_ci} 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ciint rv770_resume_smc(struct radeon_device *rdev) 141362306a36Sopenharmony_ci{ 141462306a36Sopenharmony_ci if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_Resume) != PPSMC_Result_OK) 141562306a36Sopenharmony_ci return -EINVAL; 141662306a36Sopenharmony_ci return 0; 141762306a36Sopenharmony_ci} 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ciint rv770_set_sw_state(struct radeon_device *rdev) 142062306a36Sopenharmony_ci{ 142162306a36Sopenharmony_ci if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_SwitchToSwState) != PPSMC_Result_OK) 142262306a36Sopenharmony_ci DRM_DEBUG("rv770_set_sw_state failed\n"); 142362306a36Sopenharmony_ci return 0; 142462306a36Sopenharmony_ci} 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ciint rv770_set_boot_state(struct radeon_device *rdev) 142762306a36Sopenharmony_ci{ 142862306a36Sopenharmony_ci if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_SwitchToInitialState) != PPSMC_Result_OK) 142962306a36Sopenharmony_ci return -EINVAL; 143062306a36Sopenharmony_ci return 0; 143162306a36Sopenharmony_ci} 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_civoid rv770_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev, 143462306a36Sopenharmony_ci struct radeon_ps *new_ps, 143562306a36Sopenharmony_ci struct radeon_ps *old_ps) 143662306a36Sopenharmony_ci{ 143762306a36Sopenharmony_ci struct rv7xx_ps *new_state = rv770_get_ps(new_ps); 143862306a36Sopenharmony_ci struct rv7xx_ps *current_state = rv770_get_ps(old_ps); 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci if ((new_ps->vclk == old_ps->vclk) && 144162306a36Sopenharmony_ci (new_ps->dclk == old_ps->dclk)) 144262306a36Sopenharmony_ci return; 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci if (new_state->high.sclk >= current_state->high.sclk) 144562306a36Sopenharmony_ci return; 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk); 144862306a36Sopenharmony_ci} 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_civoid rv770_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev, 145162306a36Sopenharmony_ci struct radeon_ps *new_ps, 145262306a36Sopenharmony_ci struct radeon_ps *old_ps) 145362306a36Sopenharmony_ci{ 145462306a36Sopenharmony_ci struct rv7xx_ps *new_state = rv770_get_ps(new_ps); 145562306a36Sopenharmony_ci struct rv7xx_ps *current_state = rv770_get_ps(old_ps); 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci if ((new_ps->vclk == old_ps->vclk) && 145862306a36Sopenharmony_ci (new_ps->dclk == old_ps->dclk)) 145962306a36Sopenharmony_ci return; 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci if (new_state->high.sclk < current_state->high.sclk) 146262306a36Sopenharmony_ci return; 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk); 146562306a36Sopenharmony_ci} 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ciint rv770_restrict_performance_levels_before_switch(struct radeon_device *rdev) 146862306a36Sopenharmony_ci{ 146962306a36Sopenharmony_ci if (rv770_send_msg_to_smc(rdev, (PPSMC_Msg)(PPSMC_MSG_NoForcedLevel)) != PPSMC_Result_OK) 147062306a36Sopenharmony_ci return -EINVAL; 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci if (rv770_send_msg_to_smc(rdev, (PPSMC_Msg)(PPSMC_MSG_TwoLevelsDisabled)) != PPSMC_Result_OK) 147362306a36Sopenharmony_ci return -EINVAL; 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci return 0; 147662306a36Sopenharmony_ci} 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ciint rv770_dpm_force_performance_level(struct radeon_device *rdev, 147962306a36Sopenharmony_ci enum radeon_dpm_forced_level level) 148062306a36Sopenharmony_ci{ 148162306a36Sopenharmony_ci PPSMC_Msg msg; 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { 148462306a36Sopenharmony_ci if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_ZeroLevelsDisabled) != PPSMC_Result_OK) 148562306a36Sopenharmony_ci return -EINVAL; 148662306a36Sopenharmony_ci msg = PPSMC_MSG_ForceHigh; 148762306a36Sopenharmony_ci } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) { 148862306a36Sopenharmony_ci if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_NoForcedLevel) != PPSMC_Result_OK) 148962306a36Sopenharmony_ci return -EINVAL; 149062306a36Sopenharmony_ci msg = (PPSMC_Msg)(PPSMC_MSG_TwoLevelsDisabled); 149162306a36Sopenharmony_ci } else { 149262306a36Sopenharmony_ci if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_NoForcedLevel) != PPSMC_Result_OK) 149362306a36Sopenharmony_ci return -EINVAL; 149462306a36Sopenharmony_ci msg = (PPSMC_Msg)(PPSMC_MSG_ZeroLevelsDisabled); 149562306a36Sopenharmony_ci } 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci if (rv770_send_msg_to_smc(rdev, msg) != PPSMC_Result_OK) 149862306a36Sopenharmony_ci return -EINVAL; 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci rdev->pm.dpm.forced_level = level; 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci return 0; 150362306a36Sopenharmony_ci} 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_civoid r7xx_start_smc(struct radeon_device *rdev) 150662306a36Sopenharmony_ci{ 150762306a36Sopenharmony_ci rv770_start_smc(rdev); 150862306a36Sopenharmony_ci rv770_start_smc_clock(rdev); 150962306a36Sopenharmony_ci} 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_civoid r7xx_stop_smc(struct radeon_device *rdev) 151362306a36Sopenharmony_ci{ 151462306a36Sopenharmony_ci rv770_reset_smc(rdev); 151562306a36Sopenharmony_ci rv770_stop_smc_clock(rdev); 151662306a36Sopenharmony_ci} 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_cistatic void rv770_read_clock_registers(struct radeon_device *rdev) 151962306a36Sopenharmony_ci{ 152062306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci pi->clk_regs.rv770.cg_spll_func_cntl = 152362306a36Sopenharmony_ci RREG32(CG_SPLL_FUNC_CNTL); 152462306a36Sopenharmony_ci pi->clk_regs.rv770.cg_spll_func_cntl_2 = 152562306a36Sopenharmony_ci RREG32(CG_SPLL_FUNC_CNTL_2); 152662306a36Sopenharmony_ci pi->clk_regs.rv770.cg_spll_func_cntl_3 = 152762306a36Sopenharmony_ci RREG32(CG_SPLL_FUNC_CNTL_3); 152862306a36Sopenharmony_ci pi->clk_regs.rv770.cg_spll_spread_spectrum = 152962306a36Sopenharmony_ci RREG32(CG_SPLL_SPREAD_SPECTRUM); 153062306a36Sopenharmony_ci pi->clk_regs.rv770.cg_spll_spread_spectrum_2 = 153162306a36Sopenharmony_ci RREG32(CG_SPLL_SPREAD_SPECTRUM_2); 153262306a36Sopenharmony_ci pi->clk_regs.rv770.mpll_ad_func_cntl = 153362306a36Sopenharmony_ci RREG32(MPLL_AD_FUNC_CNTL); 153462306a36Sopenharmony_ci pi->clk_regs.rv770.mpll_ad_func_cntl_2 = 153562306a36Sopenharmony_ci RREG32(MPLL_AD_FUNC_CNTL_2); 153662306a36Sopenharmony_ci pi->clk_regs.rv770.mpll_dq_func_cntl = 153762306a36Sopenharmony_ci RREG32(MPLL_DQ_FUNC_CNTL); 153862306a36Sopenharmony_ci pi->clk_regs.rv770.mpll_dq_func_cntl_2 = 153962306a36Sopenharmony_ci RREG32(MPLL_DQ_FUNC_CNTL_2); 154062306a36Sopenharmony_ci pi->clk_regs.rv770.mclk_pwrmgt_cntl = 154162306a36Sopenharmony_ci RREG32(MCLK_PWRMGT_CNTL); 154262306a36Sopenharmony_ci pi->clk_regs.rv770.dll_cntl = RREG32(DLL_CNTL); 154362306a36Sopenharmony_ci} 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_cistatic void r7xx_read_clock_registers(struct radeon_device *rdev) 154662306a36Sopenharmony_ci{ 154762306a36Sopenharmony_ci if (rdev->family == CHIP_RV740) 154862306a36Sopenharmony_ci rv740_read_clock_registers(rdev); 154962306a36Sopenharmony_ci else if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710)) 155062306a36Sopenharmony_ci rv730_read_clock_registers(rdev); 155162306a36Sopenharmony_ci else 155262306a36Sopenharmony_ci rv770_read_clock_registers(rdev); 155362306a36Sopenharmony_ci} 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_civoid rv770_read_voltage_smio_registers(struct radeon_device *rdev) 155662306a36Sopenharmony_ci{ 155762306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci pi->s0_vid_lower_smio_cntl = 156062306a36Sopenharmony_ci RREG32(S0_VID_LOWER_SMIO_CNTL); 156162306a36Sopenharmony_ci} 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_civoid rv770_reset_smio_status(struct radeon_device *rdev) 156462306a36Sopenharmony_ci{ 156562306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 156662306a36Sopenharmony_ci u32 sw_smio_index, vid_smio_cntl; 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci sw_smio_index = 156962306a36Sopenharmony_ci (RREG32(GENERAL_PWRMGT) & SW_SMIO_INDEX_MASK) >> SW_SMIO_INDEX_SHIFT; 157062306a36Sopenharmony_ci switch (sw_smio_index) { 157162306a36Sopenharmony_ci case 3: 157262306a36Sopenharmony_ci vid_smio_cntl = RREG32(S3_VID_LOWER_SMIO_CNTL); 157362306a36Sopenharmony_ci break; 157462306a36Sopenharmony_ci case 2: 157562306a36Sopenharmony_ci vid_smio_cntl = RREG32(S2_VID_LOWER_SMIO_CNTL); 157662306a36Sopenharmony_ci break; 157762306a36Sopenharmony_ci case 1: 157862306a36Sopenharmony_ci vid_smio_cntl = RREG32(S1_VID_LOWER_SMIO_CNTL); 157962306a36Sopenharmony_ci break; 158062306a36Sopenharmony_ci case 0: 158162306a36Sopenharmony_ci return; 158262306a36Sopenharmony_ci default: 158362306a36Sopenharmony_ci vid_smio_cntl = pi->s0_vid_lower_smio_cntl; 158462306a36Sopenharmony_ci break; 158562306a36Sopenharmony_ci } 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci WREG32(S0_VID_LOWER_SMIO_CNTL, vid_smio_cntl); 158862306a36Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, SW_SMIO_INDEX(0), ~SW_SMIO_INDEX_MASK); 158962306a36Sopenharmony_ci} 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_civoid rv770_get_memory_type(struct radeon_device *rdev) 159262306a36Sopenharmony_ci{ 159362306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 159462306a36Sopenharmony_ci u32 tmp; 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci tmp = RREG32(MC_SEQ_MISC0); 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci if (((tmp & MC_SEQ_MISC0_GDDR5_MASK) >> MC_SEQ_MISC0_GDDR5_SHIFT) == 159962306a36Sopenharmony_ci MC_SEQ_MISC0_GDDR5_VALUE) 160062306a36Sopenharmony_ci pi->mem_gddr5 = true; 160162306a36Sopenharmony_ci else 160262306a36Sopenharmony_ci pi->mem_gddr5 = false; 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci} 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_civoid rv770_get_pcie_gen2_status(struct radeon_device *rdev) 160762306a36Sopenharmony_ci{ 160862306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 160962306a36Sopenharmony_ci u32 tmp; 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) && 161462306a36Sopenharmony_ci (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2)) 161562306a36Sopenharmony_ci pi->pcie_gen2 = true; 161662306a36Sopenharmony_ci else 161762306a36Sopenharmony_ci pi->pcie_gen2 = false; 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci if (pi->pcie_gen2) { 162062306a36Sopenharmony_ci if (tmp & LC_CURRENT_DATA_RATE) 162162306a36Sopenharmony_ci pi->boot_in_gen2 = true; 162262306a36Sopenharmony_ci else 162362306a36Sopenharmony_ci pi->boot_in_gen2 = false; 162462306a36Sopenharmony_ci } else 162562306a36Sopenharmony_ci pi->boot_in_gen2 = false; 162662306a36Sopenharmony_ci} 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci#if 0 162962306a36Sopenharmony_cistatic int rv770_enter_ulp_state(struct radeon_device *rdev) 163062306a36Sopenharmony_ci{ 163162306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci if (pi->gfx_clock_gating) { 163462306a36Sopenharmony_ci WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN); 163562306a36Sopenharmony_ci WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON); 163662306a36Sopenharmony_ci WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON); 163762306a36Sopenharmony_ci RREG32(GB_TILING_CONFIG); 163862306a36Sopenharmony_ci } 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_ci WREG32_P(SMC_MSG, HOST_SMC_MSG(PPSMC_MSG_SwitchToMinimumPower), 164162306a36Sopenharmony_ci ~HOST_SMC_MSG_MASK); 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci udelay(7000); 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci return 0; 164662306a36Sopenharmony_ci} 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_cistatic int rv770_exit_ulp_state(struct radeon_device *rdev) 164962306a36Sopenharmony_ci{ 165062306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 165162306a36Sopenharmony_ci int i; 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci WREG32_P(SMC_MSG, HOST_SMC_MSG(PPSMC_MSG_ResumeFromMinimumPower), 165462306a36Sopenharmony_ci ~HOST_SMC_MSG_MASK); 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci udelay(7000); 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci for (i = 0; i < rdev->usec_timeout; i++) { 165962306a36Sopenharmony_ci if (((RREG32(SMC_MSG) & HOST_SMC_RESP_MASK) >> HOST_SMC_RESP_SHIFT) == 1) 166062306a36Sopenharmony_ci break; 166162306a36Sopenharmony_ci udelay(1000); 166262306a36Sopenharmony_ci } 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci if (pi->gfx_clock_gating) 166562306a36Sopenharmony_ci WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN); 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci return 0; 166862306a36Sopenharmony_ci} 166962306a36Sopenharmony_ci#endif 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_cistatic void rv770_get_mclk_odt_threshold(struct radeon_device *rdev) 167262306a36Sopenharmony_ci{ 167362306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 167462306a36Sopenharmony_ci u8 memory_module_index; 167562306a36Sopenharmony_ci struct atom_memory_info memory_info; 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_ci pi->mclk_odt_threshold = 0; 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710)) { 168062306a36Sopenharmony_ci memory_module_index = rv770_get_memory_module_index(rdev); 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci if (radeon_atom_get_memory_info(rdev, memory_module_index, &memory_info)) 168362306a36Sopenharmony_ci return; 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci if (memory_info.mem_type == MEM_TYPE_DDR2 || 168662306a36Sopenharmony_ci memory_info.mem_type == MEM_TYPE_DDR3) 168762306a36Sopenharmony_ci pi->mclk_odt_threshold = 30000; 168862306a36Sopenharmony_ci } 168962306a36Sopenharmony_ci} 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_civoid rv770_get_max_vddc(struct radeon_device *rdev) 169262306a36Sopenharmony_ci{ 169362306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 169462306a36Sopenharmony_ci u16 vddc; 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci if (radeon_atom_get_max_vddc(rdev, 0, 0, &vddc)) 169762306a36Sopenharmony_ci pi->max_vddc = 0; 169862306a36Sopenharmony_ci else 169962306a36Sopenharmony_ci pi->max_vddc = vddc; 170062306a36Sopenharmony_ci} 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_civoid rv770_program_response_times(struct radeon_device *rdev) 170362306a36Sopenharmony_ci{ 170462306a36Sopenharmony_ci u32 voltage_response_time, backbias_response_time; 170562306a36Sopenharmony_ci u32 acpi_delay_time, vbi_time_out; 170662306a36Sopenharmony_ci u32 vddc_dly, bb_dly, acpi_dly, vbi_dly; 170762306a36Sopenharmony_ci u32 reference_clock; 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci voltage_response_time = (u32)rdev->pm.dpm.voltage_response_time; 171062306a36Sopenharmony_ci backbias_response_time = (u32)rdev->pm.dpm.backbias_response_time; 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci if (voltage_response_time == 0) 171362306a36Sopenharmony_ci voltage_response_time = 1000; 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ci if (backbias_response_time == 0) 171662306a36Sopenharmony_ci backbias_response_time = 1000; 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci acpi_delay_time = 15000; 171962306a36Sopenharmony_ci vbi_time_out = 100000; 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci reference_clock = radeon_get_xclk(rdev); 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_ci vddc_dly = (voltage_response_time * reference_clock) / 1600; 172462306a36Sopenharmony_ci bb_dly = (backbias_response_time * reference_clock) / 1600; 172562306a36Sopenharmony_ci acpi_dly = (acpi_delay_time * reference_clock) / 1600; 172662306a36Sopenharmony_ci vbi_dly = (vbi_time_out * reference_clock) / 1600; 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci rv770_write_smc_soft_register(rdev, 172962306a36Sopenharmony_ci RV770_SMC_SOFT_REGISTER_delay_vreg, vddc_dly); 173062306a36Sopenharmony_ci rv770_write_smc_soft_register(rdev, 173162306a36Sopenharmony_ci RV770_SMC_SOFT_REGISTER_delay_bbias, bb_dly); 173262306a36Sopenharmony_ci rv770_write_smc_soft_register(rdev, 173362306a36Sopenharmony_ci RV770_SMC_SOFT_REGISTER_delay_acpi, acpi_dly); 173462306a36Sopenharmony_ci rv770_write_smc_soft_register(rdev, 173562306a36Sopenharmony_ci RV770_SMC_SOFT_REGISTER_mclk_chg_timeout, vbi_dly); 173662306a36Sopenharmony_ci#if 0 173762306a36Sopenharmony_ci /* XXX look up hw revision */ 173862306a36Sopenharmony_ci if (WEKIVA_A21) 173962306a36Sopenharmony_ci rv770_write_smc_soft_register(rdev, 174062306a36Sopenharmony_ci RV770_SMC_SOFT_REGISTER_baby_step_timer, 174162306a36Sopenharmony_ci 0x10); 174262306a36Sopenharmony_ci#endif 174362306a36Sopenharmony_ci} 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_cistatic void rv770_program_dcodt_before_state_switch(struct radeon_device *rdev, 174662306a36Sopenharmony_ci struct radeon_ps *radeon_new_state, 174762306a36Sopenharmony_ci struct radeon_ps *radeon_current_state) 174862306a36Sopenharmony_ci{ 174962306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 175062306a36Sopenharmony_ci struct rv7xx_ps *new_state = rv770_get_ps(radeon_new_state); 175162306a36Sopenharmony_ci struct rv7xx_ps *current_state = rv770_get_ps(radeon_current_state); 175262306a36Sopenharmony_ci bool current_use_dc = false; 175362306a36Sopenharmony_ci bool new_use_dc = false; 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci if (pi->mclk_odt_threshold == 0) 175662306a36Sopenharmony_ci return; 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ci if (current_state->high.mclk <= pi->mclk_odt_threshold) 175962306a36Sopenharmony_ci current_use_dc = true; 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci if (new_state->high.mclk <= pi->mclk_odt_threshold) 176262306a36Sopenharmony_ci new_use_dc = true; 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci if (current_use_dc == new_use_dc) 176562306a36Sopenharmony_ci return; 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci if (!current_use_dc && new_use_dc) 176862306a36Sopenharmony_ci return; 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710)) 177162306a36Sopenharmony_ci rv730_program_dcodt(rdev, new_use_dc); 177262306a36Sopenharmony_ci} 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_cistatic void rv770_program_dcodt_after_state_switch(struct radeon_device *rdev, 177562306a36Sopenharmony_ci struct radeon_ps *radeon_new_state, 177662306a36Sopenharmony_ci struct radeon_ps *radeon_current_state) 177762306a36Sopenharmony_ci{ 177862306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 177962306a36Sopenharmony_ci struct rv7xx_ps *new_state = rv770_get_ps(radeon_new_state); 178062306a36Sopenharmony_ci struct rv7xx_ps *current_state = rv770_get_ps(radeon_current_state); 178162306a36Sopenharmony_ci bool current_use_dc = false; 178262306a36Sopenharmony_ci bool new_use_dc = false; 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci if (pi->mclk_odt_threshold == 0) 178562306a36Sopenharmony_ci return; 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci if (current_state->high.mclk <= pi->mclk_odt_threshold) 178862306a36Sopenharmony_ci current_use_dc = true; 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci if (new_state->high.mclk <= pi->mclk_odt_threshold) 179162306a36Sopenharmony_ci new_use_dc = true; 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci if (current_use_dc == new_use_dc) 179462306a36Sopenharmony_ci return; 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci if (current_use_dc && !new_use_dc) 179762306a36Sopenharmony_ci return; 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ci if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710)) 180062306a36Sopenharmony_ci rv730_program_dcodt(rdev, new_use_dc); 180162306a36Sopenharmony_ci} 180262306a36Sopenharmony_ci 180362306a36Sopenharmony_cistatic void rv770_retrieve_odt_values(struct radeon_device *rdev) 180462306a36Sopenharmony_ci{ 180562306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci if (pi->mclk_odt_threshold == 0) 180862306a36Sopenharmony_ci return; 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_ci if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710)) 181162306a36Sopenharmony_ci rv730_get_odt_values(rdev); 181262306a36Sopenharmony_ci} 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_cistatic void rv770_set_dpm_event_sources(struct radeon_device *rdev, u32 sources) 181562306a36Sopenharmony_ci{ 181662306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 181762306a36Sopenharmony_ci bool want_thermal_protection; 181862306a36Sopenharmony_ci enum radeon_dpm_event_src dpm_event_src; 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci switch (sources) { 182162306a36Sopenharmony_ci case 0: 182262306a36Sopenharmony_ci default: 182362306a36Sopenharmony_ci want_thermal_protection = false; 182462306a36Sopenharmony_ci break; 182562306a36Sopenharmony_ci case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL): 182662306a36Sopenharmony_ci want_thermal_protection = true; 182762306a36Sopenharmony_ci dpm_event_src = RADEON_DPM_EVENT_SRC_DIGITAL; 182862306a36Sopenharmony_ci break; 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL): 183162306a36Sopenharmony_ci want_thermal_protection = true; 183262306a36Sopenharmony_ci dpm_event_src = RADEON_DPM_EVENT_SRC_EXTERNAL; 183362306a36Sopenharmony_ci break; 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ci case ((1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL) | 183662306a36Sopenharmony_ci (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL)): 183762306a36Sopenharmony_ci want_thermal_protection = true; 183862306a36Sopenharmony_ci dpm_event_src = RADEON_DPM_EVENT_SRC_DIGIAL_OR_EXTERNAL; 183962306a36Sopenharmony_ci break; 184062306a36Sopenharmony_ci } 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci if (want_thermal_protection) { 184362306a36Sopenharmony_ci WREG32_P(CG_THERMAL_CTRL, DPM_EVENT_SRC(dpm_event_src), ~DPM_EVENT_SRC_MASK); 184462306a36Sopenharmony_ci if (pi->thermal_protection) 184562306a36Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS); 184662306a36Sopenharmony_ci } else { 184762306a36Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS); 184862306a36Sopenharmony_ci } 184962306a36Sopenharmony_ci} 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_civoid rv770_enable_auto_throttle_source(struct radeon_device *rdev, 185262306a36Sopenharmony_ci enum radeon_dpm_auto_throttle_src source, 185362306a36Sopenharmony_ci bool enable) 185462306a36Sopenharmony_ci{ 185562306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci if (enable) { 185862306a36Sopenharmony_ci if (!(pi->active_auto_throttle_sources & (1 << source))) { 185962306a36Sopenharmony_ci pi->active_auto_throttle_sources |= 1 << source; 186062306a36Sopenharmony_ci rv770_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources); 186162306a36Sopenharmony_ci } 186262306a36Sopenharmony_ci } else { 186362306a36Sopenharmony_ci if (pi->active_auto_throttle_sources & (1 << source)) { 186462306a36Sopenharmony_ci pi->active_auto_throttle_sources &= ~(1 << source); 186562306a36Sopenharmony_ci rv770_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources); 186662306a36Sopenharmony_ci } 186762306a36Sopenharmony_ci } 186862306a36Sopenharmony_ci} 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_cistatic int rv770_set_thermal_temperature_range(struct radeon_device *rdev, 187162306a36Sopenharmony_ci int min_temp, int max_temp) 187262306a36Sopenharmony_ci{ 187362306a36Sopenharmony_ci int low_temp = 0 * 1000; 187462306a36Sopenharmony_ci int high_temp = 255 * 1000; 187562306a36Sopenharmony_ci 187662306a36Sopenharmony_ci if (low_temp < min_temp) 187762306a36Sopenharmony_ci low_temp = min_temp; 187862306a36Sopenharmony_ci if (high_temp > max_temp) 187962306a36Sopenharmony_ci high_temp = max_temp; 188062306a36Sopenharmony_ci if (high_temp < low_temp) { 188162306a36Sopenharmony_ci DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp); 188262306a36Sopenharmony_ci return -EINVAL; 188362306a36Sopenharmony_ci } 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci WREG32_P(CG_THERMAL_INT, DIG_THERM_INTH(high_temp / 1000), ~DIG_THERM_INTH_MASK); 188662306a36Sopenharmony_ci WREG32_P(CG_THERMAL_INT, DIG_THERM_INTL(low_temp / 1000), ~DIG_THERM_INTL_MASK); 188762306a36Sopenharmony_ci WREG32_P(CG_THERMAL_CTRL, DIG_THERM_DPM(high_temp / 1000), ~DIG_THERM_DPM_MASK); 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_ci rdev->pm.dpm.thermal.min_temp = low_temp; 189062306a36Sopenharmony_ci rdev->pm.dpm.thermal.max_temp = high_temp; 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci return 0; 189362306a36Sopenharmony_ci} 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ciint rv770_dpm_enable(struct radeon_device *rdev) 189662306a36Sopenharmony_ci{ 189762306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 189862306a36Sopenharmony_ci struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps; 189962306a36Sopenharmony_ci int ret; 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci if (pi->gfx_clock_gating) 190262306a36Sopenharmony_ci rv770_restore_cgcg(rdev); 190362306a36Sopenharmony_ci 190462306a36Sopenharmony_ci if (rv770_dpm_enabled(rdev)) 190562306a36Sopenharmony_ci return -EINVAL; 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci if (pi->voltage_control) { 190862306a36Sopenharmony_ci rv770_enable_voltage_control(rdev, true); 190962306a36Sopenharmony_ci ret = rv770_construct_vddc_table(rdev); 191062306a36Sopenharmony_ci if (ret) { 191162306a36Sopenharmony_ci DRM_ERROR("rv770_construct_vddc_table failed\n"); 191262306a36Sopenharmony_ci return ret; 191362306a36Sopenharmony_ci } 191462306a36Sopenharmony_ci } 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci if (pi->dcodt) 191762306a36Sopenharmony_ci rv770_retrieve_odt_values(rdev); 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_ci if (pi->mvdd_control) { 192062306a36Sopenharmony_ci ret = rv770_get_mvdd_configuration(rdev); 192162306a36Sopenharmony_ci if (ret) { 192262306a36Sopenharmony_ci DRM_ERROR("rv770_get_mvdd_configuration failed\n"); 192362306a36Sopenharmony_ci return ret; 192462306a36Sopenharmony_ci } 192562306a36Sopenharmony_ci } 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_ci if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS) 192862306a36Sopenharmony_ci rv770_enable_backbias(rdev, true); 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci rv770_enable_spread_spectrum(rdev, true); 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci if (pi->thermal_protection) 193362306a36Sopenharmony_ci rv770_enable_thermal_protection(rdev, true); 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_ci rv770_program_mpll_timing_parameters(rdev); 193662306a36Sopenharmony_ci rv770_setup_bsp(rdev); 193762306a36Sopenharmony_ci rv770_program_git(rdev); 193862306a36Sopenharmony_ci rv770_program_tp(rdev); 193962306a36Sopenharmony_ci rv770_program_tpp(rdev); 194062306a36Sopenharmony_ci rv770_program_sstp(rdev); 194162306a36Sopenharmony_ci rv770_program_engine_speed_parameters(rdev); 194262306a36Sopenharmony_ci rv770_enable_display_gap(rdev); 194362306a36Sopenharmony_ci rv770_program_vc(rdev); 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci if (pi->dynamic_pcie_gen2) 194662306a36Sopenharmony_ci rv770_enable_dynamic_pcie_gen2(rdev, true); 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_ci ret = rv770_upload_firmware(rdev); 194962306a36Sopenharmony_ci if (ret) { 195062306a36Sopenharmony_ci DRM_ERROR("rv770_upload_firmware failed\n"); 195162306a36Sopenharmony_ci return ret; 195262306a36Sopenharmony_ci } 195362306a36Sopenharmony_ci ret = rv770_init_smc_table(rdev, boot_ps); 195462306a36Sopenharmony_ci if (ret) { 195562306a36Sopenharmony_ci DRM_ERROR("rv770_init_smc_table failed\n"); 195662306a36Sopenharmony_ci return ret; 195762306a36Sopenharmony_ci } 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_ci rv770_program_response_times(rdev); 196062306a36Sopenharmony_ci r7xx_start_smc(rdev); 196162306a36Sopenharmony_ci 196262306a36Sopenharmony_ci if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710)) 196362306a36Sopenharmony_ci rv730_start_dpm(rdev); 196462306a36Sopenharmony_ci else 196562306a36Sopenharmony_ci rv770_start_dpm(rdev); 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci if (pi->gfx_clock_gating) 196862306a36Sopenharmony_ci rv770_gfx_clock_gating_enable(rdev, true); 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_ci if (pi->mg_clock_gating) 197162306a36Sopenharmony_ci rv770_mg_clock_gating_enable(rdev, true); 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_ci return 0; 197662306a36Sopenharmony_ci} 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ciint rv770_dpm_late_enable(struct radeon_device *rdev) 197962306a36Sopenharmony_ci{ 198062306a36Sopenharmony_ci int ret; 198162306a36Sopenharmony_ci 198262306a36Sopenharmony_ci if (rdev->irq.installed && 198362306a36Sopenharmony_ci r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { 198462306a36Sopenharmony_ci PPSMC_Result result; 198562306a36Sopenharmony_ci 198662306a36Sopenharmony_ci ret = rv770_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); 198762306a36Sopenharmony_ci if (ret) 198862306a36Sopenharmony_ci return ret; 198962306a36Sopenharmony_ci rdev->irq.dpm_thermal = true; 199062306a36Sopenharmony_ci radeon_irq_set(rdev); 199162306a36Sopenharmony_ci result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt); 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci if (result != PPSMC_Result_OK) 199462306a36Sopenharmony_ci DRM_DEBUG_KMS("Could not enable thermal interrupts.\n"); 199562306a36Sopenharmony_ci } 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci return 0; 199862306a36Sopenharmony_ci} 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_civoid rv770_dpm_disable(struct radeon_device *rdev) 200162306a36Sopenharmony_ci{ 200262306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ci if (!rv770_dpm_enabled(rdev)) 200562306a36Sopenharmony_ci return; 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci rv770_clear_vc(rdev); 200862306a36Sopenharmony_ci 200962306a36Sopenharmony_ci if (pi->thermal_protection) 201062306a36Sopenharmony_ci rv770_enable_thermal_protection(rdev, false); 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_ci rv770_enable_spread_spectrum(rdev, false); 201362306a36Sopenharmony_ci 201462306a36Sopenharmony_ci if (pi->dynamic_pcie_gen2) 201562306a36Sopenharmony_ci rv770_enable_dynamic_pcie_gen2(rdev, false); 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_ci if (rdev->irq.installed && 201862306a36Sopenharmony_ci r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { 201962306a36Sopenharmony_ci rdev->irq.dpm_thermal = false; 202062306a36Sopenharmony_ci radeon_irq_set(rdev); 202162306a36Sopenharmony_ci } 202262306a36Sopenharmony_ci 202362306a36Sopenharmony_ci if (pi->gfx_clock_gating) 202462306a36Sopenharmony_ci rv770_gfx_clock_gating_enable(rdev, false); 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_ci if (pi->mg_clock_gating) 202762306a36Sopenharmony_ci rv770_mg_clock_gating_enable(rdev, false); 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_ci if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710)) 203062306a36Sopenharmony_ci rv730_stop_dpm(rdev); 203162306a36Sopenharmony_ci else 203262306a36Sopenharmony_ci rv770_stop_dpm(rdev); 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci r7xx_stop_smc(rdev); 203562306a36Sopenharmony_ci rv770_reset_smio_status(rdev); 203662306a36Sopenharmony_ci} 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ciint rv770_dpm_set_power_state(struct radeon_device *rdev) 203962306a36Sopenharmony_ci{ 204062306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 204162306a36Sopenharmony_ci struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps; 204262306a36Sopenharmony_ci struct radeon_ps *old_ps = rdev->pm.dpm.current_ps; 204362306a36Sopenharmony_ci int ret; 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_ci ret = rv770_restrict_performance_levels_before_switch(rdev); 204662306a36Sopenharmony_ci if (ret) { 204762306a36Sopenharmony_ci DRM_ERROR("rv770_restrict_performance_levels_before_switch failed\n"); 204862306a36Sopenharmony_ci return ret; 204962306a36Sopenharmony_ci } 205062306a36Sopenharmony_ci rv770_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps); 205162306a36Sopenharmony_ci ret = rv770_halt_smc(rdev); 205262306a36Sopenharmony_ci if (ret) { 205362306a36Sopenharmony_ci DRM_ERROR("rv770_halt_smc failed\n"); 205462306a36Sopenharmony_ci return ret; 205562306a36Sopenharmony_ci } 205662306a36Sopenharmony_ci ret = rv770_upload_sw_state(rdev, new_ps); 205762306a36Sopenharmony_ci if (ret) { 205862306a36Sopenharmony_ci DRM_ERROR("rv770_upload_sw_state failed\n"); 205962306a36Sopenharmony_ci return ret; 206062306a36Sopenharmony_ci } 206162306a36Sopenharmony_ci r7xx_program_memory_timing_parameters(rdev, new_ps); 206262306a36Sopenharmony_ci if (pi->dcodt) 206362306a36Sopenharmony_ci rv770_program_dcodt_before_state_switch(rdev, new_ps, old_ps); 206462306a36Sopenharmony_ci ret = rv770_resume_smc(rdev); 206562306a36Sopenharmony_ci if (ret) { 206662306a36Sopenharmony_ci DRM_ERROR("rv770_resume_smc failed\n"); 206762306a36Sopenharmony_ci return ret; 206862306a36Sopenharmony_ci } 206962306a36Sopenharmony_ci ret = rv770_set_sw_state(rdev); 207062306a36Sopenharmony_ci if (ret) { 207162306a36Sopenharmony_ci DRM_ERROR("rv770_set_sw_state failed\n"); 207262306a36Sopenharmony_ci return ret; 207362306a36Sopenharmony_ci } 207462306a36Sopenharmony_ci if (pi->dcodt) 207562306a36Sopenharmony_ci rv770_program_dcodt_after_state_switch(rdev, new_ps, old_ps); 207662306a36Sopenharmony_ci rv770_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps); 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_ci return 0; 207962306a36Sopenharmony_ci} 208062306a36Sopenharmony_ci 208162306a36Sopenharmony_ci#if 0 208262306a36Sopenharmony_civoid rv770_dpm_reset_asic(struct radeon_device *rdev) 208362306a36Sopenharmony_ci{ 208462306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 208562306a36Sopenharmony_ci struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps; 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_ci rv770_restrict_performance_levels_before_switch(rdev); 208862306a36Sopenharmony_ci if (pi->dcodt) 208962306a36Sopenharmony_ci rv770_program_dcodt_before_state_switch(rdev, boot_ps, boot_ps); 209062306a36Sopenharmony_ci rv770_set_boot_state(rdev); 209162306a36Sopenharmony_ci if (pi->dcodt) 209262306a36Sopenharmony_ci rv770_program_dcodt_after_state_switch(rdev, boot_ps, boot_ps); 209362306a36Sopenharmony_ci} 209462306a36Sopenharmony_ci#endif 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_civoid rv770_dpm_setup_asic(struct radeon_device *rdev) 209762306a36Sopenharmony_ci{ 209862306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci r7xx_read_clock_registers(rdev); 210162306a36Sopenharmony_ci rv770_read_voltage_smio_registers(rdev); 210262306a36Sopenharmony_ci rv770_get_memory_type(rdev); 210362306a36Sopenharmony_ci if (pi->dcodt) 210462306a36Sopenharmony_ci rv770_get_mclk_odt_threshold(rdev); 210562306a36Sopenharmony_ci rv770_get_pcie_gen2_status(rdev); 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci rv770_enable_acpi_pm(rdev); 210862306a36Sopenharmony_ci 210962306a36Sopenharmony_ci if (radeon_aspm != 0) { 211062306a36Sopenharmony_ci if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s) 211162306a36Sopenharmony_ci rv770_enable_l0s(rdev); 211262306a36Sopenharmony_ci if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1) 211362306a36Sopenharmony_ci rv770_enable_l1(rdev); 211462306a36Sopenharmony_ci if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1) 211562306a36Sopenharmony_ci rv770_enable_pll_sleep_in_l1(rdev); 211662306a36Sopenharmony_ci } 211762306a36Sopenharmony_ci} 211862306a36Sopenharmony_ci 211962306a36Sopenharmony_civoid rv770_dpm_display_configuration_changed(struct radeon_device *rdev) 212062306a36Sopenharmony_ci{ 212162306a36Sopenharmony_ci rv770_program_display_gap(rdev); 212262306a36Sopenharmony_ci} 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_ciunion power_info { 212562306a36Sopenharmony_ci struct _ATOM_POWERPLAY_INFO info; 212662306a36Sopenharmony_ci struct _ATOM_POWERPLAY_INFO_V2 info_2; 212762306a36Sopenharmony_ci struct _ATOM_POWERPLAY_INFO_V3 info_3; 212862306a36Sopenharmony_ci struct _ATOM_PPLIB_POWERPLAYTABLE pplib; 212962306a36Sopenharmony_ci struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2; 213062306a36Sopenharmony_ci struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3; 213162306a36Sopenharmony_ci}; 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_ciunion pplib_clock_info { 213462306a36Sopenharmony_ci struct _ATOM_PPLIB_R600_CLOCK_INFO r600; 213562306a36Sopenharmony_ci struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780; 213662306a36Sopenharmony_ci struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen; 213762306a36Sopenharmony_ci struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo; 213862306a36Sopenharmony_ci}; 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ciunion pplib_power_state { 214162306a36Sopenharmony_ci struct _ATOM_PPLIB_STATE v1; 214262306a36Sopenharmony_ci struct _ATOM_PPLIB_STATE_V2 v2; 214362306a36Sopenharmony_ci}; 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_cistatic void rv7xx_parse_pplib_non_clock_info(struct radeon_device *rdev, 214662306a36Sopenharmony_ci struct radeon_ps *rps, 214762306a36Sopenharmony_ci struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info, 214862306a36Sopenharmony_ci u8 table_rev) 214962306a36Sopenharmony_ci{ 215062306a36Sopenharmony_ci rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings); 215162306a36Sopenharmony_ci rps->class = le16_to_cpu(non_clock_info->usClassification); 215262306a36Sopenharmony_ci rps->class2 = le16_to_cpu(non_clock_info->usClassification2); 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ci if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) { 215562306a36Sopenharmony_ci rps->vclk = le32_to_cpu(non_clock_info->ulVCLK); 215662306a36Sopenharmony_ci rps->dclk = le32_to_cpu(non_clock_info->ulDCLK); 215762306a36Sopenharmony_ci } else { 215862306a36Sopenharmony_ci rps->vclk = 0; 215962306a36Sopenharmony_ci rps->dclk = 0; 216062306a36Sopenharmony_ci } 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_ci if (r600_is_uvd_state(rps->class, rps->class2)) { 216362306a36Sopenharmony_ci if ((rps->vclk == 0) || (rps->dclk == 0)) { 216462306a36Sopenharmony_ci rps->vclk = RV770_DEFAULT_VCLK_FREQ; 216562306a36Sopenharmony_ci rps->dclk = RV770_DEFAULT_DCLK_FREQ; 216662306a36Sopenharmony_ci } 216762306a36Sopenharmony_ci } 216862306a36Sopenharmony_ci 216962306a36Sopenharmony_ci if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) 217062306a36Sopenharmony_ci rdev->pm.dpm.boot_ps = rps; 217162306a36Sopenharmony_ci if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) 217262306a36Sopenharmony_ci rdev->pm.dpm.uvd_ps = rps; 217362306a36Sopenharmony_ci} 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_cistatic void rv7xx_parse_pplib_clock_info(struct radeon_device *rdev, 217662306a36Sopenharmony_ci struct radeon_ps *rps, int index, 217762306a36Sopenharmony_ci union pplib_clock_info *clock_info) 217862306a36Sopenharmony_ci{ 217962306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 218062306a36Sopenharmony_ci struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); 218162306a36Sopenharmony_ci struct rv7xx_ps *ps = rv770_get_ps(rps); 218262306a36Sopenharmony_ci u32 sclk, mclk; 218362306a36Sopenharmony_ci struct rv7xx_pl *pl; 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ci switch (index) { 218662306a36Sopenharmony_ci case 0: 218762306a36Sopenharmony_ci pl = &ps->low; 218862306a36Sopenharmony_ci break; 218962306a36Sopenharmony_ci case 1: 219062306a36Sopenharmony_ci pl = &ps->medium; 219162306a36Sopenharmony_ci break; 219262306a36Sopenharmony_ci case 2: 219362306a36Sopenharmony_ci default: 219462306a36Sopenharmony_ci pl = &ps->high; 219562306a36Sopenharmony_ci break; 219662306a36Sopenharmony_ci } 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci if (rdev->family >= CHIP_CEDAR) { 219962306a36Sopenharmony_ci sclk = le16_to_cpu(clock_info->evergreen.usEngineClockLow); 220062306a36Sopenharmony_ci sclk |= clock_info->evergreen.ucEngineClockHigh << 16; 220162306a36Sopenharmony_ci mclk = le16_to_cpu(clock_info->evergreen.usMemoryClockLow); 220262306a36Sopenharmony_ci mclk |= clock_info->evergreen.ucMemoryClockHigh << 16; 220362306a36Sopenharmony_ci 220462306a36Sopenharmony_ci pl->vddc = le16_to_cpu(clock_info->evergreen.usVDDC); 220562306a36Sopenharmony_ci pl->vddci = le16_to_cpu(clock_info->evergreen.usVDDCI); 220662306a36Sopenharmony_ci pl->flags = le32_to_cpu(clock_info->evergreen.ulFlags); 220762306a36Sopenharmony_ci } else { 220862306a36Sopenharmony_ci sclk = le16_to_cpu(clock_info->r600.usEngineClockLow); 220962306a36Sopenharmony_ci sclk |= clock_info->r600.ucEngineClockHigh << 16; 221062306a36Sopenharmony_ci mclk = le16_to_cpu(clock_info->r600.usMemoryClockLow); 221162306a36Sopenharmony_ci mclk |= clock_info->r600.ucMemoryClockHigh << 16; 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci pl->vddc = le16_to_cpu(clock_info->r600.usVDDC); 221462306a36Sopenharmony_ci pl->flags = le32_to_cpu(clock_info->r600.ulFlags); 221562306a36Sopenharmony_ci } 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci pl->mclk = mclk; 221862306a36Sopenharmony_ci pl->sclk = sclk; 221962306a36Sopenharmony_ci 222062306a36Sopenharmony_ci /* patch up vddc if necessary */ 222162306a36Sopenharmony_ci if (pl->vddc == 0xff01) { 222262306a36Sopenharmony_ci if (pi->max_vddc) 222362306a36Sopenharmony_ci pl->vddc = pi->max_vddc; 222462306a36Sopenharmony_ci } 222562306a36Sopenharmony_ci 222662306a36Sopenharmony_ci if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) { 222762306a36Sopenharmony_ci pi->acpi_vddc = pl->vddc; 222862306a36Sopenharmony_ci if (rdev->family >= CHIP_CEDAR) 222962306a36Sopenharmony_ci eg_pi->acpi_vddci = pl->vddci; 223062306a36Sopenharmony_ci if (ps->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) 223162306a36Sopenharmony_ci pi->acpi_pcie_gen2 = true; 223262306a36Sopenharmony_ci else 223362306a36Sopenharmony_ci pi->acpi_pcie_gen2 = false; 223462306a36Sopenharmony_ci } 223562306a36Sopenharmony_ci 223662306a36Sopenharmony_ci if (rps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) { 223762306a36Sopenharmony_ci if (rdev->family >= CHIP_BARTS) { 223862306a36Sopenharmony_ci eg_pi->ulv.supported = true; 223962306a36Sopenharmony_ci eg_pi->ulv.pl = pl; 224062306a36Sopenharmony_ci } 224162306a36Sopenharmony_ci } 224262306a36Sopenharmony_ci 224362306a36Sopenharmony_ci if (pi->min_vddc_in_table > pl->vddc) 224462306a36Sopenharmony_ci pi->min_vddc_in_table = pl->vddc; 224562306a36Sopenharmony_ci 224662306a36Sopenharmony_ci if (pi->max_vddc_in_table < pl->vddc) 224762306a36Sopenharmony_ci pi->max_vddc_in_table = pl->vddc; 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci /* patch up boot state */ 225062306a36Sopenharmony_ci if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) { 225162306a36Sopenharmony_ci u16 vddc, vddci, mvdd; 225262306a36Sopenharmony_ci radeon_atombios_get_default_voltages(rdev, &vddc, &vddci, &mvdd); 225362306a36Sopenharmony_ci pl->mclk = rdev->clock.default_mclk; 225462306a36Sopenharmony_ci pl->sclk = rdev->clock.default_sclk; 225562306a36Sopenharmony_ci pl->vddc = vddc; 225662306a36Sopenharmony_ci pl->vddci = vddci; 225762306a36Sopenharmony_ci } 225862306a36Sopenharmony_ci 225962306a36Sopenharmony_ci if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == 226062306a36Sopenharmony_ci ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) { 226162306a36Sopenharmony_ci rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk = pl->sclk; 226262306a36Sopenharmony_ci rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.mclk = pl->mclk; 226362306a36Sopenharmony_ci rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddc = pl->vddc; 226462306a36Sopenharmony_ci rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddci = pl->vddci; 226562306a36Sopenharmony_ci } 226662306a36Sopenharmony_ci} 226762306a36Sopenharmony_ci 226862306a36Sopenharmony_ciint rv7xx_parse_power_table(struct radeon_device *rdev) 226962306a36Sopenharmony_ci{ 227062306a36Sopenharmony_ci struct radeon_mode_info *mode_info = &rdev->mode_info; 227162306a36Sopenharmony_ci struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; 227262306a36Sopenharmony_ci union pplib_power_state *power_state; 227362306a36Sopenharmony_ci int i, j; 227462306a36Sopenharmony_ci union pplib_clock_info *clock_info; 227562306a36Sopenharmony_ci union power_info *power_info; 227662306a36Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); 227762306a36Sopenharmony_ci u16 data_offset; 227862306a36Sopenharmony_ci u8 frev, crev; 227962306a36Sopenharmony_ci struct rv7xx_ps *ps; 228062306a36Sopenharmony_ci 228162306a36Sopenharmony_ci if (!atom_parse_data_header(mode_info->atom_context, index, NULL, 228262306a36Sopenharmony_ci &frev, &crev, &data_offset)) 228362306a36Sopenharmony_ci return -EINVAL; 228462306a36Sopenharmony_ci power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); 228562306a36Sopenharmony_ci 228662306a36Sopenharmony_ci rdev->pm.dpm.ps = kcalloc(power_info->pplib.ucNumStates, 228762306a36Sopenharmony_ci sizeof(struct radeon_ps), 228862306a36Sopenharmony_ci GFP_KERNEL); 228962306a36Sopenharmony_ci if (!rdev->pm.dpm.ps) 229062306a36Sopenharmony_ci return -ENOMEM; 229162306a36Sopenharmony_ci 229262306a36Sopenharmony_ci for (i = 0; i < power_info->pplib.ucNumStates; i++) { 229362306a36Sopenharmony_ci power_state = (union pplib_power_state *) 229462306a36Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 229562306a36Sopenharmony_ci le16_to_cpu(power_info->pplib.usStateArrayOffset) + 229662306a36Sopenharmony_ci i * power_info->pplib.ucStateEntrySize); 229762306a36Sopenharmony_ci non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) 229862306a36Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 229962306a36Sopenharmony_ci le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) + 230062306a36Sopenharmony_ci (power_state->v1.ucNonClockStateIndex * 230162306a36Sopenharmony_ci power_info->pplib.ucNonClockSize)); 230262306a36Sopenharmony_ci if (power_info->pplib.ucStateEntrySize - 1) { 230362306a36Sopenharmony_ci u8 *idx; 230462306a36Sopenharmony_ci ps = kzalloc(sizeof(struct rv7xx_ps), GFP_KERNEL); 230562306a36Sopenharmony_ci if (ps == NULL) { 230662306a36Sopenharmony_ci kfree(rdev->pm.dpm.ps); 230762306a36Sopenharmony_ci return -ENOMEM; 230862306a36Sopenharmony_ci } 230962306a36Sopenharmony_ci rdev->pm.dpm.ps[i].ps_priv = ps; 231062306a36Sopenharmony_ci rv7xx_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i], 231162306a36Sopenharmony_ci non_clock_info, 231262306a36Sopenharmony_ci power_info->pplib.ucNonClockSize); 231362306a36Sopenharmony_ci idx = (u8 *)&power_state->v1.ucClockStateIndices[0]; 231462306a36Sopenharmony_ci for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) { 231562306a36Sopenharmony_ci clock_info = (union pplib_clock_info *) 231662306a36Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 231762306a36Sopenharmony_ci le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) + 231862306a36Sopenharmony_ci (idx[j] * power_info->pplib.ucClockInfoSize)); 231962306a36Sopenharmony_ci rv7xx_parse_pplib_clock_info(rdev, 232062306a36Sopenharmony_ci &rdev->pm.dpm.ps[i], j, 232162306a36Sopenharmony_ci clock_info); 232262306a36Sopenharmony_ci } 232362306a36Sopenharmony_ci } 232462306a36Sopenharmony_ci } 232562306a36Sopenharmony_ci rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates; 232662306a36Sopenharmony_ci return 0; 232762306a36Sopenharmony_ci} 232862306a36Sopenharmony_ci 232962306a36Sopenharmony_civoid rv770_get_engine_memory_ss(struct radeon_device *rdev) 233062306a36Sopenharmony_ci{ 233162306a36Sopenharmony_ci struct rv7xx_power_info *pi = rv770_get_pi(rdev); 233262306a36Sopenharmony_ci struct radeon_atom_ss ss; 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci pi->sclk_ss = radeon_atombios_get_asic_ss_info(rdev, &ss, 233562306a36Sopenharmony_ci ASIC_INTERNAL_ENGINE_SS, 0); 233662306a36Sopenharmony_ci pi->mclk_ss = radeon_atombios_get_asic_ss_info(rdev, &ss, 233762306a36Sopenharmony_ci ASIC_INTERNAL_MEMORY_SS, 0); 233862306a36Sopenharmony_ci 233962306a36Sopenharmony_ci if (pi->sclk_ss || pi->mclk_ss) 234062306a36Sopenharmony_ci pi->dynamic_ss = true; 234162306a36Sopenharmony_ci else 234262306a36Sopenharmony_ci pi->dynamic_ss = false; 234362306a36Sopenharmony_ci} 234462306a36Sopenharmony_ci 234562306a36Sopenharmony_ciint rv770_dpm_init(struct radeon_device *rdev) 234662306a36Sopenharmony_ci{ 234762306a36Sopenharmony_ci struct rv7xx_power_info *pi; 234862306a36Sopenharmony_ci struct atom_clock_dividers dividers; 234962306a36Sopenharmony_ci int ret; 235062306a36Sopenharmony_ci 235162306a36Sopenharmony_ci pi = kzalloc(sizeof(struct rv7xx_power_info), GFP_KERNEL); 235262306a36Sopenharmony_ci if (pi == NULL) 235362306a36Sopenharmony_ci return -ENOMEM; 235462306a36Sopenharmony_ci rdev->pm.dpm.priv = pi; 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ci rv770_get_max_vddc(rdev); 235762306a36Sopenharmony_ci 235862306a36Sopenharmony_ci pi->acpi_vddc = 0; 235962306a36Sopenharmony_ci pi->min_vddc_in_table = 0; 236062306a36Sopenharmony_ci pi->max_vddc_in_table = 0; 236162306a36Sopenharmony_ci 236262306a36Sopenharmony_ci ret = r600_get_platform_caps(rdev); 236362306a36Sopenharmony_ci if (ret) 236462306a36Sopenharmony_ci return ret; 236562306a36Sopenharmony_ci 236662306a36Sopenharmony_ci ret = rv7xx_parse_power_table(rdev); 236762306a36Sopenharmony_ci if (ret) 236862306a36Sopenharmony_ci return ret; 236962306a36Sopenharmony_ci 237062306a36Sopenharmony_ci if (rdev->pm.dpm.voltage_response_time == 0) 237162306a36Sopenharmony_ci rdev->pm.dpm.voltage_response_time = R600_VOLTAGERESPONSETIME_DFLT; 237262306a36Sopenharmony_ci if (rdev->pm.dpm.backbias_response_time == 0) 237362306a36Sopenharmony_ci rdev->pm.dpm.backbias_response_time = R600_BACKBIASRESPONSETIME_DFLT; 237462306a36Sopenharmony_ci 237562306a36Sopenharmony_ci ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, 237662306a36Sopenharmony_ci 0, false, ÷rs); 237762306a36Sopenharmony_ci if (ret) 237862306a36Sopenharmony_ci pi->ref_div = dividers.ref_div + 1; 237962306a36Sopenharmony_ci else 238062306a36Sopenharmony_ci pi->ref_div = R600_REFERENCEDIVIDER_DFLT; 238162306a36Sopenharmony_ci 238262306a36Sopenharmony_ci pi->mclk_strobe_mode_threshold = 30000; 238362306a36Sopenharmony_ci pi->mclk_edc_enable_threshold = 30000; 238462306a36Sopenharmony_ci 238562306a36Sopenharmony_ci pi->rlp = RV770_RLP_DFLT; 238662306a36Sopenharmony_ci pi->rmp = RV770_RMP_DFLT; 238762306a36Sopenharmony_ci pi->lhp = RV770_LHP_DFLT; 238862306a36Sopenharmony_ci pi->lmp = RV770_LMP_DFLT; 238962306a36Sopenharmony_ci 239062306a36Sopenharmony_ci pi->voltage_control = 239162306a36Sopenharmony_ci radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, 0); 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_ci pi->mvdd_control = 239462306a36Sopenharmony_ci radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_MVDDC, 0); 239562306a36Sopenharmony_ci 239662306a36Sopenharmony_ci rv770_get_engine_memory_ss(rdev); 239762306a36Sopenharmony_ci 239862306a36Sopenharmony_ci pi->asi = RV770_ASI_DFLT; 239962306a36Sopenharmony_ci pi->pasi = RV770_HASI_DFLT; 240062306a36Sopenharmony_ci pi->vrc = RV770_VRC_DFLT; 240162306a36Sopenharmony_ci 240262306a36Sopenharmony_ci pi->power_gating = false; 240362306a36Sopenharmony_ci 240462306a36Sopenharmony_ci pi->gfx_clock_gating = true; 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci pi->mg_clock_gating = true; 240762306a36Sopenharmony_ci pi->mgcgtssm = true; 240862306a36Sopenharmony_ci 240962306a36Sopenharmony_ci pi->dynamic_pcie_gen2 = true; 241062306a36Sopenharmony_ci 241162306a36Sopenharmony_ci if (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE) 241262306a36Sopenharmony_ci pi->thermal_protection = true; 241362306a36Sopenharmony_ci else 241462306a36Sopenharmony_ci pi->thermal_protection = false; 241562306a36Sopenharmony_ci 241662306a36Sopenharmony_ci pi->display_gap = true; 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_ci if (rdev->flags & RADEON_IS_MOBILITY) 241962306a36Sopenharmony_ci pi->dcodt = true; 242062306a36Sopenharmony_ci else 242162306a36Sopenharmony_ci pi->dcodt = false; 242262306a36Sopenharmony_ci 242362306a36Sopenharmony_ci pi->ulps = true; 242462306a36Sopenharmony_ci 242562306a36Sopenharmony_ci pi->mclk_stutter_mode_threshold = 0; 242662306a36Sopenharmony_ci 242762306a36Sopenharmony_ci pi->sram_end = SMC_RAM_END; 242862306a36Sopenharmony_ci pi->state_table_start = RV770_SMC_TABLE_ADDRESS; 242962306a36Sopenharmony_ci pi->soft_regs_start = RV770_SMC_SOFT_REGISTERS_START; 243062306a36Sopenharmony_ci 243162306a36Sopenharmony_ci return 0; 243262306a36Sopenharmony_ci} 243362306a36Sopenharmony_ci 243462306a36Sopenharmony_civoid rv770_dpm_print_power_state(struct radeon_device *rdev, 243562306a36Sopenharmony_ci struct radeon_ps *rps) 243662306a36Sopenharmony_ci{ 243762306a36Sopenharmony_ci struct rv7xx_ps *ps = rv770_get_ps(rps); 243862306a36Sopenharmony_ci struct rv7xx_pl *pl; 243962306a36Sopenharmony_ci 244062306a36Sopenharmony_ci r600_dpm_print_class_info(rps->class, rps->class2); 244162306a36Sopenharmony_ci r600_dpm_print_cap_info(rps->caps); 244262306a36Sopenharmony_ci printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); 244362306a36Sopenharmony_ci if (rdev->family >= CHIP_CEDAR) { 244462306a36Sopenharmony_ci pl = &ps->low; 244562306a36Sopenharmony_ci printk("\t\tpower level 0 sclk: %u mclk: %u vddc: %u vddci: %u\n", 244662306a36Sopenharmony_ci pl->sclk, pl->mclk, pl->vddc, pl->vddci); 244762306a36Sopenharmony_ci pl = &ps->medium; 244862306a36Sopenharmony_ci printk("\t\tpower level 1 sclk: %u mclk: %u vddc: %u vddci: %u\n", 244962306a36Sopenharmony_ci pl->sclk, pl->mclk, pl->vddc, pl->vddci); 245062306a36Sopenharmony_ci pl = &ps->high; 245162306a36Sopenharmony_ci printk("\t\tpower level 2 sclk: %u mclk: %u vddc: %u vddci: %u\n", 245262306a36Sopenharmony_ci pl->sclk, pl->mclk, pl->vddc, pl->vddci); 245362306a36Sopenharmony_ci } else { 245462306a36Sopenharmony_ci pl = &ps->low; 245562306a36Sopenharmony_ci printk("\t\tpower level 0 sclk: %u mclk: %u vddc: %u\n", 245662306a36Sopenharmony_ci pl->sclk, pl->mclk, pl->vddc); 245762306a36Sopenharmony_ci pl = &ps->medium; 245862306a36Sopenharmony_ci printk("\t\tpower level 1 sclk: %u mclk: %u vddc: %u\n", 245962306a36Sopenharmony_ci pl->sclk, pl->mclk, pl->vddc); 246062306a36Sopenharmony_ci pl = &ps->high; 246162306a36Sopenharmony_ci printk("\t\tpower level 2 sclk: %u mclk: %u vddc: %u\n", 246262306a36Sopenharmony_ci pl->sclk, pl->mclk, pl->vddc); 246362306a36Sopenharmony_ci } 246462306a36Sopenharmony_ci r600_dpm_print_ps_status(rdev, rps); 246562306a36Sopenharmony_ci} 246662306a36Sopenharmony_ci 246762306a36Sopenharmony_civoid rv770_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, 246862306a36Sopenharmony_ci struct seq_file *m) 246962306a36Sopenharmony_ci{ 247062306a36Sopenharmony_ci struct radeon_ps *rps = rdev->pm.dpm.current_ps; 247162306a36Sopenharmony_ci struct rv7xx_ps *ps = rv770_get_ps(rps); 247262306a36Sopenharmony_ci struct rv7xx_pl *pl; 247362306a36Sopenharmony_ci u32 current_index = 247462306a36Sopenharmony_ci (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >> 247562306a36Sopenharmony_ci CURRENT_PROFILE_INDEX_SHIFT; 247662306a36Sopenharmony_ci 247762306a36Sopenharmony_ci if (current_index > 2) { 247862306a36Sopenharmony_ci seq_printf(m, "invalid dpm profile %d\n", current_index); 247962306a36Sopenharmony_ci } else { 248062306a36Sopenharmony_ci if (current_index == 0) 248162306a36Sopenharmony_ci pl = &ps->low; 248262306a36Sopenharmony_ci else if (current_index == 1) 248362306a36Sopenharmony_ci pl = &ps->medium; 248462306a36Sopenharmony_ci else /* current_index == 2 */ 248562306a36Sopenharmony_ci pl = &ps->high; 248662306a36Sopenharmony_ci seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); 248762306a36Sopenharmony_ci if (rdev->family >= CHIP_CEDAR) { 248862306a36Sopenharmony_ci seq_printf(m, "power level %d sclk: %u mclk: %u vddc: %u vddci: %u\n", 248962306a36Sopenharmony_ci current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci); 249062306a36Sopenharmony_ci } else { 249162306a36Sopenharmony_ci seq_printf(m, "power level %d sclk: %u mclk: %u vddc: %u\n", 249262306a36Sopenharmony_ci current_index, pl->sclk, pl->mclk, pl->vddc); 249362306a36Sopenharmony_ci } 249462306a36Sopenharmony_ci } 249562306a36Sopenharmony_ci} 249662306a36Sopenharmony_ci 249762306a36Sopenharmony_ciu32 rv770_dpm_get_current_sclk(struct radeon_device *rdev) 249862306a36Sopenharmony_ci{ 249962306a36Sopenharmony_ci struct radeon_ps *rps = rdev->pm.dpm.current_ps; 250062306a36Sopenharmony_ci struct rv7xx_ps *ps = rv770_get_ps(rps); 250162306a36Sopenharmony_ci struct rv7xx_pl *pl; 250262306a36Sopenharmony_ci u32 current_index = 250362306a36Sopenharmony_ci (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >> 250462306a36Sopenharmony_ci CURRENT_PROFILE_INDEX_SHIFT; 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_ci if (current_index > 2) { 250762306a36Sopenharmony_ci return 0; 250862306a36Sopenharmony_ci } else { 250962306a36Sopenharmony_ci if (current_index == 0) 251062306a36Sopenharmony_ci pl = &ps->low; 251162306a36Sopenharmony_ci else if (current_index == 1) 251262306a36Sopenharmony_ci pl = &ps->medium; 251362306a36Sopenharmony_ci else /* current_index == 2 */ 251462306a36Sopenharmony_ci pl = &ps->high; 251562306a36Sopenharmony_ci return pl->sclk; 251662306a36Sopenharmony_ci } 251762306a36Sopenharmony_ci} 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_ciu32 rv770_dpm_get_current_mclk(struct radeon_device *rdev) 252062306a36Sopenharmony_ci{ 252162306a36Sopenharmony_ci struct radeon_ps *rps = rdev->pm.dpm.current_ps; 252262306a36Sopenharmony_ci struct rv7xx_ps *ps = rv770_get_ps(rps); 252362306a36Sopenharmony_ci struct rv7xx_pl *pl; 252462306a36Sopenharmony_ci u32 current_index = 252562306a36Sopenharmony_ci (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >> 252662306a36Sopenharmony_ci CURRENT_PROFILE_INDEX_SHIFT; 252762306a36Sopenharmony_ci 252862306a36Sopenharmony_ci if (current_index > 2) { 252962306a36Sopenharmony_ci return 0; 253062306a36Sopenharmony_ci } else { 253162306a36Sopenharmony_ci if (current_index == 0) 253262306a36Sopenharmony_ci pl = &ps->low; 253362306a36Sopenharmony_ci else if (current_index == 1) 253462306a36Sopenharmony_ci pl = &ps->medium; 253562306a36Sopenharmony_ci else /* current_index == 2 */ 253662306a36Sopenharmony_ci pl = &ps->high; 253762306a36Sopenharmony_ci return pl->mclk; 253862306a36Sopenharmony_ci } 253962306a36Sopenharmony_ci} 254062306a36Sopenharmony_ci 254162306a36Sopenharmony_civoid rv770_dpm_fini(struct radeon_device *rdev) 254262306a36Sopenharmony_ci{ 254362306a36Sopenharmony_ci int i; 254462306a36Sopenharmony_ci 254562306a36Sopenharmony_ci for (i = 0; i < rdev->pm.dpm.num_ps; i++) { 254662306a36Sopenharmony_ci kfree(rdev->pm.dpm.ps[i].ps_priv); 254762306a36Sopenharmony_ci } 254862306a36Sopenharmony_ci kfree(rdev->pm.dpm.ps); 254962306a36Sopenharmony_ci kfree(rdev->pm.dpm.priv); 255062306a36Sopenharmony_ci} 255162306a36Sopenharmony_ci 255262306a36Sopenharmony_ciu32 rv770_dpm_get_sclk(struct radeon_device *rdev, bool low) 255362306a36Sopenharmony_ci{ 255462306a36Sopenharmony_ci struct rv7xx_ps *requested_state = rv770_get_ps(rdev->pm.dpm.requested_ps); 255562306a36Sopenharmony_ci 255662306a36Sopenharmony_ci if (low) 255762306a36Sopenharmony_ci return requested_state->low.sclk; 255862306a36Sopenharmony_ci else 255962306a36Sopenharmony_ci return requested_state->high.sclk; 256062306a36Sopenharmony_ci} 256162306a36Sopenharmony_ci 256262306a36Sopenharmony_ciu32 rv770_dpm_get_mclk(struct radeon_device *rdev, bool low) 256362306a36Sopenharmony_ci{ 256462306a36Sopenharmony_ci struct rv7xx_ps *requested_state = rv770_get_ps(rdev->pm.dpm.requested_ps); 256562306a36Sopenharmony_ci 256662306a36Sopenharmony_ci if (low) 256762306a36Sopenharmony_ci return requested_state->low.mclk; 256862306a36Sopenharmony_ci else 256962306a36Sopenharmony_ci return requested_state->high.mclk; 257062306a36Sopenharmony_ci} 257162306a36Sopenharmony_ci 257262306a36Sopenharmony_cibool rv770_dpm_vblank_too_short(struct radeon_device *rdev) 257362306a36Sopenharmony_ci{ 257462306a36Sopenharmony_ci u32 vblank_time = r600_dpm_get_vblank_time(rdev); 257562306a36Sopenharmony_ci u32 switch_limit = 200; /* 300 */ 257662306a36Sopenharmony_ci 257762306a36Sopenharmony_ci /* RV770 */ 257862306a36Sopenharmony_ci /* mclk switching doesn't seem to work reliably on desktop RV770s */ 257962306a36Sopenharmony_ci if ((rdev->family == CHIP_RV770) && 258062306a36Sopenharmony_ci !(rdev->flags & RADEON_IS_MOBILITY)) 258162306a36Sopenharmony_ci switch_limit = 0xffffffff; /* disable mclk switching */ 258262306a36Sopenharmony_ci 258362306a36Sopenharmony_ci if (vblank_time < switch_limit) 258462306a36Sopenharmony_ci return true; 258562306a36Sopenharmony_ci else 258662306a36Sopenharmony_ci return false; 258762306a36Sopenharmony_ci 258862306a36Sopenharmony_ci} 2589