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_power_info
*rv770_get_pi(struct radeon_device
*rdev
);
34 u32
rv740_get_decoded_reference_divider(u32 encoded_ref
)
38 switch (encoded_ref
) {
61 DRM_ERROR("Invalid encoded Reference Divider\n");
69 struct dll_speed_setting
{
75 static struct dll_speed_setting dll_speed_table
[16] =
95 u32
rv740_get_dll_speed(bool is_gddr5
, u32 memory_clock
)
106 data_rate
= (u16
)(memory_clock
* factor
/ 1000);
108 if (data_rate
< dll_speed_table
[0].max
) {
109 for (i
= 0; i
< 16; i
++) {
110 if (data_rate
> dll_speed_table
[i
].min
&&
111 data_rate
<= dll_speed_table
[i
].max
)
112 return dll_speed_table
[i
].dll_speed
;
116 DRM_DEBUG_KMS("Target MCLK greater than largest MCLK in DLL speed table\n");
121 int rv740_populate_sclk_value(struct radeon_device
*rdev
, u32 engine_clock
,
122 RV770_SMC_SCLK_VALUE
*sclk
)
124 struct rv7xx_power_info
*pi
= rv770_get_pi(rdev
);
125 struct atom_clock_dividers dividers
;
126 u32 spll_func_cntl
= pi
->clk_regs
.rv770
.cg_spll_func_cntl
;
127 u32 spll_func_cntl_2
= pi
->clk_regs
.rv770
.cg_spll_func_cntl_2
;
128 u32 spll_func_cntl_3
= pi
->clk_regs
.rv770
.cg_spll_func_cntl_3
;
129 u32 cg_spll_spread_spectrum
= pi
->clk_regs
.rv770
.cg_spll_spread_spectrum
;
130 u32 cg_spll_spread_spectrum_2
= pi
->clk_regs
.rv770
.cg_spll_spread_spectrum_2
;
132 u32 reference_clock
= rdev
->clock
.spll
.reference_freq
;
133 u32 reference_divider
;
137 ret
= radeon_atom_get_clock_dividers(rdev
, COMPUTE_ENGINE_PLL_PARAM
,
138 engine_clock
, false, ÷rs
);
142 reference_divider
= 1 + dividers
.ref_div
;
144 tmp
= (u64
) engine_clock
* reference_divider
* dividers
.post_div
* 16384;
145 do_div(tmp
, reference_clock
);
148 spll_func_cntl
&= ~(SPLL_PDIV_A_MASK
| SPLL_REF_DIV_MASK
);
149 spll_func_cntl
|= SPLL_REF_DIV(dividers
.ref_div
);
150 spll_func_cntl
|= SPLL_PDIV_A(dividers
.post_div
);
152 spll_func_cntl_2
&= ~SCLK_MUX_SEL_MASK
;
153 spll_func_cntl_2
|= SCLK_MUX_SEL(2);
155 spll_func_cntl_3
&= ~SPLL_FB_DIV_MASK
;
156 spll_func_cntl_3
|= SPLL_FB_DIV(fbdiv
);
157 spll_func_cntl_3
|= SPLL_DITHEN
;
160 struct radeon_atom_ss ss
;
161 u32 vco_freq
= engine_clock
* dividers
.post_div
;
163 if (radeon_atombios_get_asic_ss_info(rdev
, &ss
,
164 ASIC_INTERNAL_ENGINE_SS
, vco_freq
)) {
165 u32 clk_s
= reference_clock
* 5 / (reference_divider
* ss
.rate
);
166 u32 clk_v
= 4 * ss
.percentage
* fbdiv
/ (clk_s
* 10000);
168 cg_spll_spread_spectrum
&= ~CLK_S_MASK
;
169 cg_spll_spread_spectrum
|= CLK_S(clk_s
);
170 cg_spll_spread_spectrum
|= SSEN
;
172 cg_spll_spread_spectrum_2
&= ~CLK_V_MASK
;
173 cg_spll_spread_spectrum_2
|= CLK_V(clk_v
);
177 sclk
->sclk_value
= cpu_to_be32(engine_clock
);
178 sclk
->vCG_SPLL_FUNC_CNTL
= cpu_to_be32(spll_func_cntl
);
179 sclk
->vCG_SPLL_FUNC_CNTL_2
= cpu_to_be32(spll_func_cntl_2
);
180 sclk
->vCG_SPLL_FUNC_CNTL_3
= cpu_to_be32(spll_func_cntl_3
);
181 sclk
->vCG_SPLL_SPREAD_SPECTRUM
= cpu_to_be32(cg_spll_spread_spectrum
);
182 sclk
->vCG_SPLL_SPREAD_SPECTRUM_2
= cpu_to_be32(cg_spll_spread_spectrum_2
);
187 int rv740_populate_mclk_value(struct radeon_device
*rdev
,
188 u32 engine_clock
, u32 memory_clock
,
189 RV7XX_SMC_MCLK_VALUE
*mclk
)
191 struct rv7xx_power_info
*pi
= rv770_get_pi(rdev
);
192 u32 mpll_ad_func_cntl
= pi
->clk_regs
.rv770
.mpll_ad_func_cntl
;
193 u32 mpll_ad_func_cntl_2
= pi
->clk_regs
.rv770
.mpll_ad_func_cntl_2
;
194 u32 mpll_dq_func_cntl
= pi
->clk_regs
.rv770
.mpll_dq_func_cntl
;
195 u32 mpll_dq_func_cntl_2
= pi
->clk_regs
.rv770
.mpll_dq_func_cntl_2
;
196 u32 mclk_pwrmgt_cntl
= pi
->clk_regs
.rv770
.mclk_pwrmgt_cntl
;
197 u32 dll_cntl
= pi
->clk_regs
.rv770
.dll_cntl
;
198 u32 mpll_ss1
= pi
->clk_regs
.rv770
.mpll_ss1
;
199 u32 mpll_ss2
= pi
->clk_regs
.rv770
.mpll_ss2
;
200 struct atom_clock_dividers dividers
;
205 ret
= radeon_atom_get_clock_dividers(rdev
, COMPUTE_MEMORY_PLL_PARAM
,
206 memory_clock
, false, ÷rs
);
210 ibias
= rv770_map_clkf_to_ibias(rdev
, dividers
.whole_fb_div
);
212 mpll_ad_func_cntl
&= ~(CLKR_MASK
|
217 mpll_ad_func_cntl
|= CLKR(dividers
.ref_div
);
218 mpll_ad_func_cntl
|= YCLK_POST_DIV(dividers
.post_div
);
219 mpll_ad_func_cntl
|= CLKF(dividers
.whole_fb_div
);
220 mpll_ad_func_cntl
|= CLKFRAC(dividers
.frac_fb_div
);
221 mpll_ad_func_cntl
|= IBIAS(ibias
);
223 if (dividers
.vco_mode
)
224 mpll_ad_func_cntl_2
|= VCO_MODE
;
226 mpll_ad_func_cntl_2
&= ~VCO_MODE
;
229 mpll_dq_func_cntl
&= ~(CLKR_MASK
|
234 mpll_dq_func_cntl
|= CLKR(dividers
.ref_div
);
235 mpll_dq_func_cntl
|= YCLK_POST_DIV(dividers
.post_div
);
236 mpll_dq_func_cntl
|= CLKF(dividers
.whole_fb_div
);
237 mpll_dq_func_cntl
|= CLKFRAC(dividers
.frac_fb_div
);
238 mpll_dq_func_cntl
|= IBIAS(ibias
);
240 if (dividers
.vco_mode
)
241 mpll_dq_func_cntl_2
|= VCO_MODE
;
243 mpll_dq_func_cntl_2
&= ~VCO_MODE
;
247 struct radeon_atom_ss ss
;
248 u32 vco_freq
= memory_clock
* dividers
.post_div
;
250 if (radeon_atombios_get_asic_ss_info(rdev
, &ss
,
251 ASIC_INTERNAL_MEMORY_SS
, vco_freq
)) {
252 u32 reference_clock
= rdev
->clock
.mpll
.reference_freq
;
253 u32 decoded_ref
= rv740_get_decoded_reference_divider(dividers
.ref_div
);
254 u32 clk_s
= reference_clock
* 5 / (decoded_ref
* ss
.rate
);
255 u32 clk_v
= 0x40000 * ss
.percentage
*
256 (dividers
.whole_fb_div
+ (dividers
.frac_fb_div
/ 8)) / (clk_s
* 10000);
258 mpll_ss1
&= ~CLKV_MASK
;
259 mpll_ss1
|= CLKV(clk_v
);
261 mpll_ss2
&= ~CLKS_MASK
;
262 mpll_ss2
|= CLKS(clk_s
);
266 dll_speed
= rv740_get_dll_speed(pi
->mem_gddr5
,
269 mclk_pwrmgt_cntl
&= ~DLL_SPEED_MASK
;
270 mclk_pwrmgt_cntl
|= DLL_SPEED(dll_speed
);
272 mclk
->mclk770
.mclk_value
= cpu_to_be32(memory_clock
);
273 mclk
->mclk770
.vMPLL_AD_FUNC_CNTL
= cpu_to_be32(mpll_ad_func_cntl
);
274 mclk
->mclk770
.vMPLL_AD_FUNC_CNTL_2
= cpu_to_be32(mpll_ad_func_cntl_2
);
275 mclk
->mclk770
.vMPLL_DQ_FUNC_CNTL
= cpu_to_be32(mpll_dq_func_cntl
);
276 mclk
->mclk770
.vMPLL_DQ_FUNC_CNTL_2
= cpu_to_be32(mpll_dq_func_cntl_2
);
277 mclk
->mclk770
.vMCLK_PWRMGT_CNTL
= cpu_to_be32(mclk_pwrmgt_cntl
);
278 mclk
->mclk770
.vDLL_CNTL
= cpu_to_be32(dll_cntl
);
279 mclk
->mclk770
.vMPLL_SS
= cpu_to_be32(mpll_ss1
);
280 mclk
->mclk770
.vMPLL_SS2
= cpu_to_be32(mpll_ss2
);
285 void rv740_read_clock_registers(struct radeon_device
*rdev
)
287 struct rv7xx_power_info
*pi
= rv770_get_pi(rdev
);
289 pi
->clk_regs
.rv770
.cg_spll_func_cntl
=
290 RREG32(CG_SPLL_FUNC_CNTL
);
291 pi
->clk_regs
.rv770
.cg_spll_func_cntl_2
=
292 RREG32(CG_SPLL_FUNC_CNTL_2
);
293 pi
->clk_regs
.rv770
.cg_spll_func_cntl_3
=
294 RREG32(CG_SPLL_FUNC_CNTL_3
);
295 pi
->clk_regs
.rv770
.cg_spll_spread_spectrum
=
296 RREG32(CG_SPLL_SPREAD_SPECTRUM
);
297 pi
->clk_regs
.rv770
.cg_spll_spread_spectrum_2
=
298 RREG32(CG_SPLL_SPREAD_SPECTRUM_2
);
300 pi
->clk_regs
.rv770
.mpll_ad_func_cntl
=
301 RREG32(MPLL_AD_FUNC_CNTL
);
302 pi
->clk_regs
.rv770
.mpll_ad_func_cntl_2
=
303 RREG32(MPLL_AD_FUNC_CNTL_2
);
304 pi
->clk_regs
.rv770
.mpll_dq_func_cntl
=
305 RREG32(MPLL_DQ_FUNC_CNTL
);
306 pi
->clk_regs
.rv770
.mpll_dq_func_cntl_2
=
307 RREG32(MPLL_DQ_FUNC_CNTL_2
);
308 pi
->clk_regs
.rv770
.mclk_pwrmgt_cntl
=
309 RREG32(MCLK_PWRMGT_CNTL
);
310 pi
->clk_regs
.rv770
.dll_cntl
= RREG32(DLL_CNTL
);
311 pi
->clk_regs
.rv770
.mpll_ss1
= RREG32(MPLL_SS1
);
312 pi
->clk_regs
.rv770
.mpll_ss2
= RREG32(MPLL_SS2
);
315 int rv740_populate_smc_acpi_state(struct radeon_device
*rdev
,
316 RV770_SMC_STATETABLE
*table
)
318 struct rv7xx_power_info
*pi
= rv770_get_pi(rdev
);
319 u32 mpll_ad_func_cntl
= pi
->clk_regs
.rv770
.mpll_ad_func_cntl
;
320 u32 mpll_ad_func_cntl_2
= pi
->clk_regs
.rv770
.mpll_ad_func_cntl_2
;
321 u32 mpll_dq_func_cntl
= pi
->clk_regs
.rv770
.mpll_dq_func_cntl
;
322 u32 mpll_dq_func_cntl_2
= pi
->clk_regs
.rv770
.mpll_dq_func_cntl_2
;
323 u32 spll_func_cntl
= pi
->clk_regs
.rv770
.cg_spll_func_cntl
;
324 u32 spll_func_cntl_2
= pi
->clk_regs
.rv770
.cg_spll_func_cntl_2
;
325 u32 spll_func_cntl_3
= pi
->clk_regs
.rv770
.cg_spll_func_cntl_3
;
326 u32 mclk_pwrmgt_cntl
= pi
->clk_regs
.rv770
.mclk_pwrmgt_cntl
;
327 u32 dll_cntl
= pi
->clk_regs
.rv770
.dll_cntl
;
329 table
->ACPIState
= table
->initialState
;
331 table
->ACPIState
.flags
&= ~PPSMC_SWSTATE_FLAG_DC
;
334 rv770_populate_vddc_value(rdev
, pi
->acpi_vddc
,
335 &table
->ACPIState
.levels
[0].vddc
);
336 table
->ACPIState
.levels
[0].gen2PCIE
=
338 pi
->acpi_pcie_gen2
: 0;
339 table
->ACPIState
.levels
[0].gen2XSP
=
342 rv770_populate_vddc_value(rdev
, pi
->min_vddc_in_table
,
343 &table
->ACPIState
.levels
[0].vddc
);
344 table
->ACPIState
.levels
[0].gen2PCIE
= 0;
347 mpll_ad_func_cntl_2
|= BIAS_GEN_PDNB
| RESET_EN
;
349 mpll_dq_func_cntl_2
|= BYPASS
| BIAS_GEN_PDNB
| RESET_EN
;
351 mclk_pwrmgt_cntl
|= (MRDCKA0_RESET
|
360 dll_cntl
|= (MRDCKA0_BYPASS
|
369 spll_func_cntl
|= SPLL_RESET
| SPLL_SLEEP
| SPLL_BYPASS_EN
;
371 spll_func_cntl_2
&= ~SCLK_MUX_SEL_MASK
;
372 spll_func_cntl_2
|= SCLK_MUX_SEL(4);
374 table
->ACPIState
.levels
[0].mclk
.mclk770
.vMPLL_AD_FUNC_CNTL
= cpu_to_be32(mpll_ad_func_cntl
);
375 table
->ACPIState
.levels
[0].mclk
.mclk770
.vMPLL_AD_FUNC_CNTL_2
= cpu_to_be32(mpll_ad_func_cntl_2
);
376 table
->ACPIState
.levels
[0].mclk
.mclk770
.vMPLL_DQ_FUNC_CNTL
= cpu_to_be32(mpll_dq_func_cntl
);
377 table
->ACPIState
.levels
[0].mclk
.mclk770
.vMPLL_DQ_FUNC_CNTL_2
= cpu_to_be32(mpll_dq_func_cntl_2
);
378 table
->ACPIState
.levels
[0].mclk
.mclk770
.vMCLK_PWRMGT_CNTL
= cpu_to_be32(mclk_pwrmgt_cntl
);
379 table
->ACPIState
.levels
[0].mclk
.mclk770
.vDLL_CNTL
= cpu_to_be32(dll_cntl
);
381 table
->ACPIState
.levels
[0].mclk
.mclk770
.mclk_value
= 0;
383 table
->ACPIState
.levels
[0].sclk
.vCG_SPLL_FUNC_CNTL
= cpu_to_be32(spll_func_cntl
);
384 table
->ACPIState
.levels
[0].sclk
.vCG_SPLL_FUNC_CNTL_2
= cpu_to_be32(spll_func_cntl_2
);
385 table
->ACPIState
.levels
[0].sclk
.vCG_SPLL_FUNC_CNTL_3
= cpu_to_be32(spll_func_cntl_3
);
387 table
->ACPIState
.levels
[0].sclk
.sclk_value
= 0;
389 table
->ACPIState
.levels
[1] = table
->ACPIState
.levels
[0];
390 table
->ACPIState
.levels
[2] = table
->ACPIState
.levels
[0];
392 rv770_populate_mvdd_value(rdev
, 0, &table
->ACPIState
.levels
[0].mvdd
);
397 void rv740_enable_mclk_spread_spectrum(struct radeon_device
*rdev
,
401 WREG32_P(MPLL_CNTL_MODE
, SS_SSEN
, ~SS_SSEN
);
403 WREG32_P(MPLL_CNTL_MODE
, 0, ~SS_SSEN
);
406 u8
rv740_get_mclk_frequency_ratio(u32 memory_clock
)
410 if ((memory_clock
< 10000) || (memory_clock
> 47500))
411 mc_para_index
= 0x00;
413 mc_para_index
= (u8
)((memory_clock
- 10000) / 2500);
415 return mc_para_index
;