18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2011 Advanced Micro Devices, Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation 78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 128c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 158c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 168c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 178c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 188c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 198c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 208c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Authors: Alex Deucher 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "radeon.h" 268c2ecf20Sopenharmony_ci#include "radeon_asic.h" 278c2ecf20Sopenharmony_ci#include "rv6xxd.h" 288c2ecf20Sopenharmony_ci#include "r600_dpm.h" 298c2ecf20Sopenharmony_ci#include "rv6xx_dpm.h" 308c2ecf20Sopenharmony_ci#include "atom.h" 318c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic u32 rv6xx_scale_count_given_unit(struct radeon_device *rdev, 348c2ecf20Sopenharmony_ci u32 unscaled_count, u32 unit); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic struct rv6xx_ps *rv6xx_get_ps(struct radeon_ps *rps) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci struct rv6xx_ps *ps = rps->ps_priv; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci return ps; 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic struct rv6xx_power_info *rv6xx_get_pi(struct radeon_device *rdev) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rdev->pm.dpm.priv; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci return pi; 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic void rv6xx_force_pcie_gen1(struct radeon_device *rdev) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci u32 tmp; 538c2ecf20Sopenharmony_ci int i; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); 568c2ecf20Sopenharmony_ci tmp &= LC_GEN2_EN; 578c2ecf20Sopenharmony_ci WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); 608c2ecf20Sopenharmony_ci tmp |= LC_INITIATE_LINK_SPEED_CHANGE; 618c2ecf20Sopenharmony_ci WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci for (i = 0; i < rdev->usec_timeout; i++) { 648c2ecf20Sopenharmony_ci if (!(RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL) & LC_CURRENT_DATA_RATE)) 658c2ecf20Sopenharmony_ci break; 668c2ecf20Sopenharmony_ci udelay(1); 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); 708c2ecf20Sopenharmony_ci tmp &= ~LC_INITIATE_LINK_SPEED_CHANGE; 718c2ecf20Sopenharmony_ci WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic void rv6xx_enable_pcie_gen2_support(struct radeon_device *rdev) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci u32 tmp; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) && 818c2ecf20Sopenharmony_ci (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2)) { 828c2ecf20Sopenharmony_ci tmp |= LC_GEN2_EN; 838c2ecf20Sopenharmony_ci WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic void rv6xx_enable_bif_dynamic_pcie_gen2(struct radeon_device *rdev, 888c2ecf20Sopenharmony_ci bool enable) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci u32 tmp; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL) & ~LC_HW_VOLTAGE_IF_CONTROL_MASK; 938c2ecf20Sopenharmony_ci if (enable) 948c2ecf20Sopenharmony_ci tmp |= LC_HW_VOLTAGE_IF_CONTROL(1); 958c2ecf20Sopenharmony_ci else 968c2ecf20Sopenharmony_ci tmp |= LC_HW_VOLTAGE_IF_CONTROL(0); 978c2ecf20Sopenharmony_ci WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp); 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic void rv6xx_enable_l0s(struct radeon_device *rdev) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci u32 tmp; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL) & ~LC_L0S_INACTIVITY_MASK; 1058c2ecf20Sopenharmony_ci tmp |= LC_L0S_INACTIVITY(3); 1068c2ecf20Sopenharmony_ci WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic void rv6xx_enable_l1(struct radeon_device *rdev) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci u32 tmp; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL); 1148c2ecf20Sopenharmony_ci tmp &= ~LC_L1_INACTIVITY_MASK; 1158c2ecf20Sopenharmony_ci tmp |= LC_L1_INACTIVITY(4); 1168c2ecf20Sopenharmony_ci tmp &= ~LC_PMI_TO_L1_DIS; 1178c2ecf20Sopenharmony_ci tmp &= ~LC_ASPM_TO_L1_DIS; 1188c2ecf20Sopenharmony_ci WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic void rv6xx_enable_pll_sleep_in_l1(struct radeon_device *rdev) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci u32 tmp; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL) & ~LC_L1_INACTIVITY_MASK; 1268c2ecf20Sopenharmony_ci tmp |= LC_L1_INACTIVITY(8); 1278c2ecf20Sopenharmony_ci WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci /* NOTE, this is a PCIE indirect reg, not PCIE PORT */ 1308c2ecf20Sopenharmony_ci tmp = RREG32_PCIE(PCIE_P_CNTL); 1318c2ecf20Sopenharmony_ci tmp |= P_PLL_PWRDN_IN_L1L23; 1328c2ecf20Sopenharmony_ci tmp &= ~P_PLL_BUF_PDNB; 1338c2ecf20Sopenharmony_ci tmp &= ~P_PLL_PDNB; 1348c2ecf20Sopenharmony_ci tmp |= P_ALLOW_PRX_FRONTEND_SHUTOFF; 1358c2ecf20Sopenharmony_ci WREG32_PCIE(PCIE_P_CNTL, tmp); 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic int rv6xx_convert_clock_to_stepping(struct radeon_device *rdev, 1398c2ecf20Sopenharmony_ci u32 clock, struct rv6xx_sclk_stepping *step) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci int ret; 1428c2ecf20Sopenharmony_ci struct atom_clock_dividers dividers; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, 1458c2ecf20Sopenharmony_ci clock, false, ÷rs); 1468c2ecf20Sopenharmony_ci if (ret) 1478c2ecf20Sopenharmony_ci return ret; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (dividers.enable_post_div) 1508c2ecf20Sopenharmony_ci step->post_divider = 2 + (dividers.post_div & 0xF) + (dividers.post_div >> 4); 1518c2ecf20Sopenharmony_ci else 1528c2ecf20Sopenharmony_ci step->post_divider = 1; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci step->vco_frequency = clock * step->post_divider; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci return 0; 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_cistatic void rv6xx_output_stepping(struct radeon_device *rdev, 1608c2ecf20Sopenharmony_ci u32 step_index, struct rv6xx_sclk_stepping *step) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 1638c2ecf20Sopenharmony_ci u32 ref_clk = rdev->clock.spll.reference_freq; 1648c2ecf20Sopenharmony_ci u32 fb_divider; 1658c2ecf20Sopenharmony_ci u32 spll_step_count = rv6xx_scale_count_given_unit(rdev, 1668c2ecf20Sopenharmony_ci R600_SPLLSTEPTIME_DFLT * 1678c2ecf20Sopenharmony_ci pi->spll_ref_div, 1688c2ecf20Sopenharmony_ci R600_SPLLSTEPUNIT_DFLT); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci r600_engine_clock_entry_enable(rdev, step_index, true); 1718c2ecf20Sopenharmony_ci r600_engine_clock_entry_enable_pulse_skipping(rdev, step_index, false); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci if (step->post_divider == 1) 1748c2ecf20Sopenharmony_ci r600_engine_clock_entry_enable_post_divider(rdev, step_index, false); 1758c2ecf20Sopenharmony_ci else { 1768c2ecf20Sopenharmony_ci u32 lo_len = (step->post_divider - 2) / 2; 1778c2ecf20Sopenharmony_ci u32 hi_len = step->post_divider - 2 - lo_len; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci r600_engine_clock_entry_enable_post_divider(rdev, step_index, true); 1808c2ecf20Sopenharmony_ci r600_engine_clock_entry_set_post_divider(rdev, step_index, (hi_len << 4) | lo_len); 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci fb_divider = ((step->vco_frequency * pi->spll_ref_div) / ref_clk) >> 1848c2ecf20Sopenharmony_ci pi->fb_div_scale; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci r600_engine_clock_entry_set_reference_divider(rdev, step_index, 1878c2ecf20Sopenharmony_ci pi->spll_ref_div - 1); 1888c2ecf20Sopenharmony_ci r600_engine_clock_entry_set_feedback_divider(rdev, step_index, fb_divider); 1898c2ecf20Sopenharmony_ci r600_engine_clock_entry_set_step_time(rdev, step_index, spll_step_count); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic struct rv6xx_sclk_stepping rv6xx_next_vco_step(struct radeon_device *rdev, 1948c2ecf20Sopenharmony_ci struct rv6xx_sclk_stepping *cur, 1958c2ecf20Sopenharmony_ci bool increasing_vco, u32 step_size) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci struct rv6xx_sclk_stepping next; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci next.post_divider = cur->post_divider; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (increasing_vco) 2028c2ecf20Sopenharmony_ci next.vco_frequency = (cur->vco_frequency * (100 + step_size)) / 100; 2038c2ecf20Sopenharmony_ci else 2048c2ecf20Sopenharmony_ci next.vco_frequency = (cur->vco_frequency * 100 + 99 + step_size) / (100 + step_size); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci return next; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic bool rv6xx_can_step_post_div(struct radeon_device *rdev, 2108c2ecf20Sopenharmony_ci struct rv6xx_sclk_stepping *cur, 2118c2ecf20Sopenharmony_ci struct rv6xx_sclk_stepping *target) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci return (cur->post_divider > target->post_divider) && 2148c2ecf20Sopenharmony_ci ((cur->vco_frequency * target->post_divider) <= 2158c2ecf20Sopenharmony_ci (target->vco_frequency * (cur->post_divider - 1))); 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic struct rv6xx_sclk_stepping rv6xx_next_post_div_step(struct radeon_device *rdev, 2198c2ecf20Sopenharmony_ci struct rv6xx_sclk_stepping *cur, 2208c2ecf20Sopenharmony_ci struct rv6xx_sclk_stepping *target) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct rv6xx_sclk_stepping next = *cur; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci while (rv6xx_can_step_post_div(rdev, &next, target)) 2258c2ecf20Sopenharmony_ci next.post_divider--; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci return next; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic bool rv6xx_reached_stepping_target(struct radeon_device *rdev, 2318c2ecf20Sopenharmony_ci struct rv6xx_sclk_stepping *cur, 2328c2ecf20Sopenharmony_ci struct rv6xx_sclk_stepping *target, 2338c2ecf20Sopenharmony_ci bool increasing_vco) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci return (increasing_vco && (cur->vco_frequency >= target->vco_frequency)) || 2368c2ecf20Sopenharmony_ci (!increasing_vco && (cur->vco_frequency <= target->vco_frequency)); 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic void rv6xx_generate_steps(struct radeon_device *rdev, 2408c2ecf20Sopenharmony_ci u32 low, u32 high, 2418c2ecf20Sopenharmony_ci u32 start_index, u8 *end_index) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct rv6xx_sclk_stepping cur; 2448c2ecf20Sopenharmony_ci struct rv6xx_sclk_stepping target; 2458c2ecf20Sopenharmony_ci bool increasing_vco; 2468c2ecf20Sopenharmony_ci u32 step_index = start_index; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci rv6xx_convert_clock_to_stepping(rdev, low, &cur); 2498c2ecf20Sopenharmony_ci rv6xx_convert_clock_to_stepping(rdev, high, &target); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci rv6xx_output_stepping(rdev, step_index++, &cur); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci increasing_vco = (target.vco_frequency >= cur.vco_frequency); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (target.post_divider > cur.post_divider) 2568c2ecf20Sopenharmony_ci cur.post_divider = target.post_divider; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci while (1) { 2598c2ecf20Sopenharmony_ci struct rv6xx_sclk_stepping next; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (rv6xx_can_step_post_div(rdev, &cur, &target)) 2628c2ecf20Sopenharmony_ci next = rv6xx_next_post_div_step(rdev, &cur, &target); 2638c2ecf20Sopenharmony_ci else 2648c2ecf20Sopenharmony_ci next = rv6xx_next_vco_step(rdev, &cur, increasing_vco, R600_VCOSTEPPCT_DFLT); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (rv6xx_reached_stepping_target(rdev, &next, &target, increasing_vco)) { 2678c2ecf20Sopenharmony_ci struct rv6xx_sclk_stepping tiny = 2688c2ecf20Sopenharmony_ci rv6xx_next_vco_step(rdev, &target, !increasing_vco, R600_ENDINGVCOSTEPPCT_DFLT); 2698c2ecf20Sopenharmony_ci tiny.post_divider = next.post_divider; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (!rv6xx_reached_stepping_target(rdev, &tiny, &cur, !increasing_vco)) 2728c2ecf20Sopenharmony_ci rv6xx_output_stepping(rdev, step_index++, &tiny); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if ((next.post_divider != target.post_divider) && 2758c2ecf20Sopenharmony_ci (next.vco_frequency != target.vco_frequency)) { 2768c2ecf20Sopenharmony_ci struct rv6xx_sclk_stepping final_vco; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci final_vco.vco_frequency = target.vco_frequency; 2798c2ecf20Sopenharmony_ci final_vco.post_divider = next.post_divider; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci rv6xx_output_stepping(rdev, step_index++, &final_vco); 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci rv6xx_output_stepping(rdev, step_index++, &target); 2858c2ecf20Sopenharmony_ci break; 2868c2ecf20Sopenharmony_ci } else 2878c2ecf20Sopenharmony_ci rv6xx_output_stepping(rdev, step_index++, &next); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci cur = next; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci *end_index = (u8)step_index - 1; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic void rv6xx_generate_single_step(struct radeon_device *rdev, 2978c2ecf20Sopenharmony_ci u32 clock, u32 index) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci struct rv6xx_sclk_stepping step; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci rv6xx_convert_clock_to_stepping(rdev, clock, &step); 3028c2ecf20Sopenharmony_ci rv6xx_output_stepping(rdev, index, &step); 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic void rv6xx_invalidate_intermediate_steps_range(struct radeon_device *rdev, 3068c2ecf20Sopenharmony_ci u32 start_index, u32 end_index) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci u32 step_index; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci for (step_index = start_index + 1; step_index < end_index; step_index++) 3118c2ecf20Sopenharmony_ci r600_engine_clock_entry_enable(rdev, step_index, false); 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic void rv6xx_set_engine_spread_spectrum_clk_s(struct radeon_device *rdev, 3158c2ecf20Sopenharmony_ci u32 index, u32 clk_s) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4), 3188c2ecf20Sopenharmony_ci CLKS(clk_s), ~CLKS_MASK); 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistatic void rv6xx_set_engine_spread_spectrum_clk_v(struct radeon_device *rdev, 3228c2ecf20Sopenharmony_ci u32 index, u32 clk_v) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4), 3258c2ecf20Sopenharmony_ci CLKV(clk_v), ~CLKV_MASK); 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic void rv6xx_enable_engine_spread_spectrum(struct radeon_device *rdev, 3298c2ecf20Sopenharmony_ci u32 index, bool enable) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci if (enable) 3328c2ecf20Sopenharmony_ci WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4), 3338c2ecf20Sopenharmony_ci SSEN, ~SSEN); 3348c2ecf20Sopenharmony_ci else 3358c2ecf20Sopenharmony_ci WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4), 3368c2ecf20Sopenharmony_ci 0, ~SSEN); 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic void rv6xx_set_memory_spread_spectrum_clk_s(struct radeon_device *rdev, 3408c2ecf20Sopenharmony_ci u32 clk_s) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci WREG32_P(CG_MPLL_SPREAD_SPECTRUM, CLKS(clk_s), ~CLKS_MASK); 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic void rv6xx_set_memory_spread_spectrum_clk_v(struct radeon_device *rdev, 3468c2ecf20Sopenharmony_ci u32 clk_v) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci WREG32_P(CG_MPLL_SPREAD_SPECTRUM, CLKV(clk_v), ~CLKV_MASK); 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic void rv6xx_enable_memory_spread_spectrum(struct radeon_device *rdev, 3528c2ecf20Sopenharmony_ci bool enable) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci if (enable) 3558c2ecf20Sopenharmony_ci WREG32_P(CG_MPLL_SPREAD_SPECTRUM, SSEN, ~SSEN); 3568c2ecf20Sopenharmony_ci else 3578c2ecf20Sopenharmony_ci WREG32_P(CG_MPLL_SPREAD_SPECTRUM, 0, ~SSEN); 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cistatic void rv6xx_enable_dynamic_spread_spectrum(struct radeon_device *rdev, 3618c2ecf20Sopenharmony_ci bool enable) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci if (enable) 3648c2ecf20Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, ~DYN_SPREAD_SPECTRUM_EN); 3658c2ecf20Sopenharmony_ci else 3668c2ecf20Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, 0, ~DYN_SPREAD_SPECTRUM_EN); 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistatic void rv6xx_memory_clock_entry_enable_post_divider(struct radeon_device *rdev, 3708c2ecf20Sopenharmony_ci u32 index, bool enable) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci if (enable) 3738c2ecf20Sopenharmony_ci WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4), 3748c2ecf20Sopenharmony_ci LEVEL0_MPLL_DIV_EN, ~LEVEL0_MPLL_DIV_EN); 3758c2ecf20Sopenharmony_ci else 3768c2ecf20Sopenharmony_ci WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4), 0, ~LEVEL0_MPLL_DIV_EN); 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic void rv6xx_memory_clock_entry_set_post_divider(struct radeon_device *rdev, 3808c2ecf20Sopenharmony_ci u32 index, u32 divider) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4), 3838c2ecf20Sopenharmony_ci LEVEL0_MPLL_POST_DIV(divider), ~LEVEL0_MPLL_POST_DIV_MASK); 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic void rv6xx_memory_clock_entry_set_feedback_divider(struct radeon_device *rdev, 3878c2ecf20Sopenharmony_ci u32 index, u32 divider) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4), LEVEL0_MPLL_FB_DIV(divider), 3908c2ecf20Sopenharmony_ci ~LEVEL0_MPLL_FB_DIV_MASK); 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_cistatic void rv6xx_memory_clock_entry_set_reference_divider(struct radeon_device *rdev, 3948c2ecf20Sopenharmony_ci u32 index, u32 divider) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4), 3978c2ecf20Sopenharmony_ci LEVEL0_MPLL_REF_DIV(divider), ~LEVEL0_MPLL_REF_DIV_MASK); 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic void rv6xx_vid_response_set_brt(struct radeon_device *rdev, u32 rt) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci WREG32_P(VID_RT, BRT(rt), ~BRT_MASK); 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic void rv6xx_enable_engine_feedback_and_reference_sync(struct radeon_device *rdev) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci WREG32_P(SPLL_CNTL_MODE, SPLL_DIV_SYNC, ~SPLL_DIV_SYNC); 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic u32 rv6xx_clocks_per_unit(u32 unit) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci u32 tmp = 1 << (2 * unit); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci return tmp; 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic u32 rv6xx_scale_count_given_unit(struct radeon_device *rdev, 4188c2ecf20Sopenharmony_ci u32 unscaled_count, u32 unit) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci u32 count_per_unit = rv6xx_clocks_per_unit(unit); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci return (unscaled_count + count_per_unit - 1) / count_per_unit; 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic u32 rv6xx_compute_count_for_delay(struct radeon_device *rdev, 4268c2ecf20Sopenharmony_ci u32 delay_us, u32 unit) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci u32 ref_clk = rdev->clock.spll.reference_freq; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci return rv6xx_scale_count_given_unit(rdev, delay_us * (ref_clk / 100), unit); 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic void rv6xx_calculate_engine_speed_stepping_parameters(struct radeon_device *rdev, 4348c2ecf20Sopenharmony_ci struct rv6xx_ps *state) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci pi->hw.sclks[R600_POWER_LEVEL_LOW] = 4398c2ecf20Sopenharmony_ci state->low.sclk; 4408c2ecf20Sopenharmony_ci pi->hw.sclks[R600_POWER_LEVEL_MEDIUM] = 4418c2ecf20Sopenharmony_ci state->medium.sclk; 4428c2ecf20Sopenharmony_ci pi->hw.sclks[R600_POWER_LEVEL_HIGH] = 4438c2ecf20Sopenharmony_ci state->high.sclk; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci pi->hw.low_sclk_index = R600_POWER_LEVEL_LOW; 4468c2ecf20Sopenharmony_ci pi->hw.medium_sclk_index = R600_POWER_LEVEL_MEDIUM; 4478c2ecf20Sopenharmony_ci pi->hw.high_sclk_index = R600_POWER_LEVEL_HIGH; 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic void rv6xx_calculate_memory_clock_stepping_parameters(struct radeon_device *rdev, 4518c2ecf20Sopenharmony_ci struct rv6xx_ps *state) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci pi->hw.mclks[R600_POWER_LEVEL_CTXSW] = 4568c2ecf20Sopenharmony_ci state->high.mclk; 4578c2ecf20Sopenharmony_ci pi->hw.mclks[R600_POWER_LEVEL_HIGH] = 4588c2ecf20Sopenharmony_ci state->high.mclk; 4598c2ecf20Sopenharmony_ci pi->hw.mclks[R600_POWER_LEVEL_MEDIUM] = 4608c2ecf20Sopenharmony_ci state->medium.mclk; 4618c2ecf20Sopenharmony_ci pi->hw.mclks[R600_POWER_LEVEL_LOW] = 4628c2ecf20Sopenharmony_ci state->low.mclk; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci pi->hw.high_mclk_index = R600_POWER_LEVEL_HIGH; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (state->high.mclk == state->medium.mclk) 4678c2ecf20Sopenharmony_ci pi->hw.medium_mclk_index = 4688c2ecf20Sopenharmony_ci pi->hw.high_mclk_index; 4698c2ecf20Sopenharmony_ci else 4708c2ecf20Sopenharmony_ci pi->hw.medium_mclk_index = R600_POWER_LEVEL_MEDIUM; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci if (state->medium.mclk == state->low.mclk) 4748c2ecf20Sopenharmony_ci pi->hw.low_mclk_index = 4758c2ecf20Sopenharmony_ci pi->hw.medium_mclk_index; 4768c2ecf20Sopenharmony_ci else 4778c2ecf20Sopenharmony_ci pi->hw.low_mclk_index = R600_POWER_LEVEL_LOW; 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistatic void rv6xx_calculate_voltage_stepping_parameters(struct radeon_device *rdev, 4818c2ecf20Sopenharmony_ci struct rv6xx_ps *state) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci pi->hw.vddc[R600_POWER_LEVEL_CTXSW] = state->high.vddc; 4868c2ecf20Sopenharmony_ci pi->hw.vddc[R600_POWER_LEVEL_HIGH] = state->high.vddc; 4878c2ecf20Sopenharmony_ci pi->hw.vddc[R600_POWER_LEVEL_MEDIUM] = state->medium.vddc; 4888c2ecf20Sopenharmony_ci pi->hw.vddc[R600_POWER_LEVEL_LOW] = state->low.vddc; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci pi->hw.backbias[R600_POWER_LEVEL_CTXSW] = 4918c2ecf20Sopenharmony_ci (state->high.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false; 4928c2ecf20Sopenharmony_ci pi->hw.backbias[R600_POWER_LEVEL_HIGH] = 4938c2ecf20Sopenharmony_ci (state->high.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false; 4948c2ecf20Sopenharmony_ci pi->hw.backbias[R600_POWER_LEVEL_MEDIUM] = 4958c2ecf20Sopenharmony_ci (state->medium.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false; 4968c2ecf20Sopenharmony_ci pi->hw.backbias[R600_POWER_LEVEL_LOW] = 4978c2ecf20Sopenharmony_ci (state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci pi->hw.pcie_gen2[R600_POWER_LEVEL_HIGH] = 5008c2ecf20Sopenharmony_ci (state->high.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? true : false; 5018c2ecf20Sopenharmony_ci pi->hw.pcie_gen2[R600_POWER_LEVEL_MEDIUM] = 5028c2ecf20Sopenharmony_ci (state->medium.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? true : false; 5038c2ecf20Sopenharmony_ci pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW] = 5048c2ecf20Sopenharmony_ci (state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? true : false; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci pi->hw.high_vddc_index = R600_POWER_LEVEL_HIGH; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci if ((state->high.vddc == state->medium.vddc) && 5098c2ecf20Sopenharmony_ci ((state->high.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) == 5108c2ecf20Sopenharmony_ci (state->medium.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE))) 5118c2ecf20Sopenharmony_ci pi->hw.medium_vddc_index = 5128c2ecf20Sopenharmony_ci pi->hw.high_vddc_index; 5138c2ecf20Sopenharmony_ci else 5148c2ecf20Sopenharmony_ci pi->hw.medium_vddc_index = R600_POWER_LEVEL_MEDIUM; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci if ((state->medium.vddc == state->low.vddc) && 5178c2ecf20Sopenharmony_ci ((state->medium.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) == 5188c2ecf20Sopenharmony_ci (state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE))) 5198c2ecf20Sopenharmony_ci pi->hw.low_vddc_index = 5208c2ecf20Sopenharmony_ci pi->hw.medium_vddc_index; 5218c2ecf20Sopenharmony_ci else 5228c2ecf20Sopenharmony_ci pi->hw.medium_vddc_index = R600_POWER_LEVEL_LOW; 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic inline u32 rv6xx_calculate_vco_frequency(u32 ref_clock, 5268c2ecf20Sopenharmony_ci struct atom_clock_dividers *dividers, 5278c2ecf20Sopenharmony_ci u32 fb_divider_scale) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci return ref_clock * ((dividers->fb_div & ~1) << fb_divider_scale) / 5308c2ecf20Sopenharmony_ci (dividers->ref_div + 1); 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_cistatic inline u32 rv6xx_calculate_spread_spectrum_clk_v(u32 vco_freq, u32 ref_freq, 5348c2ecf20Sopenharmony_ci u32 ss_rate, u32 ss_percent, 5358c2ecf20Sopenharmony_ci u32 fb_divider_scale) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci u32 fb_divider = vco_freq / ref_freq; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci return (ss_percent * ss_rate * 4 * (fb_divider * fb_divider) / 5408c2ecf20Sopenharmony_ci (5375 * ((vco_freq * 10) / (4096 >> fb_divider_scale)))); 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic inline u32 rv6xx_calculate_spread_spectrum_clk_s(u32 ss_rate, u32 ref_freq) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci return (((ref_freq * 10) / (ss_rate * 2)) - 1) / 4; 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic void rv6xx_program_engine_spread_spectrum(struct radeon_device *rdev, 5498c2ecf20Sopenharmony_ci u32 clock, enum r600_power_level level) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci u32 ref_clk = rdev->clock.spll.reference_freq; 5528c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 5538c2ecf20Sopenharmony_ci struct atom_clock_dividers dividers; 5548c2ecf20Sopenharmony_ci struct radeon_atom_ss ss; 5558c2ecf20Sopenharmony_ci u32 vco_freq, clk_v, clk_s; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci rv6xx_enable_engine_spread_spectrum(rdev, level, false); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci if (clock && pi->sclk_ss) { 5608c2ecf20Sopenharmony_ci if (radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, clock, false, ÷rs) == 0) { 5618c2ecf20Sopenharmony_ci vco_freq = rv6xx_calculate_vco_frequency(ref_clk, ÷rs, 5628c2ecf20Sopenharmony_ci pi->fb_div_scale); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci if (radeon_atombios_get_asic_ss_info(rdev, &ss, 5658c2ecf20Sopenharmony_ci ASIC_INTERNAL_ENGINE_SS, vco_freq)) { 5668c2ecf20Sopenharmony_ci clk_v = rv6xx_calculate_spread_spectrum_clk_v(vco_freq, 5678c2ecf20Sopenharmony_ci (ref_clk / (dividers.ref_div + 1)), 5688c2ecf20Sopenharmony_ci ss.rate, 5698c2ecf20Sopenharmony_ci ss.percentage, 5708c2ecf20Sopenharmony_ci pi->fb_div_scale); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci clk_s = rv6xx_calculate_spread_spectrum_clk_s(ss.rate, 5738c2ecf20Sopenharmony_ci (ref_clk / (dividers.ref_div + 1))); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci rv6xx_set_engine_spread_spectrum_clk_v(rdev, level, clk_v); 5768c2ecf20Sopenharmony_ci rv6xx_set_engine_spread_spectrum_clk_s(rdev, level, clk_s); 5778c2ecf20Sopenharmony_ci rv6xx_enable_engine_spread_spectrum(rdev, level, true); 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cistatic void rv6xx_program_sclk_spread_spectrum_parameters_except_lowest_entry(struct radeon_device *rdev) 5848c2ecf20Sopenharmony_ci{ 5858c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci rv6xx_program_engine_spread_spectrum(rdev, 5888c2ecf20Sopenharmony_ci pi->hw.sclks[R600_POWER_LEVEL_HIGH], 5898c2ecf20Sopenharmony_ci R600_POWER_LEVEL_HIGH); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci rv6xx_program_engine_spread_spectrum(rdev, 5928c2ecf20Sopenharmony_ci pi->hw.sclks[R600_POWER_LEVEL_MEDIUM], 5938c2ecf20Sopenharmony_ci R600_POWER_LEVEL_MEDIUM); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci} 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_cistatic int rv6xx_program_mclk_stepping_entry(struct radeon_device *rdev, 5988c2ecf20Sopenharmony_ci u32 entry, u32 clock) 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci struct atom_clock_dividers dividers; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci if (radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM, clock, false, ÷rs)) 6038c2ecf20Sopenharmony_ci return -EINVAL; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci rv6xx_memory_clock_entry_set_reference_divider(rdev, entry, dividers.ref_div); 6078c2ecf20Sopenharmony_ci rv6xx_memory_clock_entry_set_feedback_divider(rdev, entry, dividers.fb_div); 6088c2ecf20Sopenharmony_ci rv6xx_memory_clock_entry_set_post_divider(rdev, entry, dividers.post_div); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci if (dividers.enable_post_div) 6118c2ecf20Sopenharmony_ci rv6xx_memory_clock_entry_enable_post_divider(rdev, entry, true); 6128c2ecf20Sopenharmony_ci else 6138c2ecf20Sopenharmony_ci rv6xx_memory_clock_entry_enable_post_divider(rdev, entry, false); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci return 0; 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_cistatic void rv6xx_program_mclk_stepping_parameters_except_lowest_entry(struct radeon_device *rdev) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 6218c2ecf20Sopenharmony_ci int i; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci for (i = 1; i < R600_PM_NUMBER_OF_MCLKS; i++) { 6248c2ecf20Sopenharmony_ci if (pi->hw.mclks[i]) 6258c2ecf20Sopenharmony_ci rv6xx_program_mclk_stepping_entry(rdev, i, 6268c2ecf20Sopenharmony_ci pi->hw.mclks[i]); 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_cistatic void rv6xx_find_memory_clock_with_highest_vco(struct radeon_device *rdev, 6318c2ecf20Sopenharmony_ci u32 requested_memory_clock, 6328c2ecf20Sopenharmony_ci u32 ref_clk, 6338c2ecf20Sopenharmony_ci struct atom_clock_dividers *dividers, 6348c2ecf20Sopenharmony_ci u32 *vco_freq) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 6378c2ecf20Sopenharmony_ci struct atom_clock_dividers req_dividers; 6388c2ecf20Sopenharmony_ci u32 vco_freq_temp; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci if (radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM, 6418c2ecf20Sopenharmony_ci requested_memory_clock, false, &req_dividers) == 0) { 6428c2ecf20Sopenharmony_ci vco_freq_temp = rv6xx_calculate_vco_frequency(ref_clk, &req_dividers, 6438c2ecf20Sopenharmony_ci pi->fb_div_scale); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci if (vco_freq_temp > *vco_freq) { 6468c2ecf20Sopenharmony_ci *dividers = req_dividers; 6478c2ecf20Sopenharmony_ci *vco_freq = vco_freq_temp; 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci} 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_cistatic void rv6xx_program_mclk_spread_spectrum_parameters(struct radeon_device *rdev) 6538c2ecf20Sopenharmony_ci{ 6548c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 6558c2ecf20Sopenharmony_ci u32 ref_clk = rdev->clock.mpll.reference_freq; 6568c2ecf20Sopenharmony_ci struct atom_clock_dividers dividers; 6578c2ecf20Sopenharmony_ci struct radeon_atom_ss ss; 6588c2ecf20Sopenharmony_ci u32 vco_freq = 0, clk_v, clk_s; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci rv6xx_enable_memory_spread_spectrum(rdev, false); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci if (pi->mclk_ss) { 6638c2ecf20Sopenharmony_ci rv6xx_find_memory_clock_with_highest_vco(rdev, 6648c2ecf20Sopenharmony_ci pi->hw.mclks[pi->hw.high_mclk_index], 6658c2ecf20Sopenharmony_ci ref_clk, 6668c2ecf20Sopenharmony_ci ÷rs, 6678c2ecf20Sopenharmony_ci &vco_freq); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci rv6xx_find_memory_clock_with_highest_vco(rdev, 6708c2ecf20Sopenharmony_ci pi->hw.mclks[pi->hw.medium_mclk_index], 6718c2ecf20Sopenharmony_ci ref_clk, 6728c2ecf20Sopenharmony_ci ÷rs, 6738c2ecf20Sopenharmony_ci &vco_freq); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci rv6xx_find_memory_clock_with_highest_vco(rdev, 6768c2ecf20Sopenharmony_ci pi->hw.mclks[pi->hw.low_mclk_index], 6778c2ecf20Sopenharmony_ci ref_clk, 6788c2ecf20Sopenharmony_ci ÷rs, 6798c2ecf20Sopenharmony_ci &vco_freq); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci if (vco_freq) { 6828c2ecf20Sopenharmony_ci if (radeon_atombios_get_asic_ss_info(rdev, &ss, 6838c2ecf20Sopenharmony_ci ASIC_INTERNAL_MEMORY_SS, vco_freq)) { 6848c2ecf20Sopenharmony_ci clk_v = rv6xx_calculate_spread_spectrum_clk_v(vco_freq, 6858c2ecf20Sopenharmony_ci (ref_clk / (dividers.ref_div + 1)), 6868c2ecf20Sopenharmony_ci ss.rate, 6878c2ecf20Sopenharmony_ci ss.percentage, 6888c2ecf20Sopenharmony_ci pi->fb_div_scale); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci clk_s = rv6xx_calculate_spread_spectrum_clk_s(ss.rate, 6918c2ecf20Sopenharmony_ci (ref_clk / (dividers.ref_div + 1))); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci rv6xx_set_memory_spread_spectrum_clk_v(rdev, clk_v); 6948c2ecf20Sopenharmony_ci rv6xx_set_memory_spread_spectrum_clk_s(rdev, clk_s); 6958c2ecf20Sopenharmony_ci rv6xx_enable_memory_spread_spectrum(rdev, true); 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci } 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_cistatic int rv6xx_program_voltage_stepping_entry(struct radeon_device *rdev, 7028c2ecf20Sopenharmony_ci u32 entry, u16 voltage) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci u32 mask, set_pins; 7058c2ecf20Sopenharmony_ci int ret; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci ret = radeon_atom_get_voltage_gpio_settings(rdev, voltage, 7088c2ecf20Sopenharmony_ci SET_VOLTAGE_TYPE_ASIC_VDDC, 7098c2ecf20Sopenharmony_ci &set_pins, &mask); 7108c2ecf20Sopenharmony_ci if (ret) 7118c2ecf20Sopenharmony_ci return ret; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci r600_voltage_control_program_voltages(rdev, entry, set_pins); 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci return 0; 7168c2ecf20Sopenharmony_ci} 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_cistatic void rv6xx_program_voltage_stepping_parameters_except_lowest_entry(struct radeon_device *rdev) 7198c2ecf20Sopenharmony_ci{ 7208c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 7218c2ecf20Sopenharmony_ci int i; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci for (i = 1; i < R600_PM_NUMBER_OF_VOLTAGE_LEVELS; i++) 7248c2ecf20Sopenharmony_ci rv6xx_program_voltage_stepping_entry(rdev, i, 7258c2ecf20Sopenharmony_ci pi->hw.vddc[i]); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci} 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_cistatic void rv6xx_program_backbias_stepping_parameters_except_lowest_entry(struct radeon_device *rdev) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci if (pi->hw.backbias[1]) 7348c2ecf20Sopenharmony_ci WREG32_P(VID_UPPER_GPIO_CNTL, MEDIUM_BACKBIAS_VALUE, ~MEDIUM_BACKBIAS_VALUE); 7358c2ecf20Sopenharmony_ci else 7368c2ecf20Sopenharmony_ci WREG32_P(VID_UPPER_GPIO_CNTL, 0, ~MEDIUM_BACKBIAS_VALUE); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci if (pi->hw.backbias[2]) 7398c2ecf20Sopenharmony_ci WREG32_P(VID_UPPER_GPIO_CNTL, HIGH_BACKBIAS_VALUE, ~HIGH_BACKBIAS_VALUE); 7408c2ecf20Sopenharmony_ci else 7418c2ecf20Sopenharmony_ci WREG32_P(VID_UPPER_GPIO_CNTL, 0, ~HIGH_BACKBIAS_VALUE); 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_cistatic void rv6xx_program_sclk_spread_spectrum_parameters_lowest_entry(struct radeon_device *rdev) 7458c2ecf20Sopenharmony_ci{ 7468c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci rv6xx_program_engine_spread_spectrum(rdev, 7498c2ecf20Sopenharmony_ci pi->hw.sclks[R600_POWER_LEVEL_LOW], 7508c2ecf20Sopenharmony_ci R600_POWER_LEVEL_LOW); 7518c2ecf20Sopenharmony_ci} 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_cistatic void rv6xx_program_mclk_stepping_parameters_lowest_entry(struct radeon_device *rdev) 7548c2ecf20Sopenharmony_ci{ 7558c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci if (pi->hw.mclks[0]) 7588c2ecf20Sopenharmony_ci rv6xx_program_mclk_stepping_entry(rdev, 0, 7598c2ecf20Sopenharmony_ci pi->hw.mclks[0]); 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_cistatic void rv6xx_program_voltage_stepping_parameters_lowest_entry(struct radeon_device *rdev) 7638c2ecf20Sopenharmony_ci{ 7648c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci rv6xx_program_voltage_stepping_entry(rdev, 0, 7678c2ecf20Sopenharmony_ci pi->hw.vddc[0]); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci} 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_cistatic void rv6xx_program_backbias_stepping_parameters_lowest_entry(struct radeon_device *rdev) 7728c2ecf20Sopenharmony_ci{ 7738c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci if (pi->hw.backbias[0]) 7768c2ecf20Sopenharmony_ci WREG32_P(VID_UPPER_GPIO_CNTL, LOW_BACKBIAS_VALUE, ~LOW_BACKBIAS_VALUE); 7778c2ecf20Sopenharmony_ci else 7788c2ecf20Sopenharmony_ci WREG32_P(VID_UPPER_GPIO_CNTL, 0, ~LOW_BACKBIAS_VALUE); 7798c2ecf20Sopenharmony_ci} 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_cistatic u32 calculate_memory_refresh_rate(struct radeon_device *rdev, 7828c2ecf20Sopenharmony_ci u32 engine_clock) 7838c2ecf20Sopenharmony_ci{ 7848c2ecf20Sopenharmony_ci u32 dram_rows, dram_refresh_rate; 7858c2ecf20Sopenharmony_ci u32 tmp; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci tmp = (RREG32(RAMCFG) & NOOFROWS_MASK) >> NOOFROWS_SHIFT; 7888c2ecf20Sopenharmony_ci dram_rows = 1 << (tmp + 10); 7898c2ecf20Sopenharmony_ci dram_refresh_rate = 1 << ((RREG32(MC_SEQ_RESERVE_M) & 0x3) + 3); 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci return ((engine_clock * 10) * dram_refresh_rate / dram_rows - 32) / 64; 7928c2ecf20Sopenharmony_ci} 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_cistatic void rv6xx_program_memory_timing_parameters(struct radeon_device *rdev) 7958c2ecf20Sopenharmony_ci{ 7968c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 7978c2ecf20Sopenharmony_ci u32 sqm_ratio; 7988c2ecf20Sopenharmony_ci u32 arb_refresh_rate; 7998c2ecf20Sopenharmony_ci u32 high_clock; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci if (pi->hw.sclks[R600_POWER_LEVEL_HIGH] < 8028c2ecf20Sopenharmony_ci (pi->hw.sclks[R600_POWER_LEVEL_LOW] * 0xFF / 0x40)) 8038c2ecf20Sopenharmony_ci high_clock = pi->hw.sclks[R600_POWER_LEVEL_HIGH]; 8048c2ecf20Sopenharmony_ci else 8058c2ecf20Sopenharmony_ci high_clock = 8068c2ecf20Sopenharmony_ci pi->hw.sclks[R600_POWER_LEVEL_LOW] * 0xFF / 0x40; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci radeon_atom_set_engine_dram_timings(rdev, high_clock, 0); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci sqm_ratio = (STATE0(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_LOW]) | 8118c2ecf20Sopenharmony_ci STATE1(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_MEDIUM]) | 8128c2ecf20Sopenharmony_ci STATE2(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_HIGH]) | 8138c2ecf20Sopenharmony_ci STATE3(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_HIGH])); 8148c2ecf20Sopenharmony_ci WREG32(SQM_RATIO, sqm_ratio); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci arb_refresh_rate = 8178c2ecf20Sopenharmony_ci (POWERMODE0(calculate_memory_refresh_rate(rdev, 8188c2ecf20Sopenharmony_ci pi->hw.sclks[R600_POWER_LEVEL_LOW])) | 8198c2ecf20Sopenharmony_ci POWERMODE1(calculate_memory_refresh_rate(rdev, 8208c2ecf20Sopenharmony_ci pi->hw.sclks[R600_POWER_LEVEL_MEDIUM])) | 8218c2ecf20Sopenharmony_ci POWERMODE2(calculate_memory_refresh_rate(rdev, 8228c2ecf20Sopenharmony_ci pi->hw.sclks[R600_POWER_LEVEL_HIGH])) | 8238c2ecf20Sopenharmony_ci POWERMODE3(calculate_memory_refresh_rate(rdev, 8248c2ecf20Sopenharmony_ci pi->hw.sclks[R600_POWER_LEVEL_HIGH]))); 8258c2ecf20Sopenharmony_ci WREG32(ARB_RFSH_RATE, arb_refresh_rate); 8268c2ecf20Sopenharmony_ci} 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_cistatic void rv6xx_program_mpll_timing_parameters(struct radeon_device *rdev) 8298c2ecf20Sopenharmony_ci{ 8308c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci r600_set_mpll_lock_time(rdev, R600_MPLLLOCKTIME_DFLT * 8338c2ecf20Sopenharmony_ci pi->mpll_ref_div); 8348c2ecf20Sopenharmony_ci r600_set_mpll_reset_time(rdev, R600_MPLLRESETTIME_DFLT); 8358c2ecf20Sopenharmony_ci} 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_cistatic void rv6xx_program_bsp(struct radeon_device *rdev) 8388c2ecf20Sopenharmony_ci{ 8398c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 8408c2ecf20Sopenharmony_ci u32 ref_clk = rdev->clock.spll.reference_freq; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci r600_calculate_u_and_p(R600_ASI_DFLT, 8438c2ecf20Sopenharmony_ci ref_clk, 16, 8448c2ecf20Sopenharmony_ci &pi->bsp, 8458c2ecf20Sopenharmony_ci &pi->bsu); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci r600_set_bsp(rdev, pi->bsu, pi->bsp); 8488c2ecf20Sopenharmony_ci} 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_cistatic void rv6xx_program_at(struct radeon_device *rdev) 8518c2ecf20Sopenharmony_ci{ 8528c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci r600_set_at(rdev, 8558c2ecf20Sopenharmony_ci (pi->hw.rp[0] * pi->bsp) / 200, 8568c2ecf20Sopenharmony_ci (pi->hw.rp[1] * pi->bsp) / 200, 8578c2ecf20Sopenharmony_ci (pi->hw.lp[2] * pi->bsp) / 200, 8588c2ecf20Sopenharmony_ci (pi->hw.lp[1] * pi->bsp) / 200); 8598c2ecf20Sopenharmony_ci} 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_cistatic void rv6xx_program_git(struct radeon_device *rdev) 8628c2ecf20Sopenharmony_ci{ 8638c2ecf20Sopenharmony_ci r600_set_git(rdev, R600_GICST_DFLT); 8648c2ecf20Sopenharmony_ci} 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_cistatic void rv6xx_program_tp(struct radeon_device *rdev) 8678c2ecf20Sopenharmony_ci{ 8688c2ecf20Sopenharmony_ci int i; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci for (i = 0; i < R600_PM_NUMBER_OF_TC; i++) 8718c2ecf20Sopenharmony_ci r600_set_tc(rdev, i, r600_utc[i], r600_dtc[i]); 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci r600_select_td(rdev, R600_TD_DFLT); 8748c2ecf20Sopenharmony_ci} 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_cistatic void rv6xx_program_vc(struct radeon_device *rdev) 8778c2ecf20Sopenharmony_ci{ 8788c2ecf20Sopenharmony_ci r600_set_vrc(rdev, R600_VRC_DFLT); 8798c2ecf20Sopenharmony_ci} 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_cistatic void rv6xx_clear_vc(struct radeon_device *rdev) 8828c2ecf20Sopenharmony_ci{ 8838c2ecf20Sopenharmony_ci r600_set_vrc(rdev, 0); 8848c2ecf20Sopenharmony_ci} 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_cistatic void rv6xx_program_tpp(struct radeon_device *rdev) 8878c2ecf20Sopenharmony_ci{ 8888c2ecf20Sopenharmony_ci r600_set_tpu(rdev, R600_TPU_DFLT); 8898c2ecf20Sopenharmony_ci r600_set_tpc(rdev, R600_TPC_DFLT); 8908c2ecf20Sopenharmony_ci} 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_cistatic void rv6xx_program_sstp(struct radeon_device *rdev) 8938c2ecf20Sopenharmony_ci{ 8948c2ecf20Sopenharmony_ci r600_set_sstu(rdev, R600_SSTU_DFLT); 8958c2ecf20Sopenharmony_ci r600_set_sst(rdev, R600_SST_DFLT); 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_cistatic void rv6xx_program_fcp(struct radeon_device *rdev) 8998c2ecf20Sopenharmony_ci{ 9008c2ecf20Sopenharmony_ci r600_set_fctu(rdev, R600_FCTU_DFLT); 9018c2ecf20Sopenharmony_ci r600_set_fct(rdev, R600_FCT_DFLT); 9028c2ecf20Sopenharmony_ci} 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_cistatic void rv6xx_program_vddc3d_parameters(struct radeon_device *rdev) 9058c2ecf20Sopenharmony_ci{ 9068c2ecf20Sopenharmony_ci r600_set_vddc3d_oorsu(rdev, R600_VDDC3DOORSU_DFLT); 9078c2ecf20Sopenharmony_ci r600_set_vddc3d_oorphc(rdev, R600_VDDC3DOORPHC_DFLT); 9088c2ecf20Sopenharmony_ci r600_set_vddc3d_oorsdc(rdev, R600_VDDC3DOORSDC_DFLT); 9098c2ecf20Sopenharmony_ci r600_set_ctxcgtt3d_rphc(rdev, R600_CTXCGTT3DRPHC_DFLT); 9108c2ecf20Sopenharmony_ci r600_set_ctxcgtt3d_rsdc(rdev, R600_CTXCGTT3DRSDC_DFLT); 9118c2ecf20Sopenharmony_ci} 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_cistatic void rv6xx_program_voltage_timing_parameters(struct radeon_device *rdev) 9148c2ecf20Sopenharmony_ci{ 9158c2ecf20Sopenharmony_ci u32 rt; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci r600_vid_rt_set_vru(rdev, R600_VRU_DFLT); 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci r600_vid_rt_set_vrt(rdev, 9208c2ecf20Sopenharmony_ci rv6xx_compute_count_for_delay(rdev, 9218c2ecf20Sopenharmony_ci rdev->pm.dpm.voltage_response_time, 9228c2ecf20Sopenharmony_ci R600_VRU_DFLT)); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci rt = rv6xx_compute_count_for_delay(rdev, 9258c2ecf20Sopenharmony_ci rdev->pm.dpm.backbias_response_time, 9268c2ecf20Sopenharmony_ci R600_VRU_DFLT); 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci rv6xx_vid_response_set_brt(rdev, (rt + 0x1F) >> 5); 9298c2ecf20Sopenharmony_ci} 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_cistatic void rv6xx_program_engine_speed_parameters(struct radeon_device *rdev) 9328c2ecf20Sopenharmony_ci{ 9338c2ecf20Sopenharmony_ci r600_vid_rt_set_ssu(rdev, R600_SPLLSTEPUNIT_DFLT); 9348c2ecf20Sopenharmony_ci rv6xx_enable_engine_feedback_and_reference_sync(rdev); 9358c2ecf20Sopenharmony_ci} 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_cistatic u64 rv6xx_get_master_voltage_mask(struct radeon_device *rdev) 9388c2ecf20Sopenharmony_ci{ 9398c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 9408c2ecf20Sopenharmony_ci u64 master_mask = 0; 9418c2ecf20Sopenharmony_ci int i; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci for (i = 0; i < R600_PM_NUMBER_OF_VOLTAGE_LEVELS; i++) { 9448c2ecf20Sopenharmony_ci u32 tmp_mask, tmp_set_pins; 9458c2ecf20Sopenharmony_ci int ret; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci ret = radeon_atom_get_voltage_gpio_settings(rdev, 9488c2ecf20Sopenharmony_ci pi->hw.vddc[i], 9498c2ecf20Sopenharmony_ci SET_VOLTAGE_TYPE_ASIC_VDDC, 9508c2ecf20Sopenharmony_ci &tmp_set_pins, &tmp_mask); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci if (ret == 0) 9538c2ecf20Sopenharmony_ci master_mask |= tmp_mask; 9548c2ecf20Sopenharmony_ci } 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci return master_mask; 9578c2ecf20Sopenharmony_ci} 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_cistatic void rv6xx_program_voltage_gpio_pins(struct radeon_device *rdev) 9608c2ecf20Sopenharmony_ci{ 9618c2ecf20Sopenharmony_ci r600_voltage_control_enable_pins(rdev, 9628c2ecf20Sopenharmony_ci rv6xx_get_master_voltage_mask(rdev)); 9638c2ecf20Sopenharmony_ci} 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_cistatic void rv6xx_enable_static_voltage_control(struct radeon_device *rdev, 9668c2ecf20Sopenharmony_ci struct radeon_ps *new_ps, 9678c2ecf20Sopenharmony_ci bool enable) 9688c2ecf20Sopenharmony_ci{ 9698c2ecf20Sopenharmony_ci struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci if (enable) 9728c2ecf20Sopenharmony_ci radeon_atom_set_voltage(rdev, 9738c2ecf20Sopenharmony_ci new_state->low.vddc, 9748c2ecf20Sopenharmony_ci SET_VOLTAGE_TYPE_ASIC_VDDC); 9758c2ecf20Sopenharmony_ci else 9768c2ecf20Sopenharmony_ci r600_voltage_control_deactivate_static_control(rdev, 9778c2ecf20Sopenharmony_ci rv6xx_get_master_voltage_mask(rdev)); 9788c2ecf20Sopenharmony_ci} 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_cistatic void rv6xx_enable_display_gap(struct radeon_device *rdev, bool enable) 9818c2ecf20Sopenharmony_ci{ 9828c2ecf20Sopenharmony_ci if (enable) { 9838c2ecf20Sopenharmony_ci u32 tmp = (DISP1_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM) | 9848c2ecf20Sopenharmony_ci DISP2_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM) | 9858c2ecf20Sopenharmony_ci DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE) | 9868c2ecf20Sopenharmony_ci DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE) | 9878c2ecf20Sopenharmony_ci VBI_TIMER_COUNT(0x3FFF) | 9888c2ecf20Sopenharmony_ci VBI_TIMER_UNIT(7)); 9898c2ecf20Sopenharmony_ci WREG32(CG_DISPLAY_GAP_CNTL, tmp); 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci WREG32_P(MCLK_PWRMGT_CNTL, USE_DISPLAY_GAP, ~USE_DISPLAY_GAP); 9928c2ecf20Sopenharmony_ci } else 9938c2ecf20Sopenharmony_ci WREG32_P(MCLK_PWRMGT_CNTL, 0, ~USE_DISPLAY_GAP); 9948c2ecf20Sopenharmony_ci} 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_cistatic void rv6xx_program_power_level_enter_state(struct radeon_device *rdev) 9978c2ecf20Sopenharmony_ci{ 9988c2ecf20Sopenharmony_ci r600_power_level_set_enter_index(rdev, R600_POWER_LEVEL_MEDIUM); 9998c2ecf20Sopenharmony_ci} 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_cistatic void rv6xx_calculate_t(u32 l_f, u32 h_f, int h, 10028c2ecf20Sopenharmony_ci int d_l, int d_r, u8 *l, u8 *r) 10038c2ecf20Sopenharmony_ci{ 10048c2ecf20Sopenharmony_ci int a_n, a_d, h_r, l_r; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci h_r = d_l; 10078c2ecf20Sopenharmony_ci l_r = 100 - d_r; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci a_n = (int)h_f * d_l + (int)l_f * (h - d_r); 10108c2ecf20Sopenharmony_ci a_d = (int)l_f * l_r + (int)h_f * h_r; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci if (a_d != 0) { 10138c2ecf20Sopenharmony_ci *l = d_l - h_r * a_n / a_d; 10148c2ecf20Sopenharmony_ci *r = d_r + l_r * a_n / a_d; 10158c2ecf20Sopenharmony_ci } 10168c2ecf20Sopenharmony_ci} 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_cistatic void rv6xx_calculate_ap(struct radeon_device *rdev, 10198c2ecf20Sopenharmony_ci struct rv6xx_ps *state) 10208c2ecf20Sopenharmony_ci{ 10218c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci pi->hw.lp[0] = 0; 10248c2ecf20Sopenharmony_ci pi->hw.rp[R600_PM_NUMBER_OF_ACTIVITY_LEVELS - 1] 10258c2ecf20Sopenharmony_ci = 100; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci rv6xx_calculate_t(state->low.sclk, 10288c2ecf20Sopenharmony_ci state->medium.sclk, 10298c2ecf20Sopenharmony_ci R600_AH_DFLT, 10308c2ecf20Sopenharmony_ci R600_LMP_DFLT, 10318c2ecf20Sopenharmony_ci R600_RLP_DFLT, 10328c2ecf20Sopenharmony_ci &pi->hw.lp[1], 10338c2ecf20Sopenharmony_ci &pi->hw.rp[0]); 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci rv6xx_calculate_t(state->medium.sclk, 10368c2ecf20Sopenharmony_ci state->high.sclk, 10378c2ecf20Sopenharmony_ci R600_AH_DFLT, 10388c2ecf20Sopenharmony_ci R600_LHP_DFLT, 10398c2ecf20Sopenharmony_ci R600_RMP_DFLT, 10408c2ecf20Sopenharmony_ci &pi->hw.lp[2], 10418c2ecf20Sopenharmony_ci &pi->hw.rp[1]); 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci} 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_cistatic void rv6xx_calculate_stepping_parameters(struct radeon_device *rdev, 10468c2ecf20Sopenharmony_ci struct radeon_ps *new_ps) 10478c2ecf20Sopenharmony_ci{ 10488c2ecf20Sopenharmony_ci struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci rv6xx_calculate_engine_speed_stepping_parameters(rdev, new_state); 10518c2ecf20Sopenharmony_ci rv6xx_calculate_memory_clock_stepping_parameters(rdev, new_state); 10528c2ecf20Sopenharmony_ci rv6xx_calculate_voltage_stepping_parameters(rdev, new_state); 10538c2ecf20Sopenharmony_ci rv6xx_calculate_ap(rdev, new_state); 10548c2ecf20Sopenharmony_ci} 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_cistatic void rv6xx_program_stepping_parameters_except_lowest_entry(struct radeon_device *rdev) 10578c2ecf20Sopenharmony_ci{ 10588c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci rv6xx_program_mclk_stepping_parameters_except_lowest_entry(rdev); 10618c2ecf20Sopenharmony_ci if (pi->voltage_control) 10628c2ecf20Sopenharmony_ci rv6xx_program_voltage_stepping_parameters_except_lowest_entry(rdev); 10638c2ecf20Sopenharmony_ci rv6xx_program_backbias_stepping_parameters_except_lowest_entry(rdev); 10648c2ecf20Sopenharmony_ci rv6xx_program_sclk_spread_spectrum_parameters_except_lowest_entry(rdev); 10658c2ecf20Sopenharmony_ci rv6xx_program_mclk_spread_spectrum_parameters(rdev); 10668c2ecf20Sopenharmony_ci rv6xx_program_memory_timing_parameters(rdev); 10678c2ecf20Sopenharmony_ci} 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_cistatic void rv6xx_program_stepping_parameters_lowest_entry(struct radeon_device *rdev) 10708c2ecf20Sopenharmony_ci{ 10718c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci rv6xx_program_mclk_stepping_parameters_lowest_entry(rdev); 10748c2ecf20Sopenharmony_ci if (pi->voltage_control) 10758c2ecf20Sopenharmony_ci rv6xx_program_voltage_stepping_parameters_lowest_entry(rdev); 10768c2ecf20Sopenharmony_ci rv6xx_program_backbias_stepping_parameters_lowest_entry(rdev); 10778c2ecf20Sopenharmony_ci rv6xx_program_sclk_spread_spectrum_parameters_lowest_entry(rdev); 10788c2ecf20Sopenharmony_ci} 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_cistatic void rv6xx_program_power_level_low(struct radeon_device *rdev) 10818c2ecf20Sopenharmony_ci{ 10828c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW, 10858c2ecf20Sopenharmony_ci pi->hw.low_vddc_index); 10868c2ecf20Sopenharmony_ci r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW, 10878c2ecf20Sopenharmony_ci pi->hw.low_mclk_index); 10888c2ecf20Sopenharmony_ci r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW, 10898c2ecf20Sopenharmony_ci pi->hw.low_sclk_index); 10908c2ecf20Sopenharmony_ci r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW, 10918c2ecf20Sopenharmony_ci R600_DISPLAY_WATERMARK_LOW); 10928c2ecf20Sopenharmony_ci r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_LOW, 10938c2ecf20Sopenharmony_ci pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW]); 10948c2ecf20Sopenharmony_ci} 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_cistatic void rv6xx_program_power_level_low_to_lowest_state(struct radeon_device *rdev) 10978c2ecf20Sopenharmony_ci{ 10988c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW, 0); 11018c2ecf20Sopenharmony_ci r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW, 0); 11028c2ecf20Sopenharmony_ci r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW, 0); 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW, 11058c2ecf20Sopenharmony_ci R600_DISPLAY_WATERMARK_LOW); 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_LOW, 11088c2ecf20Sopenharmony_ci pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW]); 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci} 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_cistatic void rv6xx_program_power_level_medium(struct radeon_device *rdev) 11138c2ecf20Sopenharmony_ci{ 11148c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM, 11178c2ecf20Sopenharmony_ci pi->hw.medium_vddc_index); 11188c2ecf20Sopenharmony_ci r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 11198c2ecf20Sopenharmony_ci pi->hw.medium_mclk_index); 11208c2ecf20Sopenharmony_ci r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 11218c2ecf20Sopenharmony_ci pi->hw.medium_sclk_index); 11228c2ecf20Sopenharmony_ci r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM, 11238c2ecf20Sopenharmony_ci R600_DISPLAY_WATERMARK_LOW); 11248c2ecf20Sopenharmony_ci r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_MEDIUM, 11258c2ecf20Sopenharmony_ci pi->hw.pcie_gen2[R600_POWER_LEVEL_MEDIUM]); 11268c2ecf20Sopenharmony_ci} 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_cistatic void rv6xx_program_power_level_medium_for_transition(struct radeon_device *rdev) 11298c2ecf20Sopenharmony_ci{ 11308c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci rv6xx_program_mclk_stepping_entry(rdev, 11338c2ecf20Sopenharmony_ci R600_POWER_LEVEL_CTXSW, 11348c2ecf20Sopenharmony_ci pi->hw.mclks[pi->hw.low_mclk_index]); 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM, 1); 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 11398c2ecf20Sopenharmony_ci R600_POWER_LEVEL_CTXSW); 11408c2ecf20Sopenharmony_ci r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 11418c2ecf20Sopenharmony_ci pi->hw.medium_sclk_index); 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM, 11448c2ecf20Sopenharmony_ci R600_DISPLAY_WATERMARK_LOW); 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_MEDIUM, false); 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_MEDIUM, 11498c2ecf20Sopenharmony_ci pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW]); 11508c2ecf20Sopenharmony_ci} 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_cistatic void rv6xx_program_power_level_high(struct radeon_device *rdev) 11538c2ecf20Sopenharmony_ci{ 11548c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_HIGH, 11578c2ecf20Sopenharmony_ci pi->hw.high_vddc_index); 11588c2ecf20Sopenharmony_ci r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_HIGH, 11598c2ecf20Sopenharmony_ci pi->hw.high_mclk_index); 11608c2ecf20Sopenharmony_ci r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_HIGH, 11618c2ecf20Sopenharmony_ci pi->hw.high_sclk_index); 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_HIGH, 11648c2ecf20Sopenharmony_ci R600_DISPLAY_WATERMARK_HIGH); 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_HIGH, 11678c2ecf20Sopenharmony_ci pi->hw.pcie_gen2[R600_POWER_LEVEL_HIGH]); 11688c2ecf20Sopenharmony_ci} 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_cistatic void rv6xx_enable_backbias(struct radeon_device *rdev, bool enable) 11718c2ecf20Sopenharmony_ci{ 11728c2ecf20Sopenharmony_ci if (enable) 11738c2ecf20Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, BACKBIAS_PAD_EN | BACKBIAS_DPM_CNTL, 11748c2ecf20Sopenharmony_ci ~(BACKBIAS_PAD_EN | BACKBIAS_DPM_CNTL)); 11758c2ecf20Sopenharmony_ci else 11768c2ecf20Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, 0, 11778c2ecf20Sopenharmony_ci ~(BACKBIAS_VALUE | BACKBIAS_PAD_EN | BACKBIAS_DPM_CNTL)); 11788c2ecf20Sopenharmony_ci} 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_cistatic void rv6xx_program_display_gap(struct radeon_device *rdev) 11818c2ecf20Sopenharmony_ci{ 11828c2ecf20Sopenharmony_ci u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL); 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK); 11858c2ecf20Sopenharmony_ci if (rdev->pm.dpm.new_active_crtcs & 1) { 11868c2ecf20Sopenharmony_ci tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK); 11878c2ecf20Sopenharmony_ci tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); 11888c2ecf20Sopenharmony_ci } else if (rdev->pm.dpm.new_active_crtcs & 2) { 11898c2ecf20Sopenharmony_ci tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); 11908c2ecf20Sopenharmony_ci tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK); 11918c2ecf20Sopenharmony_ci } else { 11928c2ecf20Sopenharmony_ci tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); 11938c2ecf20Sopenharmony_ci tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); 11948c2ecf20Sopenharmony_ci } 11958c2ecf20Sopenharmony_ci WREG32(CG_DISPLAY_GAP_CNTL, tmp); 11968c2ecf20Sopenharmony_ci} 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_cistatic void rv6xx_set_sw_voltage_to_safe(struct radeon_device *rdev, 11998c2ecf20Sopenharmony_ci struct radeon_ps *new_ps, 12008c2ecf20Sopenharmony_ci struct radeon_ps *old_ps) 12018c2ecf20Sopenharmony_ci{ 12028c2ecf20Sopenharmony_ci struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); 12038c2ecf20Sopenharmony_ci struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps); 12048c2ecf20Sopenharmony_ci u16 safe_voltage; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci safe_voltage = (new_state->low.vddc >= old_state->low.vddc) ? 12078c2ecf20Sopenharmony_ci new_state->low.vddc : old_state->low.vddc; 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci rv6xx_program_voltage_stepping_entry(rdev, R600_POWER_LEVEL_CTXSW, 12108c2ecf20Sopenharmony_ci safe_voltage); 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, SW_GPIO_INDEX(R600_POWER_LEVEL_CTXSW), 12138c2ecf20Sopenharmony_ci ~SW_GPIO_INDEX_MASK); 12148c2ecf20Sopenharmony_ci} 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_cistatic void rv6xx_set_sw_voltage_to_low(struct radeon_device *rdev, 12178c2ecf20Sopenharmony_ci struct radeon_ps *old_ps) 12188c2ecf20Sopenharmony_ci{ 12198c2ecf20Sopenharmony_ci struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci rv6xx_program_voltage_stepping_entry(rdev, R600_POWER_LEVEL_CTXSW, 12228c2ecf20Sopenharmony_ci old_state->low.vddc); 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, SW_GPIO_INDEX(R600_POWER_LEVEL_CTXSW), 12258c2ecf20Sopenharmony_ci ~SW_GPIO_INDEX_MASK); 12268c2ecf20Sopenharmony_ci} 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_cistatic void rv6xx_set_safe_backbias(struct radeon_device *rdev, 12298c2ecf20Sopenharmony_ci struct radeon_ps *new_ps, 12308c2ecf20Sopenharmony_ci struct radeon_ps *old_ps) 12318c2ecf20Sopenharmony_ci{ 12328c2ecf20Sopenharmony_ci struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); 12338c2ecf20Sopenharmony_ci struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps); 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci if ((new_state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) && 12368c2ecf20Sopenharmony_ci (old_state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE)) 12378c2ecf20Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, BACKBIAS_VALUE, ~BACKBIAS_VALUE); 12388c2ecf20Sopenharmony_ci else 12398c2ecf20Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, 0, ~BACKBIAS_VALUE); 12408c2ecf20Sopenharmony_ci} 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_cistatic void rv6xx_set_safe_pcie_gen2(struct radeon_device *rdev, 12438c2ecf20Sopenharmony_ci struct radeon_ps *new_ps, 12448c2ecf20Sopenharmony_ci struct radeon_ps *old_ps) 12458c2ecf20Sopenharmony_ci{ 12468c2ecf20Sopenharmony_ci struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); 12478c2ecf20Sopenharmony_ci struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps); 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci if ((new_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) != 12508c2ecf20Sopenharmony_ci (old_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2)) 12518c2ecf20Sopenharmony_ci rv6xx_force_pcie_gen1(rdev); 12528c2ecf20Sopenharmony_ci} 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_cistatic void rv6xx_enable_dynamic_voltage_control(struct radeon_device *rdev, 12558c2ecf20Sopenharmony_ci bool enable) 12568c2ecf20Sopenharmony_ci{ 12578c2ecf20Sopenharmony_ci if (enable) 12588c2ecf20Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, VOLT_PWRMGT_EN, ~VOLT_PWRMGT_EN); 12598c2ecf20Sopenharmony_ci else 12608c2ecf20Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, 0, ~VOLT_PWRMGT_EN); 12618c2ecf20Sopenharmony_ci} 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_cistatic void rv6xx_enable_dynamic_backbias_control(struct radeon_device *rdev, 12648c2ecf20Sopenharmony_ci bool enable) 12658c2ecf20Sopenharmony_ci{ 12668c2ecf20Sopenharmony_ci if (enable) 12678c2ecf20Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, BACKBIAS_DPM_CNTL, ~BACKBIAS_DPM_CNTL); 12688c2ecf20Sopenharmony_ci else 12698c2ecf20Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, 0, ~BACKBIAS_DPM_CNTL); 12708c2ecf20Sopenharmony_ci} 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_cistatic int rv6xx_step_sw_voltage(struct radeon_device *rdev, 12738c2ecf20Sopenharmony_ci u16 initial_voltage, 12748c2ecf20Sopenharmony_ci u16 target_voltage) 12758c2ecf20Sopenharmony_ci{ 12768c2ecf20Sopenharmony_ci u16 current_voltage; 12778c2ecf20Sopenharmony_ci u16 true_target_voltage; 12788c2ecf20Sopenharmony_ci u16 voltage_step; 12798c2ecf20Sopenharmony_ci int signed_voltage_step; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci if ((radeon_atom_get_voltage_step(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, 12828c2ecf20Sopenharmony_ci &voltage_step)) || 12838c2ecf20Sopenharmony_ci (radeon_atom_round_to_true_voltage(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, 12848c2ecf20Sopenharmony_ci initial_voltage, ¤t_voltage)) || 12858c2ecf20Sopenharmony_ci (radeon_atom_round_to_true_voltage(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, 12868c2ecf20Sopenharmony_ci target_voltage, &true_target_voltage))) 12878c2ecf20Sopenharmony_ci return -EINVAL; 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci if (true_target_voltage < current_voltage) 12908c2ecf20Sopenharmony_ci signed_voltage_step = -(int)voltage_step; 12918c2ecf20Sopenharmony_ci else 12928c2ecf20Sopenharmony_ci signed_voltage_step = voltage_step; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci while (current_voltage != true_target_voltage) { 12958c2ecf20Sopenharmony_ci current_voltage += signed_voltage_step; 12968c2ecf20Sopenharmony_ci rv6xx_program_voltage_stepping_entry(rdev, R600_POWER_LEVEL_CTXSW, 12978c2ecf20Sopenharmony_ci current_voltage); 12988c2ecf20Sopenharmony_ci msleep((rdev->pm.dpm.voltage_response_time + 999) / 1000); 12998c2ecf20Sopenharmony_ci } 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci return 0; 13028c2ecf20Sopenharmony_ci} 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_cistatic int rv6xx_step_voltage_if_increasing(struct radeon_device *rdev, 13058c2ecf20Sopenharmony_ci struct radeon_ps *new_ps, 13068c2ecf20Sopenharmony_ci struct radeon_ps *old_ps) 13078c2ecf20Sopenharmony_ci{ 13088c2ecf20Sopenharmony_ci struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); 13098c2ecf20Sopenharmony_ci struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps); 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci if (new_state->low.vddc > old_state->low.vddc) 13128c2ecf20Sopenharmony_ci return rv6xx_step_sw_voltage(rdev, 13138c2ecf20Sopenharmony_ci old_state->low.vddc, 13148c2ecf20Sopenharmony_ci new_state->low.vddc); 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci return 0; 13178c2ecf20Sopenharmony_ci} 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_cistatic int rv6xx_step_voltage_if_decreasing(struct radeon_device *rdev, 13208c2ecf20Sopenharmony_ci struct radeon_ps *new_ps, 13218c2ecf20Sopenharmony_ci struct radeon_ps *old_ps) 13228c2ecf20Sopenharmony_ci{ 13238c2ecf20Sopenharmony_ci struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); 13248c2ecf20Sopenharmony_ci struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps); 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci if (new_state->low.vddc < old_state->low.vddc) 13278c2ecf20Sopenharmony_ci return rv6xx_step_sw_voltage(rdev, 13288c2ecf20Sopenharmony_ci old_state->low.vddc, 13298c2ecf20Sopenharmony_ci new_state->low.vddc); 13308c2ecf20Sopenharmony_ci else 13318c2ecf20Sopenharmony_ci return 0; 13328c2ecf20Sopenharmony_ci} 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_cistatic void rv6xx_enable_high(struct radeon_device *rdev) 13358c2ecf20Sopenharmony_ci{ 13368c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci if ((pi->restricted_levels < 1) || 13398c2ecf20Sopenharmony_ci (pi->restricted_levels == 3)) 13408c2ecf20Sopenharmony_ci r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, true); 13418c2ecf20Sopenharmony_ci} 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_cistatic void rv6xx_enable_medium(struct radeon_device *rdev) 13448c2ecf20Sopenharmony_ci{ 13458c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci if (pi->restricted_levels < 2) 13488c2ecf20Sopenharmony_ci r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true); 13498c2ecf20Sopenharmony_ci} 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_cistatic void rv6xx_set_dpm_event_sources(struct radeon_device *rdev, u32 sources) 13528c2ecf20Sopenharmony_ci{ 13538c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 13548c2ecf20Sopenharmony_ci bool want_thermal_protection; 13558c2ecf20Sopenharmony_ci enum radeon_dpm_event_src dpm_event_src; 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci switch (sources) { 13588c2ecf20Sopenharmony_ci case 0: 13598c2ecf20Sopenharmony_ci default: 13608c2ecf20Sopenharmony_ci want_thermal_protection = false; 13618c2ecf20Sopenharmony_ci break; 13628c2ecf20Sopenharmony_ci case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL): 13638c2ecf20Sopenharmony_ci want_thermal_protection = true; 13648c2ecf20Sopenharmony_ci dpm_event_src = RADEON_DPM_EVENT_SRC_DIGITAL; 13658c2ecf20Sopenharmony_ci break; 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL): 13688c2ecf20Sopenharmony_ci want_thermal_protection = true; 13698c2ecf20Sopenharmony_ci dpm_event_src = RADEON_DPM_EVENT_SRC_EXTERNAL; 13708c2ecf20Sopenharmony_ci break; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci case ((1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL) | 13738c2ecf20Sopenharmony_ci (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL)): 13748c2ecf20Sopenharmony_ci want_thermal_protection = true; 13758c2ecf20Sopenharmony_ci dpm_event_src = RADEON_DPM_EVENT_SRC_DIGIAL_OR_EXTERNAL; 13768c2ecf20Sopenharmony_ci break; 13778c2ecf20Sopenharmony_ci } 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci if (want_thermal_protection) { 13808c2ecf20Sopenharmony_ci WREG32_P(CG_THERMAL_CTRL, DPM_EVENT_SRC(dpm_event_src), ~DPM_EVENT_SRC_MASK); 13818c2ecf20Sopenharmony_ci if (pi->thermal_protection) 13828c2ecf20Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS); 13838c2ecf20Sopenharmony_ci } else { 13848c2ecf20Sopenharmony_ci WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS); 13858c2ecf20Sopenharmony_ci } 13868c2ecf20Sopenharmony_ci} 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_cistatic void rv6xx_enable_auto_throttle_source(struct radeon_device *rdev, 13898c2ecf20Sopenharmony_ci enum radeon_dpm_auto_throttle_src source, 13908c2ecf20Sopenharmony_ci bool enable) 13918c2ecf20Sopenharmony_ci{ 13928c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci if (enable) { 13958c2ecf20Sopenharmony_ci if (!(pi->active_auto_throttle_sources & (1 << source))) { 13968c2ecf20Sopenharmony_ci pi->active_auto_throttle_sources |= 1 << source; 13978c2ecf20Sopenharmony_ci rv6xx_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources); 13988c2ecf20Sopenharmony_ci } 13998c2ecf20Sopenharmony_ci } else { 14008c2ecf20Sopenharmony_ci if (pi->active_auto_throttle_sources & (1 << source)) { 14018c2ecf20Sopenharmony_ci pi->active_auto_throttle_sources &= ~(1 << source); 14028c2ecf20Sopenharmony_ci rv6xx_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources); 14038c2ecf20Sopenharmony_ci } 14048c2ecf20Sopenharmony_ci } 14058c2ecf20Sopenharmony_ci} 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_cistatic void rv6xx_enable_thermal_protection(struct radeon_device *rdev, 14098c2ecf20Sopenharmony_ci bool enable) 14108c2ecf20Sopenharmony_ci{ 14118c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci if (pi->active_auto_throttle_sources) 14148c2ecf20Sopenharmony_ci r600_enable_thermal_protection(rdev, enable); 14158c2ecf20Sopenharmony_ci} 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_cistatic void rv6xx_generate_transition_stepping(struct radeon_device *rdev, 14188c2ecf20Sopenharmony_ci struct radeon_ps *new_ps, 14198c2ecf20Sopenharmony_ci struct radeon_ps *old_ps) 14208c2ecf20Sopenharmony_ci{ 14218c2ecf20Sopenharmony_ci struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); 14228c2ecf20Sopenharmony_ci struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps); 14238c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci rv6xx_generate_steps(rdev, 14268c2ecf20Sopenharmony_ci old_state->low.sclk, 14278c2ecf20Sopenharmony_ci new_state->low.sclk, 14288c2ecf20Sopenharmony_ci 0, &pi->hw.medium_sclk_index); 14298c2ecf20Sopenharmony_ci} 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_cistatic void rv6xx_generate_low_step(struct radeon_device *rdev, 14328c2ecf20Sopenharmony_ci struct radeon_ps *new_ps) 14338c2ecf20Sopenharmony_ci{ 14348c2ecf20Sopenharmony_ci struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); 14358c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci pi->hw.low_sclk_index = 0; 14388c2ecf20Sopenharmony_ci rv6xx_generate_single_step(rdev, 14398c2ecf20Sopenharmony_ci new_state->low.sclk, 14408c2ecf20Sopenharmony_ci 0); 14418c2ecf20Sopenharmony_ci} 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_cistatic void rv6xx_invalidate_intermediate_steps(struct radeon_device *rdev) 14448c2ecf20Sopenharmony_ci{ 14458c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci rv6xx_invalidate_intermediate_steps_range(rdev, 0, 14488c2ecf20Sopenharmony_ci pi->hw.medium_sclk_index); 14498c2ecf20Sopenharmony_ci} 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_cistatic void rv6xx_generate_stepping_table(struct radeon_device *rdev, 14528c2ecf20Sopenharmony_ci struct radeon_ps *new_ps) 14538c2ecf20Sopenharmony_ci{ 14548c2ecf20Sopenharmony_ci struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); 14558c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci pi->hw.low_sclk_index = 0; 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci rv6xx_generate_steps(rdev, 14608c2ecf20Sopenharmony_ci new_state->low.sclk, 14618c2ecf20Sopenharmony_ci new_state->medium.sclk, 14628c2ecf20Sopenharmony_ci 0, 14638c2ecf20Sopenharmony_ci &pi->hw.medium_sclk_index); 14648c2ecf20Sopenharmony_ci rv6xx_generate_steps(rdev, 14658c2ecf20Sopenharmony_ci new_state->medium.sclk, 14668c2ecf20Sopenharmony_ci new_state->high.sclk, 14678c2ecf20Sopenharmony_ci pi->hw.medium_sclk_index, 14688c2ecf20Sopenharmony_ci &pi->hw.high_sclk_index); 14698c2ecf20Sopenharmony_ci} 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_cistatic void rv6xx_enable_spread_spectrum(struct radeon_device *rdev, 14728c2ecf20Sopenharmony_ci bool enable) 14738c2ecf20Sopenharmony_ci{ 14748c2ecf20Sopenharmony_ci if (enable) 14758c2ecf20Sopenharmony_ci rv6xx_enable_dynamic_spread_spectrum(rdev, true); 14768c2ecf20Sopenharmony_ci else { 14778c2ecf20Sopenharmony_ci rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_LOW, false); 14788c2ecf20Sopenharmony_ci rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_MEDIUM, false); 14798c2ecf20Sopenharmony_ci rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_HIGH, false); 14808c2ecf20Sopenharmony_ci rv6xx_enable_dynamic_spread_spectrum(rdev, false); 14818c2ecf20Sopenharmony_ci rv6xx_enable_memory_spread_spectrum(rdev, false); 14828c2ecf20Sopenharmony_ci } 14838c2ecf20Sopenharmony_ci} 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_cistatic void rv6xx_reset_lvtm_data_sync(struct radeon_device *rdev) 14868c2ecf20Sopenharmony_ci{ 14878c2ecf20Sopenharmony_ci if (ASIC_IS_DCE3(rdev)) 14888c2ecf20Sopenharmony_ci WREG32_P(DCE3_LVTMA_DATA_SYNCHRONIZATION, LVTMA_PFREQCHG, ~LVTMA_PFREQCHG); 14898c2ecf20Sopenharmony_ci else 14908c2ecf20Sopenharmony_ci WREG32_P(LVTMA_DATA_SYNCHRONIZATION, LVTMA_PFREQCHG, ~LVTMA_PFREQCHG); 14918c2ecf20Sopenharmony_ci} 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_cistatic void rv6xx_enable_dynamic_pcie_gen2(struct radeon_device *rdev, 14948c2ecf20Sopenharmony_ci struct radeon_ps *new_ps, 14958c2ecf20Sopenharmony_ci bool enable) 14968c2ecf20Sopenharmony_ci{ 14978c2ecf20Sopenharmony_ci struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci if (enable) { 15008c2ecf20Sopenharmony_ci rv6xx_enable_bif_dynamic_pcie_gen2(rdev, true); 15018c2ecf20Sopenharmony_ci rv6xx_enable_pcie_gen2_support(rdev); 15028c2ecf20Sopenharmony_ci r600_enable_dynamic_pcie_gen2(rdev, true); 15038c2ecf20Sopenharmony_ci } else { 15048c2ecf20Sopenharmony_ci if (!(new_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2)) 15058c2ecf20Sopenharmony_ci rv6xx_force_pcie_gen1(rdev); 15068c2ecf20Sopenharmony_ci rv6xx_enable_bif_dynamic_pcie_gen2(rdev, false); 15078c2ecf20Sopenharmony_ci r600_enable_dynamic_pcie_gen2(rdev, false); 15088c2ecf20Sopenharmony_ci } 15098c2ecf20Sopenharmony_ci} 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_cistatic void rv6xx_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev, 15128c2ecf20Sopenharmony_ci struct radeon_ps *new_ps, 15138c2ecf20Sopenharmony_ci struct radeon_ps *old_ps) 15148c2ecf20Sopenharmony_ci{ 15158c2ecf20Sopenharmony_ci struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); 15168c2ecf20Sopenharmony_ci struct rv6xx_ps *current_state = rv6xx_get_ps(old_ps); 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci if ((new_ps->vclk == old_ps->vclk) && 15198c2ecf20Sopenharmony_ci (new_ps->dclk == old_ps->dclk)) 15208c2ecf20Sopenharmony_ci return; 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci if (new_state->high.sclk >= current_state->high.sclk) 15238c2ecf20Sopenharmony_ci return; 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk); 15268c2ecf20Sopenharmony_ci} 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_cistatic void rv6xx_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev, 15298c2ecf20Sopenharmony_ci struct radeon_ps *new_ps, 15308c2ecf20Sopenharmony_ci struct radeon_ps *old_ps) 15318c2ecf20Sopenharmony_ci{ 15328c2ecf20Sopenharmony_ci struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps); 15338c2ecf20Sopenharmony_ci struct rv6xx_ps *current_state = rv6xx_get_ps(old_ps); 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci if ((new_ps->vclk == old_ps->vclk) && 15368c2ecf20Sopenharmony_ci (new_ps->dclk == old_ps->dclk)) 15378c2ecf20Sopenharmony_ci return; 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci if (new_state->high.sclk < current_state->high.sclk) 15408c2ecf20Sopenharmony_ci return; 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk); 15438c2ecf20Sopenharmony_ci} 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ciint rv6xx_dpm_enable(struct radeon_device *rdev) 15468c2ecf20Sopenharmony_ci{ 15478c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 15488c2ecf20Sopenharmony_ci struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps; 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci if (r600_dynamicpm_enabled(rdev)) 15518c2ecf20Sopenharmony_ci return -EINVAL; 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS) 15548c2ecf20Sopenharmony_ci rv6xx_enable_backbias(rdev, true); 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci if (pi->dynamic_ss) 15578c2ecf20Sopenharmony_ci rv6xx_enable_spread_spectrum(rdev, true); 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci rv6xx_program_mpll_timing_parameters(rdev); 15608c2ecf20Sopenharmony_ci rv6xx_program_bsp(rdev); 15618c2ecf20Sopenharmony_ci rv6xx_program_git(rdev); 15628c2ecf20Sopenharmony_ci rv6xx_program_tp(rdev); 15638c2ecf20Sopenharmony_ci rv6xx_program_tpp(rdev); 15648c2ecf20Sopenharmony_ci rv6xx_program_sstp(rdev); 15658c2ecf20Sopenharmony_ci rv6xx_program_fcp(rdev); 15668c2ecf20Sopenharmony_ci rv6xx_program_vddc3d_parameters(rdev); 15678c2ecf20Sopenharmony_ci rv6xx_program_voltage_timing_parameters(rdev); 15688c2ecf20Sopenharmony_ci rv6xx_program_engine_speed_parameters(rdev); 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci rv6xx_enable_display_gap(rdev, true); 15718c2ecf20Sopenharmony_ci if (pi->display_gap == false) 15728c2ecf20Sopenharmony_ci rv6xx_enable_display_gap(rdev, false); 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci rv6xx_program_power_level_enter_state(rdev); 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci rv6xx_calculate_stepping_parameters(rdev, boot_ps); 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci if (pi->voltage_control) 15798c2ecf20Sopenharmony_ci rv6xx_program_voltage_gpio_pins(rdev); 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci rv6xx_generate_stepping_table(rdev, boot_ps); 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci rv6xx_program_stepping_parameters_except_lowest_entry(rdev); 15848c2ecf20Sopenharmony_ci rv6xx_program_stepping_parameters_lowest_entry(rdev); 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci rv6xx_program_power_level_low(rdev); 15878c2ecf20Sopenharmony_ci rv6xx_program_power_level_medium(rdev); 15888c2ecf20Sopenharmony_ci rv6xx_program_power_level_high(rdev); 15898c2ecf20Sopenharmony_ci rv6xx_program_vc(rdev); 15908c2ecf20Sopenharmony_ci rv6xx_program_at(rdev); 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true); 15938c2ecf20Sopenharmony_ci r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true); 15948c2ecf20Sopenharmony_ci r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, true); 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci rv6xx_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci r600_start_dpm(rdev); 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci if (pi->voltage_control) 16018c2ecf20Sopenharmony_ci rv6xx_enable_static_voltage_control(rdev, boot_ps, false); 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci if (pi->dynamic_pcie_gen2) 16048c2ecf20Sopenharmony_ci rv6xx_enable_dynamic_pcie_gen2(rdev, boot_ps, true); 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci if (pi->gfx_clock_gating) 16078c2ecf20Sopenharmony_ci r600_gfx_clockgating_enable(rdev, true); 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci return 0; 16108c2ecf20Sopenharmony_ci} 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_civoid rv6xx_dpm_disable(struct radeon_device *rdev) 16138c2ecf20Sopenharmony_ci{ 16148c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 16158c2ecf20Sopenharmony_ci struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps; 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci if (!r600_dynamicpm_enabled(rdev)) 16188c2ecf20Sopenharmony_ci return; 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true); 16218c2ecf20Sopenharmony_ci r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true); 16228c2ecf20Sopenharmony_ci rv6xx_enable_display_gap(rdev, false); 16238c2ecf20Sopenharmony_ci rv6xx_clear_vc(rdev); 16248c2ecf20Sopenharmony_ci r600_set_at(rdev, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF); 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci if (pi->thermal_protection) 16278c2ecf20Sopenharmony_ci r600_enable_thermal_protection(rdev, false); 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW); 16308c2ecf20Sopenharmony_ci r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false); 16318c2ecf20Sopenharmony_ci r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false); 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS) 16348c2ecf20Sopenharmony_ci rv6xx_enable_backbias(rdev, false); 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci rv6xx_enable_spread_spectrum(rdev, false); 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci if (pi->voltage_control) 16398c2ecf20Sopenharmony_ci rv6xx_enable_static_voltage_control(rdev, boot_ps, true); 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci if (pi->dynamic_pcie_gen2) 16428c2ecf20Sopenharmony_ci rv6xx_enable_dynamic_pcie_gen2(rdev, boot_ps, false); 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci if (rdev->irq.installed && 16458c2ecf20Sopenharmony_ci r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { 16468c2ecf20Sopenharmony_ci rdev->irq.dpm_thermal = false; 16478c2ecf20Sopenharmony_ci radeon_irq_set(rdev); 16488c2ecf20Sopenharmony_ci } 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci if (pi->gfx_clock_gating) 16518c2ecf20Sopenharmony_ci r600_gfx_clockgating_enable(rdev, false); 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci r600_stop_dpm(rdev); 16548c2ecf20Sopenharmony_ci} 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ciint rv6xx_dpm_set_power_state(struct radeon_device *rdev) 16578c2ecf20Sopenharmony_ci{ 16588c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 16598c2ecf20Sopenharmony_ci struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps; 16608c2ecf20Sopenharmony_ci struct radeon_ps *old_ps = rdev->pm.dpm.current_ps; 16618c2ecf20Sopenharmony_ci int ret; 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci pi->restricted_levels = 0; 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci rv6xx_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps); 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci rv6xx_clear_vc(rdev); 16688c2ecf20Sopenharmony_ci r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true); 16698c2ecf20Sopenharmony_ci r600_set_at(rdev, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF); 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci if (pi->thermal_protection) 16728c2ecf20Sopenharmony_ci r600_enable_thermal_protection(rdev, false); 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW); 16758c2ecf20Sopenharmony_ci r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false); 16768c2ecf20Sopenharmony_ci r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false); 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci rv6xx_generate_transition_stepping(rdev, new_ps, old_ps); 16798c2ecf20Sopenharmony_ci rv6xx_program_power_level_medium_for_transition(rdev); 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci if (pi->voltage_control) { 16828c2ecf20Sopenharmony_ci rv6xx_set_sw_voltage_to_safe(rdev, new_ps, old_ps); 16838c2ecf20Sopenharmony_ci if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC) 16848c2ecf20Sopenharmony_ci rv6xx_set_sw_voltage_to_low(rdev, old_ps); 16858c2ecf20Sopenharmony_ci } 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS) 16888c2ecf20Sopenharmony_ci rv6xx_set_safe_backbias(rdev, new_ps, old_ps); 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci if (pi->dynamic_pcie_gen2) 16918c2ecf20Sopenharmony_ci rv6xx_set_safe_pcie_gen2(rdev, new_ps, old_ps); 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci if (pi->voltage_control) 16948c2ecf20Sopenharmony_ci rv6xx_enable_dynamic_voltage_control(rdev, false); 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS) 16978c2ecf20Sopenharmony_ci rv6xx_enable_dynamic_backbias_control(rdev, false); 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci if (pi->voltage_control) { 17008c2ecf20Sopenharmony_ci if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC) 17018c2ecf20Sopenharmony_ci rv6xx_step_voltage_if_increasing(rdev, new_ps, old_ps); 17028c2ecf20Sopenharmony_ci msleep((rdev->pm.dpm.voltage_response_time + 999) / 1000); 17038c2ecf20Sopenharmony_ci } 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true); 17068c2ecf20Sopenharmony_ci r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, false); 17078c2ecf20Sopenharmony_ci r600_wait_for_power_level_unequal(rdev, R600_POWER_LEVEL_LOW); 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci rv6xx_generate_low_step(rdev, new_ps); 17108c2ecf20Sopenharmony_ci rv6xx_invalidate_intermediate_steps(rdev); 17118c2ecf20Sopenharmony_ci rv6xx_calculate_stepping_parameters(rdev, new_ps); 17128c2ecf20Sopenharmony_ci rv6xx_program_stepping_parameters_lowest_entry(rdev); 17138c2ecf20Sopenharmony_ci rv6xx_program_power_level_low_to_lowest_state(rdev); 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true); 17168c2ecf20Sopenharmony_ci r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW); 17178c2ecf20Sopenharmony_ci r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false); 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci if (pi->voltage_control) { 17208c2ecf20Sopenharmony_ci if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC) { 17218c2ecf20Sopenharmony_ci ret = rv6xx_step_voltage_if_decreasing(rdev, new_ps, old_ps); 17228c2ecf20Sopenharmony_ci if (ret) 17238c2ecf20Sopenharmony_ci return ret; 17248c2ecf20Sopenharmony_ci } 17258c2ecf20Sopenharmony_ci rv6xx_enable_dynamic_voltage_control(rdev, true); 17268c2ecf20Sopenharmony_ci } 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS) 17298c2ecf20Sopenharmony_ci rv6xx_enable_dynamic_backbias_control(rdev, true); 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci if (pi->dynamic_pcie_gen2) 17328c2ecf20Sopenharmony_ci rv6xx_enable_dynamic_pcie_gen2(rdev, new_ps, true); 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci rv6xx_reset_lvtm_data_sync(rdev); 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci rv6xx_generate_stepping_table(rdev, new_ps); 17378c2ecf20Sopenharmony_ci rv6xx_program_stepping_parameters_except_lowest_entry(rdev); 17388c2ecf20Sopenharmony_ci rv6xx_program_power_level_low(rdev); 17398c2ecf20Sopenharmony_ci rv6xx_program_power_level_medium(rdev); 17408c2ecf20Sopenharmony_ci rv6xx_program_power_level_high(rdev); 17418c2ecf20Sopenharmony_ci rv6xx_enable_medium(rdev); 17428c2ecf20Sopenharmony_ci rv6xx_enable_high(rdev); 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_ci if (pi->thermal_protection) 17458c2ecf20Sopenharmony_ci rv6xx_enable_thermal_protection(rdev, true); 17468c2ecf20Sopenharmony_ci rv6xx_program_vc(rdev); 17478c2ecf20Sopenharmony_ci rv6xx_program_at(rdev); 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci rv6xx_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps); 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci return 0; 17528c2ecf20Sopenharmony_ci} 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_civoid rv6xx_setup_asic(struct radeon_device *rdev) 17558c2ecf20Sopenharmony_ci{ 17568c2ecf20Sopenharmony_ci r600_enable_acpi_pm(rdev); 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci if (radeon_aspm != 0) { 17598c2ecf20Sopenharmony_ci if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s) 17608c2ecf20Sopenharmony_ci rv6xx_enable_l0s(rdev); 17618c2ecf20Sopenharmony_ci if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1) 17628c2ecf20Sopenharmony_ci rv6xx_enable_l1(rdev); 17638c2ecf20Sopenharmony_ci if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1) 17648c2ecf20Sopenharmony_ci rv6xx_enable_pll_sleep_in_l1(rdev); 17658c2ecf20Sopenharmony_ci } 17668c2ecf20Sopenharmony_ci} 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_civoid rv6xx_dpm_display_configuration_changed(struct radeon_device *rdev) 17698c2ecf20Sopenharmony_ci{ 17708c2ecf20Sopenharmony_ci rv6xx_program_display_gap(rdev); 17718c2ecf20Sopenharmony_ci} 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ciunion power_info { 17748c2ecf20Sopenharmony_ci struct _ATOM_POWERPLAY_INFO info; 17758c2ecf20Sopenharmony_ci struct _ATOM_POWERPLAY_INFO_V2 info_2; 17768c2ecf20Sopenharmony_ci struct _ATOM_POWERPLAY_INFO_V3 info_3; 17778c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_POWERPLAYTABLE pplib; 17788c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2; 17798c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3; 17808c2ecf20Sopenharmony_ci}; 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ciunion pplib_clock_info { 17838c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_R600_CLOCK_INFO r600; 17848c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780; 17858c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen; 17868c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo; 17878c2ecf20Sopenharmony_ci}; 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ciunion pplib_power_state { 17908c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_STATE v1; 17918c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_STATE_V2 v2; 17928c2ecf20Sopenharmony_ci}; 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_cistatic void rv6xx_parse_pplib_non_clock_info(struct radeon_device *rdev, 17958c2ecf20Sopenharmony_ci struct radeon_ps *rps, 17968c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info) 17978c2ecf20Sopenharmony_ci{ 17988c2ecf20Sopenharmony_ci rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings); 17998c2ecf20Sopenharmony_ci rps->class = le16_to_cpu(non_clock_info->usClassification); 18008c2ecf20Sopenharmony_ci rps->class2 = le16_to_cpu(non_clock_info->usClassification2); 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ci if (r600_is_uvd_state(rps->class, rps->class2)) { 18038c2ecf20Sopenharmony_ci rps->vclk = RV6XX_DEFAULT_VCLK_FREQ; 18048c2ecf20Sopenharmony_ci rps->dclk = RV6XX_DEFAULT_DCLK_FREQ; 18058c2ecf20Sopenharmony_ci } else { 18068c2ecf20Sopenharmony_ci rps->vclk = 0; 18078c2ecf20Sopenharmony_ci rps->dclk = 0; 18088c2ecf20Sopenharmony_ci } 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) 18118c2ecf20Sopenharmony_ci rdev->pm.dpm.boot_ps = rps; 18128c2ecf20Sopenharmony_ci if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) 18138c2ecf20Sopenharmony_ci rdev->pm.dpm.uvd_ps = rps; 18148c2ecf20Sopenharmony_ci} 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_cistatic void rv6xx_parse_pplib_clock_info(struct radeon_device *rdev, 18178c2ecf20Sopenharmony_ci struct radeon_ps *rps, int index, 18188c2ecf20Sopenharmony_ci union pplib_clock_info *clock_info) 18198c2ecf20Sopenharmony_ci{ 18208c2ecf20Sopenharmony_ci struct rv6xx_ps *ps = rv6xx_get_ps(rps); 18218c2ecf20Sopenharmony_ci u32 sclk, mclk; 18228c2ecf20Sopenharmony_ci u16 vddc; 18238c2ecf20Sopenharmony_ci struct rv6xx_pl *pl; 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci switch (index) { 18268c2ecf20Sopenharmony_ci case 0: 18278c2ecf20Sopenharmony_ci pl = &ps->low; 18288c2ecf20Sopenharmony_ci break; 18298c2ecf20Sopenharmony_ci case 1: 18308c2ecf20Sopenharmony_ci pl = &ps->medium; 18318c2ecf20Sopenharmony_ci break; 18328c2ecf20Sopenharmony_ci case 2: 18338c2ecf20Sopenharmony_ci default: 18348c2ecf20Sopenharmony_ci pl = &ps->high; 18358c2ecf20Sopenharmony_ci break; 18368c2ecf20Sopenharmony_ci } 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci sclk = le16_to_cpu(clock_info->r600.usEngineClockLow); 18398c2ecf20Sopenharmony_ci sclk |= clock_info->r600.ucEngineClockHigh << 16; 18408c2ecf20Sopenharmony_ci mclk = le16_to_cpu(clock_info->r600.usMemoryClockLow); 18418c2ecf20Sopenharmony_ci mclk |= clock_info->r600.ucMemoryClockHigh << 16; 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci pl->mclk = mclk; 18448c2ecf20Sopenharmony_ci pl->sclk = sclk; 18458c2ecf20Sopenharmony_ci pl->vddc = le16_to_cpu(clock_info->r600.usVDDC); 18468c2ecf20Sopenharmony_ci pl->flags = le32_to_cpu(clock_info->r600.ulFlags); 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci /* patch up vddc if necessary */ 18498c2ecf20Sopenharmony_ci if (pl->vddc == 0xff01) { 18508c2ecf20Sopenharmony_ci if (radeon_atom_get_max_vddc(rdev, 0, 0, &vddc) == 0) 18518c2ecf20Sopenharmony_ci pl->vddc = vddc; 18528c2ecf20Sopenharmony_ci } 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci /* fix up pcie gen2 */ 18558c2ecf20Sopenharmony_ci if (pl->flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) { 18568c2ecf20Sopenharmony_ci if ((rdev->family == CHIP_RV610) || (rdev->family == CHIP_RV630)) { 18578c2ecf20Sopenharmony_ci if (pl->vddc < 1100) 18588c2ecf20Sopenharmony_ci pl->flags &= ~ATOM_PPLIB_R600_FLAGS_PCIEGEN2; 18598c2ecf20Sopenharmony_ci } 18608c2ecf20Sopenharmony_ci } 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_ci /* patch up boot state */ 18638c2ecf20Sopenharmony_ci if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) { 18648c2ecf20Sopenharmony_ci u16 vddc, vddci, mvdd; 18658c2ecf20Sopenharmony_ci radeon_atombios_get_default_voltages(rdev, &vddc, &vddci, &mvdd); 18668c2ecf20Sopenharmony_ci pl->mclk = rdev->clock.default_mclk; 18678c2ecf20Sopenharmony_ci pl->sclk = rdev->clock.default_sclk; 18688c2ecf20Sopenharmony_ci pl->vddc = vddc; 18698c2ecf20Sopenharmony_ci } 18708c2ecf20Sopenharmony_ci} 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_cistatic int rv6xx_parse_power_table(struct radeon_device *rdev) 18738c2ecf20Sopenharmony_ci{ 18748c2ecf20Sopenharmony_ci struct radeon_mode_info *mode_info = &rdev->mode_info; 18758c2ecf20Sopenharmony_ci struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; 18768c2ecf20Sopenharmony_ci union pplib_power_state *power_state; 18778c2ecf20Sopenharmony_ci int i, j; 18788c2ecf20Sopenharmony_ci union pplib_clock_info *clock_info; 18798c2ecf20Sopenharmony_ci union power_info *power_info; 18808c2ecf20Sopenharmony_ci int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); 18818c2ecf20Sopenharmony_ci u16 data_offset; 18828c2ecf20Sopenharmony_ci u8 frev, crev; 18838c2ecf20Sopenharmony_ci struct rv6xx_ps *ps; 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci if (!atom_parse_data_header(mode_info->atom_context, index, NULL, 18868c2ecf20Sopenharmony_ci &frev, &crev, &data_offset)) 18878c2ecf20Sopenharmony_ci return -EINVAL; 18888c2ecf20Sopenharmony_ci power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci rdev->pm.dpm.ps = kcalloc(power_info->pplib.ucNumStates, 18918c2ecf20Sopenharmony_ci sizeof(struct radeon_ps), 18928c2ecf20Sopenharmony_ci GFP_KERNEL); 18938c2ecf20Sopenharmony_ci if (!rdev->pm.dpm.ps) 18948c2ecf20Sopenharmony_ci return -ENOMEM; 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci for (i = 0; i < power_info->pplib.ucNumStates; i++) { 18978c2ecf20Sopenharmony_ci power_state = (union pplib_power_state *) 18988c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 18998c2ecf20Sopenharmony_ci le16_to_cpu(power_info->pplib.usStateArrayOffset) + 19008c2ecf20Sopenharmony_ci i * power_info->pplib.ucStateEntrySize); 19018c2ecf20Sopenharmony_ci non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) 19028c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 19038c2ecf20Sopenharmony_ci le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) + 19048c2ecf20Sopenharmony_ci (power_state->v1.ucNonClockStateIndex * 19058c2ecf20Sopenharmony_ci power_info->pplib.ucNonClockSize)); 19068c2ecf20Sopenharmony_ci if (power_info->pplib.ucStateEntrySize - 1) { 19078c2ecf20Sopenharmony_ci u8 *idx; 19088c2ecf20Sopenharmony_ci ps = kzalloc(sizeof(struct rv6xx_ps), GFP_KERNEL); 19098c2ecf20Sopenharmony_ci if (ps == NULL) { 19108c2ecf20Sopenharmony_ci kfree(rdev->pm.dpm.ps); 19118c2ecf20Sopenharmony_ci return -ENOMEM; 19128c2ecf20Sopenharmony_ci } 19138c2ecf20Sopenharmony_ci rdev->pm.dpm.ps[i].ps_priv = ps; 19148c2ecf20Sopenharmony_ci rv6xx_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i], 19158c2ecf20Sopenharmony_ci non_clock_info); 19168c2ecf20Sopenharmony_ci idx = (u8 *)&power_state->v1.ucClockStateIndices[0]; 19178c2ecf20Sopenharmony_ci for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) { 19188c2ecf20Sopenharmony_ci clock_info = (union pplib_clock_info *) 19198c2ecf20Sopenharmony_ci (mode_info->atom_context->bios + data_offset + 19208c2ecf20Sopenharmony_ci le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) + 19218c2ecf20Sopenharmony_ci (idx[j] * power_info->pplib.ucClockInfoSize)); 19228c2ecf20Sopenharmony_ci rv6xx_parse_pplib_clock_info(rdev, 19238c2ecf20Sopenharmony_ci &rdev->pm.dpm.ps[i], j, 19248c2ecf20Sopenharmony_ci clock_info); 19258c2ecf20Sopenharmony_ci } 19268c2ecf20Sopenharmony_ci } 19278c2ecf20Sopenharmony_ci } 19288c2ecf20Sopenharmony_ci rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates; 19298c2ecf20Sopenharmony_ci return 0; 19308c2ecf20Sopenharmony_ci} 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_ciint rv6xx_dpm_init(struct radeon_device *rdev) 19338c2ecf20Sopenharmony_ci{ 19348c2ecf20Sopenharmony_ci struct radeon_atom_ss ss; 19358c2ecf20Sopenharmony_ci struct atom_clock_dividers dividers; 19368c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi; 19378c2ecf20Sopenharmony_ci int ret; 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci pi = kzalloc(sizeof(struct rv6xx_power_info), GFP_KERNEL); 19408c2ecf20Sopenharmony_ci if (pi == NULL) 19418c2ecf20Sopenharmony_ci return -ENOMEM; 19428c2ecf20Sopenharmony_ci rdev->pm.dpm.priv = pi; 19438c2ecf20Sopenharmony_ci 19448c2ecf20Sopenharmony_ci ret = r600_get_platform_caps(rdev); 19458c2ecf20Sopenharmony_ci if (ret) 19468c2ecf20Sopenharmony_ci return ret; 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci ret = rv6xx_parse_power_table(rdev); 19498c2ecf20Sopenharmony_ci if (ret) 19508c2ecf20Sopenharmony_ci return ret; 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_ci if (rdev->pm.dpm.voltage_response_time == 0) 19538c2ecf20Sopenharmony_ci rdev->pm.dpm.voltage_response_time = R600_VOLTAGERESPONSETIME_DFLT; 19548c2ecf20Sopenharmony_ci if (rdev->pm.dpm.backbias_response_time == 0) 19558c2ecf20Sopenharmony_ci rdev->pm.dpm.backbias_response_time = R600_BACKBIASRESPONSETIME_DFLT; 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, 19588c2ecf20Sopenharmony_ci 0, false, ÷rs); 19598c2ecf20Sopenharmony_ci if (ret) 19608c2ecf20Sopenharmony_ci pi->spll_ref_div = dividers.ref_div + 1; 19618c2ecf20Sopenharmony_ci else 19628c2ecf20Sopenharmony_ci pi->spll_ref_div = R600_REFERENCEDIVIDER_DFLT; 19638c2ecf20Sopenharmony_ci 19648c2ecf20Sopenharmony_ci ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM, 19658c2ecf20Sopenharmony_ci 0, false, ÷rs); 19668c2ecf20Sopenharmony_ci if (ret) 19678c2ecf20Sopenharmony_ci pi->mpll_ref_div = dividers.ref_div + 1; 19688c2ecf20Sopenharmony_ci else 19698c2ecf20Sopenharmony_ci pi->mpll_ref_div = R600_REFERENCEDIVIDER_DFLT; 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci if (rdev->family >= CHIP_RV670) 19728c2ecf20Sopenharmony_ci pi->fb_div_scale = 1; 19738c2ecf20Sopenharmony_ci else 19748c2ecf20Sopenharmony_ci pi->fb_div_scale = 0; 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_ci pi->voltage_control = 19778c2ecf20Sopenharmony_ci radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, 0); 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci pi->gfx_clock_gating = true; 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_ci pi->sclk_ss = radeon_atombios_get_asic_ss_info(rdev, &ss, 19828c2ecf20Sopenharmony_ci ASIC_INTERNAL_ENGINE_SS, 0); 19838c2ecf20Sopenharmony_ci pi->mclk_ss = radeon_atombios_get_asic_ss_info(rdev, &ss, 19848c2ecf20Sopenharmony_ci ASIC_INTERNAL_MEMORY_SS, 0); 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci /* Disable sclk ss, causes hangs on a lot of systems */ 19878c2ecf20Sopenharmony_ci pi->sclk_ss = false; 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ci if (pi->sclk_ss || pi->mclk_ss) 19908c2ecf20Sopenharmony_ci pi->dynamic_ss = true; 19918c2ecf20Sopenharmony_ci else 19928c2ecf20Sopenharmony_ci pi->dynamic_ss = false; 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_ci pi->dynamic_pcie_gen2 = true; 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci if (pi->gfx_clock_gating && 19978c2ecf20Sopenharmony_ci (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE)) 19988c2ecf20Sopenharmony_ci pi->thermal_protection = true; 19998c2ecf20Sopenharmony_ci else 20008c2ecf20Sopenharmony_ci pi->thermal_protection = false; 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci pi->display_gap = true; 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ci return 0; 20058c2ecf20Sopenharmony_ci} 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_civoid rv6xx_dpm_print_power_state(struct radeon_device *rdev, 20088c2ecf20Sopenharmony_ci struct radeon_ps *rps) 20098c2ecf20Sopenharmony_ci{ 20108c2ecf20Sopenharmony_ci struct rv6xx_ps *ps = rv6xx_get_ps(rps); 20118c2ecf20Sopenharmony_ci struct rv6xx_pl *pl; 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_ci r600_dpm_print_class_info(rps->class, rps->class2); 20148c2ecf20Sopenharmony_ci r600_dpm_print_cap_info(rps->caps); 20158c2ecf20Sopenharmony_ci printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); 20168c2ecf20Sopenharmony_ci pl = &ps->low; 20178c2ecf20Sopenharmony_ci printk("\t\tpower level 0 sclk: %u mclk: %u vddc: %u\n", 20188c2ecf20Sopenharmony_ci pl->sclk, pl->mclk, pl->vddc); 20198c2ecf20Sopenharmony_ci pl = &ps->medium; 20208c2ecf20Sopenharmony_ci printk("\t\tpower level 1 sclk: %u mclk: %u vddc: %u\n", 20218c2ecf20Sopenharmony_ci pl->sclk, pl->mclk, pl->vddc); 20228c2ecf20Sopenharmony_ci pl = &ps->high; 20238c2ecf20Sopenharmony_ci printk("\t\tpower level 2 sclk: %u mclk: %u vddc: %u\n", 20248c2ecf20Sopenharmony_ci pl->sclk, pl->mclk, pl->vddc); 20258c2ecf20Sopenharmony_ci r600_dpm_print_ps_status(rdev, rps); 20268c2ecf20Sopenharmony_ci} 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_civoid rv6xx_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, 20298c2ecf20Sopenharmony_ci struct seq_file *m) 20308c2ecf20Sopenharmony_ci{ 20318c2ecf20Sopenharmony_ci struct radeon_ps *rps = rdev->pm.dpm.current_ps; 20328c2ecf20Sopenharmony_ci struct rv6xx_ps *ps = rv6xx_get_ps(rps); 20338c2ecf20Sopenharmony_ci struct rv6xx_pl *pl; 20348c2ecf20Sopenharmony_ci u32 current_index = 20358c2ecf20Sopenharmony_ci (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >> 20368c2ecf20Sopenharmony_ci CURRENT_PROFILE_INDEX_SHIFT; 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci if (current_index > 2) { 20398c2ecf20Sopenharmony_ci seq_printf(m, "invalid dpm profile %d\n", current_index); 20408c2ecf20Sopenharmony_ci } else { 20418c2ecf20Sopenharmony_ci if (current_index == 0) 20428c2ecf20Sopenharmony_ci pl = &ps->low; 20438c2ecf20Sopenharmony_ci else if (current_index == 1) 20448c2ecf20Sopenharmony_ci pl = &ps->medium; 20458c2ecf20Sopenharmony_ci else /* current_index == 2 */ 20468c2ecf20Sopenharmony_ci pl = &ps->high; 20478c2ecf20Sopenharmony_ci seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); 20488c2ecf20Sopenharmony_ci seq_printf(m, "power level %d sclk: %u mclk: %u vddc: %u\n", 20498c2ecf20Sopenharmony_ci current_index, pl->sclk, pl->mclk, pl->vddc); 20508c2ecf20Sopenharmony_ci } 20518c2ecf20Sopenharmony_ci} 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ci/* get the current sclk in 10 khz units */ 20548c2ecf20Sopenharmony_ciu32 rv6xx_dpm_get_current_sclk(struct radeon_device *rdev) 20558c2ecf20Sopenharmony_ci{ 20568c2ecf20Sopenharmony_ci struct radeon_ps *rps = rdev->pm.dpm.current_ps; 20578c2ecf20Sopenharmony_ci struct rv6xx_ps *ps = rv6xx_get_ps(rps); 20588c2ecf20Sopenharmony_ci struct rv6xx_pl *pl; 20598c2ecf20Sopenharmony_ci u32 current_index = 20608c2ecf20Sopenharmony_ci (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >> 20618c2ecf20Sopenharmony_ci CURRENT_PROFILE_INDEX_SHIFT; 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_ci if (current_index > 2) { 20648c2ecf20Sopenharmony_ci return 0; 20658c2ecf20Sopenharmony_ci } else { 20668c2ecf20Sopenharmony_ci if (current_index == 0) 20678c2ecf20Sopenharmony_ci pl = &ps->low; 20688c2ecf20Sopenharmony_ci else if (current_index == 1) 20698c2ecf20Sopenharmony_ci pl = &ps->medium; 20708c2ecf20Sopenharmony_ci else /* current_index == 2 */ 20718c2ecf20Sopenharmony_ci pl = &ps->high; 20728c2ecf20Sopenharmony_ci return pl->sclk; 20738c2ecf20Sopenharmony_ci } 20748c2ecf20Sopenharmony_ci} 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci/* get the current mclk in 10 khz units */ 20778c2ecf20Sopenharmony_ciu32 rv6xx_dpm_get_current_mclk(struct radeon_device *rdev) 20788c2ecf20Sopenharmony_ci{ 20798c2ecf20Sopenharmony_ci struct radeon_ps *rps = rdev->pm.dpm.current_ps; 20808c2ecf20Sopenharmony_ci struct rv6xx_ps *ps = rv6xx_get_ps(rps); 20818c2ecf20Sopenharmony_ci struct rv6xx_pl *pl; 20828c2ecf20Sopenharmony_ci u32 current_index = 20838c2ecf20Sopenharmony_ci (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >> 20848c2ecf20Sopenharmony_ci CURRENT_PROFILE_INDEX_SHIFT; 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci if (current_index > 2) { 20878c2ecf20Sopenharmony_ci return 0; 20888c2ecf20Sopenharmony_ci } else { 20898c2ecf20Sopenharmony_ci if (current_index == 0) 20908c2ecf20Sopenharmony_ci pl = &ps->low; 20918c2ecf20Sopenharmony_ci else if (current_index == 1) 20928c2ecf20Sopenharmony_ci pl = &ps->medium; 20938c2ecf20Sopenharmony_ci else /* current_index == 2 */ 20948c2ecf20Sopenharmony_ci pl = &ps->high; 20958c2ecf20Sopenharmony_ci return pl->mclk; 20968c2ecf20Sopenharmony_ci } 20978c2ecf20Sopenharmony_ci} 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_civoid rv6xx_dpm_fini(struct radeon_device *rdev) 21008c2ecf20Sopenharmony_ci{ 21018c2ecf20Sopenharmony_ci int i; 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_ci for (i = 0; i < rdev->pm.dpm.num_ps; i++) { 21048c2ecf20Sopenharmony_ci kfree(rdev->pm.dpm.ps[i].ps_priv); 21058c2ecf20Sopenharmony_ci } 21068c2ecf20Sopenharmony_ci kfree(rdev->pm.dpm.ps); 21078c2ecf20Sopenharmony_ci kfree(rdev->pm.dpm.priv); 21088c2ecf20Sopenharmony_ci} 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_ciu32 rv6xx_dpm_get_sclk(struct radeon_device *rdev, bool low) 21118c2ecf20Sopenharmony_ci{ 21128c2ecf20Sopenharmony_ci struct rv6xx_ps *requested_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps); 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_ci if (low) 21158c2ecf20Sopenharmony_ci return requested_state->low.sclk; 21168c2ecf20Sopenharmony_ci else 21178c2ecf20Sopenharmony_ci return requested_state->high.sclk; 21188c2ecf20Sopenharmony_ci} 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ciu32 rv6xx_dpm_get_mclk(struct radeon_device *rdev, bool low) 21218c2ecf20Sopenharmony_ci{ 21228c2ecf20Sopenharmony_ci struct rv6xx_ps *requested_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps); 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_ci if (low) 21258c2ecf20Sopenharmony_ci return requested_state->low.mclk; 21268c2ecf20Sopenharmony_ci else 21278c2ecf20Sopenharmony_ci return requested_state->high.mclk; 21288c2ecf20Sopenharmony_ci} 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ciint rv6xx_dpm_force_performance_level(struct radeon_device *rdev, 21318c2ecf20Sopenharmony_ci enum radeon_dpm_forced_level level) 21328c2ecf20Sopenharmony_ci{ 21338c2ecf20Sopenharmony_ci struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { 21368c2ecf20Sopenharmony_ci pi->restricted_levels = 3; 21378c2ecf20Sopenharmony_ci } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) { 21388c2ecf20Sopenharmony_ci pi->restricted_levels = 2; 21398c2ecf20Sopenharmony_ci } else { 21408c2ecf20Sopenharmony_ci pi->restricted_levels = 0; 21418c2ecf20Sopenharmony_ci } 21428c2ecf20Sopenharmony_ci 21438c2ecf20Sopenharmony_ci rv6xx_clear_vc(rdev); 21448c2ecf20Sopenharmony_ci r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true); 21458c2ecf20Sopenharmony_ci r600_set_at(rdev, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF); 21468c2ecf20Sopenharmony_ci r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW); 21478c2ecf20Sopenharmony_ci r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false); 21488c2ecf20Sopenharmony_ci r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false); 21498c2ecf20Sopenharmony_ci rv6xx_enable_medium(rdev); 21508c2ecf20Sopenharmony_ci rv6xx_enable_high(rdev); 21518c2ecf20Sopenharmony_ci if (pi->restricted_levels == 3) 21528c2ecf20Sopenharmony_ci r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, false); 21538c2ecf20Sopenharmony_ci rv6xx_program_vc(rdev); 21548c2ecf20Sopenharmony_ci rv6xx_program_at(rdev); 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci rdev->pm.dpm.forced_level = level; 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ci return 0; 21598c2ecf20Sopenharmony_ci} 2160