0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025 #include "radeon.h"
0026 #include "rv740d.h"
0027 #include "r600_dpm.h"
0028 #include "rv770.h"
0029 #include "rv770_dpm.h"
0030 #include "atom.h"
0031
0032 u32 rv740_get_decoded_reference_divider(u32 encoded_ref)
0033 {
0034 u32 ref = 0;
0035
0036 switch (encoded_ref) {
0037 case 0:
0038 ref = 1;
0039 break;
0040 case 16:
0041 ref = 2;
0042 break;
0043 case 17:
0044 ref = 3;
0045 break;
0046 case 18:
0047 ref = 2;
0048 break;
0049 case 19:
0050 ref = 3;
0051 break;
0052 case 20:
0053 ref = 4;
0054 break;
0055 case 21:
0056 ref = 5;
0057 break;
0058 default:
0059 DRM_ERROR("Invalid encoded Reference Divider\n");
0060 ref = 0;
0061 break;
0062 }
0063
0064 return ref;
0065 }
0066
0067 struct dll_speed_setting {
0068 u16 min;
0069 u16 max;
0070 u32 dll_speed;
0071 };
0072
0073 static struct dll_speed_setting dll_speed_table[16] =
0074 {
0075 { 270, 320, 0x0f },
0076 { 240, 270, 0x0e },
0077 { 200, 240, 0x0d },
0078 { 180, 200, 0x0c },
0079 { 160, 180, 0x0b },
0080 { 140, 160, 0x0a },
0081 { 120, 140, 0x09 },
0082 { 110, 120, 0x08 },
0083 { 95, 110, 0x07 },
0084 { 85, 95, 0x06 },
0085 { 78, 85, 0x05 },
0086 { 70, 78, 0x04 },
0087 { 65, 70, 0x03 },
0088 { 60, 65, 0x02 },
0089 { 42, 60, 0x01 },
0090 { 00, 42, 0x00 }
0091 };
0092
0093 u32 rv740_get_dll_speed(bool is_gddr5, u32 memory_clock)
0094 {
0095 int i;
0096 u32 factor;
0097 u16 data_rate;
0098
0099 if (is_gddr5)
0100 factor = 4;
0101 else
0102 factor = 2;
0103
0104 data_rate = (u16)(memory_clock * factor / 1000);
0105
0106 if (data_rate < dll_speed_table[0].max) {
0107 for (i = 0; i < 16; i++) {
0108 if (data_rate > dll_speed_table[i].min &&
0109 data_rate <= dll_speed_table[i].max)
0110 return dll_speed_table[i].dll_speed;
0111 }
0112 }
0113
0114 DRM_DEBUG_KMS("Target MCLK greater than largest MCLK in DLL speed table\n");
0115
0116 return 0x0f;
0117 }
0118
0119 int rv740_populate_sclk_value(struct radeon_device *rdev, u32 engine_clock,
0120 RV770_SMC_SCLK_VALUE *sclk)
0121 {
0122 struct rv7xx_power_info *pi = rv770_get_pi(rdev);
0123 struct atom_clock_dividers dividers;
0124 u32 spll_func_cntl = pi->clk_regs.rv770.cg_spll_func_cntl;
0125 u32 spll_func_cntl_2 = pi->clk_regs.rv770.cg_spll_func_cntl_2;
0126 u32 spll_func_cntl_3 = pi->clk_regs.rv770.cg_spll_func_cntl_3;
0127 u32 cg_spll_spread_spectrum = pi->clk_regs.rv770.cg_spll_spread_spectrum;
0128 u32 cg_spll_spread_spectrum_2 = pi->clk_regs.rv770.cg_spll_spread_spectrum_2;
0129 u64 tmp;
0130 u32 reference_clock = rdev->clock.spll.reference_freq;
0131 u32 reference_divider;
0132 u32 fbdiv;
0133 int ret;
0134
0135 ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
0136 engine_clock, false, ÷rs);
0137 if (ret)
0138 return ret;
0139
0140 reference_divider = 1 + dividers.ref_div;
0141
0142 tmp = (u64) engine_clock * reference_divider * dividers.post_div * 16384;
0143 do_div(tmp, reference_clock);
0144 fbdiv = (u32) tmp;
0145
0146 spll_func_cntl &= ~(SPLL_PDIV_A_MASK | SPLL_REF_DIV_MASK);
0147 spll_func_cntl |= SPLL_REF_DIV(dividers.ref_div);
0148 spll_func_cntl |= SPLL_PDIV_A(dividers.post_div);
0149
0150 spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
0151 spll_func_cntl_2 |= SCLK_MUX_SEL(2);
0152
0153 spll_func_cntl_3 &= ~SPLL_FB_DIV_MASK;
0154 spll_func_cntl_3 |= SPLL_FB_DIV(fbdiv);
0155 spll_func_cntl_3 |= SPLL_DITHEN;
0156
0157 if (pi->sclk_ss) {
0158 struct radeon_atom_ss ss;
0159 u32 vco_freq = engine_clock * dividers.post_div;
0160
0161 if (radeon_atombios_get_asic_ss_info(rdev, &ss,
0162 ASIC_INTERNAL_ENGINE_SS, vco_freq)) {
0163 u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate);
0164 u32 clk_v = 4 * ss.percentage * fbdiv / (clk_s * 10000);
0165
0166 cg_spll_spread_spectrum &= ~CLK_S_MASK;
0167 cg_spll_spread_spectrum |= CLK_S(clk_s);
0168 cg_spll_spread_spectrum |= SSEN;
0169
0170 cg_spll_spread_spectrum_2 &= ~CLK_V_MASK;
0171 cg_spll_spread_spectrum_2 |= CLK_V(clk_v);
0172 }
0173 }
0174
0175 sclk->sclk_value = cpu_to_be32(engine_clock);
0176 sclk->vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl);
0177 sclk->vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2);
0178 sclk->vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3);
0179 sclk->vCG_SPLL_SPREAD_SPECTRUM = cpu_to_be32(cg_spll_spread_spectrum);
0180 sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cpu_to_be32(cg_spll_spread_spectrum_2);
0181
0182 return 0;
0183 }
0184
0185 int rv740_populate_mclk_value(struct radeon_device *rdev,
0186 u32 engine_clock, u32 memory_clock,
0187 RV7XX_SMC_MCLK_VALUE *mclk)
0188 {
0189 struct rv7xx_power_info *pi = rv770_get_pi(rdev);
0190 u32 mpll_ad_func_cntl = pi->clk_regs.rv770.mpll_ad_func_cntl;
0191 u32 mpll_ad_func_cntl_2 = pi->clk_regs.rv770.mpll_ad_func_cntl_2;
0192 u32 mpll_dq_func_cntl = pi->clk_regs.rv770.mpll_dq_func_cntl;
0193 u32 mpll_dq_func_cntl_2 = pi->clk_regs.rv770.mpll_dq_func_cntl_2;
0194 u32 mclk_pwrmgt_cntl = pi->clk_regs.rv770.mclk_pwrmgt_cntl;
0195 u32 dll_cntl = pi->clk_regs.rv770.dll_cntl;
0196 u32 mpll_ss1 = pi->clk_regs.rv770.mpll_ss1;
0197 u32 mpll_ss2 = pi->clk_regs.rv770.mpll_ss2;
0198 struct atom_clock_dividers dividers;
0199 u32 ibias;
0200 u32 dll_speed;
0201 int ret;
0202
0203 ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM,
0204 memory_clock, false, ÷rs);
0205 if (ret)
0206 return ret;
0207
0208 ibias = rv770_map_clkf_to_ibias(rdev, dividers.whole_fb_div);
0209
0210 mpll_ad_func_cntl &= ~(CLKR_MASK |
0211 YCLK_POST_DIV_MASK |
0212 CLKF_MASK |
0213 CLKFRAC_MASK |
0214 IBIAS_MASK);
0215 mpll_ad_func_cntl |= CLKR(dividers.ref_div);
0216 mpll_ad_func_cntl |= YCLK_POST_DIV(dividers.post_div);
0217 mpll_ad_func_cntl |= CLKF(dividers.whole_fb_div);
0218 mpll_ad_func_cntl |= CLKFRAC(dividers.frac_fb_div);
0219 mpll_ad_func_cntl |= IBIAS(ibias);
0220
0221 if (dividers.vco_mode)
0222 mpll_ad_func_cntl_2 |= VCO_MODE;
0223 else
0224 mpll_ad_func_cntl_2 &= ~VCO_MODE;
0225
0226 if (pi->mem_gddr5) {
0227 mpll_dq_func_cntl &= ~(CLKR_MASK |
0228 YCLK_POST_DIV_MASK |
0229 CLKF_MASK |
0230 CLKFRAC_MASK |
0231 IBIAS_MASK);
0232 mpll_dq_func_cntl |= CLKR(dividers.ref_div);
0233 mpll_dq_func_cntl |= YCLK_POST_DIV(dividers.post_div);
0234 mpll_dq_func_cntl |= CLKF(dividers.whole_fb_div);
0235 mpll_dq_func_cntl |= CLKFRAC(dividers.frac_fb_div);
0236 mpll_dq_func_cntl |= IBIAS(ibias);
0237
0238 if (dividers.vco_mode)
0239 mpll_dq_func_cntl_2 |= VCO_MODE;
0240 else
0241 mpll_dq_func_cntl_2 &= ~VCO_MODE;
0242 }
0243
0244 if (pi->mclk_ss) {
0245 struct radeon_atom_ss ss;
0246 u32 vco_freq = memory_clock * dividers.post_div;
0247
0248 if (radeon_atombios_get_asic_ss_info(rdev, &ss,
0249 ASIC_INTERNAL_MEMORY_SS, vco_freq)) {
0250 u32 reference_clock = rdev->clock.mpll.reference_freq;
0251 u32 decoded_ref = rv740_get_decoded_reference_divider(dividers.ref_div);
0252 u32 clk_s = reference_clock * 5 / (decoded_ref * ss.rate);
0253 u32 clk_v = 0x40000 * ss.percentage *
0254 (dividers.whole_fb_div + (dividers.frac_fb_div / 8)) / (clk_s * 10000);
0255
0256 mpll_ss1 &= ~CLKV_MASK;
0257 mpll_ss1 |= CLKV(clk_v);
0258
0259 mpll_ss2 &= ~CLKS_MASK;
0260 mpll_ss2 |= CLKS(clk_s);
0261 }
0262 }
0263
0264 dll_speed = rv740_get_dll_speed(pi->mem_gddr5,
0265 memory_clock);
0266
0267 mclk_pwrmgt_cntl &= ~DLL_SPEED_MASK;
0268 mclk_pwrmgt_cntl |= DLL_SPEED(dll_speed);
0269
0270 mclk->mclk770.mclk_value = cpu_to_be32(memory_clock);
0271 mclk->mclk770.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
0272 mclk->mclk770.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2);
0273 mclk->mclk770.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
0274 mclk->mclk770.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2);
0275 mclk->mclk770.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
0276 mclk->mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl);
0277 mclk->mclk770.vMPLL_SS = cpu_to_be32(mpll_ss1);
0278 mclk->mclk770.vMPLL_SS2 = cpu_to_be32(mpll_ss2);
0279
0280 return 0;
0281 }
0282
0283 void rv740_read_clock_registers(struct radeon_device *rdev)
0284 {
0285 struct rv7xx_power_info *pi = rv770_get_pi(rdev);
0286
0287 pi->clk_regs.rv770.cg_spll_func_cntl =
0288 RREG32(CG_SPLL_FUNC_CNTL);
0289 pi->clk_regs.rv770.cg_spll_func_cntl_2 =
0290 RREG32(CG_SPLL_FUNC_CNTL_2);
0291 pi->clk_regs.rv770.cg_spll_func_cntl_3 =
0292 RREG32(CG_SPLL_FUNC_CNTL_3);
0293 pi->clk_regs.rv770.cg_spll_spread_spectrum =
0294 RREG32(CG_SPLL_SPREAD_SPECTRUM);
0295 pi->clk_regs.rv770.cg_spll_spread_spectrum_2 =
0296 RREG32(CG_SPLL_SPREAD_SPECTRUM_2);
0297
0298 pi->clk_regs.rv770.mpll_ad_func_cntl =
0299 RREG32(MPLL_AD_FUNC_CNTL);
0300 pi->clk_regs.rv770.mpll_ad_func_cntl_2 =
0301 RREG32(MPLL_AD_FUNC_CNTL_2);
0302 pi->clk_regs.rv770.mpll_dq_func_cntl =
0303 RREG32(MPLL_DQ_FUNC_CNTL);
0304 pi->clk_regs.rv770.mpll_dq_func_cntl_2 =
0305 RREG32(MPLL_DQ_FUNC_CNTL_2);
0306 pi->clk_regs.rv770.mclk_pwrmgt_cntl =
0307 RREG32(MCLK_PWRMGT_CNTL);
0308 pi->clk_regs.rv770.dll_cntl = RREG32(DLL_CNTL);
0309 pi->clk_regs.rv770.mpll_ss1 = RREG32(MPLL_SS1);
0310 pi->clk_regs.rv770.mpll_ss2 = RREG32(MPLL_SS2);
0311 }
0312
0313 int rv740_populate_smc_acpi_state(struct radeon_device *rdev,
0314 RV770_SMC_STATETABLE *table)
0315 {
0316 struct rv7xx_power_info *pi = rv770_get_pi(rdev);
0317 u32 mpll_ad_func_cntl = pi->clk_regs.rv770.mpll_ad_func_cntl;
0318 u32 mpll_ad_func_cntl_2 = pi->clk_regs.rv770.mpll_ad_func_cntl_2;
0319 u32 mpll_dq_func_cntl = pi->clk_regs.rv770.mpll_dq_func_cntl;
0320 u32 mpll_dq_func_cntl_2 = pi->clk_regs.rv770.mpll_dq_func_cntl_2;
0321 u32 spll_func_cntl = pi->clk_regs.rv770.cg_spll_func_cntl;
0322 u32 spll_func_cntl_2 = pi->clk_regs.rv770.cg_spll_func_cntl_2;
0323 u32 spll_func_cntl_3 = pi->clk_regs.rv770.cg_spll_func_cntl_3;
0324 u32 mclk_pwrmgt_cntl = pi->clk_regs.rv770.mclk_pwrmgt_cntl;
0325 u32 dll_cntl = pi->clk_regs.rv770.dll_cntl;
0326
0327 table->ACPIState = table->initialState;
0328
0329 table->ACPIState.flags &= ~PPSMC_SWSTATE_FLAG_DC;
0330
0331 if (pi->acpi_vddc) {
0332 rv770_populate_vddc_value(rdev, pi->acpi_vddc,
0333 &table->ACPIState.levels[0].vddc);
0334 table->ACPIState.levels[0].gen2PCIE =
0335 pi->pcie_gen2 ?
0336 pi->acpi_pcie_gen2 : 0;
0337 table->ACPIState.levels[0].gen2XSP =
0338 pi->acpi_pcie_gen2;
0339 } else {
0340 rv770_populate_vddc_value(rdev, pi->min_vddc_in_table,
0341 &table->ACPIState.levels[0].vddc);
0342 table->ACPIState.levels[0].gen2PCIE = 0;
0343 }
0344
0345 mpll_ad_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN;
0346
0347 mpll_dq_func_cntl_2 |= BYPASS | BIAS_GEN_PDNB | RESET_EN;
0348
0349 mclk_pwrmgt_cntl |= (MRDCKA0_RESET |
0350 MRDCKA1_RESET |
0351 MRDCKB0_RESET |
0352 MRDCKB1_RESET |
0353 MRDCKC0_RESET |
0354 MRDCKC1_RESET |
0355 MRDCKD0_RESET |
0356 MRDCKD1_RESET);
0357
0358 dll_cntl |= (MRDCKA0_BYPASS |
0359 MRDCKA1_BYPASS |
0360 MRDCKB0_BYPASS |
0361 MRDCKB1_BYPASS |
0362 MRDCKC0_BYPASS |
0363 MRDCKC1_BYPASS |
0364 MRDCKD0_BYPASS |
0365 MRDCKD1_BYPASS);
0366
0367 spll_func_cntl |= SPLL_RESET | SPLL_SLEEP | SPLL_BYPASS_EN;
0368
0369 spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
0370 spll_func_cntl_2 |= SCLK_MUX_SEL(4);
0371
0372 table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
0373 table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2);
0374 table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
0375 table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2);
0376 table->ACPIState.levels[0].mclk.mclk770.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
0377 table->ACPIState.levels[0].mclk.mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl);
0378
0379 table->ACPIState.levels[0].mclk.mclk770.mclk_value = 0;
0380
0381 table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl);
0382 table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2);
0383 table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3);
0384
0385 table->ACPIState.levels[0].sclk.sclk_value = 0;
0386
0387 table->ACPIState.levels[1] = table->ACPIState.levels[0];
0388 table->ACPIState.levels[2] = table->ACPIState.levels[0];
0389
0390 rv770_populate_mvdd_value(rdev, 0, &table->ACPIState.levels[0].mvdd);
0391
0392 return 0;
0393 }
0394
0395 void rv740_enable_mclk_spread_spectrum(struct radeon_device *rdev,
0396 bool enable)
0397 {
0398 if (enable)
0399 WREG32_P(MPLL_CNTL_MODE, SS_SSEN, ~SS_SSEN);
0400 else
0401 WREG32_P(MPLL_CNTL_MODE, 0, ~SS_SSEN);
0402 }
0403
0404 u8 rv740_get_mclk_frequency_ratio(u32 memory_clock)
0405 {
0406 u8 mc_para_index;
0407
0408 if ((memory_clock < 10000) || (memory_clock > 47500))
0409 mc_para_index = 0x00;
0410 else
0411 mc_para_index = (u8)((memory_clock - 10000) / 2500);
0412
0413 return mc_para_index;
0414 }