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 u32
rv740_get_decoded_reference_divider(u32 encoded_ref
)
36 switch (encoded_ref
) {
59 DRM_ERROR("Invalid encoded Reference Divider\n");
67 struct dll_speed_setting
{
73 static struct dll_speed_setting dll_speed_table
[16] =
93 u32
rv740_get_dll_speed(bool is_gddr5
, u32 memory_clock
)
104 data_rate
= (u16
)(memory_clock
* factor
/ 1000);
106 if (data_rate
< dll_speed_table
[0].max
) {
107 for (i
= 0; i
< 16; i
++) {
108 if (data_rate
> dll_speed_table
[i
].min
&&
109 data_rate
<= dll_speed_table
[i
].max
)
110 return dll_speed_table
[i
].dll_speed
;
114 DRM_DEBUG_KMS("Target MCLK greater than largest MCLK in DLL speed table\n");
119 int rv740_populate_sclk_value(struct radeon_device
*rdev
, u32 engine_clock
,
120 RV770_SMC_SCLK_VALUE
*sclk
)
122 struct rv7xx_power_info
*pi
= rv770_get_pi(rdev
);
123 struct atom_clock_dividers dividers
;
124 u32 spll_func_cntl
= pi
->clk_regs
.rv770
.cg_spll_func_cntl
;
125 u32 spll_func_cntl_2
= pi
->clk_regs
.rv770
.cg_spll_func_cntl_2
;
126 u32 spll_func_cntl_3
= pi
->clk_regs
.rv770
.cg_spll_func_cntl_3
;
127 u32 cg_spll_spread_spectrum
= pi
->clk_regs
.rv770
.cg_spll_spread_spectrum
;
128 u32 cg_spll_spread_spectrum_2
= pi
->clk_regs
.rv770
.cg_spll_spread_spectrum_2
;
130 u32 reference_clock
= rdev
->clock
.spll
.reference_freq
;
131 u32 reference_divider
;
135 ret
= radeon_atom_get_clock_dividers(rdev
, COMPUTE_ENGINE_PLL_PARAM
,
136 engine_clock
, false, ÷rs
);
140 reference_divider
= 1 + dividers
.ref_div
;
142 tmp
= (u64
) engine_clock
* reference_divider
* dividers
.post_div
* 16384;
143 do_div(tmp
, reference_clock
);
146 spll_func_cntl
&= ~(SPLL_PDIV_A_MASK
| SPLL_REF_DIV_MASK
);
147 spll_func_cntl
|= SPLL_REF_DIV(dividers
.ref_div
);
148 spll_func_cntl
|= SPLL_PDIV_A(dividers
.post_div
);
150 spll_func_cntl_2
&= ~SCLK_MUX_SEL_MASK
;
151 spll_func_cntl_2
|= SCLK_MUX_SEL(2);
153 spll_func_cntl_3
&= ~SPLL_FB_DIV_MASK
;
154 spll_func_cntl_3
|= SPLL_FB_DIV(fbdiv
);
155 spll_func_cntl_3
|= SPLL_DITHEN
;
158 struct radeon_atom_ss ss
;
159 u32 vco_freq
= engine_clock
* dividers
.post_div
;
161 if (radeon_atombios_get_asic_ss_info(rdev
, &ss
,
162 ASIC_INTERNAL_ENGINE_SS
, vco_freq
)) {
163 u32 clk_s
= reference_clock
* 5 / (reference_divider
* ss
.rate
);
164 u32 clk_v
= 4 * ss
.percentage
* fbdiv
/ (clk_s
* 10000);
166 cg_spll_spread_spectrum
&= ~CLK_S_MASK
;
167 cg_spll_spread_spectrum
|= CLK_S(clk_s
);
168 cg_spll_spread_spectrum
|= SSEN
;
170 cg_spll_spread_spectrum_2
&= ~CLK_V_MASK
;
171 cg_spll_spread_spectrum_2
|= CLK_V(clk_v
);
175 sclk
->sclk_value
= cpu_to_be32(engine_clock
);
176 sclk
->vCG_SPLL_FUNC_CNTL
= cpu_to_be32(spll_func_cntl
);
177 sclk
->vCG_SPLL_FUNC_CNTL_2
= cpu_to_be32(spll_func_cntl_2
);
178 sclk
->vCG_SPLL_FUNC_CNTL_3
= cpu_to_be32(spll_func_cntl_3
);
179 sclk
->vCG_SPLL_SPREAD_SPECTRUM
= cpu_to_be32(cg_spll_spread_spectrum
);
180 sclk
->vCG_SPLL_SPREAD_SPECTRUM_2
= cpu_to_be32(cg_spll_spread_spectrum_2
);
185 int rv740_populate_mclk_value(struct radeon_device
*rdev
,
186 u32 engine_clock
, u32 memory_clock
,
187 RV7XX_SMC_MCLK_VALUE
*mclk
)
189 struct rv7xx_power_info
*pi
= rv770_get_pi(rdev
);
190 u32 mpll_ad_func_cntl
= pi
->clk_regs
.rv770
.mpll_ad_func_cntl
;
191 u32 mpll_ad_func_cntl_2
= pi
->clk_regs
.rv770
.mpll_ad_func_cntl_2
;
192 u32 mpll_dq_func_cntl
= pi
->clk_regs
.rv770
.mpll_dq_func_cntl
;
193 u32 mpll_dq_func_cntl_2
= pi
->clk_regs
.rv770
.mpll_dq_func_cntl_2
;
194 u32 mclk_pwrmgt_cntl
= pi
->clk_regs
.rv770
.mclk_pwrmgt_cntl
;
195 u32 dll_cntl
= pi
->clk_regs
.rv770
.dll_cntl
;
196 u32 mpll_ss1
= pi
->clk_regs
.rv770
.mpll_ss1
;
197 u32 mpll_ss2
= pi
->clk_regs
.rv770
.mpll_ss2
;
198 struct atom_clock_dividers dividers
;
203 ret
= radeon_atom_get_clock_dividers(rdev
, COMPUTE_MEMORY_PLL_PARAM
,
204 memory_clock
, false, ÷rs
);
208 ibias
= rv770_map_clkf_to_ibias(rdev
, dividers
.whole_fb_div
);
210 mpll_ad_func_cntl
&= ~(CLKR_MASK
|
215 mpll_ad_func_cntl
|= CLKR(dividers
.ref_div
);
216 mpll_ad_func_cntl
|= YCLK_POST_DIV(dividers
.post_div
);
217 mpll_ad_func_cntl
|= CLKF(dividers
.whole_fb_div
);
218 mpll_ad_func_cntl
|= CLKFRAC(dividers
.frac_fb_div
);
219 mpll_ad_func_cntl
|= IBIAS(ibias
);
221 if (dividers
.vco_mode
)
222 mpll_ad_func_cntl_2
|= VCO_MODE
;
224 mpll_ad_func_cntl_2
&= ~VCO_MODE
;
227 mpll_dq_func_cntl
&= ~(CLKR_MASK
|
232 mpll_dq_func_cntl
|= CLKR(dividers
.ref_div
);
233 mpll_dq_func_cntl
|= YCLK_POST_DIV(dividers
.post_div
);
234 mpll_dq_func_cntl
|= CLKF(dividers
.whole_fb_div
);
235 mpll_dq_func_cntl
|= CLKFRAC(dividers
.frac_fb_div
);
236 mpll_dq_func_cntl
|= IBIAS(ibias
);
238 if (dividers
.vco_mode
)
239 mpll_dq_func_cntl_2
|= VCO_MODE
;
241 mpll_dq_func_cntl_2
&= ~VCO_MODE
;
245 struct radeon_atom_ss ss
;
246 u32 vco_freq
= memory_clock
* dividers
.post_div
;
248 if (radeon_atombios_get_asic_ss_info(rdev
, &ss
,
249 ASIC_INTERNAL_MEMORY_SS
, vco_freq
)) {
250 u32 reference_clock
= rdev
->clock
.mpll
.reference_freq
;
251 u32 decoded_ref
= rv740_get_decoded_reference_divider(dividers
.ref_div
);
252 u32 clk_s
= reference_clock
* 5 / (decoded_ref
* ss
.rate
);
253 u32 clk_v
= 0x40000 * ss
.percentage
*
254 (dividers
.whole_fb_div
+ (dividers
.frac_fb_div
/ 8)) / (clk_s
* 10000);
256 mpll_ss1
&= ~CLKV_MASK
;
257 mpll_ss1
|= CLKV(clk_v
);
259 mpll_ss2
&= ~CLKS_MASK
;
260 mpll_ss2
|= CLKS(clk_s
);
264 dll_speed
= rv740_get_dll_speed(pi
->mem_gddr5
,
267 mclk_pwrmgt_cntl
&= ~DLL_SPEED_MASK
;
268 mclk_pwrmgt_cntl
|= DLL_SPEED(dll_speed
);
270 mclk
->mclk770
.mclk_value
= cpu_to_be32(memory_clock
);
271 mclk
->mclk770
.vMPLL_AD_FUNC_CNTL
= cpu_to_be32(mpll_ad_func_cntl
);
272 mclk
->mclk770
.vMPLL_AD_FUNC_CNTL_2
= cpu_to_be32(mpll_ad_func_cntl_2
);
273 mclk
->mclk770
.vMPLL_DQ_FUNC_CNTL
= cpu_to_be32(mpll_dq_func_cntl
);
274 mclk
->mclk770
.vMPLL_DQ_FUNC_CNTL_2
= cpu_to_be32(mpll_dq_func_cntl_2
);
275 mclk
->mclk770
.vMCLK_PWRMGT_CNTL
= cpu_to_be32(mclk_pwrmgt_cntl
);
276 mclk
->mclk770
.vDLL_CNTL
= cpu_to_be32(dll_cntl
);
277 mclk
->mclk770
.vMPLL_SS
= cpu_to_be32(mpll_ss1
);
278 mclk
->mclk770
.vMPLL_SS2
= cpu_to_be32(mpll_ss2
);
283 void rv740_read_clock_registers(struct radeon_device
*rdev
)
285 struct rv7xx_power_info
*pi
= rv770_get_pi(rdev
);
287 pi
->clk_regs
.rv770
.cg_spll_func_cntl
=
288 RREG32(CG_SPLL_FUNC_CNTL
);
289 pi
->clk_regs
.rv770
.cg_spll_func_cntl_2
=
290 RREG32(CG_SPLL_FUNC_CNTL_2
);
291 pi
->clk_regs
.rv770
.cg_spll_func_cntl_3
=
292 RREG32(CG_SPLL_FUNC_CNTL_3
);
293 pi
->clk_regs
.rv770
.cg_spll_spread_spectrum
=
294 RREG32(CG_SPLL_SPREAD_SPECTRUM
);
295 pi
->clk_regs
.rv770
.cg_spll_spread_spectrum_2
=
296 RREG32(CG_SPLL_SPREAD_SPECTRUM_2
);
298 pi
->clk_regs
.rv770
.mpll_ad_func_cntl
=
299 RREG32(MPLL_AD_FUNC_CNTL
);
300 pi
->clk_regs
.rv770
.mpll_ad_func_cntl_2
=
301 RREG32(MPLL_AD_FUNC_CNTL_2
);
302 pi
->clk_regs
.rv770
.mpll_dq_func_cntl
=
303 RREG32(MPLL_DQ_FUNC_CNTL
);
304 pi
->clk_regs
.rv770
.mpll_dq_func_cntl_2
=
305 RREG32(MPLL_DQ_FUNC_CNTL_2
);
306 pi
->clk_regs
.rv770
.mclk_pwrmgt_cntl
=
307 RREG32(MCLK_PWRMGT_CNTL
);
308 pi
->clk_regs
.rv770
.dll_cntl
= RREG32(DLL_CNTL
);
309 pi
->clk_regs
.rv770
.mpll_ss1
= RREG32(MPLL_SS1
);
310 pi
->clk_regs
.rv770
.mpll_ss2
= RREG32(MPLL_SS2
);
313 int rv740_populate_smc_acpi_state(struct radeon_device
*rdev
,
314 RV770_SMC_STATETABLE
*table
)
316 struct rv7xx_power_info
*pi
= rv770_get_pi(rdev
);
317 u32 mpll_ad_func_cntl
= pi
->clk_regs
.rv770
.mpll_ad_func_cntl
;
318 u32 mpll_ad_func_cntl_2
= pi
->clk_regs
.rv770
.mpll_ad_func_cntl_2
;
319 u32 mpll_dq_func_cntl
= pi
->clk_regs
.rv770
.mpll_dq_func_cntl
;
320 u32 mpll_dq_func_cntl_2
= pi
->clk_regs
.rv770
.mpll_dq_func_cntl_2
;
321 u32 spll_func_cntl
= pi
->clk_regs
.rv770
.cg_spll_func_cntl
;
322 u32 spll_func_cntl_2
= pi
->clk_regs
.rv770
.cg_spll_func_cntl_2
;
323 u32 spll_func_cntl_3
= pi
->clk_regs
.rv770
.cg_spll_func_cntl_3
;
324 u32 mclk_pwrmgt_cntl
= pi
->clk_regs
.rv770
.mclk_pwrmgt_cntl
;
325 u32 dll_cntl
= pi
->clk_regs
.rv770
.dll_cntl
;
327 table
->ACPIState
= table
->initialState
;
329 table
->ACPIState
.flags
&= ~PPSMC_SWSTATE_FLAG_DC
;
332 rv770_populate_vddc_value(rdev
, pi
->acpi_vddc
,
333 &table
->ACPIState
.levels
[0].vddc
);
334 table
->ACPIState
.levels
[0].gen2PCIE
=
336 pi
->acpi_pcie_gen2
: 0;
337 table
->ACPIState
.levels
[0].gen2XSP
=
340 rv770_populate_vddc_value(rdev
, pi
->min_vddc_in_table
,
341 &table
->ACPIState
.levels
[0].vddc
);
342 table
->ACPIState
.levels
[0].gen2PCIE
= 0;
345 mpll_ad_func_cntl_2
|= BIAS_GEN_PDNB
| RESET_EN
;
347 mpll_dq_func_cntl_2
|= BYPASS
| BIAS_GEN_PDNB
| RESET_EN
;
349 mclk_pwrmgt_cntl
|= (MRDCKA0_RESET
|
358 dll_cntl
|= (MRDCKA0_BYPASS
|
367 spll_func_cntl
|= SPLL_RESET
| SPLL_SLEEP
| SPLL_BYPASS_EN
;
369 spll_func_cntl_2
&= ~SCLK_MUX_SEL_MASK
;
370 spll_func_cntl_2
|= SCLK_MUX_SEL(4);
372 table
->ACPIState
.levels
[0].mclk
.mclk770
.vMPLL_AD_FUNC_CNTL
= cpu_to_be32(mpll_ad_func_cntl
);
373 table
->ACPIState
.levels
[0].mclk
.mclk770
.vMPLL_AD_FUNC_CNTL_2
= cpu_to_be32(mpll_ad_func_cntl_2
);
374 table
->ACPIState
.levels
[0].mclk
.mclk770
.vMPLL_DQ_FUNC_CNTL
= cpu_to_be32(mpll_dq_func_cntl
);
375 table
->ACPIState
.levels
[0].mclk
.mclk770
.vMPLL_DQ_FUNC_CNTL_2
= cpu_to_be32(mpll_dq_func_cntl_2
);
376 table
->ACPIState
.levels
[0].mclk
.mclk770
.vMCLK_PWRMGT_CNTL
= cpu_to_be32(mclk_pwrmgt_cntl
);
377 table
->ACPIState
.levels
[0].mclk
.mclk770
.vDLL_CNTL
= cpu_to_be32(dll_cntl
);
379 table
->ACPIState
.levels
[0].mclk
.mclk770
.mclk_value
= 0;
381 table
->ACPIState
.levels
[0].sclk
.vCG_SPLL_FUNC_CNTL
= cpu_to_be32(spll_func_cntl
);
382 table
->ACPIState
.levels
[0].sclk
.vCG_SPLL_FUNC_CNTL_2
= cpu_to_be32(spll_func_cntl_2
);
383 table
->ACPIState
.levels
[0].sclk
.vCG_SPLL_FUNC_CNTL_3
= cpu_to_be32(spll_func_cntl_3
);
385 table
->ACPIState
.levels
[0].sclk
.sclk_value
= 0;
387 table
->ACPIState
.levels
[1] = table
->ACPIState
.levels
[0];
388 table
->ACPIState
.levels
[2] = table
->ACPIState
.levels
[0];
390 rv770_populate_mvdd_value(rdev
, 0, &table
->ACPIState
.levels
[0].mvdd
);
395 void rv740_enable_mclk_spread_spectrum(struct radeon_device
*rdev
,
399 WREG32_P(MPLL_CNTL_MODE
, SS_SSEN
, ~SS_SSEN
);
401 WREG32_P(MPLL_CNTL_MODE
, 0, ~SS_SSEN
);
404 u8
rv740_get_mclk_frequency_ratio(u32 memory_clock
)
408 if ((memory_clock
< 10000) || (memory_clock
> 47500))
409 mc_para_index
= 0x00;
411 mc_para_index
= (u8
)((memory_clock
- 10000) / 2500);
413 return mc_para_index
;