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