17ccd5a2cSjsg /*
27ccd5a2cSjsg * Copyright 2011 Advanced Micro Devices, Inc.
37ccd5a2cSjsg *
47ccd5a2cSjsg * Permission is hereby granted, free of charge, to any person obtaining a
57ccd5a2cSjsg * copy of this software and associated documentation files (the "Software"),
67ccd5a2cSjsg * to deal in the Software without restriction, including without limitation
77ccd5a2cSjsg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
87ccd5a2cSjsg * and/or sell copies of the Software, and to permit persons to whom the
97ccd5a2cSjsg * Software is furnished to do so, subject to the following conditions:
107ccd5a2cSjsg *
117ccd5a2cSjsg * The above copyright notice and this permission notice shall be included in
127ccd5a2cSjsg * all copies or substantial portions of the Software.
137ccd5a2cSjsg *
147ccd5a2cSjsg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
157ccd5a2cSjsg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
167ccd5a2cSjsg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
177ccd5a2cSjsg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
187ccd5a2cSjsg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
197ccd5a2cSjsg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
207ccd5a2cSjsg * OTHER DEALINGS IN THE SOFTWARE.
217ccd5a2cSjsg *
227ccd5a2cSjsg * Authors: Alex Deucher
237ccd5a2cSjsg */
247ccd5a2cSjsg
257ccd5a2cSjsg #include "radeon.h"
267ccd5a2cSjsg #include "radeon_asic.h"
27*5ca02815Sjsg #include "rv770.h"
287ccd5a2cSjsg #include "rv770d.h"
297ccd5a2cSjsg #include "r600_dpm.h"
307ccd5a2cSjsg #include "rv770_dpm.h"
317ccd5a2cSjsg #include "cypress_dpm.h"
327ccd5a2cSjsg #include "atom.h"
33*5ca02815Sjsg #include "evergreen.h"
347f4dd379Sjsg #include <linux/seq_file.h>
357ccd5a2cSjsg
367ccd5a2cSjsg #define MC_CG_ARB_FREQ_F0 0x0a
377ccd5a2cSjsg #define MC_CG_ARB_FREQ_F1 0x0b
387ccd5a2cSjsg #define MC_CG_ARB_FREQ_F2 0x0c
397ccd5a2cSjsg #define MC_CG_ARB_FREQ_F3 0x0d
407ccd5a2cSjsg
417ccd5a2cSjsg #define MC_CG_SEQ_DRAMCONF_S0 0x05
427ccd5a2cSjsg #define MC_CG_SEQ_DRAMCONF_S1 0x06
437ccd5a2cSjsg
447ccd5a2cSjsg #define PCIE_BUS_CLK 10000
457ccd5a2cSjsg #define TCLK (PCIE_BUS_CLK / 10)
467ccd5a2cSjsg
477ccd5a2cSjsg #define SMC_RAM_END 0xC000
487ccd5a2cSjsg
rv770_get_ps(struct radeon_ps * rps)497ccd5a2cSjsg struct rv7xx_ps *rv770_get_ps(struct radeon_ps *rps)
507ccd5a2cSjsg {
517ccd5a2cSjsg struct rv7xx_ps *ps = rps->ps_priv;
527ccd5a2cSjsg
537ccd5a2cSjsg return ps;
547ccd5a2cSjsg }
557ccd5a2cSjsg
rv770_get_pi(struct radeon_device * rdev)567ccd5a2cSjsg struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev)
577ccd5a2cSjsg {
587ccd5a2cSjsg struct rv7xx_power_info *pi = rdev->pm.dpm.priv;
597ccd5a2cSjsg
607ccd5a2cSjsg return pi;
617ccd5a2cSjsg }
627ccd5a2cSjsg
evergreen_get_pi(struct radeon_device * rdev)637ccd5a2cSjsg struct evergreen_power_info *evergreen_get_pi(struct radeon_device *rdev)
647ccd5a2cSjsg {
657ccd5a2cSjsg struct evergreen_power_info *pi = rdev->pm.dpm.priv;
667ccd5a2cSjsg
677ccd5a2cSjsg return pi;
687ccd5a2cSjsg }
697ccd5a2cSjsg
rv770_enable_bif_dynamic_pcie_gen2(struct radeon_device * rdev,bool enable)707ccd5a2cSjsg static void rv770_enable_bif_dynamic_pcie_gen2(struct radeon_device *rdev,
717ccd5a2cSjsg bool enable)
727ccd5a2cSjsg {
737ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
747ccd5a2cSjsg u32 tmp;
757ccd5a2cSjsg
767ccd5a2cSjsg tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
777ccd5a2cSjsg if (enable) {
787ccd5a2cSjsg tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK;
797ccd5a2cSjsg tmp |= LC_HW_VOLTAGE_IF_CONTROL(1);
807ccd5a2cSjsg tmp |= LC_GEN2_EN_STRAP;
817ccd5a2cSjsg } else {
827ccd5a2cSjsg if (!pi->boot_in_gen2) {
837ccd5a2cSjsg tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK;
847ccd5a2cSjsg tmp &= ~LC_GEN2_EN_STRAP;
857ccd5a2cSjsg }
867ccd5a2cSjsg }
877ccd5a2cSjsg if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) ||
887ccd5a2cSjsg (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2))
897ccd5a2cSjsg WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
907ccd5a2cSjsg
917ccd5a2cSjsg }
927ccd5a2cSjsg
rv770_enable_l0s(struct radeon_device * rdev)937ccd5a2cSjsg static void rv770_enable_l0s(struct radeon_device *rdev)
947ccd5a2cSjsg {
957ccd5a2cSjsg u32 tmp;
967ccd5a2cSjsg
977ccd5a2cSjsg tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL) & ~LC_L0S_INACTIVITY_MASK;
987ccd5a2cSjsg tmp |= LC_L0S_INACTIVITY(3);
997ccd5a2cSjsg WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp);
1007ccd5a2cSjsg }
1017ccd5a2cSjsg
rv770_enable_l1(struct radeon_device * rdev)1027ccd5a2cSjsg static void rv770_enable_l1(struct radeon_device *rdev)
1037ccd5a2cSjsg {
1047ccd5a2cSjsg u32 tmp;
1057ccd5a2cSjsg
1067ccd5a2cSjsg tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL);
1077ccd5a2cSjsg tmp &= ~LC_L1_INACTIVITY_MASK;
1087ccd5a2cSjsg tmp |= LC_L1_INACTIVITY(4);
1097ccd5a2cSjsg tmp &= ~LC_PMI_TO_L1_DIS;
1107ccd5a2cSjsg tmp &= ~LC_ASPM_TO_L1_DIS;
1117ccd5a2cSjsg WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp);
1127ccd5a2cSjsg }
1137ccd5a2cSjsg
rv770_enable_pll_sleep_in_l1(struct radeon_device * rdev)1147ccd5a2cSjsg static void rv770_enable_pll_sleep_in_l1(struct radeon_device *rdev)
1157ccd5a2cSjsg {
1167ccd5a2cSjsg u32 tmp;
1177ccd5a2cSjsg
1187ccd5a2cSjsg tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL) & ~LC_L1_INACTIVITY_MASK;
1197ccd5a2cSjsg tmp |= LC_L1_INACTIVITY(8);
1207ccd5a2cSjsg WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp);
1217ccd5a2cSjsg
1227ccd5a2cSjsg /* NOTE, this is a PCIE indirect reg, not PCIE PORT */
1237ccd5a2cSjsg tmp = RREG32_PCIE(PCIE_P_CNTL);
1247ccd5a2cSjsg tmp |= P_PLL_PWRDN_IN_L1L23;
1257ccd5a2cSjsg tmp &= ~P_PLL_BUF_PDNB;
1267ccd5a2cSjsg tmp &= ~P_PLL_PDNB;
1277ccd5a2cSjsg tmp |= P_ALLOW_PRX_FRONTEND_SHUTOFF;
1287ccd5a2cSjsg WREG32_PCIE(PCIE_P_CNTL, tmp);
1297ccd5a2cSjsg }
1307ccd5a2cSjsg
rv770_gfx_clock_gating_enable(struct radeon_device * rdev,bool enable)1317ccd5a2cSjsg static void rv770_gfx_clock_gating_enable(struct radeon_device *rdev,
1327ccd5a2cSjsg bool enable)
1337ccd5a2cSjsg {
1347ccd5a2cSjsg if (enable)
1357ccd5a2cSjsg WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN);
1367ccd5a2cSjsg else {
1377ccd5a2cSjsg WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
1387ccd5a2cSjsg WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON);
1397ccd5a2cSjsg WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON);
1407ccd5a2cSjsg RREG32(GB_TILING_CONFIG);
1417ccd5a2cSjsg }
1427ccd5a2cSjsg }
1437ccd5a2cSjsg
rv770_mg_clock_gating_enable(struct radeon_device * rdev,bool enable)1447ccd5a2cSjsg static void rv770_mg_clock_gating_enable(struct radeon_device *rdev,
1457ccd5a2cSjsg bool enable)
1467ccd5a2cSjsg {
1477ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
1487ccd5a2cSjsg
1497ccd5a2cSjsg if (enable) {
1507ccd5a2cSjsg u32 mgcg_cgtt_local0;
1517ccd5a2cSjsg
1527ccd5a2cSjsg if (rdev->family == CHIP_RV770)
1537ccd5a2cSjsg mgcg_cgtt_local0 = RV770_MGCGTTLOCAL0_DFLT;
1547ccd5a2cSjsg else
1557ccd5a2cSjsg mgcg_cgtt_local0 = RV7XX_MGCGTTLOCAL0_DFLT;
1567ccd5a2cSjsg
1577ccd5a2cSjsg WREG32(CG_CGTT_LOCAL_0, mgcg_cgtt_local0);
1587ccd5a2cSjsg WREG32(CG_CGTT_LOCAL_1, (RV770_MGCGTTLOCAL1_DFLT & 0xFFFFCFFF));
1597ccd5a2cSjsg
1607ccd5a2cSjsg if (pi->mgcgtssm)
1617ccd5a2cSjsg WREG32(CGTS_SM_CTRL_REG, RV770_MGCGCGTSSMCTRL_DFLT);
1627ccd5a2cSjsg } else {
1637ccd5a2cSjsg WREG32(CG_CGTT_LOCAL_0, 0xFFFFFFFF);
1647ccd5a2cSjsg WREG32(CG_CGTT_LOCAL_1, 0xFFFFCFFF);
1657ccd5a2cSjsg }
1667ccd5a2cSjsg }
1677ccd5a2cSjsg
rv770_restore_cgcg(struct radeon_device * rdev)1687ccd5a2cSjsg void rv770_restore_cgcg(struct radeon_device *rdev)
1697ccd5a2cSjsg {
1707ccd5a2cSjsg bool dpm_en = false, cg_en = false;
1717ccd5a2cSjsg
1727ccd5a2cSjsg if (RREG32(GENERAL_PWRMGT) & GLOBAL_PWRMGT_EN)
1737ccd5a2cSjsg dpm_en = true;
1747ccd5a2cSjsg if (RREG32(SCLK_PWRMGT_CNTL) & DYN_GFX_CLK_OFF_EN)
1757ccd5a2cSjsg cg_en = true;
1767ccd5a2cSjsg
1777ccd5a2cSjsg if (dpm_en && !cg_en)
1787ccd5a2cSjsg WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN);
1797ccd5a2cSjsg }
1807ccd5a2cSjsg
rv770_start_dpm(struct radeon_device * rdev)1817ccd5a2cSjsg static void rv770_start_dpm(struct radeon_device *rdev)
1827ccd5a2cSjsg {
1837ccd5a2cSjsg WREG32_P(SCLK_PWRMGT_CNTL, 0, ~SCLK_PWRMGT_OFF);
1847ccd5a2cSjsg
1857ccd5a2cSjsg WREG32_P(MCLK_PWRMGT_CNTL, 0, ~MPLL_PWRMGT_OFF);
1867ccd5a2cSjsg
1877ccd5a2cSjsg WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN);
1887ccd5a2cSjsg }
1897ccd5a2cSjsg
rv770_stop_dpm(struct radeon_device * rdev)1907ccd5a2cSjsg void rv770_stop_dpm(struct radeon_device *rdev)
1917ccd5a2cSjsg {
1927ccd5a2cSjsg PPSMC_Result result;
1937ccd5a2cSjsg
1947ccd5a2cSjsg result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_TwoLevelsDisabled);
1957ccd5a2cSjsg
1967ccd5a2cSjsg if (result != PPSMC_Result_OK)
1977ccd5a2cSjsg DRM_DEBUG("Could not force DPM to low.\n");
1987ccd5a2cSjsg
1997ccd5a2cSjsg WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN);
2007ccd5a2cSjsg
2017ccd5a2cSjsg WREG32_P(SCLK_PWRMGT_CNTL, SCLK_PWRMGT_OFF, ~SCLK_PWRMGT_OFF);
2027ccd5a2cSjsg
2037ccd5a2cSjsg WREG32_P(MCLK_PWRMGT_CNTL, MPLL_PWRMGT_OFF, ~MPLL_PWRMGT_OFF);
2047ccd5a2cSjsg }
2057ccd5a2cSjsg
rv770_dpm_enabled(struct radeon_device * rdev)2067ccd5a2cSjsg bool rv770_dpm_enabled(struct radeon_device *rdev)
2077ccd5a2cSjsg {
2087ccd5a2cSjsg if (RREG32(GENERAL_PWRMGT) & GLOBAL_PWRMGT_EN)
2097ccd5a2cSjsg return true;
2107ccd5a2cSjsg else
2117ccd5a2cSjsg return false;
2127ccd5a2cSjsg }
2137ccd5a2cSjsg
rv770_enable_thermal_protection(struct radeon_device * rdev,bool enable)2147ccd5a2cSjsg void rv770_enable_thermal_protection(struct radeon_device *rdev,
2157ccd5a2cSjsg bool enable)
2167ccd5a2cSjsg {
2177ccd5a2cSjsg if (enable)
2187ccd5a2cSjsg WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS);
2197ccd5a2cSjsg else
2207ccd5a2cSjsg WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS);
2217ccd5a2cSjsg }
2227ccd5a2cSjsg
rv770_enable_acpi_pm(struct radeon_device * rdev)2237ccd5a2cSjsg void rv770_enable_acpi_pm(struct radeon_device *rdev)
2247ccd5a2cSjsg {
2257ccd5a2cSjsg WREG32_P(GENERAL_PWRMGT, STATIC_PM_EN, ~STATIC_PM_EN);
2267ccd5a2cSjsg }
2277ccd5a2cSjsg
rv770_get_seq_value(struct radeon_device * rdev,struct rv7xx_pl * pl)2287ccd5a2cSjsg u8 rv770_get_seq_value(struct radeon_device *rdev,
2297ccd5a2cSjsg struct rv7xx_pl *pl)
2307ccd5a2cSjsg {
2317ccd5a2cSjsg return (pl->flags & ATOM_PPLIB_R600_FLAGS_LOWPOWER) ?
2327ccd5a2cSjsg MC_CG_SEQ_DRAMCONF_S0 : MC_CG_SEQ_DRAMCONF_S1;
2337ccd5a2cSjsg }
2347ccd5a2cSjsg
2357ccd5a2cSjsg #if 0
2367ccd5a2cSjsg int rv770_read_smc_soft_register(struct radeon_device *rdev,
2377ccd5a2cSjsg u16 reg_offset, u32 *value)
2387ccd5a2cSjsg {
2397ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
2407ccd5a2cSjsg
2417ccd5a2cSjsg return rv770_read_smc_sram_dword(rdev,
2427ccd5a2cSjsg pi->soft_regs_start + reg_offset,
2437ccd5a2cSjsg value, pi->sram_end);
2447ccd5a2cSjsg }
2457ccd5a2cSjsg #endif
2467ccd5a2cSjsg
rv770_write_smc_soft_register(struct radeon_device * rdev,u16 reg_offset,u32 value)2477ccd5a2cSjsg int rv770_write_smc_soft_register(struct radeon_device *rdev,
2487ccd5a2cSjsg u16 reg_offset, u32 value)
2497ccd5a2cSjsg {
2507ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
2517ccd5a2cSjsg
2527ccd5a2cSjsg return rv770_write_smc_sram_dword(rdev,
2537ccd5a2cSjsg pi->soft_regs_start + reg_offset,
2547ccd5a2cSjsg value, pi->sram_end);
2557ccd5a2cSjsg }
2567ccd5a2cSjsg
rv770_populate_smc_t(struct radeon_device * rdev,struct radeon_ps * radeon_state,RV770_SMC_SWSTATE * smc_state)2577ccd5a2cSjsg int rv770_populate_smc_t(struct radeon_device *rdev,
2587ccd5a2cSjsg struct radeon_ps *radeon_state,
2597ccd5a2cSjsg RV770_SMC_SWSTATE *smc_state)
2607ccd5a2cSjsg {
2617ccd5a2cSjsg struct rv7xx_ps *state = rv770_get_ps(radeon_state);
2627ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
2637ccd5a2cSjsg int i;
2647ccd5a2cSjsg int a_n;
2657ccd5a2cSjsg int a_d;
2667ccd5a2cSjsg u8 l[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE];
2677ccd5a2cSjsg u8 r[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE];
2687ccd5a2cSjsg u32 a_t;
2697ccd5a2cSjsg
2707ccd5a2cSjsg l[0] = 0;
2717ccd5a2cSjsg r[2] = 100;
2727ccd5a2cSjsg
2737ccd5a2cSjsg a_n = (int)state->medium.sclk * pi->lmp +
2747ccd5a2cSjsg (int)state->low.sclk * (R600_AH_DFLT - pi->rlp);
2757ccd5a2cSjsg a_d = (int)state->low.sclk * (100 - (int)pi->rlp) +
2767ccd5a2cSjsg (int)state->medium.sclk * pi->lmp;
2777ccd5a2cSjsg
2787ccd5a2cSjsg l[1] = (u8)(pi->lmp - (int)pi->lmp * a_n / a_d);
2797ccd5a2cSjsg r[0] = (u8)(pi->rlp + (100 - (int)pi->rlp) * a_n / a_d);
2807ccd5a2cSjsg
2817ccd5a2cSjsg a_n = (int)state->high.sclk * pi->lhp + (int)state->medium.sclk *
2827ccd5a2cSjsg (R600_AH_DFLT - pi->rmp);
2837ccd5a2cSjsg a_d = (int)state->medium.sclk * (100 - (int)pi->rmp) +
2847ccd5a2cSjsg (int)state->high.sclk * pi->lhp;
2857ccd5a2cSjsg
2867ccd5a2cSjsg l[2] = (u8)(pi->lhp - (int)pi->lhp * a_n / a_d);
2877ccd5a2cSjsg r[1] = (u8)(pi->rmp + (100 - (int)pi->rmp) * a_n / a_d);
2887ccd5a2cSjsg
2897ccd5a2cSjsg for (i = 0; i < (RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1); i++) {
2907ccd5a2cSjsg a_t = CG_R(r[i] * pi->bsp / 200) | CG_L(l[i] * pi->bsp / 200);
2917ccd5a2cSjsg smc_state->levels[i].aT = cpu_to_be32(a_t);
2927ccd5a2cSjsg }
2937ccd5a2cSjsg
2947ccd5a2cSjsg a_t = CG_R(r[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1] * pi->pbsp / 200) |
2957ccd5a2cSjsg CG_L(l[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1] * pi->pbsp / 200);
2967ccd5a2cSjsg
2977ccd5a2cSjsg smc_state->levels[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1].aT =
2987ccd5a2cSjsg cpu_to_be32(a_t);
2997ccd5a2cSjsg
3007ccd5a2cSjsg return 0;
3017ccd5a2cSjsg }
3027ccd5a2cSjsg
rv770_populate_smc_sp(struct radeon_device * rdev,struct radeon_ps * radeon_state,RV770_SMC_SWSTATE * smc_state)3037ccd5a2cSjsg int rv770_populate_smc_sp(struct radeon_device *rdev,
3047ccd5a2cSjsg struct radeon_ps *radeon_state,
3057ccd5a2cSjsg RV770_SMC_SWSTATE *smc_state)
3067ccd5a2cSjsg {
3077ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
3087ccd5a2cSjsg int i;
3097ccd5a2cSjsg
3107ccd5a2cSjsg for (i = 0; i < (RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1); i++)
3117ccd5a2cSjsg smc_state->levels[i].bSP = cpu_to_be32(pi->dsp);
3127ccd5a2cSjsg
3137ccd5a2cSjsg smc_state->levels[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1].bSP =
3147ccd5a2cSjsg cpu_to_be32(pi->psp);
3157ccd5a2cSjsg
3167ccd5a2cSjsg return 0;
3177ccd5a2cSjsg }
3187ccd5a2cSjsg
rv770_calculate_fractional_mpll_feedback_divider(u32 memory_clock,u32 reference_clock,bool gddr5,struct atom_clock_dividers * dividers,u32 * clkf,u32 * clkfrac)3197ccd5a2cSjsg static void rv770_calculate_fractional_mpll_feedback_divider(u32 memory_clock,
3207ccd5a2cSjsg u32 reference_clock,
3217ccd5a2cSjsg bool gddr5,
3227ccd5a2cSjsg struct atom_clock_dividers *dividers,
3237ccd5a2cSjsg u32 *clkf,
3247ccd5a2cSjsg u32 *clkfrac)
3257ccd5a2cSjsg {
3267ccd5a2cSjsg u32 post_divider, reference_divider, feedback_divider8;
3277ccd5a2cSjsg u32 fyclk;
3287ccd5a2cSjsg
3297ccd5a2cSjsg if (gddr5)
3307ccd5a2cSjsg fyclk = (memory_clock * 8) / 2;
3317ccd5a2cSjsg else
3327ccd5a2cSjsg fyclk = (memory_clock * 4) / 2;
3337ccd5a2cSjsg
3347ccd5a2cSjsg post_divider = dividers->post_div;
3357ccd5a2cSjsg reference_divider = dividers->ref_div;
3367ccd5a2cSjsg
3377ccd5a2cSjsg feedback_divider8 =
3387ccd5a2cSjsg (8 * fyclk * reference_divider * post_divider) / reference_clock;
3397ccd5a2cSjsg
3407ccd5a2cSjsg *clkf = feedback_divider8 / 8;
3417ccd5a2cSjsg *clkfrac = feedback_divider8 % 8;
3427ccd5a2cSjsg }
3437ccd5a2cSjsg
rv770_encode_yclk_post_div(u32 postdiv,u32 * encoded_postdiv)3447ccd5a2cSjsg static int rv770_encode_yclk_post_div(u32 postdiv, u32 *encoded_postdiv)
3457ccd5a2cSjsg {
3467ccd5a2cSjsg int ret = 0;
3477ccd5a2cSjsg
3487ccd5a2cSjsg switch (postdiv) {
3497ccd5a2cSjsg case 1:
3507ccd5a2cSjsg *encoded_postdiv = 0;
3517ccd5a2cSjsg break;
3527ccd5a2cSjsg case 2:
3537ccd5a2cSjsg *encoded_postdiv = 1;
3547ccd5a2cSjsg break;
3557ccd5a2cSjsg case 4:
3567ccd5a2cSjsg *encoded_postdiv = 2;
3577ccd5a2cSjsg break;
3587ccd5a2cSjsg case 8:
3597ccd5a2cSjsg *encoded_postdiv = 3;
3607ccd5a2cSjsg break;
3617ccd5a2cSjsg case 16:
3627ccd5a2cSjsg *encoded_postdiv = 4;
3637ccd5a2cSjsg break;
3647ccd5a2cSjsg default:
3657ccd5a2cSjsg ret = -EINVAL;
3667ccd5a2cSjsg break;
3677ccd5a2cSjsg }
3687ccd5a2cSjsg
3697ccd5a2cSjsg return ret;
3707ccd5a2cSjsg }
3717ccd5a2cSjsg
rv770_map_clkf_to_ibias(struct radeon_device * rdev,u32 clkf)3727ccd5a2cSjsg u32 rv770_map_clkf_to_ibias(struct radeon_device *rdev, u32 clkf)
3737ccd5a2cSjsg {
3747ccd5a2cSjsg if (clkf <= 0x10)
3757ccd5a2cSjsg return 0x4B;
3767ccd5a2cSjsg if (clkf <= 0x19)
3777ccd5a2cSjsg return 0x5B;
3787ccd5a2cSjsg if (clkf <= 0x21)
3797ccd5a2cSjsg return 0x2B;
3807ccd5a2cSjsg if (clkf <= 0x27)
3817ccd5a2cSjsg return 0x6C;
3827ccd5a2cSjsg if (clkf <= 0x31)
3837ccd5a2cSjsg return 0x9D;
3847ccd5a2cSjsg return 0xC6;
3857ccd5a2cSjsg }
3867ccd5a2cSjsg
rv770_populate_mclk_value(struct radeon_device * rdev,u32 engine_clock,u32 memory_clock,RV7XX_SMC_MCLK_VALUE * mclk)3877ccd5a2cSjsg static int rv770_populate_mclk_value(struct radeon_device *rdev,
3887ccd5a2cSjsg u32 engine_clock, u32 memory_clock,
3897ccd5a2cSjsg RV7XX_SMC_MCLK_VALUE *mclk)
3907ccd5a2cSjsg {
3917ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
3927ccd5a2cSjsg u8 encoded_reference_dividers[] = { 0, 16, 17, 20, 21 };
3937ccd5a2cSjsg u32 mpll_ad_func_cntl =
3947ccd5a2cSjsg pi->clk_regs.rv770.mpll_ad_func_cntl;
3957ccd5a2cSjsg u32 mpll_ad_func_cntl_2 =
3967ccd5a2cSjsg pi->clk_regs.rv770.mpll_ad_func_cntl_2;
3977ccd5a2cSjsg u32 mpll_dq_func_cntl =
3987ccd5a2cSjsg pi->clk_regs.rv770.mpll_dq_func_cntl;
3997ccd5a2cSjsg u32 mpll_dq_func_cntl_2 =
4007ccd5a2cSjsg pi->clk_regs.rv770.mpll_dq_func_cntl_2;
4017ccd5a2cSjsg u32 mclk_pwrmgt_cntl =
4027ccd5a2cSjsg pi->clk_regs.rv770.mclk_pwrmgt_cntl;
4037ccd5a2cSjsg u32 dll_cntl = pi->clk_regs.rv770.dll_cntl;
4047ccd5a2cSjsg struct atom_clock_dividers dividers;
4057ccd5a2cSjsg u32 reference_clock = rdev->clock.mpll.reference_freq;
4067ccd5a2cSjsg u32 clkf, clkfrac;
4077ccd5a2cSjsg u32 postdiv_yclk;
4087ccd5a2cSjsg u32 ibias;
4097ccd5a2cSjsg int ret;
4107ccd5a2cSjsg
4117ccd5a2cSjsg ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM,
4127ccd5a2cSjsg memory_clock, false, ÷rs);
4137ccd5a2cSjsg if (ret)
4147ccd5a2cSjsg return ret;
4157ccd5a2cSjsg
4167ccd5a2cSjsg if ((dividers.ref_div < 1) || (dividers.ref_div > 5))
4177ccd5a2cSjsg return -EINVAL;
4187ccd5a2cSjsg
4197ccd5a2cSjsg rv770_calculate_fractional_mpll_feedback_divider(memory_clock, reference_clock,
4207ccd5a2cSjsg pi->mem_gddr5,
4217ccd5a2cSjsg ÷rs, &clkf, &clkfrac);
4227ccd5a2cSjsg
4237ccd5a2cSjsg ret = rv770_encode_yclk_post_div(dividers.post_div, &postdiv_yclk);
4247ccd5a2cSjsg if (ret)
4257ccd5a2cSjsg return ret;
4267ccd5a2cSjsg
4277ccd5a2cSjsg ibias = rv770_map_clkf_to_ibias(rdev, clkf);
4287ccd5a2cSjsg
4297ccd5a2cSjsg mpll_ad_func_cntl &= ~(CLKR_MASK |
4307ccd5a2cSjsg YCLK_POST_DIV_MASK |
4317ccd5a2cSjsg CLKF_MASK |
4327ccd5a2cSjsg CLKFRAC_MASK |
4337ccd5a2cSjsg IBIAS_MASK);
4347ccd5a2cSjsg mpll_ad_func_cntl |= CLKR(encoded_reference_dividers[dividers.ref_div - 1]);
4357ccd5a2cSjsg mpll_ad_func_cntl |= YCLK_POST_DIV(postdiv_yclk);
4367ccd5a2cSjsg mpll_ad_func_cntl |= CLKF(clkf);
4377ccd5a2cSjsg mpll_ad_func_cntl |= CLKFRAC(clkfrac);
4387ccd5a2cSjsg mpll_ad_func_cntl |= IBIAS(ibias);
4397ccd5a2cSjsg
4407ccd5a2cSjsg if (dividers.vco_mode)
4417ccd5a2cSjsg mpll_ad_func_cntl_2 |= VCO_MODE;
4427ccd5a2cSjsg else
4437ccd5a2cSjsg mpll_ad_func_cntl_2 &= ~VCO_MODE;
4447ccd5a2cSjsg
4457ccd5a2cSjsg if (pi->mem_gddr5) {
4467ccd5a2cSjsg rv770_calculate_fractional_mpll_feedback_divider(memory_clock,
4477ccd5a2cSjsg reference_clock,
4487ccd5a2cSjsg pi->mem_gddr5,
4497ccd5a2cSjsg ÷rs, &clkf, &clkfrac);
4507ccd5a2cSjsg
4517ccd5a2cSjsg ibias = rv770_map_clkf_to_ibias(rdev, clkf);
4527ccd5a2cSjsg
4537ccd5a2cSjsg ret = rv770_encode_yclk_post_div(dividers.post_div, &postdiv_yclk);
4547ccd5a2cSjsg if (ret)
4557ccd5a2cSjsg return ret;
4567ccd5a2cSjsg
4577ccd5a2cSjsg mpll_dq_func_cntl &= ~(CLKR_MASK |
4587ccd5a2cSjsg YCLK_POST_DIV_MASK |
4597ccd5a2cSjsg CLKF_MASK |
4607ccd5a2cSjsg CLKFRAC_MASK |
4617ccd5a2cSjsg IBIAS_MASK);
4627ccd5a2cSjsg mpll_dq_func_cntl |= CLKR(encoded_reference_dividers[dividers.ref_div - 1]);
4637ccd5a2cSjsg mpll_dq_func_cntl |= YCLK_POST_DIV(postdiv_yclk);
4647ccd5a2cSjsg mpll_dq_func_cntl |= CLKF(clkf);
4657ccd5a2cSjsg mpll_dq_func_cntl |= CLKFRAC(clkfrac);
4667ccd5a2cSjsg mpll_dq_func_cntl |= IBIAS(ibias);
4677ccd5a2cSjsg
4687ccd5a2cSjsg if (dividers.vco_mode)
4697ccd5a2cSjsg mpll_dq_func_cntl_2 |= VCO_MODE;
4707ccd5a2cSjsg else
4717ccd5a2cSjsg mpll_dq_func_cntl_2 &= ~VCO_MODE;
4727ccd5a2cSjsg }
4737ccd5a2cSjsg
4747ccd5a2cSjsg mclk->mclk770.mclk_value = cpu_to_be32(memory_clock);
4757ccd5a2cSjsg mclk->mclk770.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
4767ccd5a2cSjsg mclk->mclk770.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2);
4777ccd5a2cSjsg mclk->mclk770.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
4787ccd5a2cSjsg mclk->mclk770.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2);
4797ccd5a2cSjsg mclk->mclk770.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
4807ccd5a2cSjsg mclk->mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl);
4817ccd5a2cSjsg
4827ccd5a2cSjsg return 0;
4837ccd5a2cSjsg }
4847ccd5a2cSjsg
rv770_populate_sclk_value(struct radeon_device * rdev,u32 engine_clock,RV770_SMC_SCLK_VALUE * sclk)4857ccd5a2cSjsg static int rv770_populate_sclk_value(struct radeon_device *rdev,
4867ccd5a2cSjsg u32 engine_clock,
4877ccd5a2cSjsg RV770_SMC_SCLK_VALUE *sclk)
4887ccd5a2cSjsg {
4897ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
4907ccd5a2cSjsg struct atom_clock_dividers dividers;
4917ccd5a2cSjsg u32 spll_func_cntl =
4927ccd5a2cSjsg pi->clk_regs.rv770.cg_spll_func_cntl;
4937ccd5a2cSjsg u32 spll_func_cntl_2 =
4947ccd5a2cSjsg pi->clk_regs.rv770.cg_spll_func_cntl_2;
4957ccd5a2cSjsg u32 spll_func_cntl_3 =
4967ccd5a2cSjsg pi->clk_regs.rv770.cg_spll_func_cntl_3;
4977ccd5a2cSjsg u32 cg_spll_spread_spectrum =
4987ccd5a2cSjsg pi->clk_regs.rv770.cg_spll_spread_spectrum;
4997ccd5a2cSjsg u32 cg_spll_spread_spectrum_2 =
5007ccd5a2cSjsg pi->clk_regs.rv770.cg_spll_spread_spectrum_2;
5017ccd5a2cSjsg u64 tmp;
5027ccd5a2cSjsg u32 reference_clock = rdev->clock.spll.reference_freq;
5037ccd5a2cSjsg u32 reference_divider, post_divider;
5047ccd5a2cSjsg u32 fbdiv;
5057ccd5a2cSjsg int ret;
5067ccd5a2cSjsg
5077ccd5a2cSjsg ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
5087ccd5a2cSjsg engine_clock, false, ÷rs);
5097ccd5a2cSjsg if (ret)
5107ccd5a2cSjsg return ret;
5117ccd5a2cSjsg
5127ccd5a2cSjsg reference_divider = 1 + dividers.ref_div;
5137ccd5a2cSjsg
5147ccd5a2cSjsg if (dividers.enable_post_div)
5157ccd5a2cSjsg post_divider = (0x0f & (dividers.post_div >> 4)) + (0x0f & dividers.post_div) + 2;
5167ccd5a2cSjsg else
5177ccd5a2cSjsg post_divider = 1;
5187ccd5a2cSjsg
5197ccd5a2cSjsg tmp = (u64) engine_clock * reference_divider * post_divider * 16384;
5207ccd5a2cSjsg do_div(tmp, reference_clock);
5217ccd5a2cSjsg fbdiv = (u32) tmp;
5227ccd5a2cSjsg
5237ccd5a2cSjsg if (dividers.enable_post_div)
5247ccd5a2cSjsg spll_func_cntl |= SPLL_DIVEN;
5257ccd5a2cSjsg else
5267ccd5a2cSjsg spll_func_cntl &= ~SPLL_DIVEN;
5277ccd5a2cSjsg spll_func_cntl &= ~(SPLL_HILEN_MASK | SPLL_LOLEN_MASK | SPLL_REF_DIV_MASK);
5287ccd5a2cSjsg spll_func_cntl |= SPLL_REF_DIV(dividers.ref_div);
5297ccd5a2cSjsg spll_func_cntl |= SPLL_HILEN((dividers.post_div >> 4) & 0xf);
5307ccd5a2cSjsg spll_func_cntl |= SPLL_LOLEN(dividers.post_div & 0xf);
5317ccd5a2cSjsg
5327ccd5a2cSjsg spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
5337ccd5a2cSjsg spll_func_cntl_2 |= SCLK_MUX_SEL(2);
5347ccd5a2cSjsg
5357ccd5a2cSjsg spll_func_cntl_3 &= ~SPLL_FB_DIV_MASK;
5367ccd5a2cSjsg spll_func_cntl_3 |= SPLL_FB_DIV(fbdiv);
5377ccd5a2cSjsg spll_func_cntl_3 |= SPLL_DITHEN;
5387ccd5a2cSjsg
5397ccd5a2cSjsg if (pi->sclk_ss) {
5407ccd5a2cSjsg struct radeon_atom_ss ss;
5417ccd5a2cSjsg u32 vco_freq = engine_clock * post_divider;
5427ccd5a2cSjsg
5437ccd5a2cSjsg if (radeon_atombios_get_asic_ss_info(rdev, &ss,
5447ccd5a2cSjsg ASIC_INTERNAL_ENGINE_SS, vco_freq)) {
5457ccd5a2cSjsg u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate);
5467ccd5a2cSjsg u32 clk_v = ss.percentage * fbdiv / (clk_s * 10000);
5477ccd5a2cSjsg
5487ccd5a2cSjsg cg_spll_spread_spectrum &= ~CLKS_MASK;
5497ccd5a2cSjsg cg_spll_spread_spectrum |= CLKS(clk_s);
5507ccd5a2cSjsg cg_spll_spread_spectrum |= SSEN;
5517ccd5a2cSjsg
5527ccd5a2cSjsg cg_spll_spread_spectrum_2 &= ~CLKV_MASK;
5537ccd5a2cSjsg cg_spll_spread_spectrum_2 |= CLKV(clk_v);
5547ccd5a2cSjsg }
5557ccd5a2cSjsg }
5567ccd5a2cSjsg
5577ccd5a2cSjsg sclk->sclk_value = cpu_to_be32(engine_clock);
5587ccd5a2cSjsg sclk->vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl);
5597ccd5a2cSjsg sclk->vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2);
5607ccd5a2cSjsg sclk->vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3);
5617ccd5a2cSjsg sclk->vCG_SPLL_SPREAD_SPECTRUM = cpu_to_be32(cg_spll_spread_spectrum);
5627ccd5a2cSjsg sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cpu_to_be32(cg_spll_spread_spectrum_2);
5637ccd5a2cSjsg
5647ccd5a2cSjsg return 0;
5657ccd5a2cSjsg }
5667ccd5a2cSjsg
rv770_populate_vddc_value(struct radeon_device * rdev,u16 vddc,RV770_SMC_VOLTAGE_VALUE * voltage)5677ccd5a2cSjsg int rv770_populate_vddc_value(struct radeon_device *rdev, u16 vddc,
5687ccd5a2cSjsg RV770_SMC_VOLTAGE_VALUE *voltage)
5697ccd5a2cSjsg {
5707ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
5717ccd5a2cSjsg int i;
5727ccd5a2cSjsg
5737ccd5a2cSjsg if (!pi->voltage_control) {
5747ccd5a2cSjsg voltage->index = 0;
5757ccd5a2cSjsg voltage->value = 0;
5767ccd5a2cSjsg return 0;
5777ccd5a2cSjsg }
5787ccd5a2cSjsg
5797ccd5a2cSjsg for (i = 0; i < pi->valid_vddc_entries; i++) {
5807ccd5a2cSjsg if (vddc <= pi->vddc_table[i].vddc) {
5817ccd5a2cSjsg voltage->index = pi->vddc_table[i].vddc_index;
5827ccd5a2cSjsg voltage->value = cpu_to_be16(vddc);
5837ccd5a2cSjsg break;
5847ccd5a2cSjsg }
5857ccd5a2cSjsg }
5867ccd5a2cSjsg
5877ccd5a2cSjsg if (i == pi->valid_vddc_entries)
5887ccd5a2cSjsg return -EINVAL;
5897ccd5a2cSjsg
5907ccd5a2cSjsg return 0;
5917ccd5a2cSjsg }
5927ccd5a2cSjsg
rv770_populate_mvdd_value(struct radeon_device * rdev,u32 mclk,RV770_SMC_VOLTAGE_VALUE * voltage)5937ccd5a2cSjsg int rv770_populate_mvdd_value(struct radeon_device *rdev, u32 mclk,
5947ccd5a2cSjsg RV770_SMC_VOLTAGE_VALUE *voltage)
5957ccd5a2cSjsg {
5967ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
5977ccd5a2cSjsg
5987ccd5a2cSjsg if (!pi->mvdd_control) {
5997ccd5a2cSjsg voltage->index = MVDD_HIGH_INDEX;
6007ccd5a2cSjsg voltage->value = cpu_to_be16(MVDD_HIGH_VALUE);
6017ccd5a2cSjsg return 0;
6027ccd5a2cSjsg }
6037ccd5a2cSjsg
6047ccd5a2cSjsg if (mclk <= pi->mvdd_split_frequency) {
6057ccd5a2cSjsg voltage->index = MVDD_LOW_INDEX;
6067ccd5a2cSjsg voltage->value = cpu_to_be16(MVDD_LOW_VALUE);
6077ccd5a2cSjsg } else {
6087ccd5a2cSjsg voltage->index = MVDD_HIGH_INDEX;
6097ccd5a2cSjsg voltage->value = cpu_to_be16(MVDD_HIGH_VALUE);
6107ccd5a2cSjsg }
6117ccd5a2cSjsg
6127ccd5a2cSjsg return 0;
6137ccd5a2cSjsg }
6147ccd5a2cSjsg
rv770_convert_power_level_to_smc(struct radeon_device * rdev,struct rv7xx_pl * pl,RV770_SMC_HW_PERFORMANCE_LEVEL * level,u8 watermark_level)6157ccd5a2cSjsg static int rv770_convert_power_level_to_smc(struct radeon_device *rdev,
6167ccd5a2cSjsg struct rv7xx_pl *pl,
6177ccd5a2cSjsg RV770_SMC_HW_PERFORMANCE_LEVEL *level,
6187ccd5a2cSjsg u8 watermark_level)
6197ccd5a2cSjsg {
6207ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
6217ccd5a2cSjsg int ret;
6227ccd5a2cSjsg
6237ccd5a2cSjsg level->gen2PCIE = pi->pcie_gen2 ?
6247ccd5a2cSjsg ((pl->flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? 1 : 0) : 0;
6257ccd5a2cSjsg level->gen2XSP = (pl->flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? 1 : 0;
6267ccd5a2cSjsg level->backbias = (pl->flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? 1 : 0;
6277ccd5a2cSjsg level->displayWatermark = watermark_level;
6287ccd5a2cSjsg
6297ccd5a2cSjsg if (rdev->family == CHIP_RV740)
6307ccd5a2cSjsg ret = rv740_populate_sclk_value(rdev, pl->sclk,
6317ccd5a2cSjsg &level->sclk);
6327ccd5a2cSjsg else if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
6337ccd5a2cSjsg ret = rv730_populate_sclk_value(rdev, pl->sclk,
6347ccd5a2cSjsg &level->sclk);
6357ccd5a2cSjsg else
6367ccd5a2cSjsg ret = rv770_populate_sclk_value(rdev, pl->sclk,
6377ccd5a2cSjsg &level->sclk);
6387ccd5a2cSjsg if (ret)
6397ccd5a2cSjsg return ret;
6407ccd5a2cSjsg
6417ccd5a2cSjsg if (rdev->family == CHIP_RV740) {
6427ccd5a2cSjsg if (pi->mem_gddr5) {
6437ccd5a2cSjsg if (pl->mclk <= pi->mclk_strobe_mode_threshold)
6447ccd5a2cSjsg level->strobeMode =
6457ccd5a2cSjsg rv740_get_mclk_frequency_ratio(pl->mclk) | 0x10;
6467ccd5a2cSjsg else
6477ccd5a2cSjsg level->strobeMode = 0;
6487ccd5a2cSjsg
6497ccd5a2cSjsg if (pl->mclk > pi->mclk_edc_enable_threshold)
6507ccd5a2cSjsg level->mcFlags = SMC_MC_EDC_RD_FLAG | SMC_MC_EDC_WR_FLAG;
6517ccd5a2cSjsg else
6527ccd5a2cSjsg level->mcFlags = 0;
6537ccd5a2cSjsg }
6547ccd5a2cSjsg ret = rv740_populate_mclk_value(rdev, pl->sclk,
6557ccd5a2cSjsg pl->mclk, &level->mclk);
6567ccd5a2cSjsg } else if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
6577ccd5a2cSjsg ret = rv730_populate_mclk_value(rdev, pl->sclk,
6587ccd5a2cSjsg pl->mclk, &level->mclk);
6597ccd5a2cSjsg else
6607ccd5a2cSjsg ret = rv770_populate_mclk_value(rdev, pl->sclk,
6617ccd5a2cSjsg pl->mclk, &level->mclk);
6627ccd5a2cSjsg if (ret)
6637ccd5a2cSjsg return ret;
6647ccd5a2cSjsg
6657ccd5a2cSjsg ret = rv770_populate_vddc_value(rdev, pl->vddc,
6667ccd5a2cSjsg &level->vddc);
6677ccd5a2cSjsg if (ret)
6687ccd5a2cSjsg return ret;
6697ccd5a2cSjsg
6707ccd5a2cSjsg ret = rv770_populate_mvdd_value(rdev, pl->mclk, &level->mvdd);
6717ccd5a2cSjsg
6727ccd5a2cSjsg return ret;
6737ccd5a2cSjsg }
6747ccd5a2cSjsg
rv770_convert_power_state_to_smc(struct radeon_device * rdev,struct radeon_ps * radeon_state,RV770_SMC_SWSTATE * smc_state)6757ccd5a2cSjsg static int rv770_convert_power_state_to_smc(struct radeon_device *rdev,
6767ccd5a2cSjsg struct radeon_ps *radeon_state,
6777ccd5a2cSjsg RV770_SMC_SWSTATE *smc_state)
6787ccd5a2cSjsg {
6797ccd5a2cSjsg struct rv7xx_ps *state = rv770_get_ps(radeon_state);
6807ccd5a2cSjsg int ret;
6817ccd5a2cSjsg
6827ccd5a2cSjsg if (!(radeon_state->caps & ATOM_PPLIB_DISALLOW_ON_DC))
6837ccd5a2cSjsg smc_state->flags |= PPSMC_SWSTATE_FLAG_DC;
6847ccd5a2cSjsg
6857ccd5a2cSjsg ret = rv770_convert_power_level_to_smc(rdev,
6867ccd5a2cSjsg &state->low,
6877ccd5a2cSjsg &smc_state->levels[0],
6887ccd5a2cSjsg PPSMC_DISPLAY_WATERMARK_LOW);
6897ccd5a2cSjsg if (ret)
6907ccd5a2cSjsg return ret;
6917ccd5a2cSjsg
6927ccd5a2cSjsg ret = rv770_convert_power_level_to_smc(rdev,
6937ccd5a2cSjsg &state->medium,
6947ccd5a2cSjsg &smc_state->levels[1],
6957ccd5a2cSjsg PPSMC_DISPLAY_WATERMARK_LOW);
6967ccd5a2cSjsg if (ret)
6977ccd5a2cSjsg return ret;
6987ccd5a2cSjsg
6997ccd5a2cSjsg ret = rv770_convert_power_level_to_smc(rdev,
7007ccd5a2cSjsg &state->high,
7017ccd5a2cSjsg &smc_state->levels[2],
7027ccd5a2cSjsg PPSMC_DISPLAY_WATERMARK_HIGH);
7037ccd5a2cSjsg if (ret)
7047ccd5a2cSjsg return ret;
7057ccd5a2cSjsg
7067ccd5a2cSjsg smc_state->levels[0].arbValue = MC_CG_ARB_FREQ_F1;
7077ccd5a2cSjsg smc_state->levels[1].arbValue = MC_CG_ARB_FREQ_F2;
7087ccd5a2cSjsg smc_state->levels[2].arbValue = MC_CG_ARB_FREQ_F3;
7097ccd5a2cSjsg
7107ccd5a2cSjsg smc_state->levels[0].seqValue = rv770_get_seq_value(rdev,
7117ccd5a2cSjsg &state->low);
7127ccd5a2cSjsg smc_state->levels[1].seqValue = rv770_get_seq_value(rdev,
7137ccd5a2cSjsg &state->medium);
7147ccd5a2cSjsg smc_state->levels[2].seqValue = rv770_get_seq_value(rdev,
7157ccd5a2cSjsg &state->high);
7167ccd5a2cSjsg
7177ccd5a2cSjsg rv770_populate_smc_sp(rdev, radeon_state, smc_state);
7187ccd5a2cSjsg
7197ccd5a2cSjsg return rv770_populate_smc_t(rdev, radeon_state, smc_state);
7207ccd5a2cSjsg
7217ccd5a2cSjsg }
7227ccd5a2cSjsg
rv770_calculate_memory_refresh_rate(struct radeon_device * rdev,u32 engine_clock)7237ccd5a2cSjsg u32 rv770_calculate_memory_refresh_rate(struct radeon_device *rdev,
7247ccd5a2cSjsg u32 engine_clock)
7257ccd5a2cSjsg {
7267ccd5a2cSjsg u32 dram_rows;
7277ccd5a2cSjsg u32 dram_refresh_rate;
7287ccd5a2cSjsg u32 mc_arb_rfsh_rate;
7297ccd5a2cSjsg u32 tmp;
7307ccd5a2cSjsg
7317ccd5a2cSjsg tmp = (RREG32(MC_ARB_RAMCFG) & NOOFROWS_MASK) >> NOOFROWS_SHIFT;
7327ccd5a2cSjsg dram_rows = 1 << (tmp + 10);
7337ccd5a2cSjsg tmp = RREG32(MC_SEQ_MISC0) & 3;
7347ccd5a2cSjsg dram_refresh_rate = 1 << (tmp + 3);
7357ccd5a2cSjsg mc_arb_rfsh_rate = ((engine_clock * 10) * dram_refresh_rate / dram_rows - 32) / 64;
7367ccd5a2cSjsg
7377ccd5a2cSjsg return mc_arb_rfsh_rate;
7387ccd5a2cSjsg }
7397ccd5a2cSjsg
rv770_program_memory_timing_parameters(struct radeon_device * rdev,struct radeon_ps * radeon_state)7407ccd5a2cSjsg static void rv770_program_memory_timing_parameters(struct radeon_device *rdev,
7417ccd5a2cSjsg struct radeon_ps *radeon_state)
7427ccd5a2cSjsg {
7437ccd5a2cSjsg struct rv7xx_ps *state = rv770_get_ps(radeon_state);
7447ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
7457ccd5a2cSjsg u32 sqm_ratio;
7467ccd5a2cSjsg u32 arb_refresh_rate;
7477ccd5a2cSjsg u32 high_clock;
7487ccd5a2cSjsg
7497ccd5a2cSjsg if (state->high.sclk < (state->low.sclk * 0xFF / 0x40))
7507ccd5a2cSjsg high_clock = state->high.sclk;
7517ccd5a2cSjsg else
7527ccd5a2cSjsg high_clock = (state->low.sclk * 0xFF / 0x40);
7537ccd5a2cSjsg
7547ccd5a2cSjsg radeon_atom_set_engine_dram_timings(rdev, high_clock,
7557ccd5a2cSjsg state->high.mclk);
7567ccd5a2cSjsg
7577ccd5a2cSjsg sqm_ratio =
7587ccd5a2cSjsg STATE0(64 * high_clock / pi->boot_sclk) |
7597ccd5a2cSjsg STATE1(64 * high_clock / state->low.sclk) |
7607ccd5a2cSjsg STATE2(64 * high_clock / state->medium.sclk) |
7617ccd5a2cSjsg STATE3(64 * high_clock / state->high.sclk);
7627ccd5a2cSjsg WREG32(MC_ARB_SQM_RATIO, sqm_ratio);
7637ccd5a2cSjsg
7647ccd5a2cSjsg arb_refresh_rate =
7657ccd5a2cSjsg POWERMODE0(rv770_calculate_memory_refresh_rate(rdev, pi->boot_sclk)) |
7667ccd5a2cSjsg POWERMODE1(rv770_calculate_memory_refresh_rate(rdev, state->low.sclk)) |
7677ccd5a2cSjsg POWERMODE2(rv770_calculate_memory_refresh_rate(rdev, state->medium.sclk)) |
7687ccd5a2cSjsg POWERMODE3(rv770_calculate_memory_refresh_rate(rdev, state->high.sclk));
7697ccd5a2cSjsg WREG32(MC_ARB_RFSH_RATE, arb_refresh_rate);
7707ccd5a2cSjsg }
7717ccd5a2cSjsg
rv770_enable_backbias(struct radeon_device * rdev,bool enable)7727ccd5a2cSjsg void rv770_enable_backbias(struct radeon_device *rdev,
7737ccd5a2cSjsg bool enable)
7747ccd5a2cSjsg {
7757ccd5a2cSjsg if (enable)
7767ccd5a2cSjsg WREG32_P(GENERAL_PWRMGT, BACKBIAS_PAD_EN, ~BACKBIAS_PAD_EN);
7777ccd5a2cSjsg else
7787ccd5a2cSjsg WREG32_P(GENERAL_PWRMGT, 0, ~(BACKBIAS_VALUE | BACKBIAS_PAD_EN));
7797ccd5a2cSjsg }
7807ccd5a2cSjsg
rv770_enable_spread_spectrum(struct radeon_device * rdev,bool enable)7817ccd5a2cSjsg static void rv770_enable_spread_spectrum(struct radeon_device *rdev,
7827ccd5a2cSjsg bool enable)
7837ccd5a2cSjsg {
7847ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
7857ccd5a2cSjsg
7867ccd5a2cSjsg if (enable) {
7877ccd5a2cSjsg if (pi->sclk_ss)
7887ccd5a2cSjsg WREG32_P(GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, ~DYN_SPREAD_SPECTRUM_EN);
7897ccd5a2cSjsg
7907ccd5a2cSjsg if (pi->mclk_ss) {
7917ccd5a2cSjsg if (rdev->family == CHIP_RV740)
7927ccd5a2cSjsg rv740_enable_mclk_spread_spectrum(rdev, true);
7937ccd5a2cSjsg }
7947ccd5a2cSjsg } else {
7957ccd5a2cSjsg WREG32_P(CG_SPLL_SPREAD_SPECTRUM, 0, ~SSEN);
7967ccd5a2cSjsg
7977ccd5a2cSjsg WREG32_P(GENERAL_PWRMGT, 0, ~DYN_SPREAD_SPECTRUM_EN);
7987ccd5a2cSjsg
7997ccd5a2cSjsg WREG32_P(CG_MPLL_SPREAD_SPECTRUM, 0, ~SSEN);
8007ccd5a2cSjsg
8017ccd5a2cSjsg if (rdev->family == CHIP_RV740)
8027ccd5a2cSjsg rv740_enable_mclk_spread_spectrum(rdev, false);
8037ccd5a2cSjsg }
8047ccd5a2cSjsg }
8057ccd5a2cSjsg
rv770_program_mpll_timing_parameters(struct radeon_device * rdev)8067ccd5a2cSjsg static void rv770_program_mpll_timing_parameters(struct radeon_device *rdev)
8077ccd5a2cSjsg {
8087ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
8097ccd5a2cSjsg
8107ccd5a2cSjsg if ((rdev->family == CHIP_RV770) && !pi->mem_gddr5) {
8117ccd5a2cSjsg WREG32(MPLL_TIME,
8127ccd5a2cSjsg (MPLL_LOCK_TIME(R600_MPLLLOCKTIME_DFLT * pi->ref_div) |
8137ccd5a2cSjsg MPLL_RESET_TIME(R600_MPLLRESETTIME_DFLT)));
8147ccd5a2cSjsg }
8157ccd5a2cSjsg }
8167ccd5a2cSjsg
rv770_setup_bsp(struct radeon_device * rdev)8177ccd5a2cSjsg void rv770_setup_bsp(struct radeon_device *rdev)
8187ccd5a2cSjsg {
8197ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
8207ccd5a2cSjsg u32 xclk = radeon_get_xclk(rdev);
8217ccd5a2cSjsg
8227ccd5a2cSjsg r600_calculate_u_and_p(pi->asi,
8237ccd5a2cSjsg xclk,
8247ccd5a2cSjsg 16,
8257ccd5a2cSjsg &pi->bsp,
8267ccd5a2cSjsg &pi->bsu);
8277ccd5a2cSjsg
8287ccd5a2cSjsg r600_calculate_u_and_p(pi->pasi,
8297ccd5a2cSjsg xclk,
8307ccd5a2cSjsg 16,
8317ccd5a2cSjsg &pi->pbsp,
8327ccd5a2cSjsg &pi->pbsu);
8337ccd5a2cSjsg
8347ccd5a2cSjsg pi->dsp = BSP(pi->bsp) | BSU(pi->bsu);
8357ccd5a2cSjsg pi->psp = BSP(pi->pbsp) | BSU(pi->pbsu);
8367ccd5a2cSjsg
8377ccd5a2cSjsg WREG32(CG_BSP, pi->dsp);
8387ccd5a2cSjsg
8397ccd5a2cSjsg }
8407ccd5a2cSjsg
rv770_program_git(struct radeon_device * rdev)8417ccd5a2cSjsg void rv770_program_git(struct radeon_device *rdev)
8427ccd5a2cSjsg {
8437ccd5a2cSjsg WREG32_P(CG_GIT, CG_GICST(R600_GICST_DFLT), ~CG_GICST_MASK);
8447ccd5a2cSjsg }
8457ccd5a2cSjsg
rv770_program_tp(struct radeon_device * rdev)8467ccd5a2cSjsg void rv770_program_tp(struct radeon_device *rdev)
8477ccd5a2cSjsg {
8487ccd5a2cSjsg int i;
8497ccd5a2cSjsg enum r600_td td = R600_TD_DFLT;
8507ccd5a2cSjsg
8517ccd5a2cSjsg for (i = 0; i < R600_PM_NUMBER_OF_TC; i++)
8527ccd5a2cSjsg WREG32(CG_FFCT_0 + (i * 4), (UTC_0(r600_utc[i]) | DTC_0(r600_dtc[i])));
8537ccd5a2cSjsg
8547ccd5a2cSjsg if (td == R600_TD_AUTO)
8557ccd5a2cSjsg WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_FORCE_TREND_SEL);
8567ccd5a2cSjsg else
8577ccd5a2cSjsg WREG32_P(SCLK_PWRMGT_CNTL, FIR_FORCE_TREND_SEL, ~FIR_FORCE_TREND_SEL);
8587ccd5a2cSjsg if (td == R600_TD_UP)
8597ccd5a2cSjsg WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_TREND_MODE);
8607ccd5a2cSjsg if (td == R600_TD_DOWN)
8617ccd5a2cSjsg WREG32_P(SCLK_PWRMGT_CNTL, FIR_TREND_MODE, ~FIR_TREND_MODE);
8627ccd5a2cSjsg }
8637ccd5a2cSjsg
rv770_program_tpp(struct radeon_device * rdev)8647ccd5a2cSjsg void rv770_program_tpp(struct radeon_device *rdev)
8657ccd5a2cSjsg {
8667ccd5a2cSjsg WREG32(CG_TPC, R600_TPC_DFLT);
8677ccd5a2cSjsg }
8687ccd5a2cSjsg
rv770_program_sstp(struct radeon_device * rdev)8697ccd5a2cSjsg void rv770_program_sstp(struct radeon_device *rdev)
8707ccd5a2cSjsg {
8717ccd5a2cSjsg WREG32(CG_SSP, (SSTU(R600_SSTU_DFLT) | SST(R600_SST_DFLT)));
8727ccd5a2cSjsg }
8737ccd5a2cSjsg
rv770_program_engine_speed_parameters(struct radeon_device * rdev)8747ccd5a2cSjsg void rv770_program_engine_speed_parameters(struct radeon_device *rdev)
8757ccd5a2cSjsg {
8767ccd5a2cSjsg WREG32_P(SPLL_CNTL_MODE, SPLL_DIV_SYNC, ~SPLL_DIV_SYNC);
8777ccd5a2cSjsg }
8787ccd5a2cSjsg
rv770_enable_display_gap(struct radeon_device * rdev)8797ccd5a2cSjsg static void rv770_enable_display_gap(struct radeon_device *rdev)
8807ccd5a2cSjsg {
8817ccd5a2cSjsg u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL);
8827ccd5a2cSjsg
8837ccd5a2cSjsg tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK);
8847ccd5a2cSjsg tmp |= (DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE) |
8857ccd5a2cSjsg DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE));
8867ccd5a2cSjsg WREG32(CG_DISPLAY_GAP_CNTL, tmp);
8877ccd5a2cSjsg }
8887ccd5a2cSjsg
rv770_program_vc(struct radeon_device * rdev)8897ccd5a2cSjsg void rv770_program_vc(struct radeon_device *rdev)
8907ccd5a2cSjsg {
8917ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
8927ccd5a2cSjsg
8937ccd5a2cSjsg WREG32(CG_FTV, pi->vrc);
8947ccd5a2cSjsg }
8957ccd5a2cSjsg
rv770_clear_vc(struct radeon_device * rdev)8967ccd5a2cSjsg void rv770_clear_vc(struct radeon_device *rdev)
8977ccd5a2cSjsg {
8987ccd5a2cSjsg WREG32(CG_FTV, 0);
8997ccd5a2cSjsg }
9007ccd5a2cSjsg
rv770_upload_firmware(struct radeon_device * rdev)9017ccd5a2cSjsg int rv770_upload_firmware(struct radeon_device *rdev)
9027ccd5a2cSjsg {
9037ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
9047ccd5a2cSjsg int ret;
9057ccd5a2cSjsg
9067ccd5a2cSjsg rv770_reset_smc(rdev);
9077ccd5a2cSjsg rv770_stop_smc_clock(rdev);
9087ccd5a2cSjsg
9097ccd5a2cSjsg ret = rv770_load_smc_ucode(rdev, pi->sram_end);
9107ccd5a2cSjsg if (ret)
9117ccd5a2cSjsg return ret;
9127ccd5a2cSjsg
9137ccd5a2cSjsg return 0;
9147ccd5a2cSjsg }
9157ccd5a2cSjsg
rv770_populate_smc_acpi_state(struct radeon_device * rdev,RV770_SMC_STATETABLE * table)9167ccd5a2cSjsg static int rv770_populate_smc_acpi_state(struct radeon_device *rdev,
9177ccd5a2cSjsg RV770_SMC_STATETABLE *table)
9187ccd5a2cSjsg {
9197ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
9207ccd5a2cSjsg
9217ccd5a2cSjsg u32 mpll_ad_func_cntl =
9227ccd5a2cSjsg pi->clk_regs.rv770.mpll_ad_func_cntl;
9237ccd5a2cSjsg u32 mpll_ad_func_cntl_2 =
9247ccd5a2cSjsg pi->clk_regs.rv770.mpll_ad_func_cntl_2;
9257ccd5a2cSjsg u32 mpll_dq_func_cntl =
9267ccd5a2cSjsg pi->clk_regs.rv770.mpll_dq_func_cntl;
9277ccd5a2cSjsg u32 mpll_dq_func_cntl_2 =
9287ccd5a2cSjsg pi->clk_regs.rv770.mpll_dq_func_cntl_2;
9297ccd5a2cSjsg u32 spll_func_cntl =
9307ccd5a2cSjsg pi->clk_regs.rv770.cg_spll_func_cntl;
9317ccd5a2cSjsg u32 spll_func_cntl_2 =
9327ccd5a2cSjsg pi->clk_regs.rv770.cg_spll_func_cntl_2;
9337ccd5a2cSjsg u32 spll_func_cntl_3 =
9347ccd5a2cSjsg pi->clk_regs.rv770.cg_spll_func_cntl_3;
9357ccd5a2cSjsg u32 mclk_pwrmgt_cntl;
9367ccd5a2cSjsg u32 dll_cntl;
9377ccd5a2cSjsg
9387ccd5a2cSjsg table->ACPIState = table->initialState;
9397ccd5a2cSjsg
9407ccd5a2cSjsg table->ACPIState.flags &= ~PPSMC_SWSTATE_FLAG_DC;
9417ccd5a2cSjsg
9427ccd5a2cSjsg if (pi->acpi_vddc) {
9437ccd5a2cSjsg rv770_populate_vddc_value(rdev, pi->acpi_vddc,
9447ccd5a2cSjsg &table->ACPIState.levels[0].vddc);
9457ccd5a2cSjsg if (pi->pcie_gen2) {
9467ccd5a2cSjsg if (pi->acpi_pcie_gen2)
9477ccd5a2cSjsg table->ACPIState.levels[0].gen2PCIE = 1;
9487ccd5a2cSjsg else
9497ccd5a2cSjsg table->ACPIState.levels[0].gen2PCIE = 0;
9507ccd5a2cSjsg } else
9517ccd5a2cSjsg table->ACPIState.levels[0].gen2PCIE = 0;
9527ccd5a2cSjsg if (pi->acpi_pcie_gen2)
9537ccd5a2cSjsg table->ACPIState.levels[0].gen2XSP = 1;
9547ccd5a2cSjsg else
9557ccd5a2cSjsg table->ACPIState.levels[0].gen2XSP = 0;
9567ccd5a2cSjsg } else {
9577ccd5a2cSjsg rv770_populate_vddc_value(rdev, pi->min_vddc_in_table,
9587ccd5a2cSjsg &table->ACPIState.levels[0].vddc);
9597ccd5a2cSjsg table->ACPIState.levels[0].gen2PCIE = 0;
9607ccd5a2cSjsg }
9617ccd5a2cSjsg
9627ccd5a2cSjsg
9637ccd5a2cSjsg mpll_ad_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN;
9647ccd5a2cSjsg
9657ccd5a2cSjsg mpll_dq_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN;
9667ccd5a2cSjsg
9677ccd5a2cSjsg mclk_pwrmgt_cntl = (MRDCKA0_RESET |
9687ccd5a2cSjsg MRDCKA1_RESET |
9697ccd5a2cSjsg MRDCKB0_RESET |
9707ccd5a2cSjsg MRDCKB1_RESET |
9717ccd5a2cSjsg MRDCKC0_RESET |
9727ccd5a2cSjsg MRDCKC1_RESET |
9737ccd5a2cSjsg MRDCKD0_RESET |
9747ccd5a2cSjsg MRDCKD1_RESET);
9757ccd5a2cSjsg
9767ccd5a2cSjsg dll_cntl = 0xff000000;
9777ccd5a2cSjsg
9787ccd5a2cSjsg spll_func_cntl |= SPLL_RESET | SPLL_SLEEP | SPLL_BYPASS_EN;
9797ccd5a2cSjsg
9807ccd5a2cSjsg spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
9817ccd5a2cSjsg spll_func_cntl_2 |= SCLK_MUX_SEL(4);
9827ccd5a2cSjsg
9837ccd5a2cSjsg table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
9847ccd5a2cSjsg table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2);
9857ccd5a2cSjsg table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
9867ccd5a2cSjsg table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2);
9877ccd5a2cSjsg
9887ccd5a2cSjsg table->ACPIState.levels[0].mclk.mclk770.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
9897ccd5a2cSjsg table->ACPIState.levels[0].mclk.mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl);
9907ccd5a2cSjsg
9917ccd5a2cSjsg table->ACPIState.levels[0].mclk.mclk770.mclk_value = 0;
9927ccd5a2cSjsg
9937ccd5a2cSjsg table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl);
9947ccd5a2cSjsg table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2);
9957ccd5a2cSjsg table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3);
9967ccd5a2cSjsg
9977ccd5a2cSjsg table->ACPIState.levels[0].sclk.sclk_value = 0;
9987ccd5a2cSjsg
9997ccd5a2cSjsg rv770_populate_mvdd_value(rdev, 0, &table->ACPIState.levels[0].mvdd);
10007ccd5a2cSjsg
10017ccd5a2cSjsg table->ACPIState.levels[1] = table->ACPIState.levels[0];
10027ccd5a2cSjsg table->ACPIState.levels[2] = table->ACPIState.levels[0];
10037ccd5a2cSjsg
10047ccd5a2cSjsg return 0;
10057ccd5a2cSjsg }
10067ccd5a2cSjsg
rv770_populate_initial_mvdd_value(struct radeon_device * rdev,RV770_SMC_VOLTAGE_VALUE * voltage)10077ccd5a2cSjsg int rv770_populate_initial_mvdd_value(struct radeon_device *rdev,
10087ccd5a2cSjsg RV770_SMC_VOLTAGE_VALUE *voltage)
10097ccd5a2cSjsg {
10107ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
10117ccd5a2cSjsg
10127ccd5a2cSjsg if ((pi->s0_vid_lower_smio_cntl & pi->mvdd_mask_low) ==
10137ccd5a2cSjsg (pi->mvdd_low_smio[MVDD_LOW_INDEX] & pi->mvdd_mask_low) ) {
10147ccd5a2cSjsg voltage->index = MVDD_LOW_INDEX;
10157ccd5a2cSjsg voltage->value = cpu_to_be16(MVDD_LOW_VALUE);
10167ccd5a2cSjsg } else {
10177ccd5a2cSjsg voltage->index = MVDD_HIGH_INDEX;
10187ccd5a2cSjsg voltage->value = cpu_to_be16(MVDD_HIGH_VALUE);
10197ccd5a2cSjsg }
10207ccd5a2cSjsg
10217ccd5a2cSjsg return 0;
10227ccd5a2cSjsg }
10237ccd5a2cSjsg
rv770_populate_smc_initial_state(struct radeon_device * rdev,struct radeon_ps * radeon_state,RV770_SMC_STATETABLE * table)10247ccd5a2cSjsg static int rv770_populate_smc_initial_state(struct radeon_device *rdev,
10257ccd5a2cSjsg struct radeon_ps *radeon_state,
10267ccd5a2cSjsg RV770_SMC_STATETABLE *table)
10277ccd5a2cSjsg {
10287ccd5a2cSjsg struct rv7xx_ps *initial_state = rv770_get_ps(radeon_state);
10297ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
10307ccd5a2cSjsg u32 a_t;
10317ccd5a2cSjsg
10327ccd5a2cSjsg table->initialState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL =
10337ccd5a2cSjsg cpu_to_be32(pi->clk_regs.rv770.mpll_ad_func_cntl);
10347ccd5a2cSjsg table->initialState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL_2 =
10357ccd5a2cSjsg cpu_to_be32(pi->clk_regs.rv770.mpll_ad_func_cntl_2);
10367ccd5a2cSjsg table->initialState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL =
10377ccd5a2cSjsg cpu_to_be32(pi->clk_regs.rv770.mpll_dq_func_cntl);
10387ccd5a2cSjsg table->initialState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL_2 =
10397ccd5a2cSjsg cpu_to_be32(pi->clk_regs.rv770.mpll_dq_func_cntl_2);
10407ccd5a2cSjsg table->initialState.levels[0].mclk.mclk770.vMCLK_PWRMGT_CNTL =
10417ccd5a2cSjsg cpu_to_be32(pi->clk_regs.rv770.mclk_pwrmgt_cntl);
10427ccd5a2cSjsg table->initialState.levels[0].mclk.mclk770.vDLL_CNTL =
10437ccd5a2cSjsg cpu_to_be32(pi->clk_regs.rv770.dll_cntl);
10447ccd5a2cSjsg
10457ccd5a2cSjsg table->initialState.levels[0].mclk.mclk770.vMPLL_SS =
10467ccd5a2cSjsg cpu_to_be32(pi->clk_regs.rv770.mpll_ss1);
10477ccd5a2cSjsg table->initialState.levels[0].mclk.mclk770.vMPLL_SS2 =
10487ccd5a2cSjsg cpu_to_be32(pi->clk_regs.rv770.mpll_ss2);
10497ccd5a2cSjsg
10507ccd5a2cSjsg table->initialState.levels[0].mclk.mclk770.mclk_value =
10517ccd5a2cSjsg cpu_to_be32(initial_state->low.mclk);
10527ccd5a2cSjsg
10537ccd5a2cSjsg table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL =
10547ccd5a2cSjsg cpu_to_be32(pi->clk_regs.rv770.cg_spll_func_cntl);
10557ccd5a2cSjsg table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 =
10567ccd5a2cSjsg cpu_to_be32(pi->clk_regs.rv770.cg_spll_func_cntl_2);
10577ccd5a2cSjsg table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 =
10587ccd5a2cSjsg cpu_to_be32(pi->clk_regs.rv770.cg_spll_func_cntl_3);
10597ccd5a2cSjsg table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM =
10607ccd5a2cSjsg cpu_to_be32(pi->clk_regs.rv770.cg_spll_spread_spectrum);
10617ccd5a2cSjsg table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM_2 =
10627ccd5a2cSjsg cpu_to_be32(pi->clk_regs.rv770.cg_spll_spread_spectrum_2);
10637ccd5a2cSjsg
10647ccd5a2cSjsg table->initialState.levels[0].sclk.sclk_value =
10657ccd5a2cSjsg cpu_to_be32(initial_state->low.sclk);
10667ccd5a2cSjsg
10677ccd5a2cSjsg table->initialState.levels[0].arbValue = MC_CG_ARB_FREQ_F0;
10687ccd5a2cSjsg
10697ccd5a2cSjsg table->initialState.levels[0].seqValue =
10707ccd5a2cSjsg rv770_get_seq_value(rdev, &initial_state->low);
10717ccd5a2cSjsg
10727ccd5a2cSjsg rv770_populate_vddc_value(rdev,
10737ccd5a2cSjsg initial_state->low.vddc,
10747ccd5a2cSjsg &table->initialState.levels[0].vddc);
10757ccd5a2cSjsg rv770_populate_initial_mvdd_value(rdev,
10767ccd5a2cSjsg &table->initialState.levels[0].mvdd);
10777ccd5a2cSjsg
10787ccd5a2cSjsg a_t = CG_R(0xffff) | CG_L(0);
10797ccd5a2cSjsg table->initialState.levels[0].aT = cpu_to_be32(a_t);
10807ccd5a2cSjsg
10817ccd5a2cSjsg table->initialState.levels[0].bSP = cpu_to_be32(pi->dsp);
10827ccd5a2cSjsg
10837ccd5a2cSjsg if (pi->boot_in_gen2)
10847ccd5a2cSjsg table->initialState.levels[0].gen2PCIE = 1;
10857ccd5a2cSjsg else
10867ccd5a2cSjsg table->initialState.levels[0].gen2PCIE = 0;
10877ccd5a2cSjsg if (initial_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2)
10887ccd5a2cSjsg table->initialState.levels[0].gen2XSP = 1;
10897ccd5a2cSjsg else
10907ccd5a2cSjsg table->initialState.levels[0].gen2XSP = 0;
10917ccd5a2cSjsg
10927ccd5a2cSjsg if (rdev->family == CHIP_RV740) {
10937ccd5a2cSjsg if (pi->mem_gddr5) {
10947ccd5a2cSjsg if (initial_state->low.mclk <= pi->mclk_strobe_mode_threshold)
10957ccd5a2cSjsg table->initialState.levels[0].strobeMode =
10967ccd5a2cSjsg rv740_get_mclk_frequency_ratio(initial_state->low.mclk) | 0x10;
10977ccd5a2cSjsg else
10987ccd5a2cSjsg table->initialState.levels[0].strobeMode = 0;
10997ccd5a2cSjsg
11007ccd5a2cSjsg if (initial_state->low.mclk >= pi->mclk_edc_enable_threshold)
11017ccd5a2cSjsg table->initialState.levels[0].mcFlags = SMC_MC_EDC_RD_FLAG | SMC_MC_EDC_WR_FLAG;
11027ccd5a2cSjsg else
11037ccd5a2cSjsg table->initialState.levels[0].mcFlags = 0;
11047ccd5a2cSjsg }
11057ccd5a2cSjsg }
11067ccd5a2cSjsg
11077ccd5a2cSjsg table->initialState.levels[1] = table->initialState.levels[0];
11087ccd5a2cSjsg table->initialState.levels[2] = table->initialState.levels[0];
11097ccd5a2cSjsg
11107ccd5a2cSjsg table->initialState.flags |= PPSMC_SWSTATE_FLAG_DC;
11117ccd5a2cSjsg
11127ccd5a2cSjsg return 0;
11137ccd5a2cSjsg }
11147ccd5a2cSjsg
rv770_populate_smc_vddc_table(struct radeon_device * rdev,RV770_SMC_STATETABLE * table)11157ccd5a2cSjsg static int rv770_populate_smc_vddc_table(struct radeon_device *rdev,
11167ccd5a2cSjsg RV770_SMC_STATETABLE *table)
11177ccd5a2cSjsg {
11187ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
11197ccd5a2cSjsg int i;
11207ccd5a2cSjsg
11217ccd5a2cSjsg for (i = 0; i < pi->valid_vddc_entries; i++) {
11227ccd5a2cSjsg table->highSMIO[pi->vddc_table[i].vddc_index] =
11237ccd5a2cSjsg pi->vddc_table[i].high_smio;
11247ccd5a2cSjsg table->lowSMIO[pi->vddc_table[i].vddc_index] =
11257ccd5a2cSjsg cpu_to_be32(pi->vddc_table[i].low_smio);
11267ccd5a2cSjsg }
11277ccd5a2cSjsg
11287ccd5a2cSjsg table->voltageMaskTable.highMask[RV770_SMC_VOLTAGEMASK_VDDC] = 0;
11297ccd5a2cSjsg table->voltageMaskTable.lowMask[RV770_SMC_VOLTAGEMASK_VDDC] =
11307ccd5a2cSjsg cpu_to_be32(pi->vddc_mask_low);
11317ccd5a2cSjsg
11327ccd5a2cSjsg for (i = 0;
11337ccd5a2cSjsg ((i < pi->valid_vddc_entries) &&
11347ccd5a2cSjsg (pi->max_vddc_in_table >
11357ccd5a2cSjsg pi->vddc_table[i].vddc));
11367ccd5a2cSjsg i++);
11377ccd5a2cSjsg
11387ccd5a2cSjsg table->maxVDDCIndexInPPTable =
11397ccd5a2cSjsg pi->vddc_table[i].vddc_index;
11407ccd5a2cSjsg
11417ccd5a2cSjsg return 0;
11427ccd5a2cSjsg }
11437ccd5a2cSjsg
rv770_populate_smc_mvdd_table(struct radeon_device * rdev,RV770_SMC_STATETABLE * table)11447ccd5a2cSjsg static int rv770_populate_smc_mvdd_table(struct radeon_device *rdev,
11457ccd5a2cSjsg RV770_SMC_STATETABLE *table)
11467ccd5a2cSjsg {
11477ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
11487ccd5a2cSjsg
11497ccd5a2cSjsg if (pi->mvdd_control) {
11507ccd5a2cSjsg table->lowSMIO[MVDD_HIGH_INDEX] |=
11517ccd5a2cSjsg cpu_to_be32(pi->mvdd_low_smio[MVDD_HIGH_INDEX]);
11527ccd5a2cSjsg table->lowSMIO[MVDD_LOW_INDEX] |=
11537ccd5a2cSjsg cpu_to_be32(pi->mvdd_low_smio[MVDD_LOW_INDEX]);
11547ccd5a2cSjsg
11557ccd5a2cSjsg table->voltageMaskTable.highMask[RV770_SMC_VOLTAGEMASK_MVDD] = 0;
11567ccd5a2cSjsg table->voltageMaskTable.lowMask[RV770_SMC_VOLTAGEMASK_MVDD] =
11577ccd5a2cSjsg cpu_to_be32(pi->mvdd_mask_low);
11587ccd5a2cSjsg }
11597ccd5a2cSjsg
11607ccd5a2cSjsg return 0;
11617ccd5a2cSjsg }
11627ccd5a2cSjsg
rv770_init_smc_table(struct radeon_device * rdev,struct radeon_ps * radeon_boot_state)11637ccd5a2cSjsg static int rv770_init_smc_table(struct radeon_device *rdev,
11647ccd5a2cSjsg struct radeon_ps *radeon_boot_state)
11657ccd5a2cSjsg {
11667ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
11677ccd5a2cSjsg struct rv7xx_ps *boot_state = rv770_get_ps(radeon_boot_state);
11687ccd5a2cSjsg RV770_SMC_STATETABLE *table = &pi->smc_statetable;
11697ccd5a2cSjsg int ret;
11707ccd5a2cSjsg
11717ccd5a2cSjsg memset(table, 0, sizeof(RV770_SMC_STATETABLE));
11727ccd5a2cSjsg
11737ccd5a2cSjsg pi->boot_sclk = boot_state->low.sclk;
11747ccd5a2cSjsg
11757ccd5a2cSjsg rv770_populate_smc_vddc_table(rdev, table);
11767ccd5a2cSjsg rv770_populate_smc_mvdd_table(rdev, table);
11777ccd5a2cSjsg
11787ccd5a2cSjsg switch (rdev->pm.int_thermal_type) {
11797ccd5a2cSjsg case THERMAL_TYPE_RV770:
11807ccd5a2cSjsg case THERMAL_TYPE_ADT7473_WITH_INTERNAL:
11817ccd5a2cSjsg table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_INTERNAL;
11827ccd5a2cSjsg break;
11837ccd5a2cSjsg case THERMAL_TYPE_NONE:
11847ccd5a2cSjsg table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_NONE;
11857ccd5a2cSjsg break;
11867ccd5a2cSjsg case THERMAL_TYPE_EXTERNAL_GPIO:
11877ccd5a2cSjsg default:
11887ccd5a2cSjsg table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL;
11897ccd5a2cSjsg break;
11907ccd5a2cSjsg }
11917ccd5a2cSjsg
11927ccd5a2cSjsg if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC) {
11937ccd5a2cSjsg table->systemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
11947ccd5a2cSjsg
11957ccd5a2cSjsg if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_DONT_WAIT_FOR_VBLANK_ON_ALERT)
11967ccd5a2cSjsg table->extraFlags |= PPSMC_EXTRAFLAGS_AC2DC_DONT_WAIT_FOR_VBLANK;
11977ccd5a2cSjsg
11987ccd5a2cSjsg if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_GOTO_BOOT_ON_ALERT)
11997ccd5a2cSjsg table->extraFlags |= PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTOINITIALSTATE;
12007ccd5a2cSjsg }
12017ccd5a2cSjsg
12027ccd5a2cSjsg if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC)
12037ccd5a2cSjsg table->systemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
12047ccd5a2cSjsg
12057ccd5a2cSjsg if (pi->mem_gddr5)
12067ccd5a2cSjsg table->systemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
12077ccd5a2cSjsg
12087ccd5a2cSjsg if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
12097ccd5a2cSjsg ret = rv730_populate_smc_initial_state(rdev, radeon_boot_state, table);
12107ccd5a2cSjsg else
12117ccd5a2cSjsg ret = rv770_populate_smc_initial_state(rdev, radeon_boot_state, table);
12127ccd5a2cSjsg if (ret)
12137ccd5a2cSjsg return ret;
12147ccd5a2cSjsg
12157ccd5a2cSjsg if (rdev->family == CHIP_RV740)
12167ccd5a2cSjsg ret = rv740_populate_smc_acpi_state(rdev, table);
12177ccd5a2cSjsg else if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
12187ccd5a2cSjsg ret = rv730_populate_smc_acpi_state(rdev, table);
12197ccd5a2cSjsg else
12207ccd5a2cSjsg ret = rv770_populate_smc_acpi_state(rdev, table);
12217ccd5a2cSjsg if (ret)
12227ccd5a2cSjsg return ret;
12237ccd5a2cSjsg
12247ccd5a2cSjsg table->driverState = table->initialState;
12257ccd5a2cSjsg
12267ccd5a2cSjsg return rv770_copy_bytes_to_smc(rdev,
12277ccd5a2cSjsg pi->state_table_start,
12287ccd5a2cSjsg (const u8 *)table,
12297ccd5a2cSjsg sizeof(RV770_SMC_STATETABLE),
12307ccd5a2cSjsg pi->sram_end);
12317ccd5a2cSjsg }
12327ccd5a2cSjsg
rv770_construct_vddc_table(struct radeon_device * rdev)12337ccd5a2cSjsg static int rv770_construct_vddc_table(struct radeon_device *rdev)
12347ccd5a2cSjsg {
12357ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
12367ccd5a2cSjsg u16 min, max, step;
12377ccd5a2cSjsg u32 steps = 0;
12387ccd5a2cSjsg u8 vddc_index = 0;
12397ccd5a2cSjsg u32 i;
12407ccd5a2cSjsg
12417ccd5a2cSjsg radeon_atom_get_min_voltage(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, &min);
12427ccd5a2cSjsg radeon_atom_get_max_voltage(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, &max);
12437ccd5a2cSjsg radeon_atom_get_voltage_step(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, &step);
12447ccd5a2cSjsg
12457ccd5a2cSjsg steps = (max - min) / step + 1;
12467ccd5a2cSjsg
12477ccd5a2cSjsg if (steps > MAX_NO_VREG_STEPS)
12487ccd5a2cSjsg return -EINVAL;
12497ccd5a2cSjsg
12507ccd5a2cSjsg for (i = 0; i < steps; i++) {
12517ccd5a2cSjsg u32 gpio_pins, gpio_mask;
12527ccd5a2cSjsg
12537ccd5a2cSjsg pi->vddc_table[i].vddc = (u16)(min + i * step);
12547ccd5a2cSjsg radeon_atom_get_voltage_gpio_settings(rdev,
12557ccd5a2cSjsg pi->vddc_table[i].vddc,
12567ccd5a2cSjsg SET_VOLTAGE_TYPE_ASIC_VDDC,
12577ccd5a2cSjsg &gpio_pins, &gpio_mask);
12587ccd5a2cSjsg pi->vddc_table[i].low_smio = gpio_pins & gpio_mask;
12597ccd5a2cSjsg pi->vddc_table[i].high_smio = 0;
12607ccd5a2cSjsg pi->vddc_mask_low = gpio_mask;
12617ccd5a2cSjsg if (i > 0) {
12627ccd5a2cSjsg if ((pi->vddc_table[i].low_smio !=
12637ccd5a2cSjsg pi->vddc_table[i - 1].low_smio ) ||
12647ccd5a2cSjsg (pi->vddc_table[i].high_smio !=
12657ccd5a2cSjsg pi->vddc_table[i - 1].high_smio))
12667ccd5a2cSjsg vddc_index++;
12677ccd5a2cSjsg }
12687ccd5a2cSjsg pi->vddc_table[i].vddc_index = vddc_index;
12697ccd5a2cSjsg }
12707ccd5a2cSjsg
12717ccd5a2cSjsg pi->valid_vddc_entries = (u8)steps;
12727ccd5a2cSjsg
12737ccd5a2cSjsg return 0;
12747ccd5a2cSjsg }
12757ccd5a2cSjsg
rv770_get_mclk_split_point(struct atom_memory_info * memory_info)12767ccd5a2cSjsg static u32 rv770_get_mclk_split_point(struct atom_memory_info *memory_info)
12777ccd5a2cSjsg {
12787ccd5a2cSjsg if (memory_info->mem_type == MEM_TYPE_GDDR3)
12797ccd5a2cSjsg return 30000;
12807ccd5a2cSjsg
12817ccd5a2cSjsg return 0;
12827ccd5a2cSjsg }
12837ccd5a2cSjsg
rv770_get_mvdd_pin_configuration(struct radeon_device * rdev)12847ccd5a2cSjsg static int rv770_get_mvdd_pin_configuration(struct radeon_device *rdev)
12857ccd5a2cSjsg {
12867ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
12877ccd5a2cSjsg u32 gpio_pins, gpio_mask;
12887ccd5a2cSjsg
12897ccd5a2cSjsg radeon_atom_get_voltage_gpio_settings(rdev,
12907ccd5a2cSjsg MVDD_HIGH_VALUE, SET_VOLTAGE_TYPE_ASIC_MVDDC,
12917ccd5a2cSjsg &gpio_pins, &gpio_mask);
12927ccd5a2cSjsg pi->mvdd_mask_low = gpio_mask;
12937ccd5a2cSjsg pi->mvdd_low_smio[MVDD_HIGH_INDEX] =
12947ccd5a2cSjsg gpio_pins & gpio_mask;
12957ccd5a2cSjsg
12967ccd5a2cSjsg radeon_atom_get_voltage_gpio_settings(rdev,
12977ccd5a2cSjsg MVDD_LOW_VALUE, SET_VOLTAGE_TYPE_ASIC_MVDDC,
12987ccd5a2cSjsg &gpio_pins, &gpio_mask);
12997ccd5a2cSjsg pi->mvdd_low_smio[MVDD_LOW_INDEX] =
13007ccd5a2cSjsg gpio_pins & gpio_mask;
13017ccd5a2cSjsg
13027ccd5a2cSjsg return 0;
13037ccd5a2cSjsg }
13047ccd5a2cSjsg
rv770_get_memory_module_index(struct radeon_device * rdev)13057ccd5a2cSjsg u8 rv770_get_memory_module_index(struct radeon_device *rdev)
13067ccd5a2cSjsg {
13077ccd5a2cSjsg return (u8) ((RREG32(BIOS_SCRATCH_4) >> 16) & 0xff);
13087ccd5a2cSjsg }
13097ccd5a2cSjsg
rv770_get_mvdd_configuration(struct radeon_device * rdev)13107ccd5a2cSjsg static int rv770_get_mvdd_configuration(struct radeon_device *rdev)
13117ccd5a2cSjsg {
13127ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
13137ccd5a2cSjsg u8 memory_module_index;
13147ccd5a2cSjsg struct atom_memory_info memory_info;
13157ccd5a2cSjsg
13167ccd5a2cSjsg memory_module_index = rv770_get_memory_module_index(rdev);
13177ccd5a2cSjsg
13187ccd5a2cSjsg if (radeon_atom_get_memory_info(rdev, memory_module_index, &memory_info)) {
13197ccd5a2cSjsg pi->mvdd_control = false;
13207ccd5a2cSjsg return 0;
13217ccd5a2cSjsg }
13227ccd5a2cSjsg
13237ccd5a2cSjsg pi->mvdd_split_frequency =
13247ccd5a2cSjsg rv770_get_mclk_split_point(&memory_info);
13257ccd5a2cSjsg
13267ccd5a2cSjsg if (pi->mvdd_split_frequency == 0) {
13277ccd5a2cSjsg pi->mvdd_control = false;
13287ccd5a2cSjsg return 0;
13297ccd5a2cSjsg }
13307ccd5a2cSjsg
13317ccd5a2cSjsg return rv770_get_mvdd_pin_configuration(rdev);
13327ccd5a2cSjsg }
13337ccd5a2cSjsg
rv770_enable_voltage_control(struct radeon_device * rdev,bool enable)13347ccd5a2cSjsg void rv770_enable_voltage_control(struct radeon_device *rdev,
13357ccd5a2cSjsg bool enable)
13367ccd5a2cSjsg {
13377ccd5a2cSjsg if (enable)
13387ccd5a2cSjsg WREG32_P(GENERAL_PWRMGT, VOLT_PWRMGT_EN, ~VOLT_PWRMGT_EN);
13397ccd5a2cSjsg else
13407ccd5a2cSjsg WREG32_P(GENERAL_PWRMGT, 0, ~VOLT_PWRMGT_EN);
13417ccd5a2cSjsg }
13427ccd5a2cSjsg
rv770_program_display_gap(struct radeon_device * rdev)13437ccd5a2cSjsg static void rv770_program_display_gap(struct radeon_device *rdev)
13447ccd5a2cSjsg {
13457ccd5a2cSjsg u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL);
13467ccd5a2cSjsg
13477ccd5a2cSjsg tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK);
13487ccd5a2cSjsg if (rdev->pm.dpm.new_active_crtcs & 1) {
13497ccd5a2cSjsg tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK);
13507ccd5a2cSjsg tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
13517ccd5a2cSjsg } else if (rdev->pm.dpm.new_active_crtcs & 2) {
13527ccd5a2cSjsg tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
13537ccd5a2cSjsg tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK);
13547ccd5a2cSjsg } else {
13557ccd5a2cSjsg tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
13567ccd5a2cSjsg tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
13577ccd5a2cSjsg }
13587ccd5a2cSjsg WREG32(CG_DISPLAY_GAP_CNTL, tmp);
13597ccd5a2cSjsg }
13607ccd5a2cSjsg
rv770_enable_dynamic_pcie_gen2(struct radeon_device * rdev,bool enable)13617ccd5a2cSjsg static void rv770_enable_dynamic_pcie_gen2(struct radeon_device *rdev,
13627ccd5a2cSjsg bool enable)
13637ccd5a2cSjsg {
13647ccd5a2cSjsg rv770_enable_bif_dynamic_pcie_gen2(rdev, enable);
13657ccd5a2cSjsg
13667ccd5a2cSjsg if (enable)
13677ccd5a2cSjsg WREG32_P(GENERAL_PWRMGT, ENABLE_GEN2PCIE, ~ENABLE_GEN2PCIE);
13687ccd5a2cSjsg else
13697ccd5a2cSjsg WREG32_P(GENERAL_PWRMGT, 0, ~ENABLE_GEN2PCIE);
13707ccd5a2cSjsg }
13717ccd5a2cSjsg
r7xx_program_memory_timing_parameters(struct radeon_device * rdev,struct radeon_ps * radeon_new_state)13727ccd5a2cSjsg static void r7xx_program_memory_timing_parameters(struct radeon_device *rdev,
13737ccd5a2cSjsg struct radeon_ps *radeon_new_state)
13747ccd5a2cSjsg {
13757ccd5a2cSjsg if ((rdev->family == CHIP_RV730) ||
13767ccd5a2cSjsg (rdev->family == CHIP_RV710) ||
13777ccd5a2cSjsg (rdev->family == CHIP_RV740))
13787ccd5a2cSjsg rv730_program_memory_timing_parameters(rdev, radeon_new_state);
13797ccd5a2cSjsg else
13807ccd5a2cSjsg rv770_program_memory_timing_parameters(rdev, radeon_new_state);
13817ccd5a2cSjsg }
13827ccd5a2cSjsg
rv770_upload_sw_state(struct radeon_device * rdev,struct radeon_ps * radeon_new_state)13837ccd5a2cSjsg static int rv770_upload_sw_state(struct radeon_device *rdev,
13847ccd5a2cSjsg struct radeon_ps *radeon_new_state)
13857ccd5a2cSjsg {
13867ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
13877ccd5a2cSjsg u16 address = pi->state_table_start +
13887ccd5a2cSjsg offsetof(RV770_SMC_STATETABLE, driverState);
13897ccd5a2cSjsg RV770_SMC_SWSTATE state = { 0 };
13907ccd5a2cSjsg int ret;
13917ccd5a2cSjsg
13927ccd5a2cSjsg ret = rv770_convert_power_state_to_smc(rdev, radeon_new_state, &state);
13937ccd5a2cSjsg if (ret)
13947ccd5a2cSjsg return ret;
13957ccd5a2cSjsg
13967ccd5a2cSjsg return rv770_copy_bytes_to_smc(rdev, address, (const u8 *)&state,
13977ccd5a2cSjsg sizeof(RV770_SMC_SWSTATE),
13987ccd5a2cSjsg pi->sram_end);
13997ccd5a2cSjsg }
14007ccd5a2cSjsg
rv770_halt_smc(struct radeon_device * rdev)14017ccd5a2cSjsg int rv770_halt_smc(struct radeon_device *rdev)
14027ccd5a2cSjsg {
14037ccd5a2cSjsg if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_Halt) != PPSMC_Result_OK)
14047ccd5a2cSjsg return -EINVAL;
14057ccd5a2cSjsg
14067ccd5a2cSjsg if (rv770_wait_for_smc_inactive(rdev) != PPSMC_Result_OK)
14077ccd5a2cSjsg return -EINVAL;
14087ccd5a2cSjsg
14097ccd5a2cSjsg return 0;
14107ccd5a2cSjsg }
14117ccd5a2cSjsg
rv770_resume_smc(struct radeon_device * rdev)14127ccd5a2cSjsg int rv770_resume_smc(struct radeon_device *rdev)
14137ccd5a2cSjsg {
14147ccd5a2cSjsg if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_Resume) != PPSMC_Result_OK)
14157ccd5a2cSjsg return -EINVAL;
14167ccd5a2cSjsg return 0;
14177ccd5a2cSjsg }
14187ccd5a2cSjsg
rv770_set_sw_state(struct radeon_device * rdev)14197ccd5a2cSjsg int rv770_set_sw_state(struct radeon_device *rdev)
14207ccd5a2cSjsg {
14217ccd5a2cSjsg if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_SwitchToSwState) != PPSMC_Result_OK)
14227ccd5a2cSjsg DRM_DEBUG("rv770_set_sw_state failed\n");
14237ccd5a2cSjsg return 0;
14247ccd5a2cSjsg }
14257ccd5a2cSjsg
rv770_set_boot_state(struct radeon_device * rdev)14267ccd5a2cSjsg int rv770_set_boot_state(struct radeon_device *rdev)
14277ccd5a2cSjsg {
14287ccd5a2cSjsg if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_SwitchToInitialState) != PPSMC_Result_OK)
14297ccd5a2cSjsg return -EINVAL;
14307ccd5a2cSjsg return 0;
14317ccd5a2cSjsg }
14327ccd5a2cSjsg
rv770_set_uvd_clock_before_set_eng_clock(struct radeon_device * rdev,struct radeon_ps * new_ps,struct radeon_ps * old_ps)14337ccd5a2cSjsg void rv770_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev,
14347ccd5a2cSjsg struct radeon_ps *new_ps,
14357ccd5a2cSjsg struct radeon_ps *old_ps)
14367ccd5a2cSjsg {
14377ccd5a2cSjsg struct rv7xx_ps *new_state = rv770_get_ps(new_ps);
14387ccd5a2cSjsg struct rv7xx_ps *current_state = rv770_get_ps(old_ps);
14397ccd5a2cSjsg
14407ccd5a2cSjsg if ((new_ps->vclk == old_ps->vclk) &&
14417ccd5a2cSjsg (new_ps->dclk == old_ps->dclk))
14427ccd5a2cSjsg return;
14437ccd5a2cSjsg
14447ccd5a2cSjsg if (new_state->high.sclk >= current_state->high.sclk)
14457ccd5a2cSjsg return;
14467ccd5a2cSjsg
14477ccd5a2cSjsg radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk);
14487ccd5a2cSjsg }
14497ccd5a2cSjsg
rv770_set_uvd_clock_after_set_eng_clock(struct radeon_device * rdev,struct radeon_ps * new_ps,struct radeon_ps * old_ps)14507ccd5a2cSjsg void rv770_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
14517ccd5a2cSjsg struct radeon_ps *new_ps,
14527ccd5a2cSjsg struct radeon_ps *old_ps)
14537ccd5a2cSjsg {
14547ccd5a2cSjsg struct rv7xx_ps *new_state = rv770_get_ps(new_ps);
14557ccd5a2cSjsg struct rv7xx_ps *current_state = rv770_get_ps(old_ps);
14567ccd5a2cSjsg
14577ccd5a2cSjsg if ((new_ps->vclk == old_ps->vclk) &&
14587ccd5a2cSjsg (new_ps->dclk == old_ps->dclk))
14597ccd5a2cSjsg return;
14607ccd5a2cSjsg
14617ccd5a2cSjsg if (new_state->high.sclk < current_state->high.sclk)
14627ccd5a2cSjsg return;
14637ccd5a2cSjsg
14647ccd5a2cSjsg radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk);
14657ccd5a2cSjsg }
14667ccd5a2cSjsg
rv770_restrict_performance_levels_before_switch(struct radeon_device * rdev)14677ccd5a2cSjsg int rv770_restrict_performance_levels_before_switch(struct radeon_device *rdev)
14687ccd5a2cSjsg {
14697ccd5a2cSjsg if (rv770_send_msg_to_smc(rdev, (PPSMC_Msg)(PPSMC_MSG_NoForcedLevel)) != PPSMC_Result_OK)
14707ccd5a2cSjsg return -EINVAL;
14717ccd5a2cSjsg
14727ccd5a2cSjsg if (rv770_send_msg_to_smc(rdev, (PPSMC_Msg)(PPSMC_MSG_TwoLevelsDisabled)) != PPSMC_Result_OK)
14737ccd5a2cSjsg return -EINVAL;
14747ccd5a2cSjsg
14757ccd5a2cSjsg return 0;
14767ccd5a2cSjsg }
14777ccd5a2cSjsg
rv770_dpm_force_performance_level(struct radeon_device * rdev,enum radeon_dpm_forced_level level)14787ccd5a2cSjsg int rv770_dpm_force_performance_level(struct radeon_device *rdev,
14797ccd5a2cSjsg enum radeon_dpm_forced_level level)
14807ccd5a2cSjsg {
14817ccd5a2cSjsg PPSMC_Msg msg;
14827ccd5a2cSjsg
14837ccd5a2cSjsg if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
14847ccd5a2cSjsg if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_ZeroLevelsDisabled) != PPSMC_Result_OK)
14857ccd5a2cSjsg return -EINVAL;
14867ccd5a2cSjsg msg = PPSMC_MSG_ForceHigh;
14877ccd5a2cSjsg } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
14887ccd5a2cSjsg if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_NoForcedLevel) != PPSMC_Result_OK)
14897ccd5a2cSjsg return -EINVAL;
14907ccd5a2cSjsg msg = (PPSMC_Msg)(PPSMC_MSG_TwoLevelsDisabled);
14917ccd5a2cSjsg } else {
14927ccd5a2cSjsg if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_NoForcedLevel) != PPSMC_Result_OK)
14937ccd5a2cSjsg return -EINVAL;
14947ccd5a2cSjsg msg = (PPSMC_Msg)(PPSMC_MSG_ZeroLevelsDisabled);
14957ccd5a2cSjsg }
14967ccd5a2cSjsg
14977ccd5a2cSjsg if (rv770_send_msg_to_smc(rdev, msg) != PPSMC_Result_OK)
14987ccd5a2cSjsg return -EINVAL;
14997ccd5a2cSjsg
15007ccd5a2cSjsg rdev->pm.dpm.forced_level = level;
15017ccd5a2cSjsg
15027ccd5a2cSjsg return 0;
15037ccd5a2cSjsg }
15047ccd5a2cSjsg
r7xx_start_smc(struct radeon_device * rdev)15057ccd5a2cSjsg void r7xx_start_smc(struct radeon_device *rdev)
15067ccd5a2cSjsg {
15077ccd5a2cSjsg rv770_start_smc(rdev);
15087ccd5a2cSjsg rv770_start_smc_clock(rdev);
15097ccd5a2cSjsg }
15107ccd5a2cSjsg
15117ccd5a2cSjsg
r7xx_stop_smc(struct radeon_device * rdev)15127ccd5a2cSjsg void r7xx_stop_smc(struct radeon_device *rdev)
15137ccd5a2cSjsg {
15147ccd5a2cSjsg rv770_reset_smc(rdev);
15157ccd5a2cSjsg rv770_stop_smc_clock(rdev);
15167ccd5a2cSjsg }
15177ccd5a2cSjsg
rv770_read_clock_registers(struct radeon_device * rdev)15187ccd5a2cSjsg static void rv770_read_clock_registers(struct radeon_device *rdev)
15197ccd5a2cSjsg {
15207ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
15217ccd5a2cSjsg
15227ccd5a2cSjsg pi->clk_regs.rv770.cg_spll_func_cntl =
15237ccd5a2cSjsg RREG32(CG_SPLL_FUNC_CNTL);
15247ccd5a2cSjsg pi->clk_regs.rv770.cg_spll_func_cntl_2 =
15257ccd5a2cSjsg RREG32(CG_SPLL_FUNC_CNTL_2);
15267ccd5a2cSjsg pi->clk_regs.rv770.cg_spll_func_cntl_3 =
15277ccd5a2cSjsg RREG32(CG_SPLL_FUNC_CNTL_3);
15287ccd5a2cSjsg pi->clk_regs.rv770.cg_spll_spread_spectrum =
15297ccd5a2cSjsg RREG32(CG_SPLL_SPREAD_SPECTRUM);
15307ccd5a2cSjsg pi->clk_regs.rv770.cg_spll_spread_spectrum_2 =
15317ccd5a2cSjsg RREG32(CG_SPLL_SPREAD_SPECTRUM_2);
15327ccd5a2cSjsg pi->clk_regs.rv770.mpll_ad_func_cntl =
15337ccd5a2cSjsg RREG32(MPLL_AD_FUNC_CNTL);
15347ccd5a2cSjsg pi->clk_regs.rv770.mpll_ad_func_cntl_2 =
15357ccd5a2cSjsg RREG32(MPLL_AD_FUNC_CNTL_2);
15367ccd5a2cSjsg pi->clk_regs.rv770.mpll_dq_func_cntl =
15377ccd5a2cSjsg RREG32(MPLL_DQ_FUNC_CNTL);
15387ccd5a2cSjsg pi->clk_regs.rv770.mpll_dq_func_cntl_2 =
15397ccd5a2cSjsg RREG32(MPLL_DQ_FUNC_CNTL_2);
15407ccd5a2cSjsg pi->clk_regs.rv770.mclk_pwrmgt_cntl =
15417ccd5a2cSjsg RREG32(MCLK_PWRMGT_CNTL);
15427ccd5a2cSjsg pi->clk_regs.rv770.dll_cntl = RREG32(DLL_CNTL);
15437ccd5a2cSjsg }
15447ccd5a2cSjsg
r7xx_read_clock_registers(struct radeon_device * rdev)15457ccd5a2cSjsg static void r7xx_read_clock_registers(struct radeon_device *rdev)
15467ccd5a2cSjsg {
15477ccd5a2cSjsg if (rdev->family == CHIP_RV740)
15487ccd5a2cSjsg rv740_read_clock_registers(rdev);
15497ccd5a2cSjsg else if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
15507ccd5a2cSjsg rv730_read_clock_registers(rdev);
15517ccd5a2cSjsg else
15527ccd5a2cSjsg rv770_read_clock_registers(rdev);
15537ccd5a2cSjsg }
15547ccd5a2cSjsg
rv770_read_voltage_smio_registers(struct radeon_device * rdev)15557ccd5a2cSjsg void rv770_read_voltage_smio_registers(struct radeon_device *rdev)
15567ccd5a2cSjsg {
15577ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
15587ccd5a2cSjsg
15597ccd5a2cSjsg pi->s0_vid_lower_smio_cntl =
15607ccd5a2cSjsg RREG32(S0_VID_LOWER_SMIO_CNTL);
15617ccd5a2cSjsg }
15627ccd5a2cSjsg
rv770_reset_smio_status(struct radeon_device * rdev)15637ccd5a2cSjsg void rv770_reset_smio_status(struct radeon_device *rdev)
15647ccd5a2cSjsg {
15657ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
15667ccd5a2cSjsg u32 sw_smio_index, vid_smio_cntl;
15677ccd5a2cSjsg
15687ccd5a2cSjsg sw_smio_index =
15697ccd5a2cSjsg (RREG32(GENERAL_PWRMGT) & SW_SMIO_INDEX_MASK) >> SW_SMIO_INDEX_SHIFT;
15707ccd5a2cSjsg switch (sw_smio_index) {
15717ccd5a2cSjsg case 3:
15727ccd5a2cSjsg vid_smio_cntl = RREG32(S3_VID_LOWER_SMIO_CNTL);
15737ccd5a2cSjsg break;
15747ccd5a2cSjsg case 2:
15757ccd5a2cSjsg vid_smio_cntl = RREG32(S2_VID_LOWER_SMIO_CNTL);
15767ccd5a2cSjsg break;
15777ccd5a2cSjsg case 1:
15787ccd5a2cSjsg vid_smio_cntl = RREG32(S1_VID_LOWER_SMIO_CNTL);
15797ccd5a2cSjsg break;
15807ccd5a2cSjsg case 0:
15817ccd5a2cSjsg return;
15827ccd5a2cSjsg default:
15837ccd5a2cSjsg vid_smio_cntl = pi->s0_vid_lower_smio_cntl;
15847ccd5a2cSjsg break;
15857ccd5a2cSjsg }
15867ccd5a2cSjsg
15877ccd5a2cSjsg WREG32(S0_VID_LOWER_SMIO_CNTL, vid_smio_cntl);
15887ccd5a2cSjsg WREG32_P(GENERAL_PWRMGT, SW_SMIO_INDEX(0), ~SW_SMIO_INDEX_MASK);
15897ccd5a2cSjsg }
15907ccd5a2cSjsg
rv770_get_memory_type(struct radeon_device * rdev)15917ccd5a2cSjsg void rv770_get_memory_type(struct radeon_device *rdev)
15927ccd5a2cSjsg {
15937ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
15947ccd5a2cSjsg u32 tmp;
15957ccd5a2cSjsg
15967ccd5a2cSjsg tmp = RREG32(MC_SEQ_MISC0);
15977ccd5a2cSjsg
15987ccd5a2cSjsg if (((tmp & MC_SEQ_MISC0_GDDR5_MASK) >> MC_SEQ_MISC0_GDDR5_SHIFT) ==
15997ccd5a2cSjsg MC_SEQ_MISC0_GDDR5_VALUE)
16007ccd5a2cSjsg pi->mem_gddr5 = true;
16017ccd5a2cSjsg else
16027ccd5a2cSjsg pi->mem_gddr5 = false;
16037ccd5a2cSjsg
16047ccd5a2cSjsg }
16057ccd5a2cSjsg
rv770_get_pcie_gen2_status(struct radeon_device * rdev)16067ccd5a2cSjsg void rv770_get_pcie_gen2_status(struct radeon_device *rdev)
16077ccd5a2cSjsg {
16087ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
16097ccd5a2cSjsg u32 tmp;
16107ccd5a2cSjsg
16117ccd5a2cSjsg tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
16127ccd5a2cSjsg
16137ccd5a2cSjsg if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) &&
16147ccd5a2cSjsg (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2))
16157ccd5a2cSjsg pi->pcie_gen2 = true;
16167ccd5a2cSjsg else
16177ccd5a2cSjsg pi->pcie_gen2 = false;
16187ccd5a2cSjsg
16197ccd5a2cSjsg if (pi->pcie_gen2) {
16207ccd5a2cSjsg if (tmp & LC_CURRENT_DATA_RATE)
16217ccd5a2cSjsg pi->boot_in_gen2 = true;
16227ccd5a2cSjsg else
16237ccd5a2cSjsg pi->boot_in_gen2 = false;
16247ccd5a2cSjsg } else
16257ccd5a2cSjsg pi->boot_in_gen2 = false;
16267ccd5a2cSjsg }
16277ccd5a2cSjsg
16287ccd5a2cSjsg #if 0
16297ccd5a2cSjsg static int rv770_enter_ulp_state(struct radeon_device *rdev)
16307ccd5a2cSjsg {
16317ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
16327ccd5a2cSjsg
16337ccd5a2cSjsg if (pi->gfx_clock_gating) {
16347ccd5a2cSjsg WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
16357ccd5a2cSjsg WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON);
16367ccd5a2cSjsg WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON);
16377ccd5a2cSjsg RREG32(GB_TILING_CONFIG);
16387ccd5a2cSjsg }
16397ccd5a2cSjsg
16407ccd5a2cSjsg WREG32_P(SMC_MSG, HOST_SMC_MSG(PPSMC_MSG_SwitchToMinimumPower),
16417ccd5a2cSjsg ~HOST_SMC_MSG_MASK);
16427ccd5a2cSjsg
16437ccd5a2cSjsg udelay(7000);
16447ccd5a2cSjsg
16457ccd5a2cSjsg return 0;
16467ccd5a2cSjsg }
16477ccd5a2cSjsg
16487ccd5a2cSjsg static int rv770_exit_ulp_state(struct radeon_device *rdev)
16497ccd5a2cSjsg {
16507ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
16517ccd5a2cSjsg int i;
16527ccd5a2cSjsg
16537ccd5a2cSjsg WREG32_P(SMC_MSG, HOST_SMC_MSG(PPSMC_MSG_ResumeFromMinimumPower),
16547ccd5a2cSjsg ~HOST_SMC_MSG_MASK);
16557ccd5a2cSjsg
16567ccd5a2cSjsg udelay(7000);
16577ccd5a2cSjsg
16587ccd5a2cSjsg for (i = 0; i < rdev->usec_timeout; i++) {
16597ccd5a2cSjsg if (((RREG32(SMC_MSG) & HOST_SMC_RESP_MASK) >> HOST_SMC_RESP_SHIFT) == 1)
16607ccd5a2cSjsg break;
16617ccd5a2cSjsg udelay(1000);
16627ccd5a2cSjsg }
16637ccd5a2cSjsg
16647ccd5a2cSjsg if (pi->gfx_clock_gating)
16657ccd5a2cSjsg WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN);
16667ccd5a2cSjsg
16677ccd5a2cSjsg return 0;
16687ccd5a2cSjsg }
16697ccd5a2cSjsg #endif
16707ccd5a2cSjsg
rv770_get_mclk_odt_threshold(struct radeon_device * rdev)16717ccd5a2cSjsg static void rv770_get_mclk_odt_threshold(struct radeon_device *rdev)
16727ccd5a2cSjsg {
16737ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
16747ccd5a2cSjsg u8 memory_module_index;
16757ccd5a2cSjsg struct atom_memory_info memory_info;
16767ccd5a2cSjsg
16777ccd5a2cSjsg pi->mclk_odt_threshold = 0;
16787ccd5a2cSjsg
16797ccd5a2cSjsg if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710)) {
16807ccd5a2cSjsg memory_module_index = rv770_get_memory_module_index(rdev);
16817ccd5a2cSjsg
16827ccd5a2cSjsg if (radeon_atom_get_memory_info(rdev, memory_module_index, &memory_info))
16837ccd5a2cSjsg return;
16847ccd5a2cSjsg
16857ccd5a2cSjsg if (memory_info.mem_type == MEM_TYPE_DDR2 ||
16867ccd5a2cSjsg memory_info.mem_type == MEM_TYPE_DDR3)
16877ccd5a2cSjsg pi->mclk_odt_threshold = 30000;
16887ccd5a2cSjsg }
16897ccd5a2cSjsg }
16907ccd5a2cSjsg
rv770_get_max_vddc(struct radeon_device * rdev)16917ccd5a2cSjsg void rv770_get_max_vddc(struct radeon_device *rdev)
16927ccd5a2cSjsg {
16937ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
16947ccd5a2cSjsg u16 vddc;
16957ccd5a2cSjsg
16967ccd5a2cSjsg if (radeon_atom_get_max_vddc(rdev, 0, 0, &vddc))
16977ccd5a2cSjsg pi->max_vddc = 0;
16987ccd5a2cSjsg else
16997ccd5a2cSjsg pi->max_vddc = vddc;
17007ccd5a2cSjsg }
17017ccd5a2cSjsg
rv770_program_response_times(struct radeon_device * rdev)17027ccd5a2cSjsg void rv770_program_response_times(struct radeon_device *rdev)
17037ccd5a2cSjsg {
17047ccd5a2cSjsg u32 voltage_response_time, backbias_response_time;
17057ccd5a2cSjsg u32 acpi_delay_time, vbi_time_out;
17067ccd5a2cSjsg u32 vddc_dly, bb_dly, acpi_dly, vbi_dly;
17077ccd5a2cSjsg u32 reference_clock;
17087ccd5a2cSjsg
17097ccd5a2cSjsg voltage_response_time = (u32)rdev->pm.dpm.voltage_response_time;
17107ccd5a2cSjsg backbias_response_time = (u32)rdev->pm.dpm.backbias_response_time;
17117ccd5a2cSjsg
17127ccd5a2cSjsg if (voltage_response_time == 0)
17137ccd5a2cSjsg voltage_response_time = 1000;
17147ccd5a2cSjsg
17157ccd5a2cSjsg if (backbias_response_time == 0)
17167ccd5a2cSjsg backbias_response_time = 1000;
17177ccd5a2cSjsg
17187ccd5a2cSjsg acpi_delay_time = 15000;
17197ccd5a2cSjsg vbi_time_out = 100000;
17207ccd5a2cSjsg
17217ccd5a2cSjsg reference_clock = radeon_get_xclk(rdev);
17227ccd5a2cSjsg
17237ccd5a2cSjsg vddc_dly = (voltage_response_time * reference_clock) / 1600;
17247ccd5a2cSjsg bb_dly = (backbias_response_time * reference_clock) / 1600;
17257ccd5a2cSjsg acpi_dly = (acpi_delay_time * reference_clock) / 1600;
17267ccd5a2cSjsg vbi_dly = (vbi_time_out * reference_clock) / 1600;
17277ccd5a2cSjsg
17287ccd5a2cSjsg rv770_write_smc_soft_register(rdev,
17297ccd5a2cSjsg RV770_SMC_SOFT_REGISTER_delay_vreg, vddc_dly);
17307ccd5a2cSjsg rv770_write_smc_soft_register(rdev,
17317ccd5a2cSjsg RV770_SMC_SOFT_REGISTER_delay_bbias, bb_dly);
17327ccd5a2cSjsg rv770_write_smc_soft_register(rdev,
17337ccd5a2cSjsg RV770_SMC_SOFT_REGISTER_delay_acpi, acpi_dly);
17347ccd5a2cSjsg rv770_write_smc_soft_register(rdev,
17357ccd5a2cSjsg RV770_SMC_SOFT_REGISTER_mclk_chg_timeout, vbi_dly);
17367ccd5a2cSjsg #if 0
17377ccd5a2cSjsg /* XXX look up hw revision */
17387ccd5a2cSjsg if (WEKIVA_A21)
17397ccd5a2cSjsg rv770_write_smc_soft_register(rdev,
17407ccd5a2cSjsg RV770_SMC_SOFT_REGISTER_baby_step_timer,
17417ccd5a2cSjsg 0x10);
17427ccd5a2cSjsg #endif
17437ccd5a2cSjsg }
17447ccd5a2cSjsg
rv770_program_dcodt_before_state_switch(struct radeon_device * rdev,struct radeon_ps * radeon_new_state,struct radeon_ps * radeon_current_state)17457ccd5a2cSjsg static void rv770_program_dcodt_before_state_switch(struct radeon_device *rdev,
17467ccd5a2cSjsg struct radeon_ps *radeon_new_state,
17477ccd5a2cSjsg struct radeon_ps *radeon_current_state)
17487ccd5a2cSjsg {
17497ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
17507ccd5a2cSjsg struct rv7xx_ps *new_state = rv770_get_ps(radeon_new_state);
17517ccd5a2cSjsg struct rv7xx_ps *current_state = rv770_get_ps(radeon_current_state);
17527ccd5a2cSjsg bool current_use_dc = false;
17537ccd5a2cSjsg bool new_use_dc = false;
17547ccd5a2cSjsg
17557ccd5a2cSjsg if (pi->mclk_odt_threshold == 0)
17567ccd5a2cSjsg return;
17577ccd5a2cSjsg
17587ccd5a2cSjsg if (current_state->high.mclk <= pi->mclk_odt_threshold)
17597ccd5a2cSjsg current_use_dc = true;
17607ccd5a2cSjsg
17617ccd5a2cSjsg if (new_state->high.mclk <= pi->mclk_odt_threshold)
17627ccd5a2cSjsg new_use_dc = true;
17637ccd5a2cSjsg
17647ccd5a2cSjsg if (current_use_dc == new_use_dc)
17657ccd5a2cSjsg return;
17667ccd5a2cSjsg
17677ccd5a2cSjsg if (!current_use_dc && new_use_dc)
17687ccd5a2cSjsg return;
17697ccd5a2cSjsg
17707ccd5a2cSjsg if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
17717ccd5a2cSjsg rv730_program_dcodt(rdev, new_use_dc);
17727ccd5a2cSjsg }
17737ccd5a2cSjsg
rv770_program_dcodt_after_state_switch(struct radeon_device * rdev,struct radeon_ps * radeon_new_state,struct radeon_ps * radeon_current_state)17747ccd5a2cSjsg static void rv770_program_dcodt_after_state_switch(struct radeon_device *rdev,
17757ccd5a2cSjsg struct radeon_ps *radeon_new_state,
17767ccd5a2cSjsg struct radeon_ps *radeon_current_state)
17777ccd5a2cSjsg {
17787ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
17797ccd5a2cSjsg struct rv7xx_ps *new_state = rv770_get_ps(radeon_new_state);
17807ccd5a2cSjsg struct rv7xx_ps *current_state = rv770_get_ps(radeon_current_state);
17817ccd5a2cSjsg bool current_use_dc = false;
17827ccd5a2cSjsg bool new_use_dc = false;
17837ccd5a2cSjsg
17847ccd5a2cSjsg if (pi->mclk_odt_threshold == 0)
17857ccd5a2cSjsg return;
17867ccd5a2cSjsg
17877ccd5a2cSjsg if (current_state->high.mclk <= pi->mclk_odt_threshold)
17887ccd5a2cSjsg current_use_dc = true;
17897ccd5a2cSjsg
17907ccd5a2cSjsg if (new_state->high.mclk <= pi->mclk_odt_threshold)
17917ccd5a2cSjsg new_use_dc = true;
17927ccd5a2cSjsg
17937ccd5a2cSjsg if (current_use_dc == new_use_dc)
17947ccd5a2cSjsg return;
17957ccd5a2cSjsg
17967ccd5a2cSjsg if (current_use_dc && !new_use_dc)
17977ccd5a2cSjsg return;
17987ccd5a2cSjsg
17997ccd5a2cSjsg if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
18007ccd5a2cSjsg rv730_program_dcodt(rdev, new_use_dc);
18017ccd5a2cSjsg }
18027ccd5a2cSjsg
rv770_retrieve_odt_values(struct radeon_device * rdev)18037ccd5a2cSjsg static void rv770_retrieve_odt_values(struct radeon_device *rdev)
18047ccd5a2cSjsg {
18057ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
18067ccd5a2cSjsg
18077ccd5a2cSjsg if (pi->mclk_odt_threshold == 0)
18087ccd5a2cSjsg return;
18097ccd5a2cSjsg
18107ccd5a2cSjsg if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
18117ccd5a2cSjsg rv730_get_odt_values(rdev);
18127ccd5a2cSjsg }
18137ccd5a2cSjsg
rv770_set_dpm_event_sources(struct radeon_device * rdev,u32 sources)18147ccd5a2cSjsg static void rv770_set_dpm_event_sources(struct radeon_device *rdev, u32 sources)
18157ccd5a2cSjsg {
18167ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
18177ccd5a2cSjsg bool want_thermal_protection;
18187ccd5a2cSjsg enum radeon_dpm_event_src dpm_event_src;
18197ccd5a2cSjsg
18207ccd5a2cSjsg switch (sources) {
18217ccd5a2cSjsg case 0:
18227ccd5a2cSjsg default:
18237ccd5a2cSjsg want_thermal_protection = false;
18247ccd5a2cSjsg break;
18257ccd5a2cSjsg case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL):
18267ccd5a2cSjsg want_thermal_protection = true;
18277ccd5a2cSjsg dpm_event_src = RADEON_DPM_EVENT_SRC_DIGITAL;
18287ccd5a2cSjsg break;
18297ccd5a2cSjsg
18307ccd5a2cSjsg case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL):
18317ccd5a2cSjsg want_thermal_protection = true;
18327ccd5a2cSjsg dpm_event_src = RADEON_DPM_EVENT_SRC_EXTERNAL;
18337ccd5a2cSjsg break;
18347ccd5a2cSjsg
18357ccd5a2cSjsg case ((1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL) |
18367ccd5a2cSjsg (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL)):
18377ccd5a2cSjsg want_thermal_protection = true;
18387ccd5a2cSjsg dpm_event_src = RADEON_DPM_EVENT_SRC_DIGIAL_OR_EXTERNAL;
18397ccd5a2cSjsg break;
18407ccd5a2cSjsg }
18417ccd5a2cSjsg
18427ccd5a2cSjsg if (want_thermal_protection) {
18437ccd5a2cSjsg WREG32_P(CG_THERMAL_CTRL, DPM_EVENT_SRC(dpm_event_src), ~DPM_EVENT_SRC_MASK);
18447ccd5a2cSjsg if (pi->thermal_protection)
18457ccd5a2cSjsg WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS);
18467ccd5a2cSjsg } else {
18477ccd5a2cSjsg WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS);
18487ccd5a2cSjsg }
18497ccd5a2cSjsg }
18507ccd5a2cSjsg
rv770_enable_auto_throttle_source(struct radeon_device * rdev,enum radeon_dpm_auto_throttle_src source,bool enable)18517ccd5a2cSjsg void rv770_enable_auto_throttle_source(struct radeon_device *rdev,
18527ccd5a2cSjsg enum radeon_dpm_auto_throttle_src source,
18537ccd5a2cSjsg bool enable)
18547ccd5a2cSjsg {
18557ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
18567ccd5a2cSjsg
18577ccd5a2cSjsg if (enable) {
18587ccd5a2cSjsg if (!(pi->active_auto_throttle_sources & (1 << source))) {
18597ccd5a2cSjsg pi->active_auto_throttle_sources |= 1 << source;
18607ccd5a2cSjsg rv770_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources);
18617ccd5a2cSjsg }
18627ccd5a2cSjsg } else {
18637ccd5a2cSjsg if (pi->active_auto_throttle_sources & (1 << source)) {
18647ccd5a2cSjsg pi->active_auto_throttle_sources &= ~(1 << source);
18657ccd5a2cSjsg rv770_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources);
18667ccd5a2cSjsg }
18677ccd5a2cSjsg }
18687ccd5a2cSjsg }
18697ccd5a2cSjsg
rv770_set_thermal_temperature_range(struct radeon_device * rdev,int min_temp,int max_temp)18707ccd5a2cSjsg static int rv770_set_thermal_temperature_range(struct radeon_device *rdev,
18717ccd5a2cSjsg int min_temp, int max_temp)
18727ccd5a2cSjsg {
18737ccd5a2cSjsg int low_temp = 0 * 1000;
18747ccd5a2cSjsg int high_temp = 255 * 1000;
18757ccd5a2cSjsg
18767ccd5a2cSjsg if (low_temp < min_temp)
18777ccd5a2cSjsg low_temp = min_temp;
18787ccd5a2cSjsg if (high_temp > max_temp)
18797ccd5a2cSjsg high_temp = max_temp;
18807ccd5a2cSjsg if (high_temp < low_temp) {
18817ccd5a2cSjsg DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp);
18827ccd5a2cSjsg return -EINVAL;
18837ccd5a2cSjsg }
18847ccd5a2cSjsg
18857ccd5a2cSjsg WREG32_P(CG_THERMAL_INT, DIG_THERM_INTH(high_temp / 1000), ~DIG_THERM_INTH_MASK);
18867ccd5a2cSjsg WREG32_P(CG_THERMAL_INT, DIG_THERM_INTL(low_temp / 1000), ~DIG_THERM_INTL_MASK);
18877ccd5a2cSjsg WREG32_P(CG_THERMAL_CTRL, DIG_THERM_DPM(high_temp / 1000), ~DIG_THERM_DPM_MASK);
18887ccd5a2cSjsg
18897ccd5a2cSjsg rdev->pm.dpm.thermal.min_temp = low_temp;
18907ccd5a2cSjsg rdev->pm.dpm.thermal.max_temp = high_temp;
18917ccd5a2cSjsg
18927ccd5a2cSjsg return 0;
18937ccd5a2cSjsg }
18947ccd5a2cSjsg
rv770_dpm_enable(struct radeon_device * rdev)18957ccd5a2cSjsg int rv770_dpm_enable(struct radeon_device *rdev)
18967ccd5a2cSjsg {
18977ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
18987ccd5a2cSjsg struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
18997ccd5a2cSjsg int ret;
19007ccd5a2cSjsg
19017ccd5a2cSjsg if (pi->gfx_clock_gating)
19027ccd5a2cSjsg rv770_restore_cgcg(rdev);
19037ccd5a2cSjsg
19047ccd5a2cSjsg if (rv770_dpm_enabled(rdev))
19057ccd5a2cSjsg return -EINVAL;
19067ccd5a2cSjsg
19077ccd5a2cSjsg if (pi->voltage_control) {
19087ccd5a2cSjsg rv770_enable_voltage_control(rdev, true);
19097ccd5a2cSjsg ret = rv770_construct_vddc_table(rdev);
19107ccd5a2cSjsg if (ret) {
19117ccd5a2cSjsg DRM_ERROR("rv770_construct_vddc_table failed\n");
19127ccd5a2cSjsg return ret;
19137ccd5a2cSjsg }
19147ccd5a2cSjsg }
19157ccd5a2cSjsg
19167ccd5a2cSjsg if (pi->dcodt)
19177ccd5a2cSjsg rv770_retrieve_odt_values(rdev);
19187ccd5a2cSjsg
19197ccd5a2cSjsg if (pi->mvdd_control) {
19207ccd5a2cSjsg ret = rv770_get_mvdd_configuration(rdev);
19217ccd5a2cSjsg if (ret) {
19227ccd5a2cSjsg DRM_ERROR("rv770_get_mvdd_configuration failed\n");
19237ccd5a2cSjsg return ret;
19247ccd5a2cSjsg }
19257ccd5a2cSjsg }
19267ccd5a2cSjsg
19277ccd5a2cSjsg if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS)
19287ccd5a2cSjsg rv770_enable_backbias(rdev, true);
19297ccd5a2cSjsg
19307ccd5a2cSjsg rv770_enable_spread_spectrum(rdev, true);
19317ccd5a2cSjsg
19327ccd5a2cSjsg if (pi->thermal_protection)
19337ccd5a2cSjsg rv770_enable_thermal_protection(rdev, true);
19347ccd5a2cSjsg
19357ccd5a2cSjsg rv770_program_mpll_timing_parameters(rdev);
19367ccd5a2cSjsg rv770_setup_bsp(rdev);
19377ccd5a2cSjsg rv770_program_git(rdev);
19387ccd5a2cSjsg rv770_program_tp(rdev);
19397ccd5a2cSjsg rv770_program_tpp(rdev);
19407ccd5a2cSjsg rv770_program_sstp(rdev);
19417ccd5a2cSjsg rv770_program_engine_speed_parameters(rdev);
19427ccd5a2cSjsg rv770_enable_display_gap(rdev);
19437ccd5a2cSjsg rv770_program_vc(rdev);
19447ccd5a2cSjsg
19457ccd5a2cSjsg if (pi->dynamic_pcie_gen2)
19467ccd5a2cSjsg rv770_enable_dynamic_pcie_gen2(rdev, true);
19477ccd5a2cSjsg
19487ccd5a2cSjsg ret = rv770_upload_firmware(rdev);
19497ccd5a2cSjsg if (ret) {
19507ccd5a2cSjsg DRM_ERROR("rv770_upload_firmware failed\n");
19517ccd5a2cSjsg return ret;
19527ccd5a2cSjsg }
19537ccd5a2cSjsg ret = rv770_init_smc_table(rdev, boot_ps);
19547ccd5a2cSjsg if (ret) {
19557ccd5a2cSjsg DRM_ERROR("rv770_init_smc_table failed\n");
19567ccd5a2cSjsg return ret;
19577ccd5a2cSjsg }
19587ccd5a2cSjsg
19597ccd5a2cSjsg rv770_program_response_times(rdev);
19607ccd5a2cSjsg r7xx_start_smc(rdev);
19617ccd5a2cSjsg
19627ccd5a2cSjsg if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
19637ccd5a2cSjsg rv730_start_dpm(rdev);
19647ccd5a2cSjsg else
19657ccd5a2cSjsg rv770_start_dpm(rdev);
19667ccd5a2cSjsg
19677ccd5a2cSjsg if (pi->gfx_clock_gating)
19687ccd5a2cSjsg rv770_gfx_clock_gating_enable(rdev, true);
19697ccd5a2cSjsg
19707ccd5a2cSjsg if (pi->mg_clock_gating)
19717ccd5a2cSjsg rv770_mg_clock_gating_enable(rdev, true);
19727ccd5a2cSjsg
19737ccd5a2cSjsg rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
19747ccd5a2cSjsg
19757ccd5a2cSjsg return 0;
19767ccd5a2cSjsg }
19777ccd5a2cSjsg
rv770_dpm_late_enable(struct radeon_device * rdev)19787ccd5a2cSjsg int rv770_dpm_late_enable(struct radeon_device *rdev)
19797ccd5a2cSjsg {
19807ccd5a2cSjsg int ret;
19817ccd5a2cSjsg
19827ccd5a2cSjsg if (rdev->irq.installed &&
19837ccd5a2cSjsg r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
19847ccd5a2cSjsg PPSMC_Result result;
19857ccd5a2cSjsg
19867ccd5a2cSjsg ret = rv770_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
19877ccd5a2cSjsg if (ret)
19887ccd5a2cSjsg return ret;
19897ccd5a2cSjsg rdev->irq.dpm_thermal = true;
19907ccd5a2cSjsg radeon_irq_set(rdev);
19917ccd5a2cSjsg result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt);
19927ccd5a2cSjsg
19937ccd5a2cSjsg if (result != PPSMC_Result_OK)
19947ccd5a2cSjsg DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");
19957ccd5a2cSjsg }
19967ccd5a2cSjsg
19977ccd5a2cSjsg return 0;
19987ccd5a2cSjsg }
19997ccd5a2cSjsg
rv770_dpm_disable(struct radeon_device * rdev)20007ccd5a2cSjsg void rv770_dpm_disable(struct radeon_device *rdev)
20017ccd5a2cSjsg {
20027ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
20037ccd5a2cSjsg
20047ccd5a2cSjsg if (!rv770_dpm_enabled(rdev))
20057ccd5a2cSjsg return;
20067ccd5a2cSjsg
20077ccd5a2cSjsg rv770_clear_vc(rdev);
20087ccd5a2cSjsg
20097ccd5a2cSjsg if (pi->thermal_protection)
20107ccd5a2cSjsg rv770_enable_thermal_protection(rdev, false);
20117ccd5a2cSjsg
20127ccd5a2cSjsg rv770_enable_spread_spectrum(rdev, false);
20137ccd5a2cSjsg
20147ccd5a2cSjsg if (pi->dynamic_pcie_gen2)
20157ccd5a2cSjsg rv770_enable_dynamic_pcie_gen2(rdev, false);
20167ccd5a2cSjsg
20177ccd5a2cSjsg if (rdev->irq.installed &&
20187ccd5a2cSjsg r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
20197ccd5a2cSjsg rdev->irq.dpm_thermal = false;
20207ccd5a2cSjsg radeon_irq_set(rdev);
20217ccd5a2cSjsg }
20227ccd5a2cSjsg
20237ccd5a2cSjsg if (pi->gfx_clock_gating)
20247ccd5a2cSjsg rv770_gfx_clock_gating_enable(rdev, false);
20257ccd5a2cSjsg
20267ccd5a2cSjsg if (pi->mg_clock_gating)
20277ccd5a2cSjsg rv770_mg_clock_gating_enable(rdev, false);
20287ccd5a2cSjsg
20297ccd5a2cSjsg if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
20307ccd5a2cSjsg rv730_stop_dpm(rdev);
20317ccd5a2cSjsg else
20327ccd5a2cSjsg rv770_stop_dpm(rdev);
20337ccd5a2cSjsg
20347ccd5a2cSjsg r7xx_stop_smc(rdev);
20357ccd5a2cSjsg rv770_reset_smio_status(rdev);
20367ccd5a2cSjsg }
20377ccd5a2cSjsg
rv770_dpm_set_power_state(struct radeon_device * rdev)20387ccd5a2cSjsg int rv770_dpm_set_power_state(struct radeon_device *rdev)
20397ccd5a2cSjsg {
20407ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
20417ccd5a2cSjsg struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps;
20427ccd5a2cSjsg struct radeon_ps *old_ps = rdev->pm.dpm.current_ps;
20437ccd5a2cSjsg int ret;
20447ccd5a2cSjsg
20457ccd5a2cSjsg ret = rv770_restrict_performance_levels_before_switch(rdev);
20467ccd5a2cSjsg if (ret) {
20477ccd5a2cSjsg DRM_ERROR("rv770_restrict_performance_levels_before_switch failed\n");
20487ccd5a2cSjsg return ret;
20497ccd5a2cSjsg }
20507ccd5a2cSjsg rv770_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
20517ccd5a2cSjsg ret = rv770_halt_smc(rdev);
20527ccd5a2cSjsg if (ret) {
20537ccd5a2cSjsg DRM_ERROR("rv770_halt_smc failed\n");
20547ccd5a2cSjsg return ret;
20557ccd5a2cSjsg }
20567ccd5a2cSjsg ret = rv770_upload_sw_state(rdev, new_ps);
20577ccd5a2cSjsg if (ret) {
20587ccd5a2cSjsg DRM_ERROR("rv770_upload_sw_state failed\n");
20597ccd5a2cSjsg return ret;
20607ccd5a2cSjsg }
20617ccd5a2cSjsg r7xx_program_memory_timing_parameters(rdev, new_ps);
20627ccd5a2cSjsg if (pi->dcodt)
20637ccd5a2cSjsg rv770_program_dcodt_before_state_switch(rdev, new_ps, old_ps);
20647ccd5a2cSjsg ret = rv770_resume_smc(rdev);
20657ccd5a2cSjsg if (ret) {
20667ccd5a2cSjsg DRM_ERROR("rv770_resume_smc failed\n");
20677ccd5a2cSjsg return ret;
20687ccd5a2cSjsg }
20697ccd5a2cSjsg ret = rv770_set_sw_state(rdev);
20707ccd5a2cSjsg if (ret) {
20717ccd5a2cSjsg DRM_ERROR("rv770_set_sw_state failed\n");
20727ccd5a2cSjsg return ret;
20737ccd5a2cSjsg }
20747ccd5a2cSjsg if (pi->dcodt)
20757ccd5a2cSjsg rv770_program_dcodt_after_state_switch(rdev, new_ps, old_ps);
20767ccd5a2cSjsg rv770_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
20777ccd5a2cSjsg
20787ccd5a2cSjsg return 0;
20797ccd5a2cSjsg }
20807ccd5a2cSjsg
20817ccd5a2cSjsg #if 0
20827ccd5a2cSjsg void rv770_dpm_reset_asic(struct radeon_device *rdev)
20837ccd5a2cSjsg {
20847ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
20857ccd5a2cSjsg struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
20867ccd5a2cSjsg
20877ccd5a2cSjsg rv770_restrict_performance_levels_before_switch(rdev);
20887ccd5a2cSjsg if (pi->dcodt)
20897ccd5a2cSjsg rv770_program_dcodt_before_state_switch(rdev, boot_ps, boot_ps);
20907ccd5a2cSjsg rv770_set_boot_state(rdev);
20917ccd5a2cSjsg if (pi->dcodt)
20927ccd5a2cSjsg rv770_program_dcodt_after_state_switch(rdev, boot_ps, boot_ps);
20937ccd5a2cSjsg }
20947ccd5a2cSjsg #endif
20957ccd5a2cSjsg
rv770_dpm_setup_asic(struct radeon_device * rdev)20967ccd5a2cSjsg void rv770_dpm_setup_asic(struct radeon_device *rdev)
20977ccd5a2cSjsg {
20987ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
20997ccd5a2cSjsg
21007ccd5a2cSjsg r7xx_read_clock_registers(rdev);
21017ccd5a2cSjsg rv770_read_voltage_smio_registers(rdev);
21027ccd5a2cSjsg rv770_get_memory_type(rdev);
21037ccd5a2cSjsg if (pi->dcodt)
21047ccd5a2cSjsg rv770_get_mclk_odt_threshold(rdev);
21057ccd5a2cSjsg rv770_get_pcie_gen2_status(rdev);
21067ccd5a2cSjsg
21077ccd5a2cSjsg rv770_enable_acpi_pm(rdev);
21087ccd5a2cSjsg
21097ccd5a2cSjsg if (radeon_aspm != 0) {
21107ccd5a2cSjsg if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s)
21117ccd5a2cSjsg rv770_enable_l0s(rdev);
21127ccd5a2cSjsg if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1)
21137ccd5a2cSjsg rv770_enable_l1(rdev);
21147ccd5a2cSjsg if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1)
21157ccd5a2cSjsg rv770_enable_pll_sleep_in_l1(rdev);
21167ccd5a2cSjsg }
21177ccd5a2cSjsg }
21187ccd5a2cSjsg
rv770_dpm_display_configuration_changed(struct radeon_device * rdev)21197ccd5a2cSjsg void rv770_dpm_display_configuration_changed(struct radeon_device *rdev)
21207ccd5a2cSjsg {
21217ccd5a2cSjsg rv770_program_display_gap(rdev);
21227ccd5a2cSjsg }
21237ccd5a2cSjsg
21247ccd5a2cSjsg union power_info {
21257ccd5a2cSjsg struct _ATOM_POWERPLAY_INFO info;
21267ccd5a2cSjsg struct _ATOM_POWERPLAY_INFO_V2 info_2;
21277ccd5a2cSjsg struct _ATOM_POWERPLAY_INFO_V3 info_3;
21287ccd5a2cSjsg struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
21297ccd5a2cSjsg struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
21307ccd5a2cSjsg struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
21317ccd5a2cSjsg };
21327ccd5a2cSjsg
21337ccd5a2cSjsg union pplib_clock_info {
21347ccd5a2cSjsg struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
21357ccd5a2cSjsg struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
21367ccd5a2cSjsg struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
21377ccd5a2cSjsg struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
21387ccd5a2cSjsg };
21397ccd5a2cSjsg
21407ccd5a2cSjsg union pplib_power_state {
21417ccd5a2cSjsg struct _ATOM_PPLIB_STATE v1;
21427ccd5a2cSjsg struct _ATOM_PPLIB_STATE_V2 v2;
21437ccd5a2cSjsg };
21447ccd5a2cSjsg
rv7xx_parse_pplib_non_clock_info(struct radeon_device * rdev,struct radeon_ps * rps,struct _ATOM_PPLIB_NONCLOCK_INFO * non_clock_info,u8 table_rev)21457ccd5a2cSjsg static void rv7xx_parse_pplib_non_clock_info(struct radeon_device *rdev,
21467ccd5a2cSjsg struct radeon_ps *rps,
21477ccd5a2cSjsg struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
21487ccd5a2cSjsg u8 table_rev)
21497ccd5a2cSjsg {
21507ccd5a2cSjsg rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
21517ccd5a2cSjsg rps->class = le16_to_cpu(non_clock_info->usClassification);
21527ccd5a2cSjsg rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
21537ccd5a2cSjsg
21547ccd5a2cSjsg if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
21557ccd5a2cSjsg rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
21567ccd5a2cSjsg rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
21577ccd5a2cSjsg } else {
21587ccd5a2cSjsg rps->vclk = 0;
21597ccd5a2cSjsg rps->dclk = 0;
21607ccd5a2cSjsg }
21617ccd5a2cSjsg
21627ccd5a2cSjsg if (r600_is_uvd_state(rps->class, rps->class2)) {
21637ccd5a2cSjsg if ((rps->vclk == 0) || (rps->dclk == 0)) {
21647ccd5a2cSjsg rps->vclk = RV770_DEFAULT_VCLK_FREQ;
21657ccd5a2cSjsg rps->dclk = RV770_DEFAULT_DCLK_FREQ;
21667ccd5a2cSjsg }
21677ccd5a2cSjsg }
21687ccd5a2cSjsg
21697ccd5a2cSjsg if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
21707ccd5a2cSjsg rdev->pm.dpm.boot_ps = rps;
21717ccd5a2cSjsg if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
21727ccd5a2cSjsg rdev->pm.dpm.uvd_ps = rps;
21737ccd5a2cSjsg }
21747ccd5a2cSjsg
rv7xx_parse_pplib_clock_info(struct radeon_device * rdev,struct radeon_ps * rps,int index,union pplib_clock_info * clock_info)21757ccd5a2cSjsg static void rv7xx_parse_pplib_clock_info(struct radeon_device *rdev,
21767ccd5a2cSjsg struct radeon_ps *rps, int index,
21777ccd5a2cSjsg union pplib_clock_info *clock_info)
21787ccd5a2cSjsg {
21797ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
21807ccd5a2cSjsg struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
21817ccd5a2cSjsg struct rv7xx_ps *ps = rv770_get_ps(rps);
21827ccd5a2cSjsg u32 sclk, mclk;
21837ccd5a2cSjsg struct rv7xx_pl *pl;
21847ccd5a2cSjsg
21857ccd5a2cSjsg switch (index) {
21867ccd5a2cSjsg case 0:
21877ccd5a2cSjsg pl = &ps->low;
21887ccd5a2cSjsg break;
21897ccd5a2cSjsg case 1:
21907ccd5a2cSjsg pl = &ps->medium;
21917ccd5a2cSjsg break;
21927ccd5a2cSjsg case 2:
21937ccd5a2cSjsg default:
21947ccd5a2cSjsg pl = &ps->high;
21957ccd5a2cSjsg break;
21967ccd5a2cSjsg }
21977ccd5a2cSjsg
21987ccd5a2cSjsg if (rdev->family >= CHIP_CEDAR) {
21997ccd5a2cSjsg sclk = le16_to_cpu(clock_info->evergreen.usEngineClockLow);
22007ccd5a2cSjsg sclk |= clock_info->evergreen.ucEngineClockHigh << 16;
22017ccd5a2cSjsg mclk = le16_to_cpu(clock_info->evergreen.usMemoryClockLow);
22027ccd5a2cSjsg mclk |= clock_info->evergreen.ucMemoryClockHigh << 16;
22037ccd5a2cSjsg
22047ccd5a2cSjsg pl->vddc = le16_to_cpu(clock_info->evergreen.usVDDC);
22057ccd5a2cSjsg pl->vddci = le16_to_cpu(clock_info->evergreen.usVDDCI);
22067ccd5a2cSjsg pl->flags = le32_to_cpu(clock_info->evergreen.ulFlags);
22077ccd5a2cSjsg } else {
22087ccd5a2cSjsg sclk = le16_to_cpu(clock_info->r600.usEngineClockLow);
22097ccd5a2cSjsg sclk |= clock_info->r600.ucEngineClockHigh << 16;
22107ccd5a2cSjsg mclk = le16_to_cpu(clock_info->r600.usMemoryClockLow);
22117ccd5a2cSjsg mclk |= clock_info->r600.ucMemoryClockHigh << 16;
22127ccd5a2cSjsg
22137ccd5a2cSjsg pl->vddc = le16_to_cpu(clock_info->r600.usVDDC);
22147ccd5a2cSjsg pl->flags = le32_to_cpu(clock_info->r600.ulFlags);
22157ccd5a2cSjsg }
22167ccd5a2cSjsg
22177ccd5a2cSjsg pl->mclk = mclk;
22187ccd5a2cSjsg pl->sclk = sclk;
22197ccd5a2cSjsg
22207ccd5a2cSjsg /* patch up vddc if necessary */
22217ccd5a2cSjsg if (pl->vddc == 0xff01) {
22227ccd5a2cSjsg if (pi->max_vddc)
22237ccd5a2cSjsg pl->vddc = pi->max_vddc;
22247ccd5a2cSjsg }
22257ccd5a2cSjsg
22267ccd5a2cSjsg if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) {
22277ccd5a2cSjsg pi->acpi_vddc = pl->vddc;
22287ccd5a2cSjsg if (rdev->family >= CHIP_CEDAR)
22297ccd5a2cSjsg eg_pi->acpi_vddci = pl->vddci;
22307ccd5a2cSjsg if (ps->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2)
22317ccd5a2cSjsg pi->acpi_pcie_gen2 = true;
22327ccd5a2cSjsg else
22337ccd5a2cSjsg pi->acpi_pcie_gen2 = false;
22347ccd5a2cSjsg }
22357ccd5a2cSjsg
22367ccd5a2cSjsg if (rps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) {
22377ccd5a2cSjsg if (rdev->family >= CHIP_BARTS) {
22387ccd5a2cSjsg eg_pi->ulv.supported = true;
22397ccd5a2cSjsg eg_pi->ulv.pl = pl;
22407ccd5a2cSjsg }
22417ccd5a2cSjsg }
22427ccd5a2cSjsg
22437ccd5a2cSjsg if (pi->min_vddc_in_table > pl->vddc)
22447ccd5a2cSjsg pi->min_vddc_in_table = pl->vddc;
22457ccd5a2cSjsg
22467ccd5a2cSjsg if (pi->max_vddc_in_table < pl->vddc)
22477ccd5a2cSjsg pi->max_vddc_in_table = pl->vddc;
22487ccd5a2cSjsg
22497ccd5a2cSjsg /* patch up boot state */
22507ccd5a2cSjsg if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
22517ccd5a2cSjsg u16 vddc, vddci, mvdd;
22527ccd5a2cSjsg radeon_atombios_get_default_voltages(rdev, &vddc, &vddci, &mvdd);
22537ccd5a2cSjsg pl->mclk = rdev->clock.default_mclk;
22547ccd5a2cSjsg pl->sclk = rdev->clock.default_sclk;
22557ccd5a2cSjsg pl->vddc = vddc;
22567ccd5a2cSjsg pl->vddci = vddci;
22577ccd5a2cSjsg }
22587ccd5a2cSjsg
22597ccd5a2cSjsg if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) ==
22607ccd5a2cSjsg ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) {
22617ccd5a2cSjsg rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk = pl->sclk;
22627ccd5a2cSjsg rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.mclk = pl->mclk;
22637ccd5a2cSjsg rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddc = pl->vddc;
22647ccd5a2cSjsg rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddci = pl->vddci;
22657ccd5a2cSjsg }
22667ccd5a2cSjsg }
22677ccd5a2cSjsg
rv7xx_parse_power_table(struct radeon_device * rdev)22687ccd5a2cSjsg int rv7xx_parse_power_table(struct radeon_device *rdev)
22697ccd5a2cSjsg {
22707ccd5a2cSjsg struct radeon_mode_info *mode_info = &rdev->mode_info;
22717ccd5a2cSjsg struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
22727ccd5a2cSjsg union pplib_power_state *power_state;
22737ccd5a2cSjsg int i, j;
22747ccd5a2cSjsg union pplib_clock_info *clock_info;
22757ccd5a2cSjsg union power_info *power_info;
22767ccd5a2cSjsg int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
22777ccd5a2cSjsg u16 data_offset;
22787ccd5a2cSjsg u8 frev, crev;
22797ccd5a2cSjsg struct rv7xx_ps *ps;
22807ccd5a2cSjsg
22817ccd5a2cSjsg if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
22827ccd5a2cSjsg &frev, &crev, &data_offset))
22837ccd5a2cSjsg return -EINVAL;
22847ccd5a2cSjsg power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
22857ccd5a2cSjsg
22867f4dd379Sjsg rdev->pm.dpm.ps = kcalloc(power_info->pplib.ucNumStates,
22877f4dd379Sjsg sizeof(struct radeon_ps),
22887f4dd379Sjsg GFP_KERNEL);
22897ccd5a2cSjsg if (!rdev->pm.dpm.ps)
22907ccd5a2cSjsg return -ENOMEM;
22917ccd5a2cSjsg
22927ccd5a2cSjsg for (i = 0; i < power_info->pplib.ucNumStates; i++) {
22937ccd5a2cSjsg power_state = (union pplib_power_state *)
22947ccd5a2cSjsg (mode_info->atom_context->bios + data_offset +
22957ccd5a2cSjsg le16_to_cpu(power_info->pplib.usStateArrayOffset) +
22967ccd5a2cSjsg i * power_info->pplib.ucStateEntrySize);
22977ccd5a2cSjsg non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
22987ccd5a2cSjsg (mode_info->atom_context->bios + data_offset +
22997ccd5a2cSjsg le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
23007ccd5a2cSjsg (power_state->v1.ucNonClockStateIndex *
23017ccd5a2cSjsg power_info->pplib.ucNonClockSize));
23027ccd5a2cSjsg if (power_info->pplib.ucStateEntrySize - 1) {
23037ccd5a2cSjsg u8 *idx;
23047ccd5a2cSjsg ps = kzalloc(sizeof(struct rv7xx_ps), GFP_KERNEL);
23057ccd5a2cSjsg if (ps == NULL) {
23067ccd5a2cSjsg kfree(rdev->pm.dpm.ps);
23077ccd5a2cSjsg return -ENOMEM;
23087ccd5a2cSjsg }
23097ccd5a2cSjsg rdev->pm.dpm.ps[i].ps_priv = ps;
23107ccd5a2cSjsg rv7xx_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
23117ccd5a2cSjsg non_clock_info,
23127ccd5a2cSjsg power_info->pplib.ucNonClockSize);
23137ccd5a2cSjsg idx = (u8 *)&power_state->v1.ucClockStateIndices[0];
23147ccd5a2cSjsg for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) {
23157ccd5a2cSjsg clock_info = (union pplib_clock_info *)
23167ccd5a2cSjsg (mode_info->atom_context->bios + data_offset +
23177ccd5a2cSjsg le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
23187ccd5a2cSjsg (idx[j] * power_info->pplib.ucClockInfoSize));
23197ccd5a2cSjsg rv7xx_parse_pplib_clock_info(rdev,
23207ccd5a2cSjsg &rdev->pm.dpm.ps[i], j,
23217ccd5a2cSjsg clock_info);
23227ccd5a2cSjsg }
23237ccd5a2cSjsg }
23247ccd5a2cSjsg }
23257ccd5a2cSjsg rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates;
23267ccd5a2cSjsg return 0;
23277ccd5a2cSjsg }
23287ccd5a2cSjsg
rv770_get_engine_memory_ss(struct radeon_device * rdev)23297ccd5a2cSjsg void rv770_get_engine_memory_ss(struct radeon_device *rdev)
23307ccd5a2cSjsg {
23317ccd5a2cSjsg struct rv7xx_power_info *pi = rv770_get_pi(rdev);
23327ccd5a2cSjsg struct radeon_atom_ss ss;
23337ccd5a2cSjsg
23347ccd5a2cSjsg pi->sclk_ss = radeon_atombios_get_asic_ss_info(rdev, &ss,
23357ccd5a2cSjsg ASIC_INTERNAL_ENGINE_SS, 0);
23367ccd5a2cSjsg pi->mclk_ss = radeon_atombios_get_asic_ss_info(rdev, &ss,
23377ccd5a2cSjsg ASIC_INTERNAL_MEMORY_SS, 0);
23387ccd5a2cSjsg
23397ccd5a2cSjsg if (pi->sclk_ss || pi->mclk_ss)
23407ccd5a2cSjsg pi->dynamic_ss = true;
23417ccd5a2cSjsg else
23427ccd5a2cSjsg pi->dynamic_ss = false;
23437ccd5a2cSjsg }
23447ccd5a2cSjsg
rv770_dpm_init(struct radeon_device * rdev)23457ccd5a2cSjsg int rv770_dpm_init(struct radeon_device *rdev)
23467ccd5a2cSjsg {
23477ccd5a2cSjsg struct rv7xx_power_info *pi;
23487ccd5a2cSjsg struct atom_clock_dividers dividers;
23497ccd5a2cSjsg int ret;
23507ccd5a2cSjsg
23517ccd5a2cSjsg pi = kzalloc(sizeof(struct rv7xx_power_info), GFP_KERNEL);
23527ccd5a2cSjsg if (pi == NULL)
23537ccd5a2cSjsg return -ENOMEM;
23547ccd5a2cSjsg rdev->pm.dpm.priv = pi;
23557ccd5a2cSjsg
23567ccd5a2cSjsg rv770_get_max_vddc(rdev);
23577ccd5a2cSjsg
23587ccd5a2cSjsg pi->acpi_vddc = 0;
23597ccd5a2cSjsg pi->min_vddc_in_table = 0;
23607ccd5a2cSjsg pi->max_vddc_in_table = 0;
23617ccd5a2cSjsg
23627ccd5a2cSjsg ret = r600_get_platform_caps(rdev);
23637ccd5a2cSjsg if (ret)
23647ccd5a2cSjsg return ret;
23657ccd5a2cSjsg
23667ccd5a2cSjsg ret = rv7xx_parse_power_table(rdev);
23677ccd5a2cSjsg if (ret)
23687ccd5a2cSjsg return ret;
23697ccd5a2cSjsg
23707ccd5a2cSjsg if (rdev->pm.dpm.voltage_response_time == 0)
23717ccd5a2cSjsg rdev->pm.dpm.voltage_response_time = R600_VOLTAGERESPONSETIME_DFLT;
23727ccd5a2cSjsg if (rdev->pm.dpm.backbias_response_time == 0)
23737ccd5a2cSjsg rdev->pm.dpm.backbias_response_time = R600_BACKBIASRESPONSETIME_DFLT;
23747ccd5a2cSjsg
23757ccd5a2cSjsg ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
23767ccd5a2cSjsg 0, false, ÷rs);
23777ccd5a2cSjsg if (ret)
23787ccd5a2cSjsg pi->ref_div = dividers.ref_div + 1;
23797ccd5a2cSjsg else
23807ccd5a2cSjsg pi->ref_div = R600_REFERENCEDIVIDER_DFLT;
23817ccd5a2cSjsg
23827ccd5a2cSjsg pi->mclk_strobe_mode_threshold = 30000;
23837ccd5a2cSjsg pi->mclk_edc_enable_threshold = 30000;
23847ccd5a2cSjsg
23857ccd5a2cSjsg pi->rlp = RV770_RLP_DFLT;
23867ccd5a2cSjsg pi->rmp = RV770_RMP_DFLT;
23877ccd5a2cSjsg pi->lhp = RV770_LHP_DFLT;
23887ccd5a2cSjsg pi->lmp = RV770_LMP_DFLT;
23897ccd5a2cSjsg
23907ccd5a2cSjsg pi->voltage_control =
23917ccd5a2cSjsg radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, 0);
23927ccd5a2cSjsg
23937ccd5a2cSjsg pi->mvdd_control =
23947ccd5a2cSjsg radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_MVDDC, 0);
23957ccd5a2cSjsg
23967ccd5a2cSjsg rv770_get_engine_memory_ss(rdev);
23977ccd5a2cSjsg
23987ccd5a2cSjsg pi->asi = RV770_ASI_DFLT;
23997ccd5a2cSjsg pi->pasi = RV770_HASI_DFLT;
24007ccd5a2cSjsg pi->vrc = RV770_VRC_DFLT;
24017ccd5a2cSjsg
24027ccd5a2cSjsg pi->power_gating = false;
24037ccd5a2cSjsg
24047ccd5a2cSjsg pi->gfx_clock_gating = true;
24057ccd5a2cSjsg
24067ccd5a2cSjsg pi->mg_clock_gating = true;
24077ccd5a2cSjsg pi->mgcgtssm = true;
24087ccd5a2cSjsg
24097ccd5a2cSjsg pi->dynamic_pcie_gen2 = true;
24107ccd5a2cSjsg
24117ccd5a2cSjsg if (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE)
24127ccd5a2cSjsg pi->thermal_protection = true;
24137ccd5a2cSjsg else
24147ccd5a2cSjsg pi->thermal_protection = false;
24157ccd5a2cSjsg
24167ccd5a2cSjsg pi->display_gap = true;
24177ccd5a2cSjsg
24187ccd5a2cSjsg if (rdev->flags & RADEON_IS_MOBILITY)
24197ccd5a2cSjsg pi->dcodt = true;
24207ccd5a2cSjsg else
24217ccd5a2cSjsg pi->dcodt = false;
24227ccd5a2cSjsg
24237ccd5a2cSjsg pi->ulps = true;
24247ccd5a2cSjsg
24257ccd5a2cSjsg pi->mclk_stutter_mode_threshold = 0;
24267ccd5a2cSjsg
24277ccd5a2cSjsg pi->sram_end = SMC_RAM_END;
24287ccd5a2cSjsg pi->state_table_start = RV770_SMC_TABLE_ADDRESS;
24297ccd5a2cSjsg pi->soft_regs_start = RV770_SMC_SOFT_REGISTERS_START;
24307ccd5a2cSjsg
24317ccd5a2cSjsg return 0;
24327ccd5a2cSjsg }
24337ccd5a2cSjsg
rv770_dpm_print_power_state(struct radeon_device * rdev,struct radeon_ps * rps)24347ccd5a2cSjsg void rv770_dpm_print_power_state(struct radeon_device *rdev,
24357ccd5a2cSjsg struct radeon_ps *rps)
24367ccd5a2cSjsg {
24377ccd5a2cSjsg struct rv7xx_ps *ps = rv770_get_ps(rps);
24387ccd5a2cSjsg struct rv7xx_pl *pl;
24397ccd5a2cSjsg
24407ccd5a2cSjsg r600_dpm_print_class_info(rps->class, rps->class2);
24417ccd5a2cSjsg r600_dpm_print_cap_info(rps->caps);
24427ccd5a2cSjsg printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
24437ccd5a2cSjsg if (rdev->family >= CHIP_CEDAR) {
24447ccd5a2cSjsg pl = &ps->low;
24457ccd5a2cSjsg printk("\t\tpower level 0 sclk: %u mclk: %u vddc: %u vddci: %u\n",
24467ccd5a2cSjsg pl->sclk, pl->mclk, pl->vddc, pl->vddci);
24477ccd5a2cSjsg pl = &ps->medium;
24487ccd5a2cSjsg printk("\t\tpower level 1 sclk: %u mclk: %u vddc: %u vddci: %u\n",
24497ccd5a2cSjsg pl->sclk, pl->mclk, pl->vddc, pl->vddci);
24507ccd5a2cSjsg pl = &ps->high;
24517ccd5a2cSjsg printk("\t\tpower level 2 sclk: %u mclk: %u vddc: %u vddci: %u\n",
24527ccd5a2cSjsg pl->sclk, pl->mclk, pl->vddc, pl->vddci);
24537ccd5a2cSjsg } else {
24547ccd5a2cSjsg pl = &ps->low;
24557ccd5a2cSjsg printk("\t\tpower level 0 sclk: %u mclk: %u vddc: %u\n",
24567ccd5a2cSjsg pl->sclk, pl->mclk, pl->vddc);
24577ccd5a2cSjsg pl = &ps->medium;
24587ccd5a2cSjsg printk("\t\tpower level 1 sclk: %u mclk: %u vddc: %u\n",
24597ccd5a2cSjsg pl->sclk, pl->mclk, pl->vddc);
24607ccd5a2cSjsg pl = &ps->high;
24617ccd5a2cSjsg printk("\t\tpower level 2 sclk: %u mclk: %u vddc: %u\n",
24627ccd5a2cSjsg pl->sclk, pl->mclk, pl->vddc);
24637ccd5a2cSjsg }
24647ccd5a2cSjsg r600_dpm_print_ps_status(rdev, rps);
24657ccd5a2cSjsg }
24667ccd5a2cSjsg
rv770_dpm_debugfs_print_current_performance_level(struct radeon_device * rdev,struct seq_file * m)24677ccd5a2cSjsg void rv770_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
24687ccd5a2cSjsg struct seq_file *m)
24697ccd5a2cSjsg {
24707ccd5a2cSjsg struct radeon_ps *rps = rdev->pm.dpm.current_ps;
24717ccd5a2cSjsg struct rv7xx_ps *ps = rv770_get_ps(rps);
24727ccd5a2cSjsg struct rv7xx_pl *pl;
24737ccd5a2cSjsg u32 current_index =
24747ccd5a2cSjsg (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
24757ccd5a2cSjsg CURRENT_PROFILE_INDEX_SHIFT;
24767ccd5a2cSjsg
24777ccd5a2cSjsg if (current_index > 2) {
24787ccd5a2cSjsg seq_printf(m, "invalid dpm profile %d\n", current_index);
24797ccd5a2cSjsg } else {
24807ccd5a2cSjsg if (current_index == 0)
24817ccd5a2cSjsg pl = &ps->low;
24827ccd5a2cSjsg else if (current_index == 1)
24837ccd5a2cSjsg pl = &ps->medium;
24847ccd5a2cSjsg else /* current_index == 2 */
24857ccd5a2cSjsg pl = &ps->high;
24867ccd5a2cSjsg seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
24877ccd5a2cSjsg if (rdev->family >= CHIP_CEDAR) {
24887ccd5a2cSjsg seq_printf(m, "power level %d sclk: %u mclk: %u vddc: %u vddci: %u\n",
24897ccd5a2cSjsg current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci);
24907ccd5a2cSjsg } else {
24917ccd5a2cSjsg seq_printf(m, "power level %d sclk: %u mclk: %u vddc: %u\n",
24927ccd5a2cSjsg current_index, pl->sclk, pl->mclk, pl->vddc);
24937ccd5a2cSjsg }
24947ccd5a2cSjsg }
24957ccd5a2cSjsg }
24967ccd5a2cSjsg
rv770_dpm_get_current_sclk(struct radeon_device * rdev)24977ccd5a2cSjsg u32 rv770_dpm_get_current_sclk(struct radeon_device *rdev)
24987ccd5a2cSjsg {
24997ccd5a2cSjsg struct radeon_ps *rps = rdev->pm.dpm.current_ps;
25007ccd5a2cSjsg struct rv7xx_ps *ps = rv770_get_ps(rps);
25017ccd5a2cSjsg struct rv7xx_pl *pl;
25027ccd5a2cSjsg u32 current_index =
25037ccd5a2cSjsg (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
25047ccd5a2cSjsg CURRENT_PROFILE_INDEX_SHIFT;
25057ccd5a2cSjsg
25067ccd5a2cSjsg if (current_index > 2) {
25077ccd5a2cSjsg return 0;
25087ccd5a2cSjsg } else {
25097ccd5a2cSjsg if (current_index == 0)
25107ccd5a2cSjsg pl = &ps->low;
25117ccd5a2cSjsg else if (current_index == 1)
25127ccd5a2cSjsg pl = &ps->medium;
25137ccd5a2cSjsg else /* current_index == 2 */
25147ccd5a2cSjsg pl = &ps->high;
25157ccd5a2cSjsg return pl->sclk;
25167ccd5a2cSjsg }
25177ccd5a2cSjsg }
25187ccd5a2cSjsg
rv770_dpm_get_current_mclk(struct radeon_device * rdev)25197ccd5a2cSjsg u32 rv770_dpm_get_current_mclk(struct radeon_device *rdev)
25207ccd5a2cSjsg {
25217ccd5a2cSjsg struct radeon_ps *rps = rdev->pm.dpm.current_ps;
25227ccd5a2cSjsg struct rv7xx_ps *ps = rv770_get_ps(rps);
25237ccd5a2cSjsg struct rv7xx_pl *pl;
25247ccd5a2cSjsg u32 current_index =
25257ccd5a2cSjsg (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
25267ccd5a2cSjsg CURRENT_PROFILE_INDEX_SHIFT;
25277ccd5a2cSjsg
25287ccd5a2cSjsg if (current_index > 2) {
25297ccd5a2cSjsg return 0;
25307ccd5a2cSjsg } else {
25317ccd5a2cSjsg if (current_index == 0)
25327ccd5a2cSjsg pl = &ps->low;
25337ccd5a2cSjsg else if (current_index == 1)
25347ccd5a2cSjsg pl = &ps->medium;
25357ccd5a2cSjsg else /* current_index == 2 */
25367ccd5a2cSjsg pl = &ps->high;
25377ccd5a2cSjsg return pl->mclk;
25387ccd5a2cSjsg }
25397ccd5a2cSjsg }
25407ccd5a2cSjsg
rv770_dpm_fini(struct radeon_device * rdev)25417ccd5a2cSjsg void rv770_dpm_fini(struct radeon_device *rdev)
25427ccd5a2cSjsg {
25437ccd5a2cSjsg int i;
25447ccd5a2cSjsg
25457ccd5a2cSjsg for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
25467ccd5a2cSjsg kfree(rdev->pm.dpm.ps[i].ps_priv);
25477ccd5a2cSjsg }
25487ccd5a2cSjsg kfree(rdev->pm.dpm.ps);
25497ccd5a2cSjsg kfree(rdev->pm.dpm.priv);
25507ccd5a2cSjsg }
25517ccd5a2cSjsg
rv770_dpm_get_sclk(struct radeon_device * rdev,bool low)25527ccd5a2cSjsg u32 rv770_dpm_get_sclk(struct radeon_device *rdev, bool low)
25537ccd5a2cSjsg {
25547ccd5a2cSjsg struct rv7xx_ps *requested_state = rv770_get_ps(rdev->pm.dpm.requested_ps);
25557ccd5a2cSjsg
25567ccd5a2cSjsg if (low)
25577ccd5a2cSjsg return requested_state->low.sclk;
25587ccd5a2cSjsg else
25597ccd5a2cSjsg return requested_state->high.sclk;
25607ccd5a2cSjsg }
25617ccd5a2cSjsg
rv770_dpm_get_mclk(struct radeon_device * rdev,bool low)25627ccd5a2cSjsg u32 rv770_dpm_get_mclk(struct radeon_device *rdev, bool low)
25637ccd5a2cSjsg {
25647ccd5a2cSjsg struct rv7xx_ps *requested_state = rv770_get_ps(rdev->pm.dpm.requested_ps);
25657ccd5a2cSjsg
25667ccd5a2cSjsg if (low)
25677ccd5a2cSjsg return requested_state->low.mclk;
25687ccd5a2cSjsg else
25697ccd5a2cSjsg return requested_state->high.mclk;
25707ccd5a2cSjsg }
25717ccd5a2cSjsg
rv770_dpm_vblank_too_short(struct radeon_device * rdev)25727ccd5a2cSjsg bool rv770_dpm_vblank_too_short(struct radeon_device *rdev)
25737ccd5a2cSjsg {
25747ccd5a2cSjsg u32 vblank_time = r600_dpm_get_vblank_time(rdev);
25757ccd5a2cSjsg u32 switch_limit = 200; /* 300 */
25767ccd5a2cSjsg
25777ccd5a2cSjsg /* RV770 */
25787ccd5a2cSjsg /* mclk switching doesn't seem to work reliably on desktop RV770s */
25797ccd5a2cSjsg if ((rdev->family == CHIP_RV770) &&
25807ccd5a2cSjsg !(rdev->flags & RADEON_IS_MOBILITY))
25817ccd5a2cSjsg switch_limit = 0xffffffff; /* disable mclk switching */
25827ccd5a2cSjsg
25837ccd5a2cSjsg if (vblank_time < switch_limit)
25847ccd5a2cSjsg return true;
25857ccd5a2cSjsg else
25867ccd5a2cSjsg return false;
25877ccd5a2cSjsg
25887ccd5a2cSjsg }
2589