Line data Source code
1 : /*
2 : * Copyright 2011 Advanced Micro Devices, Inc.
3 : *
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:
10 : *
11 : * The above copyright notice and this permission notice shall be included in
12 : * all copies or substantial portions of the Software.
13 : *
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.
21 : *
22 : * Authors: Alex Deucher
23 : */
24 :
25 : #include <dev/pci/drm/drmP.h>
26 : #include "radeon.h"
27 : #include "radeon_asic.h"
28 : #include "rs780d.h"
29 : #include "r600_dpm.h"
30 : #include "rs780_dpm.h"
31 : #include "atom.h"
32 :
33 0 : static struct igp_ps *rs780_get_ps(struct radeon_ps *rps)
34 : {
35 0 : struct igp_ps *ps = rps->ps_priv;
36 :
37 0 : return ps;
38 : }
39 :
40 0 : static struct igp_power_info *rs780_get_pi(struct radeon_device *rdev)
41 : {
42 0 : struct igp_power_info *pi = rdev->pm.dpm.priv;
43 :
44 0 : return pi;
45 : }
46 :
47 0 : static void rs780_get_pm_mode_parameters(struct radeon_device *rdev)
48 : {
49 0 : struct igp_power_info *pi = rs780_get_pi(rdev);
50 0 : struct radeon_mode_info *minfo = &rdev->mode_info;
51 : struct drm_crtc *crtc;
52 : struct radeon_crtc *radeon_crtc;
53 : int i;
54 :
55 : /* defaults */
56 0 : pi->crtc_id = 0;
57 0 : pi->refresh_rate = 60;
58 :
59 0 : for (i = 0; i < rdev->num_crtc; i++) {
60 0 : crtc = (struct drm_crtc *)minfo->crtcs[i];
61 0 : if (crtc && crtc->enabled) {
62 0 : radeon_crtc = to_radeon_crtc(crtc);
63 0 : pi->crtc_id = radeon_crtc->crtc_id;
64 0 : if (crtc->mode.htotal && crtc->mode.vtotal)
65 0 : pi->refresh_rate = drm_mode_vrefresh(&crtc->mode);
66 : break;
67 : }
68 : }
69 0 : }
70 :
71 : static void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable);
72 :
73 0 : static int rs780_initialize_dpm_power_state(struct radeon_device *rdev,
74 : struct radeon_ps *boot_ps)
75 : {
76 0 : struct atom_clock_dividers dividers;
77 0 : struct igp_ps *default_state = rs780_get_ps(boot_ps);
78 : int i, ret;
79 :
80 0 : ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
81 0 : default_state->sclk_low, false, ÷rs);
82 0 : if (ret)
83 0 : return ret;
84 :
85 0 : r600_engine_clock_entry_set_reference_divider(rdev, 0, dividers.ref_div);
86 0 : r600_engine_clock_entry_set_feedback_divider(rdev, 0, dividers.fb_div);
87 0 : r600_engine_clock_entry_set_post_divider(rdev, 0, dividers.post_div);
88 :
89 0 : if (dividers.enable_post_div)
90 0 : r600_engine_clock_entry_enable_post_divider(rdev, 0, true);
91 : else
92 0 : r600_engine_clock_entry_enable_post_divider(rdev, 0, false);
93 :
94 0 : r600_engine_clock_entry_set_step_time(rdev, 0, R600_SST_DFLT);
95 0 : r600_engine_clock_entry_enable_pulse_skipping(rdev, 0, false);
96 :
97 0 : r600_engine_clock_entry_enable(rdev, 0, true);
98 0 : for (i = 1; i < R600_PM_NUMBER_OF_SCLKS; i++)
99 0 : r600_engine_clock_entry_enable(rdev, i, false);
100 :
101 0 : r600_enable_mclk_control(rdev, false);
102 0 : r600_voltage_control_enable_pins(rdev, 0);
103 :
104 0 : return 0;
105 0 : }
106 :
107 0 : static int rs780_initialize_dpm_parameters(struct radeon_device *rdev,
108 : struct radeon_ps *boot_ps)
109 : {
110 : int ret = 0;
111 : int i;
112 :
113 0 : r600_set_bsp(rdev, R600_BSU_DFLT, R600_BSP_DFLT);
114 :
115 0 : r600_set_at(rdev, 0, 0, 0, 0);
116 :
117 0 : r600_set_git(rdev, R600_GICST_DFLT);
118 :
119 0 : for (i = 0; i < R600_PM_NUMBER_OF_TC; i++)
120 0 : r600_set_tc(rdev, i, 0, 0);
121 :
122 0 : r600_select_td(rdev, R600_TD_DFLT);
123 0 : r600_set_vrc(rdev, 0);
124 :
125 0 : r600_set_tpu(rdev, R600_TPU_DFLT);
126 0 : r600_set_tpc(rdev, R600_TPC_DFLT);
127 :
128 0 : r600_set_sstu(rdev, R600_SSTU_DFLT);
129 0 : r600_set_sst(rdev, R600_SST_DFLT);
130 :
131 0 : r600_set_fctu(rdev, R600_FCTU_DFLT);
132 0 : r600_set_fct(rdev, R600_FCT_DFLT);
133 :
134 0 : r600_set_vddc3d_oorsu(rdev, R600_VDDC3DOORSU_DFLT);
135 0 : r600_set_vddc3d_oorphc(rdev, R600_VDDC3DOORPHC_DFLT);
136 0 : r600_set_vddc3d_oorsdc(rdev, R600_VDDC3DOORSDC_DFLT);
137 0 : r600_set_ctxcgtt3d_rphc(rdev, R600_CTXCGTT3DRPHC_DFLT);
138 0 : r600_set_ctxcgtt3d_rsdc(rdev, R600_CTXCGTT3DRSDC_DFLT);
139 :
140 0 : r600_vid_rt_set_vru(rdev, R600_VRU_DFLT);
141 0 : r600_vid_rt_set_vrt(rdev, R600_VOLTAGERESPONSETIME_DFLT);
142 0 : r600_vid_rt_set_ssu(rdev, R600_SPLLSTEPUNIT_DFLT);
143 :
144 0 : ret = rs780_initialize_dpm_power_state(rdev, boot_ps);
145 :
146 0 : r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW, 0);
147 0 : r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
148 0 : r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_HIGH, 0);
149 :
150 0 : r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW, 0);
151 0 : r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
152 0 : r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_HIGH, 0);
153 :
154 0 : r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW, 0);
155 0 : r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
156 0 : r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_HIGH, 0);
157 :
158 0 : r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW, R600_DISPLAY_WATERMARK_HIGH);
159 0 : r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM, R600_DISPLAY_WATERMARK_HIGH);
160 0 : r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_HIGH, R600_DISPLAY_WATERMARK_HIGH);
161 :
162 0 : r600_power_level_enable(rdev, R600_POWER_LEVEL_CTXSW, false);
163 0 : r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false);
164 0 : r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false);
165 0 : r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
166 :
167 0 : r600_power_level_set_enter_index(rdev, R600_POWER_LEVEL_LOW);
168 :
169 0 : r600_set_vrc(rdev, RS780_CGFTV_DFLT);
170 :
171 0 : return ret;
172 : }
173 :
174 0 : static void rs780_start_dpm(struct radeon_device *rdev)
175 : {
176 0 : r600_enable_sclk_control(rdev, false);
177 0 : r600_enable_mclk_control(rdev, false);
178 :
179 0 : r600_dynamicpm_enable(rdev, true);
180 :
181 0 : radeon_wait_for_vblank(rdev, 0);
182 0 : radeon_wait_for_vblank(rdev, 1);
183 :
184 0 : r600_enable_spll_bypass(rdev, true);
185 0 : r600_wait_for_spll_change(rdev);
186 0 : r600_enable_spll_bypass(rdev, false);
187 0 : r600_wait_for_spll_change(rdev);
188 :
189 0 : r600_enable_spll_bypass(rdev, true);
190 0 : r600_wait_for_spll_change(rdev);
191 0 : r600_enable_spll_bypass(rdev, false);
192 0 : r600_wait_for_spll_change(rdev);
193 :
194 0 : r600_enable_sclk_control(rdev, true);
195 0 : }
196 :
197 :
198 0 : static void rs780_preset_ranges_slow_clk_fbdiv_en(struct radeon_device *rdev)
199 : {
200 0 : WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1, RANGE_SLOW_CLK_FEEDBACK_DIV_EN,
201 : ~RANGE_SLOW_CLK_FEEDBACK_DIV_EN);
202 :
203 0 : WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1,
204 : RANGE0_SLOW_CLK_FEEDBACK_DIV(RS780_SLOWCLKFEEDBACKDIV_DFLT),
205 : ~RANGE0_SLOW_CLK_FEEDBACK_DIV_MASK);
206 0 : }
207 :
208 0 : static void rs780_preset_starting_fbdiv(struct radeon_device *rdev)
209 : {
210 0 : u32 fbdiv = (RREG32(CG_SPLL_FUNC_CNTL) & SPLL_FB_DIV_MASK) >> SPLL_FB_DIV_SHIFT;
211 :
212 0 : WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(fbdiv),
213 : ~STARTING_FEEDBACK_DIV_MASK);
214 :
215 0 : WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(fbdiv),
216 : ~FORCED_FEEDBACK_DIV_MASK);
217 :
218 0 : WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
219 0 : }
220 :
221 0 : static void rs780_voltage_scaling_init(struct radeon_device *rdev)
222 : {
223 0 : struct igp_power_info *pi = rs780_get_pi(rdev);
224 0 : struct drm_device *dev = rdev->ddev;
225 : u32 fv_throt_pwm_fb_div_range[3];
226 : u32 fv_throt_pwm_range[4];
227 :
228 0 : if (dev->pdev->device == 0x9614) {
229 : fv_throt_pwm_fb_div_range[0] = RS780D_FVTHROTPWMFBDIVRANGEREG0_DFLT;
230 : fv_throt_pwm_fb_div_range[1] = RS780D_FVTHROTPWMFBDIVRANGEREG1_DFLT;
231 : fv_throt_pwm_fb_div_range[2] = RS780D_FVTHROTPWMFBDIVRANGEREG2_DFLT;
232 0 : } else if ((dev->pdev->device == 0x9714) ||
233 0 : (dev->pdev->device == 0x9715)) {
234 : fv_throt_pwm_fb_div_range[0] = RS880D_FVTHROTPWMFBDIVRANGEREG0_DFLT;
235 : fv_throt_pwm_fb_div_range[1] = RS880D_FVTHROTPWMFBDIVRANGEREG1_DFLT;
236 : fv_throt_pwm_fb_div_range[2] = RS880D_FVTHROTPWMFBDIVRANGEREG2_DFLT;
237 0 : } else {
238 : fv_throt_pwm_fb_div_range[0] = RS780_FVTHROTPWMFBDIVRANGEREG0_DFLT;
239 : fv_throt_pwm_fb_div_range[1] = RS780_FVTHROTPWMFBDIVRANGEREG1_DFLT;
240 : fv_throt_pwm_fb_div_range[2] = RS780_FVTHROTPWMFBDIVRANGEREG2_DFLT;
241 : }
242 :
243 0 : if (pi->pwm_voltage_control) {
244 0 : fv_throt_pwm_range[0] = pi->min_voltage;
245 0 : fv_throt_pwm_range[1] = pi->min_voltage;
246 0 : fv_throt_pwm_range[2] = pi->max_voltage;
247 : fv_throt_pwm_range[3] = pi->max_voltage;
248 0 : } else {
249 0 : fv_throt_pwm_range[0] = pi->invert_pwm_required ?
250 : RS780_FVTHROTPWMRANGE3_GPIO_DFLT : RS780_FVTHROTPWMRANGE0_GPIO_DFLT;
251 0 : fv_throt_pwm_range[1] = pi->invert_pwm_required ?
252 : RS780_FVTHROTPWMRANGE2_GPIO_DFLT : RS780_FVTHROTPWMRANGE1_GPIO_DFLT;
253 0 : fv_throt_pwm_range[2] = pi->invert_pwm_required ?
254 : RS780_FVTHROTPWMRANGE1_GPIO_DFLT : RS780_FVTHROTPWMRANGE2_GPIO_DFLT;
255 : fv_throt_pwm_range[3] = pi->invert_pwm_required ?
256 : RS780_FVTHROTPWMRANGE0_GPIO_DFLT : RS780_FVTHROTPWMRANGE3_GPIO_DFLT;
257 : }
258 :
259 0 : WREG32_P(FVTHROT_PWM_CTRL_REG0,
260 : STARTING_PWM_HIGHTIME(pi->max_voltage),
261 : ~STARTING_PWM_HIGHTIME_MASK);
262 :
263 0 : WREG32_P(FVTHROT_PWM_CTRL_REG0,
264 : NUMBER_OF_CYCLES_IN_PERIOD(pi->num_of_cycles_in_period),
265 : ~NUMBER_OF_CYCLES_IN_PERIOD_MASK);
266 :
267 0 : WREG32_P(FVTHROT_PWM_CTRL_REG0, FORCE_STARTING_PWM_HIGHTIME,
268 : ~FORCE_STARTING_PWM_HIGHTIME);
269 :
270 0 : if (pi->invert_pwm_required)
271 0 : WREG32_P(FVTHROT_PWM_CTRL_REG0, INVERT_PWM_WAVEFORM, ~INVERT_PWM_WAVEFORM);
272 : else
273 0 : WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~INVERT_PWM_WAVEFORM);
274 :
275 0 : rs780_voltage_scaling_enable(rdev, true);
276 :
277 0 : WREG32(FVTHROT_PWM_CTRL_REG1,
278 : (MIN_PWM_HIGHTIME(pi->min_voltage) |
279 : MAX_PWM_HIGHTIME(pi->max_voltage)));
280 :
281 0 : WREG32(FVTHROT_PWM_US_REG0, RS780_FVTHROTPWMUSREG0_DFLT);
282 0 : WREG32(FVTHROT_PWM_US_REG1, RS780_FVTHROTPWMUSREG1_DFLT);
283 0 : WREG32(FVTHROT_PWM_DS_REG0, RS780_FVTHROTPWMDSREG0_DFLT);
284 0 : WREG32(FVTHROT_PWM_DS_REG1, RS780_FVTHROTPWMDSREG1_DFLT);
285 :
286 0 : WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1,
287 : RANGE0_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[0]),
288 : ~RANGE0_PWM_FEEDBACK_DIV_MASK);
289 :
290 0 : WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG2,
291 : (RANGE1_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[1]) |
292 : RANGE2_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[2])));
293 :
294 0 : WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG3,
295 : (RANGE0_PWM(fv_throt_pwm_range[1]) |
296 : RANGE1_PWM(fv_throt_pwm_range[2])));
297 0 : WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG4,
298 : (RANGE2_PWM(fv_throt_pwm_range[1]) |
299 : RANGE3_PWM(fv_throt_pwm_range[2])));
300 0 : }
301 :
302 0 : static void rs780_clk_scaling_enable(struct radeon_device *rdev, bool enable)
303 : {
304 0 : if (enable)
305 0 : WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT | ENABLE_FV_UPDATE,
306 : ~(ENABLE_FV_THROT | ENABLE_FV_UPDATE));
307 : else
308 0 : WREG32_P(FVTHROT_CNTRL_REG, 0,
309 : ~(ENABLE_FV_THROT | ENABLE_FV_UPDATE));
310 0 : }
311 :
312 0 : static void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable)
313 : {
314 0 : if (enable)
315 0 : WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT_IO, ~ENABLE_FV_THROT_IO);
316 : else
317 0 : WREG32_P(FVTHROT_CNTRL_REG, 0, ~ENABLE_FV_THROT_IO);
318 0 : }
319 :
320 0 : static void rs780_set_engine_clock_wfc(struct radeon_device *rdev)
321 : {
322 0 : WREG32(FVTHROT_UTC0, RS780_FVTHROTUTC0_DFLT);
323 0 : WREG32(FVTHROT_UTC1, RS780_FVTHROTUTC1_DFLT);
324 0 : WREG32(FVTHROT_UTC2, RS780_FVTHROTUTC2_DFLT);
325 0 : WREG32(FVTHROT_UTC3, RS780_FVTHROTUTC3_DFLT);
326 0 : WREG32(FVTHROT_UTC4, RS780_FVTHROTUTC4_DFLT);
327 :
328 0 : WREG32(FVTHROT_DTC0, RS780_FVTHROTDTC0_DFLT);
329 0 : WREG32(FVTHROT_DTC1, RS780_FVTHROTDTC1_DFLT);
330 0 : WREG32(FVTHROT_DTC2, RS780_FVTHROTDTC2_DFLT);
331 0 : WREG32(FVTHROT_DTC3, RS780_FVTHROTDTC3_DFLT);
332 0 : WREG32(FVTHROT_DTC4, RS780_FVTHROTDTC4_DFLT);
333 0 : }
334 :
335 0 : static void rs780_set_engine_clock_sc(struct radeon_device *rdev)
336 : {
337 0 : WREG32_P(FVTHROT_FBDIV_REG2,
338 : FB_DIV_TIMER_VAL(RS780_FBDIVTIMERVAL_DFLT),
339 : ~FB_DIV_TIMER_VAL_MASK);
340 :
341 0 : WREG32_P(FVTHROT_CNTRL_REG,
342 : REFRESH_RATE_DIVISOR(0) | MINIMUM_CIP(0xf),
343 : ~(REFRESH_RATE_DIVISOR_MASK | MINIMUM_CIP_MASK));
344 0 : }
345 :
346 0 : static void rs780_set_engine_clock_tdc(struct radeon_device *rdev)
347 : {
348 0 : WREG32_P(FVTHROT_CNTRL_REG, 0, ~(FORCE_TREND_SEL | TREND_SEL_MODE));
349 0 : }
350 :
351 0 : static void rs780_set_engine_clock_ssc(struct radeon_device *rdev)
352 : {
353 0 : WREG32(FVTHROT_FB_US_REG0, RS780_FVTHROTFBUSREG0_DFLT);
354 0 : WREG32(FVTHROT_FB_US_REG1, RS780_FVTHROTFBUSREG1_DFLT);
355 0 : WREG32(FVTHROT_FB_DS_REG0, RS780_FVTHROTFBDSREG0_DFLT);
356 0 : WREG32(FVTHROT_FB_DS_REG1, RS780_FVTHROTFBDSREG1_DFLT);
357 :
358 0 : WREG32_P(FVTHROT_FBDIV_REG1, MAX_FEEDBACK_STEP(1), ~MAX_FEEDBACK_STEP_MASK);
359 0 : }
360 :
361 0 : static void rs780_program_at(struct radeon_device *rdev)
362 : {
363 0 : struct igp_power_info *pi = rs780_get_pi(rdev);
364 :
365 0 : WREG32(FVTHROT_TARGET_REG, 30000000 / pi->refresh_rate);
366 0 : WREG32(FVTHROT_CB1, 1000000 * 5 / pi->refresh_rate);
367 0 : WREG32(FVTHROT_CB2, 1000000 * 10 / pi->refresh_rate);
368 0 : WREG32(FVTHROT_CB3, 1000000 * 30 / pi->refresh_rate);
369 0 : WREG32(FVTHROT_CB4, 1000000 * 50 / pi->refresh_rate);
370 0 : }
371 :
372 0 : static void rs780_disable_vbios_powersaving(struct radeon_device *rdev)
373 : {
374 0 : WREG32_P(CG_INTGFX_MISC, 0, ~0xFFF00000);
375 0 : }
376 :
377 0 : static void rs780_force_voltage(struct radeon_device *rdev, u16 voltage)
378 : {
379 0 : struct igp_ps *current_state = rs780_get_ps(rdev->pm.dpm.current_ps);
380 :
381 0 : if ((current_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
382 0 : (current_state->min_voltage == RS780_VDDC_LEVEL_HIGH))
383 0 : return;
384 :
385 0 : WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
386 :
387 0 : udelay(1);
388 :
389 0 : WREG32_P(FVTHROT_PWM_CTRL_REG0,
390 : STARTING_PWM_HIGHTIME(voltage),
391 : ~STARTING_PWM_HIGHTIME_MASK);
392 :
393 0 : WREG32_P(FVTHROT_PWM_CTRL_REG0,
394 : FORCE_STARTING_PWM_HIGHTIME, ~FORCE_STARTING_PWM_HIGHTIME);
395 :
396 0 : WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1, 0,
397 : ~RANGE_PWM_FEEDBACK_DIV_EN);
398 :
399 0 : udelay(1);
400 :
401 0 : WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
402 0 : }
403 :
404 0 : static void rs780_force_fbdiv(struct radeon_device *rdev, u32 fb_div)
405 : {
406 0 : struct igp_ps *current_state = rs780_get_ps(rdev->pm.dpm.current_ps);
407 :
408 0 : if (current_state->sclk_low == current_state->sclk_high)
409 0 : return;
410 :
411 0 : WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
412 :
413 0 : WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(fb_div),
414 : ~FORCED_FEEDBACK_DIV_MASK);
415 0 : WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(fb_div),
416 : ~STARTING_FEEDBACK_DIV_MASK);
417 0 : WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
418 :
419 0 : udelay(100);
420 :
421 0 : WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
422 0 : }
423 :
424 0 : static int rs780_set_engine_clock_scaling(struct radeon_device *rdev,
425 : struct radeon_ps *new_ps,
426 : struct radeon_ps *old_ps)
427 : {
428 0 : struct atom_clock_dividers min_dividers, max_dividers, current_max_dividers;
429 0 : struct igp_ps *new_state = rs780_get_ps(new_ps);
430 0 : struct igp_ps *old_state = rs780_get_ps(old_ps);
431 : int ret;
432 :
433 0 : if ((new_state->sclk_high == old_state->sclk_high) &&
434 0 : (new_state->sclk_low == old_state->sclk_low))
435 0 : return 0;
436 :
437 0 : ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
438 0 : new_state->sclk_low, false, &min_dividers);
439 0 : if (ret)
440 0 : return ret;
441 :
442 0 : ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
443 0 : new_state->sclk_high, false, &max_dividers);
444 0 : if (ret)
445 0 : return ret;
446 :
447 0 : ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
448 0 : old_state->sclk_high, false, ¤t_max_dividers);
449 0 : if (ret)
450 0 : return ret;
451 :
452 0 : if ((min_dividers.ref_div != max_dividers.ref_div) ||
453 0 : (min_dividers.post_div != max_dividers.post_div) ||
454 0 : (max_dividers.ref_div != current_max_dividers.ref_div) ||
455 0 : (max_dividers.post_div != current_max_dividers.post_div))
456 0 : return -EINVAL;
457 :
458 0 : rs780_force_fbdiv(rdev, max_dividers.fb_div);
459 :
460 0 : if (max_dividers.fb_div > min_dividers.fb_div) {
461 0 : WREG32_P(FVTHROT_FBDIV_REG0,
462 : MIN_FEEDBACK_DIV(min_dividers.fb_div) |
463 : MAX_FEEDBACK_DIV(max_dividers.fb_div),
464 : ~(MIN_FEEDBACK_DIV_MASK | MAX_FEEDBACK_DIV_MASK));
465 :
466 0 : WREG32_P(FVTHROT_FBDIV_REG1, 0, ~FORCE_FEEDBACK_DIV);
467 0 : }
468 :
469 0 : return 0;
470 0 : }
471 :
472 0 : static void rs780_set_engine_clock_spc(struct radeon_device *rdev,
473 : struct radeon_ps *new_ps,
474 : struct radeon_ps *old_ps)
475 : {
476 0 : struct igp_ps *new_state = rs780_get_ps(new_ps);
477 0 : struct igp_ps *old_state = rs780_get_ps(old_ps);
478 0 : struct igp_power_info *pi = rs780_get_pi(rdev);
479 :
480 0 : if ((new_state->sclk_high == old_state->sclk_high) &&
481 0 : (new_state->sclk_low == old_state->sclk_low))
482 0 : return;
483 :
484 0 : if (pi->crtc_id == 0)
485 0 : WREG32_P(CG_INTGFX_MISC, 0, ~FVTHROT_VBLANK_SEL);
486 : else
487 0 : WREG32_P(CG_INTGFX_MISC, FVTHROT_VBLANK_SEL, ~FVTHROT_VBLANK_SEL);
488 :
489 0 : }
490 :
491 0 : static void rs780_activate_engine_clk_scaling(struct radeon_device *rdev,
492 : struct radeon_ps *new_ps,
493 : struct radeon_ps *old_ps)
494 : {
495 0 : struct igp_ps *new_state = rs780_get_ps(new_ps);
496 0 : struct igp_ps *old_state = rs780_get_ps(old_ps);
497 :
498 0 : if ((new_state->sclk_high == old_state->sclk_high) &&
499 0 : (new_state->sclk_low == old_state->sclk_low))
500 0 : return;
501 :
502 0 : if (new_state->sclk_high == new_state->sclk_low)
503 0 : return;
504 :
505 0 : rs780_clk_scaling_enable(rdev, true);
506 0 : }
507 :
508 0 : static u32 rs780_get_voltage_for_vddc_level(struct radeon_device *rdev,
509 : enum rs780_vddc_level vddc)
510 : {
511 0 : struct igp_power_info *pi = rs780_get_pi(rdev);
512 :
513 0 : if (vddc == RS780_VDDC_LEVEL_HIGH)
514 0 : return pi->max_voltage;
515 0 : else if (vddc == RS780_VDDC_LEVEL_LOW)
516 0 : return pi->min_voltage;
517 : else
518 0 : return pi->max_voltage;
519 0 : }
520 :
521 0 : static void rs780_enable_voltage_scaling(struct radeon_device *rdev,
522 : struct radeon_ps *new_ps)
523 : {
524 0 : struct igp_ps *new_state = rs780_get_ps(new_ps);
525 0 : struct igp_power_info *pi = rs780_get_pi(rdev);
526 : enum rs780_vddc_level vddc_high, vddc_low;
527 :
528 0 : udelay(100);
529 :
530 0 : if ((new_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
531 0 : (new_state->min_voltage == RS780_VDDC_LEVEL_HIGH))
532 0 : return;
533 :
534 0 : vddc_high = rs780_get_voltage_for_vddc_level(rdev,
535 0 : new_state->max_voltage);
536 0 : vddc_low = rs780_get_voltage_for_vddc_level(rdev,
537 0 : new_state->min_voltage);
538 :
539 0 : WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
540 :
541 0 : udelay(1);
542 0 : if (vddc_high > vddc_low) {
543 0 : WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1,
544 : RANGE_PWM_FEEDBACK_DIV_EN, ~RANGE_PWM_FEEDBACK_DIV_EN);
545 :
546 0 : WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~FORCE_STARTING_PWM_HIGHTIME);
547 0 : } else if (vddc_high == vddc_low) {
548 0 : if (pi->max_voltage != vddc_high) {
549 0 : WREG32_P(FVTHROT_PWM_CTRL_REG0,
550 : STARTING_PWM_HIGHTIME(vddc_high),
551 : ~STARTING_PWM_HIGHTIME_MASK);
552 :
553 0 : WREG32_P(FVTHROT_PWM_CTRL_REG0,
554 : FORCE_STARTING_PWM_HIGHTIME,
555 : ~FORCE_STARTING_PWM_HIGHTIME);
556 0 : }
557 : }
558 :
559 0 : WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
560 0 : }
561 :
562 0 : static void rs780_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev,
563 : struct radeon_ps *new_ps,
564 : struct radeon_ps *old_ps)
565 : {
566 0 : struct igp_ps *new_state = rs780_get_ps(new_ps);
567 0 : struct igp_ps *current_state = rs780_get_ps(old_ps);
568 :
569 0 : if ((new_ps->vclk == old_ps->vclk) &&
570 0 : (new_ps->dclk == old_ps->dclk))
571 0 : return;
572 :
573 0 : if (new_state->sclk_high >= current_state->sclk_high)
574 0 : return;
575 :
576 0 : radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk);
577 0 : }
578 :
579 0 : static void rs780_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
580 : struct radeon_ps *new_ps,
581 : struct radeon_ps *old_ps)
582 : {
583 0 : struct igp_ps *new_state = rs780_get_ps(new_ps);
584 0 : struct igp_ps *current_state = rs780_get_ps(old_ps);
585 :
586 0 : if ((new_ps->vclk == old_ps->vclk) &&
587 0 : (new_ps->dclk == old_ps->dclk))
588 0 : return;
589 :
590 0 : if (new_state->sclk_high < current_state->sclk_high)
591 0 : return;
592 :
593 0 : radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk);
594 0 : }
595 :
596 0 : int rs780_dpm_enable(struct radeon_device *rdev)
597 : {
598 0 : struct igp_power_info *pi = rs780_get_pi(rdev);
599 0 : struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
600 : int ret;
601 :
602 0 : rs780_get_pm_mode_parameters(rdev);
603 0 : rs780_disable_vbios_powersaving(rdev);
604 :
605 0 : if (r600_dynamicpm_enabled(rdev))
606 0 : return -EINVAL;
607 0 : ret = rs780_initialize_dpm_parameters(rdev, boot_ps);
608 0 : if (ret)
609 0 : return ret;
610 0 : rs780_start_dpm(rdev);
611 :
612 0 : rs780_preset_ranges_slow_clk_fbdiv_en(rdev);
613 0 : rs780_preset_starting_fbdiv(rdev);
614 0 : if (pi->voltage_control)
615 0 : rs780_voltage_scaling_init(rdev);
616 0 : rs780_clk_scaling_enable(rdev, true);
617 0 : rs780_set_engine_clock_sc(rdev);
618 0 : rs780_set_engine_clock_wfc(rdev);
619 0 : rs780_program_at(rdev);
620 0 : rs780_set_engine_clock_tdc(rdev);
621 0 : rs780_set_engine_clock_ssc(rdev);
622 :
623 0 : if (pi->gfx_clock_gating)
624 0 : r600_gfx_clockgating_enable(rdev, true);
625 :
626 0 : return 0;
627 0 : }
628 :
629 0 : void rs780_dpm_disable(struct radeon_device *rdev)
630 : {
631 0 : struct igp_power_info *pi = rs780_get_pi(rdev);
632 :
633 0 : r600_dynamicpm_enable(rdev, false);
634 :
635 0 : rs780_clk_scaling_enable(rdev, false);
636 0 : rs780_voltage_scaling_enable(rdev, false);
637 :
638 0 : if (pi->gfx_clock_gating)
639 0 : r600_gfx_clockgating_enable(rdev, false);
640 :
641 0 : if (rdev->irq.installed &&
642 0 : (rdev->pm.int_thermal_type == THERMAL_TYPE_RV6XX)) {
643 0 : rdev->irq.dpm_thermal = false;
644 0 : radeon_irq_set(rdev);
645 0 : }
646 0 : }
647 :
648 0 : int rs780_dpm_set_power_state(struct radeon_device *rdev)
649 : {
650 0 : struct igp_power_info *pi = rs780_get_pi(rdev);
651 0 : struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps;
652 0 : struct radeon_ps *old_ps = rdev->pm.dpm.current_ps;
653 : int ret;
654 :
655 0 : rs780_get_pm_mode_parameters(rdev);
656 :
657 0 : rs780_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
658 :
659 0 : if (pi->voltage_control) {
660 0 : rs780_force_voltage(rdev, pi->max_voltage);
661 0 : mdelay(5);
662 0 : }
663 :
664 0 : ret = rs780_set_engine_clock_scaling(rdev, new_ps, old_ps);
665 0 : if (ret)
666 0 : return ret;
667 0 : rs780_set_engine_clock_spc(rdev, new_ps, old_ps);
668 :
669 0 : rs780_activate_engine_clk_scaling(rdev, new_ps, old_ps);
670 :
671 0 : if (pi->voltage_control)
672 0 : rs780_enable_voltage_scaling(rdev, new_ps);
673 :
674 0 : rs780_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
675 :
676 0 : return 0;
677 0 : }
678 :
679 0 : void rs780_dpm_setup_asic(struct radeon_device *rdev)
680 : {
681 :
682 0 : }
683 :
684 0 : void rs780_dpm_display_configuration_changed(struct radeon_device *rdev)
685 : {
686 0 : rs780_get_pm_mode_parameters(rdev);
687 0 : rs780_program_at(rdev);
688 0 : }
689 :
690 : union igp_info {
691 : struct _ATOM_INTEGRATED_SYSTEM_INFO info;
692 : struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
693 : };
694 :
695 : union power_info {
696 : struct _ATOM_POWERPLAY_INFO info;
697 : struct _ATOM_POWERPLAY_INFO_V2 info_2;
698 : struct _ATOM_POWERPLAY_INFO_V3 info_3;
699 : struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
700 : struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
701 : struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
702 : };
703 :
704 : union pplib_clock_info {
705 : struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
706 : struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
707 : struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
708 : struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
709 : };
710 :
711 : union pplib_power_state {
712 : struct _ATOM_PPLIB_STATE v1;
713 : struct _ATOM_PPLIB_STATE_V2 v2;
714 : };
715 :
716 0 : static void rs780_parse_pplib_non_clock_info(struct radeon_device *rdev,
717 : struct radeon_ps *rps,
718 : struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
719 : u8 table_rev)
720 : {
721 0 : rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
722 0 : rps->class = le16_to_cpu(non_clock_info->usClassification);
723 0 : rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
724 :
725 0 : if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
726 0 : rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
727 0 : rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
728 0 : } else {
729 0 : rps->vclk = 0;
730 0 : rps->dclk = 0;
731 : }
732 :
733 0 : if (r600_is_uvd_state(rps->class, rps->class2)) {
734 0 : if ((rps->vclk == 0) || (rps->dclk == 0)) {
735 0 : rps->vclk = RS780_DEFAULT_VCLK_FREQ;
736 0 : rps->dclk = RS780_DEFAULT_DCLK_FREQ;
737 0 : }
738 : }
739 :
740 0 : if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
741 0 : rdev->pm.dpm.boot_ps = rps;
742 0 : if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
743 0 : rdev->pm.dpm.uvd_ps = rps;
744 0 : }
745 :
746 0 : static void rs780_parse_pplib_clock_info(struct radeon_device *rdev,
747 : struct radeon_ps *rps,
748 : union pplib_clock_info *clock_info)
749 : {
750 0 : struct igp_ps *ps = rs780_get_ps(rps);
751 : u32 sclk;
752 :
753 0 : sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow);
754 0 : sclk |= clock_info->rs780.ucLowEngineClockHigh << 16;
755 0 : ps->sclk_low = sclk;
756 0 : sclk = le16_to_cpu(clock_info->rs780.usHighEngineClockLow);
757 0 : sclk |= clock_info->rs780.ucHighEngineClockHigh << 16;
758 0 : ps->sclk_high = sclk;
759 0 : switch (le16_to_cpu(clock_info->rs780.usVDDC)) {
760 : case ATOM_PPLIB_RS780_VOLTAGE_NONE:
761 : default:
762 0 : ps->min_voltage = RS780_VDDC_LEVEL_UNKNOWN;
763 0 : ps->max_voltage = RS780_VDDC_LEVEL_UNKNOWN;
764 0 : break;
765 : case ATOM_PPLIB_RS780_VOLTAGE_LOW:
766 0 : ps->min_voltage = RS780_VDDC_LEVEL_LOW;
767 0 : ps->max_voltage = RS780_VDDC_LEVEL_LOW;
768 0 : break;
769 : case ATOM_PPLIB_RS780_VOLTAGE_HIGH:
770 0 : ps->min_voltage = RS780_VDDC_LEVEL_HIGH;
771 0 : ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
772 0 : break;
773 : case ATOM_PPLIB_RS780_VOLTAGE_VARIABLE:
774 0 : ps->min_voltage = RS780_VDDC_LEVEL_LOW;
775 0 : ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
776 0 : break;
777 : }
778 0 : ps->flags = le32_to_cpu(clock_info->rs780.ulFlags);
779 :
780 0 : if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
781 0 : ps->sclk_low = rdev->clock.default_sclk;
782 0 : ps->sclk_high = rdev->clock.default_sclk;
783 0 : ps->min_voltage = RS780_VDDC_LEVEL_HIGH;
784 0 : ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
785 0 : }
786 0 : }
787 :
788 0 : static int rs780_parse_power_table(struct radeon_device *rdev)
789 : {
790 0 : struct radeon_mode_info *mode_info = &rdev->mode_info;
791 : struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
792 : union pplib_power_state *power_state;
793 : int i;
794 : union pplib_clock_info *clock_info;
795 : union power_info *power_info;
796 : int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
797 0 : u16 data_offset;
798 0 : u8 frev, crev;
799 : struct igp_ps *ps;
800 :
801 0 : if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
802 : &frev, &crev, &data_offset))
803 0 : return -EINVAL;
804 0 : power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
805 :
806 0 : rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
807 0 : power_info->pplib.ucNumStates, GFP_KERNEL);
808 0 : if (!rdev->pm.dpm.ps)
809 0 : return -ENOMEM;
810 :
811 0 : for (i = 0; i < power_info->pplib.ucNumStates; i++) {
812 0 : power_state = (union pplib_power_state *)
813 0 : (mode_info->atom_context->bios + data_offset +
814 0 : le16_to_cpu(power_info->pplib.usStateArrayOffset) +
815 0 : i * power_info->pplib.ucStateEntrySize);
816 0 : non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
817 0 : (mode_info->atom_context->bios + data_offset +
818 0 : le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
819 0 : (power_state->v1.ucNonClockStateIndex *
820 0 : power_info->pplib.ucNonClockSize));
821 0 : if (power_info->pplib.ucStateEntrySize - 1) {
822 0 : clock_info = (union pplib_clock_info *)
823 0 : (mode_info->atom_context->bios + data_offset +
824 0 : le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
825 0 : (power_state->v1.ucClockStateIndices[0] *
826 0 : power_info->pplib.ucClockInfoSize));
827 0 : ps = kzalloc(sizeof(struct igp_ps), GFP_KERNEL);
828 0 : if (ps == NULL) {
829 0 : kfree(rdev->pm.dpm.ps);
830 0 : return -ENOMEM;
831 : }
832 0 : rdev->pm.dpm.ps[i].ps_priv = ps;
833 0 : rs780_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
834 : non_clock_info,
835 0 : power_info->pplib.ucNonClockSize);
836 0 : rs780_parse_pplib_clock_info(rdev,
837 0 : &rdev->pm.dpm.ps[i],
838 : clock_info);
839 0 : }
840 : }
841 0 : rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates;
842 0 : return 0;
843 0 : }
844 :
845 0 : int rs780_dpm_init(struct radeon_device *rdev)
846 : {
847 : struct igp_power_info *pi;
848 : int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
849 : union igp_info *info;
850 0 : u16 data_offset;
851 0 : u8 frev, crev;
852 : int ret;
853 :
854 0 : pi = kzalloc(sizeof(struct igp_power_info), GFP_KERNEL);
855 0 : if (pi == NULL)
856 0 : return -ENOMEM;
857 0 : rdev->pm.dpm.priv = pi;
858 :
859 0 : ret = r600_get_platform_caps(rdev);
860 0 : if (ret)
861 0 : return ret;
862 :
863 0 : ret = rs780_parse_power_table(rdev);
864 0 : if (ret)
865 0 : return ret;
866 :
867 0 : pi->voltage_control = false;
868 0 : pi->gfx_clock_gating = true;
869 :
870 0 : if (atom_parse_data_header(rdev->mode_info.atom_context, index, NULL,
871 : &frev, &crev, &data_offset)) {
872 0 : info = (union igp_info *)(rdev->mode_info.atom_context->bios + data_offset);
873 :
874 : /* Get various system informations from bios */
875 0 : switch (crev) {
876 : case 1:
877 0 : pi->num_of_cycles_in_period =
878 0 : info->info.ucNumberOfCyclesInPeriod;
879 0 : pi->num_of_cycles_in_period |=
880 0 : info->info.ucNumberOfCyclesInPeriodHi << 8;
881 0 : pi->invert_pwm_required =
882 0 : (pi->num_of_cycles_in_period & 0x8000) ? true : false;
883 0 : pi->boot_voltage = info->info.ucStartingPWM_HighTime;
884 0 : pi->max_voltage = info->info.ucMaxNBVoltage;
885 0 : pi->max_voltage |= info->info.ucMaxNBVoltageHigh << 8;
886 0 : pi->min_voltage = info->info.ucMinNBVoltage;
887 0 : pi->min_voltage |= info->info.ucMinNBVoltageHigh << 8;
888 0 : pi->inter_voltage_low =
889 0 : le16_to_cpu(info->info.usInterNBVoltageLow);
890 0 : pi->inter_voltage_high =
891 0 : le16_to_cpu(info->info.usInterNBVoltageHigh);
892 0 : pi->voltage_control = true;
893 0 : pi->bootup_uma_clk = info->info.usK8MemoryClock * 100;
894 0 : break;
895 : case 2:
896 0 : pi->num_of_cycles_in_period =
897 0 : le16_to_cpu(info->info_2.usNumberOfCyclesInPeriod);
898 0 : pi->invert_pwm_required =
899 0 : (pi->num_of_cycles_in_period & 0x8000) ? true : false;
900 0 : pi->boot_voltage =
901 0 : le16_to_cpu(info->info_2.usBootUpNBVoltage);
902 0 : pi->max_voltage =
903 0 : le16_to_cpu(info->info_2.usMaxNBVoltage);
904 0 : pi->min_voltage =
905 0 : le16_to_cpu(info->info_2.usMinNBVoltage);
906 0 : pi->system_config =
907 0 : le32_to_cpu(info->info_2.ulSystemConfig);
908 0 : pi->pwm_voltage_control =
909 0 : (pi->system_config & 0x4) ? true : false;
910 0 : pi->voltage_control = true;
911 0 : pi->bootup_uma_clk = le32_to_cpu(info->info_2.ulBootUpUMAClock);
912 0 : break;
913 : default:
914 0 : DRM_ERROR("No integrated system info for your GPU\n");
915 0 : return -EINVAL;
916 : }
917 0 : if (pi->min_voltage > pi->max_voltage)
918 0 : pi->voltage_control = false;
919 0 : if (pi->pwm_voltage_control) {
920 0 : if ((pi->num_of_cycles_in_period == 0) ||
921 0 : (pi->max_voltage == 0) ||
922 0 : (pi->min_voltage == 0))
923 0 : pi->voltage_control = false;
924 : } else {
925 0 : if ((pi->num_of_cycles_in_period == 0) ||
926 0 : (pi->max_voltage == 0))
927 0 : pi->voltage_control = false;
928 : }
929 :
930 0 : return 0;
931 : }
932 0 : radeon_dpm_fini(rdev);
933 0 : return -EINVAL;
934 0 : }
935 :
936 0 : void rs780_dpm_print_power_state(struct radeon_device *rdev,
937 : struct radeon_ps *rps)
938 : {
939 0 : struct igp_ps *ps = rs780_get_ps(rps);
940 :
941 0 : r600_dpm_print_class_info(rps->class, rps->class2);
942 0 : r600_dpm_print_cap_info(rps->caps);
943 0 : printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
944 0 : printk("\t\tpower level 0 sclk: %u vddc_index: %d\n",
945 : ps->sclk_low, ps->min_voltage);
946 0 : printk("\t\tpower level 1 sclk: %u vddc_index: %d\n",
947 : ps->sclk_high, ps->max_voltage);
948 0 : r600_dpm_print_ps_status(rdev, rps);
949 0 : }
950 :
951 0 : void rs780_dpm_fini(struct radeon_device *rdev)
952 : {
953 : int i;
954 :
955 0 : for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
956 0 : kfree(rdev->pm.dpm.ps[i].ps_priv);
957 : }
958 0 : kfree(rdev->pm.dpm.ps);
959 0 : kfree(rdev->pm.dpm.priv);
960 0 : }
961 :
962 0 : u32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low)
963 : {
964 0 : struct igp_ps *requested_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
965 :
966 0 : if (low)
967 0 : return requested_state->sclk_low;
968 : else
969 0 : return requested_state->sclk_high;
970 0 : }
971 :
972 0 : u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low)
973 : {
974 0 : struct igp_power_info *pi = rs780_get_pi(rdev);
975 :
976 0 : return pi->bootup_uma_clk;
977 : }
978 :
979 0 : void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
980 : struct seq_file *m)
981 : {
982 0 : struct radeon_ps *rps = rdev->pm.dpm.current_ps;
983 0 : struct igp_ps *ps = rs780_get_ps(rps);
984 0 : u32 current_fb_div = RREG32(FVTHROT_STATUS_REG0) & CURRENT_FEEDBACK_DIV_MASK;
985 0 : u32 func_cntl = RREG32(CG_SPLL_FUNC_CNTL);
986 0 : u32 ref_div = ((func_cntl & SPLL_REF_DIV_MASK) >> SPLL_REF_DIV_SHIFT) + 1;
987 0 : u32 post_div = ((func_cntl & SPLL_SW_HILEN_MASK) >> SPLL_SW_HILEN_SHIFT) + 1 +
988 0 : ((func_cntl & SPLL_SW_LOLEN_MASK) >> SPLL_SW_LOLEN_SHIFT) + 1;
989 0 : u32 sclk = (rdev->clock.spll.reference_freq * current_fb_div) /
990 0 : (post_div * ref_div);
991 :
992 0 : seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
993 :
994 : /* guess based on the current sclk */
995 0 : if (sclk < (ps->sclk_low + 500))
996 0 : seq_printf(m, "power level 0 sclk: %u vddc_index: %d\n",
997 0 : ps->sclk_low, ps->min_voltage);
998 : else
999 0 : seq_printf(m, "power level 1 sclk: %u vddc_index: %d\n",
1000 0 : ps->sclk_high, ps->max_voltage);
1001 0 : }
1002 :
1003 : /* get the current sclk in 10 khz units */
1004 0 : u32 rs780_dpm_get_current_sclk(struct radeon_device *rdev)
1005 : {
1006 0 : u32 current_fb_div = RREG32(FVTHROT_STATUS_REG0) & CURRENT_FEEDBACK_DIV_MASK;
1007 0 : u32 func_cntl = RREG32(CG_SPLL_FUNC_CNTL);
1008 0 : u32 ref_div = ((func_cntl & SPLL_REF_DIV_MASK) >> SPLL_REF_DIV_SHIFT) + 1;
1009 0 : u32 post_div = ((func_cntl & SPLL_SW_HILEN_MASK) >> SPLL_SW_HILEN_SHIFT) + 1 +
1010 0 : ((func_cntl & SPLL_SW_LOLEN_MASK) >> SPLL_SW_LOLEN_SHIFT) + 1;
1011 0 : u32 sclk = (rdev->clock.spll.reference_freq * current_fb_div) /
1012 0 : (post_div * ref_div);
1013 :
1014 0 : return sclk;
1015 : }
1016 :
1017 : /* get the current mclk in 10 khz units */
1018 0 : u32 rs780_dpm_get_current_mclk(struct radeon_device *rdev)
1019 : {
1020 0 : struct igp_power_info *pi = rs780_get_pi(rdev);
1021 :
1022 0 : return pi->bootup_uma_clk;
1023 : }
1024 :
1025 0 : int rs780_dpm_force_performance_level(struct radeon_device *rdev,
1026 : enum radeon_dpm_forced_level level)
1027 : {
1028 0 : struct igp_power_info *pi = rs780_get_pi(rdev);
1029 0 : struct radeon_ps *rps = rdev->pm.dpm.current_ps;
1030 0 : struct igp_ps *ps = rs780_get_ps(rps);
1031 0 : struct atom_clock_dividers dividers;
1032 : int ret;
1033 :
1034 0 : rs780_clk_scaling_enable(rdev, false);
1035 0 : rs780_voltage_scaling_enable(rdev, false);
1036 :
1037 0 : if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
1038 0 : if (pi->voltage_control)
1039 0 : rs780_force_voltage(rdev, pi->max_voltage);
1040 :
1041 0 : ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
1042 0 : ps->sclk_high, false, ÷rs);
1043 0 : if (ret)
1044 0 : return ret;
1045 :
1046 0 : rs780_force_fbdiv(rdev, dividers.fb_div);
1047 0 : } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
1048 0 : ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
1049 0 : ps->sclk_low, false, ÷rs);
1050 0 : if (ret)
1051 0 : return ret;
1052 :
1053 0 : rs780_force_fbdiv(rdev, dividers.fb_div);
1054 :
1055 0 : if (pi->voltage_control)
1056 0 : rs780_force_voltage(rdev, pi->min_voltage);
1057 : } else {
1058 0 : if (pi->voltage_control)
1059 0 : rs780_force_voltage(rdev, pi->max_voltage);
1060 :
1061 0 : if (ps->sclk_high != ps->sclk_low) {
1062 0 : WREG32_P(FVTHROT_FBDIV_REG1, 0, ~FORCE_FEEDBACK_DIV);
1063 0 : rs780_clk_scaling_enable(rdev, true);
1064 0 : }
1065 :
1066 0 : if (pi->voltage_control) {
1067 0 : rs780_voltage_scaling_enable(rdev, true);
1068 0 : rs780_enable_voltage_scaling(rdev, rps);
1069 0 : }
1070 : }
1071 :
1072 0 : rdev->pm.dpm.forced_level = level;
1073 :
1074 0 : return 0;
1075 0 : }
|