2 * Copyright 2011 Advanced Micro Devices, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
22 * Authors: Alex Deucher
29 #include "rv770_dpm.h"
32 struct rv7xx_ps
*rv770_get_ps(struct radeon_ps
*rps
);
33 struct rv7xx_power_info
*rv770_get_pi(struct radeon_device
*rdev
);
35 u32
rv740_get_decoded_reference_divider(u32 encoded_ref
)
39 switch (encoded_ref
) {
62 DRM_ERROR("Invalid encoded Reference Divider\n");
70 struct dll_speed_setting
{
76 static struct dll_speed_setting dll_speed_table
[16] =
96 u32
rv740_get_dll_speed(bool is_gddr5
, u32 memory_clock
)
107 data_rate
= (u16
)(memory_clock
* factor
/ 1000);
109 if (data_rate
< dll_speed_table
[0].max
) {
110 for (i
= 0; i
< 16; i
++) {
111 if (data_rate
> dll_speed_table
[i
].min
&&
112 data_rate
<= dll_speed_table
[i
].max
)
113 return dll_speed_table
[i
].dll_speed
;
117 DRM_DEBUG_KMS("Target MCLK greater than largest MCLK in DLL speed table\n");
122 int rv740_populate_sclk_value(struct radeon_device
*rdev
, u32 engine_clock
,
123 RV770_SMC_SCLK_VALUE
*sclk
)
125 struct rv7xx_power_info
*pi
= rv770_get_pi(rdev
);
126 struct atom_clock_dividers dividers
;
127 u32 spll_func_cntl
= pi
->clk_regs
.rv770
.cg_spll_func_cntl
;
128 u32 spll_func_cntl_2
= pi
->clk_regs
.rv770
.cg_spll_func_cntl_2
;
129 u32 spll_func_cntl_3
= pi
->clk_regs
.rv770
.cg_spll_func_cntl_3
;
130 u32 cg_spll_spread_spectrum
= pi
->clk_regs
.rv770
.cg_spll_spread_spectrum
;
131 u32 cg_spll_spread_spectrum_2
= pi
->clk_regs
.rv770
.cg_spll_spread_spectrum_2
;
133 u32 reference_clock
= rdev
->clock
.spll
.reference_freq
;
134 u32 reference_divider
;
138 ret
= radeon_atom_get_clock_dividers(rdev
, COMPUTE_ENGINE_PLL_PARAM
,
139 engine_clock
, false, ÷rs
);
143 reference_divider
= 1 + dividers
.ref_div
;
145 tmp
= (u64
) engine_clock
* reference_divider
* dividers
.post_div
* 16384;
146 do_div(tmp
, reference_clock
);
149 spll_func_cntl
&= ~(SPLL_PDIV_A_MASK
| SPLL_REF_DIV_MASK
);
150 spll_func_cntl
|= SPLL_REF_DIV(dividers
.ref_div
);
151 spll_func_cntl
|= SPLL_PDIV_A(dividers
.post_div
);
153 spll_func_cntl_2
&= ~SCLK_MUX_SEL_MASK
;
154 spll_func_cntl_2
|= SCLK_MUX_SEL(2);
156 spll_func_cntl_3
&= ~SPLL_FB_DIV_MASK
;
157 spll_func_cntl_3
|= SPLL_FB_DIV(fbdiv
);
158 spll_func_cntl_3
|= SPLL_DITHEN
;
161 struct radeon_atom_ss ss
;
162 u32 vco_freq
= engine_clock
* dividers
.post_div
;
164 if (radeon_atombios_get_asic_ss_info(rdev
, &ss
,
165 ASIC_INTERNAL_ENGINE_SS
, vco_freq
)) {
166 u32 clk_s
= reference_clock
* 5 / (reference_divider
* ss
.rate
);
167 u32 clk_v
= 4 * ss
.percentage
* fbdiv
/ (clk_s
* 10000);
169 cg_spll_spread_spectrum
&= ~CLK_S_MASK
;
170 cg_spll_spread_spectrum
|= CLK_S(clk_s
);
171 cg_spll_spread_spectrum
|= SSEN
;
173 cg_spll_spread_spectrum_2
&= ~CLK_V_MASK
;
174 cg_spll_spread_spectrum_2
|= CLK_V(clk_v
);
178 sclk
->sclk_value
= cpu_to_be32(engine_clock
);
179 sclk
->vCG_SPLL_FUNC_CNTL
= cpu_to_be32(spll_func_cntl
);
180 sclk
->vCG_SPLL_FUNC_CNTL_2
= cpu_to_be32(spll_func_cntl_2
);
181 sclk
->vCG_SPLL_FUNC_CNTL_3
= cpu_to_be32(spll_func_cntl_3
);
182 sclk
->vCG_SPLL_SPREAD_SPECTRUM
= cpu_to_be32(cg_spll_spread_spectrum
);
183 sclk
->vCG_SPLL_SPREAD_SPECTRUM_2
= cpu_to_be32(cg_spll_spread_spectrum_2
);
188 int rv740_populate_mclk_value(struct radeon_device
*rdev
,
189 u32 engine_clock
, u32 memory_clock
,
190 RV7XX_SMC_MCLK_VALUE
*mclk
)
192 struct rv7xx_power_info
*pi
= rv770_get_pi(rdev
);
193 u32 mpll_ad_func_cntl
= pi
->clk_regs
.rv770
.mpll_ad_func_cntl
;
194 u32 mpll_ad_func_cntl_2
= pi
->clk_regs
.rv770
.mpll_ad_func_cntl_2
;
195 u32 mpll_dq_func_cntl
= pi
->clk_regs
.rv770
.mpll_dq_func_cntl
;
196 u32 mpll_dq_func_cntl_2
= pi
->clk_regs
.rv770
.mpll_dq_func_cntl_2
;
197 u32 mclk_pwrmgt_cntl
= pi
->clk_regs
.rv770
.mclk_pwrmgt_cntl
;
198 u32 dll_cntl
= pi
->clk_regs
.rv770
.dll_cntl
;
199 u32 mpll_ss1
= pi
->clk_regs
.rv770
.mpll_ss1
;
200 u32 mpll_ss2
= pi
->clk_regs
.rv770
.mpll_ss2
;
201 struct atom_clock_dividers dividers
;
206 ret
= radeon_atom_get_clock_dividers(rdev
, COMPUTE_MEMORY_PLL_PARAM
,
207 memory_clock
, false, ÷rs
);
211 ibias
= rv770_map_clkf_to_ibias(rdev
, dividers
.whole_fb_div
);
213 mpll_ad_func_cntl
&= ~(CLKR_MASK
|
218 mpll_ad_func_cntl
|= CLKR(dividers
.ref_div
);
219 mpll_ad_func_cntl
|= YCLK_POST_DIV(dividers
.post_div
);
220 mpll_ad_func_cntl
|= CLKF(dividers
.whole_fb_div
);
221 mpll_ad_func_cntl
|= CLKFRAC(dividers
.frac_fb_div
);
222 mpll_ad_func_cntl
|= IBIAS(ibias
);
224 if (dividers
.vco_mode
)
225 mpll_ad_func_cntl_2
|= VCO_MODE
;
227 mpll_ad_func_cntl_2
&= ~VCO_MODE
;
230 mpll_dq_func_cntl
&= ~(CLKR_MASK
|
235 mpll_dq_func_cntl
|= CLKR(dividers
.ref_div
);
236 mpll_dq_func_cntl
|= YCLK_POST_DIV(dividers
.post_div
);
237 mpll_dq_func_cntl
|= CLKF(dividers
.whole_fb_div
);
238 mpll_dq_func_cntl
|= CLKFRAC(dividers
.frac_fb_div
);
239 mpll_dq_func_cntl
|= IBIAS(ibias
);
241 if (dividers
.vco_mode
)
242 mpll_dq_func_cntl_2
|= VCO_MODE
;
244 mpll_dq_func_cntl_2
&= ~VCO_MODE
;
248 struct radeon_atom_ss ss
;
249 u32 vco_freq
= memory_clock
* dividers
.post_div
;
251 if (radeon_atombios_get_asic_ss_info(rdev
, &ss
,
252 ASIC_INTERNAL_MEMORY_SS
, vco_freq
)) {
253 u32 reference_clock
= rdev
->clock
.mpll
.reference_freq
;
254 u32 decoded_ref
= rv740_get_decoded_reference_divider(dividers
.ref_div
);
255 u32 clk_s
= reference_clock
* 5 / (decoded_ref
* ss
.rate
);
256 u32 clk_v
= 0x40000 * ss
.percentage
*
257 (dividers
.whole_fb_div
+ (dividers
.frac_fb_div
/ 8)) / (clk_s
* 10000);
259 mpll_ss1
&= ~CLKV_MASK
;
260 mpll_ss1
|= CLKV(clk_v
);
262 mpll_ss2
&= ~CLKS_MASK
;
263 mpll_ss2
|= CLKS(clk_s
);
267 dll_speed
= rv740_get_dll_speed(pi
->mem_gddr5
,
270 mclk_pwrmgt_cntl
&= ~DLL_SPEED_MASK
;
271 mclk_pwrmgt_cntl
|= DLL_SPEED(dll_speed
);
273 mclk
->mclk770
.mclk_value
= cpu_to_be32(memory_clock
);
274 mclk
->mclk770
.vMPLL_AD_FUNC_CNTL
= cpu_to_be32(mpll_ad_func_cntl
);
275 mclk
->mclk770
.vMPLL_AD_FUNC_CNTL_2
= cpu_to_be32(mpll_ad_func_cntl_2
);
276 mclk
->mclk770
.vMPLL_DQ_FUNC_CNTL
= cpu_to_be32(mpll_dq_func_cntl
);
277 mclk
->mclk770
.vMPLL_DQ_FUNC_CNTL_2
= cpu_to_be32(mpll_dq_func_cntl_2
);
278 mclk
->mclk770
.vMCLK_PWRMGT_CNTL
= cpu_to_be32(mclk_pwrmgt_cntl
);
279 mclk
->mclk770
.vDLL_CNTL
= cpu_to_be32(dll_cntl
);
280 mclk
->mclk770
.vMPLL_SS
= cpu_to_be32(mpll_ss1
);
281 mclk
->mclk770
.vMPLL_SS2
= cpu_to_be32(mpll_ss2
);
286 void rv740_read_clock_registers(struct radeon_device
*rdev
)
288 struct rv7xx_power_info
*pi
= rv770_get_pi(rdev
);
290 pi
->clk_regs
.rv770
.cg_spll_func_cntl
=
291 RREG32(CG_SPLL_FUNC_CNTL
);
292 pi
->clk_regs
.rv770
.cg_spll_func_cntl_2
=
293 RREG32(CG_SPLL_FUNC_CNTL_2
);
294 pi
->clk_regs
.rv770
.cg_spll_func_cntl_3
=
295 RREG32(CG_SPLL_FUNC_CNTL_3
);
296 pi
->clk_regs
.rv770
.cg_spll_spread_spectrum
=
297 RREG32(CG_SPLL_SPREAD_SPECTRUM
);
298 pi
->clk_regs
.rv770
.cg_spll_spread_spectrum_2
=
299 RREG32(CG_SPLL_SPREAD_SPECTRUM_2
);
301 pi
->clk_regs
.rv770
.mpll_ad_func_cntl
=
302 RREG32(MPLL_AD_FUNC_CNTL
);
303 pi
->clk_regs
.rv770
.mpll_ad_func_cntl_2
=
304 RREG32(MPLL_AD_FUNC_CNTL_2
);
305 pi
->clk_regs
.rv770
.mpll_dq_func_cntl
=
306 RREG32(MPLL_DQ_FUNC_CNTL
);
307 pi
->clk_regs
.rv770
.mpll_dq_func_cntl_2
=
308 RREG32(MPLL_DQ_FUNC_CNTL_2
);
309 pi
->clk_regs
.rv770
.mclk_pwrmgt_cntl
=
310 RREG32(MCLK_PWRMGT_CNTL
);
311 pi
->clk_regs
.rv770
.dll_cntl
= RREG32(DLL_CNTL
);
312 pi
->clk_regs
.rv770
.mpll_ss1
= RREG32(MPLL_SS1
);
313 pi
->clk_regs
.rv770
.mpll_ss2
= RREG32(MPLL_SS2
);
316 int rv740_populate_smc_acpi_state(struct radeon_device
*rdev
,
317 RV770_SMC_STATETABLE
*table
)
319 struct rv7xx_power_info
*pi
= rv770_get_pi(rdev
);
320 u32 mpll_ad_func_cntl
= pi
->clk_regs
.rv770
.mpll_ad_func_cntl
;
321 u32 mpll_ad_func_cntl_2
= pi
->clk_regs
.rv770
.mpll_ad_func_cntl_2
;
322 u32 mpll_dq_func_cntl
= pi
->clk_regs
.rv770
.mpll_dq_func_cntl
;
323 u32 mpll_dq_func_cntl_2
= pi
->clk_regs
.rv770
.mpll_dq_func_cntl_2
;
324 u32 spll_func_cntl
= pi
->clk_regs
.rv770
.cg_spll_func_cntl
;
325 u32 spll_func_cntl_2
= pi
->clk_regs
.rv770
.cg_spll_func_cntl_2
;
326 u32 spll_func_cntl_3
= pi
->clk_regs
.rv770
.cg_spll_func_cntl_3
;
327 u32 mclk_pwrmgt_cntl
= pi
->clk_regs
.rv770
.mclk_pwrmgt_cntl
;
328 u32 dll_cntl
= pi
->clk_regs
.rv770
.dll_cntl
;
330 table
->ACPIState
= table
->initialState
;
332 table
->ACPIState
.flags
&= ~PPSMC_SWSTATE_FLAG_DC
;
335 rv770_populate_vddc_value(rdev
, pi
->acpi_vddc
,
336 &table
->ACPIState
.levels
[0].vddc
);
337 table
->ACPIState
.levels
[0].gen2PCIE
=
339 pi
->acpi_pcie_gen2
: 0;
340 table
->ACPIState
.levels
[0].gen2XSP
=
343 rv770_populate_vddc_value(rdev
, pi
->min_vddc_in_table
,
344 &table
->ACPIState
.levels
[0].vddc
);
345 table
->ACPIState
.levels
[0].gen2PCIE
= 0;
348 mpll_ad_func_cntl_2
|= BIAS_GEN_PDNB
| RESET_EN
;
350 mpll_dq_func_cntl_2
|= BYPASS
| BIAS_GEN_PDNB
| RESET_EN
;
352 mclk_pwrmgt_cntl
|= (MRDCKA0_RESET
|
361 dll_cntl
|= (MRDCKA0_BYPASS
|
370 spll_func_cntl
|= SPLL_RESET
| SPLL_SLEEP
| SPLL_BYPASS_EN
;
372 spll_func_cntl_2
&= ~SCLK_MUX_SEL_MASK
;
373 spll_func_cntl_2
|= SCLK_MUX_SEL(4);
375 table
->ACPIState
.levels
[0].mclk
.mclk770
.vMPLL_AD_FUNC_CNTL
= cpu_to_be32(mpll_ad_func_cntl
);
376 table
->ACPIState
.levels
[0].mclk
.mclk770
.vMPLL_AD_FUNC_CNTL_2
= cpu_to_be32(mpll_ad_func_cntl_2
);
377 table
->ACPIState
.levels
[0].mclk
.mclk770
.vMPLL_DQ_FUNC_CNTL
= cpu_to_be32(mpll_dq_func_cntl
);
378 table
->ACPIState
.levels
[0].mclk
.mclk770
.vMPLL_DQ_FUNC_CNTL_2
= cpu_to_be32(mpll_dq_func_cntl_2
);
379 table
->ACPIState
.levels
[0].mclk
.mclk770
.vMCLK_PWRMGT_CNTL
= cpu_to_be32(mclk_pwrmgt_cntl
);
380 table
->ACPIState
.levels
[0].mclk
.mclk770
.vDLL_CNTL
= cpu_to_be32(dll_cntl
);
382 table
->ACPIState
.levels
[0].mclk
.mclk770
.mclk_value
= 0;
384 table
->ACPIState
.levels
[0].sclk
.vCG_SPLL_FUNC_CNTL
= cpu_to_be32(spll_func_cntl
);
385 table
->ACPIState
.levels
[0].sclk
.vCG_SPLL_FUNC_CNTL_2
= cpu_to_be32(spll_func_cntl_2
);
386 table
->ACPIState
.levels
[0].sclk
.vCG_SPLL_FUNC_CNTL_3
= cpu_to_be32(spll_func_cntl_3
);
388 table
->ACPIState
.levels
[0].sclk
.sclk_value
= 0;
390 table
->ACPIState
.levels
[1] = table
->ACPIState
.levels
[0];
391 table
->ACPIState
.levels
[2] = table
->ACPIState
.levels
[0];
393 rv770_populate_mvdd_value(rdev
, 0, &table
->ACPIState
.levels
[0].mvdd
);
398 void rv740_enable_mclk_spread_spectrum(struct radeon_device
*rdev
,
402 WREG32_P(MPLL_CNTL_MODE
, SS_SSEN
, ~SS_SSEN
);
404 WREG32_P(MPLL_CNTL_MODE
, 0, ~SS_SSEN
);
407 u8
rv740_get_mclk_frequency_ratio(u32 memory_clock
)
411 if ((memory_clock
< 10000) || (memory_clock
> 47500))
412 mc_para_index
= 0x00;
414 mc_para_index
= (u8
)((memory_clock
- 10000) / 2500);
416 return mc_para_index
;