157e252bfSMichael Neumann /* 257e252bfSMichael Neumann * Copyright 2011 Advanced Micro Devices, Inc. 357e252bfSMichael Neumann * 457e252bfSMichael Neumann * Permission is hereby granted, free of charge, to any person obtaining a 557e252bfSMichael Neumann * copy of this software and associated documentation files (the "Software"), 657e252bfSMichael Neumann * to deal in the Software without restriction, including without limitation 757e252bfSMichael Neumann * the rights to use, copy, modify, merge, publish, distribute, sublicense, 857e252bfSMichael Neumann * and/or sell copies of the Software, and to permit persons to whom the 957e252bfSMichael Neumann * Software is furnished to do so, subject to the following conditions: 1057e252bfSMichael Neumann * 1157e252bfSMichael Neumann * The above copyright notice and this permission notice shall be included in 1257e252bfSMichael Neumann * all copies or substantial portions of the Software. 1357e252bfSMichael Neumann * 1457e252bfSMichael Neumann * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1557e252bfSMichael Neumann * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1657e252bfSMichael Neumann * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1757e252bfSMichael Neumann * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 1857e252bfSMichael Neumann * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 1957e252bfSMichael Neumann * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2057e252bfSMichael Neumann * OTHER DEALINGS IN THE SOFTWARE. 2157e252bfSMichael Neumann * 2257e252bfSMichael Neumann * Authors: Alex Deucher 2357e252bfSMichael Neumann */ 2457e252bfSMichael Neumann 2557e252bfSMichael Neumann #include <drm/drmP.h> 2657e252bfSMichael Neumann #include "radeon.h" 2757e252bfSMichael Neumann #include "radeon_asic.h" 2857e252bfSMichael Neumann #include "rv6xxd.h" 2957e252bfSMichael Neumann #include "r600_dpm.h" 3057e252bfSMichael Neumann #include "rv6xx_dpm.h" 3157e252bfSMichael Neumann #include "atom.h" 3257e252bfSMichael Neumann #include <linux/seq_file.h> 3357e252bfSMichael Neumann 3457e252bfSMichael Neumann static u32 rv6xx_scale_count_given_unit(struct radeon_device *rdev, 3557e252bfSMichael Neumann u32 unscaled_count, u32 unit); 3657e252bfSMichael Neumann 3757e252bfSMichael Neumann static struct rv6xx_ps *rv6xx_get_ps(struct radeon_ps *rps) 3857e252bfSMichael Neumann { 3957e252bfSMichael Neumann struct rv6xx_ps *ps = rps->ps_priv; 4057e252bfSMichael Neumann 4157e252bfSMichael Neumann return ps; 4257e252bfSMichael Neumann } 4357e252bfSMichael Neumann 4457e252bfSMichael Neumann static struct rv6xx_power_info *rv6xx_get_pi(struct radeon_device *rdev) 4557e252bfSMichael Neumann { 4657e252bfSMichael Neumann struct rv6xx_power_info *pi = rdev->pm.dpm.priv; 4757e252bfSMichael Neumann 4857e252bfSMichael Neumann return pi; 4957e252bfSMichael Neumann } 5057e252bfSMichael Neumann 5157e252bfSMichael Neumann static void rv6xx_force_pcie_gen1(struct radeon_device *rdev) 5257e252bfSMichael Neumann { 5357e252bfSMichael Neumann u32 tmp; 5457e252bfSMichael Neumann int i; 5557e252bfSMichael Neumann 5657e252bfSMichael Neumann tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); 5757e252bfSMichael Neumann tmp &= LC_GEN2_EN; 5857e252bfSMichael Neumann WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); 5957e252bfSMichael Neumann 6057e252bfSMichael Neumann tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); 6157e252bfSMichael Neumann tmp |= LC_INITIATE_LINK_SPEED_CHANGE; 6257e252bfSMichael Neumann WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); 6357e252bfSMichael Neumann 6457e252bfSMichael Neumann for (i = 0; i < rdev->usec_timeout; i++) { 6557e252bfSMichael Neumann if (!(RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL) & LC_CURRENT_DATA_RATE)) 6657e252bfSMichael Neumann break; 67c4ef309bSzrj udelay(1); 6857e252bfSMichael Neumann } 6957e252bfSMichael Neumann 7057e252bfSMichael Neumann tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); 7157e252bfSMichael Neumann tmp &= ~LC_INITIATE_LINK_SPEED_CHANGE; 7257e252bfSMichael Neumann WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); 7357e252bfSMichael Neumann } 7457e252bfSMichael Neumann 7557e252bfSMichael Neumann static void rv6xx_enable_pcie_gen2_support(struct radeon_device *rdev) 7657e252bfSMichael Neumann { 7757e252bfSMichael Neumann u32 tmp; 7857e252bfSMichael Neumann 7957e252bfSMichael Neumann tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); 8057e252bfSMichael Neumann 8157e252bfSMichael Neumann if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) && 8257e252bfSMichael Neumann (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2)) { 8357e252bfSMichael Neumann tmp |= LC_GEN2_EN; 8457e252bfSMichael Neumann WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); 8557e252bfSMichael Neumann } 8657e252bfSMichael Neumann } 8757e252bfSMichael Neumann 8857e252bfSMichael Neumann static void rv6xx_enable_bif_dynamic_pcie_gen2(struct radeon_device *rdev, 8957e252bfSMichael Neumann bool enable) 9057e252bfSMichael Neumann { 9157e252bfSMichael Neumann u32 tmp; 9257e252bfSMichael Neumann 9357e252bfSMichael Neumann tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL) & ~LC_HW_VOLTAGE_IF_CONTROL_MASK; 9457e252bfSMichael Neumann if (enable) 9557e252bfSMichael Neumann tmp |= LC_HW_VOLTAGE_IF_CONTROL(1); 9657e252bfSMichael Neumann else 9757e252bfSMichael Neumann tmp |= LC_HW_VOLTAGE_IF_CONTROL(0); 9857e252bfSMichael Neumann WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); 9957e252bfSMichael Neumann } 10057e252bfSMichael Neumann 10157e252bfSMichael Neumann static void rv6xx_enable_l0s(struct radeon_device *rdev) 10257e252bfSMichael Neumann { 10357e252bfSMichael Neumann u32 tmp; 10457e252bfSMichael Neumann 10557e252bfSMichael Neumann tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL) & ~LC_L0S_INACTIVITY_MASK; 10657e252bfSMichael Neumann tmp |= LC_L0S_INACTIVITY(3); 10757e252bfSMichael Neumann WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp); 10857e252bfSMichael Neumann } 10957e252bfSMichael Neumann 11057e252bfSMichael Neumann static void rv6xx_enable_l1(struct radeon_device *rdev) 11157e252bfSMichael Neumann { 11257e252bfSMichael Neumann u32 tmp; 11357e252bfSMichael Neumann 11457e252bfSMichael Neumann tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL); 11557e252bfSMichael Neumann tmp &= ~LC_L1_INACTIVITY_MASK; 11657e252bfSMichael Neumann tmp |= LC_L1_INACTIVITY(4); 11757e252bfSMichael Neumann tmp &= ~LC_PMI_TO_L1_DIS; 11857e252bfSMichael Neumann tmp &= ~LC_ASPM_TO_L1_DIS; 11957e252bfSMichael Neumann WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp); 12057e252bfSMichael Neumann } 12157e252bfSMichael Neumann 12257e252bfSMichael Neumann static void rv6xx_enable_pll_sleep_in_l1(struct radeon_device *rdev) 12357e252bfSMichael Neumann { 12457e252bfSMichael Neumann u32 tmp; 12557e252bfSMichael Neumann 12657e252bfSMichael Neumann tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL) & ~LC_L1_INACTIVITY_MASK; 12757e252bfSMichael Neumann tmp |= LC_L1_INACTIVITY(8); 12857e252bfSMichael Neumann WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp); 12957e252bfSMichael Neumann 13057e252bfSMichael Neumann /* NOTE, this is a PCIE indirect reg, not PCIE PORT */ 13157e252bfSMichael Neumann tmp = RREG32_PCIE(PCIE_P_CNTL); 13257e252bfSMichael Neumann tmp |= P_PLL_PWRDN_IN_L1L23; 13357e252bfSMichael Neumann tmp &= ~P_PLL_BUF_PDNB; 13457e252bfSMichael Neumann tmp &= ~P_PLL_PDNB; 13557e252bfSMichael Neumann tmp |= P_ALLOW_PRX_FRONTEND_SHUTOFF; 13657e252bfSMichael Neumann WREG32_PCIE(PCIE_P_CNTL, tmp); 13757e252bfSMichael Neumann } 13857e252bfSMichael Neumann 13957e252bfSMichael Neumann static int rv6xx_convert_clock_to_stepping(struct radeon_device *rdev, 14057e252bfSMichael Neumann u32 clock, struct rv6xx_sclk_stepping *step) 14157e252bfSMichael Neumann { 14257e252bfSMichael Neumann int ret; 14357e252bfSMichael Neumann struct atom_clock_dividers dividers; 14457e252bfSMichael Neumann 14557e252bfSMichael Neumann ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, 14657e252bfSMichael Neumann clock, false, ÷rs); 14757e252bfSMichael Neumann if (ret) 14857e252bfSMichael Neumann return ret; 14957e252bfSMichael Neumann 15057e252bfSMichael Neumann if (dividers.enable_post_div) 15157e252bfSMichael Neumann step->post_divider = 2 + (dividers.post_div & 0xF) + (dividers.post_div >> 4); 15257e252bfSMichael Neumann else 15357e252bfSMichael Neumann step->post_divider = 1; 15457e252bfSMichael Neumann 15557e252bfSMichael Neumann step->vco_frequency = clock * step->post_divider; 15657e252bfSMichael Neumann 15757e252bfSMichael Neumann return 0; 15857e252bfSMichael Neumann } 15957e252bfSMichael Neumann 16057e252bfSMichael Neumann static void rv6xx_output_stepping(struct radeon_device *rdev, 16157e252bfSMichael Neumann u32 step_index, struct rv6xx_sclk_stepping *step) 16257e252bfSMichael Neumann { 16357e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 16457e252bfSMichael Neumann u32 ref_clk = rdev->clock.spll.reference_freq; 16557e252bfSMichael Neumann u32 fb_divider; 16657e252bfSMichael Neumann u32 spll_step_count = rv6xx_scale_count_given_unit(rdev, 16757e252bfSMichael Neumann R600_SPLLSTEPTIME_DFLT * 16857e252bfSMichael Neumann pi->spll_ref_div, 16957e252bfSMichael Neumann R600_SPLLSTEPUNIT_DFLT); 17057e252bfSMichael Neumann 17157e252bfSMichael Neumann r600_engine_clock_entry_enable(rdev, step_index, true); 17257e252bfSMichael Neumann r600_engine_clock_entry_enable_pulse_skipping(rdev, step_index, false); 17357e252bfSMichael Neumann 17457e252bfSMichael Neumann if (step->post_divider == 1) 17557e252bfSMichael Neumann r600_engine_clock_entry_enable_post_divider(rdev, step_index, false); 17657e252bfSMichael Neumann else { 17757e252bfSMichael Neumann u32 lo_len = (step->post_divider - 2) / 2; 17857e252bfSMichael Neumann u32 hi_len = step->post_divider - 2 - lo_len; 17957e252bfSMichael Neumann 18057e252bfSMichael Neumann r600_engine_clock_entry_enable_post_divider(rdev, step_index, true); 18157e252bfSMichael Neumann r600_engine_clock_entry_set_post_divider(rdev, step_index, (hi_len << 4) | lo_len); 18257e252bfSMichael Neumann } 18357e252bfSMichael Neumann 18457e252bfSMichael Neumann fb_divider = ((step->vco_frequency * pi->spll_ref_div) / ref_clk) >> 18557e252bfSMichael Neumann pi->fb_div_scale; 18657e252bfSMichael Neumann 18757e252bfSMichael Neumann r600_engine_clock_entry_set_reference_divider(rdev, step_index, 18857e252bfSMichael Neumann pi->spll_ref_div - 1); 18957e252bfSMichael Neumann r600_engine_clock_entry_set_feedback_divider(rdev, step_index, fb_divider); 19057e252bfSMichael Neumann r600_engine_clock_entry_set_step_time(rdev, step_index, spll_step_count); 19157e252bfSMichael Neumann 19257e252bfSMichael Neumann } 19357e252bfSMichael Neumann 19457e252bfSMichael Neumann static struct rv6xx_sclk_stepping rv6xx_next_vco_step(struct radeon_device *rdev, 19557e252bfSMichael Neumann struct rv6xx_sclk_stepping *cur, 19657e252bfSMichael Neumann bool increasing_vco, u32 step_size) 19757e252bfSMichael Neumann { 19857e252bfSMichael Neumann struct rv6xx_sclk_stepping next; 19957e252bfSMichael Neumann 20057e252bfSMichael Neumann next.post_divider = cur->post_divider; 20157e252bfSMichael Neumann 20257e252bfSMichael Neumann if (increasing_vco) 20357e252bfSMichael Neumann next.vco_frequency = (cur->vco_frequency * (100 + step_size)) / 100; 20457e252bfSMichael Neumann else 20557e252bfSMichael Neumann next.vco_frequency = (cur->vco_frequency * 100 + 99 + step_size) / (100 + step_size); 20657e252bfSMichael Neumann 20757e252bfSMichael Neumann return next; 20857e252bfSMichael Neumann } 20957e252bfSMichael Neumann 21057e252bfSMichael Neumann static bool rv6xx_can_step_post_div(struct radeon_device *rdev, 21157e252bfSMichael Neumann struct rv6xx_sclk_stepping *cur, 21257e252bfSMichael Neumann struct rv6xx_sclk_stepping *target) 21357e252bfSMichael Neumann { 21457e252bfSMichael Neumann return (cur->post_divider > target->post_divider) && 21557e252bfSMichael Neumann ((cur->vco_frequency * target->post_divider) <= 21657e252bfSMichael Neumann (target->vco_frequency * (cur->post_divider - 1))); 21757e252bfSMichael Neumann } 21857e252bfSMichael Neumann 21957e252bfSMichael Neumann static struct rv6xx_sclk_stepping rv6xx_next_post_div_step(struct radeon_device *rdev, 22057e252bfSMichael Neumann struct rv6xx_sclk_stepping *cur, 22157e252bfSMichael Neumann struct rv6xx_sclk_stepping *target) 22257e252bfSMichael Neumann { 22357e252bfSMichael Neumann struct rv6xx_sclk_stepping next = *cur; 22457e252bfSMichael Neumann 22557e252bfSMichael Neumann while (rv6xx_can_step_post_div(rdev, &next, target)) 22657e252bfSMichael Neumann next.post_divider--; 22757e252bfSMichael Neumann 22857e252bfSMichael Neumann return next; 22957e252bfSMichael Neumann } 23057e252bfSMichael Neumann 23157e252bfSMichael Neumann static bool rv6xx_reached_stepping_target(struct radeon_device *rdev, 23257e252bfSMichael Neumann struct rv6xx_sclk_stepping *cur, 23357e252bfSMichael Neumann struct rv6xx_sclk_stepping *target, 23457e252bfSMichael Neumann bool increasing_vco) 23557e252bfSMichael Neumann { 23657e252bfSMichael Neumann return (increasing_vco && (cur->vco_frequency >= target->vco_frequency)) || 23757e252bfSMichael Neumann (!increasing_vco && (cur->vco_frequency <= target->vco_frequency)); 23857e252bfSMichael Neumann } 23957e252bfSMichael Neumann 24057e252bfSMichael Neumann static void rv6xx_generate_steps(struct radeon_device *rdev, 24157e252bfSMichael Neumann u32 low, u32 high, 24257e252bfSMichael Neumann u32 start_index, u8 *end_index) 24357e252bfSMichael Neumann { 24457e252bfSMichael Neumann struct rv6xx_sclk_stepping cur; 24557e252bfSMichael Neumann struct rv6xx_sclk_stepping target; 24657e252bfSMichael Neumann bool increasing_vco; 24757e252bfSMichael Neumann u32 step_index = start_index; 24857e252bfSMichael Neumann 24957e252bfSMichael Neumann rv6xx_convert_clock_to_stepping(rdev, low, &cur); 25057e252bfSMichael Neumann rv6xx_convert_clock_to_stepping(rdev, high, &target); 25157e252bfSMichael Neumann 25257e252bfSMichael Neumann rv6xx_output_stepping(rdev, step_index++, &cur); 25357e252bfSMichael Neumann 25457e252bfSMichael Neumann increasing_vco = (target.vco_frequency >= cur.vco_frequency); 25557e252bfSMichael Neumann 25657e252bfSMichael Neumann if (target.post_divider > cur.post_divider) 25757e252bfSMichael Neumann cur.post_divider = target.post_divider; 25857e252bfSMichael Neumann 25957e252bfSMichael Neumann while (1) { 26057e252bfSMichael Neumann struct rv6xx_sclk_stepping next; 26157e252bfSMichael Neumann 26257e252bfSMichael Neumann if (rv6xx_can_step_post_div(rdev, &cur, &target)) 26357e252bfSMichael Neumann next = rv6xx_next_post_div_step(rdev, &cur, &target); 26457e252bfSMichael Neumann else 26557e252bfSMichael Neumann next = rv6xx_next_vco_step(rdev, &cur, increasing_vco, R600_VCOSTEPPCT_DFLT); 26657e252bfSMichael Neumann 26757e252bfSMichael Neumann if (rv6xx_reached_stepping_target(rdev, &next, &target, increasing_vco)) { 26857e252bfSMichael Neumann struct rv6xx_sclk_stepping tiny = 26957e252bfSMichael Neumann rv6xx_next_vco_step(rdev, &target, !increasing_vco, R600_ENDINGVCOSTEPPCT_DFLT); 27057e252bfSMichael Neumann tiny.post_divider = next.post_divider; 27157e252bfSMichael Neumann 27257e252bfSMichael Neumann if (!rv6xx_reached_stepping_target(rdev, &tiny, &cur, !increasing_vco)) 27357e252bfSMichael Neumann rv6xx_output_stepping(rdev, step_index++, &tiny); 27457e252bfSMichael Neumann 27557e252bfSMichael Neumann if ((next.post_divider != target.post_divider) && 27657e252bfSMichael Neumann (next.vco_frequency != target.vco_frequency)) { 27757e252bfSMichael Neumann struct rv6xx_sclk_stepping final_vco; 27857e252bfSMichael Neumann 27957e252bfSMichael Neumann final_vco.vco_frequency = target.vco_frequency; 28057e252bfSMichael Neumann final_vco.post_divider = next.post_divider; 28157e252bfSMichael Neumann 28257e252bfSMichael Neumann rv6xx_output_stepping(rdev, step_index++, &final_vco); 28357e252bfSMichael Neumann } 28457e252bfSMichael Neumann 28557e252bfSMichael Neumann rv6xx_output_stepping(rdev, step_index++, &target); 28657e252bfSMichael Neumann break; 28757e252bfSMichael Neumann } else 28857e252bfSMichael Neumann rv6xx_output_stepping(rdev, step_index++, &next); 28957e252bfSMichael Neumann 29057e252bfSMichael Neumann cur = next; 29157e252bfSMichael Neumann } 29257e252bfSMichael Neumann 29357e252bfSMichael Neumann *end_index = (u8)step_index - 1; 29457e252bfSMichael Neumann 29557e252bfSMichael Neumann } 29657e252bfSMichael Neumann 29757e252bfSMichael Neumann static void rv6xx_generate_single_step(struct radeon_device *rdev, 29857e252bfSMichael Neumann u32 clock, u32 index) 29957e252bfSMichael Neumann { 30057e252bfSMichael Neumann struct rv6xx_sclk_stepping step; 30157e252bfSMichael Neumann 30257e252bfSMichael Neumann rv6xx_convert_clock_to_stepping(rdev, clock, &step); 30357e252bfSMichael Neumann rv6xx_output_stepping(rdev, index, &step); 30457e252bfSMichael Neumann } 30557e252bfSMichael Neumann 30657e252bfSMichael Neumann static void rv6xx_invalidate_intermediate_steps_range(struct radeon_device *rdev, 30757e252bfSMichael Neumann u32 start_index, u32 end_index) 30857e252bfSMichael Neumann { 30957e252bfSMichael Neumann u32 step_index; 31057e252bfSMichael Neumann 31157e252bfSMichael Neumann for (step_index = start_index + 1; step_index < end_index; step_index++) 31257e252bfSMichael Neumann r600_engine_clock_entry_enable(rdev, step_index, false); 31357e252bfSMichael Neumann } 31457e252bfSMichael Neumann 31557e252bfSMichael Neumann static void rv6xx_set_engine_spread_spectrum_clk_s(struct radeon_device *rdev, 31657e252bfSMichael Neumann u32 index, u32 clk_s) 31757e252bfSMichael Neumann { 31857e252bfSMichael Neumann WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4), 31957e252bfSMichael Neumann CLKS(clk_s), ~CLKS_MASK); 32057e252bfSMichael Neumann } 32157e252bfSMichael Neumann 32257e252bfSMichael Neumann static void rv6xx_set_engine_spread_spectrum_clk_v(struct radeon_device *rdev, 32357e252bfSMichael Neumann u32 index, u32 clk_v) 32457e252bfSMichael Neumann { 32557e252bfSMichael Neumann WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4), 32657e252bfSMichael Neumann CLKV(clk_v), ~CLKV_MASK); 32757e252bfSMichael Neumann } 32857e252bfSMichael Neumann 32957e252bfSMichael Neumann static void rv6xx_enable_engine_spread_spectrum(struct radeon_device *rdev, 33057e252bfSMichael Neumann u32 index, bool enable) 33157e252bfSMichael Neumann { 33257e252bfSMichael Neumann if (enable) 33357e252bfSMichael Neumann WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4), 33457e252bfSMichael Neumann SSEN, ~SSEN); 33557e252bfSMichael Neumann else 33657e252bfSMichael Neumann WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4), 33757e252bfSMichael Neumann 0, ~SSEN); 33857e252bfSMichael Neumann } 33957e252bfSMichael Neumann 34057e252bfSMichael Neumann static void rv6xx_set_memory_spread_spectrum_clk_s(struct radeon_device *rdev, 34157e252bfSMichael Neumann u32 clk_s) 34257e252bfSMichael Neumann { 34357e252bfSMichael Neumann WREG32_P(CG_MPLL_SPREAD_SPECTRUM, CLKS(clk_s), ~CLKS_MASK); 34457e252bfSMichael Neumann } 34557e252bfSMichael Neumann 34657e252bfSMichael Neumann static void rv6xx_set_memory_spread_spectrum_clk_v(struct radeon_device *rdev, 34757e252bfSMichael Neumann u32 clk_v) 34857e252bfSMichael Neumann { 34957e252bfSMichael Neumann WREG32_P(CG_MPLL_SPREAD_SPECTRUM, CLKV(clk_v), ~CLKV_MASK); 35057e252bfSMichael Neumann } 35157e252bfSMichael Neumann 35257e252bfSMichael Neumann static void rv6xx_enable_memory_spread_spectrum(struct radeon_device *rdev, 35357e252bfSMichael Neumann bool enable) 35457e252bfSMichael Neumann { 35557e252bfSMichael Neumann if (enable) 35657e252bfSMichael Neumann WREG32_P(CG_MPLL_SPREAD_SPECTRUM, SSEN, ~SSEN); 35757e252bfSMichael Neumann else 35857e252bfSMichael Neumann WREG32_P(CG_MPLL_SPREAD_SPECTRUM, 0, ~SSEN); 35957e252bfSMichael Neumann } 36057e252bfSMichael Neumann 36157e252bfSMichael Neumann static void rv6xx_enable_dynamic_spread_spectrum(struct radeon_device *rdev, 36257e252bfSMichael Neumann bool enable) 36357e252bfSMichael Neumann { 36457e252bfSMichael Neumann if (enable) 36557e252bfSMichael Neumann WREG32_P(GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, ~DYN_SPREAD_SPECTRUM_EN); 36657e252bfSMichael Neumann else 36757e252bfSMichael Neumann WREG32_P(GENERAL_PWRMGT, 0, ~DYN_SPREAD_SPECTRUM_EN); 36857e252bfSMichael Neumann } 36957e252bfSMichael Neumann 37057e252bfSMichael Neumann static void rv6xx_memory_clock_entry_enable_post_divider(struct radeon_device *rdev, 37157e252bfSMichael Neumann u32 index, bool enable) 37257e252bfSMichael Neumann { 37357e252bfSMichael Neumann if (enable) 37457e252bfSMichael Neumann WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4), 37557e252bfSMichael Neumann LEVEL0_MPLL_DIV_EN, ~LEVEL0_MPLL_DIV_EN); 37657e252bfSMichael Neumann else 37757e252bfSMichael Neumann WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4), 0, ~LEVEL0_MPLL_DIV_EN); 37857e252bfSMichael Neumann } 37957e252bfSMichael Neumann 38057e252bfSMichael Neumann static void rv6xx_memory_clock_entry_set_post_divider(struct radeon_device *rdev, 38157e252bfSMichael Neumann u32 index, u32 divider) 38257e252bfSMichael Neumann { 38357e252bfSMichael Neumann WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4), 38457e252bfSMichael Neumann LEVEL0_MPLL_POST_DIV(divider), ~LEVEL0_MPLL_POST_DIV_MASK); 38557e252bfSMichael Neumann } 38657e252bfSMichael Neumann 38757e252bfSMichael Neumann static void rv6xx_memory_clock_entry_set_feedback_divider(struct radeon_device *rdev, 38857e252bfSMichael Neumann u32 index, u32 divider) 38957e252bfSMichael Neumann { 39057e252bfSMichael Neumann WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4), LEVEL0_MPLL_FB_DIV(divider), 39157e252bfSMichael Neumann ~LEVEL0_MPLL_FB_DIV_MASK); 39257e252bfSMichael Neumann } 39357e252bfSMichael Neumann 39457e252bfSMichael Neumann static void rv6xx_memory_clock_entry_set_reference_divider(struct radeon_device *rdev, 39557e252bfSMichael Neumann u32 index, u32 divider) 39657e252bfSMichael Neumann { 39757e252bfSMichael Neumann WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4), 39857e252bfSMichael Neumann LEVEL0_MPLL_REF_DIV(divider), ~LEVEL0_MPLL_REF_DIV_MASK); 39957e252bfSMichael Neumann } 40057e252bfSMichael Neumann 40157e252bfSMichael Neumann static void rv6xx_vid_response_set_brt(struct radeon_device *rdev, u32 rt) 40257e252bfSMichael Neumann { 40357e252bfSMichael Neumann WREG32_P(VID_RT, BRT(rt), ~BRT_MASK); 40457e252bfSMichael Neumann } 40557e252bfSMichael Neumann 40657e252bfSMichael Neumann static void rv6xx_enable_engine_feedback_and_reference_sync(struct radeon_device *rdev) 40757e252bfSMichael Neumann { 40857e252bfSMichael Neumann WREG32_P(SPLL_CNTL_MODE, SPLL_DIV_SYNC, ~SPLL_DIV_SYNC); 40957e252bfSMichael Neumann } 41057e252bfSMichael Neumann 41157e252bfSMichael Neumann static u64 rv6xx_clocks_per_unit(u32 unit) 41257e252bfSMichael Neumann { 41357e252bfSMichael Neumann u64 tmp = 1 << (2 * unit); 41457e252bfSMichael Neumann 41557e252bfSMichael Neumann return tmp; 41657e252bfSMichael Neumann } 41757e252bfSMichael Neumann 41857e252bfSMichael Neumann static u32 rv6xx_scale_count_given_unit(struct radeon_device *rdev, 41957e252bfSMichael Neumann u32 unscaled_count, u32 unit) 42057e252bfSMichael Neumann { 42157e252bfSMichael Neumann u32 count_per_unit = (u32)rv6xx_clocks_per_unit(unit); 42257e252bfSMichael Neumann 42357e252bfSMichael Neumann return (unscaled_count + count_per_unit - 1) / count_per_unit; 42457e252bfSMichael Neumann } 42557e252bfSMichael Neumann 42657e252bfSMichael Neumann static u32 rv6xx_compute_count_for_delay(struct radeon_device *rdev, 42757e252bfSMichael Neumann u32 delay_us, u32 unit) 42857e252bfSMichael Neumann { 42957e252bfSMichael Neumann u32 ref_clk = rdev->clock.spll.reference_freq; 43057e252bfSMichael Neumann 43157e252bfSMichael Neumann return rv6xx_scale_count_given_unit(rdev, delay_us * (ref_clk / 100), unit); 43257e252bfSMichael Neumann } 43357e252bfSMichael Neumann 43457e252bfSMichael Neumann static void rv6xx_calculate_engine_speed_stepping_parameters(struct radeon_device *rdev, 43557e252bfSMichael Neumann struct rv6xx_ps *state) 43657e252bfSMichael Neumann { 43757e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 43857e252bfSMichael Neumann 43957e252bfSMichael Neumann pi->hw.sclks[R600_POWER_LEVEL_LOW] = 44057e252bfSMichael Neumann state->low.sclk; 44157e252bfSMichael Neumann pi->hw.sclks[R600_POWER_LEVEL_MEDIUM] = 44257e252bfSMichael Neumann state->medium.sclk; 44357e252bfSMichael Neumann pi->hw.sclks[R600_POWER_LEVEL_HIGH] = 44457e252bfSMichael Neumann state->high.sclk; 44557e252bfSMichael Neumann 44657e252bfSMichael Neumann pi->hw.low_sclk_index = R600_POWER_LEVEL_LOW; 44757e252bfSMichael Neumann pi->hw.medium_sclk_index = R600_POWER_LEVEL_MEDIUM; 44857e252bfSMichael Neumann pi->hw.high_sclk_index = R600_POWER_LEVEL_HIGH; 44957e252bfSMichael Neumann } 45057e252bfSMichael Neumann 45157e252bfSMichael Neumann static void rv6xx_calculate_memory_clock_stepping_parameters(struct radeon_device *rdev, 45257e252bfSMichael Neumann struct rv6xx_ps *state) 45357e252bfSMichael Neumann { 45457e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 45557e252bfSMichael Neumann 45657e252bfSMichael Neumann pi->hw.mclks[R600_POWER_LEVEL_CTXSW] = 45757e252bfSMichael Neumann state->high.mclk; 45857e252bfSMichael Neumann pi->hw.mclks[R600_POWER_LEVEL_HIGH] = 45957e252bfSMichael Neumann state->high.mclk; 46057e252bfSMichael Neumann pi->hw.mclks[R600_POWER_LEVEL_MEDIUM] = 46157e252bfSMichael Neumann state->medium.mclk; 46257e252bfSMichael Neumann pi->hw.mclks[R600_POWER_LEVEL_LOW] = 46357e252bfSMichael Neumann state->low.mclk; 46457e252bfSMichael Neumann 46557e252bfSMichael Neumann pi->hw.high_mclk_index = R600_POWER_LEVEL_HIGH; 46657e252bfSMichael Neumann 46757e252bfSMichael Neumann if (state->high.mclk == state->medium.mclk) 46857e252bfSMichael Neumann pi->hw.medium_mclk_index = 46957e252bfSMichael Neumann pi->hw.high_mclk_index; 47057e252bfSMichael Neumann else 47157e252bfSMichael Neumann pi->hw.medium_mclk_index = R600_POWER_LEVEL_MEDIUM; 47257e252bfSMichael Neumann 47357e252bfSMichael Neumann 47457e252bfSMichael Neumann if (state->medium.mclk == state->low.mclk) 47557e252bfSMichael Neumann pi->hw.low_mclk_index = 47657e252bfSMichael Neumann pi->hw.medium_mclk_index; 47757e252bfSMichael Neumann else 47857e252bfSMichael Neumann pi->hw.low_mclk_index = R600_POWER_LEVEL_LOW; 47957e252bfSMichael Neumann } 48057e252bfSMichael Neumann 48157e252bfSMichael Neumann static void rv6xx_calculate_voltage_stepping_parameters(struct radeon_device *rdev, 48257e252bfSMichael Neumann struct rv6xx_ps *state) 48357e252bfSMichael Neumann { 48457e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 48557e252bfSMichael Neumann 48657e252bfSMichael Neumann pi->hw.vddc[R600_POWER_LEVEL_CTXSW] = state->high.vddc; 48757e252bfSMichael Neumann pi->hw.vddc[R600_POWER_LEVEL_HIGH] = state->high.vddc; 48857e252bfSMichael Neumann pi->hw.vddc[R600_POWER_LEVEL_MEDIUM] = state->medium.vddc; 48957e252bfSMichael Neumann pi->hw.vddc[R600_POWER_LEVEL_LOW] = state->low.vddc; 49057e252bfSMichael Neumann 49157e252bfSMichael Neumann pi->hw.backbias[R600_POWER_LEVEL_CTXSW] = 49257e252bfSMichael Neumann (state->high.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false; 49357e252bfSMichael Neumann pi->hw.backbias[R600_POWER_LEVEL_HIGH] = 49457e252bfSMichael Neumann (state->high.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false; 49557e252bfSMichael Neumann pi->hw.backbias[R600_POWER_LEVEL_MEDIUM] = 49657e252bfSMichael Neumann (state->medium.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false; 49757e252bfSMichael Neumann pi->hw.backbias[R600_POWER_LEVEL_LOW] = 49857e252bfSMichael Neumann (state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false; 49957e252bfSMichael Neumann 50057e252bfSMichael Neumann pi->hw.pcie_gen2[R600_POWER_LEVEL_HIGH] = 50157e252bfSMichael Neumann (state->high.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? true : false; 50257e252bfSMichael Neumann pi->hw.pcie_gen2[R600_POWER_LEVEL_MEDIUM] = 50357e252bfSMichael Neumann (state->medium.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? true : false; 50457e252bfSMichael Neumann pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW] = 50557e252bfSMichael Neumann (state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? true : false; 50657e252bfSMichael Neumann 50757e252bfSMichael Neumann pi->hw.high_vddc_index = R600_POWER_LEVEL_HIGH; 50857e252bfSMichael Neumann 50957e252bfSMichael Neumann if ((state->high.vddc == state->medium.vddc) && 51057e252bfSMichael Neumann ((state->high.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) == 51157e252bfSMichael Neumann (state->medium.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE))) 51257e252bfSMichael Neumann pi->hw.medium_vddc_index = 51357e252bfSMichael Neumann pi->hw.high_vddc_index; 51457e252bfSMichael Neumann else 51557e252bfSMichael Neumann pi->hw.medium_vddc_index = R600_POWER_LEVEL_MEDIUM; 51657e252bfSMichael Neumann 51757e252bfSMichael Neumann if ((state->medium.vddc == state->low.vddc) && 51857e252bfSMichael Neumann ((state->medium.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) == 51957e252bfSMichael Neumann (state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE))) 52057e252bfSMichael Neumann pi->hw.low_vddc_index = 52157e252bfSMichael Neumann pi->hw.medium_vddc_index; 52257e252bfSMichael Neumann else 52357e252bfSMichael Neumann pi->hw.medium_vddc_index = R600_POWER_LEVEL_LOW; 52457e252bfSMichael Neumann } 52557e252bfSMichael Neumann 52657e252bfSMichael Neumann static inline u32 rv6xx_calculate_vco_frequency(u32 ref_clock, 52757e252bfSMichael Neumann struct atom_clock_dividers *dividers, 52857e252bfSMichael Neumann u32 fb_divider_scale) 52957e252bfSMichael Neumann { 53057e252bfSMichael Neumann return ref_clock * ((dividers->fb_div & ~1) << fb_divider_scale) / 53157e252bfSMichael Neumann (dividers->ref_div + 1); 53257e252bfSMichael Neumann } 53357e252bfSMichael Neumann 53457e252bfSMichael Neumann static inline u32 rv6xx_calculate_spread_spectrum_clk_v(u32 vco_freq, u32 ref_freq, 53557e252bfSMichael Neumann u32 ss_rate, u32 ss_percent, 53657e252bfSMichael Neumann u32 fb_divider_scale) 53757e252bfSMichael Neumann { 53857e252bfSMichael Neumann u32 fb_divider = vco_freq / ref_freq; 53957e252bfSMichael Neumann 54057e252bfSMichael Neumann return (ss_percent * ss_rate * 4 * (fb_divider * fb_divider) / 54157e252bfSMichael Neumann (5375 * ((vco_freq * 10) / (4096 >> fb_divider_scale)))); 54257e252bfSMichael Neumann } 54357e252bfSMichael Neumann 54457e252bfSMichael Neumann static inline u32 rv6xx_calculate_spread_spectrum_clk_s(u32 ss_rate, u32 ref_freq) 54557e252bfSMichael Neumann { 54657e252bfSMichael Neumann return (((ref_freq * 10) / (ss_rate * 2)) - 1) / 4; 54757e252bfSMichael Neumann } 54857e252bfSMichael Neumann 54957e252bfSMichael Neumann static void rv6xx_program_engine_spread_spectrum(struct radeon_device *rdev, 55057e252bfSMichael Neumann u32 clock, enum r600_power_level level) 55157e252bfSMichael Neumann { 55257e252bfSMichael Neumann u32 ref_clk = rdev->clock.spll.reference_freq; 55357e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 55457e252bfSMichael Neumann struct atom_clock_dividers dividers; 55557e252bfSMichael Neumann struct radeon_atom_ss ss; 55657e252bfSMichael Neumann u32 vco_freq, clk_v, clk_s; 55757e252bfSMichael Neumann 55857e252bfSMichael Neumann rv6xx_enable_engine_spread_spectrum(rdev, level, false); 55957e252bfSMichael Neumann 56057e252bfSMichael Neumann if (clock && pi->sclk_ss) { 56157e252bfSMichael Neumann if (radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, clock, false, ÷rs) == 0) { 56257e252bfSMichael Neumann vco_freq = rv6xx_calculate_vco_frequency(ref_clk, ÷rs, 56357e252bfSMichael Neumann pi->fb_div_scale); 56457e252bfSMichael Neumann 56557e252bfSMichael Neumann if (radeon_atombios_get_asic_ss_info(rdev, &ss, 56657e252bfSMichael Neumann ASIC_INTERNAL_ENGINE_SS, vco_freq)) { 56757e252bfSMichael Neumann clk_v = rv6xx_calculate_spread_spectrum_clk_v(vco_freq, 56857e252bfSMichael Neumann (ref_clk / (dividers.ref_div + 1)), 56957e252bfSMichael Neumann ss.rate, 57057e252bfSMichael Neumann ss.percentage, 57157e252bfSMichael Neumann pi->fb_div_scale); 57257e252bfSMichael Neumann 57357e252bfSMichael Neumann clk_s = rv6xx_calculate_spread_spectrum_clk_s(ss.rate, 57457e252bfSMichael Neumann (ref_clk / (dividers.ref_div + 1))); 57557e252bfSMichael Neumann 57657e252bfSMichael Neumann rv6xx_set_engine_spread_spectrum_clk_v(rdev, level, clk_v); 57757e252bfSMichael Neumann rv6xx_set_engine_spread_spectrum_clk_s(rdev, level, clk_s); 57857e252bfSMichael Neumann rv6xx_enable_engine_spread_spectrum(rdev, level, true); 57957e252bfSMichael Neumann } 58057e252bfSMichael Neumann } 58157e252bfSMichael Neumann } 58257e252bfSMichael Neumann } 58357e252bfSMichael Neumann 58457e252bfSMichael Neumann static void rv6xx_program_sclk_spread_spectrum_parameters_except_lowest_entry(struct radeon_device *rdev) 58557e252bfSMichael Neumann { 58657e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 58757e252bfSMichael Neumann 58857e252bfSMichael Neumann rv6xx_program_engine_spread_spectrum(rdev, 58957e252bfSMichael Neumann pi->hw.sclks[R600_POWER_LEVEL_HIGH], 59057e252bfSMichael Neumann R600_POWER_LEVEL_HIGH); 59157e252bfSMichael Neumann 59257e252bfSMichael Neumann rv6xx_program_engine_spread_spectrum(rdev, 59357e252bfSMichael Neumann pi->hw.sclks[R600_POWER_LEVEL_MEDIUM], 59457e252bfSMichael Neumann R600_POWER_LEVEL_MEDIUM); 59557e252bfSMichael Neumann 59657e252bfSMichael Neumann } 59757e252bfSMichael Neumann 59857e252bfSMichael Neumann static int rv6xx_program_mclk_stepping_entry(struct radeon_device *rdev, 59957e252bfSMichael Neumann u32 entry, u32 clock) 60057e252bfSMichael Neumann { 60157e252bfSMichael Neumann struct atom_clock_dividers dividers; 60257e252bfSMichael Neumann 60357e252bfSMichael Neumann if (radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM, clock, false, ÷rs)) 60457e252bfSMichael Neumann return -EINVAL; 60557e252bfSMichael Neumann 60657e252bfSMichael Neumann 60757e252bfSMichael Neumann rv6xx_memory_clock_entry_set_reference_divider(rdev, entry, dividers.ref_div); 60857e252bfSMichael Neumann rv6xx_memory_clock_entry_set_feedback_divider(rdev, entry, dividers.fb_div); 60957e252bfSMichael Neumann rv6xx_memory_clock_entry_set_post_divider(rdev, entry, dividers.post_div); 61057e252bfSMichael Neumann 61157e252bfSMichael Neumann if (dividers.enable_post_div) 61257e252bfSMichael Neumann rv6xx_memory_clock_entry_enable_post_divider(rdev, entry, true); 61357e252bfSMichael Neumann else 61457e252bfSMichael Neumann rv6xx_memory_clock_entry_enable_post_divider(rdev, entry, false); 61557e252bfSMichael Neumann 61657e252bfSMichael Neumann return 0; 61757e252bfSMichael Neumann } 61857e252bfSMichael Neumann 61957e252bfSMichael Neumann static void rv6xx_program_mclk_stepping_parameters_except_lowest_entry(struct radeon_device *rdev) 62057e252bfSMichael Neumann { 62157e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 62257e252bfSMichael Neumann int i; 62357e252bfSMichael Neumann 62457e252bfSMichael Neumann for (i = 1; i < R600_PM_NUMBER_OF_MCLKS; i++) { 62557e252bfSMichael Neumann if (pi->hw.mclks[i]) 62657e252bfSMichael Neumann rv6xx_program_mclk_stepping_entry(rdev, i, 62757e252bfSMichael Neumann pi->hw.mclks[i]); 62857e252bfSMichael Neumann } 62957e252bfSMichael Neumann } 63057e252bfSMichael Neumann 63157e252bfSMichael Neumann static void rv6xx_find_memory_clock_with_highest_vco(struct radeon_device *rdev, 63257e252bfSMichael Neumann u32 requested_memory_clock, 63357e252bfSMichael Neumann u32 ref_clk, 63457e252bfSMichael Neumann struct atom_clock_dividers *dividers, 63557e252bfSMichael Neumann u32 *vco_freq) 63657e252bfSMichael Neumann { 63757e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 63857e252bfSMichael Neumann struct atom_clock_dividers req_dividers; 63957e252bfSMichael Neumann u32 vco_freq_temp; 64057e252bfSMichael Neumann 64157e252bfSMichael Neumann if (radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM, 64257e252bfSMichael Neumann requested_memory_clock, false, &req_dividers) == 0) { 64357e252bfSMichael Neumann vco_freq_temp = rv6xx_calculate_vco_frequency(ref_clk, &req_dividers, 64457e252bfSMichael Neumann pi->fb_div_scale); 64557e252bfSMichael Neumann 64657e252bfSMichael Neumann if (vco_freq_temp > *vco_freq) { 64757e252bfSMichael Neumann *dividers = req_dividers; 64857e252bfSMichael Neumann *vco_freq = vco_freq_temp; 64957e252bfSMichael Neumann } 65057e252bfSMichael Neumann } 65157e252bfSMichael Neumann } 65257e252bfSMichael Neumann 65357e252bfSMichael Neumann static void rv6xx_program_mclk_spread_spectrum_parameters(struct radeon_device *rdev) 65457e252bfSMichael Neumann { 65557e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 65657e252bfSMichael Neumann u32 ref_clk = rdev->clock.mpll.reference_freq; 65757e252bfSMichael Neumann struct atom_clock_dividers dividers; 65857e252bfSMichael Neumann struct radeon_atom_ss ss; 65957e252bfSMichael Neumann u32 vco_freq = 0, clk_v, clk_s; 66057e252bfSMichael Neumann 66157e252bfSMichael Neumann rv6xx_enable_memory_spread_spectrum(rdev, false); 66257e252bfSMichael Neumann 66357e252bfSMichael Neumann if (pi->mclk_ss) { 66457e252bfSMichael Neumann rv6xx_find_memory_clock_with_highest_vco(rdev, 66557e252bfSMichael Neumann pi->hw.mclks[pi->hw.high_mclk_index], 66657e252bfSMichael Neumann ref_clk, 66757e252bfSMichael Neumann ÷rs, 66857e252bfSMichael Neumann &vco_freq); 66957e252bfSMichael Neumann 67057e252bfSMichael Neumann rv6xx_find_memory_clock_with_highest_vco(rdev, 67157e252bfSMichael Neumann pi->hw.mclks[pi->hw.medium_mclk_index], 67257e252bfSMichael Neumann ref_clk, 67357e252bfSMichael Neumann ÷rs, 67457e252bfSMichael Neumann &vco_freq); 67557e252bfSMichael Neumann 67657e252bfSMichael Neumann rv6xx_find_memory_clock_with_highest_vco(rdev, 67757e252bfSMichael Neumann pi->hw.mclks[pi->hw.low_mclk_index], 67857e252bfSMichael Neumann ref_clk, 67957e252bfSMichael Neumann ÷rs, 68057e252bfSMichael Neumann &vco_freq); 68157e252bfSMichael Neumann 68257e252bfSMichael Neumann if (vco_freq) { 68357e252bfSMichael Neumann if (radeon_atombios_get_asic_ss_info(rdev, &ss, 68457e252bfSMichael Neumann ASIC_INTERNAL_MEMORY_SS, vco_freq)) { 68557e252bfSMichael Neumann clk_v = rv6xx_calculate_spread_spectrum_clk_v(vco_freq, 68657e252bfSMichael Neumann (ref_clk / (dividers.ref_div + 1)), 68757e252bfSMichael Neumann ss.rate, 68857e252bfSMichael Neumann ss.percentage, 68957e252bfSMichael Neumann pi->fb_div_scale); 69057e252bfSMichael Neumann 69157e252bfSMichael Neumann clk_s = rv6xx_calculate_spread_spectrum_clk_s(ss.rate, 69257e252bfSMichael Neumann (ref_clk / (dividers.ref_div + 1))); 69357e252bfSMichael Neumann 69457e252bfSMichael Neumann rv6xx_set_memory_spread_spectrum_clk_v(rdev, clk_v); 69557e252bfSMichael Neumann rv6xx_set_memory_spread_spectrum_clk_s(rdev, clk_s); 69657e252bfSMichael Neumann rv6xx_enable_memory_spread_spectrum(rdev, true); 69757e252bfSMichael Neumann } 69857e252bfSMichael Neumann } 69957e252bfSMichael Neumann } 70057e252bfSMichael Neumann } 70157e252bfSMichael Neumann 70257e252bfSMichael Neumann static int rv6xx_program_voltage_stepping_entry(struct radeon_device *rdev, 70357e252bfSMichael Neumann u32 entry, u16 voltage) 70457e252bfSMichael Neumann { 70557e252bfSMichael Neumann u32 mask, set_pins; 70657e252bfSMichael Neumann int ret; 70757e252bfSMichael Neumann 70857e252bfSMichael Neumann ret = radeon_atom_get_voltage_gpio_settings(rdev, voltage, 70957e252bfSMichael Neumann SET_VOLTAGE_TYPE_ASIC_VDDC, 71057e252bfSMichael Neumann &set_pins, &mask); 71157e252bfSMichael Neumann if (ret) 71257e252bfSMichael Neumann return ret; 71357e252bfSMichael Neumann 71457e252bfSMichael Neumann r600_voltage_control_program_voltages(rdev, entry, set_pins); 71557e252bfSMichael Neumann 71657e252bfSMichael Neumann return 0; 71757e252bfSMichael Neumann } 71857e252bfSMichael Neumann 71957e252bfSMichael Neumann static void rv6xx_program_voltage_stepping_parameters_except_lowest_entry(struct radeon_device *rdev) 72057e252bfSMichael Neumann { 72157e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 72257e252bfSMichael Neumann int i; 72357e252bfSMichael Neumann 72457e252bfSMichael Neumann for (i = 1; i < R600_PM_NUMBER_OF_VOLTAGE_LEVELS; i++) 72557e252bfSMichael Neumann rv6xx_program_voltage_stepping_entry(rdev, i, 72657e252bfSMichael Neumann pi->hw.vddc[i]); 72757e252bfSMichael Neumann 72857e252bfSMichael Neumann } 72957e252bfSMichael Neumann 73057e252bfSMichael Neumann static void rv6xx_program_backbias_stepping_parameters_except_lowest_entry(struct radeon_device *rdev) 73157e252bfSMichael Neumann { 73257e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 73357e252bfSMichael Neumann 73457e252bfSMichael Neumann if (pi->hw.backbias[1]) 73557e252bfSMichael Neumann WREG32_P(VID_UPPER_GPIO_CNTL, MEDIUM_BACKBIAS_VALUE, ~MEDIUM_BACKBIAS_VALUE); 73657e252bfSMichael Neumann else 73757e252bfSMichael Neumann WREG32_P(VID_UPPER_GPIO_CNTL, 0, ~MEDIUM_BACKBIAS_VALUE); 73857e252bfSMichael Neumann 73957e252bfSMichael Neumann if (pi->hw.backbias[2]) 74057e252bfSMichael Neumann WREG32_P(VID_UPPER_GPIO_CNTL, HIGH_BACKBIAS_VALUE, ~HIGH_BACKBIAS_VALUE); 74157e252bfSMichael Neumann else 74257e252bfSMichael Neumann WREG32_P(VID_UPPER_GPIO_CNTL, 0, ~HIGH_BACKBIAS_VALUE); 74357e252bfSMichael Neumann } 74457e252bfSMichael Neumann 74557e252bfSMichael Neumann static void rv6xx_program_sclk_spread_spectrum_parameters_lowest_entry(struct radeon_device *rdev) 74657e252bfSMichael Neumann { 74757e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 74857e252bfSMichael Neumann 74957e252bfSMichael Neumann rv6xx_program_engine_spread_spectrum(rdev, 75057e252bfSMichael Neumann pi->hw.sclks[R600_POWER_LEVEL_LOW], 75157e252bfSMichael Neumann R600_POWER_LEVEL_LOW); 75257e252bfSMichael Neumann } 75357e252bfSMichael Neumann 75457e252bfSMichael Neumann static void rv6xx_program_mclk_stepping_parameters_lowest_entry(struct radeon_device *rdev) 75557e252bfSMichael Neumann { 75657e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 75757e252bfSMichael Neumann 75857e252bfSMichael Neumann if (pi->hw.mclks[0]) 75957e252bfSMichael Neumann rv6xx_program_mclk_stepping_entry(rdev, 0, 76057e252bfSMichael Neumann pi->hw.mclks[0]); 76157e252bfSMichael Neumann } 76257e252bfSMichael Neumann 76357e252bfSMichael Neumann static void rv6xx_program_voltage_stepping_parameters_lowest_entry(struct radeon_device *rdev) 76457e252bfSMichael Neumann { 76557e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 76657e252bfSMichael Neumann 76757e252bfSMichael Neumann rv6xx_program_voltage_stepping_entry(rdev, 0, 76857e252bfSMichael Neumann pi->hw.vddc[0]); 76957e252bfSMichael Neumann 77057e252bfSMichael Neumann } 77157e252bfSMichael Neumann 77257e252bfSMichael Neumann static void rv6xx_program_backbias_stepping_parameters_lowest_entry(struct radeon_device *rdev) 77357e252bfSMichael Neumann { 77457e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 77557e252bfSMichael Neumann 77657e252bfSMichael Neumann if (pi->hw.backbias[0]) 77757e252bfSMichael Neumann WREG32_P(VID_UPPER_GPIO_CNTL, LOW_BACKBIAS_VALUE, ~LOW_BACKBIAS_VALUE); 77857e252bfSMichael Neumann else 77957e252bfSMichael Neumann WREG32_P(VID_UPPER_GPIO_CNTL, 0, ~LOW_BACKBIAS_VALUE); 78057e252bfSMichael Neumann } 78157e252bfSMichael Neumann 78257e252bfSMichael Neumann static u32 calculate_memory_refresh_rate(struct radeon_device *rdev, 78357e252bfSMichael Neumann u32 engine_clock) 78457e252bfSMichael Neumann { 78557e252bfSMichael Neumann u32 dram_rows, dram_refresh_rate; 78657e252bfSMichael Neumann u32 tmp; 78757e252bfSMichael Neumann 78857e252bfSMichael Neumann tmp = (RREG32(RAMCFG) & NOOFROWS_MASK) >> NOOFROWS_SHIFT; 78957e252bfSMichael Neumann dram_rows = 1 << (tmp + 10); 79057e252bfSMichael Neumann dram_refresh_rate = 1 << ((RREG32(MC_SEQ_RESERVE_M) & 0x3) + 3); 79157e252bfSMichael Neumann 79257e252bfSMichael Neumann return ((engine_clock * 10) * dram_refresh_rate / dram_rows - 32) / 64; 79357e252bfSMichael Neumann } 79457e252bfSMichael Neumann 79557e252bfSMichael Neumann static void rv6xx_program_memory_timing_parameters(struct radeon_device *rdev) 79657e252bfSMichael Neumann { 79757e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 79857e252bfSMichael Neumann u32 sqm_ratio; 79957e252bfSMichael Neumann u32 arb_refresh_rate; 80057e252bfSMichael Neumann u32 high_clock; 80157e252bfSMichael Neumann 80257e252bfSMichael Neumann if (pi->hw.sclks[R600_POWER_LEVEL_HIGH] < 80357e252bfSMichael Neumann (pi->hw.sclks[R600_POWER_LEVEL_LOW] * 0xFF / 0x40)) 80457e252bfSMichael Neumann high_clock = pi->hw.sclks[R600_POWER_LEVEL_HIGH]; 80557e252bfSMichael Neumann else 80657e252bfSMichael Neumann high_clock = 80757e252bfSMichael Neumann pi->hw.sclks[R600_POWER_LEVEL_LOW] * 0xFF / 0x40; 80857e252bfSMichael Neumann 80957e252bfSMichael Neumann radeon_atom_set_engine_dram_timings(rdev, high_clock, 0); 81057e252bfSMichael Neumann 81157e252bfSMichael Neumann sqm_ratio = (STATE0(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_LOW]) | 81257e252bfSMichael Neumann STATE1(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_MEDIUM]) | 81357e252bfSMichael Neumann STATE2(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_HIGH]) | 81457e252bfSMichael Neumann STATE3(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_HIGH])); 81557e252bfSMichael Neumann WREG32(SQM_RATIO, sqm_ratio); 81657e252bfSMichael Neumann 81757e252bfSMichael Neumann arb_refresh_rate = 81857e252bfSMichael Neumann (POWERMODE0(calculate_memory_refresh_rate(rdev, 81957e252bfSMichael Neumann pi->hw.sclks[R600_POWER_LEVEL_LOW])) | 82057e252bfSMichael Neumann POWERMODE1(calculate_memory_refresh_rate(rdev, 82157e252bfSMichael Neumann pi->hw.sclks[R600_POWER_LEVEL_MEDIUM])) | 82257e252bfSMichael Neumann POWERMODE2(calculate_memory_refresh_rate(rdev, 82357e252bfSMichael Neumann pi->hw.sclks[R600_POWER_LEVEL_HIGH])) | 82457e252bfSMichael Neumann POWERMODE3(calculate_memory_refresh_rate(rdev, 82557e252bfSMichael Neumann pi->hw.sclks[R600_POWER_LEVEL_HIGH]))); 82657e252bfSMichael Neumann WREG32(ARB_RFSH_RATE, arb_refresh_rate); 82757e252bfSMichael Neumann } 82857e252bfSMichael Neumann 82957e252bfSMichael Neumann static void rv6xx_program_mpll_timing_parameters(struct radeon_device *rdev) 83057e252bfSMichael Neumann { 83157e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 83257e252bfSMichael Neumann 83357e252bfSMichael Neumann r600_set_mpll_lock_time(rdev, R600_MPLLLOCKTIME_DFLT * 83457e252bfSMichael Neumann pi->mpll_ref_div); 83557e252bfSMichael Neumann r600_set_mpll_reset_time(rdev, R600_MPLLRESETTIME_DFLT); 83657e252bfSMichael Neumann } 83757e252bfSMichael Neumann 83857e252bfSMichael Neumann static void rv6xx_program_bsp(struct radeon_device *rdev) 83957e252bfSMichael Neumann { 84057e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 84157e252bfSMichael Neumann u32 ref_clk = rdev->clock.spll.reference_freq; 84257e252bfSMichael Neumann 84357e252bfSMichael Neumann r600_calculate_u_and_p(R600_ASI_DFLT, 84457e252bfSMichael Neumann ref_clk, 16, 84557e252bfSMichael Neumann &pi->bsp, 84657e252bfSMichael Neumann &pi->bsu); 84757e252bfSMichael Neumann 84857e252bfSMichael Neumann r600_set_bsp(rdev, pi->bsu, pi->bsp); 84957e252bfSMichael Neumann } 85057e252bfSMichael Neumann 85157e252bfSMichael Neumann static void rv6xx_program_at(struct radeon_device *rdev) 85257e252bfSMichael Neumann { 85357e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 85457e252bfSMichael Neumann 85557e252bfSMichael Neumann r600_set_at(rdev, 85657e252bfSMichael Neumann (pi->hw.rp[0] * pi->bsp) / 200, 85757e252bfSMichael Neumann (pi->hw.rp[1] * pi->bsp) / 200, 85857e252bfSMichael Neumann (pi->hw.lp[2] * pi->bsp) / 200, 85957e252bfSMichael Neumann (pi->hw.lp[1] * pi->bsp) / 200); 86057e252bfSMichael Neumann } 86157e252bfSMichael Neumann 86257e252bfSMichael Neumann static void rv6xx_program_git(struct radeon_device *rdev) 86357e252bfSMichael Neumann { 86457e252bfSMichael Neumann r600_set_git(rdev, R600_GICST_DFLT); 86557e252bfSMichael Neumann } 86657e252bfSMichael Neumann 86757e252bfSMichael Neumann static void rv6xx_program_tp(struct radeon_device *rdev) 86857e252bfSMichael Neumann { 86957e252bfSMichael Neumann int i; 87057e252bfSMichael Neumann 87157e252bfSMichael Neumann for (i = 0; i < R600_PM_NUMBER_OF_TC; i++) 87257e252bfSMichael Neumann r600_set_tc(rdev, i, r600_utc[i], r600_dtc[i]); 87357e252bfSMichael Neumann 87457e252bfSMichael Neumann r600_select_td(rdev, R600_TD_DFLT); 87557e252bfSMichael Neumann } 87657e252bfSMichael Neumann 87757e252bfSMichael Neumann static void rv6xx_program_vc(struct radeon_device *rdev) 87857e252bfSMichael Neumann { 87957e252bfSMichael Neumann r600_set_vrc(rdev, R600_VRC_DFLT); 88057e252bfSMichael Neumann } 88157e252bfSMichael Neumann 88257e252bfSMichael Neumann static void rv6xx_clear_vc(struct radeon_device *rdev) 88357e252bfSMichael Neumann { 88457e252bfSMichael Neumann r600_set_vrc(rdev, 0); 88557e252bfSMichael Neumann } 88657e252bfSMichael Neumann 88757e252bfSMichael Neumann static void rv6xx_program_tpp(struct radeon_device *rdev) 88857e252bfSMichael Neumann { 88957e252bfSMichael Neumann r600_set_tpu(rdev, R600_TPU_DFLT); 89057e252bfSMichael Neumann r600_set_tpc(rdev, R600_TPC_DFLT); 89157e252bfSMichael Neumann } 89257e252bfSMichael Neumann 89357e252bfSMichael Neumann static void rv6xx_program_sstp(struct radeon_device *rdev) 89457e252bfSMichael Neumann { 89557e252bfSMichael Neumann r600_set_sstu(rdev, R600_SSTU_DFLT); 89657e252bfSMichael Neumann r600_set_sst(rdev, R600_SST_DFLT); 89757e252bfSMichael Neumann } 89857e252bfSMichael Neumann 89957e252bfSMichael Neumann static void rv6xx_program_fcp(struct radeon_device *rdev) 90057e252bfSMichael Neumann { 90157e252bfSMichael Neumann r600_set_fctu(rdev, R600_FCTU_DFLT); 90257e252bfSMichael Neumann r600_set_fct(rdev, R600_FCT_DFLT); 90357e252bfSMichael Neumann } 90457e252bfSMichael Neumann 90557e252bfSMichael Neumann static void rv6xx_program_vddc3d_parameters(struct radeon_device *rdev) 90657e252bfSMichael Neumann { 90757e252bfSMichael Neumann r600_set_vddc3d_oorsu(rdev, R600_VDDC3DOORSU_DFLT); 90857e252bfSMichael Neumann r600_set_vddc3d_oorphc(rdev, R600_VDDC3DOORPHC_DFLT); 90957e252bfSMichael Neumann r600_set_vddc3d_oorsdc(rdev, R600_VDDC3DOORSDC_DFLT); 91057e252bfSMichael Neumann r600_set_ctxcgtt3d_rphc(rdev, R600_CTXCGTT3DRPHC_DFLT); 91157e252bfSMichael Neumann r600_set_ctxcgtt3d_rsdc(rdev, R600_CTXCGTT3DRSDC_DFLT); 91257e252bfSMichael Neumann } 91357e252bfSMichael Neumann 91457e252bfSMichael Neumann static void rv6xx_program_voltage_timing_parameters(struct radeon_device *rdev) 91557e252bfSMichael Neumann { 91657e252bfSMichael Neumann u32 rt; 91757e252bfSMichael Neumann 91857e252bfSMichael Neumann r600_vid_rt_set_vru(rdev, R600_VRU_DFLT); 91957e252bfSMichael Neumann 92057e252bfSMichael Neumann r600_vid_rt_set_vrt(rdev, 92157e252bfSMichael Neumann rv6xx_compute_count_for_delay(rdev, 92257e252bfSMichael Neumann rdev->pm.dpm.voltage_response_time, 92357e252bfSMichael Neumann R600_VRU_DFLT)); 92457e252bfSMichael Neumann 92557e252bfSMichael Neumann rt = rv6xx_compute_count_for_delay(rdev, 92657e252bfSMichael Neumann rdev->pm.dpm.backbias_response_time, 92757e252bfSMichael Neumann R600_VRU_DFLT); 92857e252bfSMichael Neumann 92957e252bfSMichael Neumann rv6xx_vid_response_set_brt(rdev, (rt + 0x1F) >> 5); 93057e252bfSMichael Neumann } 93157e252bfSMichael Neumann 93257e252bfSMichael Neumann static void rv6xx_program_engine_speed_parameters(struct radeon_device *rdev) 93357e252bfSMichael Neumann { 93457e252bfSMichael Neumann r600_vid_rt_set_ssu(rdev, R600_SPLLSTEPUNIT_DFLT); 93557e252bfSMichael Neumann rv6xx_enable_engine_feedback_and_reference_sync(rdev); 93657e252bfSMichael Neumann } 93757e252bfSMichael Neumann 93857e252bfSMichael Neumann static u64 rv6xx_get_master_voltage_mask(struct radeon_device *rdev) 93957e252bfSMichael Neumann { 94057e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 94157e252bfSMichael Neumann u64 master_mask = 0; 94257e252bfSMichael Neumann int i; 94357e252bfSMichael Neumann 94457e252bfSMichael Neumann for (i = 0; i < R600_PM_NUMBER_OF_VOLTAGE_LEVELS; i++) { 94557e252bfSMichael Neumann u32 tmp_mask, tmp_set_pins; 94657e252bfSMichael Neumann int ret; 94757e252bfSMichael Neumann 94857e252bfSMichael Neumann ret = radeon_atom_get_voltage_gpio_settings(rdev, 94957e252bfSMichael Neumann pi->hw.vddc[i], 95057e252bfSMichael Neumann SET_VOLTAGE_TYPE_ASIC_VDDC, 95157e252bfSMichael Neumann &tmp_set_pins, &tmp_mask); 95257e252bfSMichael Neumann 95357e252bfSMichael Neumann if (ret == 0) 95457e252bfSMichael Neumann master_mask |= tmp_mask; 95557e252bfSMichael Neumann } 95657e252bfSMichael Neumann 95757e252bfSMichael Neumann return master_mask; 95857e252bfSMichael Neumann } 95957e252bfSMichael Neumann 96057e252bfSMichael Neumann static void rv6xx_program_voltage_gpio_pins(struct radeon_device *rdev) 96157e252bfSMichael Neumann { 96257e252bfSMichael Neumann r600_voltage_control_enable_pins(rdev, 96357e252bfSMichael Neumann rv6xx_get_master_voltage_mask(rdev)); 96457e252bfSMichael Neumann } 96557e252bfSMichael Neumann 96657e252bfSMichael Neumann static void rv6xx_enable_static_voltage_control(struct radeon_device *rdev, 96757e252bfSMichael Neumann struct radeon_ps *new_ps, 96857e252bfSMichael Neumann bool enable) 96957e252bfSMichael Neumann { 97057e252bfSMichael Neumann struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); 97157e252bfSMichael Neumann 97257e252bfSMichael Neumann if (enable) 97357e252bfSMichael Neumann radeon_atom_set_voltage(rdev, 97457e252bfSMichael Neumann new_state->low.vddc, 97557e252bfSMichael Neumann SET_VOLTAGE_TYPE_ASIC_VDDC); 97657e252bfSMichael Neumann else 97757e252bfSMichael Neumann r600_voltage_control_deactivate_static_control(rdev, 97857e252bfSMichael Neumann rv6xx_get_master_voltage_mask(rdev)); 97957e252bfSMichael Neumann } 98057e252bfSMichael Neumann 98157e252bfSMichael Neumann static void rv6xx_enable_display_gap(struct radeon_device *rdev, bool enable) 98257e252bfSMichael Neumann { 98357e252bfSMichael Neumann if (enable) { 98457e252bfSMichael Neumann u32 tmp = (DISP1_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM) | 98557e252bfSMichael Neumann DISP2_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM) | 98657e252bfSMichael Neumann DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE) | 98757e252bfSMichael Neumann DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE) | 98857e252bfSMichael Neumann VBI_TIMER_COUNT(0x3FFF) | 98957e252bfSMichael Neumann VBI_TIMER_UNIT(7)); 99057e252bfSMichael Neumann WREG32(CG_DISPLAY_GAP_CNTL, tmp); 99157e252bfSMichael Neumann 99257e252bfSMichael Neumann WREG32_P(MCLK_PWRMGT_CNTL, USE_DISPLAY_GAP, ~USE_DISPLAY_GAP); 99357e252bfSMichael Neumann } else 99457e252bfSMichael Neumann WREG32_P(MCLK_PWRMGT_CNTL, 0, ~USE_DISPLAY_GAP); 99557e252bfSMichael Neumann } 99657e252bfSMichael Neumann 99757e252bfSMichael Neumann static void rv6xx_program_power_level_enter_state(struct radeon_device *rdev) 99857e252bfSMichael Neumann { 99957e252bfSMichael Neumann r600_power_level_set_enter_index(rdev, R600_POWER_LEVEL_MEDIUM); 100057e252bfSMichael Neumann } 100157e252bfSMichael Neumann 100257e252bfSMichael Neumann static void rv6xx_calculate_t(u32 l_f, u32 h_f, int h, 100357e252bfSMichael Neumann int d_l, int d_r, u8 *l, u8 *r) 100457e252bfSMichael Neumann { 100557e252bfSMichael Neumann int a_n, a_d, h_r, l_r; 100657e252bfSMichael Neumann 100757e252bfSMichael Neumann h_r = d_l; 100857e252bfSMichael Neumann l_r = 100 - d_r; 100957e252bfSMichael Neumann 101057e252bfSMichael Neumann a_n = (int)h_f * d_l + (int)l_f * (h - d_r); 101157e252bfSMichael Neumann a_d = (int)l_f * l_r + (int)h_f * h_r; 101257e252bfSMichael Neumann 101357e252bfSMichael Neumann if (a_d != 0) { 101457e252bfSMichael Neumann *l = d_l - h_r * a_n / a_d; 101557e252bfSMichael Neumann *r = d_r + l_r * a_n / a_d; 101657e252bfSMichael Neumann } 101757e252bfSMichael Neumann } 101857e252bfSMichael Neumann 101957e252bfSMichael Neumann static void rv6xx_calculate_ap(struct radeon_device *rdev, 102057e252bfSMichael Neumann struct rv6xx_ps *state) 102157e252bfSMichael Neumann { 102257e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 102357e252bfSMichael Neumann 102457e252bfSMichael Neumann pi->hw.lp[0] = 0; 102557e252bfSMichael Neumann pi->hw.rp[R600_PM_NUMBER_OF_ACTIVITY_LEVELS - 1] 102657e252bfSMichael Neumann = 100; 102757e252bfSMichael Neumann 102857e252bfSMichael Neumann rv6xx_calculate_t(state->low.sclk, 102957e252bfSMichael Neumann state->medium.sclk, 103057e252bfSMichael Neumann R600_AH_DFLT, 103157e252bfSMichael Neumann R600_LMP_DFLT, 103257e252bfSMichael Neumann R600_RLP_DFLT, 103357e252bfSMichael Neumann &pi->hw.lp[1], 103457e252bfSMichael Neumann &pi->hw.rp[0]); 103557e252bfSMichael Neumann 103657e252bfSMichael Neumann rv6xx_calculate_t(state->medium.sclk, 103757e252bfSMichael Neumann state->high.sclk, 103857e252bfSMichael Neumann R600_AH_DFLT, 103957e252bfSMichael Neumann R600_LHP_DFLT, 104057e252bfSMichael Neumann R600_RMP_DFLT, 104157e252bfSMichael Neumann &pi->hw.lp[2], 104257e252bfSMichael Neumann &pi->hw.rp[1]); 104357e252bfSMichael Neumann 104457e252bfSMichael Neumann } 104557e252bfSMichael Neumann 104657e252bfSMichael Neumann static void rv6xx_calculate_stepping_parameters(struct radeon_device *rdev, 104757e252bfSMichael Neumann struct radeon_ps *new_ps) 104857e252bfSMichael Neumann { 104957e252bfSMichael Neumann struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); 105057e252bfSMichael Neumann 105157e252bfSMichael Neumann rv6xx_calculate_engine_speed_stepping_parameters(rdev, new_state); 105257e252bfSMichael Neumann rv6xx_calculate_memory_clock_stepping_parameters(rdev, new_state); 105357e252bfSMichael Neumann rv6xx_calculate_voltage_stepping_parameters(rdev, new_state); 105457e252bfSMichael Neumann rv6xx_calculate_ap(rdev, new_state); 105557e252bfSMichael Neumann } 105657e252bfSMichael Neumann 105757e252bfSMichael Neumann static void rv6xx_program_stepping_parameters_except_lowest_entry(struct radeon_device *rdev) 105857e252bfSMichael Neumann { 105957e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 106057e252bfSMichael Neumann 106157e252bfSMichael Neumann rv6xx_program_mclk_stepping_parameters_except_lowest_entry(rdev); 106257e252bfSMichael Neumann if (pi->voltage_control) 106357e252bfSMichael Neumann rv6xx_program_voltage_stepping_parameters_except_lowest_entry(rdev); 106457e252bfSMichael Neumann rv6xx_program_backbias_stepping_parameters_except_lowest_entry(rdev); 106557e252bfSMichael Neumann rv6xx_program_sclk_spread_spectrum_parameters_except_lowest_entry(rdev); 106657e252bfSMichael Neumann rv6xx_program_mclk_spread_spectrum_parameters(rdev); 106757e252bfSMichael Neumann rv6xx_program_memory_timing_parameters(rdev); 106857e252bfSMichael Neumann } 106957e252bfSMichael Neumann 107057e252bfSMichael Neumann static void rv6xx_program_stepping_parameters_lowest_entry(struct radeon_device *rdev) 107157e252bfSMichael Neumann { 107257e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 107357e252bfSMichael Neumann 107457e252bfSMichael Neumann rv6xx_program_mclk_stepping_parameters_lowest_entry(rdev); 107557e252bfSMichael Neumann if (pi->voltage_control) 107657e252bfSMichael Neumann rv6xx_program_voltage_stepping_parameters_lowest_entry(rdev); 107757e252bfSMichael Neumann rv6xx_program_backbias_stepping_parameters_lowest_entry(rdev); 107857e252bfSMichael Neumann rv6xx_program_sclk_spread_spectrum_parameters_lowest_entry(rdev); 107957e252bfSMichael Neumann } 108057e252bfSMichael Neumann 108157e252bfSMichael Neumann static void rv6xx_program_power_level_low(struct radeon_device *rdev) 108257e252bfSMichael Neumann { 108357e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 108457e252bfSMichael Neumann 108557e252bfSMichael Neumann r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW, 108657e252bfSMichael Neumann pi->hw.low_vddc_index); 108757e252bfSMichael Neumann r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW, 108857e252bfSMichael Neumann pi->hw.low_mclk_index); 108957e252bfSMichael Neumann r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW, 109057e252bfSMichael Neumann pi->hw.low_sclk_index); 109157e252bfSMichael Neumann r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW, 109257e252bfSMichael Neumann R600_DISPLAY_WATERMARK_LOW); 109357e252bfSMichael Neumann r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_LOW, 109457e252bfSMichael Neumann pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW]); 109557e252bfSMichael Neumann } 109657e252bfSMichael Neumann 109757e252bfSMichael Neumann static void rv6xx_program_power_level_low_to_lowest_state(struct radeon_device *rdev) 109857e252bfSMichael Neumann { 109957e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 110057e252bfSMichael Neumann 110157e252bfSMichael Neumann r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW, 0); 110257e252bfSMichael Neumann r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW, 0); 110357e252bfSMichael Neumann r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW, 0); 110457e252bfSMichael Neumann 110557e252bfSMichael Neumann r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW, 110657e252bfSMichael Neumann R600_DISPLAY_WATERMARK_LOW); 110757e252bfSMichael Neumann 110857e252bfSMichael Neumann r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_LOW, 110957e252bfSMichael Neumann pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW]); 111057e252bfSMichael Neumann 111157e252bfSMichael Neumann } 111257e252bfSMichael Neumann 111357e252bfSMichael Neumann static void rv6xx_program_power_level_medium(struct radeon_device *rdev) 111457e252bfSMichael Neumann { 111557e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 111657e252bfSMichael Neumann 111757e252bfSMichael Neumann r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM, 111857e252bfSMichael Neumann pi->hw.medium_vddc_index); 111957e252bfSMichael Neumann r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 112057e252bfSMichael Neumann pi->hw.medium_mclk_index); 112157e252bfSMichael Neumann r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 112257e252bfSMichael Neumann pi->hw.medium_sclk_index); 112357e252bfSMichael Neumann r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM, 112457e252bfSMichael Neumann R600_DISPLAY_WATERMARK_LOW); 112557e252bfSMichael Neumann r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_MEDIUM, 112657e252bfSMichael Neumann pi->hw.pcie_gen2[R600_POWER_LEVEL_MEDIUM]); 112757e252bfSMichael Neumann } 112857e252bfSMichael Neumann 112957e252bfSMichael Neumann static void rv6xx_program_power_level_medium_for_transition(struct radeon_device *rdev) 113057e252bfSMichael Neumann { 113157e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 113257e252bfSMichael Neumann 113357e252bfSMichael Neumann rv6xx_program_mclk_stepping_entry(rdev, 113457e252bfSMichael Neumann R600_POWER_LEVEL_CTXSW, 113557e252bfSMichael Neumann pi->hw.mclks[pi->hw.low_mclk_index]); 113657e252bfSMichael Neumann 113757e252bfSMichael Neumann r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM, 1); 113857e252bfSMichael Neumann 113957e252bfSMichael Neumann r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 114057e252bfSMichael Neumann R600_POWER_LEVEL_CTXSW); 114157e252bfSMichael Neumann r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 114257e252bfSMichael Neumann pi->hw.medium_sclk_index); 114357e252bfSMichael Neumann 114457e252bfSMichael Neumann r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM, 114557e252bfSMichael Neumann R600_DISPLAY_WATERMARK_LOW); 114657e252bfSMichael Neumann 114757e252bfSMichael Neumann rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_MEDIUM, false); 114857e252bfSMichael Neumann 114957e252bfSMichael Neumann r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_MEDIUM, 115057e252bfSMichael Neumann pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW]); 115157e252bfSMichael Neumann } 115257e252bfSMichael Neumann 115357e252bfSMichael Neumann static void rv6xx_program_power_level_high(struct radeon_device *rdev) 115457e252bfSMichael Neumann { 115557e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 115657e252bfSMichael Neumann 115757e252bfSMichael Neumann r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_HIGH, 115857e252bfSMichael Neumann pi->hw.high_vddc_index); 115957e252bfSMichael Neumann r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_HIGH, 116057e252bfSMichael Neumann pi->hw.high_mclk_index); 116157e252bfSMichael Neumann r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_HIGH, 116257e252bfSMichael Neumann pi->hw.high_sclk_index); 116357e252bfSMichael Neumann 116457e252bfSMichael Neumann r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_HIGH, 116557e252bfSMichael Neumann R600_DISPLAY_WATERMARK_HIGH); 116657e252bfSMichael Neumann 116757e252bfSMichael Neumann r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_HIGH, 116857e252bfSMichael Neumann pi->hw.pcie_gen2[R600_POWER_LEVEL_HIGH]); 116957e252bfSMichael Neumann } 117057e252bfSMichael Neumann 117157e252bfSMichael Neumann static void rv6xx_enable_backbias(struct radeon_device *rdev, bool enable) 117257e252bfSMichael Neumann { 117357e252bfSMichael Neumann if (enable) 117457e252bfSMichael Neumann WREG32_P(GENERAL_PWRMGT, BACKBIAS_PAD_EN | BACKBIAS_DPM_CNTL, 117557e252bfSMichael Neumann ~(BACKBIAS_PAD_EN | BACKBIAS_DPM_CNTL)); 117657e252bfSMichael Neumann else 117757e252bfSMichael Neumann WREG32_P(GENERAL_PWRMGT, 0, 117857e252bfSMichael Neumann ~(BACKBIAS_VALUE | BACKBIAS_PAD_EN | BACKBIAS_DPM_CNTL)); 117957e252bfSMichael Neumann } 118057e252bfSMichael Neumann 118157e252bfSMichael Neumann static void rv6xx_program_display_gap(struct radeon_device *rdev) 118257e252bfSMichael Neumann { 118357e252bfSMichael Neumann u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL); 118457e252bfSMichael Neumann 118557e252bfSMichael Neumann tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK); 118657e252bfSMichael Neumann if (rdev->pm.dpm.new_active_crtcs & 1) { 118757e252bfSMichael Neumann tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK); 118857e252bfSMichael Neumann tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); 118957e252bfSMichael Neumann } else if (rdev->pm.dpm.new_active_crtcs & 2) { 119057e252bfSMichael Neumann tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); 119157e252bfSMichael Neumann tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK); 119257e252bfSMichael Neumann } else { 119357e252bfSMichael Neumann tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); 119457e252bfSMichael Neumann tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); 119557e252bfSMichael Neumann } 119657e252bfSMichael Neumann WREG32(CG_DISPLAY_GAP_CNTL, tmp); 119757e252bfSMichael Neumann } 119857e252bfSMichael Neumann 119957e252bfSMichael Neumann static void rv6xx_set_sw_voltage_to_safe(struct radeon_device *rdev, 120057e252bfSMichael Neumann struct radeon_ps *new_ps, 120157e252bfSMichael Neumann struct radeon_ps *old_ps) 120257e252bfSMichael Neumann { 120357e252bfSMichael Neumann struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); 120457e252bfSMichael Neumann struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps); 120557e252bfSMichael Neumann u16 safe_voltage; 120657e252bfSMichael Neumann 120757e252bfSMichael Neumann safe_voltage = (new_state->low.vddc >= old_state->low.vddc) ? 120857e252bfSMichael Neumann new_state->low.vddc : old_state->low.vddc; 120957e252bfSMichael Neumann 121057e252bfSMichael Neumann rv6xx_program_voltage_stepping_entry(rdev, R600_POWER_LEVEL_CTXSW, 121157e252bfSMichael Neumann safe_voltage); 121257e252bfSMichael Neumann 121357e252bfSMichael Neumann WREG32_P(GENERAL_PWRMGT, SW_GPIO_INDEX(R600_POWER_LEVEL_CTXSW), 121457e252bfSMichael Neumann ~SW_GPIO_INDEX_MASK); 121557e252bfSMichael Neumann } 121657e252bfSMichael Neumann 121757e252bfSMichael Neumann static void rv6xx_set_sw_voltage_to_low(struct radeon_device *rdev, 121857e252bfSMichael Neumann struct radeon_ps *old_ps) 121957e252bfSMichael Neumann { 122057e252bfSMichael Neumann struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps); 122157e252bfSMichael Neumann 122257e252bfSMichael Neumann rv6xx_program_voltage_stepping_entry(rdev, R600_POWER_LEVEL_CTXSW, 122357e252bfSMichael Neumann old_state->low.vddc); 122457e252bfSMichael Neumann 122557e252bfSMichael Neumann WREG32_P(GENERAL_PWRMGT, SW_GPIO_INDEX(R600_POWER_LEVEL_CTXSW), 122657e252bfSMichael Neumann ~SW_GPIO_INDEX_MASK); 122757e252bfSMichael Neumann } 122857e252bfSMichael Neumann 122957e252bfSMichael Neumann static void rv6xx_set_safe_backbias(struct radeon_device *rdev, 123057e252bfSMichael Neumann struct radeon_ps *new_ps, 123157e252bfSMichael Neumann struct radeon_ps *old_ps) 123257e252bfSMichael Neumann { 123357e252bfSMichael Neumann struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); 123457e252bfSMichael Neumann struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps); 123557e252bfSMichael Neumann 123657e252bfSMichael Neumann if ((new_state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) && 123757e252bfSMichael Neumann (old_state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE)) 123857e252bfSMichael Neumann WREG32_P(GENERAL_PWRMGT, BACKBIAS_VALUE, ~BACKBIAS_VALUE); 123957e252bfSMichael Neumann else 124057e252bfSMichael Neumann WREG32_P(GENERAL_PWRMGT, 0, ~BACKBIAS_VALUE); 124157e252bfSMichael Neumann } 124257e252bfSMichael Neumann 124357e252bfSMichael Neumann static void rv6xx_set_safe_pcie_gen2(struct radeon_device *rdev, 124457e252bfSMichael Neumann struct radeon_ps *new_ps, 124557e252bfSMichael Neumann struct radeon_ps *old_ps) 124657e252bfSMichael Neumann { 124757e252bfSMichael Neumann struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); 124857e252bfSMichael Neumann struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps); 124957e252bfSMichael Neumann 125057e252bfSMichael Neumann if ((new_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) != 125157e252bfSMichael Neumann (old_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2)) 125257e252bfSMichael Neumann rv6xx_force_pcie_gen1(rdev); 125357e252bfSMichael Neumann } 125457e252bfSMichael Neumann 125557e252bfSMichael Neumann static void rv6xx_enable_dynamic_voltage_control(struct radeon_device *rdev, 125657e252bfSMichael Neumann bool enable) 125757e252bfSMichael Neumann { 125857e252bfSMichael Neumann if (enable) 125957e252bfSMichael Neumann WREG32_P(GENERAL_PWRMGT, VOLT_PWRMGT_EN, ~VOLT_PWRMGT_EN); 126057e252bfSMichael Neumann else 126157e252bfSMichael Neumann WREG32_P(GENERAL_PWRMGT, 0, ~VOLT_PWRMGT_EN); 126257e252bfSMichael Neumann } 126357e252bfSMichael Neumann 126457e252bfSMichael Neumann static void rv6xx_enable_dynamic_backbias_control(struct radeon_device *rdev, 126557e252bfSMichael Neumann bool enable) 126657e252bfSMichael Neumann { 126757e252bfSMichael Neumann if (enable) 126857e252bfSMichael Neumann WREG32_P(GENERAL_PWRMGT, BACKBIAS_DPM_CNTL, ~BACKBIAS_DPM_CNTL); 126957e252bfSMichael Neumann else 127057e252bfSMichael Neumann WREG32_P(GENERAL_PWRMGT, 0, ~BACKBIAS_DPM_CNTL); 127157e252bfSMichael Neumann } 127257e252bfSMichael Neumann 127357e252bfSMichael Neumann static int rv6xx_step_sw_voltage(struct radeon_device *rdev, 127457e252bfSMichael Neumann u16 initial_voltage, 127557e252bfSMichael Neumann u16 target_voltage) 127657e252bfSMichael Neumann { 127757e252bfSMichael Neumann u16 current_voltage; 127857e252bfSMichael Neumann u16 true_target_voltage; 127957e252bfSMichael Neumann u16 voltage_step; 128057e252bfSMichael Neumann int signed_voltage_step; 128157e252bfSMichael Neumann 128257e252bfSMichael Neumann if ((radeon_atom_get_voltage_step(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, 128357e252bfSMichael Neumann &voltage_step)) || 128457e252bfSMichael Neumann (radeon_atom_round_to_true_voltage(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, 128557e252bfSMichael Neumann initial_voltage, ¤t_voltage)) || 128657e252bfSMichael Neumann (radeon_atom_round_to_true_voltage(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, 128757e252bfSMichael Neumann target_voltage, &true_target_voltage))) 128857e252bfSMichael Neumann return -EINVAL; 128957e252bfSMichael Neumann 129057e252bfSMichael Neumann if (true_target_voltage < current_voltage) 129157e252bfSMichael Neumann signed_voltage_step = -(int)voltage_step; 129257e252bfSMichael Neumann else 129357e252bfSMichael Neumann signed_voltage_step = voltage_step; 129457e252bfSMichael Neumann 129557e252bfSMichael Neumann while (current_voltage != true_target_voltage) { 129657e252bfSMichael Neumann current_voltage += signed_voltage_step; 129757e252bfSMichael Neumann rv6xx_program_voltage_stepping_entry(rdev, R600_POWER_LEVEL_CTXSW, 129857e252bfSMichael Neumann current_voltage); 129957e252bfSMichael Neumann msleep((rdev->pm.dpm.voltage_response_time + 999) / 1000); 130057e252bfSMichael Neumann } 130157e252bfSMichael Neumann 130257e252bfSMichael Neumann return 0; 130357e252bfSMichael Neumann } 130457e252bfSMichael Neumann 130557e252bfSMichael Neumann static int rv6xx_step_voltage_if_increasing(struct radeon_device *rdev, 130657e252bfSMichael Neumann struct radeon_ps *new_ps, 130757e252bfSMichael Neumann struct radeon_ps *old_ps) 130857e252bfSMichael Neumann { 130957e252bfSMichael Neumann struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); 131057e252bfSMichael Neumann struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps); 131157e252bfSMichael Neumann 131257e252bfSMichael Neumann if (new_state->low.vddc > old_state->low.vddc) 131357e252bfSMichael Neumann return rv6xx_step_sw_voltage(rdev, 131457e252bfSMichael Neumann old_state->low.vddc, 131557e252bfSMichael Neumann new_state->low.vddc); 131657e252bfSMichael Neumann 131757e252bfSMichael Neumann return 0; 131857e252bfSMichael Neumann } 131957e252bfSMichael Neumann 132057e252bfSMichael Neumann static int rv6xx_step_voltage_if_decreasing(struct radeon_device *rdev, 132157e252bfSMichael Neumann struct radeon_ps *new_ps, 132257e252bfSMichael Neumann struct radeon_ps *old_ps) 132357e252bfSMichael Neumann { 132457e252bfSMichael Neumann struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); 132557e252bfSMichael Neumann struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps); 132657e252bfSMichael Neumann 132757e252bfSMichael Neumann if (new_state->low.vddc < old_state->low.vddc) 132857e252bfSMichael Neumann return rv6xx_step_sw_voltage(rdev, 132957e252bfSMichael Neumann old_state->low.vddc, 133057e252bfSMichael Neumann new_state->low.vddc); 133157e252bfSMichael Neumann else 133257e252bfSMichael Neumann return 0; 133357e252bfSMichael Neumann } 133457e252bfSMichael Neumann 133557e252bfSMichael Neumann static void rv6xx_enable_high(struct radeon_device *rdev) 133657e252bfSMichael Neumann { 133757e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 133857e252bfSMichael Neumann 133957e252bfSMichael Neumann if ((pi->restricted_levels < 1) || 134057e252bfSMichael Neumann (pi->restricted_levels == 3)) 134157e252bfSMichael Neumann r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, true); 134257e252bfSMichael Neumann } 134357e252bfSMichael Neumann 134457e252bfSMichael Neumann static void rv6xx_enable_medium(struct radeon_device *rdev) 134557e252bfSMichael Neumann { 134657e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 134757e252bfSMichael Neumann 134857e252bfSMichael Neumann if (pi->restricted_levels < 2) 134957e252bfSMichael Neumann r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true); 135057e252bfSMichael Neumann } 135157e252bfSMichael Neumann 135257e252bfSMichael Neumann static void rv6xx_set_dpm_event_sources(struct radeon_device *rdev, u32 sources) 135357e252bfSMichael Neumann { 135457e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 135557e252bfSMichael Neumann bool want_thermal_protection; 135657e252bfSMichael Neumann enum radeon_dpm_event_src dpm_event_src; 135757e252bfSMichael Neumann 135857e252bfSMichael Neumann switch (sources) { 135957e252bfSMichael Neumann case 0: 136057e252bfSMichael Neumann default: 136157e252bfSMichael Neumann want_thermal_protection = false; 136257e252bfSMichael Neumann break; 136357e252bfSMichael Neumann case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL): 136457e252bfSMichael Neumann want_thermal_protection = true; 136557e252bfSMichael Neumann dpm_event_src = RADEON_DPM_EVENT_SRC_DIGITAL; 136657e252bfSMichael Neumann break; 136757e252bfSMichael Neumann 136857e252bfSMichael Neumann case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL): 136957e252bfSMichael Neumann want_thermal_protection = true; 137057e252bfSMichael Neumann dpm_event_src = RADEON_DPM_EVENT_SRC_EXTERNAL; 137157e252bfSMichael Neumann break; 137257e252bfSMichael Neumann 137357e252bfSMichael Neumann case ((1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL) | 137457e252bfSMichael Neumann (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL)): 137557e252bfSMichael Neumann want_thermal_protection = true; 137657e252bfSMichael Neumann dpm_event_src = RADEON_DPM_EVENT_SRC_DIGIAL_OR_EXTERNAL; 137757e252bfSMichael Neumann break; 137857e252bfSMichael Neumann } 137957e252bfSMichael Neumann 138057e252bfSMichael Neumann if (want_thermal_protection) { 138157e252bfSMichael Neumann WREG32_P(CG_THERMAL_CTRL, DPM_EVENT_SRC(dpm_event_src), ~DPM_EVENT_SRC_MASK); 138257e252bfSMichael Neumann if (pi->thermal_protection) 138357e252bfSMichael Neumann WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS); 138457e252bfSMichael Neumann } else { 138557e252bfSMichael Neumann WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS); 138657e252bfSMichael Neumann } 138757e252bfSMichael Neumann } 138857e252bfSMichael Neumann 138957e252bfSMichael Neumann static void rv6xx_enable_auto_throttle_source(struct radeon_device *rdev, 139057e252bfSMichael Neumann enum radeon_dpm_auto_throttle_src source, 139157e252bfSMichael Neumann bool enable) 139257e252bfSMichael Neumann { 139357e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 139457e252bfSMichael Neumann 139557e252bfSMichael Neumann if (enable) { 139657e252bfSMichael Neumann if (!(pi->active_auto_throttle_sources & (1 << source))) { 139757e252bfSMichael Neumann pi->active_auto_throttle_sources |= 1 << source; 139857e252bfSMichael Neumann rv6xx_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources); 139957e252bfSMichael Neumann } 140057e252bfSMichael Neumann } else { 140157e252bfSMichael Neumann if (pi->active_auto_throttle_sources & (1 << source)) { 140257e252bfSMichael Neumann pi->active_auto_throttle_sources &= ~(1 << source); 140357e252bfSMichael Neumann rv6xx_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources); 140457e252bfSMichael Neumann } 140557e252bfSMichael Neumann } 140657e252bfSMichael Neumann } 140757e252bfSMichael Neumann 140857e252bfSMichael Neumann 140957e252bfSMichael Neumann static void rv6xx_enable_thermal_protection(struct radeon_device *rdev, 141057e252bfSMichael Neumann bool enable) 141157e252bfSMichael Neumann { 141257e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 141357e252bfSMichael Neumann 141457e252bfSMichael Neumann if (pi->active_auto_throttle_sources) 141557e252bfSMichael Neumann r600_enable_thermal_protection(rdev, enable); 141657e252bfSMichael Neumann } 141757e252bfSMichael Neumann 141857e252bfSMichael Neumann static void rv6xx_generate_transition_stepping(struct radeon_device *rdev, 141957e252bfSMichael Neumann struct radeon_ps *new_ps, 142057e252bfSMichael Neumann struct radeon_ps *old_ps) 142157e252bfSMichael Neumann { 142257e252bfSMichael Neumann struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); 142357e252bfSMichael Neumann struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps); 142457e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 142557e252bfSMichael Neumann 142657e252bfSMichael Neumann rv6xx_generate_steps(rdev, 142757e252bfSMichael Neumann old_state->low.sclk, 142857e252bfSMichael Neumann new_state->low.sclk, 142957e252bfSMichael Neumann 0, &pi->hw.medium_sclk_index); 143057e252bfSMichael Neumann } 143157e252bfSMichael Neumann 143257e252bfSMichael Neumann static void rv6xx_generate_low_step(struct radeon_device *rdev, 143357e252bfSMichael Neumann struct radeon_ps *new_ps) 143457e252bfSMichael Neumann { 143557e252bfSMichael Neumann struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); 143657e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 143757e252bfSMichael Neumann 143857e252bfSMichael Neumann pi->hw.low_sclk_index = 0; 143957e252bfSMichael Neumann rv6xx_generate_single_step(rdev, 144057e252bfSMichael Neumann new_state->low.sclk, 144157e252bfSMichael Neumann 0); 144257e252bfSMichael Neumann } 144357e252bfSMichael Neumann 144457e252bfSMichael Neumann static void rv6xx_invalidate_intermediate_steps(struct radeon_device *rdev) 144557e252bfSMichael Neumann { 144657e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 144757e252bfSMichael Neumann 144857e252bfSMichael Neumann rv6xx_invalidate_intermediate_steps_range(rdev, 0, 144957e252bfSMichael Neumann pi->hw.medium_sclk_index); 145057e252bfSMichael Neumann } 145157e252bfSMichael Neumann 145257e252bfSMichael Neumann static void rv6xx_generate_stepping_table(struct radeon_device *rdev, 145357e252bfSMichael Neumann struct radeon_ps *new_ps) 145457e252bfSMichael Neumann { 145557e252bfSMichael Neumann struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); 145657e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 145757e252bfSMichael Neumann 145857e252bfSMichael Neumann pi->hw.low_sclk_index = 0; 145957e252bfSMichael Neumann 146057e252bfSMichael Neumann rv6xx_generate_steps(rdev, 146157e252bfSMichael Neumann new_state->low.sclk, 146257e252bfSMichael Neumann new_state->medium.sclk, 146357e252bfSMichael Neumann 0, 146457e252bfSMichael Neumann &pi->hw.medium_sclk_index); 146557e252bfSMichael Neumann rv6xx_generate_steps(rdev, 146657e252bfSMichael Neumann new_state->medium.sclk, 146757e252bfSMichael Neumann new_state->high.sclk, 146857e252bfSMichael Neumann pi->hw.medium_sclk_index, 146957e252bfSMichael Neumann &pi->hw.high_sclk_index); 147057e252bfSMichael Neumann } 147157e252bfSMichael Neumann 147257e252bfSMichael Neumann static void rv6xx_enable_spread_spectrum(struct radeon_device *rdev, 147357e252bfSMichael Neumann bool enable) 147457e252bfSMichael Neumann { 147557e252bfSMichael Neumann if (enable) 147657e252bfSMichael Neumann rv6xx_enable_dynamic_spread_spectrum(rdev, true); 147757e252bfSMichael Neumann else { 147857e252bfSMichael Neumann rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_LOW, false); 147957e252bfSMichael Neumann rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_MEDIUM, false); 148057e252bfSMichael Neumann rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_HIGH, false); 148157e252bfSMichael Neumann rv6xx_enable_dynamic_spread_spectrum(rdev, false); 148257e252bfSMichael Neumann rv6xx_enable_memory_spread_spectrum(rdev, false); 148357e252bfSMichael Neumann } 148457e252bfSMichael Neumann } 148557e252bfSMichael Neumann 148657e252bfSMichael Neumann static void rv6xx_reset_lvtm_data_sync(struct radeon_device *rdev) 148757e252bfSMichael Neumann { 148857e252bfSMichael Neumann if (ASIC_IS_DCE3(rdev)) 148957e252bfSMichael Neumann WREG32_P(DCE3_LVTMA_DATA_SYNCHRONIZATION, LVTMA_PFREQCHG, ~LVTMA_PFREQCHG); 149057e252bfSMichael Neumann else 149157e252bfSMichael Neumann WREG32_P(LVTMA_DATA_SYNCHRONIZATION, LVTMA_PFREQCHG, ~LVTMA_PFREQCHG); 149257e252bfSMichael Neumann } 149357e252bfSMichael Neumann 149457e252bfSMichael Neumann static void rv6xx_enable_dynamic_pcie_gen2(struct radeon_device *rdev, 149557e252bfSMichael Neumann struct radeon_ps *new_ps, 149657e252bfSMichael Neumann bool enable) 149757e252bfSMichael Neumann { 149857e252bfSMichael Neumann struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); 149957e252bfSMichael Neumann 150057e252bfSMichael Neumann if (enable) { 150157e252bfSMichael Neumann rv6xx_enable_bif_dynamic_pcie_gen2(rdev, true); 150257e252bfSMichael Neumann rv6xx_enable_pcie_gen2_support(rdev); 150357e252bfSMichael Neumann r600_enable_dynamic_pcie_gen2(rdev, true); 150457e252bfSMichael Neumann } else { 150557e252bfSMichael Neumann if (!(new_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2)) 150657e252bfSMichael Neumann rv6xx_force_pcie_gen1(rdev); 150757e252bfSMichael Neumann rv6xx_enable_bif_dynamic_pcie_gen2(rdev, false); 150857e252bfSMichael Neumann r600_enable_dynamic_pcie_gen2(rdev, false); 150957e252bfSMichael Neumann } 151057e252bfSMichael Neumann } 151157e252bfSMichael Neumann 151257e252bfSMichael Neumann static void rv6xx_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev, 151357e252bfSMichael Neumann struct radeon_ps *new_ps, 151457e252bfSMichael Neumann struct radeon_ps *old_ps) 151557e252bfSMichael Neumann { 151657e252bfSMichael Neumann struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); 151757e252bfSMichael Neumann struct rv6xx_ps *current_state = rv6xx_get_ps(old_ps); 151857e252bfSMichael Neumann 151957e252bfSMichael Neumann if ((new_ps->vclk == old_ps->vclk) && 152057e252bfSMichael Neumann (new_ps->dclk == old_ps->dclk)) 152157e252bfSMichael Neumann return; 152257e252bfSMichael Neumann 152357e252bfSMichael Neumann if (new_state->high.sclk >= current_state->high.sclk) 152457e252bfSMichael Neumann return; 152557e252bfSMichael Neumann 152657e252bfSMichael Neumann radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk); 152757e252bfSMichael Neumann } 152857e252bfSMichael Neumann 152957e252bfSMichael Neumann static void rv6xx_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev, 153057e252bfSMichael Neumann struct radeon_ps *new_ps, 153157e252bfSMichael Neumann struct radeon_ps *old_ps) 153257e252bfSMichael Neumann { 153357e252bfSMichael Neumann struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); 153457e252bfSMichael Neumann struct rv6xx_ps *current_state = rv6xx_get_ps(old_ps); 153557e252bfSMichael Neumann 153657e252bfSMichael Neumann if ((new_ps->vclk == old_ps->vclk) && 153757e252bfSMichael Neumann (new_ps->dclk == old_ps->dclk)) 153857e252bfSMichael Neumann return; 153957e252bfSMichael Neumann 154057e252bfSMichael Neumann if (new_state->high.sclk < current_state->high.sclk) 154157e252bfSMichael Neumann return; 154257e252bfSMichael Neumann 154357e252bfSMichael Neumann radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk); 154457e252bfSMichael Neumann } 154557e252bfSMichael Neumann 154657e252bfSMichael Neumann int rv6xx_dpm_enable(struct radeon_device *rdev) 154757e252bfSMichael Neumann { 154857e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 154957e252bfSMichael Neumann struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps; 155057e252bfSMichael Neumann int ret; 155157e252bfSMichael Neumann 155257e252bfSMichael Neumann if (r600_dynamicpm_enabled(rdev)) 155357e252bfSMichael Neumann return -EINVAL; 155457e252bfSMichael Neumann 155557e252bfSMichael Neumann if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS) 155657e252bfSMichael Neumann rv6xx_enable_backbias(rdev, true); 155757e252bfSMichael Neumann 155857e252bfSMichael Neumann if (pi->dynamic_ss) 155957e252bfSMichael Neumann rv6xx_enable_spread_spectrum(rdev, true); 156057e252bfSMichael Neumann 156157e252bfSMichael Neumann rv6xx_program_mpll_timing_parameters(rdev); 156257e252bfSMichael Neumann rv6xx_program_bsp(rdev); 156357e252bfSMichael Neumann rv6xx_program_git(rdev); 156457e252bfSMichael Neumann rv6xx_program_tp(rdev); 156557e252bfSMichael Neumann rv6xx_program_tpp(rdev); 156657e252bfSMichael Neumann rv6xx_program_sstp(rdev); 156757e252bfSMichael Neumann rv6xx_program_fcp(rdev); 156857e252bfSMichael Neumann rv6xx_program_vddc3d_parameters(rdev); 156957e252bfSMichael Neumann rv6xx_program_voltage_timing_parameters(rdev); 157057e252bfSMichael Neumann rv6xx_program_engine_speed_parameters(rdev); 157157e252bfSMichael Neumann 157257e252bfSMichael Neumann rv6xx_enable_display_gap(rdev, true); 157357e252bfSMichael Neumann if (pi->display_gap == false) 157457e252bfSMichael Neumann rv6xx_enable_display_gap(rdev, false); 157557e252bfSMichael Neumann 157657e252bfSMichael Neumann rv6xx_program_power_level_enter_state(rdev); 157757e252bfSMichael Neumann 157857e252bfSMichael Neumann rv6xx_calculate_stepping_parameters(rdev, boot_ps); 157957e252bfSMichael Neumann 158057e252bfSMichael Neumann if (pi->voltage_control) 158157e252bfSMichael Neumann rv6xx_program_voltage_gpio_pins(rdev); 158257e252bfSMichael Neumann 158357e252bfSMichael Neumann rv6xx_generate_stepping_table(rdev, boot_ps); 158457e252bfSMichael Neumann 158557e252bfSMichael Neumann rv6xx_program_stepping_parameters_except_lowest_entry(rdev); 158657e252bfSMichael Neumann rv6xx_program_stepping_parameters_lowest_entry(rdev); 158757e252bfSMichael Neumann 158857e252bfSMichael Neumann rv6xx_program_power_level_low(rdev); 158957e252bfSMichael Neumann rv6xx_program_power_level_medium(rdev); 159057e252bfSMichael Neumann rv6xx_program_power_level_high(rdev); 159157e252bfSMichael Neumann rv6xx_program_vc(rdev); 159257e252bfSMichael Neumann rv6xx_program_at(rdev); 159357e252bfSMichael Neumann 159457e252bfSMichael Neumann r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true); 159557e252bfSMichael Neumann r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true); 159657e252bfSMichael Neumann r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, true); 159757e252bfSMichael Neumann 159857e252bfSMichael Neumann if (rdev->irq.installed && 159957e252bfSMichael Neumann r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { 160057e252bfSMichael Neumann ret = r600_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); 160157e252bfSMichael Neumann if (ret) 160257e252bfSMichael Neumann return ret; 160357e252bfSMichael Neumann rdev->irq.dpm_thermal = true; 160457e252bfSMichael Neumann radeon_irq_set(rdev); 160557e252bfSMichael Neumann } 160657e252bfSMichael Neumann 160757e252bfSMichael Neumann rv6xx_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); 160857e252bfSMichael Neumann 160957e252bfSMichael Neumann r600_start_dpm(rdev); 161057e252bfSMichael Neumann 161157e252bfSMichael Neumann if (pi->voltage_control) 161257e252bfSMichael Neumann rv6xx_enable_static_voltage_control(rdev, boot_ps, false); 161357e252bfSMichael Neumann 161457e252bfSMichael Neumann if (pi->dynamic_pcie_gen2) 161557e252bfSMichael Neumann rv6xx_enable_dynamic_pcie_gen2(rdev, boot_ps, true); 161657e252bfSMichael Neumann 161757e252bfSMichael Neumann if (pi->gfx_clock_gating) 161857e252bfSMichael Neumann r600_gfx_clockgating_enable(rdev, true); 161957e252bfSMichael Neumann 162057e252bfSMichael Neumann return 0; 162157e252bfSMichael Neumann } 162257e252bfSMichael Neumann 162357e252bfSMichael Neumann void rv6xx_dpm_disable(struct radeon_device *rdev) 162457e252bfSMichael Neumann { 162557e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 162657e252bfSMichael Neumann struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps; 162757e252bfSMichael Neumann 162857e252bfSMichael Neumann if (!r600_dynamicpm_enabled(rdev)) 162957e252bfSMichael Neumann return; 163057e252bfSMichael Neumann 163157e252bfSMichael Neumann r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true); 163257e252bfSMichael Neumann r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true); 163357e252bfSMichael Neumann rv6xx_enable_display_gap(rdev, false); 163457e252bfSMichael Neumann rv6xx_clear_vc(rdev); 163557e252bfSMichael Neumann r600_set_at(rdev, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF); 163657e252bfSMichael Neumann 163757e252bfSMichael Neumann if (pi->thermal_protection) 163857e252bfSMichael Neumann r600_enable_thermal_protection(rdev, false); 163957e252bfSMichael Neumann 164057e252bfSMichael Neumann r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW); 164157e252bfSMichael Neumann r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false); 164257e252bfSMichael Neumann r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false); 164357e252bfSMichael Neumann 164457e252bfSMichael Neumann if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS) 164557e252bfSMichael Neumann rv6xx_enable_backbias(rdev, false); 164657e252bfSMichael Neumann 164757e252bfSMichael Neumann rv6xx_enable_spread_spectrum(rdev, false); 164857e252bfSMichael Neumann 164957e252bfSMichael Neumann if (pi->voltage_control) 165057e252bfSMichael Neumann rv6xx_enable_static_voltage_control(rdev, boot_ps, true); 165157e252bfSMichael Neumann 165257e252bfSMichael Neumann if (pi->dynamic_pcie_gen2) 165357e252bfSMichael Neumann rv6xx_enable_dynamic_pcie_gen2(rdev, boot_ps, false); 165457e252bfSMichael Neumann 165557e252bfSMichael Neumann if (rdev->irq.installed && 165657e252bfSMichael Neumann r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { 165757e252bfSMichael Neumann rdev->irq.dpm_thermal = false; 165857e252bfSMichael Neumann radeon_irq_set(rdev); 165957e252bfSMichael Neumann } 166057e252bfSMichael Neumann 166157e252bfSMichael Neumann if (pi->gfx_clock_gating) 166257e252bfSMichael Neumann r600_gfx_clockgating_enable(rdev, false); 166357e252bfSMichael Neumann 166457e252bfSMichael Neumann r600_stop_dpm(rdev); 166557e252bfSMichael Neumann } 166657e252bfSMichael Neumann 166757e252bfSMichael Neumann int rv6xx_dpm_set_power_state(struct radeon_device *rdev) 166857e252bfSMichael Neumann { 166957e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 167057e252bfSMichael Neumann struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps; 167157e252bfSMichael Neumann struct radeon_ps *old_ps = rdev->pm.dpm.current_ps; 167257e252bfSMichael Neumann int ret; 167357e252bfSMichael Neumann 167457e252bfSMichael Neumann pi->restricted_levels = 0; 167557e252bfSMichael Neumann 167657e252bfSMichael Neumann rv6xx_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps); 167757e252bfSMichael Neumann 167857e252bfSMichael Neumann rv6xx_clear_vc(rdev); 167957e252bfSMichael Neumann r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true); 168057e252bfSMichael Neumann r600_set_at(rdev, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF); 168157e252bfSMichael Neumann 168257e252bfSMichael Neumann if (pi->thermal_protection) 168357e252bfSMichael Neumann r600_enable_thermal_protection(rdev, false); 168457e252bfSMichael Neumann 168557e252bfSMichael Neumann r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW); 168657e252bfSMichael Neumann r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false); 168757e252bfSMichael Neumann r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false); 168857e252bfSMichael Neumann 168957e252bfSMichael Neumann rv6xx_generate_transition_stepping(rdev, new_ps, old_ps); 169057e252bfSMichael Neumann rv6xx_program_power_level_medium_for_transition(rdev); 169157e252bfSMichael Neumann 169257e252bfSMichael Neumann if (pi->voltage_control) { 169357e252bfSMichael Neumann rv6xx_set_sw_voltage_to_safe(rdev, new_ps, old_ps); 169457e252bfSMichael Neumann if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC) 169557e252bfSMichael Neumann rv6xx_set_sw_voltage_to_low(rdev, old_ps); 169657e252bfSMichael Neumann } 169757e252bfSMichael Neumann 169857e252bfSMichael Neumann if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS) 169957e252bfSMichael Neumann rv6xx_set_safe_backbias(rdev, new_ps, old_ps); 170057e252bfSMichael Neumann 170157e252bfSMichael Neumann if (pi->dynamic_pcie_gen2) 170257e252bfSMichael Neumann rv6xx_set_safe_pcie_gen2(rdev, new_ps, old_ps); 170357e252bfSMichael Neumann 170457e252bfSMichael Neumann if (pi->voltage_control) 170557e252bfSMichael Neumann rv6xx_enable_dynamic_voltage_control(rdev, false); 170657e252bfSMichael Neumann 170757e252bfSMichael Neumann if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS) 170857e252bfSMichael Neumann rv6xx_enable_dynamic_backbias_control(rdev, false); 170957e252bfSMichael Neumann 171057e252bfSMichael Neumann if (pi->voltage_control) { 171157e252bfSMichael Neumann if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC) 171257e252bfSMichael Neumann rv6xx_step_voltage_if_increasing(rdev, new_ps, old_ps); 171357e252bfSMichael Neumann msleep((rdev->pm.dpm.voltage_response_time + 999) / 1000); 171457e252bfSMichael Neumann } 171557e252bfSMichael Neumann 171657e252bfSMichael Neumann r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true); 171757e252bfSMichael Neumann r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, false); 171857e252bfSMichael Neumann r600_wait_for_power_level_unequal(rdev, R600_POWER_LEVEL_LOW); 171957e252bfSMichael Neumann 172057e252bfSMichael Neumann rv6xx_generate_low_step(rdev, new_ps); 172157e252bfSMichael Neumann rv6xx_invalidate_intermediate_steps(rdev); 172257e252bfSMichael Neumann rv6xx_calculate_stepping_parameters(rdev, new_ps); 172357e252bfSMichael Neumann rv6xx_program_stepping_parameters_lowest_entry(rdev); 172457e252bfSMichael Neumann rv6xx_program_power_level_low_to_lowest_state(rdev); 172557e252bfSMichael Neumann 172657e252bfSMichael Neumann r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true); 172757e252bfSMichael Neumann r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW); 172857e252bfSMichael Neumann r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false); 172957e252bfSMichael Neumann 173057e252bfSMichael Neumann if (pi->voltage_control) { 173157e252bfSMichael Neumann if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC) { 173257e252bfSMichael Neumann ret = rv6xx_step_voltage_if_decreasing(rdev, new_ps, old_ps); 173357e252bfSMichael Neumann if (ret) 173457e252bfSMichael Neumann return ret; 173557e252bfSMichael Neumann } 173657e252bfSMichael Neumann rv6xx_enable_dynamic_voltage_control(rdev, true); 173757e252bfSMichael Neumann } 173857e252bfSMichael Neumann 173957e252bfSMichael Neumann if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS) 174057e252bfSMichael Neumann rv6xx_enable_dynamic_backbias_control(rdev, true); 174157e252bfSMichael Neumann 174257e252bfSMichael Neumann if (pi->dynamic_pcie_gen2) 174357e252bfSMichael Neumann rv6xx_enable_dynamic_pcie_gen2(rdev, new_ps, true); 174457e252bfSMichael Neumann 174557e252bfSMichael Neumann rv6xx_reset_lvtm_data_sync(rdev); 174657e252bfSMichael Neumann 174757e252bfSMichael Neumann rv6xx_generate_stepping_table(rdev, new_ps); 174857e252bfSMichael Neumann rv6xx_program_stepping_parameters_except_lowest_entry(rdev); 174957e252bfSMichael Neumann rv6xx_program_power_level_low(rdev); 175057e252bfSMichael Neumann rv6xx_program_power_level_medium(rdev); 175157e252bfSMichael Neumann rv6xx_program_power_level_high(rdev); 175257e252bfSMichael Neumann rv6xx_enable_medium(rdev); 175357e252bfSMichael Neumann rv6xx_enable_high(rdev); 175457e252bfSMichael Neumann 175557e252bfSMichael Neumann if (pi->thermal_protection) 175657e252bfSMichael Neumann rv6xx_enable_thermal_protection(rdev, true); 175757e252bfSMichael Neumann rv6xx_program_vc(rdev); 175857e252bfSMichael Neumann rv6xx_program_at(rdev); 175957e252bfSMichael Neumann 176057e252bfSMichael Neumann rv6xx_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps); 176157e252bfSMichael Neumann 176257e252bfSMichael Neumann return 0; 176357e252bfSMichael Neumann } 176457e252bfSMichael Neumann 176557e252bfSMichael Neumann void rv6xx_setup_asic(struct radeon_device *rdev) 176657e252bfSMichael Neumann { 176757e252bfSMichael Neumann r600_enable_acpi_pm(rdev); 176857e252bfSMichael Neumann 176957e252bfSMichael Neumann if (radeon_aspm != 0) { 177057e252bfSMichael Neumann if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s) 177157e252bfSMichael Neumann rv6xx_enable_l0s(rdev); 177257e252bfSMichael Neumann if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1) 177357e252bfSMichael Neumann rv6xx_enable_l1(rdev); 177457e252bfSMichael Neumann if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1) 177557e252bfSMichael Neumann rv6xx_enable_pll_sleep_in_l1(rdev); 177657e252bfSMichael Neumann } 177757e252bfSMichael Neumann } 177857e252bfSMichael Neumann 177957e252bfSMichael Neumann void rv6xx_dpm_display_configuration_changed(struct radeon_device *rdev) 178057e252bfSMichael Neumann { 178157e252bfSMichael Neumann rv6xx_program_display_gap(rdev); 178257e252bfSMichael Neumann } 178357e252bfSMichael Neumann 178457e252bfSMichael Neumann union power_info { 178557e252bfSMichael Neumann struct _ATOM_POWERPLAY_INFO info; 178657e252bfSMichael Neumann struct _ATOM_POWERPLAY_INFO_V2 info_2; 178757e252bfSMichael Neumann struct _ATOM_POWERPLAY_INFO_V3 info_3; 178857e252bfSMichael Neumann struct _ATOM_PPLIB_POWERPLAYTABLE pplib; 178957e252bfSMichael Neumann struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2; 179057e252bfSMichael Neumann struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3; 179157e252bfSMichael Neumann }; 179257e252bfSMichael Neumann 179357e252bfSMichael Neumann union pplib_clock_info { 179457e252bfSMichael Neumann struct _ATOM_PPLIB_R600_CLOCK_INFO r600; 179557e252bfSMichael Neumann struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780; 179657e252bfSMichael Neumann struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen; 179757e252bfSMichael Neumann struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo; 179857e252bfSMichael Neumann }; 179957e252bfSMichael Neumann 180057e252bfSMichael Neumann union pplib_power_state { 180157e252bfSMichael Neumann struct _ATOM_PPLIB_STATE v1; 180257e252bfSMichael Neumann struct _ATOM_PPLIB_STATE_V2 v2; 180357e252bfSMichael Neumann }; 180457e252bfSMichael Neumann 180557e252bfSMichael Neumann static void rv6xx_parse_pplib_non_clock_info(struct radeon_device *rdev, 180657e252bfSMichael Neumann struct radeon_ps *rps, 180757e252bfSMichael Neumann struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info) 180857e252bfSMichael Neumann { 180957e252bfSMichael Neumann rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings); 181057e252bfSMichael Neumann rps->class = le16_to_cpu(non_clock_info->usClassification); 181157e252bfSMichael Neumann rps->class2 = le16_to_cpu(non_clock_info->usClassification2); 181257e252bfSMichael Neumann 181357e252bfSMichael Neumann if (r600_is_uvd_state(rps->class, rps->class2)) { 181457e252bfSMichael Neumann rps->vclk = RV6XX_DEFAULT_VCLK_FREQ; 181557e252bfSMichael Neumann rps->dclk = RV6XX_DEFAULT_DCLK_FREQ; 181657e252bfSMichael Neumann } else { 181757e252bfSMichael Neumann rps->vclk = 0; 181857e252bfSMichael Neumann rps->dclk = 0; 181957e252bfSMichael Neumann } 182057e252bfSMichael Neumann 182157e252bfSMichael Neumann if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) 182257e252bfSMichael Neumann rdev->pm.dpm.boot_ps = rps; 182357e252bfSMichael Neumann if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) 182457e252bfSMichael Neumann rdev->pm.dpm.uvd_ps = rps; 182557e252bfSMichael Neumann } 182657e252bfSMichael Neumann 182757e252bfSMichael Neumann static void rv6xx_parse_pplib_clock_info(struct radeon_device *rdev, 182857e252bfSMichael Neumann struct radeon_ps *rps, int index, 182957e252bfSMichael Neumann union pplib_clock_info *clock_info) 183057e252bfSMichael Neumann { 183157e252bfSMichael Neumann struct rv6xx_ps *ps = rv6xx_get_ps(rps); 183257e252bfSMichael Neumann u32 sclk, mclk; 183357e252bfSMichael Neumann u16 vddc; 183457e252bfSMichael Neumann struct rv6xx_pl *pl; 183557e252bfSMichael Neumann 183657e252bfSMichael Neumann switch (index) { 183757e252bfSMichael Neumann case 0: 183857e252bfSMichael Neumann pl = &ps->low; 183957e252bfSMichael Neumann break; 184057e252bfSMichael Neumann case 1: 184157e252bfSMichael Neumann pl = &ps->medium; 184257e252bfSMichael Neumann break; 184357e252bfSMichael Neumann case 2: 184457e252bfSMichael Neumann default: 184557e252bfSMichael Neumann pl = &ps->high; 184657e252bfSMichael Neumann break; 184757e252bfSMichael Neumann } 184857e252bfSMichael Neumann 184957e252bfSMichael Neumann sclk = le16_to_cpu(clock_info->r600.usEngineClockLow); 185057e252bfSMichael Neumann sclk |= clock_info->r600.ucEngineClockHigh << 16; 185157e252bfSMichael Neumann mclk = le16_to_cpu(clock_info->r600.usMemoryClockLow); 185257e252bfSMichael Neumann mclk |= clock_info->r600.ucMemoryClockHigh << 16; 185357e252bfSMichael Neumann 185457e252bfSMichael Neumann pl->mclk = mclk; 185557e252bfSMichael Neumann pl->sclk = sclk; 185657e252bfSMichael Neumann pl->vddc = le16_to_cpu(clock_info->r600.usVDDC); 185757e252bfSMichael Neumann pl->flags = le32_to_cpu(clock_info->r600.ulFlags); 185857e252bfSMichael Neumann 185957e252bfSMichael Neumann /* patch up vddc if necessary */ 186057e252bfSMichael Neumann if (pl->vddc == 0xff01) { 186157e252bfSMichael Neumann if (radeon_atom_get_max_vddc(rdev, 0, 0, &vddc) == 0) 186257e252bfSMichael Neumann pl->vddc = vddc; 186357e252bfSMichael Neumann } 186457e252bfSMichael Neumann 186557e252bfSMichael Neumann /* fix up pcie gen2 */ 186657e252bfSMichael Neumann if (pl->flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) { 186757e252bfSMichael Neumann if ((rdev->family == CHIP_RV610) || (rdev->family == CHIP_RV630)) { 186857e252bfSMichael Neumann if (pl->vddc < 1100) 186957e252bfSMichael Neumann pl->flags &= ~ATOM_PPLIB_R600_FLAGS_PCIEGEN2; 187057e252bfSMichael Neumann } 187157e252bfSMichael Neumann } 187257e252bfSMichael Neumann 187357e252bfSMichael Neumann /* patch up boot state */ 187457e252bfSMichael Neumann if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) { 187557e252bfSMichael Neumann u16 vddc, vddci, mvdd; 187657e252bfSMichael Neumann radeon_atombios_get_default_voltages(rdev, &vddc, &vddci, &mvdd); 187757e252bfSMichael Neumann pl->mclk = rdev->clock.default_mclk; 187857e252bfSMichael Neumann pl->sclk = rdev->clock.default_sclk; 187957e252bfSMichael Neumann pl->vddc = vddc; 188057e252bfSMichael Neumann } 188157e252bfSMichael Neumann } 188257e252bfSMichael Neumann 188357e252bfSMichael Neumann static int rv6xx_parse_power_table(struct radeon_device *rdev) 188457e252bfSMichael Neumann { 188557e252bfSMichael Neumann struct radeon_mode_info *mode_info = &rdev->mode_info; 188657e252bfSMichael Neumann struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; 188757e252bfSMichael Neumann union pplib_power_state *power_state; 188857e252bfSMichael Neumann int i, j; 188957e252bfSMichael Neumann union pplib_clock_info *clock_info; 189057e252bfSMichael Neumann union power_info *power_info; 189157e252bfSMichael Neumann int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); 189257e252bfSMichael Neumann u16 data_offset; 189357e252bfSMichael Neumann u8 frev, crev; 189457e252bfSMichael Neumann struct rv6xx_ps *ps; 189557e252bfSMichael Neumann 189657e252bfSMichael Neumann if (!atom_parse_data_header(mode_info->atom_context, index, NULL, 189757e252bfSMichael Neumann &frev, &crev, &data_offset)) 189857e252bfSMichael Neumann return -EINVAL; 189957e252bfSMichael Neumann power_info = (union power_info *)((uint8_t*)mode_info->atom_context->bios + data_offset); 190057e252bfSMichael Neumann 190157e252bfSMichael Neumann rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) * 190257e252bfSMichael Neumann power_info->pplib.ucNumStates, GFP_KERNEL); 190357e252bfSMichael Neumann if (!rdev->pm.dpm.ps) 190457e252bfSMichael Neumann return -ENOMEM; 190557e252bfSMichael Neumann rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps); 190657e252bfSMichael Neumann rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime); 190757e252bfSMichael Neumann rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime); 190857e252bfSMichael Neumann 190957e252bfSMichael Neumann for (i = 0; i < power_info->pplib.ucNumStates; i++) { 191057e252bfSMichael Neumann power_state = (union pplib_power_state *) 191157e252bfSMichael Neumann ((uint8_t*)mode_info->atom_context->bios + data_offset + 191257e252bfSMichael Neumann le16_to_cpu(power_info->pplib.usStateArrayOffset) + 191357e252bfSMichael Neumann i * power_info->pplib.ucStateEntrySize); 191457e252bfSMichael Neumann non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) 191557e252bfSMichael Neumann ((uint8_t*)mode_info->atom_context->bios + data_offset + 191657e252bfSMichael Neumann le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) + 191757e252bfSMichael Neumann (power_state->v1.ucNonClockStateIndex * 191857e252bfSMichael Neumann power_info->pplib.ucNonClockSize)); 191957e252bfSMichael Neumann if (power_info->pplib.ucStateEntrySize - 1) { 1920*4cd92098Szrj u8 *idx; 192157e252bfSMichael Neumann ps = kzalloc(sizeof(struct rv6xx_ps), GFP_KERNEL); 192257e252bfSMichael Neumann if (ps == NULL) { 192357e252bfSMichael Neumann kfree(rdev->pm.dpm.ps); 192457e252bfSMichael Neumann return -ENOMEM; 192557e252bfSMichael Neumann } 192657e252bfSMichael Neumann rdev->pm.dpm.ps[i].ps_priv = ps; 192757e252bfSMichael Neumann rv6xx_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i], 192857e252bfSMichael Neumann non_clock_info); 1929*4cd92098Szrj idx = (u8 *)&power_state->v1.ucClockStateIndices[0]; 193057e252bfSMichael Neumann for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) { 193157e252bfSMichael Neumann clock_info = (union pplib_clock_info *) 193257e252bfSMichael Neumann ((uint8_t*)mode_info->atom_context->bios + data_offset + 193357e252bfSMichael Neumann le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) + 1934*4cd92098Szrj (idx[j] * power_info->pplib.ucClockInfoSize)); 193557e252bfSMichael Neumann rv6xx_parse_pplib_clock_info(rdev, 193657e252bfSMichael Neumann &rdev->pm.dpm.ps[i], j, 193757e252bfSMichael Neumann clock_info); 193857e252bfSMichael Neumann } 193957e252bfSMichael Neumann } 194057e252bfSMichael Neumann } 194157e252bfSMichael Neumann rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates; 194257e252bfSMichael Neumann return 0; 194357e252bfSMichael Neumann } 194457e252bfSMichael Neumann 194557e252bfSMichael Neumann int rv6xx_dpm_init(struct radeon_device *rdev) 194657e252bfSMichael Neumann { 194757e252bfSMichael Neumann struct radeon_atom_ss ss; 194857e252bfSMichael Neumann struct atom_clock_dividers dividers; 194957e252bfSMichael Neumann struct rv6xx_power_info *pi; 195057e252bfSMichael Neumann int ret; 195157e252bfSMichael Neumann 195257e252bfSMichael Neumann pi = kzalloc(sizeof(struct rv6xx_power_info), GFP_KERNEL); 195357e252bfSMichael Neumann if (pi == NULL) 195457e252bfSMichael Neumann return -ENOMEM; 195557e252bfSMichael Neumann rdev->pm.dpm.priv = pi; 195657e252bfSMichael Neumann 195757e252bfSMichael Neumann ret = rv6xx_parse_power_table(rdev); 195857e252bfSMichael Neumann if (ret) 195957e252bfSMichael Neumann return ret; 196057e252bfSMichael Neumann 196157e252bfSMichael Neumann if (rdev->pm.dpm.voltage_response_time == 0) 196257e252bfSMichael Neumann rdev->pm.dpm.voltage_response_time = R600_VOLTAGERESPONSETIME_DFLT; 196357e252bfSMichael Neumann if (rdev->pm.dpm.backbias_response_time == 0) 196457e252bfSMichael Neumann rdev->pm.dpm.backbias_response_time = R600_BACKBIASRESPONSETIME_DFLT; 196557e252bfSMichael Neumann 196657e252bfSMichael Neumann ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, 196757e252bfSMichael Neumann 0, false, ÷rs); 196857e252bfSMichael Neumann if (ret) 196957e252bfSMichael Neumann pi->spll_ref_div = dividers.ref_div + 1; 197057e252bfSMichael Neumann else 197157e252bfSMichael Neumann pi->spll_ref_div = R600_REFERENCEDIVIDER_DFLT; 197257e252bfSMichael Neumann 197357e252bfSMichael Neumann ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM, 197457e252bfSMichael Neumann 0, false, ÷rs); 197557e252bfSMichael Neumann if (ret) 197657e252bfSMichael Neumann pi->mpll_ref_div = dividers.ref_div + 1; 197757e252bfSMichael Neumann else 197857e252bfSMichael Neumann pi->mpll_ref_div = R600_REFERENCEDIVIDER_DFLT; 197957e252bfSMichael Neumann 198057e252bfSMichael Neumann if (rdev->family >= CHIP_RV670) 198157e252bfSMichael Neumann pi->fb_div_scale = 1; 198257e252bfSMichael Neumann else 198357e252bfSMichael Neumann pi->fb_div_scale = 0; 198457e252bfSMichael Neumann 198557e252bfSMichael Neumann pi->voltage_control = 198657e252bfSMichael Neumann radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, 0); 198757e252bfSMichael Neumann 198857e252bfSMichael Neumann pi->gfx_clock_gating = true; 198957e252bfSMichael Neumann 199057e252bfSMichael Neumann pi->sclk_ss = radeon_atombios_get_asic_ss_info(rdev, &ss, 199157e252bfSMichael Neumann ASIC_INTERNAL_ENGINE_SS, 0); 199257e252bfSMichael Neumann pi->mclk_ss = radeon_atombios_get_asic_ss_info(rdev, &ss, 199357e252bfSMichael Neumann ASIC_INTERNAL_MEMORY_SS, 0); 199457e252bfSMichael Neumann 199557e252bfSMichael Neumann /* Disable sclk ss, causes hangs on a lot of systems */ 199657e252bfSMichael Neumann pi->sclk_ss = false; 199757e252bfSMichael Neumann 199857e252bfSMichael Neumann if (pi->sclk_ss || pi->mclk_ss) 199957e252bfSMichael Neumann pi->dynamic_ss = true; 200057e252bfSMichael Neumann else 200157e252bfSMichael Neumann pi->dynamic_ss = false; 200257e252bfSMichael Neumann 200357e252bfSMichael Neumann pi->dynamic_pcie_gen2 = true; 200457e252bfSMichael Neumann 200557e252bfSMichael Neumann if (pi->gfx_clock_gating && 200657e252bfSMichael Neumann (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE)) 200757e252bfSMichael Neumann pi->thermal_protection = true; 200857e252bfSMichael Neumann else 200957e252bfSMichael Neumann pi->thermal_protection = false; 201057e252bfSMichael Neumann 201157e252bfSMichael Neumann pi->display_gap = true; 201257e252bfSMichael Neumann 201357e252bfSMichael Neumann return 0; 201457e252bfSMichael Neumann } 201557e252bfSMichael Neumann 201657e252bfSMichael Neumann void rv6xx_dpm_print_power_state(struct radeon_device *rdev, 201757e252bfSMichael Neumann struct radeon_ps *rps) 201857e252bfSMichael Neumann { 201957e252bfSMichael Neumann struct rv6xx_ps *ps = rv6xx_get_ps(rps); 202057e252bfSMichael Neumann struct rv6xx_pl *pl; 202157e252bfSMichael Neumann 202257e252bfSMichael Neumann r600_dpm_print_class_info(rps->class, rps->class2); 202357e252bfSMichael Neumann r600_dpm_print_cap_info(rps->caps); 202457e252bfSMichael Neumann printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); 202557e252bfSMichael Neumann pl = &ps->low; 202657e252bfSMichael Neumann printk("\t\tpower level 0 sclk: %u mclk: %u vddc: %u\n", 202757e252bfSMichael Neumann pl->sclk, pl->mclk, pl->vddc); 202857e252bfSMichael Neumann pl = &ps->medium; 202957e252bfSMichael Neumann printk("\t\tpower level 1 sclk: %u mclk: %u vddc: %u\n", 203057e252bfSMichael Neumann pl->sclk, pl->mclk, pl->vddc); 203157e252bfSMichael Neumann pl = &ps->high; 203257e252bfSMichael Neumann printk("\t\tpower level 2 sclk: %u mclk: %u vddc: %u\n", 203357e252bfSMichael Neumann pl->sclk, pl->mclk, pl->vddc); 203457e252bfSMichael Neumann r600_dpm_print_ps_status(rdev, rps); 203557e252bfSMichael Neumann } 203657e252bfSMichael Neumann 203757e252bfSMichael Neumann void rv6xx_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, 203857e252bfSMichael Neumann struct seq_file *m) 203957e252bfSMichael Neumann { 204057e252bfSMichael Neumann struct radeon_ps *rps = rdev->pm.dpm.current_ps; 204157e252bfSMichael Neumann struct rv6xx_ps *ps = rv6xx_get_ps(rps); 204257e252bfSMichael Neumann struct rv6xx_pl *pl; 204357e252bfSMichael Neumann u32 current_index = 204457e252bfSMichael Neumann (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >> 204557e252bfSMichael Neumann CURRENT_PROFILE_INDEX_SHIFT; 204657e252bfSMichael Neumann 204757e252bfSMichael Neumann if (current_index > 2) { 204857e252bfSMichael Neumann seq_printf(m, "invalid dpm profile %d\n", current_index); 204957e252bfSMichael Neumann } else { 205057e252bfSMichael Neumann if (current_index == 0) 205157e252bfSMichael Neumann pl = &ps->low; 205257e252bfSMichael Neumann else if (current_index == 1) 205357e252bfSMichael Neumann pl = &ps->medium; 205457e252bfSMichael Neumann else /* current_index == 2 */ 205557e252bfSMichael Neumann pl = &ps->high; 205657e252bfSMichael Neumann seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); 205757e252bfSMichael Neumann seq_printf(m, "power level %d sclk: %u mclk: %u vddc: %u\n", 205857e252bfSMichael Neumann current_index, pl->sclk, pl->mclk, pl->vddc); 205957e252bfSMichael Neumann } 206057e252bfSMichael Neumann } 206157e252bfSMichael Neumann 206257e252bfSMichael Neumann void rv6xx_dpm_fini(struct radeon_device *rdev) 206357e252bfSMichael Neumann { 206457e252bfSMichael Neumann int i; 206557e252bfSMichael Neumann 206657e252bfSMichael Neumann for (i = 0; i < rdev->pm.dpm.num_ps; i++) { 206757e252bfSMichael Neumann kfree(rdev->pm.dpm.ps[i].ps_priv); 206857e252bfSMichael Neumann } 206957e252bfSMichael Neumann kfree(rdev->pm.dpm.ps); 207057e252bfSMichael Neumann kfree(rdev->pm.dpm.priv); 207157e252bfSMichael Neumann } 207257e252bfSMichael Neumann 207357e252bfSMichael Neumann u32 rv6xx_dpm_get_sclk(struct radeon_device *rdev, bool low) 207457e252bfSMichael Neumann { 207557e252bfSMichael Neumann struct rv6xx_ps *requested_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps); 207657e252bfSMichael Neumann 207757e252bfSMichael Neumann if (low) 207857e252bfSMichael Neumann return requested_state->low.sclk; 207957e252bfSMichael Neumann else 208057e252bfSMichael Neumann return requested_state->high.sclk; 208157e252bfSMichael Neumann } 208257e252bfSMichael Neumann 208357e252bfSMichael Neumann u32 rv6xx_dpm_get_mclk(struct radeon_device *rdev, bool low) 208457e252bfSMichael Neumann { 208557e252bfSMichael Neumann struct rv6xx_ps *requested_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps); 208657e252bfSMichael Neumann 208757e252bfSMichael Neumann if (low) 208857e252bfSMichael Neumann return requested_state->low.mclk; 208957e252bfSMichael Neumann else 209057e252bfSMichael Neumann return requested_state->high.mclk; 209157e252bfSMichael Neumann } 209257e252bfSMichael Neumann 209357e252bfSMichael Neumann int rv6xx_dpm_force_performance_level(struct radeon_device *rdev, 209457e252bfSMichael Neumann enum radeon_dpm_forced_level level) 209557e252bfSMichael Neumann { 209657e252bfSMichael Neumann struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 209757e252bfSMichael Neumann 209857e252bfSMichael Neumann if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { 209957e252bfSMichael Neumann pi->restricted_levels = 3; 210057e252bfSMichael Neumann } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) { 210157e252bfSMichael Neumann pi->restricted_levels = 2; 210257e252bfSMichael Neumann } else { 210357e252bfSMichael Neumann pi->restricted_levels = 0; 210457e252bfSMichael Neumann } 210557e252bfSMichael Neumann 210657e252bfSMichael Neumann rv6xx_clear_vc(rdev); 210757e252bfSMichael Neumann r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true); 210857e252bfSMichael Neumann r600_set_at(rdev, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF); 210957e252bfSMichael Neumann r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW); 211057e252bfSMichael Neumann r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false); 211157e252bfSMichael Neumann r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false); 211257e252bfSMichael Neumann rv6xx_enable_medium(rdev); 211357e252bfSMichael Neumann rv6xx_enable_high(rdev); 211457e252bfSMichael Neumann if (pi->restricted_levels == 3) 211557e252bfSMichael Neumann r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, false); 211657e252bfSMichael Neumann rv6xx_program_vc(rdev); 211757e252bfSMichael Neumann rv6xx_program_at(rdev); 211857e252bfSMichael Neumann 211957e252bfSMichael Neumann rdev->pm.dpm.forced_level = level; 212057e252bfSMichael Neumann 212157e252bfSMichael Neumann return 0; 212257e252bfSMichael Neumann } 2123