Home | History | Annotate | Line # | Download | only in radeon
radeon_rv740_dpm.c revision 1.1
      1 /*	$NetBSD: radeon_rv740_dpm.c,v 1.1 2018/08/27 14:38:20 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright 2011 Advanced Micro Devices, Inc.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     22  * OTHER DEALINGS IN THE SOFTWARE.
     23  *
     24  * Authors: Alex Deucher
     25  */
     26 
     27 #include <sys/cdefs.h>
     28 __KERNEL_RCSID(0, "$NetBSD: radeon_rv740_dpm.c,v 1.1 2018/08/27 14:38:20 riastradh Exp $");
     29 
     30 #include "drmP.h"
     31 #include "radeon.h"
     32 #include "rv740d.h"
     33 #include "r600_dpm.h"
     34 #include "rv770_dpm.h"
     35 #include "atom.h"
     36 
     37 struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev);
     38 
     39 u32 rv740_get_decoded_reference_divider(u32 encoded_ref)
     40 {
     41 	u32 ref = 0;
     42 
     43 	switch (encoded_ref) {
     44         case 0:
     45 		ref = 1;
     46 		break;
     47         case 16:
     48 		ref = 2;
     49 		break;
     50         case 17:
     51 		ref = 3;
     52 		break;
     53         case 18:
     54 		ref = 2;
     55 		break;
     56         case 19:
     57 		ref = 3;
     58 		break;
     59         case 20:
     60 		ref = 4;
     61 		break;
     62         case 21:
     63 		ref = 5;
     64 		break;
     65         default:
     66 		DRM_ERROR("Invalid encoded Reference Divider\n");
     67 		ref = 0;
     68 		break;
     69 	}
     70 
     71 	return ref;
     72 }
     73 
     74 struct dll_speed_setting {
     75 	u16 min;
     76 	u16 max;
     77 	u32 dll_speed;
     78 };
     79 
     80 static struct dll_speed_setting dll_speed_table[16] =
     81 {
     82 	{ 270, 320, 0x0f },
     83 	{ 240, 270, 0x0e },
     84 	{ 200, 240, 0x0d },
     85 	{ 180, 200, 0x0c },
     86 	{ 160, 180, 0x0b },
     87 	{ 140, 160, 0x0a },
     88 	{ 120, 140, 0x09 },
     89 	{ 110, 120, 0x08 },
     90 	{  95, 110, 0x07 },
     91 	{  85,  95, 0x06 },
     92 	{  78,  85, 0x05 },
     93 	{  70,  78, 0x04 },
     94 	{  65,  70, 0x03 },
     95 	{  60,  65, 0x02 },
     96 	{  42,  60, 0x01 },
     97 	{  00,  42, 0x00 }
     98 };
     99 
    100 u32 rv740_get_dll_speed(bool is_gddr5, u32 memory_clock)
    101 {
    102 	int i;
    103 	u32 factor;
    104 	u16 data_rate;
    105 
    106 	if (is_gddr5)
    107 		factor = 4;
    108 	else
    109 		factor = 2;
    110 
    111 	data_rate = (u16)(memory_clock * factor / 1000);
    112 
    113 	if (data_rate < dll_speed_table[0].max) {
    114 		for (i = 0; i < 16; i++) {
    115 			if (data_rate > dll_speed_table[i].min &&
    116 			    data_rate <= dll_speed_table[i].max)
    117 				return dll_speed_table[i].dll_speed;
    118 		}
    119 	}
    120 
    121 	DRM_DEBUG_KMS("Target MCLK greater than largest MCLK in DLL speed table\n");
    122 
    123 	return 0x0f;
    124 }
    125 
    126 int rv740_populate_sclk_value(struct radeon_device *rdev, u32 engine_clock,
    127 			      RV770_SMC_SCLK_VALUE *sclk)
    128 {
    129 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
    130 	struct atom_clock_dividers dividers;
    131 	u32 spll_func_cntl = pi->clk_regs.rv770.cg_spll_func_cntl;
    132 	u32 spll_func_cntl_2 = pi->clk_regs.rv770.cg_spll_func_cntl_2;
    133 	u32 spll_func_cntl_3 = pi->clk_regs.rv770.cg_spll_func_cntl_3;
    134 	u32 cg_spll_spread_spectrum = pi->clk_regs.rv770.cg_spll_spread_spectrum;
    135 	u32 cg_spll_spread_spectrum_2 = pi->clk_regs.rv770.cg_spll_spread_spectrum_2;
    136 	u64 tmp;
    137 	u32 reference_clock = rdev->clock.spll.reference_freq;
    138 	u32 reference_divider;
    139 	u32 fbdiv;
    140 	int ret;
    141 
    142 	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
    143 					     engine_clock, false, &dividers);
    144 	if (ret)
    145 		return ret;
    146 
    147 	reference_divider = 1 + dividers.ref_div;
    148 
    149 	tmp = (u64) engine_clock * reference_divider * dividers.post_div * 16384;
    150 	do_div(tmp, reference_clock);
    151 	fbdiv = (u32) tmp;
    152 
    153 	spll_func_cntl &= ~(SPLL_PDIV_A_MASK | SPLL_REF_DIV_MASK);
    154 	spll_func_cntl |= SPLL_REF_DIV(dividers.ref_div);
    155 	spll_func_cntl |= SPLL_PDIV_A(dividers.post_div);
    156 
    157 	spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
    158 	spll_func_cntl_2 |= SCLK_MUX_SEL(2);
    159 
    160 	spll_func_cntl_3 &= ~SPLL_FB_DIV_MASK;
    161 	spll_func_cntl_3 |= SPLL_FB_DIV(fbdiv);
    162 	spll_func_cntl_3 |= SPLL_DITHEN;
    163 
    164 	if (pi->sclk_ss) {
    165 		struct radeon_atom_ss ss;
    166 		u32 vco_freq = engine_clock * dividers.post_div;
    167 
    168 		if (radeon_atombios_get_asic_ss_info(rdev, &ss,
    169 						     ASIC_INTERNAL_ENGINE_SS, vco_freq)) {
    170 			u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate);
    171 			u32 clk_v = 4 * ss.percentage * fbdiv / (clk_s * 10000);
    172 
    173 			cg_spll_spread_spectrum &= ~CLK_S_MASK;
    174 			cg_spll_spread_spectrum |= CLK_S(clk_s);
    175 			cg_spll_spread_spectrum |= SSEN;
    176 
    177 			cg_spll_spread_spectrum_2 &= ~CLK_V_MASK;
    178 			cg_spll_spread_spectrum_2 |= CLK_V(clk_v);
    179 		}
    180 	}
    181 
    182 	sclk->sclk_value = cpu_to_be32(engine_clock);
    183 	sclk->vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl);
    184 	sclk->vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2);
    185 	sclk->vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3);
    186 	sclk->vCG_SPLL_SPREAD_SPECTRUM = cpu_to_be32(cg_spll_spread_spectrum);
    187 	sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cpu_to_be32(cg_spll_spread_spectrum_2);
    188 
    189 	return 0;
    190 }
    191 
    192 int rv740_populate_mclk_value(struct radeon_device *rdev,
    193 			      u32 engine_clock, u32 memory_clock,
    194 			      RV7XX_SMC_MCLK_VALUE *mclk)
    195 {
    196 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
    197 	u32 mpll_ad_func_cntl = pi->clk_regs.rv770.mpll_ad_func_cntl;
    198 	u32 mpll_ad_func_cntl_2 = pi->clk_regs.rv770.mpll_ad_func_cntl_2;
    199 	u32 mpll_dq_func_cntl = pi->clk_regs.rv770.mpll_dq_func_cntl;
    200 	u32 mpll_dq_func_cntl_2 = pi->clk_regs.rv770.mpll_dq_func_cntl_2;
    201 	u32 mclk_pwrmgt_cntl = pi->clk_regs.rv770.mclk_pwrmgt_cntl;
    202 	u32 dll_cntl = pi->clk_regs.rv770.dll_cntl;
    203 	u32 mpll_ss1 = pi->clk_regs.rv770.mpll_ss1;
    204 	u32 mpll_ss2 = pi->clk_regs.rv770.mpll_ss2;
    205 	struct atom_clock_dividers dividers;
    206 	u32 ibias;
    207 	u32 dll_speed;
    208 	int ret;
    209 
    210 	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM,
    211 					     memory_clock, false, &dividers);
    212 	if (ret)
    213 		return ret;
    214 
    215 	ibias = rv770_map_clkf_to_ibias(rdev, dividers.whole_fb_div);
    216 
    217 	mpll_ad_func_cntl &= ~(CLKR_MASK |
    218 			       YCLK_POST_DIV_MASK |
    219 			       CLKF_MASK |
    220 			       CLKFRAC_MASK |
    221 			       IBIAS_MASK);
    222 	mpll_ad_func_cntl |= CLKR(dividers.ref_div);
    223 	mpll_ad_func_cntl |= YCLK_POST_DIV(dividers.post_div);
    224 	mpll_ad_func_cntl |= CLKF(dividers.whole_fb_div);
    225 	mpll_ad_func_cntl |= CLKFRAC(dividers.frac_fb_div);
    226 	mpll_ad_func_cntl |= IBIAS(ibias);
    227 
    228 	if (dividers.vco_mode)
    229 		mpll_ad_func_cntl_2 |= VCO_MODE;
    230 	else
    231 		mpll_ad_func_cntl_2 &= ~VCO_MODE;
    232 
    233 	if (pi->mem_gddr5) {
    234 		mpll_dq_func_cntl &= ~(CLKR_MASK |
    235 				       YCLK_POST_DIV_MASK |
    236 				       CLKF_MASK |
    237 				       CLKFRAC_MASK |
    238 				       IBIAS_MASK);
    239 		mpll_dq_func_cntl |= CLKR(dividers.ref_div);
    240 		mpll_dq_func_cntl |= YCLK_POST_DIV(dividers.post_div);
    241 		mpll_dq_func_cntl |= CLKF(dividers.whole_fb_div);
    242 		mpll_dq_func_cntl |= CLKFRAC(dividers.frac_fb_div);
    243 		mpll_dq_func_cntl |= IBIAS(ibias);
    244 
    245 		if (dividers.vco_mode)
    246 			mpll_dq_func_cntl_2 |= VCO_MODE;
    247 		else
    248 			mpll_dq_func_cntl_2 &= ~VCO_MODE;
    249 	}
    250 
    251 	if (pi->mclk_ss) {
    252 		struct radeon_atom_ss ss;
    253 		u32 vco_freq = memory_clock * dividers.post_div;
    254 
    255 		if (radeon_atombios_get_asic_ss_info(rdev, &ss,
    256 						     ASIC_INTERNAL_MEMORY_SS, vco_freq)) {
    257 			u32 reference_clock = rdev->clock.mpll.reference_freq;
    258 			u32 decoded_ref = rv740_get_decoded_reference_divider(dividers.ref_div);
    259 			u32 clk_s = reference_clock * 5 / (decoded_ref * ss.rate);
    260 			u32 clk_v = 0x40000 * ss.percentage *
    261 				(dividers.whole_fb_div + (dividers.frac_fb_div / 8)) / (clk_s * 10000);
    262 
    263 			mpll_ss1 &= ~CLKV_MASK;
    264 			mpll_ss1 |= CLKV(clk_v);
    265 
    266 			mpll_ss2 &= ~CLKS_MASK;
    267 			mpll_ss2 |= CLKS(clk_s);
    268 		}
    269 	}
    270 
    271 	dll_speed = rv740_get_dll_speed(pi->mem_gddr5,
    272 					memory_clock);
    273 
    274 	mclk_pwrmgt_cntl &= ~DLL_SPEED_MASK;
    275 	mclk_pwrmgt_cntl |= DLL_SPEED(dll_speed);
    276 
    277 	mclk->mclk770.mclk_value = cpu_to_be32(memory_clock);
    278 	mclk->mclk770.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
    279 	mclk->mclk770.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2);
    280 	mclk->mclk770.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
    281 	mclk->mclk770.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2);
    282 	mclk->mclk770.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
    283 	mclk->mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl);
    284 	mclk->mclk770.vMPLL_SS = cpu_to_be32(mpll_ss1);
    285 	mclk->mclk770.vMPLL_SS2 = cpu_to_be32(mpll_ss2);
    286 
    287 	return 0;
    288 }
    289 
    290 void rv740_read_clock_registers(struct radeon_device *rdev)
    291 {
    292 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
    293 
    294 	pi->clk_regs.rv770.cg_spll_func_cntl =
    295 		RREG32(CG_SPLL_FUNC_CNTL);
    296 	pi->clk_regs.rv770.cg_spll_func_cntl_2 =
    297 		RREG32(CG_SPLL_FUNC_CNTL_2);
    298 	pi->clk_regs.rv770.cg_spll_func_cntl_3 =
    299 		RREG32(CG_SPLL_FUNC_CNTL_3);
    300 	pi->clk_regs.rv770.cg_spll_spread_spectrum =
    301 		RREG32(CG_SPLL_SPREAD_SPECTRUM);
    302 	pi->clk_regs.rv770.cg_spll_spread_spectrum_2 =
    303 		RREG32(CG_SPLL_SPREAD_SPECTRUM_2);
    304 
    305 	pi->clk_regs.rv770.mpll_ad_func_cntl =
    306 		RREG32(MPLL_AD_FUNC_CNTL);
    307 	pi->clk_regs.rv770.mpll_ad_func_cntl_2 =
    308 		RREG32(MPLL_AD_FUNC_CNTL_2);
    309 	pi->clk_regs.rv770.mpll_dq_func_cntl =
    310 		RREG32(MPLL_DQ_FUNC_CNTL);
    311 	pi->clk_regs.rv770.mpll_dq_func_cntl_2 =
    312 		RREG32(MPLL_DQ_FUNC_CNTL_2);
    313 	pi->clk_regs.rv770.mclk_pwrmgt_cntl =
    314 		RREG32(MCLK_PWRMGT_CNTL);
    315 	pi->clk_regs.rv770.dll_cntl = RREG32(DLL_CNTL);
    316 	pi->clk_regs.rv770.mpll_ss1 = RREG32(MPLL_SS1);
    317 	pi->clk_regs.rv770.mpll_ss2 = RREG32(MPLL_SS2);
    318 }
    319 
    320 int rv740_populate_smc_acpi_state(struct radeon_device *rdev,
    321 				  RV770_SMC_STATETABLE *table)
    322 {
    323 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
    324 	u32 mpll_ad_func_cntl = pi->clk_regs.rv770.mpll_ad_func_cntl;
    325 	u32 mpll_ad_func_cntl_2 = pi->clk_regs.rv770.mpll_ad_func_cntl_2;
    326 	u32 mpll_dq_func_cntl = pi->clk_regs.rv770.mpll_dq_func_cntl;
    327 	u32 mpll_dq_func_cntl_2 = pi->clk_regs.rv770.mpll_dq_func_cntl_2;
    328 	u32 spll_func_cntl = pi->clk_regs.rv770.cg_spll_func_cntl;
    329 	u32 spll_func_cntl_2 = pi->clk_regs.rv770.cg_spll_func_cntl_2;
    330 	u32 spll_func_cntl_3 = pi->clk_regs.rv770.cg_spll_func_cntl_3;
    331 	u32 mclk_pwrmgt_cntl = pi->clk_regs.rv770.mclk_pwrmgt_cntl;
    332 	u32 dll_cntl = pi->clk_regs.rv770.dll_cntl;
    333 
    334 	table->ACPIState = table->initialState;
    335 
    336 	table->ACPIState.flags &= ~PPSMC_SWSTATE_FLAG_DC;
    337 
    338 	if (pi->acpi_vddc) {
    339 		rv770_populate_vddc_value(rdev, pi->acpi_vddc,
    340 					  &table->ACPIState.levels[0].vddc);
    341 		table->ACPIState.levels[0].gen2PCIE =
    342 			pi->pcie_gen2 ?
    343 			pi->acpi_pcie_gen2 : 0;
    344 		table->ACPIState.levels[0].gen2XSP =
    345 			pi->acpi_pcie_gen2;
    346 	} else {
    347 		rv770_populate_vddc_value(rdev, pi->min_vddc_in_table,
    348 					  &table->ACPIState.levels[0].vddc);
    349 		table->ACPIState.levels[0].gen2PCIE = 0;
    350 	}
    351 
    352 	mpll_ad_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN;
    353 
    354 	mpll_dq_func_cntl_2 |= BYPASS | BIAS_GEN_PDNB | RESET_EN;
    355 
    356 	mclk_pwrmgt_cntl |= (MRDCKA0_RESET |
    357 			     MRDCKA1_RESET |
    358 			     MRDCKB0_RESET |
    359 			     MRDCKB1_RESET |
    360 			     MRDCKC0_RESET |
    361 			     MRDCKC1_RESET |
    362 			     MRDCKD0_RESET |
    363 			     MRDCKD1_RESET);
    364 
    365 	dll_cntl |= (MRDCKA0_BYPASS |
    366 		     MRDCKA1_BYPASS |
    367 		     MRDCKB0_BYPASS |
    368 		     MRDCKB1_BYPASS |
    369 		     MRDCKC0_BYPASS |
    370 		     MRDCKC1_BYPASS |
    371 		     MRDCKD0_BYPASS |
    372 		     MRDCKD1_BYPASS);
    373 
    374 	spll_func_cntl |= SPLL_RESET | SPLL_SLEEP | SPLL_BYPASS_EN;
    375 
    376 	spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
    377 	spll_func_cntl_2 |= SCLK_MUX_SEL(4);
    378 
    379 	table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
    380 	table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2);
    381 	table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
    382 	table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2);
    383 	table->ACPIState.levels[0].mclk.mclk770.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
    384 	table->ACPIState.levels[0].mclk.mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl);
    385 
    386 	table->ACPIState.levels[0].mclk.mclk770.mclk_value = 0;
    387 
    388 	table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl);
    389 	table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2);
    390 	table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3);
    391 
    392 	table->ACPIState.levels[0].sclk.sclk_value = 0;
    393 
    394 	table->ACPIState.levels[1] = table->ACPIState.levels[0];
    395 	table->ACPIState.levels[2] = table->ACPIState.levels[0];
    396 
    397 	rv770_populate_mvdd_value(rdev, 0, &table->ACPIState.levels[0].mvdd);
    398 
    399 	return 0;
    400 }
    401 
    402 void rv740_enable_mclk_spread_spectrum(struct radeon_device *rdev,
    403 				       bool enable)
    404 {
    405 	if (enable)
    406 		WREG32_P(MPLL_CNTL_MODE, SS_SSEN, ~SS_SSEN);
    407 	else
    408 		WREG32_P(MPLL_CNTL_MODE, 0, ~SS_SSEN);
    409 }
    410 
    411 u8 rv740_get_mclk_frequency_ratio(u32 memory_clock)
    412 {
    413 	u8 mc_para_index;
    414 
    415 	if ((memory_clock < 10000) || (memory_clock > 47500))
    416 		mc_para_index = 0x00;
    417 	else
    418 		mc_para_index = (u8)((memory_clock - 10000) / 2500);
    419 
    420 	return mc_para_index;
    421 }
    422