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