diff mbox

[075/165] drm/radeon/kms: add dpm support for rs780/rs880

Message ID 1372253045-17042-76-git-send-email-alexdeucher@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Alex Deucher June 26, 2013, 1:22 p.m. UTC
From: Alex Deucher <alexander.deucher@amd.com>

This adds dpm support for rs780/rs880 asics.  This includes:
- clockgating
- dynamic engine clock scaling
- dynamic voltage scaling

set radeon.dpm=1 to enable it.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/Makefile      |    2 +-
 drivers/gpu/drm/radeon/radeon_asic.c |   12 +
 drivers/gpu/drm/radeon/radeon_asic.h |   12 +
 drivers/gpu/drm/radeon/radeon_pm.c   |    7 +
 drivers/gpu/drm/radeon/rs780_dpm.c   |  894 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/rs780_dpm.h   |  109 ++++
 drivers/gpu/drm/radeon/rs780d.h      |  168 +++++++
 7 files changed, 1203 insertions(+), 1 deletions(-)
 create mode 100644 drivers/gpu/drm/radeon/rs780_dpm.c
 create mode 100644 drivers/gpu/drm/radeon/rs780_dpm.h
 create mode 100644 drivers/gpu/drm/radeon/rs780d.h

Comments

Jerome Glisse June 26, 2013, 10:46 a.m. UTC | #1
On Wed, Jun 26, 2013 at 09:22:35AM -0400, alexdeucher@gmail.com wrote:
> From: Alex Deucher <alexander.deucher@amd.com>
> 
> This adds dpm support for rs780/rs880 asics.  This includes:
> - clockgating
> - dynamic engine clock scaling
> - dynamic voltage scaling
> 
> set radeon.dpm=1 to enable it.
> 
> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

Depending on the answer to inline question :

Reviewed-by: Jerome Glisse <jglisse@redhat.com>

> ---
>  drivers/gpu/drm/radeon/Makefile      |    2 +-
>  drivers/gpu/drm/radeon/radeon_asic.c |   12 +
>  drivers/gpu/drm/radeon/radeon_asic.h |   12 +
>  drivers/gpu/drm/radeon/radeon_pm.c   |    7 +
>  drivers/gpu/drm/radeon/rs780_dpm.c   |  894 ++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/radeon/rs780_dpm.h   |  109 ++++
>  drivers/gpu/drm/radeon/rs780d.h      |  168 +++++++
>  7 files changed, 1203 insertions(+), 1 deletions(-)
>  create mode 100644 drivers/gpu/drm/radeon/rs780_dpm.c
>  create mode 100644 drivers/gpu/drm/radeon/rs780_dpm.h
>  create mode 100644 drivers/gpu/drm/radeon/rs780d.h
> 
> diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
> index a131a13..e44b046 100644
> --- a/drivers/gpu/drm/radeon/Makefile
> +++ b/drivers/gpu/drm/radeon/Makefile
> @@ -77,7 +77,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
>  	evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \
>  	atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
>  	si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \
> -	r600_dpm.o
> +	r600_dpm.o rs780_dpm.o
>  
>  radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
>  radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
> diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
> index d9c8e9a..db3c930 100644
> --- a/drivers/gpu/drm/radeon/radeon_asic.c
> +++ b/drivers/gpu/drm/radeon/radeon_asic.c
> @@ -1194,6 +1194,18 @@ static struct radeon_asic rs780_asic = {
>  		.set_clock_gating = NULL,
>  		.get_temperature = &rv6xx_get_temp,
>  	},
> +	.dpm = {
> +		.init = &rs780_dpm_init,
> +		.setup_asic = &rs780_dpm_setup_asic,
> +		.enable = &rs780_dpm_enable,
> +		.disable = &rs780_dpm_disable,
> +		.set_power_state = &rs780_dpm_set_power_state,
> +		.display_configuration_changed = &rs780_dpm_display_configuration_changed,
> +		.fini = &rs780_dpm_fini,
> +		.get_sclk = &rs780_dpm_get_sclk,
> +		.get_mclk = &rs780_dpm_get_mclk,
> +		.print_power_state = &rs780_dpm_print_power_state,
> +	},
>  	.pflip = {
>  		.pre_page_flip = &rs600_pre_page_flip,
>  		.page_flip = &rs600_page_flip,
> diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
> index 8507cae..134bf57 100644
> --- a/drivers/gpu/drm/radeon/radeon_asic.h
> +++ b/drivers/gpu/drm/radeon/radeon_asic.h
> @@ -396,6 +396,18 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev);
>  u32 r600_get_xclk(struct radeon_device *rdev);
>  uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev);
>  int rv6xx_get_temp(struct radeon_device *rdev);
> +/* rs780 dpm */
> +int rs780_dpm_init(struct radeon_device *rdev);
> +int rs780_dpm_enable(struct radeon_device *rdev);
> +void rs780_dpm_disable(struct radeon_device *rdev);
> +int rs780_dpm_set_power_state(struct radeon_device *rdev);
> +void rs780_dpm_setup_asic(struct radeon_device *rdev);
> +void rs780_dpm_display_configuration_changed(struct radeon_device *rdev);
> +void rs780_dpm_fini(struct radeon_device *rdev);
> +u32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low);
> +u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low);
> +void rs780_dpm_print_power_state(struct radeon_device *rdev,
> +				 struct radeon_ps *ps);
>  
>  /* uvd */
>  int r600_uvd_init(struct radeon_device *rdev);
> diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
> index 4f5422e..853a8a2 100644
> --- a/drivers/gpu/drm/radeon/radeon_pm.c
> +++ b/drivers/gpu/drm/radeon/radeon_pm.c
> @@ -1030,6 +1030,13 @@ int radeon_pm_init(struct radeon_device *rdev)
>  {
>  	/* enable dpm on rv6xx+ */
>  	switch (rdev->family) {
> +	case CHIP_RS780:
> +	case CHIP_RS880:
> +		if (radeon_dpm == 1)
> +			rdev->pm.pm_method = PM_METHOD_DPM;
> +		else
> +			rdev->pm.pm_method = PM_METHOD_PROFILE;
> +		break;
>  	default:
>  		/* default to profile method */
>  		rdev->pm.pm_method = PM_METHOD_PROFILE;
> diff --git a/drivers/gpu/drm/radeon/rs780_dpm.c b/drivers/gpu/drm/radeon/rs780_dpm.c
> new file mode 100644
> index 0000000..f594900
> --- /dev/null
> +++ b/drivers/gpu/drm/radeon/rs780_dpm.c
> @@ -0,0 +1,894 @@
> +/*
> + * Copyright 2011 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * Authors: Alex Deucher
> + */
> +
> +#include "drmP.h"
> +#include "radeon.h"
> +#include "rs780d.h"
> +#include "r600_dpm.h"
> +#include "rs780_dpm.h"
> +#include "atom.h"
> +
> +static struct igp_ps *rs780_get_ps(struct radeon_ps *rps)
> +{
> +	struct igp_ps *ps = rps->ps_priv;
> +
> +	return ps;
> +}
> +
> +static struct igp_power_info *rs780_get_pi(struct radeon_device *rdev)
> +{
> +	struct igp_power_info *pi = rdev->pm.dpm.priv;
> +
> +	return pi;
> +}
> +
> +static void rs780_get_pm_mode_parameters(struct radeon_device *rdev)
> +{
> +	struct igp_power_info *pi = rs780_get_pi(rdev);
> +	struct radeon_mode_info *minfo = &rdev->mode_info;
> +	struct drm_crtc *crtc;
> +	struct radeon_crtc *radeon_crtc;
> +	int i;
> +
> +	/* defaults */
> +	pi->crtc_id = 0;
> +	pi->refresh_rate = 60;
> +
> +	for (i = 0; i < rdev->num_crtc; i++) {
> +		crtc = (struct drm_crtc *)minfo->crtcs[i];
> +		if (crtc && crtc->enabled) {
> +			radeon_crtc = to_radeon_crtc(crtc);
> +			pi->crtc_id = radeon_crtc->crtc_id;
> +			if (crtc->mode.htotal && crtc->mode.vtotal)
> +				pi->refresh_rate =
> +					(crtc->mode.clock * 1000) /
> +					(crtc->mode.htotal * crtc->mode.vtotal);
> +			break;
> +		}
> +	}

Ok this looks wrong to me you look for the first enabled crtc but on those iirc
there could be 2 so first one might be a low refresh rate and second one an higher
one. Thus returning the first one might lead to PM decision that are wrong.

> +}
> +
> +static void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable);
> +
> +static int rs780_initialize_dpm_power_state(struct radeon_device *rdev)
> +{
> +	struct atom_clock_dividers dividers;
> +	struct igp_ps *default_state = rs780_get_ps(rdev->pm.dpm.boot_ps);
> +	int i, ret;
> +
> +	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
> +					     default_state->sclk_low, false, &dividers);
> +	if (ret)
> +		return ret;
> +
> +	r600_engine_clock_entry_set_reference_divider(rdev, 0, dividers.ref_div);
> +	r600_engine_clock_entry_set_feedback_divider(rdev, 0, dividers.fb_div);
> +	r600_engine_clock_entry_set_post_divider(rdev, 0, dividers.post_div);
> +
> +	if (dividers.enable_post_div)
> +		r600_engine_clock_entry_enable_post_divider(rdev, 0, true);
> +	else
> +		r600_engine_clock_entry_enable_post_divider(rdev, 0, false);
> +
> +	r600_engine_clock_entry_set_step_time(rdev, 0, R600_SST_DFLT);
> +	r600_engine_clock_entry_enable_pulse_skipping(rdev, 0, false);
> +
> +	r600_engine_clock_entry_enable(rdev, 0, true);
> +	for (i = 1; i < R600_PM_NUMBER_OF_SCLKS; i++)
> +		r600_engine_clock_entry_enable(rdev, i, false);
> +
> +	r600_enable_mclk_control(rdev, false);
> +	r600_voltage_control_enable_pins(rdev, 0);
> +
> +	return 0;
> +}
> +
> +static int rs780_initialize_dpm_parameters(struct radeon_device *rdev)
> +{
> +	int ret = 0;
> +	int i;
> +
> +	r600_set_bsp(rdev, R600_BSU_DFLT, R600_BSP_DFLT);
> +
> +	r600_set_at(rdev, 0, 0, 0, 0);
> +
> +	r600_set_git(rdev, R600_GICST_DFLT);
> +
> +	for (i = 0; i < R600_PM_NUMBER_OF_TC; i++)
> +		r600_set_tc(rdev, i, 0, 0);
> +
> +	r600_select_td(rdev, R600_TD_DFLT);
> +	r600_set_vrc(rdev, 0);
> +
> +	r600_set_tpu(rdev, R600_TPU_DFLT);
> +	r600_set_tpc(rdev, R600_TPC_DFLT);
> +
> +	r600_set_sstu(rdev, R600_SSTU_DFLT);
> +	r600_set_sst(rdev, R600_SST_DFLT);
> +
> +	r600_set_fctu(rdev, R600_FCTU_DFLT);
> +	r600_set_fct(rdev, R600_FCT_DFLT);
> +
> +	r600_set_vddc3d_oorsu(rdev, R600_VDDC3DOORSU_DFLT);
> +	r600_set_vddc3d_oorphc(rdev, R600_VDDC3DOORPHC_DFLT);
> +	r600_set_vddc3d_oorsdc(rdev, R600_VDDC3DOORSDC_DFLT);
> +	r600_set_ctxcgtt3d_rphc(rdev, R600_CTXCGTT3DRPHC_DFLT);
> +	r600_set_ctxcgtt3d_rsdc(rdev, R600_CTXCGTT3DRSDC_DFLT);
> +
> +	r600_vid_rt_set_vru(rdev, R600_VRU_DFLT);
> +	r600_vid_rt_set_vrt(rdev, R600_VOLTAGERESPONSETIME_DFLT);
> +	r600_vid_rt_set_ssu(rdev, R600_SPLLSTEPUNIT_DFLT);
> +
> +	ret = rs780_initialize_dpm_power_state(rdev);
> +
> +	r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW,     0);
> +	r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM,  0);
> +	r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_HIGH,    0);
> +
> +	r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW,    0);
> +	r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
> +	r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_HIGH,   0);
> +
> +	r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW,    0);
> +	r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
> +	r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_HIGH,   0);
> +
> +	r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW,    R600_DISPLAY_WATERMARK_HIGH);
> +	r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM, R600_DISPLAY_WATERMARK_HIGH);
> +	r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_HIGH,   R600_DISPLAY_WATERMARK_HIGH);
> +
> +	r600_power_level_enable(rdev, R600_POWER_LEVEL_CTXSW, false);
> +	r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false);
> +	r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false);
> +	r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
> +
> +	r600_power_level_set_enter_index(rdev, R600_POWER_LEVEL_LOW);
> +
> +	r600_set_vrc(rdev, RS780_CGFTV_DFLT);
> +
> +	return ret;
> +}
> +
> +static void rs780_start_dpm(struct radeon_device *rdev)
> +{
> +	r600_enable_sclk_control(rdev, false);
> +	r600_enable_mclk_control(rdev, false);
> +
> +	r600_dynamicpm_enable(rdev, true);
> +
> +	radeon_wait_for_vblank(rdev, 0);
> +	radeon_wait_for_vblank(rdev, 1);
> +
> +	r600_enable_spll_bypass(rdev, true);
> +	r600_wait_for_spll_change(rdev);
> +	r600_enable_spll_bypass(rdev, false);
> +	r600_wait_for_spll_change(rdev);
> +
> +	r600_enable_spll_bypass(rdev, true);
> +	r600_wait_for_spll_change(rdev);
> +	r600_enable_spll_bypass(rdev, false);
> +	r600_wait_for_spll_change(rdev);
> +
> +	r600_enable_sclk_control(rdev, true);
> +}
> +
> +
> +static void rs780_preset_ranges_slow_clk_fbdiv_en(struct radeon_device *rdev)
> +{
> +	WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1, RANGE_SLOW_CLK_FEEDBACK_DIV_EN,
> +		 ~RANGE_SLOW_CLK_FEEDBACK_DIV_EN);
> +
> +	WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1,
> +		 RANGE0_SLOW_CLK_FEEDBACK_DIV(RS780_SLOWCLKFEEDBACKDIV_DFLT),
> +		 ~RANGE0_SLOW_CLK_FEEDBACK_DIV_MASK);
> +}
> +
> +static void rs780_preset_starting_fbdiv(struct radeon_device *rdev)
> +{
> +	u32 fbdiv = (RREG32(CG_SPLL_FUNC_CNTL) & SPLL_FB_DIV_MASK) >> SPLL_FB_DIV_SHIFT;
> +
> +	WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(fbdiv),
> +		 ~STARTING_FEEDBACK_DIV_MASK);
> +
> +	WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(fbdiv),
> +		 ~FORCED_FEEDBACK_DIV_MASK);
> +
> +	WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
> +}
> +
> +static void rs780_voltage_scaling_init(struct radeon_device *rdev)
> +{
> +	struct igp_power_info *pi = rs780_get_pi(rdev);
> +	struct drm_device *dev = rdev->ddev;
> +	u32 fv_throt_pwm_fb_div_range[3];
> +	u32 fv_throt_pwm_range[4];
> +
> +	if (dev->pdev->device == 0x9614) {
> +		fv_throt_pwm_fb_div_range[0] = RS780D_FVTHROTPWMFBDIVRANGEREG0_DFLT;
> +		fv_throt_pwm_fb_div_range[1] = RS780D_FVTHROTPWMFBDIVRANGEREG1_DFLT;
> +		fv_throt_pwm_fb_div_range[2] = RS780D_FVTHROTPWMFBDIVRANGEREG2_DFLT;
> +	} else if ((dev->pdev->device == 0x9714) ||
> +		   (dev->pdev->device == 0x9715)) {
> +		fv_throt_pwm_fb_div_range[0] = RS880D_FVTHROTPWMFBDIVRANGEREG0_DFLT;
> +		fv_throt_pwm_fb_div_range[1] = RS880D_FVTHROTPWMFBDIVRANGEREG1_DFLT;
> +		fv_throt_pwm_fb_div_range[2] = RS880D_FVTHROTPWMFBDIVRANGEREG2_DFLT;
> +	} else {
> +		fv_throt_pwm_fb_div_range[0] = RS780_FVTHROTPWMFBDIVRANGEREG0_DFLT;
> +		fv_throt_pwm_fb_div_range[1] = RS780_FVTHROTPWMFBDIVRANGEREG1_DFLT;
> +		fv_throt_pwm_fb_div_range[2] = RS780_FVTHROTPWMFBDIVRANGEREG2_DFLT;
> +	}
> +
> +	if (pi->pwm_voltage_control) {
> +		fv_throt_pwm_range[0] = pi->min_voltage;
> +		fv_throt_pwm_range[1] = pi->min_voltage;
> +		fv_throt_pwm_range[2] = pi->max_voltage;
> +		fv_throt_pwm_range[3] = pi->max_voltage;
> +	} else {
> +		fv_throt_pwm_range[0] = pi->invert_pwm_required ?
> +			RS780_FVTHROTPWMRANGE3_GPIO_DFLT : RS780_FVTHROTPWMRANGE0_GPIO_DFLT;
> +		fv_throt_pwm_range[1] = pi->invert_pwm_required ?
> +			RS780_FVTHROTPWMRANGE2_GPIO_DFLT : RS780_FVTHROTPWMRANGE1_GPIO_DFLT;
> +		fv_throt_pwm_range[2] = pi->invert_pwm_required ?
> +			RS780_FVTHROTPWMRANGE1_GPIO_DFLT : RS780_FVTHROTPWMRANGE2_GPIO_DFLT;
> +		fv_throt_pwm_range[3] = pi->invert_pwm_required ?
> +			RS780_FVTHROTPWMRANGE0_GPIO_DFLT : RS780_FVTHROTPWMRANGE3_GPIO_DFLT;
> +	}
> +
> +	WREG32_P(FVTHROT_PWM_CTRL_REG0,
> +		 STARTING_PWM_HIGHTIME(pi->max_voltage),
> +		 ~STARTING_PWM_HIGHTIME_MASK);
> +
> +	WREG32_P(FVTHROT_PWM_CTRL_REG0,
> +		 NUMBER_OF_CYCLES_IN_PERIOD(pi->num_of_cycles_in_period),
> +		 ~NUMBER_OF_CYCLES_IN_PERIOD_MASK);
> +
> +	WREG32_P(FVTHROT_PWM_CTRL_REG0, FORCE_STARTING_PWM_HIGHTIME,
> +		 ~FORCE_STARTING_PWM_HIGHTIME);
> +
> +	if (pi->invert_pwm_required)
> +		WREG32_P(FVTHROT_PWM_CTRL_REG0, INVERT_PWM_WAVEFORM, ~INVERT_PWM_WAVEFORM);
> +	else
> +		WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~INVERT_PWM_WAVEFORM);
> +
> +	rs780_voltage_scaling_enable(rdev, true);
> +
> +	WREG32(FVTHROT_PWM_CTRL_REG1,
> +	       (MIN_PWM_HIGHTIME(pi->min_voltage) |
> +		MAX_PWM_HIGHTIME(pi->max_voltage)));
> +
> +	WREG32(FVTHROT_PWM_US_REG0, RS780_FVTHROTPWMUSREG0_DFLT);
> +	WREG32(FVTHROT_PWM_US_REG1, RS780_FVTHROTPWMUSREG1_DFLT);
> +	WREG32(FVTHROT_PWM_DS_REG0, RS780_FVTHROTPWMDSREG0_DFLT);
> +	WREG32(FVTHROT_PWM_DS_REG1, RS780_FVTHROTPWMDSREG1_DFLT);
> +
> +	WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1,
> +		 RANGE0_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[0]),
> +		 ~RANGE0_PWM_FEEDBACK_DIV_MASK);
> +
> +	WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG2,
> +	       (RANGE1_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[1]) |
> +		RANGE2_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[2])));
> +
> +	WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG3,
> +	       (RANGE0_PWM(fv_throt_pwm_range[1]) |
> +		RANGE1_PWM(fv_throt_pwm_range[2])));
> +	WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG4,
> +	       (RANGE2_PWM(fv_throt_pwm_range[1]) |
> +		RANGE3_PWM(fv_throt_pwm_range[2])));
> +}
> +
> +static void rs780_clk_scaling_enable(struct radeon_device *rdev, bool enable)
> +{
> +	if (enable)
> +		WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT | ENABLE_FV_UPDATE,
> +			 ~(ENABLE_FV_THROT | ENABLE_FV_UPDATE));
> +	else
> +		WREG32_P(FVTHROT_CNTRL_REG, 0,
> +			 ~(ENABLE_FV_THROT | ENABLE_FV_UPDATE));
> +}
> +
> +static void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable)
> +{
> +	if (enable)
> +		WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT_IO, ~ENABLE_FV_THROT_IO);
> +	else
> +		WREG32_P(FVTHROT_CNTRL_REG, 0, ~ENABLE_FV_THROT_IO);
> +}
> +
> +static void rs780_set_engine_clock_wfc(struct radeon_device *rdev)
> +{
> +	WREG32(FVTHROT_UTC0, RS780_FVTHROTUTC0_DFLT);
> +	WREG32(FVTHROT_UTC1, RS780_FVTHROTUTC1_DFLT);
> +	WREG32(FVTHROT_UTC2, RS780_FVTHROTUTC2_DFLT);
> +	WREG32(FVTHROT_UTC3, RS780_FVTHROTUTC3_DFLT);
> +	WREG32(FVTHROT_UTC4, RS780_FVTHROTUTC4_DFLT);
> +
> +	WREG32(FVTHROT_DTC0, RS780_FVTHROTDTC0_DFLT);
> +	WREG32(FVTHROT_DTC1, RS780_FVTHROTDTC1_DFLT);
> +	WREG32(FVTHROT_DTC2, RS780_FVTHROTDTC2_DFLT);
> +	WREG32(FVTHROT_DTC3, RS780_FVTHROTDTC3_DFLT);
> +	WREG32(FVTHROT_DTC4, RS780_FVTHROTDTC4_DFLT);
> +}
> +
> +static void rs780_set_engine_clock_sc(struct radeon_device *rdev)
> +{
> +	WREG32_P(FVTHROT_FBDIV_REG2,
> +		 FB_DIV_TIMER_VAL(RS780_FBDIVTIMERVAL_DFLT),
> +		 ~FB_DIV_TIMER_VAL_MASK);
> +
> +	WREG32_P(FVTHROT_CNTRL_REG,
> +		 REFRESH_RATE_DIVISOR(0) | MINIMUM_CIP(0xf),
> +		 ~(REFRESH_RATE_DIVISOR_MASK | MINIMUM_CIP_MASK));
> +}
> +
> +static void rs780_set_engine_clock_tdc(struct radeon_device *rdev)
> +{
> +	WREG32_P(FVTHROT_CNTRL_REG, 0, ~(FORCE_TREND_SEL | TREND_SEL_MODE));
> +}
> +
> +static void rs780_set_engine_clock_ssc(struct radeon_device *rdev)
> +{
> +	WREG32(FVTHROT_FB_US_REG0, RS780_FVTHROTFBUSREG0_DFLT);
> +	WREG32(FVTHROT_FB_US_REG1, RS780_FVTHROTFBUSREG1_DFLT);
> +	WREG32(FVTHROT_FB_DS_REG0, RS780_FVTHROTFBDSREG0_DFLT);
> +	WREG32(FVTHROT_FB_DS_REG1, RS780_FVTHROTFBDSREG1_DFLT);
> +
> +	WREG32_P(FVTHROT_FBDIV_REG1, MAX_FEEDBACK_STEP(1), ~MAX_FEEDBACK_STEP_MASK);
> +}
> +
> +static void rs780_program_at(struct radeon_device *rdev)
> +{
> +	struct igp_power_info *pi = rs780_get_pi(rdev);
> +
> +	WREG32(FVTHROT_TARGET_REG, 30000000 / pi->refresh_rate);
> +	WREG32(FVTHROT_CB1, 1000000 * 5 / pi->refresh_rate);
> +	WREG32(FVTHROT_CB2, 1000000 * 10 / pi->refresh_rate);
> +	WREG32(FVTHROT_CB3, 1000000 * 30 / pi->refresh_rate);
> +	WREG32(FVTHROT_CB4, 1000000 * 50 / pi->refresh_rate);
> +}
> +
> +static void rs780_disable_vbios_powersaving(struct radeon_device *rdev)
> +{
> +	WREG32_P(CG_INTGFX_MISC, 0, ~0xFFF00000);
> +}
> +
> +static void rs780_force_voltage_to_high(struct radeon_device *rdev)
> +{
> +	struct igp_power_info *pi = rs780_get_pi(rdev);
> +	struct igp_ps *current_state = rs780_get_ps(rdev->pm.dpm.current_ps);
> +
> +	if ((current_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
> +	    (current_state->min_voltage == RS780_VDDC_LEVEL_HIGH))
> +		return;
> +
> +	WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
> +
> +	udelay(1);
> +
> +	WREG32_P(FVTHROT_PWM_CTRL_REG0,
> +		 STARTING_PWM_HIGHTIME(pi->max_voltage),
> +		 ~STARTING_PWM_HIGHTIME_MASK);
> +
> +	WREG32_P(FVTHROT_PWM_CTRL_REG0,
> +		 FORCE_STARTING_PWM_HIGHTIME, ~FORCE_STARTING_PWM_HIGHTIME);
> +
> +	WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1, 0,
> +		~RANGE_PWM_FEEDBACK_DIV_EN);
> +
> +	udelay(1);
> +
> +	WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
> +}
> +
> +static int rs780_set_engine_clock_scaling(struct radeon_device *rdev)
> +{
> +	struct atom_clock_dividers min_dividers, max_dividers, current_max_dividers;
> +	struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
> +	struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
> +	int ret;
> +
> +	if ((new_state->sclk_high == old_state->sclk_high) &&
> +	    (new_state->sclk_low == old_state->sclk_low))
> +		return 0;
> +
> +	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
> +					     new_state->sclk_low, false, &min_dividers);
> +	if (ret)
> +		return ret;
> +
> +	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
> +					     new_state->sclk_high, false, &max_dividers);
> +	if (ret)
> +		return ret;
> +
> +	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
> +					     old_state->sclk_high, false, &current_max_dividers);
> +	if (ret)
> +		return ret;
> +
> +	WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
> +
> +	WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(max_dividers.fb_div),
> +		 ~FORCED_FEEDBACK_DIV_MASK);
> +	WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(max_dividers.fb_div),
> +		 ~STARTING_FEEDBACK_DIV_MASK);
> +	WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
> +
> +	udelay(100);
> +
> +	WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
> +
> +	if (max_dividers.fb_div > min_dividers.fb_div) {
> +		WREG32_P(FVTHROT_FBDIV_REG0,
> +			 MIN_FEEDBACK_DIV(min_dividers.fb_div) |
> +			 MAX_FEEDBACK_DIV(max_dividers.fb_div),
> +			 ~(MIN_FEEDBACK_DIV_MASK | MAX_FEEDBACK_DIV_MASK));
> +
> +		WREG32_P(FVTHROT_FBDIV_REG1, 0, ~FORCE_FEEDBACK_DIV);
> +	}
> +
> +	return 0;
> +}
> +
> +static void rs780_set_engine_clock_spc(struct radeon_device *rdev)
> +{
> +	struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
> +	struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
> +	struct igp_power_info *pi = rs780_get_pi(rdev);
> +
> +	if ((new_state->sclk_high == old_state->sclk_high) &&
> +	    (new_state->sclk_low == old_state->sclk_low))
> +		return;
> +
> +	if (pi->crtc_id == 0)
> +		WREG32_P(CG_INTGFX_MISC, 0, ~FVTHROT_VBLANK_SEL);
> +	else
> +		WREG32_P(CG_INTGFX_MISC, FVTHROT_VBLANK_SEL, ~FVTHROT_VBLANK_SEL);
> +
> +}
> +
> +static void rs780_activate_engine_clk_scaling(struct radeon_device *rdev)
> +{
> +	struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
> +	struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
> +
> +	if ((new_state->sclk_high == old_state->sclk_high) &&
> +	    (new_state->sclk_low == old_state->sclk_low))
> +		return;
> +
> +	rs780_clk_scaling_enable(rdev, true);
> +}
> +
> +static u32 rs780_get_voltage_for_vddc_level(struct radeon_device *rdev,
> +					    enum rs780_vddc_level vddc)
> +{
> +	struct igp_power_info *pi = rs780_get_pi(rdev);
> +
> +	if (vddc == RS780_VDDC_LEVEL_HIGH)
> +		return pi->max_voltage;
> +	else if (vddc == RS780_VDDC_LEVEL_LOW)
> +		return pi->min_voltage;
> +	else
> +		return pi->max_voltage;
> +}
> +
> +static void rs780_enable_voltage_scaling(struct radeon_device *rdev)
> +{
> +	struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
> +	struct igp_power_info *pi = rs780_get_pi(rdev);
> +	enum rs780_vddc_level vddc_high, vddc_low;
> +
> +	udelay(100);
> +
> +	if ((new_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
> +	    (new_state->min_voltage == RS780_VDDC_LEVEL_HIGH))
> +		return;
> +
> +	vddc_high = rs780_get_voltage_for_vddc_level(rdev,
> +						     new_state->max_voltage);
> +	vddc_low = rs780_get_voltage_for_vddc_level(rdev,
> +						    new_state->min_voltage);
> +
> +	WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
> +
> +	udelay(1);
> +	if (vddc_high > vddc_low) {
> +		WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1,
> +			 RANGE_PWM_FEEDBACK_DIV_EN, ~RANGE_PWM_FEEDBACK_DIV_EN);
> +
> +		WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~FORCE_STARTING_PWM_HIGHTIME);
> +	} else if (vddc_high == vddc_low) {
> +		if (pi->max_voltage != vddc_high) {
> +			WREG32_P(FVTHROT_PWM_CTRL_REG0,
> +				 STARTING_PWM_HIGHTIME(vddc_high),
> +				 ~STARTING_PWM_HIGHTIME_MASK);
> +
> +			WREG32_P(FVTHROT_PWM_CTRL_REG0,
> +				 FORCE_STARTING_PWM_HIGHTIME,
> +				 ~FORCE_STARTING_PWM_HIGHTIME);
> +		}
> +	}
> +
> +	WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
> +}
> +
> +int rs780_dpm_enable(struct radeon_device *rdev)
> +{
> +	struct igp_power_info *pi = rs780_get_pi(rdev);
> +
> +	rs780_get_pm_mode_parameters(rdev);
> +	rs780_disable_vbios_powersaving(rdev);
> +
> +	if (r600_dynamicpm_enabled(rdev))
> +		return -EINVAL;
> +	if (rs780_initialize_dpm_parameters(rdev))
> +		return -EINVAL;
> +	rs780_start_dpm(rdev);
> +
> +	rs780_preset_ranges_slow_clk_fbdiv_en(rdev);
> +	rs780_preset_starting_fbdiv(rdev);
> +	if (pi->voltage_control)
> +		rs780_voltage_scaling_init(rdev);
> +	rs780_clk_scaling_enable(rdev, true);
> +	rs780_set_engine_clock_sc(rdev);
> +	rs780_set_engine_clock_wfc(rdev);
> +	rs780_program_at(rdev);
> +	rs780_set_engine_clock_tdc(rdev);
> +	rs780_set_engine_clock_ssc(rdev);
> +
> +	if (pi->gfx_clock_gating)
> +		r600_gfx_clockgating_enable(rdev, true);
> +
> +	return 0;
> +}
> +
> +void rs780_dpm_disable(struct radeon_device *rdev)
> +{
> +	struct igp_power_info *pi = rs780_get_pi(rdev);
> +
> +	r600_dynamicpm_enable(rdev, false);
> +
> +	rs780_clk_scaling_enable(rdev, false);
> +	rs780_voltage_scaling_enable(rdev, false);
> +
> +	if (pi->gfx_clock_gating)
> +		r600_gfx_clockgating_enable(rdev, false);
> +}
> +
> +int rs780_dpm_set_power_state(struct radeon_device *rdev)
> +{
> +	struct igp_power_info *pi = rs780_get_pi(rdev);
> +
> +	rs780_get_pm_mode_parameters(rdev);
> +
> +	if (pi->voltage_control) {
> +		rs780_force_voltage_to_high(rdev);
> +		mdelay(5);
> +	}
> +
> +	rs780_set_engine_clock_scaling(rdev);
> +	rs780_set_engine_clock_spc(rdev);
> +
> +	rs780_activate_engine_clk_scaling(rdev);
> +
> +	if (pi->voltage_control)
> +		rs780_enable_voltage_scaling(rdev);
> +
> +	return 0;
> +}
> +
> +void rs780_dpm_setup_asic(struct radeon_device *rdev)
> +{
> +
> +}
> +
> +void rs780_dpm_display_configuration_changed(struct radeon_device *rdev)
> +{
> +	rs780_get_pm_mode_parameters(rdev);
> +	rs780_program_at(rdev);
> +}
> +
> +union igp_info {
> +	struct _ATOM_INTEGRATED_SYSTEM_INFO info;
> +	struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
> +};
> +
> +union power_info {
> +	struct _ATOM_POWERPLAY_INFO info;
> +	struct _ATOM_POWERPLAY_INFO_V2 info_2;
> +	struct _ATOM_POWERPLAY_INFO_V3 info_3;
> +	struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
> +	struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
> +	struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
> +};
> +
> +union pplib_clock_info {
> +	struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
> +	struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
> +	struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
> +	struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
> +};
> +
> +union pplib_power_state {
> +	struct _ATOM_PPLIB_STATE v1;
> +	struct _ATOM_PPLIB_STATE_V2 v2;
> +};
> +
> +static void 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)
> +{
> +	rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
> +	rps->class = le16_to_cpu(non_clock_info->usClassification);
> +	rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
> +
> +	if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
> +		rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
> +		rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
> +	} else if (r600_is_uvd_state(rps->class, rps->class2)) {
> +		rps->vclk = RS780_DEFAULT_VCLK_FREQ;
> +		rps->dclk = RS780_DEFAULT_DCLK_FREQ;
> +	} else {
> +		rps->vclk = 0;
> +		rps->dclk = 0;
> +	}
> +
> +	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
> +		rdev->pm.dpm.boot_ps = rps;
> +	if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
> +		rdev->pm.dpm.uvd_ps = rps;
> +}
> +
> +static void rs780_parse_pplib_clock_info(struct radeon_device *rdev,
> +					 struct radeon_ps *rps,
> +					 union pplib_clock_info *clock_info)
> +{
> +	struct igp_ps *ps = rs780_get_ps(rps);
> +	u32 sclk;
> +
> +	sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow);
> +	sclk |= clock_info->rs780.ucLowEngineClockHigh << 16;
> +	ps->sclk_low = sclk;
> +	sclk = le16_to_cpu(clock_info->rs780.usHighEngineClockLow);
> +	sclk |= clock_info->rs780.ucHighEngineClockHigh << 16;
> +	ps->sclk_high = sclk;
> +	switch (le16_to_cpu(clock_info->rs780.usVDDC)) {
> +	case ATOM_PPLIB_RS780_VOLTAGE_NONE:
> +	default:
> +		ps->min_voltage = RS780_VDDC_LEVEL_UNKNOWN;
> +		ps->max_voltage = RS780_VDDC_LEVEL_UNKNOWN;
> +		break;
> +	case ATOM_PPLIB_RS780_VOLTAGE_LOW:
> +		ps->min_voltage = RS780_VDDC_LEVEL_LOW;
> +		ps->max_voltage = RS780_VDDC_LEVEL_LOW;
> +		break;
> +	case ATOM_PPLIB_RS780_VOLTAGE_HIGH:
> +		ps->min_voltage = RS780_VDDC_LEVEL_HIGH;
> +		ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
> +		break;
> +	case ATOM_PPLIB_RS780_VOLTAGE_VARIABLE:
> +		ps->min_voltage = RS780_VDDC_LEVEL_LOW;
> +		ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
> +		break;
> +	}
> +	ps->flags = le32_to_cpu(clock_info->rs780.ulFlags);
> +
> +	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
> +		ps->sclk_low = rdev->clock.default_sclk;
> +		ps->sclk_high = rdev->clock.default_sclk;
> +		ps->min_voltage = RS780_VDDC_LEVEL_HIGH;
> +		ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
> +	}
> +}
> +
> +static int rs780_parse_power_table(struct radeon_device *rdev)
> +{
> +	struct radeon_mode_info *mode_info = &rdev->mode_info;
> +	struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
> +	union pplib_power_state *power_state;
> +	int i;
> +	union pplib_clock_info *clock_info;
> +	union power_info *power_info;
> +	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
> +        u16 data_offset;
> +	u8 frev, crev;
> +	struct igp_ps *ps;
> +
> +	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
> +				   &frev, &crev, &data_offset))
> +		return -EINVAL;
> +	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
> +
> +	rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
> +				  power_info->pplib.ucNumStates, GFP_KERNEL);
> +	if (!rdev->pm.dpm.ps)
> +		return -ENOMEM;
> +	rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
> +	rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
> +	rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
> +
> +	for (i = 0; i < power_info->pplib.ucNumStates; i++) {
> +		power_state = (union pplib_power_state *)
> +			(mode_info->atom_context->bios + data_offset +
> +			 le16_to_cpu(power_info->pplib.usStateArrayOffset) +
> +			 i * power_info->pplib.ucStateEntrySize);
> +		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
> +			(mode_info->atom_context->bios + data_offset +
> +			 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
> +			 (power_state->v1.ucNonClockStateIndex *
> +			  power_info->pplib.ucNonClockSize));
> +		if (power_info->pplib.ucStateEntrySize - 1) {
> +			clock_info = (union pplib_clock_info *)
> +				(mode_info->atom_context->bios + data_offset +
> +				 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
> +				 (power_state->v1.ucClockStateIndices[0] *
> +				  power_info->pplib.ucClockInfoSize));
> +			ps = kzalloc(sizeof(struct igp_ps), GFP_KERNEL);
> +			if (ps == NULL) {
> +				kfree(rdev->pm.dpm.ps);
> +				return -ENOMEM;
> +			}
> +			rdev->pm.dpm.ps[i].ps_priv = ps;
> +			rs780_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
> +							 non_clock_info,
> +							 power_info->pplib.ucNonClockSize);
> +			rs780_parse_pplib_clock_info(rdev,
> +						     &rdev->pm.dpm.ps[i],
> +						     clock_info);
> +		}
> +	}
> +	rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates;
> +	return 0;
> +}
> +
> +int rs780_dpm_init(struct radeon_device *rdev)
> +{
> +	struct igp_power_info *pi;
> +	int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
> +	union igp_info *info;
> +	u16 data_offset;
> +	u8 frev, crev;
> +	int ret;
> +
> +	pi = kzalloc(sizeof(struct igp_power_info), GFP_KERNEL);
> +	if (pi == NULL)
> +		return -ENOMEM;
> +	rdev->pm.dpm.priv = pi;
> +
> +	ret = rs780_parse_power_table(rdev);
> +	if (ret)
> +		return ret;
> +
> +	pi->voltage_control = false;
> +	pi->gfx_clock_gating = true;
> +
> +	if (atom_parse_data_header(rdev->mode_info.atom_context, index, NULL,
> +				   &frev, &crev, &data_offset)) {
> +		info = (union igp_info *)(rdev->mode_info.atom_context->bios + data_offset);
> +
> +		/* Get various system informations from bios */
> +		switch (crev) {
> +		case 1:
> +			pi->num_of_cycles_in_period =
> +				info->info.ucNumberOfCyclesInPeriod;
> +			pi->num_of_cycles_in_period |=
> +				info->info.ucNumberOfCyclesInPeriodHi << 8;
> +			pi->invert_pwm_required =
> +				(pi->num_of_cycles_in_period & 0x8000) ? true : false;
> +			pi->boot_voltage = info->info.ucStartingPWM_HighTime;
> +			pi->max_voltage = info->info.ucMaxNBVoltage;
> +			pi->max_voltage |= info->info.ucMaxNBVoltageHigh << 8;
> +			pi->min_voltage = info->info.ucMinNBVoltage;
> +			pi->min_voltage |= info->info.ucMinNBVoltageHigh << 8;
> +			pi->inter_voltage_low =
> +				le16_to_cpu(info->info.usInterNBVoltageLow);
> +			pi->inter_voltage_high =
> +				le16_to_cpu(info->info.usInterNBVoltageHigh);
> +			pi->voltage_control = true;
> +			pi->bootup_uma_clk = info->info.usK8MemoryClock * 100;
> +			break;
> +		case 2:
> +			pi->num_of_cycles_in_period =
> +				le16_to_cpu(info->info_2.usNumberOfCyclesInPeriod);
> +			pi->invert_pwm_required =
> +				(pi->num_of_cycles_in_period & 0x8000) ? true : false;
> +			pi->boot_voltage =
> +				le16_to_cpu(info->info_2.usBootUpNBVoltage);
> +			pi->max_voltage =
> +				le16_to_cpu(info->info_2.usMaxNBVoltage);
> +			pi->min_voltage =
> +				le16_to_cpu(info->info_2.usMinNBVoltage);
> +			pi->system_config =
> +				le32_to_cpu(info->info_2.ulSystemConfig);
> +			pi->pwm_voltage_control =
> +				(pi->system_config & 0x4) ? true : false;
> +			pi->voltage_control = true;
> +			pi->bootup_uma_clk = le32_to_cpu(info->info_2.ulBootUpUMAClock);
> +			break;
> +		default:
> +			DRM_ERROR("No integrated system info for your GPU\n");
> +			return -EINVAL;
> +		}
> +		if (pi->min_voltage > pi->max_voltage)
> +			pi->voltage_control = false;
> +		if (pi->pwm_voltage_control) {
> +			if ((pi->num_of_cycles_in_period == 0) ||
> +			    (pi->max_voltage == 0) ||
> +			    (pi->min_voltage == 0))
> +				pi->voltage_control = false;
> +		} else {
> +			if ((pi->num_of_cycles_in_period == 0) ||
> +			    (pi->max_voltage == 0))
> +				pi->voltage_control = false;
> +		}
> +
> +		return 0;
> +	}
> +	radeon_dpm_fini(rdev);
> +	return -EINVAL;
> +}
> +
> +void rs780_dpm_print_power_state(struct radeon_device *rdev,
> +				 struct radeon_ps *rps)
> +{
> +	struct igp_ps *ps = rs780_get_ps(rps);
> +
> +	r600_dpm_print_class_info(rps->class, rps->class2);
> +	r600_dpm_print_cap_info(rps->caps);
> +	printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
> +	printk("\t\tpower level 0    sclk: %u vddc_index: %d\n",
> +	       ps->sclk_low, ps->min_voltage);
> +	printk("\t\tpower level 1    sclk: %u vddc_index: %d\n",
> +	       ps->sclk_high, ps->max_voltage);
> +	r600_dpm_print_ps_status(rdev, rps);
> +}
> +
> +void rs780_dpm_fini(struct radeon_device *rdev)
> +{
> +	int i;
> +
> +	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
> +		kfree(rdev->pm.dpm.ps[i].ps_priv);
> +	}
> +	kfree(rdev->pm.dpm.ps);
> +	kfree(rdev->pm.dpm.priv);
> +}
> +
> +u32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low)
> +{
> +	struct igp_ps *requested_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
> +
> +	if (low)
> +		return requested_state->sclk_low;
> +	else
> +		return requested_state->sclk_high;
> +}
> +
> +u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low)
> +{
> +	struct igp_power_info *pi = rs780_get_pi(rdev);
> +
> +	return pi->bootup_uma_clk;
> +}
> diff --git a/drivers/gpu/drm/radeon/rs780_dpm.h b/drivers/gpu/drm/radeon/rs780_dpm.h
> new file mode 100644
> index 0000000..47a40b1
> --- /dev/null
> +++ b/drivers/gpu/drm/radeon/rs780_dpm.h
> @@ -0,0 +1,109 @@
> +/*
> + * Copyright 2011 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + */
> +#ifndef __RS780_DPM_H__
> +#define __RS780_DPM_H__
> +
> +enum rs780_vddc_level {
> +	RS780_VDDC_LEVEL_UNKNOWN = 0,
> +	RS780_VDDC_LEVEL_LOW = 1,
> +	RS780_VDDC_LEVEL_HIGH = 2,
> +};
> +
> +struct igp_power_info {
> +	/* flags */
> +	bool invert_pwm_required;
> +	bool pwm_voltage_control;
> +	bool voltage_control;
> +	bool gfx_clock_gating;
> +	/* stored values */
> +	u32 system_config;
> +	u32 bootup_uma_clk;
> +	u16 max_voltage;
> +	u16 min_voltage;
> +	u16 boot_voltage;
> +	u16 inter_voltage_low;
> +	u16 inter_voltage_high;
> +	u16 num_of_cycles_in_period;
> +	/* variable */
> +	int crtc_id;
> +	int refresh_rate;
> +};
> +
> +struct igp_ps {
> +	enum rs780_vddc_level min_voltage;
> +	enum rs780_vddc_level max_voltage;
> +	u32 sclk_low;
> +	u32 sclk_high;
> +	u32 flags;
> +};
> +
> +#define RS780_CGFTV_DFLT                 0x0303000f
> +#define RS780_FBDIVTIMERVAL_DFLT         0x2710
> +
> +#define RS780_FVTHROTUTC0_DFLT   0x04010040
> +#define RS780_FVTHROTUTC1_DFLT   0x04010040
> +#define RS780_FVTHROTUTC2_DFLT   0x04010040
> +#define RS780_FVTHROTUTC3_DFLT   0x04010040
> +#define RS780_FVTHROTUTC4_DFLT   0x04010040
> +
> +#define RS780_FVTHROTDTC0_DFLT 0x04010040
> +#define RS780_FVTHROTDTC1_DFLT 0x04010040
> +#define RS780_FVTHROTDTC2_DFLT 0x04010040
> +#define RS780_FVTHROTDTC3_DFLT 0x04010040
> +#define RS780_FVTHROTDTC4_DFLT 0x04010040
> +
> +#define RS780_FVTHROTFBUSREG0_DFLT       0x00001001
> +#define RS780_FVTHROTFBUSREG1_DFLT       0x00002002
> +#define RS780_FVTHROTFBDSREG0_DFLT       0x00004001
> +#define RS780_FVTHROTFBDSREG1_DFLT       0x00020010
> +
> +#define RS780_FVTHROTPWMUSREG0_DFLT      0x00002001
> +#define RS780_FVTHROTPWMUSREG1_DFLT      0x00004003
> +#define RS780_FVTHROTPWMDSREG0_DFLT      0x00002001
> +#define RS780_FVTHROTPWMDSREG1_DFLT      0x00004003
> +
> +#define RS780_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x37
> +#define RS780_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x4b
> +#define RS780_FVTHROTPWMFBDIVRANGEREG2_DFLT  0x8b
> +
> +#define RS780D_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x8b
> +#define RS780D_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x8c
> +#define RS780D_FVTHROTPWMFBDIVRANGEREG2_DFLT  0xb5
> +
> +#define RS880D_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x8d
> +#define RS880D_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x8e
> +#define RS880D_FVTHROTPWMFBDIVRANGEREG2_DFLT  0xBa
> +
> +#define RS780_FVTHROTPWMRANGE0_GPIO_DFLT  0x1a
> +#define RS780_FVTHROTPWMRANGE1_GPIO_DFLT  0x1a
> +#define RS780_FVTHROTPWMRANGE2_GPIO_DFLT  0x0
> +#define RS780_FVTHROTPWMRANGE3_GPIO_DFLT  0x0
> +
> +#define RS780_SLOWCLKFEEDBACKDIV_DFLT 110
> +
> +#define RS780_CGCLKGATING_DFLT           0x0000E204
> +
> +#define RS780_DEFAULT_VCLK_FREQ  53300 /* 10 khz */
> +#define RS780_DEFAULT_DCLK_FREQ  40000 /* 10 khz */
> +
> +#endif
> diff --git a/drivers/gpu/drm/radeon/rs780d.h b/drivers/gpu/drm/radeon/rs780d.h
> new file mode 100644
> index 0000000..b1142ed
> --- /dev/null
> +++ b/drivers/gpu/drm/radeon/rs780d.h
> @@ -0,0 +1,168 @@
> +/*
> + * Copyright 2011 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + */
> +#ifndef __RS780D_H__
> +#define __RS780D_H__
> +
> +#define CG_SPLL_FUNC_CNTL                                 0x600
> +#       define SPLL_RESET                                (1 << 0)
> +#       define SPLL_SLEEP                                (1 << 1)
> +#       define SPLL_REF_DIV(x)                           ((x) << 2)
> +#       define SPLL_REF_DIV_MASK                         (7 << 2)
> +#       define SPLL_FB_DIV(x)                            ((x) << 5)
> +#       define SPLL_FB_DIV_MASK                          (0xff << 2)
> +#       define SPLL_FB_DIV_SHIFT                         2
> +#       define SPLL_PULSEEN                              (1 << 13)
> +#       define SPLL_PULSENUM(x)                          ((x) << 14)
> +#       define SPLL_PULSENUM_MASK                        (3 << 14)
> +#       define SPLL_SW_HILEN(x)                          ((x) << 16)
> +#       define SPLL_SW_HILEN_MASK                        (0xf << 16)
> +#       define SPLL_SW_LOLEN(x)                          ((x) << 20)
> +#       define SPLL_SW_LOLEN_MASK                        (0xf << 20)
> +#       define SPLL_DIVEN                                (1 << 24)
> +#       define SPLL_BYPASS_EN                            (1 << 25)
> +#       define SPLL_CHG_STATUS                           (1 << 29)
> +#       define SPLL_CTLREQ                               (1 << 30)
> +#       define SPLL_CTLACK                               (1 << 31)
> +
> +/* RS780/RS880 PM */
> +#define	FVTHROT_CNTRL_REG				0x3000
> +#define		DONT_WAIT_FOR_FBDIV_WRAP		(1 << 0)
> +#define		MINIMUM_CIP(x)				((x) << 1)
> +#define		MINIMUM_CIP_SHIFT			1
> +#define		MINIMUM_CIP_MASK			0x1fffffe
> +#define		REFRESH_RATE_DIVISOR(x)			((x) << 25)
> +#define		REFRESH_RATE_DIVISOR_SHIFT		25
> +#define		REFRESH_RATE_DIVISOR_MASK		(0x3 << 25)
> +#define		ENABLE_FV_THROT				(1 << 27)
> +#define		ENABLE_FV_UPDATE			(1 << 28)
> +#define		TREND_SEL_MODE				(1 << 29)
> +#define		FORCE_TREND_SEL				(1 << 30)
> +#define		ENABLE_FV_THROT_IO			(1 << 31)
> +#define	FVTHROT_TARGET_REG				0x3004
> +#define		TARGET_IDLE_COUNT(x)			((x) << 0)
> +#define		TARGET_IDLE_COUNT_MASK			0xffffff
> +#define		TARGET_IDLE_COUNT_SHIFT			0
> +#define	FVTHROT_CB1					0x3008
> +#define	FVTHROT_CB2					0x300c
> +#define	FVTHROT_CB3					0x3010
> +#define	FVTHROT_CB4					0x3014
> +#define	FVTHROT_UTC0					0x3018
> +#define	FVTHROT_UTC1					0x301c
> +#define	FVTHROT_UTC2					0x3020
> +#define	FVTHROT_UTC3					0x3024
> +#define	FVTHROT_UTC4					0x3028
> +#define	FVTHROT_DTC0					0x302c
> +#define	FVTHROT_DTC1					0x3030
> +#define	FVTHROT_DTC2					0x3034
> +#define	FVTHROT_DTC3					0x3038
> +#define	FVTHROT_DTC4					0x303c
> +#define	FVTHROT_FBDIV_REG0				0x3040
> +#define		MIN_FEEDBACK_DIV(x)			((x) << 0)
> +#define		MIN_FEEDBACK_DIV_MASK			0xfff
> +#define		MIN_FEEDBACK_DIV_SHIFT			0
> +#define		MAX_FEEDBACK_DIV(x)			((x) << 12)
> +#define		MAX_FEEDBACK_DIV_MASK			(0xfff << 12)
> +#define		MAX_FEEDBACK_DIV_SHIFT			12
> +#define	FVTHROT_FBDIV_REG1				0x3044
> +#define		MAX_FEEDBACK_STEP(x)			((x) << 0)
> +#define		MAX_FEEDBACK_STEP_MASK			0xfff
> +#define		MAX_FEEDBACK_STEP_SHIFT			0
> +#define		STARTING_FEEDBACK_DIV(x)		((x) << 12)
> +#define		STARTING_FEEDBACK_DIV_MASK		(0xfff << 12)
> +#define		STARTING_FEEDBACK_DIV_SHIFT		12
> +#define		FORCE_FEEDBACK_DIV			(1 << 24)
> +#define	FVTHROT_FBDIV_REG2				0x3048
> +#define		FORCED_FEEDBACK_DIV(x)			((x) << 0)
> +#define		FORCED_FEEDBACK_DIV_MASK		0xfff
> +#define		FORCED_FEEDBACK_DIV_SHIFT		0
> +#define		FB_DIV_TIMER_VAL(x)			((x) << 12)
> +#define		FB_DIV_TIMER_VAL_MASK			(0xffff << 12)
> +#define		FB_DIV_TIMER_VAL_SHIFT			12
> +#define	FVTHROT_FB_US_REG0				0x304c
> +#define	FVTHROT_FB_US_REG1				0x3050
> +#define	FVTHROT_FB_DS_REG0				0x3054
> +#define	FVTHROT_FB_DS_REG1				0x3058
> +#define	FVTHROT_PWM_CTRL_REG0				0x305c
> +#define		STARTING_PWM_HIGHTIME(x)		((x) << 0)
> +#define		STARTING_PWM_HIGHTIME_MASK		0xfff
> +#define		STARTING_PWM_HIGHTIME_SHIFT		0
> +#define		NUMBER_OF_CYCLES_IN_PERIOD(x)		((x) << 12)
> +#define		NUMBER_OF_CYCLES_IN_PERIOD_MASK		(0xfff << 12)
> +#define		NUMBER_OF_CYCLES_IN_PERIOD_SHIFT	12
> +#define		FORCE_STARTING_PWM_HIGHTIME		(1 << 24)
> +#define		INVERT_PWM_WAVEFORM			(1 << 25)
> +#define	FVTHROT_PWM_CTRL_REG1				0x3060
> +#define		MIN_PWM_HIGHTIME(x)			((x) << 0)
> +#define		MIN_PWM_HIGHTIME_MASK			0xfff
> +#define		MIN_PWM_HIGHTIME_SHIFT			0
> +#define		MAX_PWM_HIGHTIME(x)			((x) << 12)
> +#define		MAX_PWM_HIGHTIME_MASK			(0xfff << 12)
> +#define		MAX_PWM_HIGHTIME_SHIFT			12
> +#define	FVTHROT_PWM_US_REG0				0x3064
> +#define	FVTHROT_PWM_US_REG1				0x3068
> +#define	FVTHROT_PWM_DS_REG0				0x306c
> +#define	FVTHROT_PWM_DS_REG1				0x3070
> +#define	FVTHROT_STATUS_REG0				0x3074
> +#define		CURRENT_FEEDBACK_DIV_MASK		0xfff
> +#define		CURRENT_FEEDBACK_DIV_SHIFT		0
> +#define	FVTHROT_STATUS_REG1				0x3078
> +#define	FVTHROT_STATUS_REG2				0x307c
> +#define	CG_INTGFX_MISC					0x3080
> +#define		FVTHROT_VBLANK_SEL			(1 << 9)
> +#define	FVTHROT_PWM_FEEDBACK_DIV_REG1			0x308c
> +#define		RANGE0_PWM_FEEDBACK_DIV(x)		((x) << 0)
> +#define		RANGE0_PWM_FEEDBACK_DIV_MASK		0xfff
> +#define		RANGE0_PWM_FEEDBACK_DIV_SHIFT		0
> +#define		RANGE_PWM_FEEDBACK_DIV_EN		(1 << 12)
> +#define	FVTHROT_PWM_FEEDBACK_DIV_REG2			0x3090
> +#define		RANGE1_PWM_FEEDBACK_DIV(x)		((x) << 0)
> +#define		RANGE1_PWM_FEEDBACK_DIV_MASK		0xfff
> +#define		RANGE1_PWM_FEEDBACK_DIV_SHIFT		0
> +#define		RANGE2_PWM_FEEDBACK_DIV(x)		((x) << 12)
> +#define		RANGE2_PWM_FEEDBACK_DIV_MASK		(0xfff << 12)
> +#define		RANGE2_PWM_FEEDBACK_DIV_SHIFT		12
> +#define	FVTHROT_PWM_FEEDBACK_DIV_REG3			0x3094
> +#define		RANGE0_PWM(x)				((x) << 0)
> +#define		RANGE0_PWM_MASK				0xfff
> +#define		RANGE0_PWM_SHIFT			0
> +#define		RANGE1_PWM(x)				((x) << 12)
> +#define		RANGE1_PWM_MASK				(0xfff << 12)
> +#define		RANGE1_PWM_SHIFT			12
> +#define	FVTHROT_PWM_FEEDBACK_DIV_REG4			0x3098
> +#define		RANGE2_PWM(x)				((x) << 0)
> +#define		RANGE2_PWM_MASK				0xfff
> +#define		RANGE2_PWM_SHIFT			0
> +#define		RANGE3_PWM(x)				((x) << 12)
> +#define		RANGE3_PWM_MASK				(0xfff << 12)
> +#define		RANGE3_PWM_SHIFT			12
> +#define	FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1		0x30ac
> +#define		RANGE0_SLOW_CLK_FEEDBACK_DIV(x)		((x) << 0)
> +#define		RANGE0_SLOW_CLK_FEEDBACK_DIV_MASK	0xfff
> +#define		RANGE0_SLOW_CLK_FEEDBACK_DIV_SHIFT	0
> +#define		RANGE_SLOW_CLK_FEEDBACK_DIV_EN		(1 << 12)
> +
> +#define	GFX_MACRO_BYPASS_CNTL				0x30c0
> +#define		SPLL_BYPASS_CNTL			(1 << 0)
> +#define		UPLL_BYPASS_CNTL			(1 << 1)
> +
> +#endif
> -- 
> 1.7.7.5
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
Jerome Glisse June 26, 2013, 1:18 p.m. UTC | #2
On Wed, Jun 26, 2013 at 02:19:23PM -0400, Alex Deucher wrote:
> On Wed, Jun 26, 2013 at 6:46 AM, Jerome Glisse <j.glisse@gmail.com> wrote:
> > On Wed, Jun 26, 2013 at 09:22:35AM -0400, alexdeucher@gmail.com wrote:
> >> From: Alex Deucher <alexander.deucher@amd.com>
> >>
> >> This adds dpm support for rs780/rs880 asics.  This includes:
> >> - clockgating
> >> - dynamic engine clock scaling
> >> - dynamic voltage scaling
> >>
> >> set radeon.dpm=1 to enable it.
> >>
> >> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
> >
> > Depending on the answer to inline question :
> >
> > Reviewed-by: Jerome Glisse <jglisse@redhat.com>
> >
> >> ---
> >>  drivers/gpu/drm/radeon/Makefile      |    2 +-
> >>  drivers/gpu/drm/radeon/radeon_asic.c |   12 +
> >>  drivers/gpu/drm/radeon/radeon_asic.h |   12 +
> >>  drivers/gpu/drm/radeon/radeon_pm.c   |    7 +
> >>  drivers/gpu/drm/radeon/rs780_dpm.c   |  894 ++++++++++++++++++++++++++++++++++
> >>  drivers/gpu/drm/radeon/rs780_dpm.h   |  109 ++++
> >>  drivers/gpu/drm/radeon/rs780d.h      |  168 +++++++
> >>  7 files changed, 1203 insertions(+), 1 deletions(-)
> >>  create mode 100644 drivers/gpu/drm/radeon/rs780_dpm.c
> >>  create mode 100644 drivers/gpu/drm/radeon/rs780_dpm.h
> >>  create mode 100644 drivers/gpu/drm/radeon/rs780d.h
> >>
> >> diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
> >> index a131a13..e44b046 100644
> >> --- a/drivers/gpu/drm/radeon/Makefile
> >> +++ b/drivers/gpu/drm/radeon/Makefile
> >> @@ -77,7 +77,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
> >>       evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \
> >>       atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
> >>       si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \
> >> -     r600_dpm.o
> >> +     r600_dpm.o rs780_dpm.o
> >>
> >>  radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
> >>  radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
> >> diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
> >> index d9c8e9a..db3c930 100644
> >> --- a/drivers/gpu/drm/radeon/radeon_asic.c
> >> +++ b/drivers/gpu/drm/radeon/radeon_asic.c
> >> @@ -1194,6 +1194,18 @@ static struct radeon_asic rs780_asic = {
> >>               .set_clock_gating = NULL,
> >>               .get_temperature = &rv6xx_get_temp,
> >>       },
> >> +     .dpm = {
> >> +             .init = &rs780_dpm_init,
> >> +             .setup_asic = &rs780_dpm_setup_asic,
> >> +             .enable = &rs780_dpm_enable,
> >> +             .disable = &rs780_dpm_disable,
> >> +             .set_power_state = &rs780_dpm_set_power_state,
> >> +             .display_configuration_changed = &rs780_dpm_display_configuration_changed,
> >> +             .fini = &rs780_dpm_fini,
> >> +             .get_sclk = &rs780_dpm_get_sclk,
> >> +             .get_mclk = &rs780_dpm_get_mclk,
> >> +             .print_power_state = &rs780_dpm_print_power_state,
> >> +     },
> >>       .pflip = {
> >>               .pre_page_flip = &rs600_pre_page_flip,
> >>               .page_flip = &rs600_page_flip,
> >> diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
> >> index 8507cae..134bf57 100644
> >> --- a/drivers/gpu/drm/radeon/radeon_asic.h
> >> +++ b/drivers/gpu/drm/radeon/radeon_asic.h
> >> @@ -396,6 +396,18 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev);
> >>  u32 r600_get_xclk(struct radeon_device *rdev);
> >>  uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev);
> >>  int rv6xx_get_temp(struct radeon_device *rdev);
> >> +/* rs780 dpm */
> >> +int rs780_dpm_init(struct radeon_device *rdev);
> >> +int rs780_dpm_enable(struct radeon_device *rdev);
> >> +void rs780_dpm_disable(struct radeon_device *rdev);
> >> +int rs780_dpm_set_power_state(struct radeon_device *rdev);
> >> +void rs780_dpm_setup_asic(struct radeon_device *rdev);
> >> +void rs780_dpm_display_configuration_changed(struct radeon_device *rdev);
> >> +void rs780_dpm_fini(struct radeon_device *rdev);
> >> +u32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low);
> >> +u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low);
> >> +void rs780_dpm_print_power_state(struct radeon_device *rdev,
> >> +                              struct radeon_ps *ps);
> >>
> >>  /* uvd */
> >>  int r600_uvd_init(struct radeon_device *rdev);
> >> diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
> >> index 4f5422e..853a8a2 100644
> >> --- a/drivers/gpu/drm/radeon/radeon_pm.c
> >> +++ b/drivers/gpu/drm/radeon/radeon_pm.c
> >> @@ -1030,6 +1030,13 @@ int radeon_pm_init(struct radeon_device *rdev)
> >>  {
> >>       /* enable dpm on rv6xx+ */
> >>       switch (rdev->family) {
> >> +     case CHIP_RS780:
> >> +     case CHIP_RS880:
> >> +             if (radeon_dpm == 1)
> >> +                     rdev->pm.pm_method = PM_METHOD_DPM;
> >> +             else
> >> +                     rdev->pm.pm_method = PM_METHOD_PROFILE;
> >> +             break;
> >>       default:
> >>               /* default to profile method */
> >>               rdev->pm.pm_method = PM_METHOD_PROFILE;
> >> diff --git a/drivers/gpu/drm/radeon/rs780_dpm.c b/drivers/gpu/drm/radeon/rs780_dpm.c
> >> new file mode 100644
> >> index 0000000..f594900
> >> --- /dev/null
> >> +++ b/drivers/gpu/drm/radeon/rs780_dpm.c
> >> @@ -0,0 +1,894 @@
> >> +/*
> >> + * Copyright 2011 Advanced Micro Devices, Inc.
> >> + *
> >> + * Permission is hereby granted, free of charge, to any person obtaining a
> >> + * copy of this software and associated documentation files (the "Software"),
> >> + * to deal in the Software without restriction, including without limitation
> >> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> >> + * and/or sell copies of the Software, and to permit persons to whom the
> >> + * Software is furnished to do so, subject to the following conditions:
> >> + *
> >> + * The above copyright notice and this permission notice shall be included in
> >> + * all copies or substantial portions of the Software.
> >> + *
> >> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> >> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> >> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> >> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> >> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> >> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> >> + * OTHER DEALINGS IN THE SOFTWARE.
> >> + *
> >> + * Authors: Alex Deucher
> >> + */
> >> +
> >> +#include "drmP.h"
> >> +#include "radeon.h"
> >> +#include "rs780d.h"
> >> +#include "r600_dpm.h"
> >> +#include "rs780_dpm.h"
> >> +#include "atom.h"
> >> +
> >> +static struct igp_ps *rs780_get_ps(struct radeon_ps *rps)
> >> +{
> >> +     struct igp_ps *ps = rps->ps_priv;
> >> +
> >> +     return ps;
> >> +}
> >> +
> >> +static struct igp_power_info *rs780_get_pi(struct radeon_device *rdev)
> >> +{
> >> +     struct igp_power_info *pi = rdev->pm.dpm.priv;
> >> +
> >> +     return pi;
> >> +}
> >> +
> >> +static void rs780_get_pm_mode_parameters(struct radeon_device *rdev)
> >> +{
> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
> >> +     struct radeon_mode_info *minfo = &rdev->mode_info;
> >> +     struct drm_crtc *crtc;
> >> +     struct radeon_crtc *radeon_crtc;
> >> +     int i;
> >> +
> >> +     /* defaults */
> >> +     pi->crtc_id = 0;
> >> +     pi->refresh_rate = 60;
> >> +
> >> +     for (i = 0; i < rdev->num_crtc; i++) {
> >> +             crtc = (struct drm_crtc *)minfo->crtcs[i];
> >> +             if (crtc && crtc->enabled) {
> >> +                     radeon_crtc = to_radeon_crtc(crtc);
> >> +                     pi->crtc_id = radeon_crtc->crtc_id;
> >> +                     if (crtc->mode.htotal && crtc->mode.vtotal)
> >> +                             pi->refresh_rate =
> >> +                                     (crtc->mode.clock * 1000) /
> >> +                                     (crtc->mode.htotal * crtc->mode.vtotal);
> >> +                     break;
> >> +             }
> >> +     }
> >
> > Ok this looks wrong to me you look for the first enabled crtc but on those iirc
> > there could be 2 so first one might be a low refresh rate and second one an higher
> > one. Thus returning the first one might lead to PM decision that are wrong.
> >

So what happens when 2 are active ? Flickering on the unsync one ?

Cheers,
Jerome

> 
> On RS780/RS880, the hardware can only synchronize with a single crtc,
> so it doesn't really matter which one we pick as long as it's active.
> 
> 
> >> +}
> >> +
> >> +static void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable);
> >> +
> >> +static int rs780_initialize_dpm_power_state(struct radeon_device *rdev)
> >> +{
> >> +     struct atom_clock_dividers dividers;
> >> +     struct igp_ps *default_state = rs780_get_ps(rdev->pm.dpm.boot_ps);
> >> +     int i, ret;
> >> +
> >> +     ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
> >> +                                          default_state->sclk_low, false, &dividers);
> >> +     if (ret)
> >> +             return ret;
> >> +
> >> +     r600_engine_clock_entry_set_reference_divider(rdev, 0, dividers.ref_div);
> >> +     r600_engine_clock_entry_set_feedback_divider(rdev, 0, dividers.fb_div);
> >> +     r600_engine_clock_entry_set_post_divider(rdev, 0, dividers.post_div);
> >> +
> >> +     if (dividers.enable_post_div)
> >> +             r600_engine_clock_entry_enable_post_divider(rdev, 0, true);
> >> +     else
> >> +             r600_engine_clock_entry_enable_post_divider(rdev, 0, false);
> >> +
> >> +     r600_engine_clock_entry_set_step_time(rdev, 0, R600_SST_DFLT);
> >> +     r600_engine_clock_entry_enable_pulse_skipping(rdev, 0, false);
> >> +
> >> +     r600_engine_clock_entry_enable(rdev, 0, true);
> >> +     for (i = 1; i < R600_PM_NUMBER_OF_SCLKS; i++)
> >> +             r600_engine_clock_entry_enable(rdev, i, false);
> >> +
> >> +     r600_enable_mclk_control(rdev, false);
> >> +     r600_voltage_control_enable_pins(rdev, 0);
> >> +
> >> +     return 0;
> >> +}
> >> +
> >> +static int rs780_initialize_dpm_parameters(struct radeon_device *rdev)
> >> +{
> >> +     int ret = 0;
> >> +     int i;
> >> +
> >> +     r600_set_bsp(rdev, R600_BSU_DFLT, R600_BSP_DFLT);
> >> +
> >> +     r600_set_at(rdev, 0, 0, 0, 0);
> >> +
> >> +     r600_set_git(rdev, R600_GICST_DFLT);
> >> +
> >> +     for (i = 0; i < R600_PM_NUMBER_OF_TC; i++)
> >> +             r600_set_tc(rdev, i, 0, 0);
> >> +
> >> +     r600_select_td(rdev, R600_TD_DFLT);
> >> +     r600_set_vrc(rdev, 0);
> >> +
> >> +     r600_set_tpu(rdev, R600_TPU_DFLT);
> >> +     r600_set_tpc(rdev, R600_TPC_DFLT);
> >> +
> >> +     r600_set_sstu(rdev, R600_SSTU_DFLT);
> >> +     r600_set_sst(rdev, R600_SST_DFLT);
> >> +
> >> +     r600_set_fctu(rdev, R600_FCTU_DFLT);
> >> +     r600_set_fct(rdev, R600_FCT_DFLT);
> >> +
> >> +     r600_set_vddc3d_oorsu(rdev, R600_VDDC3DOORSU_DFLT);
> >> +     r600_set_vddc3d_oorphc(rdev, R600_VDDC3DOORPHC_DFLT);
> >> +     r600_set_vddc3d_oorsdc(rdev, R600_VDDC3DOORSDC_DFLT);
> >> +     r600_set_ctxcgtt3d_rphc(rdev, R600_CTXCGTT3DRPHC_DFLT);
> >> +     r600_set_ctxcgtt3d_rsdc(rdev, R600_CTXCGTT3DRSDC_DFLT);
> >> +
> >> +     r600_vid_rt_set_vru(rdev, R600_VRU_DFLT);
> >> +     r600_vid_rt_set_vrt(rdev, R600_VOLTAGERESPONSETIME_DFLT);
> >> +     r600_vid_rt_set_ssu(rdev, R600_SPLLSTEPUNIT_DFLT);
> >> +
> >> +     ret = rs780_initialize_dpm_power_state(rdev);
> >> +
> >> +     r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW,     0);
> >> +     r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM,  0);
> >> +     r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_HIGH,    0);
> >> +
> >> +     r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW,    0);
> >> +     r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
> >> +     r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_HIGH,   0);
> >> +
> >> +     r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW,    0);
> >> +     r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
> >> +     r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_HIGH,   0);
> >> +
> >> +     r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW,    R600_DISPLAY_WATERMARK_HIGH);
> >> +     r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM, R600_DISPLAY_WATERMARK_HIGH);
> >> +     r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_HIGH,   R600_DISPLAY_WATERMARK_HIGH);
> >> +
> >> +     r600_power_level_enable(rdev, R600_POWER_LEVEL_CTXSW, false);
> >> +     r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false);
> >> +     r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false);
> >> +     r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
> >> +
> >> +     r600_power_level_set_enter_index(rdev, R600_POWER_LEVEL_LOW);
> >> +
> >> +     r600_set_vrc(rdev, RS780_CGFTV_DFLT);
> >> +
> >> +     return ret;
> >> +}
> >> +
> >> +static void rs780_start_dpm(struct radeon_device *rdev)
> >> +{
> >> +     r600_enable_sclk_control(rdev, false);
> >> +     r600_enable_mclk_control(rdev, false);
> >> +
> >> +     r600_dynamicpm_enable(rdev, true);
> >> +
> >> +     radeon_wait_for_vblank(rdev, 0);
> >> +     radeon_wait_for_vblank(rdev, 1);
> >> +
> >> +     r600_enable_spll_bypass(rdev, true);
> >> +     r600_wait_for_spll_change(rdev);
> >> +     r600_enable_spll_bypass(rdev, false);
> >> +     r600_wait_for_spll_change(rdev);
> >> +
> >> +     r600_enable_spll_bypass(rdev, true);
> >> +     r600_wait_for_spll_change(rdev);
> >> +     r600_enable_spll_bypass(rdev, false);
> >> +     r600_wait_for_spll_change(rdev);
> >> +
> >> +     r600_enable_sclk_control(rdev, true);
> >> +}
> >> +
> >> +
> >> +static void rs780_preset_ranges_slow_clk_fbdiv_en(struct radeon_device *rdev)
> >> +{
> >> +     WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1, RANGE_SLOW_CLK_FEEDBACK_DIV_EN,
> >> +              ~RANGE_SLOW_CLK_FEEDBACK_DIV_EN);
> >> +
> >> +     WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1,
> >> +              RANGE0_SLOW_CLK_FEEDBACK_DIV(RS780_SLOWCLKFEEDBACKDIV_DFLT),
> >> +              ~RANGE0_SLOW_CLK_FEEDBACK_DIV_MASK);
> >> +}
> >> +
> >> +static void rs780_preset_starting_fbdiv(struct radeon_device *rdev)
> >> +{
> >> +     u32 fbdiv = (RREG32(CG_SPLL_FUNC_CNTL) & SPLL_FB_DIV_MASK) >> SPLL_FB_DIV_SHIFT;
> >> +
> >> +     WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(fbdiv),
> >> +              ~STARTING_FEEDBACK_DIV_MASK);
> >> +
> >> +     WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(fbdiv),
> >> +              ~FORCED_FEEDBACK_DIV_MASK);
> >> +
> >> +     WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
> >> +}
> >> +
> >> +static void rs780_voltage_scaling_init(struct radeon_device *rdev)
> >> +{
> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
> >> +     struct drm_device *dev = rdev->ddev;
> >> +     u32 fv_throt_pwm_fb_div_range[3];
> >> +     u32 fv_throt_pwm_range[4];
> >> +
> >> +     if (dev->pdev->device == 0x9614) {
> >> +             fv_throt_pwm_fb_div_range[0] = RS780D_FVTHROTPWMFBDIVRANGEREG0_DFLT;
> >> +             fv_throt_pwm_fb_div_range[1] = RS780D_FVTHROTPWMFBDIVRANGEREG1_DFLT;
> >> +             fv_throt_pwm_fb_div_range[2] = RS780D_FVTHROTPWMFBDIVRANGEREG2_DFLT;
> >> +     } else if ((dev->pdev->device == 0x9714) ||
> >> +                (dev->pdev->device == 0x9715)) {
> >> +             fv_throt_pwm_fb_div_range[0] = RS880D_FVTHROTPWMFBDIVRANGEREG0_DFLT;
> >> +             fv_throt_pwm_fb_div_range[1] = RS880D_FVTHROTPWMFBDIVRANGEREG1_DFLT;
> >> +             fv_throt_pwm_fb_div_range[2] = RS880D_FVTHROTPWMFBDIVRANGEREG2_DFLT;
> >> +     } else {
> >> +             fv_throt_pwm_fb_div_range[0] = RS780_FVTHROTPWMFBDIVRANGEREG0_DFLT;
> >> +             fv_throt_pwm_fb_div_range[1] = RS780_FVTHROTPWMFBDIVRANGEREG1_DFLT;
> >> +             fv_throt_pwm_fb_div_range[2] = RS780_FVTHROTPWMFBDIVRANGEREG2_DFLT;
> >> +     }
> >> +
> >> +     if (pi->pwm_voltage_control) {
> >> +             fv_throt_pwm_range[0] = pi->min_voltage;
> >> +             fv_throt_pwm_range[1] = pi->min_voltage;
> >> +             fv_throt_pwm_range[2] = pi->max_voltage;
> >> +             fv_throt_pwm_range[3] = pi->max_voltage;
> >> +     } else {
> >> +             fv_throt_pwm_range[0] = pi->invert_pwm_required ?
> >> +                     RS780_FVTHROTPWMRANGE3_GPIO_DFLT : RS780_FVTHROTPWMRANGE0_GPIO_DFLT;
> >> +             fv_throt_pwm_range[1] = pi->invert_pwm_required ?
> >> +                     RS780_FVTHROTPWMRANGE2_GPIO_DFLT : RS780_FVTHROTPWMRANGE1_GPIO_DFLT;
> >> +             fv_throt_pwm_range[2] = pi->invert_pwm_required ?
> >> +                     RS780_FVTHROTPWMRANGE1_GPIO_DFLT : RS780_FVTHROTPWMRANGE2_GPIO_DFLT;
> >> +             fv_throt_pwm_range[3] = pi->invert_pwm_required ?
> >> +                     RS780_FVTHROTPWMRANGE0_GPIO_DFLT : RS780_FVTHROTPWMRANGE3_GPIO_DFLT;
> >> +     }
> >> +
> >> +     WREG32_P(FVTHROT_PWM_CTRL_REG0,
> >> +              STARTING_PWM_HIGHTIME(pi->max_voltage),
> >> +              ~STARTING_PWM_HIGHTIME_MASK);
> >> +
> >> +     WREG32_P(FVTHROT_PWM_CTRL_REG0,
> >> +              NUMBER_OF_CYCLES_IN_PERIOD(pi->num_of_cycles_in_period),
> >> +              ~NUMBER_OF_CYCLES_IN_PERIOD_MASK);
> >> +
> >> +     WREG32_P(FVTHROT_PWM_CTRL_REG0, FORCE_STARTING_PWM_HIGHTIME,
> >> +              ~FORCE_STARTING_PWM_HIGHTIME);
> >> +
> >> +     if (pi->invert_pwm_required)
> >> +             WREG32_P(FVTHROT_PWM_CTRL_REG0, INVERT_PWM_WAVEFORM, ~INVERT_PWM_WAVEFORM);
> >> +     else
> >> +             WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~INVERT_PWM_WAVEFORM);
> >> +
> >> +     rs780_voltage_scaling_enable(rdev, true);
> >> +
> >> +     WREG32(FVTHROT_PWM_CTRL_REG1,
> >> +            (MIN_PWM_HIGHTIME(pi->min_voltage) |
> >> +             MAX_PWM_HIGHTIME(pi->max_voltage)));
> >> +
> >> +     WREG32(FVTHROT_PWM_US_REG0, RS780_FVTHROTPWMUSREG0_DFLT);
> >> +     WREG32(FVTHROT_PWM_US_REG1, RS780_FVTHROTPWMUSREG1_DFLT);
> >> +     WREG32(FVTHROT_PWM_DS_REG0, RS780_FVTHROTPWMDSREG0_DFLT);
> >> +     WREG32(FVTHROT_PWM_DS_REG1, RS780_FVTHROTPWMDSREG1_DFLT);
> >> +
> >> +     WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1,
> >> +              RANGE0_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[0]),
> >> +              ~RANGE0_PWM_FEEDBACK_DIV_MASK);
> >> +
> >> +     WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG2,
> >> +            (RANGE1_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[1]) |
> >> +             RANGE2_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[2])));
> >> +
> >> +     WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG3,
> >> +            (RANGE0_PWM(fv_throt_pwm_range[1]) |
> >> +             RANGE1_PWM(fv_throt_pwm_range[2])));
> >> +     WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG4,
> >> +            (RANGE2_PWM(fv_throt_pwm_range[1]) |
> >> +             RANGE3_PWM(fv_throt_pwm_range[2])));
> >> +}
> >> +
> >> +static void rs780_clk_scaling_enable(struct radeon_device *rdev, bool enable)
> >> +{
> >> +     if (enable)
> >> +             WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT | ENABLE_FV_UPDATE,
> >> +                      ~(ENABLE_FV_THROT | ENABLE_FV_UPDATE));
> >> +     else
> >> +             WREG32_P(FVTHROT_CNTRL_REG, 0,
> >> +                      ~(ENABLE_FV_THROT | ENABLE_FV_UPDATE));
> >> +}
> >> +
> >> +static void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable)
> >> +{
> >> +     if (enable)
> >> +             WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT_IO, ~ENABLE_FV_THROT_IO);
> >> +     else
> >> +             WREG32_P(FVTHROT_CNTRL_REG, 0, ~ENABLE_FV_THROT_IO);
> >> +}
> >> +
> >> +static void rs780_set_engine_clock_wfc(struct radeon_device *rdev)
> >> +{
> >> +     WREG32(FVTHROT_UTC0, RS780_FVTHROTUTC0_DFLT);
> >> +     WREG32(FVTHROT_UTC1, RS780_FVTHROTUTC1_DFLT);
> >> +     WREG32(FVTHROT_UTC2, RS780_FVTHROTUTC2_DFLT);
> >> +     WREG32(FVTHROT_UTC3, RS780_FVTHROTUTC3_DFLT);
> >> +     WREG32(FVTHROT_UTC4, RS780_FVTHROTUTC4_DFLT);
> >> +
> >> +     WREG32(FVTHROT_DTC0, RS780_FVTHROTDTC0_DFLT);
> >> +     WREG32(FVTHROT_DTC1, RS780_FVTHROTDTC1_DFLT);
> >> +     WREG32(FVTHROT_DTC2, RS780_FVTHROTDTC2_DFLT);
> >> +     WREG32(FVTHROT_DTC3, RS780_FVTHROTDTC3_DFLT);
> >> +     WREG32(FVTHROT_DTC4, RS780_FVTHROTDTC4_DFLT);
> >> +}
> >> +
> >> +static void rs780_set_engine_clock_sc(struct radeon_device *rdev)
> >> +{
> >> +     WREG32_P(FVTHROT_FBDIV_REG2,
> >> +              FB_DIV_TIMER_VAL(RS780_FBDIVTIMERVAL_DFLT),
> >> +              ~FB_DIV_TIMER_VAL_MASK);
> >> +
> >> +     WREG32_P(FVTHROT_CNTRL_REG,
> >> +              REFRESH_RATE_DIVISOR(0) | MINIMUM_CIP(0xf),
> >> +              ~(REFRESH_RATE_DIVISOR_MASK | MINIMUM_CIP_MASK));
> >> +}
> >> +
> >> +static void rs780_set_engine_clock_tdc(struct radeon_device *rdev)
> >> +{
> >> +     WREG32_P(FVTHROT_CNTRL_REG, 0, ~(FORCE_TREND_SEL | TREND_SEL_MODE));
> >> +}
> >> +
> >> +static void rs780_set_engine_clock_ssc(struct radeon_device *rdev)
> >> +{
> >> +     WREG32(FVTHROT_FB_US_REG0, RS780_FVTHROTFBUSREG0_DFLT);
> >> +     WREG32(FVTHROT_FB_US_REG1, RS780_FVTHROTFBUSREG1_DFLT);
> >> +     WREG32(FVTHROT_FB_DS_REG0, RS780_FVTHROTFBDSREG0_DFLT);
> >> +     WREG32(FVTHROT_FB_DS_REG1, RS780_FVTHROTFBDSREG1_DFLT);
> >> +
> >> +     WREG32_P(FVTHROT_FBDIV_REG1, MAX_FEEDBACK_STEP(1), ~MAX_FEEDBACK_STEP_MASK);
> >> +}
> >> +
> >> +static void rs780_program_at(struct radeon_device *rdev)
> >> +{
> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
> >> +
> >> +     WREG32(FVTHROT_TARGET_REG, 30000000 / pi->refresh_rate);
> >> +     WREG32(FVTHROT_CB1, 1000000 * 5 / pi->refresh_rate);
> >> +     WREG32(FVTHROT_CB2, 1000000 * 10 / pi->refresh_rate);
> >> +     WREG32(FVTHROT_CB3, 1000000 * 30 / pi->refresh_rate);
> >> +     WREG32(FVTHROT_CB4, 1000000 * 50 / pi->refresh_rate);
> >> +}
> >> +
> >> +static void rs780_disable_vbios_powersaving(struct radeon_device *rdev)
> >> +{
> >> +     WREG32_P(CG_INTGFX_MISC, 0, ~0xFFF00000);
> >> +}
> >> +
> >> +static void rs780_force_voltage_to_high(struct radeon_device *rdev)
> >> +{
> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
> >> +     struct igp_ps *current_state = rs780_get_ps(rdev->pm.dpm.current_ps);
> >> +
> >> +     if ((current_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
> >> +         (current_state->min_voltage == RS780_VDDC_LEVEL_HIGH))
> >> +             return;
> >> +
> >> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
> >> +
> >> +     udelay(1);
> >> +
> >> +     WREG32_P(FVTHROT_PWM_CTRL_REG0,
> >> +              STARTING_PWM_HIGHTIME(pi->max_voltage),
> >> +              ~STARTING_PWM_HIGHTIME_MASK);
> >> +
> >> +     WREG32_P(FVTHROT_PWM_CTRL_REG0,
> >> +              FORCE_STARTING_PWM_HIGHTIME, ~FORCE_STARTING_PWM_HIGHTIME);
> >> +
> >> +     WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1, 0,
> >> +             ~RANGE_PWM_FEEDBACK_DIV_EN);
> >> +
> >> +     udelay(1);
> >> +
> >> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
> >> +}
> >> +
> >> +static int rs780_set_engine_clock_scaling(struct radeon_device *rdev)
> >> +{
> >> +     struct atom_clock_dividers min_dividers, max_dividers, current_max_dividers;
> >> +     struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
> >> +     struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
> >> +     int ret;
> >> +
> >> +     if ((new_state->sclk_high == old_state->sclk_high) &&
> >> +         (new_state->sclk_low == old_state->sclk_low))
> >> +             return 0;
> >> +
> >> +     ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
> >> +                                          new_state->sclk_low, false, &min_dividers);
> >> +     if (ret)
> >> +             return ret;
> >> +
> >> +     ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
> >> +                                          new_state->sclk_high, false, &max_dividers);
> >> +     if (ret)
> >> +             return ret;
> >> +
> >> +     ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
> >> +                                          old_state->sclk_high, false, &current_max_dividers);
> >> +     if (ret)
> >> +             return ret;
> >> +
> >> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
> >> +
> >> +     WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(max_dividers.fb_div),
> >> +              ~FORCED_FEEDBACK_DIV_MASK);
> >> +     WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(max_dividers.fb_div),
> >> +              ~STARTING_FEEDBACK_DIV_MASK);
> >> +     WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
> >> +
> >> +     udelay(100);
> >> +
> >> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
> >> +
> >> +     if (max_dividers.fb_div > min_dividers.fb_div) {
> >> +             WREG32_P(FVTHROT_FBDIV_REG0,
> >> +                      MIN_FEEDBACK_DIV(min_dividers.fb_div) |
> >> +                      MAX_FEEDBACK_DIV(max_dividers.fb_div),
> >> +                      ~(MIN_FEEDBACK_DIV_MASK | MAX_FEEDBACK_DIV_MASK));
> >> +
> >> +             WREG32_P(FVTHROT_FBDIV_REG1, 0, ~FORCE_FEEDBACK_DIV);
> >> +     }
> >> +
> >> +     return 0;
> >> +}
> >> +
> >> +static void rs780_set_engine_clock_spc(struct radeon_device *rdev)
> >> +{
> >> +     struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
> >> +     struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
> >> +
> >> +     if ((new_state->sclk_high == old_state->sclk_high) &&
> >> +         (new_state->sclk_low == old_state->sclk_low))
> >> +             return;
> >> +
> >> +     if (pi->crtc_id == 0)
> >> +             WREG32_P(CG_INTGFX_MISC, 0, ~FVTHROT_VBLANK_SEL);
> >> +     else
> >> +             WREG32_P(CG_INTGFX_MISC, FVTHROT_VBLANK_SEL, ~FVTHROT_VBLANK_SEL);
> >> +
> >> +}
> >> +
> >> +static void rs780_activate_engine_clk_scaling(struct radeon_device *rdev)
> >> +{
> >> +     struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
> >> +     struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
> >> +
> >> +     if ((new_state->sclk_high == old_state->sclk_high) &&
> >> +         (new_state->sclk_low == old_state->sclk_low))
> >> +             return;
> >> +
> >> +     rs780_clk_scaling_enable(rdev, true);
> >> +}
> >> +
> >> +static u32 rs780_get_voltage_for_vddc_level(struct radeon_device *rdev,
> >> +                                         enum rs780_vddc_level vddc)
> >> +{
> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
> >> +
> >> +     if (vddc == RS780_VDDC_LEVEL_HIGH)
> >> +             return pi->max_voltage;
> >> +     else if (vddc == RS780_VDDC_LEVEL_LOW)
> >> +             return pi->min_voltage;
> >> +     else
> >> +             return pi->max_voltage;
> >> +}
> >> +
> >> +static void rs780_enable_voltage_scaling(struct radeon_device *rdev)
> >> +{
> >> +     struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
> >> +     enum rs780_vddc_level vddc_high, vddc_low;
> >> +
> >> +     udelay(100);
> >> +
> >> +     if ((new_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
> >> +         (new_state->min_voltage == RS780_VDDC_LEVEL_HIGH))
> >> +             return;
> >> +
> >> +     vddc_high = rs780_get_voltage_for_vddc_level(rdev,
> >> +                                                  new_state->max_voltage);
> >> +     vddc_low = rs780_get_voltage_for_vddc_level(rdev,
> >> +                                                 new_state->min_voltage);
> >> +
> >> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
> >> +
> >> +     udelay(1);
> >> +     if (vddc_high > vddc_low) {
> >> +             WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1,
> >> +                      RANGE_PWM_FEEDBACK_DIV_EN, ~RANGE_PWM_FEEDBACK_DIV_EN);
> >> +
> >> +             WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~FORCE_STARTING_PWM_HIGHTIME);
> >> +     } else if (vddc_high == vddc_low) {
> >> +             if (pi->max_voltage != vddc_high) {
> >> +                     WREG32_P(FVTHROT_PWM_CTRL_REG0,
> >> +                              STARTING_PWM_HIGHTIME(vddc_high),
> >> +                              ~STARTING_PWM_HIGHTIME_MASK);
> >> +
> >> +                     WREG32_P(FVTHROT_PWM_CTRL_REG0,
> >> +                              FORCE_STARTING_PWM_HIGHTIME,
> >> +                              ~FORCE_STARTING_PWM_HIGHTIME);
> >> +             }
> >> +     }
> >> +
> >> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
> >> +}
> >> +
> >> +int rs780_dpm_enable(struct radeon_device *rdev)
> >> +{
> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
> >> +
> >> +     rs780_get_pm_mode_parameters(rdev);
> >> +     rs780_disable_vbios_powersaving(rdev);
> >> +
> >> +     if (r600_dynamicpm_enabled(rdev))
> >> +             return -EINVAL;
> >> +     if (rs780_initialize_dpm_parameters(rdev))
> >> +             return -EINVAL;
> >> +     rs780_start_dpm(rdev);
> >> +
> >> +     rs780_preset_ranges_slow_clk_fbdiv_en(rdev);
> >> +     rs780_preset_starting_fbdiv(rdev);
> >> +     if (pi->voltage_control)
> >> +             rs780_voltage_scaling_init(rdev);
> >> +     rs780_clk_scaling_enable(rdev, true);
> >> +     rs780_set_engine_clock_sc(rdev);
> >> +     rs780_set_engine_clock_wfc(rdev);
> >> +     rs780_program_at(rdev);
> >> +     rs780_set_engine_clock_tdc(rdev);
> >> +     rs780_set_engine_clock_ssc(rdev);
> >> +
> >> +     if (pi->gfx_clock_gating)
> >> +             r600_gfx_clockgating_enable(rdev, true);
> >> +
> >> +     return 0;
> >> +}
> >> +
> >> +void rs780_dpm_disable(struct radeon_device *rdev)
> >> +{
> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
> >> +
> >> +     r600_dynamicpm_enable(rdev, false);
> >> +
> >> +     rs780_clk_scaling_enable(rdev, false);
> >> +     rs780_voltage_scaling_enable(rdev, false);
> >> +
> >> +     if (pi->gfx_clock_gating)
> >> +             r600_gfx_clockgating_enable(rdev, false);
> >> +}
> >> +
> >> +int rs780_dpm_set_power_state(struct radeon_device *rdev)
> >> +{
> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
> >> +
> >> +     rs780_get_pm_mode_parameters(rdev);
> >> +
> >> +     if (pi->voltage_control) {
> >> +             rs780_force_voltage_to_high(rdev);
> >> +             mdelay(5);
> >> +     }
> >> +
> >> +     rs780_set_engine_clock_scaling(rdev);
> >> +     rs780_set_engine_clock_spc(rdev);
> >> +
> >> +     rs780_activate_engine_clk_scaling(rdev);
> >> +
> >> +     if (pi->voltage_control)
> >> +             rs780_enable_voltage_scaling(rdev);
> >> +
> >> +     return 0;
> >> +}
> >> +
> >> +void rs780_dpm_setup_asic(struct radeon_device *rdev)
> >> +{
> >> +
> >> +}
> >> +
> >> +void rs780_dpm_display_configuration_changed(struct radeon_device *rdev)
> >> +{
> >> +     rs780_get_pm_mode_parameters(rdev);
> >> +     rs780_program_at(rdev);
> >> +}
> >> +
> >> +union igp_info {
> >> +     struct _ATOM_INTEGRATED_SYSTEM_INFO info;
> >> +     struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
> >> +};
> >> +
> >> +union power_info {
> >> +     struct _ATOM_POWERPLAY_INFO info;
> >> +     struct _ATOM_POWERPLAY_INFO_V2 info_2;
> >> +     struct _ATOM_POWERPLAY_INFO_V3 info_3;
> >> +     struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
> >> +     struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
> >> +     struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
> >> +};
> >> +
> >> +union pplib_clock_info {
> >> +     struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
> >> +     struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
> >> +     struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
> >> +     struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
> >> +};
> >> +
> >> +union pplib_power_state {
> >> +     struct _ATOM_PPLIB_STATE v1;
> >> +     struct _ATOM_PPLIB_STATE_V2 v2;
> >> +};
> >> +
> >> +static void 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)
> >> +{
> >> +     rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
> >> +     rps->class = le16_to_cpu(non_clock_info->usClassification);
> >> +     rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
> >> +
> >> +     if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
> >> +             rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
> >> +             rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
> >> +     } else if (r600_is_uvd_state(rps->class, rps->class2)) {
> >> +             rps->vclk = RS780_DEFAULT_VCLK_FREQ;
> >> +             rps->dclk = RS780_DEFAULT_DCLK_FREQ;
> >> +     } else {
> >> +             rps->vclk = 0;
> >> +             rps->dclk = 0;
> >> +     }
> >> +
> >> +     if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
> >> +             rdev->pm.dpm.boot_ps = rps;
> >> +     if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
> >> +             rdev->pm.dpm.uvd_ps = rps;
> >> +}
> >> +
> >> +static void rs780_parse_pplib_clock_info(struct radeon_device *rdev,
> >> +                                      struct radeon_ps *rps,
> >> +                                      union pplib_clock_info *clock_info)
> >> +{
> >> +     struct igp_ps *ps = rs780_get_ps(rps);
> >> +     u32 sclk;
> >> +
> >> +     sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow);
> >> +     sclk |= clock_info->rs780.ucLowEngineClockHigh << 16;
> >> +     ps->sclk_low = sclk;
> >> +     sclk = le16_to_cpu(clock_info->rs780.usHighEngineClockLow);
> >> +     sclk |= clock_info->rs780.ucHighEngineClockHigh << 16;
> >> +     ps->sclk_high = sclk;
> >> +     switch (le16_to_cpu(clock_info->rs780.usVDDC)) {
> >> +     case ATOM_PPLIB_RS780_VOLTAGE_NONE:
> >> +     default:
> >> +             ps->min_voltage = RS780_VDDC_LEVEL_UNKNOWN;
> >> +             ps->max_voltage = RS780_VDDC_LEVEL_UNKNOWN;
> >> +             break;
> >> +     case ATOM_PPLIB_RS780_VOLTAGE_LOW:
> >> +             ps->min_voltage = RS780_VDDC_LEVEL_LOW;
> >> +             ps->max_voltage = RS780_VDDC_LEVEL_LOW;
> >> +             break;
> >> +     case ATOM_PPLIB_RS780_VOLTAGE_HIGH:
> >> +             ps->min_voltage = RS780_VDDC_LEVEL_HIGH;
> >> +             ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
> >> +             break;
> >> +     case ATOM_PPLIB_RS780_VOLTAGE_VARIABLE:
> >> +             ps->min_voltage = RS780_VDDC_LEVEL_LOW;
> >> +             ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
> >> +             break;
> >> +     }
> >> +     ps->flags = le32_to_cpu(clock_info->rs780.ulFlags);
> >> +
> >> +     if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
> >> +             ps->sclk_low = rdev->clock.default_sclk;
> >> +             ps->sclk_high = rdev->clock.default_sclk;
> >> +             ps->min_voltage = RS780_VDDC_LEVEL_HIGH;
> >> +             ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
> >> +     }
> >> +}
> >> +
> >> +static int rs780_parse_power_table(struct radeon_device *rdev)
> >> +{
> >> +     struct radeon_mode_info *mode_info = &rdev->mode_info;
> >> +     struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
> >> +     union pplib_power_state *power_state;
> >> +     int i;
> >> +     union pplib_clock_info *clock_info;
> >> +     union power_info *power_info;
> >> +     int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
> >> +        u16 data_offset;
> >> +     u8 frev, crev;
> >> +     struct igp_ps *ps;
> >> +
> >> +     if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
> >> +                                &frev, &crev, &data_offset))
> >> +             return -EINVAL;
> >> +     power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
> >> +
> >> +     rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
> >> +                               power_info->pplib.ucNumStates, GFP_KERNEL);
> >> +     if (!rdev->pm.dpm.ps)
> >> +             return -ENOMEM;
> >> +     rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
> >> +     rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
> >> +     rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
> >> +
> >> +     for (i = 0; i < power_info->pplib.ucNumStates; i++) {
> >> +             power_state = (union pplib_power_state *)
> >> +                     (mode_info->atom_context->bios + data_offset +
> >> +                      le16_to_cpu(power_info->pplib.usStateArrayOffset) +
> >> +                      i * power_info->pplib.ucStateEntrySize);
> >> +             non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
> >> +                     (mode_info->atom_context->bios + data_offset +
> >> +                      le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
> >> +                      (power_state->v1.ucNonClockStateIndex *
> >> +                       power_info->pplib.ucNonClockSize));
> >> +             if (power_info->pplib.ucStateEntrySize - 1) {
> >> +                     clock_info = (union pplib_clock_info *)
> >> +                             (mode_info->atom_context->bios + data_offset +
> >> +                              le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
> >> +                              (power_state->v1.ucClockStateIndices[0] *
> >> +                               power_info->pplib.ucClockInfoSize));
> >> +                     ps = kzalloc(sizeof(struct igp_ps), GFP_KERNEL);
> >> +                     if (ps == NULL) {
> >> +                             kfree(rdev->pm.dpm.ps);
> >> +                             return -ENOMEM;
> >> +                     }
> >> +                     rdev->pm.dpm.ps[i].ps_priv = ps;
> >> +                     rs780_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
> >> +                                                      non_clock_info,
> >> +                                                      power_info->pplib.ucNonClockSize);
> >> +                     rs780_parse_pplib_clock_info(rdev,
> >> +                                                  &rdev->pm.dpm.ps[i],
> >> +                                                  clock_info);
> >> +             }
> >> +     }
> >> +     rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates;
> >> +     return 0;
> >> +}
> >> +
> >> +int rs780_dpm_init(struct radeon_device *rdev)
> >> +{
> >> +     struct igp_power_info *pi;
> >> +     int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
> >> +     union igp_info *info;
> >> +     u16 data_offset;
> >> +     u8 frev, crev;
> >> +     int ret;
> >> +
> >> +     pi = kzalloc(sizeof(struct igp_power_info), GFP_KERNEL);
> >> +     if (pi == NULL)
> >> +             return -ENOMEM;
> >> +     rdev->pm.dpm.priv = pi;
> >> +
> >> +     ret = rs780_parse_power_table(rdev);
> >> +     if (ret)
> >> +             return ret;
> >> +
> >> +     pi->voltage_control = false;
> >> +     pi->gfx_clock_gating = true;
> >> +
> >> +     if (atom_parse_data_header(rdev->mode_info.atom_context, index, NULL,
> >> +                                &frev, &crev, &data_offset)) {
> >> +             info = (union igp_info *)(rdev->mode_info.atom_context->bios + data_offset);
> >> +
> >> +             /* Get various system informations from bios */
> >> +             switch (crev) {
> >> +             case 1:
> >> +                     pi->num_of_cycles_in_period =
> >> +                             info->info.ucNumberOfCyclesInPeriod;
> >> +                     pi->num_of_cycles_in_period |=
> >> +                             info->info.ucNumberOfCyclesInPeriodHi << 8;
> >> +                     pi->invert_pwm_required =
> >> +                             (pi->num_of_cycles_in_period & 0x8000) ? true : false;
> >> +                     pi->boot_voltage = info->info.ucStartingPWM_HighTime;
> >> +                     pi->max_voltage = info->info.ucMaxNBVoltage;
> >> +                     pi->max_voltage |= info->info.ucMaxNBVoltageHigh << 8;
> >> +                     pi->min_voltage = info->info.ucMinNBVoltage;
> >> +                     pi->min_voltage |= info->info.ucMinNBVoltageHigh << 8;
> >> +                     pi->inter_voltage_low =
> >> +                             le16_to_cpu(info->info.usInterNBVoltageLow);
> >> +                     pi->inter_voltage_high =
> >> +                             le16_to_cpu(info->info.usInterNBVoltageHigh);
> >> +                     pi->voltage_control = true;
> >> +                     pi->bootup_uma_clk = info->info.usK8MemoryClock * 100;
> >> +                     break;
> >> +             case 2:
> >> +                     pi->num_of_cycles_in_period =
> >> +                             le16_to_cpu(info->info_2.usNumberOfCyclesInPeriod);
> >> +                     pi->invert_pwm_required =
> >> +                             (pi->num_of_cycles_in_period & 0x8000) ? true : false;
> >> +                     pi->boot_voltage =
> >> +                             le16_to_cpu(info->info_2.usBootUpNBVoltage);
> >> +                     pi->max_voltage =
> >> +                             le16_to_cpu(info->info_2.usMaxNBVoltage);
> >> +                     pi->min_voltage =
> >> +                             le16_to_cpu(info->info_2.usMinNBVoltage);
> >> +                     pi->system_config =
> >> +                             le32_to_cpu(info->info_2.ulSystemConfig);
> >> +                     pi->pwm_voltage_control =
> >> +                             (pi->system_config & 0x4) ? true : false;
> >> +                     pi->voltage_control = true;
> >> +                     pi->bootup_uma_clk = le32_to_cpu(info->info_2.ulBootUpUMAClock);
> >> +                     break;
> >> +             default:
> >> +                     DRM_ERROR("No integrated system info for your GPU\n");
> >> +                     return -EINVAL;
> >> +             }
> >> +             if (pi->min_voltage > pi->max_voltage)
> >> +                     pi->voltage_control = false;
> >> +             if (pi->pwm_voltage_control) {
> >> +                     if ((pi->num_of_cycles_in_period == 0) ||
> >> +                         (pi->max_voltage == 0) ||
> >> +                         (pi->min_voltage == 0))
> >> +                             pi->voltage_control = false;
> >> +             } else {
> >> +                     if ((pi->num_of_cycles_in_period == 0) ||
> >> +                         (pi->max_voltage == 0))
> >> +                             pi->voltage_control = false;
> >> +             }
> >> +
> >> +             return 0;
> >> +     }
> >> +     radeon_dpm_fini(rdev);
> >> +     return -EINVAL;
> >> +}
> >> +
> >> +void rs780_dpm_print_power_state(struct radeon_device *rdev,
> >> +                              struct radeon_ps *rps)
> >> +{
> >> +     struct igp_ps *ps = rs780_get_ps(rps);
> >> +
> >> +     r600_dpm_print_class_info(rps->class, rps->class2);
> >> +     r600_dpm_print_cap_info(rps->caps);
> >> +     printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
> >> +     printk("\t\tpower level 0    sclk: %u vddc_index: %d\n",
> >> +            ps->sclk_low, ps->min_voltage);
> >> +     printk("\t\tpower level 1    sclk: %u vddc_index: %d\n",
> >> +            ps->sclk_high, ps->max_voltage);
> >> +     r600_dpm_print_ps_status(rdev, rps);
> >> +}
> >> +
> >> +void rs780_dpm_fini(struct radeon_device *rdev)
> >> +{
> >> +     int i;
> >> +
> >> +     for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
> >> +             kfree(rdev->pm.dpm.ps[i].ps_priv);
> >> +     }
> >> +     kfree(rdev->pm.dpm.ps);
> >> +     kfree(rdev->pm.dpm.priv);
> >> +}
> >> +
> >> +u32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low)
> >> +{
> >> +     struct igp_ps *requested_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
> >> +
> >> +     if (low)
> >> +             return requested_state->sclk_low;
> >> +     else
> >> +             return requested_state->sclk_high;
> >> +}
> >> +
> >> +u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low)
> >> +{
> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
> >> +
> >> +     return pi->bootup_uma_clk;
> >> +}
> >> diff --git a/drivers/gpu/drm/radeon/rs780_dpm.h b/drivers/gpu/drm/radeon/rs780_dpm.h
> >> new file mode 100644
> >> index 0000000..47a40b1
> >> --- /dev/null
> >> +++ b/drivers/gpu/drm/radeon/rs780_dpm.h
> >> @@ -0,0 +1,109 @@
> >> +/*
> >> + * Copyright 2011 Advanced Micro Devices, Inc.
> >> + *
> >> + * Permission is hereby granted, free of charge, to any person obtaining a
> >> + * copy of this software and associated documentation files (the "Software"),
> >> + * to deal in the Software without restriction, including without limitation
> >> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> >> + * and/or sell copies of the Software, and to permit persons to whom the
> >> + * Software is furnished to do so, subject to the following conditions:
> >> + *
> >> + * The above copyright notice and this permission notice shall be included in
> >> + * all copies or substantial portions of the Software.
> >> + *
> >> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> >> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> >> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> >> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> >> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> >> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> >> + * OTHER DEALINGS IN THE SOFTWARE.
> >> + *
> >> + */
> >> +#ifndef __RS780_DPM_H__
> >> +#define __RS780_DPM_H__
> >> +
> >> +enum rs780_vddc_level {
> >> +     RS780_VDDC_LEVEL_UNKNOWN = 0,
> >> +     RS780_VDDC_LEVEL_LOW = 1,
> >> +     RS780_VDDC_LEVEL_HIGH = 2,
> >> +};
> >> +
> >> +struct igp_power_info {
> >> +     /* flags */
> >> +     bool invert_pwm_required;
> >> +     bool pwm_voltage_control;
> >> +     bool voltage_control;
> >> +     bool gfx_clock_gating;
> >> +     /* stored values */
> >> +     u32 system_config;
> >> +     u32 bootup_uma_clk;
> >> +     u16 max_voltage;
> >> +     u16 min_voltage;
> >> +     u16 boot_voltage;
> >> +     u16 inter_voltage_low;
> >> +     u16 inter_voltage_high;
> >> +     u16 num_of_cycles_in_period;
> >> +     /* variable */
> >> +     int crtc_id;
> >> +     int refresh_rate;
> >> +};
> >> +
> >> +struct igp_ps {
> >> +     enum rs780_vddc_level min_voltage;
> >> +     enum rs780_vddc_level max_voltage;
> >> +     u32 sclk_low;
> >> +     u32 sclk_high;
> >> +     u32 flags;
> >> +};
> >> +
> >> +#define RS780_CGFTV_DFLT                 0x0303000f
> >> +#define RS780_FBDIVTIMERVAL_DFLT         0x2710
> >> +
> >> +#define RS780_FVTHROTUTC0_DFLT   0x04010040
> >> +#define RS780_FVTHROTUTC1_DFLT   0x04010040
> >> +#define RS780_FVTHROTUTC2_DFLT   0x04010040
> >> +#define RS780_FVTHROTUTC3_DFLT   0x04010040
> >> +#define RS780_FVTHROTUTC4_DFLT   0x04010040
> >> +
> >> +#define RS780_FVTHROTDTC0_DFLT 0x04010040
> >> +#define RS780_FVTHROTDTC1_DFLT 0x04010040
> >> +#define RS780_FVTHROTDTC2_DFLT 0x04010040
> >> +#define RS780_FVTHROTDTC3_DFLT 0x04010040
> >> +#define RS780_FVTHROTDTC4_DFLT 0x04010040
> >> +
> >> +#define RS780_FVTHROTFBUSREG0_DFLT       0x00001001
> >> +#define RS780_FVTHROTFBUSREG1_DFLT       0x00002002
> >> +#define RS780_FVTHROTFBDSREG0_DFLT       0x00004001
> >> +#define RS780_FVTHROTFBDSREG1_DFLT       0x00020010
> >> +
> >> +#define RS780_FVTHROTPWMUSREG0_DFLT      0x00002001
> >> +#define RS780_FVTHROTPWMUSREG1_DFLT      0x00004003
> >> +#define RS780_FVTHROTPWMDSREG0_DFLT      0x00002001
> >> +#define RS780_FVTHROTPWMDSREG1_DFLT      0x00004003
> >> +
> >> +#define RS780_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x37
> >> +#define RS780_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x4b
> >> +#define RS780_FVTHROTPWMFBDIVRANGEREG2_DFLT  0x8b
> >> +
> >> +#define RS780D_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x8b
> >> +#define RS780D_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x8c
> >> +#define RS780D_FVTHROTPWMFBDIVRANGEREG2_DFLT  0xb5
> >> +
> >> +#define RS880D_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x8d
> >> +#define RS880D_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x8e
> >> +#define RS880D_FVTHROTPWMFBDIVRANGEREG2_DFLT  0xBa
> >> +
> >> +#define RS780_FVTHROTPWMRANGE0_GPIO_DFLT  0x1a
> >> +#define RS780_FVTHROTPWMRANGE1_GPIO_DFLT  0x1a
> >> +#define RS780_FVTHROTPWMRANGE2_GPIO_DFLT  0x0
> >> +#define RS780_FVTHROTPWMRANGE3_GPIO_DFLT  0x0
> >> +
> >> +#define RS780_SLOWCLKFEEDBACKDIV_DFLT 110
> >> +
> >> +#define RS780_CGCLKGATING_DFLT           0x0000E204
> >> +
> >> +#define RS780_DEFAULT_VCLK_FREQ  53300 /* 10 khz */
> >> +#define RS780_DEFAULT_DCLK_FREQ  40000 /* 10 khz */
> >> +
> >> +#endif
> >> diff --git a/drivers/gpu/drm/radeon/rs780d.h b/drivers/gpu/drm/radeon/rs780d.h
> >> new file mode 100644
> >> index 0000000..b1142ed
> >> --- /dev/null
> >> +++ b/drivers/gpu/drm/radeon/rs780d.h
> >> @@ -0,0 +1,168 @@
> >> +/*
> >> + * Copyright 2011 Advanced Micro Devices, Inc.
> >> + *
> >> + * Permission is hereby granted, free of charge, to any person obtaining a
> >> + * copy of this software and associated documentation files (the "Software"),
> >> + * to deal in the Software without restriction, including without limitation
> >> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> >> + * and/or sell copies of the Software, and to permit persons to whom the
> >> + * Software is furnished to do so, subject to the following conditions:
> >> + *
> >> + * The above copyright notice and this permission notice shall be included in
> >> + * all copies or substantial portions of the Software.
> >> + *
> >> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> >> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> >> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> >> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> >> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> >> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> >> + * OTHER DEALINGS IN THE SOFTWARE.
> >> + *
> >> + */
> >> +#ifndef __RS780D_H__
> >> +#define __RS780D_H__
> >> +
> >> +#define CG_SPLL_FUNC_CNTL                                 0x600
> >> +#       define SPLL_RESET                                (1 << 0)
> >> +#       define SPLL_SLEEP                                (1 << 1)
> >> +#       define SPLL_REF_DIV(x)                           ((x) << 2)
> >> +#       define SPLL_REF_DIV_MASK                         (7 << 2)
> >> +#       define SPLL_FB_DIV(x)                            ((x) << 5)
> >> +#       define SPLL_FB_DIV_MASK                          (0xff << 2)
> >> +#       define SPLL_FB_DIV_SHIFT                         2
> >> +#       define SPLL_PULSEEN                              (1 << 13)
> >> +#       define SPLL_PULSENUM(x)                          ((x) << 14)
> >> +#       define SPLL_PULSENUM_MASK                        (3 << 14)
> >> +#       define SPLL_SW_HILEN(x)                          ((x) << 16)
> >> +#       define SPLL_SW_HILEN_MASK                        (0xf << 16)
> >> +#       define SPLL_SW_LOLEN(x)                          ((x) << 20)
> >> +#       define SPLL_SW_LOLEN_MASK                        (0xf << 20)
> >> +#       define SPLL_DIVEN                                (1 << 24)
> >> +#       define SPLL_BYPASS_EN                            (1 << 25)
> >> +#       define SPLL_CHG_STATUS                           (1 << 29)
> >> +#       define SPLL_CTLREQ                               (1 << 30)
> >> +#       define SPLL_CTLACK                               (1 << 31)
> >> +
> >> +/* RS780/RS880 PM */
> >> +#define      FVTHROT_CNTRL_REG                               0x3000
> >> +#define              DONT_WAIT_FOR_FBDIV_WRAP                (1 << 0)
> >> +#define              MINIMUM_CIP(x)                          ((x) << 1)
> >> +#define              MINIMUM_CIP_SHIFT                       1
> >> +#define              MINIMUM_CIP_MASK                        0x1fffffe
> >> +#define              REFRESH_RATE_DIVISOR(x)                 ((x) << 25)
> >> +#define              REFRESH_RATE_DIVISOR_SHIFT              25
> >> +#define              REFRESH_RATE_DIVISOR_MASK               (0x3 << 25)
> >> +#define              ENABLE_FV_THROT                         (1 << 27)
> >> +#define              ENABLE_FV_UPDATE                        (1 << 28)
> >> +#define              TREND_SEL_MODE                          (1 << 29)
> >> +#define              FORCE_TREND_SEL                         (1 << 30)
> >> +#define              ENABLE_FV_THROT_IO                      (1 << 31)
> >> +#define      FVTHROT_TARGET_REG                              0x3004
> >> +#define              TARGET_IDLE_COUNT(x)                    ((x) << 0)
> >> +#define              TARGET_IDLE_COUNT_MASK                  0xffffff
> >> +#define              TARGET_IDLE_COUNT_SHIFT                 0
> >> +#define      FVTHROT_CB1                                     0x3008
> >> +#define      FVTHROT_CB2                                     0x300c
> >> +#define      FVTHROT_CB3                                     0x3010
> >> +#define      FVTHROT_CB4                                     0x3014
> >> +#define      FVTHROT_UTC0                                    0x3018
> >> +#define      FVTHROT_UTC1                                    0x301c
> >> +#define      FVTHROT_UTC2                                    0x3020
> >> +#define      FVTHROT_UTC3                                    0x3024
> >> +#define      FVTHROT_UTC4                                    0x3028
> >> +#define      FVTHROT_DTC0                                    0x302c
> >> +#define      FVTHROT_DTC1                                    0x3030
> >> +#define      FVTHROT_DTC2                                    0x3034
> >> +#define      FVTHROT_DTC3                                    0x3038
> >> +#define      FVTHROT_DTC4                                    0x303c
> >> +#define      FVTHROT_FBDIV_REG0                              0x3040
> >> +#define              MIN_FEEDBACK_DIV(x)                     ((x) << 0)
> >> +#define              MIN_FEEDBACK_DIV_MASK                   0xfff
> >> +#define              MIN_FEEDBACK_DIV_SHIFT                  0
> >> +#define              MAX_FEEDBACK_DIV(x)                     ((x) << 12)
> >> +#define              MAX_FEEDBACK_DIV_MASK                   (0xfff << 12)
> >> +#define              MAX_FEEDBACK_DIV_SHIFT                  12
> >> +#define      FVTHROT_FBDIV_REG1                              0x3044
> >> +#define              MAX_FEEDBACK_STEP(x)                    ((x) << 0)
> >> +#define              MAX_FEEDBACK_STEP_MASK                  0xfff
> >> +#define              MAX_FEEDBACK_STEP_SHIFT                 0
> >> +#define              STARTING_FEEDBACK_DIV(x)                ((x) << 12)
> >> +#define              STARTING_FEEDBACK_DIV_MASK              (0xfff << 12)
> >> +#define              STARTING_FEEDBACK_DIV_SHIFT             12
> >> +#define              FORCE_FEEDBACK_DIV                      (1 << 24)
> >> +#define      FVTHROT_FBDIV_REG2                              0x3048
> >> +#define              FORCED_FEEDBACK_DIV(x)                  ((x) << 0)
> >> +#define              FORCED_FEEDBACK_DIV_MASK                0xfff
> >> +#define              FORCED_FEEDBACK_DIV_SHIFT               0
> >> +#define              FB_DIV_TIMER_VAL(x)                     ((x) << 12)
> >> +#define              FB_DIV_TIMER_VAL_MASK                   (0xffff << 12)
> >> +#define              FB_DIV_TIMER_VAL_SHIFT                  12
> >> +#define      FVTHROT_FB_US_REG0                              0x304c
> >> +#define      FVTHROT_FB_US_REG1                              0x3050
> >> +#define      FVTHROT_FB_DS_REG0                              0x3054
> >> +#define      FVTHROT_FB_DS_REG1                              0x3058
> >> +#define      FVTHROT_PWM_CTRL_REG0                           0x305c
> >> +#define              STARTING_PWM_HIGHTIME(x)                ((x) << 0)
> >> +#define              STARTING_PWM_HIGHTIME_MASK              0xfff
> >> +#define              STARTING_PWM_HIGHTIME_SHIFT             0
> >> +#define              NUMBER_OF_CYCLES_IN_PERIOD(x)           ((x) << 12)
> >> +#define              NUMBER_OF_CYCLES_IN_PERIOD_MASK         (0xfff << 12)
> >> +#define              NUMBER_OF_CYCLES_IN_PERIOD_SHIFT        12
> >> +#define              FORCE_STARTING_PWM_HIGHTIME             (1 << 24)
> >> +#define              INVERT_PWM_WAVEFORM                     (1 << 25)
> >> +#define      FVTHROT_PWM_CTRL_REG1                           0x3060
> >> +#define              MIN_PWM_HIGHTIME(x)                     ((x) << 0)
> >> +#define              MIN_PWM_HIGHTIME_MASK                   0xfff
> >> +#define              MIN_PWM_HIGHTIME_SHIFT                  0
> >> +#define              MAX_PWM_HIGHTIME(x)                     ((x) << 12)
> >> +#define              MAX_PWM_HIGHTIME_MASK                   (0xfff << 12)
> >> +#define              MAX_PWM_HIGHTIME_SHIFT                  12
> >> +#define      FVTHROT_PWM_US_REG0                             0x3064
> >> +#define      FVTHROT_PWM_US_REG1                             0x3068
> >> +#define      FVTHROT_PWM_DS_REG0                             0x306c
> >> +#define      FVTHROT_PWM_DS_REG1                             0x3070
> >> +#define      FVTHROT_STATUS_REG0                             0x3074
> >> +#define              CURRENT_FEEDBACK_DIV_MASK               0xfff
> >> +#define              CURRENT_FEEDBACK_DIV_SHIFT              0
> >> +#define      FVTHROT_STATUS_REG1                             0x3078
> >> +#define      FVTHROT_STATUS_REG2                             0x307c
> >> +#define      CG_INTGFX_MISC                                  0x3080
> >> +#define              FVTHROT_VBLANK_SEL                      (1 << 9)
> >> +#define      FVTHROT_PWM_FEEDBACK_DIV_REG1                   0x308c
> >> +#define              RANGE0_PWM_FEEDBACK_DIV(x)              ((x) << 0)
> >> +#define              RANGE0_PWM_FEEDBACK_DIV_MASK            0xfff
> >> +#define              RANGE0_PWM_FEEDBACK_DIV_SHIFT           0
> >> +#define              RANGE_PWM_FEEDBACK_DIV_EN               (1 << 12)
> >> +#define      FVTHROT_PWM_FEEDBACK_DIV_REG2                   0x3090
> >> +#define              RANGE1_PWM_FEEDBACK_DIV(x)              ((x) << 0)
> >> +#define              RANGE1_PWM_FEEDBACK_DIV_MASK            0xfff
> >> +#define              RANGE1_PWM_FEEDBACK_DIV_SHIFT           0
> >> +#define              RANGE2_PWM_FEEDBACK_DIV(x)              ((x) << 12)
> >> +#define              RANGE2_PWM_FEEDBACK_DIV_MASK            (0xfff << 12)
> >> +#define              RANGE2_PWM_FEEDBACK_DIV_SHIFT           12
> >> +#define      FVTHROT_PWM_FEEDBACK_DIV_REG3                   0x3094
> >> +#define              RANGE0_PWM(x)                           ((x) << 0)
> >> +#define              RANGE0_PWM_MASK                         0xfff
> >> +#define              RANGE0_PWM_SHIFT                        0
> >> +#define              RANGE1_PWM(x)                           ((x) << 12)
> >> +#define              RANGE1_PWM_MASK                         (0xfff << 12)
> >> +#define              RANGE1_PWM_SHIFT                        12
> >> +#define      FVTHROT_PWM_FEEDBACK_DIV_REG4                   0x3098
> >> +#define              RANGE2_PWM(x)                           ((x) << 0)
> >> +#define              RANGE2_PWM_MASK                         0xfff
> >> +#define              RANGE2_PWM_SHIFT                        0
> >> +#define              RANGE3_PWM(x)                           ((x) << 12)
> >> +#define              RANGE3_PWM_MASK                         (0xfff << 12)
> >> +#define              RANGE3_PWM_SHIFT                        12
> >> +#define      FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1              0x30ac
> >> +#define              RANGE0_SLOW_CLK_FEEDBACK_DIV(x)         ((x) << 0)
> >> +#define              RANGE0_SLOW_CLK_FEEDBACK_DIV_MASK       0xfff
> >> +#define              RANGE0_SLOW_CLK_FEEDBACK_DIV_SHIFT      0
> >> +#define              RANGE_SLOW_CLK_FEEDBACK_DIV_EN          (1 << 12)
> >> +
> >> +#define      GFX_MACRO_BYPASS_CNTL                           0x30c0
> >> +#define              SPLL_BYPASS_CNTL                        (1 << 0)
> >> +#define              UPLL_BYPASS_CNTL                        (1 << 1)
> >> +
> >> +#endif
> >> --
> >> 1.7.7.5
> >>
> >> _______________________________________________
> >> dri-devel mailing list
> >> dri-devel@lists.freedesktop.org
> >> http://lists.freedesktop.org/mailman/listinfo/dri-devel
Alex Deucher June 26, 2013, 6:19 p.m. UTC | #3
On Wed, Jun 26, 2013 at 6:46 AM, Jerome Glisse <j.glisse@gmail.com> wrote:
> On Wed, Jun 26, 2013 at 09:22:35AM -0400, alexdeucher@gmail.com wrote:
>> From: Alex Deucher <alexander.deucher@amd.com>
>>
>> This adds dpm support for rs780/rs880 asics.  This includes:
>> - clockgating
>> - dynamic engine clock scaling
>> - dynamic voltage scaling
>>
>> set radeon.dpm=1 to enable it.
>>
>> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
>
> Depending on the answer to inline question :
>
> Reviewed-by: Jerome Glisse <jglisse@redhat.com>
>
>> ---
>>  drivers/gpu/drm/radeon/Makefile      |    2 +-
>>  drivers/gpu/drm/radeon/radeon_asic.c |   12 +
>>  drivers/gpu/drm/radeon/radeon_asic.h |   12 +
>>  drivers/gpu/drm/radeon/radeon_pm.c   |    7 +
>>  drivers/gpu/drm/radeon/rs780_dpm.c   |  894 ++++++++++++++++++++++++++++++++++
>>  drivers/gpu/drm/radeon/rs780_dpm.h   |  109 ++++
>>  drivers/gpu/drm/radeon/rs780d.h      |  168 +++++++
>>  7 files changed, 1203 insertions(+), 1 deletions(-)
>>  create mode 100644 drivers/gpu/drm/radeon/rs780_dpm.c
>>  create mode 100644 drivers/gpu/drm/radeon/rs780_dpm.h
>>  create mode 100644 drivers/gpu/drm/radeon/rs780d.h
>>
>> diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
>> index a131a13..e44b046 100644
>> --- a/drivers/gpu/drm/radeon/Makefile
>> +++ b/drivers/gpu/drm/radeon/Makefile
>> @@ -77,7 +77,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
>>       evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \
>>       atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
>>       si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \
>> -     r600_dpm.o
>> +     r600_dpm.o rs780_dpm.o
>>
>>  radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
>>  radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
>> diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
>> index d9c8e9a..db3c930 100644
>> --- a/drivers/gpu/drm/radeon/radeon_asic.c
>> +++ b/drivers/gpu/drm/radeon/radeon_asic.c
>> @@ -1194,6 +1194,18 @@ static struct radeon_asic rs780_asic = {
>>               .set_clock_gating = NULL,
>>               .get_temperature = &rv6xx_get_temp,
>>       },
>> +     .dpm = {
>> +             .init = &rs780_dpm_init,
>> +             .setup_asic = &rs780_dpm_setup_asic,
>> +             .enable = &rs780_dpm_enable,
>> +             .disable = &rs780_dpm_disable,
>> +             .set_power_state = &rs780_dpm_set_power_state,
>> +             .display_configuration_changed = &rs780_dpm_display_configuration_changed,
>> +             .fini = &rs780_dpm_fini,
>> +             .get_sclk = &rs780_dpm_get_sclk,
>> +             .get_mclk = &rs780_dpm_get_mclk,
>> +             .print_power_state = &rs780_dpm_print_power_state,
>> +     },
>>       .pflip = {
>>               .pre_page_flip = &rs600_pre_page_flip,
>>               .page_flip = &rs600_page_flip,
>> diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
>> index 8507cae..134bf57 100644
>> --- a/drivers/gpu/drm/radeon/radeon_asic.h
>> +++ b/drivers/gpu/drm/radeon/radeon_asic.h
>> @@ -396,6 +396,18 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev);
>>  u32 r600_get_xclk(struct radeon_device *rdev);
>>  uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev);
>>  int rv6xx_get_temp(struct radeon_device *rdev);
>> +/* rs780 dpm */
>> +int rs780_dpm_init(struct radeon_device *rdev);
>> +int rs780_dpm_enable(struct radeon_device *rdev);
>> +void rs780_dpm_disable(struct radeon_device *rdev);
>> +int rs780_dpm_set_power_state(struct radeon_device *rdev);
>> +void rs780_dpm_setup_asic(struct radeon_device *rdev);
>> +void rs780_dpm_display_configuration_changed(struct radeon_device *rdev);
>> +void rs780_dpm_fini(struct radeon_device *rdev);
>> +u32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low);
>> +u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low);
>> +void rs780_dpm_print_power_state(struct radeon_device *rdev,
>> +                              struct radeon_ps *ps);
>>
>>  /* uvd */
>>  int r600_uvd_init(struct radeon_device *rdev);
>> diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
>> index 4f5422e..853a8a2 100644
>> --- a/drivers/gpu/drm/radeon/radeon_pm.c
>> +++ b/drivers/gpu/drm/radeon/radeon_pm.c
>> @@ -1030,6 +1030,13 @@ int radeon_pm_init(struct radeon_device *rdev)
>>  {
>>       /* enable dpm on rv6xx+ */
>>       switch (rdev->family) {
>> +     case CHIP_RS780:
>> +     case CHIP_RS880:
>> +             if (radeon_dpm == 1)
>> +                     rdev->pm.pm_method = PM_METHOD_DPM;
>> +             else
>> +                     rdev->pm.pm_method = PM_METHOD_PROFILE;
>> +             break;
>>       default:
>>               /* default to profile method */
>>               rdev->pm.pm_method = PM_METHOD_PROFILE;
>> diff --git a/drivers/gpu/drm/radeon/rs780_dpm.c b/drivers/gpu/drm/radeon/rs780_dpm.c
>> new file mode 100644
>> index 0000000..f594900
>> --- /dev/null
>> +++ b/drivers/gpu/drm/radeon/rs780_dpm.c
>> @@ -0,0 +1,894 @@
>> +/*
>> + * Copyright 2011 Advanced Micro Devices, Inc.
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a
>> + * copy of this software and associated documentation files (the "Software"),
>> + * to deal in the Software without restriction, including without limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice shall be included in
>> + * all copies or substantial portions of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
>> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>> + * OTHER DEALINGS IN THE SOFTWARE.
>> + *
>> + * Authors: Alex Deucher
>> + */
>> +
>> +#include "drmP.h"
>> +#include "radeon.h"
>> +#include "rs780d.h"
>> +#include "r600_dpm.h"
>> +#include "rs780_dpm.h"
>> +#include "atom.h"
>> +
>> +static struct igp_ps *rs780_get_ps(struct radeon_ps *rps)
>> +{
>> +     struct igp_ps *ps = rps->ps_priv;
>> +
>> +     return ps;
>> +}
>> +
>> +static struct igp_power_info *rs780_get_pi(struct radeon_device *rdev)
>> +{
>> +     struct igp_power_info *pi = rdev->pm.dpm.priv;
>> +
>> +     return pi;
>> +}
>> +
>> +static void rs780_get_pm_mode_parameters(struct radeon_device *rdev)
>> +{
>> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> +     struct radeon_mode_info *minfo = &rdev->mode_info;
>> +     struct drm_crtc *crtc;
>> +     struct radeon_crtc *radeon_crtc;
>> +     int i;
>> +
>> +     /* defaults */
>> +     pi->crtc_id = 0;
>> +     pi->refresh_rate = 60;
>> +
>> +     for (i = 0; i < rdev->num_crtc; i++) {
>> +             crtc = (struct drm_crtc *)minfo->crtcs[i];
>> +             if (crtc && crtc->enabled) {
>> +                     radeon_crtc = to_radeon_crtc(crtc);
>> +                     pi->crtc_id = radeon_crtc->crtc_id;
>> +                     if (crtc->mode.htotal && crtc->mode.vtotal)
>> +                             pi->refresh_rate =
>> +                                     (crtc->mode.clock * 1000) /
>> +                                     (crtc->mode.htotal * crtc->mode.vtotal);
>> +                     break;
>> +             }
>> +     }
>
> Ok this looks wrong to me you look for the first enabled crtc but on those iirc
> there could be 2 so first one might be a low refresh rate and second one an higher
> one. Thus returning the first one might lead to PM decision that are wrong.
>

On RS780/RS880, the hardware can only synchronize with a single crtc,
so it doesn't really matter which one we pick as long as it's active.


>> +}
>> +
>> +static void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable);
>> +
>> +static int rs780_initialize_dpm_power_state(struct radeon_device *rdev)
>> +{
>> +     struct atom_clock_dividers dividers;
>> +     struct igp_ps *default_state = rs780_get_ps(rdev->pm.dpm.boot_ps);
>> +     int i, ret;
>> +
>> +     ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
>> +                                          default_state->sclk_low, false, &dividers);
>> +     if (ret)
>> +             return ret;
>> +
>> +     r600_engine_clock_entry_set_reference_divider(rdev, 0, dividers.ref_div);
>> +     r600_engine_clock_entry_set_feedback_divider(rdev, 0, dividers.fb_div);
>> +     r600_engine_clock_entry_set_post_divider(rdev, 0, dividers.post_div);
>> +
>> +     if (dividers.enable_post_div)
>> +             r600_engine_clock_entry_enable_post_divider(rdev, 0, true);
>> +     else
>> +             r600_engine_clock_entry_enable_post_divider(rdev, 0, false);
>> +
>> +     r600_engine_clock_entry_set_step_time(rdev, 0, R600_SST_DFLT);
>> +     r600_engine_clock_entry_enable_pulse_skipping(rdev, 0, false);
>> +
>> +     r600_engine_clock_entry_enable(rdev, 0, true);
>> +     for (i = 1; i < R600_PM_NUMBER_OF_SCLKS; i++)
>> +             r600_engine_clock_entry_enable(rdev, i, false);
>> +
>> +     r600_enable_mclk_control(rdev, false);
>> +     r600_voltage_control_enable_pins(rdev, 0);
>> +
>> +     return 0;
>> +}
>> +
>> +static int rs780_initialize_dpm_parameters(struct radeon_device *rdev)
>> +{
>> +     int ret = 0;
>> +     int i;
>> +
>> +     r600_set_bsp(rdev, R600_BSU_DFLT, R600_BSP_DFLT);
>> +
>> +     r600_set_at(rdev, 0, 0, 0, 0);
>> +
>> +     r600_set_git(rdev, R600_GICST_DFLT);
>> +
>> +     for (i = 0; i < R600_PM_NUMBER_OF_TC; i++)
>> +             r600_set_tc(rdev, i, 0, 0);
>> +
>> +     r600_select_td(rdev, R600_TD_DFLT);
>> +     r600_set_vrc(rdev, 0);
>> +
>> +     r600_set_tpu(rdev, R600_TPU_DFLT);
>> +     r600_set_tpc(rdev, R600_TPC_DFLT);
>> +
>> +     r600_set_sstu(rdev, R600_SSTU_DFLT);
>> +     r600_set_sst(rdev, R600_SST_DFLT);
>> +
>> +     r600_set_fctu(rdev, R600_FCTU_DFLT);
>> +     r600_set_fct(rdev, R600_FCT_DFLT);
>> +
>> +     r600_set_vddc3d_oorsu(rdev, R600_VDDC3DOORSU_DFLT);
>> +     r600_set_vddc3d_oorphc(rdev, R600_VDDC3DOORPHC_DFLT);
>> +     r600_set_vddc3d_oorsdc(rdev, R600_VDDC3DOORSDC_DFLT);
>> +     r600_set_ctxcgtt3d_rphc(rdev, R600_CTXCGTT3DRPHC_DFLT);
>> +     r600_set_ctxcgtt3d_rsdc(rdev, R600_CTXCGTT3DRSDC_DFLT);
>> +
>> +     r600_vid_rt_set_vru(rdev, R600_VRU_DFLT);
>> +     r600_vid_rt_set_vrt(rdev, R600_VOLTAGERESPONSETIME_DFLT);
>> +     r600_vid_rt_set_ssu(rdev, R600_SPLLSTEPUNIT_DFLT);
>> +
>> +     ret = rs780_initialize_dpm_power_state(rdev);
>> +
>> +     r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW,     0);
>> +     r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM,  0);
>> +     r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_HIGH,    0);
>> +
>> +     r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW,    0);
>> +     r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
>> +     r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_HIGH,   0);
>> +
>> +     r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW,    0);
>> +     r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
>> +     r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_HIGH,   0);
>> +
>> +     r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW,    R600_DISPLAY_WATERMARK_HIGH);
>> +     r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM, R600_DISPLAY_WATERMARK_HIGH);
>> +     r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_HIGH,   R600_DISPLAY_WATERMARK_HIGH);
>> +
>> +     r600_power_level_enable(rdev, R600_POWER_LEVEL_CTXSW, false);
>> +     r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false);
>> +     r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false);
>> +     r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
>> +
>> +     r600_power_level_set_enter_index(rdev, R600_POWER_LEVEL_LOW);
>> +
>> +     r600_set_vrc(rdev, RS780_CGFTV_DFLT);
>> +
>> +     return ret;
>> +}
>> +
>> +static void rs780_start_dpm(struct radeon_device *rdev)
>> +{
>> +     r600_enable_sclk_control(rdev, false);
>> +     r600_enable_mclk_control(rdev, false);
>> +
>> +     r600_dynamicpm_enable(rdev, true);
>> +
>> +     radeon_wait_for_vblank(rdev, 0);
>> +     radeon_wait_for_vblank(rdev, 1);
>> +
>> +     r600_enable_spll_bypass(rdev, true);
>> +     r600_wait_for_spll_change(rdev);
>> +     r600_enable_spll_bypass(rdev, false);
>> +     r600_wait_for_spll_change(rdev);
>> +
>> +     r600_enable_spll_bypass(rdev, true);
>> +     r600_wait_for_spll_change(rdev);
>> +     r600_enable_spll_bypass(rdev, false);
>> +     r600_wait_for_spll_change(rdev);
>> +
>> +     r600_enable_sclk_control(rdev, true);
>> +}
>> +
>> +
>> +static void rs780_preset_ranges_slow_clk_fbdiv_en(struct radeon_device *rdev)
>> +{
>> +     WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1, RANGE_SLOW_CLK_FEEDBACK_DIV_EN,
>> +              ~RANGE_SLOW_CLK_FEEDBACK_DIV_EN);
>> +
>> +     WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1,
>> +              RANGE0_SLOW_CLK_FEEDBACK_DIV(RS780_SLOWCLKFEEDBACKDIV_DFLT),
>> +              ~RANGE0_SLOW_CLK_FEEDBACK_DIV_MASK);
>> +}
>> +
>> +static void rs780_preset_starting_fbdiv(struct radeon_device *rdev)
>> +{
>> +     u32 fbdiv = (RREG32(CG_SPLL_FUNC_CNTL) & SPLL_FB_DIV_MASK) >> SPLL_FB_DIV_SHIFT;
>> +
>> +     WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(fbdiv),
>> +              ~STARTING_FEEDBACK_DIV_MASK);
>> +
>> +     WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(fbdiv),
>> +              ~FORCED_FEEDBACK_DIV_MASK);
>> +
>> +     WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
>> +}
>> +
>> +static void rs780_voltage_scaling_init(struct radeon_device *rdev)
>> +{
>> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> +     struct drm_device *dev = rdev->ddev;
>> +     u32 fv_throt_pwm_fb_div_range[3];
>> +     u32 fv_throt_pwm_range[4];
>> +
>> +     if (dev->pdev->device == 0x9614) {
>> +             fv_throt_pwm_fb_div_range[0] = RS780D_FVTHROTPWMFBDIVRANGEREG0_DFLT;
>> +             fv_throt_pwm_fb_div_range[1] = RS780D_FVTHROTPWMFBDIVRANGEREG1_DFLT;
>> +             fv_throt_pwm_fb_div_range[2] = RS780D_FVTHROTPWMFBDIVRANGEREG2_DFLT;
>> +     } else if ((dev->pdev->device == 0x9714) ||
>> +                (dev->pdev->device == 0x9715)) {
>> +             fv_throt_pwm_fb_div_range[0] = RS880D_FVTHROTPWMFBDIVRANGEREG0_DFLT;
>> +             fv_throt_pwm_fb_div_range[1] = RS880D_FVTHROTPWMFBDIVRANGEREG1_DFLT;
>> +             fv_throt_pwm_fb_div_range[2] = RS880D_FVTHROTPWMFBDIVRANGEREG2_DFLT;
>> +     } else {
>> +             fv_throt_pwm_fb_div_range[0] = RS780_FVTHROTPWMFBDIVRANGEREG0_DFLT;
>> +             fv_throt_pwm_fb_div_range[1] = RS780_FVTHROTPWMFBDIVRANGEREG1_DFLT;
>> +             fv_throt_pwm_fb_div_range[2] = RS780_FVTHROTPWMFBDIVRANGEREG2_DFLT;
>> +     }
>> +
>> +     if (pi->pwm_voltage_control) {
>> +             fv_throt_pwm_range[0] = pi->min_voltage;
>> +             fv_throt_pwm_range[1] = pi->min_voltage;
>> +             fv_throt_pwm_range[2] = pi->max_voltage;
>> +             fv_throt_pwm_range[3] = pi->max_voltage;
>> +     } else {
>> +             fv_throt_pwm_range[0] = pi->invert_pwm_required ?
>> +                     RS780_FVTHROTPWMRANGE3_GPIO_DFLT : RS780_FVTHROTPWMRANGE0_GPIO_DFLT;
>> +             fv_throt_pwm_range[1] = pi->invert_pwm_required ?
>> +                     RS780_FVTHROTPWMRANGE2_GPIO_DFLT : RS780_FVTHROTPWMRANGE1_GPIO_DFLT;
>> +             fv_throt_pwm_range[2] = pi->invert_pwm_required ?
>> +                     RS780_FVTHROTPWMRANGE1_GPIO_DFLT : RS780_FVTHROTPWMRANGE2_GPIO_DFLT;
>> +             fv_throt_pwm_range[3] = pi->invert_pwm_required ?
>> +                     RS780_FVTHROTPWMRANGE0_GPIO_DFLT : RS780_FVTHROTPWMRANGE3_GPIO_DFLT;
>> +     }
>> +
>> +     WREG32_P(FVTHROT_PWM_CTRL_REG0,
>> +              STARTING_PWM_HIGHTIME(pi->max_voltage),
>> +              ~STARTING_PWM_HIGHTIME_MASK);
>> +
>> +     WREG32_P(FVTHROT_PWM_CTRL_REG0,
>> +              NUMBER_OF_CYCLES_IN_PERIOD(pi->num_of_cycles_in_period),
>> +              ~NUMBER_OF_CYCLES_IN_PERIOD_MASK);
>> +
>> +     WREG32_P(FVTHROT_PWM_CTRL_REG0, FORCE_STARTING_PWM_HIGHTIME,
>> +              ~FORCE_STARTING_PWM_HIGHTIME);
>> +
>> +     if (pi->invert_pwm_required)
>> +             WREG32_P(FVTHROT_PWM_CTRL_REG0, INVERT_PWM_WAVEFORM, ~INVERT_PWM_WAVEFORM);
>> +     else
>> +             WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~INVERT_PWM_WAVEFORM);
>> +
>> +     rs780_voltage_scaling_enable(rdev, true);
>> +
>> +     WREG32(FVTHROT_PWM_CTRL_REG1,
>> +            (MIN_PWM_HIGHTIME(pi->min_voltage) |
>> +             MAX_PWM_HIGHTIME(pi->max_voltage)));
>> +
>> +     WREG32(FVTHROT_PWM_US_REG0, RS780_FVTHROTPWMUSREG0_DFLT);
>> +     WREG32(FVTHROT_PWM_US_REG1, RS780_FVTHROTPWMUSREG1_DFLT);
>> +     WREG32(FVTHROT_PWM_DS_REG0, RS780_FVTHROTPWMDSREG0_DFLT);
>> +     WREG32(FVTHROT_PWM_DS_REG1, RS780_FVTHROTPWMDSREG1_DFLT);
>> +
>> +     WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1,
>> +              RANGE0_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[0]),
>> +              ~RANGE0_PWM_FEEDBACK_DIV_MASK);
>> +
>> +     WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG2,
>> +            (RANGE1_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[1]) |
>> +             RANGE2_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[2])));
>> +
>> +     WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG3,
>> +            (RANGE0_PWM(fv_throt_pwm_range[1]) |
>> +             RANGE1_PWM(fv_throt_pwm_range[2])));
>> +     WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG4,
>> +            (RANGE2_PWM(fv_throt_pwm_range[1]) |
>> +             RANGE3_PWM(fv_throt_pwm_range[2])));
>> +}
>> +
>> +static void rs780_clk_scaling_enable(struct radeon_device *rdev, bool enable)
>> +{
>> +     if (enable)
>> +             WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT | ENABLE_FV_UPDATE,
>> +                      ~(ENABLE_FV_THROT | ENABLE_FV_UPDATE));
>> +     else
>> +             WREG32_P(FVTHROT_CNTRL_REG, 0,
>> +                      ~(ENABLE_FV_THROT | ENABLE_FV_UPDATE));
>> +}
>> +
>> +static void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable)
>> +{
>> +     if (enable)
>> +             WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT_IO, ~ENABLE_FV_THROT_IO);
>> +     else
>> +             WREG32_P(FVTHROT_CNTRL_REG, 0, ~ENABLE_FV_THROT_IO);
>> +}
>> +
>> +static void rs780_set_engine_clock_wfc(struct radeon_device *rdev)
>> +{
>> +     WREG32(FVTHROT_UTC0, RS780_FVTHROTUTC0_DFLT);
>> +     WREG32(FVTHROT_UTC1, RS780_FVTHROTUTC1_DFLT);
>> +     WREG32(FVTHROT_UTC2, RS780_FVTHROTUTC2_DFLT);
>> +     WREG32(FVTHROT_UTC3, RS780_FVTHROTUTC3_DFLT);
>> +     WREG32(FVTHROT_UTC4, RS780_FVTHROTUTC4_DFLT);
>> +
>> +     WREG32(FVTHROT_DTC0, RS780_FVTHROTDTC0_DFLT);
>> +     WREG32(FVTHROT_DTC1, RS780_FVTHROTDTC1_DFLT);
>> +     WREG32(FVTHROT_DTC2, RS780_FVTHROTDTC2_DFLT);
>> +     WREG32(FVTHROT_DTC3, RS780_FVTHROTDTC3_DFLT);
>> +     WREG32(FVTHROT_DTC4, RS780_FVTHROTDTC4_DFLT);
>> +}
>> +
>> +static void rs780_set_engine_clock_sc(struct radeon_device *rdev)
>> +{
>> +     WREG32_P(FVTHROT_FBDIV_REG2,
>> +              FB_DIV_TIMER_VAL(RS780_FBDIVTIMERVAL_DFLT),
>> +              ~FB_DIV_TIMER_VAL_MASK);
>> +
>> +     WREG32_P(FVTHROT_CNTRL_REG,
>> +              REFRESH_RATE_DIVISOR(0) | MINIMUM_CIP(0xf),
>> +              ~(REFRESH_RATE_DIVISOR_MASK | MINIMUM_CIP_MASK));
>> +}
>> +
>> +static void rs780_set_engine_clock_tdc(struct radeon_device *rdev)
>> +{
>> +     WREG32_P(FVTHROT_CNTRL_REG, 0, ~(FORCE_TREND_SEL | TREND_SEL_MODE));
>> +}
>> +
>> +static void rs780_set_engine_clock_ssc(struct radeon_device *rdev)
>> +{
>> +     WREG32(FVTHROT_FB_US_REG0, RS780_FVTHROTFBUSREG0_DFLT);
>> +     WREG32(FVTHROT_FB_US_REG1, RS780_FVTHROTFBUSREG1_DFLT);
>> +     WREG32(FVTHROT_FB_DS_REG0, RS780_FVTHROTFBDSREG0_DFLT);
>> +     WREG32(FVTHROT_FB_DS_REG1, RS780_FVTHROTFBDSREG1_DFLT);
>> +
>> +     WREG32_P(FVTHROT_FBDIV_REG1, MAX_FEEDBACK_STEP(1), ~MAX_FEEDBACK_STEP_MASK);
>> +}
>> +
>> +static void rs780_program_at(struct radeon_device *rdev)
>> +{
>> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> +
>> +     WREG32(FVTHROT_TARGET_REG, 30000000 / pi->refresh_rate);
>> +     WREG32(FVTHROT_CB1, 1000000 * 5 / pi->refresh_rate);
>> +     WREG32(FVTHROT_CB2, 1000000 * 10 / pi->refresh_rate);
>> +     WREG32(FVTHROT_CB3, 1000000 * 30 / pi->refresh_rate);
>> +     WREG32(FVTHROT_CB4, 1000000 * 50 / pi->refresh_rate);
>> +}
>> +
>> +static void rs780_disable_vbios_powersaving(struct radeon_device *rdev)
>> +{
>> +     WREG32_P(CG_INTGFX_MISC, 0, ~0xFFF00000);
>> +}
>> +
>> +static void rs780_force_voltage_to_high(struct radeon_device *rdev)
>> +{
>> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> +     struct igp_ps *current_state = rs780_get_ps(rdev->pm.dpm.current_ps);
>> +
>> +     if ((current_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
>> +         (current_state->min_voltage == RS780_VDDC_LEVEL_HIGH))
>> +             return;
>> +
>> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
>> +
>> +     udelay(1);
>> +
>> +     WREG32_P(FVTHROT_PWM_CTRL_REG0,
>> +              STARTING_PWM_HIGHTIME(pi->max_voltage),
>> +              ~STARTING_PWM_HIGHTIME_MASK);
>> +
>> +     WREG32_P(FVTHROT_PWM_CTRL_REG0,
>> +              FORCE_STARTING_PWM_HIGHTIME, ~FORCE_STARTING_PWM_HIGHTIME);
>> +
>> +     WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1, 0,
>> +             ~RANGE_PWM_FEEDBACK_DIV_EN);
>> +
>> +     udelay(1);
>> +
>> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
>> +}
>> +
>> +static int rs780_set_engine_clock_scaling(struct radeon_device *rdev)
>> +{
>> +     struct atom_clock_dividers min_dividers, max_dividers, current_max_dividers;
>> +     struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
>> +     struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
>> +     int ret;
>> +
>> +     if ((new_state->sclk_high == old_state->sclk_high) &&
>> +         (new_state->sclk_low == old_state->sclk_low))
>> +             return 0;
>> +
>> +     ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
>> +                                          new_state->sclk_low, false, &min_dividers);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
>> +                                          new_state->sclk_high, false, &max_dividers);
>> +     if (ret)
>> +             return ret;
>> +
>> +     ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
>> +                                          old_state->sclk_high, false, &current_max_dividers);
>> +     if (ret)
>> +             return ret;
>> +
>> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
>> +
>> +     WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(max_dividers.fb_div),
>> +              ~FORCED_FEEDBACK_DIV_MASK);
>> +     WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(max_dividers.fb_div),
>> +              ~STARTING_FEEDBACK_DIV_MASK);
>> +     WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
>> +
>> +     udelay(100);
>> +
>> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
>> +
>> +     if (max_dividers.fb_div > min_dividers.fb_div) {
>> +             WREG32_P(FVTHROT_FBDIV_REG0,
>> +                      MIN_FEEDBACK_DIV(min_dividers.fb_div) |
>> +                      MAX_FEEDBACK_DIV(max_dividers.fb_div),
>> +                      ~(MIN_FEEDBACK_DIV_MASK | MAX_FEEDBACK_DIV_MASK));
>> +
>> +             WREG32_P(FVTHROT_FBDIV_REG1, 0, ~FORCE_FEEDBACK_DIV);
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +static void rs780_set_engine_clock_spc(struct radeon_device *rdev)
>> +{
>> +     struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
>> +     struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
>> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> +
>> +     if ((new_state->sclk_high == old_state->sclk_high) &&
>> +         (new_state->sclk_low == old_state->sclk_low))
>> +             return;
>> +
>> +     if (pi->crtc_id == 0)
>> +             WREG32_P(CG_INTGFX_MISC, 0, ~FVTHROT_VBLANK_SEL);
>> +     else
>> +             WREG32_P(CG_INTGFX_MISC, FVTHROT_VBLANK_SEL, ~FVTHROT_VBLANK_SEL);
>> +
>> +}
>> +
>> +static void rs780_activate_engine_clk_scaling(struct radeon_device *rdev)
>> +{
>> +     struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
>> +     struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
>> +
>> +     if ((new_state->sclk_high == old_state->sclk_high) &&
>> +         (new_state->sclk_low == old_state->sclk_low))
>> +             return;
>> +
>> +     rs780_clk_scaling_enable(rdev, true);
>> +}
>> +
>> +static u32 rs780_get_voltage_for_vddc_level(struct radeon_device *rdev,
>> +                                         enum rs780_vddc_level vddc)
>> +{
>> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> +
>> +     if (vddc == RS780_VDDC_LEVEL_HIGH)
>> +             return pi->max_voltage;
>> +     else if (vddc == RS780_VDDC_LEVEL_LOW)
>> +             return pi->min_voltage;
>> +     else
>> +             return pi->max_voltage;
>> +}
>> +
>> +static void rs780_enable_voltage_scaling(struct radeon_device *rdev)
>> +{
>> +     struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
>> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> +     enum rs780_vddc_level vddc_high, vddc_low;
>> +
>> +     udelay(100);
>> +
>> +     if ((new_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
>> +         (new_state->min_voltage == RS780_VDDC_LEVEL_HIGH))
>> +             return;
>> +
>> +     vddc_high = rs780_get_voltage_for_vddc_level(rdev,
>> +                                                  new_state->max_voltage);
>> +     vddc_low = rs780_get_voltage_for_vddc_level(rdev,
>> +                                                 new_state->min_voltage);
>> +
>> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
>> +
>> +     udelay(1);
>> +     if (vddc_high > vddc_low) {
>> +             WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1,
>> +                      RANGE_PWM_FEEDBACK_DIV_EN, ~RANGE_PWM_FEEDBACK_DIV_EN);
>> +
>> +             WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~FORCE_STARTING_PWM_HIGHTIME);
>> +     } else if (vddc_high == vddc_low) {
>> +             if (pi->max_voltage != vddc_high) {
>> +                     WREG32_P(FVTHROT_PWM_CTRL_REG0,
>> +                              STARTING_PWM_HIGHTIME(vddc_high),
>> +                              ~STARTING_PWM_HIGHTIME_MASK);
>> +
>> +                     WREG32_P(FVTHROT_PWM_CTRL_REG0,
>> +                              FORCE_STARTING_PWM_HIGHTIME,
>> +                              ~FORCE_STARTING_PWM_HIGHTIME);
>> +             }
>> +     }
>> +
>> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
>> +}
>> +
>> +int rs780_dpm_enable(struct radeon_device *rdev)
>> +{
>> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> +
>> +     rs780_get_pm_mode_parameters(rdev);
>> +     rs780_disable_vbios_powersaving(rdev);
>> +
>> +     if (r600_dynamicpm_enabled(rdev))
>> +             return -EINVAL;
>> +     if (rs780_initialize_dpm_parameters(rdev))
>> +             return -EINVAL;
>> +     rs780_start_dpm(rdev);
>> +
>> +     rs780_preset_ranges_slow_clk_fbdiv_en(rdev);
>> +     rs780_preset_starting_fbdiv(rdev);
>> +     if (pi->voltage_control)
>> +             rs780_voltage_scaling_init(rdev);
>> +     rs780_clk_scaling_enable(rdev, true);
>> +     rs780_set_engine_clock_sc(rdev);
>> +     rs780_set_engine_clock_wfc(rdev);
>> +     rs780_program_at(rdev);
>> +     rs780_set_engine_clock_tdc(rdev);
>> +     rs780_set_engine_clock_ssc(rdev);
>> +
>> +     if (pi->gfx_clock_gating)
>> +             r600_gfx_clockgating_enable(rdev, true);
>> +
>> +     return 0;
>> +}
>> +
>> +void rs780_dpm_disable(struct radeon_device *rdev)
>> +{
>> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> +
>> +     r600_dynamicpm_enable(rdev, false);
>> +
>> +     rs780_clk_scaling_enable(rdev, false);
>> +     rs780_voltage_scaling_enable(rdev, false);
>> +
>> +     if (pi->gfx_clock_gating)
>> +             r600_gfx_clockgating_enable(rdev, false);
>> +}
>> +
>> +int rs780_dpm_set_power_state(struct radeon_device *rdev)
>> +{
>> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> +
>> +     rs780_get_pm_mode_parameters(rdev);
>> +
>> +     if (pi->voltage_control) {
>> +             rs780_force_voltage_to_high(rdev);
>> +             mdelay(5);
>> +     }
>> +
>> +     rs780_set_engine_clock_scaling(rdev);
>> +     rs780_set_engine_clock_spc(rdev);
>> +
>> +     rs780_activate_engine_clk_scaling(rdev);
>> +
>> +     if (pi->voltage_control)
>> +             rs780_enable_voltage_scaling(rdev);
>> +
>> +     return 0;
>> +}
>> +
>> +void rs780_dpm_setup_asic(struct radeon_device *rdev)
>> +{
>> +
>> +}
>> +
>> +void rs780_dpm_display_configuration_changed(struct radeon_device *rdev)
>> +{
>> +     rs780_get_pm_mode_parameters(rdev);
>> +     rs780_program_at(rdev);
>> +}
>> +
>> +union igp_info {
>> +     struct _ATOM_INTEGRATED_SYSTEM_INFO info;
>> +     struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
>> +};
>> +
>> +union power_info {
>> +     struct _ATOM_POWERPLAY_INFO info;
>> +     struct _ATOM_POWERPLAY_INFO_V2 info_2;
>> +     struct _ATOM_POWERPLAY_INFO_V3 info_3;
>> +     struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
>> +     struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
>> +     struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
>> +};
>> +
>> +union pplib_clock_info {
>> +     struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
>> +     struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
>> +     struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
>> +     struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
>> +};
>> +
>> +union pplib_power_state {
>> +     struct _ATOM_PPLIB_STATE v1;
>> +     struct _ATOM_PPLIB_STATE_V2 v2;
>> +};
>> +
>> +static void 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)
>> +{
>> +     rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
>> +     rps->class = le16_to_cpu(non_clock_info->usClassification);
>> +     rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
>> +
>> +     if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
>> +             rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
>> +             rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
>> +     } else if (r600_is_uvd_state(rps->class, rps->class2)) {
>> +             rps->vclk = RS780_DEFAULT_VCLK_FREQ;
>> +             rps->dclk = RS780_DEFAULT_DCLK_FREQ;
>> +     } else {
>> +             rps->vclk = 0;
>> +             rps->dclk = 0;
>> +     }
>> +
>> +     if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
>> +             rdev->pm.dpm.boot_ps = rps;
>> +     if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
>> +             rdev->pm.dpm.uvd_ps = rps;
>> +}
>> +
>> +static void rs780_parse_pplib_clock_info(struct radeon_device *rdev,
>> +                                      struct radeon_ps *rps,
>> +                                      union pplib_clock_info *clock_info)
>> +{
>> +     struct igp_ps *ps = rs780_get_ps(rps);
>> +     u32 sclk;
>> +
>> +     sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow);
>> +     sclk |= clock_info->rs780.ucLowEngineClockHigh << 16;
>> +     ps->sclk_low = sclk;
>> +     sclk = le16_to_cpu(clock_info->rs780.usHighEngineClockLow);
>> +     sclk |= clock_info->rs780.ucHighEngineClockHigh << 16;
>> +     ps->sclk_high = sclk;
>> +     switch (le16_to_cpu(clock_info->rs780.usVDDC)) {
>> +     case ATOM_PPLIB_RS780_VOLTAGE_NONE:
>> +     default:
>> +             ps->min_voltage = RS780_VDDC_LEVEL_UNKNOWN;
>> +             ps->max_voltage = RS780_VDDC_LEVEL_UNKNOWN;
>> +             break;
>> +     case ATOM_PPLIB_RS780_VOLTAGE_LOW:
>> +             ps->min_voltage = RS780_VDDC_LEVEL_LOW;
>> +             ps->max_voltage = RS780_VDDC_LEVEL_LOW;
>> +             break;
>> +     case ATOM_PPLIB_RS780_VOLTAGE_HIGH:
>> +             ps->min_voltage = RS780_VDDC_LEVEL_HIGH;
>> +             ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
>> +             break;
>> +     case ATOM_PPLIB_RS780_VOLTAGE_VARIABLE:
>> +             ps->min_voltage = RS780_VDDC_LEVEL_LOW;
>> +             ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
>> +             break;
>> +     }
>> +     ps->flags = le32_to_cpu(clock_info->rs780.ulFlags);
>> +
>> +     if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
>> +             ps->sclk_low = rdev->clock.default_sclk;
>> +             ps->sclk_high = rdev->clock.default_sclk;
>> +             ps->min_voltage = RS780_VDDC_LEVEL_HIGH;
>> +             ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
>> +     }
>> +}
>> +
>> +static int rs780_parse_power_table(struct radeon_device *rdev)
>> +{
>> +     struct radeon_mode_info *mode_info = &rdev->mode_info;
>> +     struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
>> +     union pplib_power_state *power_state;
>> +     int i;
>> +     union pplib_clock_info *clock_info;
>> +     union power_info *power_info;
>> +     int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
>> +        u16 data_offset;
>> +     u8 frev, crev;
>> +     struct igp_ps *ps;
>> +
>> +     if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
>> +                                &frev, &crev, &data_offset))
>> +             return -EINVAL;
>> +     power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
>> +
>> +     rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
>> +                               power_info->pplib.ucNumStates, GFP_KERNEL);
>> +     if (!rdev->pm.dpm.ps)
>> +             return -ENOMEM;
>> +     rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
>> +     rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
>> +     rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
>> +
>> +     for (i = 0; i < power_info->pplib.ucNumStates; i++) {
>> +             power_state = (union pplib_power_state *)
>> +                     (mode_info->atom_context->bios + data_offset +
>> +                      le16_to_cpu(power_info->pplib.usStateArrayOffset) +
>> +                      i * power_info->pplib.ucStateEntrySize);
>> +             non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
>> +                     (mode_info->atom_context->bios + data_offset +
>> +                      le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
>> +                      (power_state->v1.ucNonClockStateIndex *
>> +                       power_info->pplib.ucNonClockSize));
>> +             if (power_info->pplib.ucStateEntrySize - 1) {
>> +                     clock_info = (union pplib_clock_info *)
>> +                             (mode_info->atom_context->bios + data_offset +
>> +                              le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
>> +                              (power_state->v1.ucClockStateIndices[0] *
>> +                               power_info->pplib.ucClockInfoSize));
>> +                     ps = kzalloc(sizeof(struct igp_ps), GFP_KERNEL);
>> +                     if (ps == NULL) {
>> +                             kfree(rdev->pm.dpm.ps);
>> +                             return -ENOMEM;
>> +                     }
>> +                     rdev->pm.dpm.ps[i].ps_priv = ps;
>> +                     rs780_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
>> +                                                      non_clock_info,
>> +                                                      power_info->pplib.ucNonClockSize);
>> +                     rs780_parse_pplib_clock_info(rdev,
>> +                                                  &rdev->pm.dpm.ps[i],
>> +                                                  clock_info);
>> +             }
>> +     }
>> +     rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates;
>> +     return 0;
>> +}
>> +
>> +int rs780_dpm_init(struct radeon_device *rdev)
>> +{
>> +     struct igp_power_info *pi;
>> +     int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
>> +     union igp_info *info;
>> +     u16 data_offset;
>> +     u8 frev, crev;
>> +     int ret;
>> +
>> +     pi = kzalloc(sizeof(struct igp_power_info), GFP_KERNEL);
>> +     if (pi == NULL)
>> +             return -ENOMEM;
>> +     rdev->pm.dpm.priv = pi;
>> +
>> +     ret = rs780_parse_power_table(rdev);
>> +     if (ret)
>> +             return ret;
>> +
>> +     pi->voltage_control = false;
>> +     pi->gfx_clock_gating = true;
>> +
>> +     if (atom_parse_data_header(rdev->mode_info.atom_context, index, NULL,
>> +                                &frev, &crev, &data_offset)) {
>> +             info = (union igp_info *)(rdev->mode_info.atom_context->bios + data_offset);
>> +
>> +             /* Get various system informations from bios */
>> +             switch (crev) {
>> +             case 1:
>> +                     pi->num_of_cycles_in_period =
>> +                             info->info.ucNumberOfCyclesInPeriod;
>> +                     pi->num_of_cycles_in_period |=
>> +                             info->info.ucNumberOfCyclesInPeriodHi << 8;
>> +                     pi->invert_pwm_required =
>> +                             (pi->num_of_cycles_in_period & 0x8000) ? true : false;
>> +                     pi->boot_voltage = info->info.ucStartingPWM_HighTime;
>> +                     pi->max_voltage = info->info.ucMaxNBVoltage;
>> +                     pi->max_voltage |= info->info.ucMaxNBVoltageHigh << 8;
>> +                     pi->min_voltage = info->info.ucMinNBVoltage;
>> +                     pi->min_voltage |= info->info.ucMinNBVoltageHigh << 8;
>> +                     pi->inter_voltage_low =
>> +                             le16_to_cpu(info->info.usInterNBVoltageLow);
>> +                     pi->inter_voltage_high =
>> +                             le16_to_cpu(info->info.usInterNBVoltageHigh);
>> +                     pi->voltage_control = true;
>> +                     pi->bootup_uma_clk = info->info.usK8MemoryClock * 100;
>> +                     break;
>> +             case 2:
>> +                     pi->num_of_cycles_in_period =
>> +                             le16_to_cpu(info->info_2.usNumberOfCyclesInPeriod);
>> +                     pi->invert_pwm_required =
>> +                             (pi->num_of_cycles_in_period & 0x8000) ? true : false;
>> +                     pi->boot_voltage =
>> +                             le16_to_cpu(info->info_2.usBootUpNBVoltage);
>> +                     pi->max_voltage =
>> +                             le16_to_cpu(info->info_2.usMaxNBVoltage);
>> +                     pi->min_voltage =
>> +                             le16_to_cpu(info->info_2.usMinNBVoltage);
>> +                     pi->system_config =
>> +                             le32_to_cpu(info->info_2.ulSystemConfig);
>> +                     pi->pwm_voltage_control =
>> +                             (pi->system_config & 0x4) ? true : false;
>> +                     pi->voltage_control = true;
>> +                     pi->bootup_uma_clk = le32_to_cpu(info->info_2.ulBootUpUMAClock);
>> +                     break;
>> +             default:
>> +                     DRM_ERROR("No integrated system info for your GPU\n");
>> +                     return -EINVAL;
>> +             }
>> +             if (pi->min_voltage > pi->max_voltage)
>> +                     pi->voltage_control = false;
>> +             if (pi->pwm_voltage_control) {
>> +                     if ((pi->num_of_cycles_in_period == 0) ||
>> +                         (pi->max_voltage == 0) ||
>> +                         (pi->min_voltage == 0))
>> +                             pi->voltage_control = false;
>> +             } else {
>> +                     if ((pi->num_of_cycles_in_period == 0) ||
>> +                         (pi->max_voltage == 0))
>> +                             pi->voltage_control = false;
>> +             }
>> +
>> +             return 0;
>> +     }
>> +     radeon_dpm_fini(rdev);
>> +     return -EINVAL;
>> +}
>> +
>> +void rs780_dpm_print_power_state(struct radeon_device *rdev,
>> +                              struct radeon_ps *rps)
>> +{
>> +     struct igp_ps *ps = rs780_get_ps(rps);
>> +
>> +     r600_dpm_print_class_info(rps->class, rps->class2);
>> +     r600_dpm_print_cap_info(rps->caps);
>> +     printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
>> +     printk("\t\tpower level 0    sclk: %u vddc_index: %d\n",
>> +            ps->sclk_low, ps->min_voltage);
>> +     printk("\t\tpower level 1    sclk: %u vddc_index: %d\n",
>> +            ps->sclk_high, ps->max_voltage);
>> +     r600_dpm_print_ps_status(rdev, rps);
>> +}
>> +
>> +void rs780_dpm_fini(struct radeon_device *rdev)
>> +{
>> +     int i;
>> +
>> +     for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
>> +             kfree(rdev->pm.dpm.ps[i].ps_priv);
>> +     }
>> +     kfree(rdev->pm.dpm.ps);
>> +     kfree(rdev->pm.dpm.priv);
>> +}
>> +
>> +u32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low)
>> +{
>> +     struct igp_ps *requested_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
>> +
>> +     if (low)
>> +             return requested_state->sclk_low;
>> +     else
>> +             return requested_state->sclk_high;
>> +}
>> +
>> +u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low)
>> +{
>> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> +
>> +     return pi->bootup_uma_clk;
>> +}
>> diff --git a/drivers/gpu/drm/radeon/rs780_dpm.h b/drivers/gpu/drm/radeon/rs780_dpm.h
>> new file mode 100644
>> index 0000000..47a40b1
>> --- /dev/null
>> +++ b/drivers/gpu/drm/radeon/rs780_dpm.h
>> @@ -0,0 +1,109 @@
>> +/*
>> + * Copyright 2011 Advanced Micro Devices, Inc.
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a
>> + * copy of this software and associated documentation files (the "Software"),
>> + * to deal in the Software without restriction, including without limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice shall be included in
>> + * all copies or substantial portions of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
>> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>> + * OTHER DEALINGS IN THE SOFTWARE.
>> + *
>> + */
>> +#ifndef __RS780_DPM_H__
>> +#define __RS780_DPM_H__
>> +
>> +enum rs780_vddc_level {
>> +     RS780_VDDC_LEVEL_UNKNOWN = 0,
>> +     RS780_VDDC_LEVEL_LOW = 1,
>> +     RS780_VDDC_LEVEL_HIGH = 2,
>> +};
>> +
>> +struct igp_power_info {
>> +     /* flags */
>> +     bool invert_pwm_required;
>> +     bool pwm_voltage_control;
>> +     bool voltage_control;
>> +     bool gfx_clock_gating;
>> +     /* stored values */
>> +     u32 system_config;
>> +     u32 bootup_uma_clk;
>> +     u16 max_voltage;
>> +     u16 min_voltage;
>> +     u16 boot_voltage;
>> +     u16 inter_voltage_low;
>> +     u16 inter_voltage_high;
>> +     u16 num_of_cycles_in_period;
>> +     /* variable */
>> +     int crtc_id;
>> +     int refresh_rate;
>> +};
>> +
>> +struct igp_ps {
>> +     enum rs780_vddc_level min_voltage;
>> +     enum rs780_vddc_level max_voltage;
>> +     u32 sclk_low;
>> +     u32 sclk_high;
>> +     u32 flags;
>> +};
>> +
>> +#define RS780_CGFTV_DFLT                 0x0303000f
>> +#define RS780_FBDIVTIMERVAL_DFLT         0x2710
>> +
>> +#define RS780_FVTHROTUTC0_DFLT   0x04010040
>> +#define RS780_FVTHROTUTC1_DFLT   0x04010040
>> +#define RS780_FVTHROTUTC2_DFLT   0x04010040
>> +#define RS780_FVTHROTUTC3_DFLT   0x04010040
>> +#define RS780_FVTHROTUTC4_DFLT   0x04010040
>> +
>> +#define RS780_FVTHROTDTC0_DFLT 0x04010040
>> +#define RS780_FVTHROTDTC1_DFLT 0x04010040
>> +#define RS780_FVTHROTDTC2_DFLT 0x04010040
>> +#define RS780_FVTHROTDTC3_DFLT 0x04010040
>> +#define RS780_FVTHROTDTC4_DFLT 0x04010040
>> +
>> +#define RS780_FVTHROTFBUSREG0_DFLT       0x00001001
>> +#define RS780_FVTHROTFBUSREG1_DFLT       0x00002002
>> +#define RS780_FVTHROTFBDSREG0_DFLT       0x00004001
>> +#define RS780_FVTHROTFBDSREG1_DFLT       0x00020010
>> +
>> +#define RS780_FVTHROTPWMUSREG0_DFLT      0x00002001
>> +#define RS780_FVTHROTPWMUSREG1_DFLT      0x00004003
>> +#define RS780_FVTHROTPWMDSREG0_DFLT      0x00002001
>> +#define RS780_FVTHROTPWMDSREG1_DFLT      0x00004003
>> +
>> +#define RS780_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x37
>> +#define RS780_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x4b
>> +#define RS780_FVTHROTPWMFBDIVRANGEREG2_DFLT  0x8b
>> +
>> +#define RS780D_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x8b
>> +#define RS780D_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x8c
>> +#define RS780D_FVTHROTPWMFBDIVRANGEREG2_DFLT  0xb5
>> +
>> +#define RS880D_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x8d
>> +#define RS880D_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x8e
>> +#define RS880D_FVTHROTPWMFBDIVRANGEREG2_DFLT  0xBa
>> +
>> +#define RS780_FVTHROTPWMRANGE0_GPIO_DFLT  0x1a
>> +#define RS780_FVTHROTPWMRANGE1_GPIO_DFLT  0x1a
>> +#define RS780_FVTHROTPWMRANGE2_GPIO_DFLT  0x0
>> +#define RS780_FVTHROTPWMRANGE3_GPIO_DFLT  0x0
>> +
>> +#define RS780_SLOWCLKFEEDBACKDIV_DFLT 110
>> +
>> +#define RS780_CGCLKGATING_DFLT           0x0000E204
>> +
>> +#define RS780_DEFAULT_VCLK_FREQ  53300 /* 10 khz */
>> +#define RS780_DEFAULT_DCLK_FREQ  40000 /* 10 khz */
>> +
>> +#endif
>> diff --git a/drivers/gpu/drm/radeon/rs780d.h b/drivers/gpu/drm/radeon/rs780d.h
>> new file mode 100644
>> index 0000000..b1142ed
>> --- /dev/null
>> +++ b/drivers/gpu/drm/radeon/rs780d.h
>> @@ -0,0 +1,168 @@
>> +/*
>> + * Copyright 2011 Advanced Micro Devices, Inc.
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a
>> + * copy of this software and associated documentation files (the "Software"),
>> + * to deal in the Software without restriction, including without limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice shall be included in
>> + * all copies or substantial portions of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
>> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>> + * OTHER DEALINGS IN THE SOFTWARE.
>> + *
>> + */
>> +#ifndef __RS780D_H__
>> +#define __RS780D_H__
>> +
>> +#define CG_SPLL_FUNC_CNTL                                 0x600
>> +#       define SPLL_RESET                                (1 << 0)
>> +#       define SPLL_SLEEP                                (1 << 1)
>> +#       define SPLL_REF_DIV(x)                           ((x) << 2)
>> +#       define SPLL_REF_DIV_MASK                         (7 << 2)
>> +#       define SPLL_FB_DIV(x)                            ((x) << 5)
>> +#       define SPLL_FB_DIV_MASK                          (0xff << 2)
>> +#       define SPLL_FB_DIV_SHIFT                         2
>> +#       define SPLL_PULSEEN                              (1 << 13)
>> +#       define SPLL_PULSENUM(x)                          ((x) << 14)
>> +#       define SPLL_PULSENUM_MASK                        (3 << 14)
>> +#       define SPLL_SW_HILEN(x)                          ((x) << 16)
>> +#       define SPLL_SW_HILEN_MASK                        (0xf << 16)
>> +#       define SPLL_SW_LOLEN(x)                          ((x) << 20)
>> +#       define SPLL_SW_LOLEN_MASK                        (0xf << 20)
>> +#       define SPLL_DIVEN                                (1 << 24)
>> +#       define SPLL_BYPASS_EN                            (1 << 25)
>> +#       define SPLL_CHG_STATUS                           (1 << 29)
>> +#       define SPLL_CTLREQ                               (1 << 30)
>> +#       define SPLL_CTLACK                               (1 << 31)
>> +
>> +/* RS780/RS880 PM */
>> +#define      FVTHROT_CNTRL_REG                               0x3000
>> +#define              DONT_WAIT_FOR_FBDIV_WRAP                (1 << 0)
>> +#define              MINIMUM_CIP(x)                          ((x) << 1)
>> +#define              MINIMUM_CIP_SHIFT                       1
>> +#define              MINIMUM_CIP_MASK                        0x1fffffe
>> +#define              REFRESH_RATE_DIVISOR(x)                 ((x) << 25)
>> +#define              REFRESH_RATE_DIVISOR_SHIFT              25
>> +#define              REFRESH_RATE_DIVISOR_MASK               (0x3 << 25)
>> +#define              ENABLE_FV_THROT                         (1 << 27)
>> +#define              ENABLE_FV_UPDATE                        (1 << 28)
>> +#define              TREND_SEL_MODE                          (1 << 29)
>> +#define              FORCE_TREND_SEL                         (1 << 30)
>> +#define              ENABLE_FV_THROT_IO                      (1 << 31)
>> +#define      FVTHROT_TARGET_REG                              0x3004
>> +#define              TARGET_IDLE_COUNT(x)                    ((x) << 0)
>> +#define              TARGET_IDLE_COUNT_MASK                  0xffffff
>> +#define              TARGET_IDLE_COUNT_SHIFT                 0
>> +#define      FVTHROT_CB1                                     0x3008
>> +#define      FVTHROT_CB2                                     0x300c
>> +#define      FVTHROT_CB3                                     0x3010
>> +#define      FVTHROT_CB4                                     0x3014
>> +#define      FVTHROT_UTC0                                    0x3018
>> +#define      FVTHROT_UTC1                                    0x301c
>> +#define      FVTHROT_UTC2                                    0x3020
>> +#define      FVTHROT_UTC3                                    0x3024
>> +#define      FVTHROT_UTC4                                    0x3028
>> +#define      FVTHROT_DTC0                                    0x302c
>> +#define      FVTHROT_DTC1                                    0x3030
>> +#define      FVTHROT_DTC2                                    0x3034
>> +#define      FVTHROT_DTC3                                    0x3038
>> +#define      FVTHROT_DTC4                                    0x303c
>> +#define      FVTHROT_FBDIV_REG0                              0x3040
>> +#define              MIN_FEEDBACK_DIV(x)                     ((x) << 0)
>> +#define              MIN_FEEDBACK_DIV_MASK                   0xfff
>> +#define              MIN_FEEDBACK_DIV_SHIFT                  0
>> +#define              MAX_FEEDBACK_DIV(x)                     ((x) << 12)
>> +#define              MAX_FEEDBACK_DIV_MASK                   (0xfff << 12)
>> +#define              MAX_FEEDBACK_DIV_SHIFT                  12
>> +#define      FVTHROT_FBDIV_REG1                              0x3044
>> +#define              MAX_FEEDBACK_STEP(x)                    ((x) << 0)
>> +#define              MAX_FEEDBACK_STEP_MASK                  0xfff
>> +#define              MAX_FEEDBACK_STEP_SHIFT                 0
>> +#define              STARTING_FEEDBACK_DIV(x)                ((x) << 12)
>> +#define              STARTING_FEEDBACK_DIV_MASK              (0xfff << 12)
>> +#define              STARTING_FEEDBACK_DIV_SHIFT             12
>> +#define              FORCE_FEEDBACK_DIV                      (1 << 24)
>> +#define      FVTHROT_FBDIV_REG2                              0x3048
>> +#define              FORCED_FEEDBACK_DIV(x)                  ((x) << 0)
>> +#define              FORCED_FEEDBACK_DIV_MASK                0xfff
>> +#define              FORCED_FEEDBACK_DIV_SHIFT               0
>> +#define              FB_DIV_TIMER_VAL(x)                     ((x) << 12)
>> +#define              FB_DIV_TIMER_VAL_MASK                   (0xffff << 12)
>> +#define              FB_DIV_TIMER_VAL_SHIFT                  12
>> +#define      FVTHROT_FB_US_REG0                              0x304c
>> +#define      FVTHROT_FB_US_REG1                              0x3050
>> +#define      FVTHROT_FB_DS_REG0                              0x3054
>> +#define      FVTHROT_FB_DS_REG1                              0x3058
>> +#define      FVTHROT_PWM_CTRL_REG0                           0x305c
>> +#define              STARTING_PWM_HIGHTIME(x)                ((x) << 0)
>> +#define              STARTING_PWM_HIGHTIME_MASK              0xfff
>> +#define              STARTING_PWM_HIGHTIME_SHIFT             0
>> +#define              NUMBER_OF_CYCLES_IN_PERIOD(x)           ((x) << 12)
>> +#define              NUMBER_OF_CYCLES_IN_PERIOD_MASK         (0xfff << 12)
>> +#define              NUMBER_OF_CYCLES_IN_PERIOD_SHIFT        12
>> +#define              FORCE_STARTING_PWM_HIGHTIME             (1 << 24)
>> +#define              INVERT_PWM_WAVEFORM                     (1 << 25)
>> +#define      FVTHROT_PWM_CTRL_REG1                           0x3060
>> +#define              MIN_PWM_HIGHTIME(x)                     ((x) << 0)
>> +#define              MIN_PWM_HIGHTIME_MASK                   0xfff
>> +#define              MIN_PWM_HIGHTIME_SHIFT                  0
>> +#define              MAX_PWM_HIGHTIME(x)                     ((x) << 12)
>> +#define              MAX_PWM_HIGHTIME_MASK                   (0xfff << 12)
>> +#define              MAX_PWM_HIGHTIME_SHIFT                  12
>> +#define      FVTHROT_PWM_US_REG0                             0x3064
>> +#define      FVTHROT_PWM_US_REG1                             0x3068
>> +#define      FVTHROT_PWM_DS_REG0                             0x306c
>> +#define      FVTHROT_PWM_DS_REG1                             0x3070
>> +#define      FVTHROT_STATUS_REG0                             0x3074
>> +#define              CURRENT_FEEDBACK_DIV_MASK               0xfff
>> +#define              CURRENT_FEEDBACK_DIV_SHIFT              0
>> +#define      FVTHROT_STATUS_REG1                             0x3078
>> +#define      FVTHROT_STATUS_REG2                             0x307c
>> +#define      CG_INTGFX_MISC                                  0x3080
>> +#define              FVTHROT_VBLANK_SEL                      (1 << 9)
>> +#define      FVTHROT_PWM_FEEDBACK_DIV_REG1                   0x308c
>> +#define              RANGE0_PWM_FEEDBACK_DIV(x)              ((x) << 0)
>> +#define              RANGE0_PWM_FEEDBACK_DIV_MASK            0xfff
>> +#define              RANGE0_PWM_FEEDBACK_DIV_SHIFT           0
>> +#define              RANGE_PWM_FEEDBACK_DIV_EN               (1 << 12)
>> +#define      FVTHROT_PWM_FEEDBACK_DIV_REG2                   0x3090
>> +#define              RANGE1_PWM_FEEDBACK_DIV(x)              ((x) << 0)
>> +#define              RANGE1_PWM_FEEDBACK_DIV_MASK            0xfff
>> +#define              RANGE1_PWM_FEEDBACK_DIV_SHIFT           0
>> +#define              RANGE2_PWM_FEEDBACK_DIV(x)              ((x) << 12)
>> +#define              RANGE2_PWM_FEEDBACK_DIV_MASK            (0xfff << 12)
>> +#define              RANGE2_PWM_FEEDBACK_DIV_SHIFT           12
>> +#define      FVTHROT_PWM_FEEDBACK_DIV_REG3                   0x3094
>> +#define              RANGE0_PWM(x)                           ((x) << 0)
>> +#define              RANGE0_PWM_MASK                         0xfff
>> +#define              RANGE0_PWM_SHIFT                        0
>> +#define              RANGE1_PWM(x)                           ((x) << 12)
>> +#define              RANGE1_PWM_MASK                         (0xfff << 12)
>> +#define              RANGE1_PWM_SHIFT                        12
>> +#define      FVTHROT_PWM_FEEDBACK_DIV_REG4                   0x3098
>> +#define              RANGE2_PWM(x)                           ((x) << 0)
>> +#define              RANGE2_PWM_MASK                         0xfff
>> +#define              RANGE2_PWM_SHIFT                        0
>> +#define              RANGE3_PWM(x)                           ((x) << 12)
>> +#define              RANGE3_PWM_MASK                         (0xfff << 12)
>> +#define              RANGE3_PWM_SHIFT                        12
>> +#define      FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1              0x30ac
>> +#define              RANGE0_SLOW_CLK_FEEDBACK_DIV(x)         ((x) << 0)
>> +#define              RANGE0_SLOW_CLK_FEEDBACK_DIV_MASK       0xfff
>> +#define              RANGE0_SLOW_CLK_FEEDBACK_DIV_SHIFT      0
>> +#define              RANGE_SLOW_CLK_FEEDBACK_DIV_EN          (1 << 12)
>> +
>> +#define      GFX_MACRO_BYPASS_CNTL                           0x30c0
>> +#define              SPLL_BYPASS_CNTL                        (1 << 0)
>> +#define              UPLL_BYPASS_CNTL                        (1 << 1)
>> +
>> +#endif
>> --
>> 1.7.7.5
>>
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/dri-devel
Alex Deucher June 26, 2013, 6:41 p.m. UTC | #4
On Wed, Jun 26, 2013 at 9:18 AM, Jerome Glisse <j.glisse@gmail.com> wrote:
> On Wed, Jun 26, 2013 at 02:19:23PM -0400, Alex Deucher wrote:
>> On Wed, Jun 26, 2013 at 6:46 AM, Jerome Glisse <j.glisse@gmail.com> wrote:
>> > On Wed, Jun 26, 2013 at 09:22:35AM -0400, alexdeucher@gmail.com wrote:
>> >> From: Alex Deucher <alexander.deucher@amd.com>
>> >>
>> >> This adds dpm support for rs780/rs880 asics.  This includes:
>> >> - clockgating
>> >> - dynamic engine clock scaling
>> >> - dynamic voltage scaling
>> >>
>> >> set radeon.dpm=1 to enable it.
>> >>
>> >> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
>> >
>> > Depending on the answer to inline question :
>> >
>> > Reviewed-by: Jerome Glisse <jglisse@redhat.com>
>> >
>> >> ---
>> >>  drivers/gpu/drm/radeon/Makefile      |    2 +-
>> >>  drivers/gpu/drm/radeon/radeon_asic.c |   12 +
>> >>  drivers/gpu/drm/radeon/radeon_asic.h |   12 +
>> >>  drivers/gpu/drm/radeon/radeon_pm.c   |    7 +
>> >>  drivers/gpu/drm/radeon/rs780_dpm.c   |  894 ++++++++++++++++++++++++++++++++++
>> >>  drivers/gpu/drm/radeon/rs780_dpm.h   |  109 ++++
>> >>  drivers/gpu/drm/radeon/rs780d.h      |  168 +++++++
>> >>  7 files changed, 1203 insertions(+), 1 deletions(-)
>> >>  create mode 100644 drivers/gpu/drm/radeon/rs780_dpm.c
>> >>  create mode 100644 drivers/gpu/drm/radeon/rs780_dpm.h
>> >>  create mode 100644 drivers/gpu/drm/radeon/rs780d.h
>> >>
>> >> diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
>> >> index a131a13..e44b046 100644
>> >> --- a/drivers/gpu/drm/radeon/Makefile
>> >> +++ b/drivers/gpu/drm/radeon/Makefile
>> >> @@ -77,7 +77,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
>> >>       evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \
>> >>       atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
>> >>       si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \
>> >> -     r600_dpm.o
>> >> +     r600_dpm.o rs780_dpm.o
>> >>
>> >>  radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
>> >>  radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
>> >> diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
>> >> index d9c8e9a..db3c930 100644
>> >> --- a/drivers/gpu/drm/radeon/radeon_asic.c
>> >> +++ b/drivers/gpu/drm/radeon/radeon_asic.c
>> >> @@ -1194,6 +1194,18 @@ static struct radeon_asic rs780_asic = {
>> >>               .set_clock_gating = NULL,
>> >>               .get_temperature = &rv6xx_get_temp,
>> >>       },
>> >> +     .dpm = {
>> >> +             .init = &rs780_dpm_init,
>> >> +             .setup_asic = &rs780_dpm_setup_asic,
>> >> +             .enable = &rs780_dpm_enable,
>> >> +             .disable = &rs780_dpm_disable,
>> >> +             .set_power_state = &rs780_dpm_set_power_state,
>> >> +             .display_configuration_changed = &rs780_dpm_display_configuration_changed,
>> >> +             .fini = &rs780_dpm_fini,
>> >> +             .get_sclk = &rs780_dpm_get_sclk,
>> >> +             .get_mclk = &rs780_dpm_get_mclk,
>> >> +             .print_power_state = &rs780_dpm_print_power_state,
>> >> +     },
>> >>       .pflip = {
>> >>               .pre_page_flip = &rs600_pre_page_flip,
>> >>               .page_flip = &rs600_page_flip,
>> >> diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
>> >> index 8507cae..134bf57 100644
>> >> --- a/drivers/gpu/drm/radeon/radeon_asic.h
>> >> +++ b/drivers/gpu/drm/radeon/radeon_asic.h
>> >> @@ -396,6 +396,18 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev);
>> >>  u32 r600_get_xclk(struct radeon_device *rdev);
>> >>  uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev);
>> >>  int rv6xx_get_temp(struct radeon_device *rdev);
>> >> +/* rs780 dpm */
>> >> +int rs780_dpm_init(struct radeon_device *rdev);
>> >> +int rs780_dpm_enable(struct radeon_device *rdev);
>> >> +void rs780_dpm_disable(struct radeon_device *rdev);
>> >> +int rs780_dpm_set_power_state(struct radeon_device *rdev);
>> >> +void rs780_dpm_setup_asic(struct radeon_device *rdev);
>> >> +void rs780_dpm_display_configuration_changed(struct radeon_device *rdev);
>> >> +void rs780_dpm_fini(struct radeon_device *rdev);
>> >> +u32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low);
>> >> +u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low);
>> >> +void rs780_dpm_print_power_state(struct radeon_device *rdev,
>> >> +                              struct radeon_ps *ps);
>> >>
>> >>  /* uvd */
>> >>  int r600_uvd_init(struct radeon_device *rdev);
>> >> diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
>> >> index 4f5422e..853a8a2 100644
>> >> --- a/drivers/gpu/drm/radeon/radeon_pm.c
>> >> +++ b/drivers/gpu/drm/radeon/radeon_pm.c
>> >> @@ -1030,6 +1030,13 @@ int radeon_pm_init(struct radeon_device *rdev)
>> >>  {
>> >>       /* enable dpm on rv6xx+ */
>> >>       switch (rdev->family) {
>> >> +     case CHIP_RS780:
>> >> +     case CHIP_RS880:
>> >> +             if (radeon_dpm == 1)
>> >> +                     rdev->pm.pm_method = PM_METHOD_DPM;
>> >> +             else
>> >> +                     rdev->pm.pm_method = PM_METHOD_PROFILE;
>> >> +             break;
>> >>       default:
>> >>               /* default to profile method */
>> >>               rdev->pm.pm_method = PM_METHOD_PROFILE;
>> >> diff --git a/drivers/gpu/drm/radeon/rs780_dpm.c b/drivers/gpu/drm/radeon/rs780_dpm.c
>> >> new file mode 100644
>> >> index 0000000..f594900
>> >> --- /dev/null
>> >> +++ b/drivers/gpu/drm/radeon/rs780_dpm.c
>> >> @@ -0,0 +1,894 @@
>> >> +/*
>> >> + * Copyright 2011 Advanced Micro Devices, Inc.
>> >> + *
>> >> + * Permission is hereby granted, free of charge, to any person obtaining a
>> >> + * copy of this software and associated documentation files (the "Software"),
>> >> + * to deal in the Software without restriction, including without limitation
>> >> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> >> + * and/or sell copies of the Software, and to permit persons to whom the
>> >> + * Software is furnished to do so, subject to the following conditions:
>> >> + *
>> >> + * The above copyright notice and this permission notice shall be included in
>> >> + * all copies or substantial portions of the Software.
>> >> + *
>> >> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> >> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> >> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> >> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
>> >> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>> >> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>> >> + * OTHER DEALINGS IN THE SOFTWARE.
>> >> + *
>> >> + * Authors: Alex Deucher
>> >> + */
>> >> +
>> >> +#include "drmP.h"
>> >> +#include "radeon.h"
>> >> +#include "rs780d.h"
>> >> +#include "r600_dpm.h"
>> >> +#include "rs780_dpm.h"
>> >> +#include "atom.h"
>> >> +
>> >> +static struct igp_ps *rs780_get_ps(struct radeon_ps *rps)
>> >> +{
>> >> +     struct igp_ps *ps = rps->ps_priv;
>> >> +
>> >> +     return ps;
>> >> +}
>> >> +
>> >> +static struct igp_power_info *rs780_get_pi(struct radeon_device *rdev)
>> >> +{
>> >> +     struct igp_power_info *pi = rdev->pm.dpm.priv;
>> >> +
>> >> +     return pi;
>> >> +}
>> >> +
>> >> +static void rs780_get_pm_mode_parameters(struct radeon_device *rdev)
>> >> +{
>> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> >> +     struct radeon_mode_info *minfo = &rdev->mode_info;
>> >> +     struct drm_crtc *crtc;
>> >> +     struct radeon_crtc *radeon_crtc;
>> >> +     int i;
>> >> +
>> >> +     /* defaults */
>> >> +     pi->crtc_id = 0;
>> >> +     pi->refresh_rate = 60;
>> >> +
>> >> +     for (i = 0; i < rdev->num_crtc; i++) {
>> >> +             crtc = (struct drm_crtc *)minfo->crtcs[i];
>> >> +             if (crtc && crtc->enabled) {
>> >> +                     radeon_crtc = to_radeon_crtc(crtc);
>> >> +                     pi->crtc_id = radeon_crtc->crtc_id;
>> >> +                     if (crtc->mode.htotal && crtc->mode.vtotal)
>> >> +                             pi->refresh_rate =
>> >> +                                     (crtc->mode.clock * 1000) /
>> >> +                                     (crtc->mode.htotal * crtc->mode.vtotal);
>> >> +                     break;
>> >> +             }
>> >> +     }
>> >
>> > Ok this looks wrong to me you look for the first enabled crtc but on those iirc
>> > there could be 2 so first one might be a low refresh rate and second one an higher
>> > one. Thus returning the first one might lead to PM decision that are wrong.
>> >
>
> So what happens when 2 are active ? Flickering on the unsync one ?

In theory, although changing sclk and voltage can be done outside of
the vblank period on most asics.  vblank is mainly needed for memory
related operations.  I'm not sure what exactly is affected on rs780.
Too old.  Hard to find docs on it.

Alex

>
> Cheers,
> Jerome
>
>>
>> On RS780/RS880, the hardware can only synchronize with a single crtc,
>> so it doesn't really matter which one we pick as long as it's active.
>>
>>
>> >> +}
>> >> +
>> >> +static void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable);
>> >> +
>> >> +static int rs780_initialize_dpm_power_state(struct radeon_device *rdev)
>> >> +{
>> >> +     struct atom_clock_dividers dividers;
>> >> +     struct igp_ps *default_state = rs780_get_ps(rdev->pm.dpm.boot_ps);
>> >> +     int i, ret;
>> >> +
>> >> +     ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
>> >> +                                          default_state->sclk_low, false, &dividers);
>> >> +     if (ret)
>> >> +             return ret;
>> >> +
>> >> +     r600_engine_clock_entry_set_reference_divider(rdev, 0, dividers.ref_div);
>> >> +     r600_engine_clock_entry_set_feedback_divider(rdev, 0, dividers.fb_div);
>> >> +     r600_engine_clock_entry_set_post_divider(rdev, 0, dividers.post_div);
>> >> +
>> >> +     if (dividers.enable_post_div)
>> >> +             r600_engine_clock_entry_enable_post_divider(rdev, 0, true);
>> >> +     else
>> >> +             r600_engine_clock_entry_enable_post_divider(rdev, 0, false);
>> >> +
>> >> +     r600_engine_clock_entry_set_step_time(rdev, 0, R600_SST_DFLT);
>> >> +     r600_engine_clock_entry_enable_pulse_skipping(rdev, 0, false);
>> >> +
>> >> +     r600_engine_clock_entry_enable(rdev, 0, true);
>> >> +     for (i = 1; i < R600_PM_NUMBER_OF_SCLKS; i++)
>> >> +             r600_engine_clock_entry_enable(rdev, i, false);
>> >> +
>> >> +     r600_enable_mclk_control(rdev, false);
>> >> +     r600_voltage_control_enable_pins(rdev, 0);
>> >> +
>> >> +     return 0;
>> >> +}
>> >> +
>> >> +static int rs780_initialize_dpm_parameters(struct radeon_device *rdev)
>> >> +{
>> >> +     int ret = 0;
>> >> +     int i;
>> >> +
>> >> +     r600_set_bsp(rdev, R600_BSU_DFLT, R600_BSP_DFLT);
>> >> +
>> >> +     r600_set_at(rdev, 0, 0, 0, 0);
>> >> +
>> >> +     r600_set_git(rdev, R600_GICST_DFLT);
>> >> +
>> >> +     for (i = 0; i < R600_PM_NUMBER_OF_TC; i++)
>> >> +             r600_set_tc(rdev, i, 0, 0);
>> >> +
>> >> +     r600_select_td(rdev, R600_TD_DFLT);
>> >> +     r600_set_vrc(rdev, 0);
>> >> +
>> >> +     r600_set_tpu(rdev, R600_TPU_DFLT);
>> >> +     r600_set_tpc(rdev, R600_TPC_DFLT);
>> >> +
>> >> +     r600_set_sstu(rdev, R600_SSTU_DFLT);
>> >> +     r600_set_sst(rdev, R600_SST_DFLT);
>> >> +
>> >> +     r600_set_fctu(rdev, R600_FCTU_DFLT);
>> >> +     r600_set_fct(rdev, R600_FCT_DFLT);
>> >> +
>> >> +     r600_set_vddc3d_oorsu(rdev, R600_VDDC3DOORSU_DFLT);
>> >> +     r600_set_vddc3d_oorphc(rdev, R600_VDDC3DOORPHC_DFLT);
>> >> +     r600_set_vddc3d_oorsdc(rdev, R600_VDDC3DOORSDC_DFLT);
>> >> +     r600_set_ctxcgtt3d_rphc(rdev, R600_CTXCGTT3DRPHC_DFLT);
>> >> +     r600_set_ctxcgtt3d_rsdc(rdev, R600_CTXCGTT3DRSDC_DFLT);
>> >> +
>> >> +     r600_vid_rt_set_vru(rdev, R600_VRU_DFLT);
>> >> +     r600_vid_rt_set_vrt(rdev, R600_VOLTAGERESPONSETIME_DFLT);
>> >> +     r600_vid_rt_set_ssu(rdev, R600_SPLLSTEPUNIT_DFLT);
>> >> +
>> >> +     ret = rs780_initialize_dpm_power_state(rdev);
>> >> +
>> >> +     r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW,     0);
>> >> +     r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM,  0);
>> >> +     r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_HIGH,    0);
>> >> +
>> >> +     r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW,    0);
>> >> +     r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
>> >> +     r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_HIGH,   0);
>> >> +
>> >> +     r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW,    0);
>> >> +     r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
>> >> +     r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_HIGH,   0);
>> >> +
>> >> +     r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW,    R600_DISPLAY_WATERMARK_HIGH);
>> >> +     r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM, R600_DISPLAY_WATERMARK_HIGH);
>> >> +     r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_HIGH,   R600_DISPLAY_WATERMARK_HIGH);
>> >> +
>> >> +     r600_power_level_enable(rdev, R600_POWER_LEVEL_CTXSW, false);
>> >> +     r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false);
>> >> +     r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false);
>> >> +     r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
>> >> +
>> >> +     r600_power_level_set_enter_index(rdev, R600_POWER_LEVEL_LOW);
>> >> +
>> >> +     r600_set_vrc(rdev, RS780_CGFTV_DFLT);
>> >> +
>> >> +     return ret;
>> >> +}
>> >> +
>> >> +static void rs780_start_dpm(struct radeon_device *rdev)
>> >> +{
>> >> +     r600_enable_sclk_control(rdev, false);
>> >> +     r600_enable_mclk_control(rdev, false);
>> >> +
>> >> +     r600_dynamicpm_enable(rdev, true);
>> >> +
>> >> +     radeon_wait_for_vblank(rdev, 0);
>> >> +     radeon_wait_for_vblank(rdev, 1);
>> >> +
>> >> +     r600_enable_spll_bypass(rdev, true);
>> >> +     r600_wait_for_spll_change(rdev);
>> >> +     r600_enable_spll_bypass(rdev, false);
>> >> +     r600_wait_for_spll_change(rdev);
>> >> +
>> >> +     r600_enable_spll_bypass(rdev, true);
>> >> +     r600_wait_for_spll_change(rdev);
>> >> +     r600_enable_spll_bypass(rdev, false);
>> >> +     r600_wait_for_spll_change(rdev);
>> >> +
>> >> +     r600_enable_sclk_control(rdev, true);
>> >> +}
>> >> +
>> >> +
>> >> +static void rs780_preset_ranges_slow_clk_fbdiv_en(struct radeon_device *rdev)
>> >> +{
>> >> +     WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1, RANGE_SLOW_CLK_FEEDBACK_DIV_EN,
>> >> +              ~RANGE_SLOW_CLK_FEEDBACK_DIV_EN);
>> >> +
>> >> +     WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1,
>> >> +              RANGE0_SLOW_CLK_FEEDBACK_DIV(RS780_SLOWCLKFEEDBACKDIV_DFLT),
>> >> +              ~RANGE0_SLOW_CLK_FEEDBACK_DIV_MASK);
>> >> +}
>> >> +
>> >> +static void rs780_preset_starting_fbdiv(struct radeon_device *rdev)
>> >> +{
>> >> +     u32 fbdiv = (RREG32(CG_SPLL_FUNC_CNTL) & SPLL_FB_DIV_MASK) >> SPLL_FB_DIV_SHIFT;
>> >> +
>> >> +     WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(fbdiv),
>> >> +              ~STARTING_FEEDBACK_DIV_MASK);
>> >> +
>> >> +     WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(fbdiv),
>> >> +              ~FORCED_FEEDBACK_DIV_MASK);
>> >> +
>> >> +     WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
>> >> +}
>> >> +
>> >> +static void rs780_voltage_scaling_init(struct radeon_device *rdev)
>> >> +{
>> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> >> +     struct drm_device *dev = rdev->ddev;
>> >> +     u32 fv_throt_pwm_fb_div_range[3];
>> >> +     u32 fv_throt_pwm_range[4];
>> >> +
>> >> +     if (dev->pdev->device == 0x9614) {
>> >> +             fv_throt_pwm_fb_div_range[0] = RS780D_FVTHROTPWMFBDIVRANGEREG0_DFLT;
>> >> +             fv_throt_pwm_fb_div_range[1] = RS780D_FVTHROTPWMFBDIVRANGEREG1_DFLT;
>> >> +             fv_throt_pwm_fb_div_range[2] = RS780D_FVTHROTPWMFBDIVRANGEREG2_DFLT;
>> >> +     } else if ((dev->pdev->device == 0x9714) ||
>> >> +                (dev->pdev->device == 0x9715)) {
>> >> +             fv_throt_pwm_fb_div_range[0] = RS880D_FVTHROTPWMFBDIVRANGEREG0_DFLT;
>> >> +             fv_throt_pwm_fb_div_range[1] = RS880D_FVTHROTPWMFBDIVRANGEREG1_DFLT;
>> >> +             fv_throt_pwm_fb_div_range[2] = RS880D_FVTHROTPWMFBDIVRANGEREG2_DFLT;
>> >> +     } else {
>> >> +             fv_throt_pwm_fb_div_range[0] = RS780_FVTHROTPWMFBDIVRANGEREG0_DFLT;
>> >> +             fv_throt_pwm_fb_div_range[1] = RS780_FVTHROTPWMFBDIVRANGEREG1_DFLT;
>> >> +             fv_throt_pwm_fb_div_range[2] = RS780_FVTHROTPWMFBDIVRANGEREG2_DFLT;
>> >> +     }
>> >> +
>> >> +     if (pi->pwm_voltage_control) {
>> >> +             fv_throt_pwm_range[0] = pi->min_voltage;
>> >> +             fv_throt_pwm_range[1] = pi->min_voltage;
>> >> +             fv_throt_pwm_range[2] = pi->max_voltage;
>> >> +             fv_throt_pwm_range[3] = pi->max_voltage;
>> >> +     } else {
>> >> +             fv_throt_pwm_range[0] = pi->invert_pwm_required ?
>> >> +                     RS780_FVTHROTPWMRANGE3_GPIO_DFLT : RS780_FVTHROTPWMRANGE0_GPIO_DFLT;
>> >> +             fv_throt_pwm_range[1] = pi->invert_pwm_required ?
>> >> +                     RS780_FVTHROTPWMRANGE2_GPIO_DFLT : RS780_FVTHROTPWMRANGE1_GPIO_DFLT;
>> >> +             fv_throt_pwm_range[2] = pi->invert_pwm_required ?
>> >> +                     RS780_FVTHROTPWMRANGE1_GPIO_DFLT : RS780_FVTHROTPWMRANGE2_GPIO_DFLT;
>> >> +             fv_throt_pwm_range[3] = pi->invert_pwm_required ?
>> >> +                     RS780_FVTHROTPWMRANGE0_GPIO_DFLT : RS780_FVTHROTPWMRANGE3_GPIO_DFLT;
>> >> +     }
>> >> +
>> >> +     WREG32_P(FVTHROT_PWM_CTRL_REG0,
>> >> +              STARTING_PWM_HIGHTIME(pi->max_voltage),
>> >> +              ~STARTING_PWM_HIGHTIME_MASK);
>> >> +
>> >> +     WREG32_P(FVTHROT_PWM_CTRL_REG0,
>> >> +              NUMBER_OF_CYCLES_IN_PERIOD(pi->num_of_cycles_in_period),
>> >> +              ~NUMBER_OF_CYCLES_IN_PERIOD_MASK);
>> >> +
>> >> +     WREG32_P(FVTHROT_PWM_CTRL_REG0, FORCE_STARTING_PWM_HIGHTIME,
>> >> +              ~FORCE_STARTING_PWM_HIGHTIME);
>> >> +
>> >> +     if (pi->invert_pwm_required)
>> >> +             WREG32_P(FVTHROT_PWM_CTRL_REG0, INVERT_PWM_WAVEFORM, ~INVERT_PWM_WAVEFORM);
>> >> +     else
>> >> +             WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~INVERT_PWM_WAVEFORM);
>> >> +
>> >> +     rs780_voltage_scaling_enable(rdev, true);
>> >> +
>> >> +     WREG32(FVTHROT_PWM_CTRL_REG1,
>> >> +            (MIN_PWM_HIGHTIME(pi->min_voltage) |
>> >> +             MAX_PWM_HIGHTIME(pi->max_voltage)));
>> >> +
>> >> +     WREG32(FVTHROT_PWM_US_REG0, RS780_FVTHROTPWMUSREG0_DFLT);
>> >> +     WREG32(FVTHROT_PWM_US_REG1, RS780_FVTHROTPWMUSREG1_DFLT);
>> >> +     WREG32(FVTHROT_PWM_DS_REG0, RS780_FVTHROTPWMDSREG0_DFLT);
>> >> +     WREG32(FVTHROT_PWM_DS_REG1, RS780_FVTHROTPWMDSREG1_DFLT);
>> >> +
>> >> +     WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1,
>> >> +              RANGE0_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[0]),
>> >> +              ~RANGE0_PWM_FEEDBACK_DIV_MASK);
>> >> +
>> >> +     WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG2,
>> >> +            (RANGE1_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[1]) |
>> >> +             RANGE2_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[2])));
>> >> +
>> >> +     WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG3,
>> >> +            (RANGE0_PWM(fv_throt_pwm_range[1]) |
>> >> +             RANGE1_PWM(fv_throt_pwm_range[2])));
>> >> +     WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG4,
>> >> +            (RANGE2_PWM(fv_throt_pwm_range[1]) |
>> >> +             RANGE3_PWM(fv_throt_pwm_range[2])));
>> >> +}
>> >> +
>> >> +static void rs780_clk_scaling_enable(struct radeon_device *rdev, bool enable)
>> >> +{
>> >> +     if (enable)
>> >> +             WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT | ENABLE_FV_UPDATE,
>> >> +                      ~(ENABLE_FV_THROT | ENABLE_FV_UPDATE));
>> >> +     else
>> >> +             WREG32_P(FVTHROT_CNTRL_REG, 0,
>> >> +                      ~(ENABLE_FV_THROT | ENABLE_FV_UPDATE));
>> >> +}
>> >> +
>> >> +static void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable)
>> >> +{
>> >> +     if (enable)
>> >> +             WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT_IO, ~ENABLE_FV_THROT_IO);
>> >> +     else
>> >> +             WREG32_P(FVTHROT_CNTRL_REG, 0, ~ENABLE_FV_THROT_IO);
>> >> +}
>> >> +
>> >> +static void rs780_set_engine_clock_wfc(struct radeon_device *rdev)
>> >> +{
>> >> +     WREG32(FVTHROT_UTC0, RS780_FVTHROTUTC0_DFLT);
>> >> +     WREG32(FVTHROT_UTC1, RS780_FVTHROTUTC1_DFLT);
>> >> +     WREG32(FVTHROT_UTC2, RS780_FVTHROTUTC2_DFLT);
>> >> +     WREG32(FVTHROT_UTC3, RS780_FVTHROTUTC3_DFLT);
>> >> +     WREG32(FVTHROT_UTC4, RS780_FVTHROTUTC4_DFLT);
>> >> +
>> >> +     WREG32(FVTHROT_DTC0, RS780_FVTHROTDTC0_DFLT);
>> >> +     WREG32(FVTHROT_DTC1, RS780_FVTHROTDTC1_DFLT);
>> >> +     WREG32(FVTHROT_DTC2, RS780_FVTHROTDTC2_DFLT);
>> >> +     WREG32(FVTHROT_DTC3, RS780_FVTHROTDTC3_DFLT);
>> >> +     WREG32(FVTHROT_DTC4, RS780_FVTHROTDTC4_DFLT);
>> >> +}
>> >> +
>> >> +static void rs780_set_engine_clock_sc(struct radeon_device *rdev)
>> >> +{
>> >> +     WREG32_P(FVTHROT_FBDIV_REG2,
>> >> +              FB_DIV_TIMER_VAL(RS780_FBDIVTIMERVAL_DFLT),
>> >> +              ~FB_DIV_TIMER_VAL_MASK);
>> >> +
>> >> +     WREG32_P(FVTHROT_CNTRL_REG,
>> >> +              REFRESH_RATE_DIVISOR(0) | MINIMUM_CIP(0xf),
>> >> +              ~(REFRESH_RATE_DIVISOR_MASK | MINIMUM_CIP_MASK));
>> >> +}
>> >> +
>> >> +static void rs780_set_engine_clock_tdc(struct radeon_device *rdev)
>> >> +{
>> >> +     WREG32_P(FVTHROT_CNTRL_REG, 0, ~(FORCE_TREND_SEL | TREND_SEL_MODE));
>> >> +}
>> >> +
>> >> +static void rs780_set_engine_clock_ssc(struct radeon_device *rdev)
>> >> +{
>> >> +     WREG32(FVTHROT_FB_US_REG0, RS780_FVTHROTFBUSREG0_DFLT);
>> >> +     WREG32(FVTHROT_FB_US_REG1, RS780_FVTHROTFBUSREG1_DFLT);
>> >> +     WREG32(FVTHROT_FB_DS_REG0, RS780_FVTHROTFBDSREG0_DFLT);
>> >> +     WREG32(FVTHROT_FB_DS_REG1, RS780_FVTHROTFBDSREG1_DFLT);
>> >> +
>> >> +     WREG32_P(FVTHROT_FBDIV_REG1, MAX_FEEDBACK_STEP(1), ~MAX_FEEDBACK_STEP_MASK);
>> >> +}
>> >> +
>> >> +static void rs780_program_at(struct radeon_device *rdev)
>> >> +{
>> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> >> +
>> >> +     WREG32(FVTHROT_TARGET_REG, 30000000 / pi->refresh_rate);
>> >> +     WREG32(FVTHROT_CB1, 1000000 * 5 / pi->refresh_rate);
>> >> +     WREG32(FVTHROT_CB2, 1000000 * 10 / pi->refresh_rate);
>> >> +     WREG32(FVTHROT_CB3, 1000000 * 30 / pi->refresh_rate);
>> >> +     WREG32(FVTHROT_CB4, 1000000 * 50 / pi->refresh_rate);
>> >> +}
>> >> +
>> >> +static void rs780_disable_vbios_powersaving(struct radeon_device *rdev)
>> >> +{
>> >> +     WREG32_P(CG_INTGFX_MISC, 0, ~0xFFF00000);
>> >> +}
>> >> +
>> >> +static void rs780_force_voltage_to_high(struct radeon_device *rdev)
>> >> +{
>> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> >> +     struct igp_ps *current_state = rs780_get_ps(rdev->pm.dpm.current_ps);
>> >> +
>> >> +     if ((current_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
>> >> +         (current_state->min_voltage == RS780_VDDC_LEVEL_HIGH))
>> >> +             return;
>> >> +
>> >> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
>> >> +
>> >> +     udelay(1);
>> >> +
>> >> +     WREG32_P(FVTHROT_PWM_CTRL_REG0,
>> >> +              STARTING_PWM_HIGHTIME(pi->max_voltage),
>> >> +              ~STARTING_PWM_HIGHTIME_MASK);
>> >> +
>> >> +     WREG32_P(FVTHROT_PWM_CTRL_REG0,
>> >> +              FORCE_STARTING_PWM_HIGHTIME, ~FORCE_STARTING_PWM_HIGHTIME);
>> >> +
>> >> +     WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1, 0,
>> >> +             ~RANGE_PWM_FEEDBACK_DIV_EN);
>> >> +
>> >> +     udelay(1);
>> >> +
>> >> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
>> >> +}
>> >> +
>> >> +static int rs780_set_engine_clock_scaling(struct radeon_device *rdev)
>> >> +{
>> >> +     struct atom_clock_dividers min_dividers, max_dividers, current_max_dividers;
>> >> +     struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
>> >> +     struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
>> >> +     int ret;
>> >> +
>> >> +     if ((new_state->sclk_high == old_state->sclk_high) &&
>> >> +         (new_state->sclk_low == old_state->sclk_low))
>> >> +             return 0;
>> >> +
>> >> +     ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
>> >> +                                          new_state->sclk_low, false, &min_dividers);
>> >> +     if (ret)
>> >> +             return ret;
>> >> +
>> >> +     ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
>> >> +                                          new_state->sclk_high, false, &max_dividers);
>> >> +     if (ret)
>> >> +             return ret;
>> >> +
>> >> +     ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
>> >> +                                          old_state->sclk_high, false, &current_max_dividers);
>> >> +     if (ret)
>> >> +             return ret;
>> >> +
>> >> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
>> >> +
>> >> +     WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(max_dividers.fb_div),
>> >> +              ~FORCED_FEEDBACK_DIV_MASK);
>> >> +     WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(max_dividers.fb_div),
>> >> +              ~STARTING_FEEDBACK_DIV_MASK);
>> >> +     WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
>> >> +
>> >> +     udelay(100);
>> >> +
>> >> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
>> >> +
>> >> +     if (max_dividers.fb_div > min_dividers.fb_div) {
>> >> +             WREG32_P(FVTHROT_FBDIV_REG0,
>> >> +                      MIN_FEEDBACK_DIV(min_dividers.fb_div) |
>> >> +                      MAX_FEEDBACK_DIV(max_dividers.fb_div),
>> >> +                      ~(MIN_FEEDBACK_DIV_MASK | MAX_FEEDBACK_DIV_MASK));
>> >> +
>> >> +             WREG32_P(FVTHROT_FBDIV_REG1, 0, ~FORCE_FEEDBACK_DIV);
>> >> +     }
>> >> +
>> >> +     return 0;
>> >> +}
>> >> +
>> >> +static void rs780_set_engine_clock_spc(struct radeon_device *rdev)
>> >> +{
>> >> +     struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
>> >> +     struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
>> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> >> +
>> >> +     if ((new_state->sclk_high == old_state->sclk_high) &&
>> >> +         (new_state->sclk_low == old_state->sclk_low))
>> >> +             return;
>> >> +
>> >> +     if (pi->crtc_id == 0)
>> >> +             WREG32_P(CG_INTGFX_MISC, 0, ~FVTHROT_VBLANK_SEL);
>> >> +     else
>> >> +             WREG32_P(CG_INTGFX_MISC, FVTHROT_VBLANK_SEL, ~FVTHROT_VBLANK_SEL);
>> >> +
>> >> +}
>> >> +
>> >> +static void rs780_activate_engine_clk_scaling(struct radeon_device *rdev)
>> >> +{
>> >> +     struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
>> >> +     struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
>> >> +
>> >> +     if ((new_state->sclk_high == old_state->sclk_high) &&
>> >> +         (new_state->sclk_low == old_state->sclk_low))
>> >> +             return;
>> >> +
>> >> +     rs780_clk_scaling_enable(rdev, true);
>> >> +}
>> >> +
>> >> +static u32 rs780_get_voltage_for_vddc_level(struct radeon_device *rdev,
>> >> +                                         enum rs780_vddc_level vddc)
>> >> +{
>> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> >> +
>> >> +     if (vddc == RS780_VDDC_LEVEL_HIGH)
>> >> +             return pi->max_voltage;
>> >> +     else if (vddc == RS780_VDDC_LEVEL_LOW)
>> >> +             return pi->min_voltage;
>> >> +     else
>> >> +             return pi->max_voltage;
>> >> +}
>> >> +
>> >> +static void rs780_enable_voltage_scaling(struct radeon_device *rdev)
>> >> +{
>> >> +     struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
>> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> >> +     enum rs780_vddc_level vddc_high, vddc_low;
>> >> +
>> >> +     udelay(100);
>> >> +
>> >> +     if ((new_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
>> >> +         (new_state->min_voltage == RS780_VDDC_LEVEL_HIGH))
>> >> +             return;
>> >> +
>> >> +     vddc_high = rs780_get_voltage_for_vddc_level(rdev,
>> >> +                                                  new_state->max_voltage);
>> >> +     vddc_low = rs780_get_voltage_for_vddc_level(rdev,
>> >> +                                                 new_state->min_voltage);
>> >> +
>> >> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
>> >> +
>> >> +     udelay(1);
>> >> +     if (vddc_high > vddc_low) {
>> >> +             WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1,
>> >> +                      RANGE_PWM_FEEDBACK_DIV_EN, ~RANGE_PWM_FEEDBACK_DIV_EN);
>> >> +
>> >> +             WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~FORCE_STARTING_PWM_HIGHTIME);
>> >> +     } else if (vddc_high == vddc_low) {
>> >> +             if (pi->max_voltage != vddc_high) {
>> >> +                     WREG32_P(FVTHROT_PWM_CTRL_REG0,
>> >> +                              STARTING_PWM_HIGHTIME(vddc_high),
>> >> +                              ~STARTING_PWM_HIGHTIME_MASK);
>> >> +
>> >> +                     WREG32_P(FVTHROT_PWM_CTRL_REG0,
>> >> +                              FORCE_STARTING_PWM_HIGHTIME,
>> >> +                              ~FORCE_STARTING_PWM_HIGHTIME);
>> >> +             }
>> >> +     }
>> >> +
>> >> +     WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
>> >> +}
>> >> +
>> >> +int rs780_dpm_enable(struct radeon_device *rdev)
>> >> +{
>> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> >> +
>> >> +     rs780_get_pm_mode_parameters(rdev);
>> >> +     rs780_disable_vbios_powersaving(rdev);
>> >> +
>> >> +     if (r600_dynamicpm_enabled(rdev))
>> >> +             return -EINVAL;
>> >> +     if (rs780_initialize_dpm_parameters(rdev))
>> >> +             return -EINVAL;
>> >> +     rs780_start_dpm(rdev);
>> >> +
>> >> +     rs780_preset_ranges_slow_clk_fbdiv_en(rdev);
>> >> +     rs780_preset_starting_fbdiv(rdev);
>> >> +     if (pi->voltage_control)
>> >> +             rs780_voltage_scaling_init(rdev);
>> >> +     rs780_clk_scaling_enable(rdev, true);
>> >> +     rs780_set_engine_clock_sc(rdev);
>> >> +     rs780_set_engine_clock_wfc(rdev);
>> >> +     rs780_program_at(rdev);
>> >> +     rs780_set_engine_clock_tdc(rdev);
>> >> +     rs780_set_engine_clock_ssc(rdev);
>> >> +
>> >> +     if (pi->gfx_clock_gating)
>> >> +             r600_gfx_clockgating_enable(rdev, true);
>> >> +
>> >> +     return 0;
>> >> +}
>> >> +
>> >> +void rs780_dpm_disable(struct radeon_device *rdev)
>> >> +{
>> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> >> +
>> >> +     r600_dynamicpm_enable(rdev, false);
>> >> +
>> >> +     rs780_clk_scaling_enable(rdev, false);
>> >> +     rs780_voltage_scaling_enable(rdev, false);
>> >> +
>> >> +     if (pi->gfx_clock_gating)
>> >> +             r600_gfx_clockgating_enable(rdev, false);
>> >> +}
>> >> +
>> >> +int rs780_dpm_set_power_state(struct radeon_device *rdev)
>> >> +{
>> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> >> +
>> >> +     rs780_get_pm_mode_parameters(rdev);
>> >> +
>> >> +     if (pi->voltage_control) {
>> >> +             rs780_force_voltage_to_high(rdev);
>> >> +             mdelay(5);
>> >> +     }
>> >> +
>> >> +     rs780_set_engine_clock_scaling(rdev);
>> >> +     rs780_set_engine_clock_spc(rdev);
>> >> +
>> >> +     rs780_activate_engine_clk_scaling(rdev);
>> >> +
>> >> +     if (pi->voltage_control)
>> >> +             rs780_enable_voltage_scaling(rdev);
>> >> +
>> >> +     return 0;
>> >> +}
>> >> +
>> >> +void rs780_dpm_setup_asic(struct radeon_device *rdev)
>> >> +{
>> >> +
>> >> +}
>> >> +
>> >> +void rs780_dpm_display_configuration_changed(struct radeon_device *rdev)
>> >> +{
>> >> +     rs780_get_pm_mode_parameters(rdev);
>> >> +     rs780_program_at(rdev);
>> >> +}
>> >> +
>> >> +union igp_info {
>> >> +     struct _ATOM_INTEGRATED_SYSTEM_INFO info;
>> >> +     struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
>> >> +};
>> >> +
>> >> +union power_info {
>> >> +     struct _ATOM_POWERPLAY_INFO info;
>> >> +     struct _ATOM_POWERPLAY_INFO_V2 info_2;
>> >> +     struct _ATOM_POWERPLAY_INFO_V3 info_3;
>> >> +     struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
>> >> +     struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
>> >> +     struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
>> >> +};
>> >> +
>> >> +union pplib_clock_info {
>> >> +     struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
>> >> +     struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
>> >> +     struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
>> >> +     struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
>> >> +};
>> >> +
>> >> +union pplib_power_state {
>> >> +     struct _ATOM_PPLIB_STATE v1;
>> >> +     struct _ATOM_PPLIB_STATE_V2 v2;
>> >> +};
>> >> +
>> >> +static void 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)
>> >> +{
>> >> +     rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
>> >> +     rps->class = le16_to_cpu(non_clock_info->usClassification);
>> >> +     rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
>> >> +
>> >> +     if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
>> >> +             rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
>> >> +             rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
>> >> +     } else if (r600_is_uvd_state(rps->class, rps->class2)) {
>> >> +             rps->vclk = RS780_DEFAULT_VCLK_FREQ;
>> >> +             rps->dclk = RS780_DEFAULT_DCLK_FREQ;
>> >> +     } else {
>> >> +             rps->vclk = 0;
>> >> +             rps->dclk = 0;
>> >> +     }
>> >> +
>> >> +     if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
>> >> +             rdev->pm.dpm.boot_ps = rps;
>> >> +     if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
>> >> +             rdev->pm.dpm.uvd_ps = rps;
>> >> +}
>> >> +
>> >> +static void rs780_parse_pplib_clock_info(struct radeon_device *rdev,
>> >> +                                      struct radeon_ps *rps,
>> >> +                                      union pplib_clock_info *clock_info)
>> >> +{
>> >> +     struct igp_ps *ps = rs780_get_ps(rps);
>> >> +     u32 sclk;
>> >> +
>> >> +     sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow);
>> >> +     sclk |= clock_info->rs780.ucLowEngineClockHigh << 16;
>> >> +     ps->sclk_low = sclk;
>> >> +     sclk = le16_to_cpu(clock_info->rs780.usHighEngineClockLow);
>> >> +     sclk |= clock_info->rs780.ucHighEngineClockHigh << 16;
>> >> +     ps->sclk_high = sclk;
>> >> +     switch (le16_to_cpu(clock_info->rs780.usVDDC)) {
>> >> +     case ATOM_PPLIB_RS780_VOLTAGE_NONE:
>> >> +     default:
>> >> +             ps->min_voltage = RS780_VDDC_LEVEL_UNKNOWN;
>> >> +             ps->max_voltage = RS780_VDDC_LEVEL_UNKNOWN;
>> >> +             break;
>> >> +     case ATOM_PPLIB_RS780_VOLTAGE_LOW:
>> >> +             ps->min_voltage = RS780_VDDC_LEVEL_LOW;
>> >> +             ps->max_voltage = RS780_VDDC_LEVEL_LOW;
>> >> +             break;
>> >> +     case ATOM_PPLIB_RS780_VOLTAGE_HIGH:
>> >> +             ps->min_voltage = RS780_VDDC_LEVEL_HIGH;
>> >> +             ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
>> >> +             break;
>> >> +     case ATOM_PPLIB_RS780_VOLTAGE_VARIABLE:
>> >> +             ps->min_voltage = RS780_VDDC_LEVEL_LOW;
>> >> +             ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
>> >> +             break;
>> >> +     }
>> >> +     ps->flags = le32_to_cpu(clock_info->rs780.ulFlags);
>> >> +
>> >> +     if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
>> >> +             ps->sclk_low = rdev->clock.default_sclk;
>> >> +             ps->sclk_high = rdev->clock.default_sclk;
>> >> +             ps->min_voltage = RS780_VDDC_LEVEL_HIGH;
>> >> +             ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
>> >> +     }
>> >> +}
>> >> +
>> >> +static int rs780_parse_power_table(struct radeon_device *rdev)
>> >> +{
>> >> +     struct radeon_mode_info *mode_info = &rdev->mode_info;
>> >> +     struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
>> >> +     union pplib_power_state *power_state;
>> >> +     int i;
>> >> +     union pplib_clock_info *clock_info;
>> >> +     union power_info *power_info;
>> >> +     int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
>> >> +        u16 data_offset;
>> >> +     u8 frev, crev;
>> >> +     struct igp_ps *ps;
>> >> +
>> >> +     if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
>> >> +                                &frev, &crev, &data_offset))
>> >> +             return -EINVAL;
>> >> +     power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
>> >> +
>> >> +     rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
>> >> +                               power_info->pplib.ucNumStates, GFP_KERNEL);
>> >> +     if (!rdev->pm.dpm.ps)
>> >> +             return -ENOMEM;
>> >> +     rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
>> >> +     rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
>> >> +     rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
>> >> +
>> >> +     for (i = 0; i < power_info->pplib.ucNumStates; i++) {
>> >> +             power_state = (union pplib_power_state *)
>> >> +                     (mode_info->atom_context->bios + data_offset +
>> >> +                      le16_to_cpu(power_info->pplib.usStateArrayOffset) +
>> >> +                      i * power_info->pplib.ucStateEntrySize);
>> >> +             non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
>> >> +                     (mode_info->atom_context->bios + data_offset +
>> >> +                      le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
>> >> +                      (power_state->v1.ucNonClockStateIndex *
>> >> +                       power_info->pplib.ucNonClockSize));
>> >> +             if (power_info->pplib.ucStateEntrySize - 1) {
>> >> +                     clock_info = (union pplib_clock_info *)
>> >> +                             (mode_info->atom_context->bios + data_offset +
>> >> +                              le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
>> >> +                              (power_state->v1.ucClockStateIndices[0] *
>> >> +                               power_info->pplib.ucClockInfoSize));
>> >> +                     ps = kzalloc(sizeof(struct igp_ps), GFP_KERNEL);
>> >> +                     if (ps == NULL) {
>> >> +                             kfree(rdev->pm.dpm.ps);
>> >> +                             return -ENOMEM;
>> >> +                     }
>> >> +                     rdev->pm.dpm.ps[i].ps_priv = ps;
>> >> +                     rs780_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
>> >> +                                                      non_clock_info,
>> >> +                                                      power_info->pplib.ucNonClockSize);
>> >> +                     rs780_parse_pplib_clock_info(rdev,
>> >> +                                                  &rdev->pm.dpm.ps[i],
>> >> +                                                  clock_info);
>> >> +             }
>> >> +     }
>> >> +     rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates;
>> >> +     return 0;
>> >> +}
>> >> +
>> >> +int rs780_dpm_init(struct radeon_device *rdev)
>> >> +{
>> >> +     struct igp_power_info *pi;
>> >> +     int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
>> >> +     union igp_info *info;
>> >> +     u16 data_offset;
>> >> +     u8 frev, crev;
>> >> +     int ret;
>> >> +
>> >> +     pi = kzalloc(sizeof(struct igp_power_info), GFP_KERNEL);
>> >> +     if (pi == NULL)
>> >> +             return -ENOMEM;
>> >> +     rdev->pm.dpm.priv = pi;
>> >> +
>> >> +     ret = rs780_parse_power_table(rdev);
>> >> +     if (ret)
>> >> +             return ret;
>> >> +
>> >> +     pi->voltage_control = false;
>> >> +     pi->gfx_clock_gating = true;
>> >> +
>> >> +     if (atom_parse_data_header(rdev->mode_info.atom_context, index, NULL,
>> >> +                                &frev, &crev, &data_offset)) {
>> >> +             info = (union igp_info *)(rdev->mode_info.atom_context->bios + data_offset);
>> >> +
>> >> +             /* Get various system informations from bios */
>> >> +             switch (crev) {
>> >> +             case 1:
>> >> +                     pi->num_of_cycles_in_period =
>> >> +                             info->info.ucNumberOfCyclesInPeriod;
>> >> +                     pi->num_of_cycles_in_period |=
>> >> +                             info->info.ucNumberOfCyclesInPeriodHi << 8;
>> >> +                     pi->invert_pwm_required =
>> >> +                             (pi->num_of_cycles_in_period & 0x8000) ? true : false;
>> >> +                     pi->boot_voltage = info->info.ucStartingPWM_HighTime;
>> >> +                     pi->max_voltage = info->info.ucMaxNBVoltage;
>> >> +                     pi->max_voltage |= info->info.ucMaxNBVoltageHigh << 8;
>> >> +                     pi->min_voltage = info->info.ucMinNBVoltage;
>> >> +                     pi->min_voltage |= info->info.ucMinNBVoltageHigh << 8;
>> >> +                     pi->inter_voltage_low =
>> >> +                             le16_to_cpu(info->info.usInterNBVoltageLow);
>> >> +                     pi->inter_voltage_high =
>> >> +                             le16_to_cpu(info->info.usInterNBVoltageHigh);
>> >> +                     pi->voltage_control = true;
>> >> +                     pi->bootup_uma_clk = info->info.usK8MemoryClock * 100;
>> >> +                     break;
>> >> +             case 2:
>> >> +                     pi->num_of_cycles_in_period =
>> >> +                             le16_to_cpu(info->info_2.usNumberOfCyclesInPeriod);
>> >> +                     pi->invert_pwm_required =
>> >> +                             (pi->num_of_cycles_in_period & 0x8000) ? true : false;
>> >> +                     pi->boot_voltage =
>> >> +                             le16_to_cpu(info->info_2.usBootUpNBVoltage);
>> >> +                     pi->max_voltage =
>> >> +                             le16_to_cpu(info->info_2.usMaxNBVoltage);
>> >> +                     pi->min_voltage =
>> >> +                             le16_to_cpu(info->info_2.usMinNBVoltage);
>> >> +                     pi->system_config =
>> >> +                             le32_to_cpu(info->info_2.ulSystemConfig);
>> >> +                     pi->pwm_voltage_control =
>> >> +                             (pi->system_config & 0x4) ? true : false;
>> >> +                     pi->voltage_control = true;
>> >> +                     pi->bootup_uma_clk = le32_to_cpu(info->info_2.ulBootUpUMAClock);
>> >> +                     break;
>> >> +             default:
>> >> +                     DRM_ERROR("No integrated system info for your GPU\n");
>> >> +                     return -EINVAL;
>> >> +             }
>> >> +             if (pi->min_voltage > pi->max_voltage)
>> >> +                     pi->voltage_control = false;
>> >> +             if (pi->pwm_voltage_control) {
>> >> +                     if ((pi->num_of_cycles_in_period == 0) ||
>> >> +                         (pi->max_voltage == 0) ||
>> >> +                         (pi->min_voltage == 0))
>> >> +                             pi->voltage_control = false;
>> >> +             } else {
>> >> +                     if ((pi->num_of_cycles_in_period == 0) ||
>> >> +                         (pi->max_voltage == 0))
>> >> +                             pi->voltage_control = false;
>> >> +             }
>> >> +
>> >> +             return 0;
>> >> +     }
>> >> +     radeon_dpm_fini(rdev);
>> >> +     return -EINVAL;
>> >> +}
>> >> +
>> >> +void rs780_dpm_print_power_state(struct radeon_device *rdev,
>> >> +                              struct radeon_ps *rps)
>> >> +{
>> >> +     struct igp_ps *ps = rs780_get_ps(rps);
>> >> +
>> >> +     r600_dpm_print_class_info(rps->class, rps->class2);
>> >> +     r600_dpm_print_cap_info(rps->caps);
>> >> +     printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
>> >> +     printk("\t\tpower level 0    sclk: %u vddc_index: %d\n",
>> >> +            ps->sclk_low, ps->min_voltage);
>> >> +     printk("\t\tpower level 1    sclk: %u vddc_index: %d\n",
>> >> +            ps->sclk_high, ps->max_voltage);
>> >> +     r600_dpm_print_ps_status(rdev, rps);
>> >> +}
>> >> +
>> >> +void rs780_dpm_fini(struct radeon_device *rdev)
>> >> +{
>> >> +     int i;
>> >> +
>> >> +     for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
>> >> +             kfree(rdev->pm.dpm.ps[i].ps_priv);
>> >> +     }
>> >> +     kfree(rdev->pm.dpm.ps);
>> >> +     kfree(rdev->pm.dpm.priv);
>> >> +}
>> >> +
>> >> +u32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low)
>> >> +{
>> >> +     struct igp_ps *requested_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
>> >> +
>> >> +     if (low)
>> >> +             return requested_state->sclk_low;
>> >> +     else
>> >> +             return requested_state->sclk_high;
>> >> +}
>> >> +
>> >> +u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low)
>> >> +{
>> >> +     struct igp_power_info *pi = rs780_get_pi(rdev);
>> >> +
>> >> +     return pi->bootup_uma_clk;
>> >> +}
>> >> diff --git a/drivers/gpu/drm/radeon/rs780_dpm.h b/drivers/gpu/drm/radeon/rs780_dpm.h
>> >> new file mode 100644
>> >> index 0000000..47a40b1
>> >> --- /dev/null
>> >> +++ b/drivers/gpu/drm/radeon/rs780_dpm.h
>> >> @@ -0,0 +1,109 @@
>> >> +/*
>> >> + * Copyright 2011 Advanced Micro Devices, Inc.
>> >> + *
>> >> + * Permission is hereby granted, free of charge, to any person obtaining a
>> >> + * copy of this software and associated documentation files (the "Software"),
>> >> + * to deal in the Software without restriction, including without limitation
>> >> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> >> + * and/or sell copies of the Software, and to permit persons to whom the
>> >> + * Software is furnished to do so, subject to the following conditions:
>> >> + *
>> >> + * The above copyright notice and this permission notice shall be included in
>> >> + * all copies or substantial portions of the Software.
>> >> + *
>> >> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> >> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> >> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> >> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
>> >> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>> >> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>> >> + * OTHER DEALINGS IN THE SOFTWARE.
>> >> + *
>> >> + */
>> >> +#ifndef __RS780_DPM_H__
>> >> +#define __RS780_DPM_H__
>> >> +
>> >> +enum rs780_vddc_level {
>> >> +     RS780_VDDC_LEVEL_UNKNOWN = 0,
>> >> +     RS780_VDDC_LEVEL_LOW = 1,
>> >> +     RS780_VDDC_LEVEL_HIGH = 2,
>> >> +};
>> >> +
>> >> +struct igp_power_info {
>> >> +     /* flags */
>> >> +     bool invert_pwm_required;
>> >> +     bool pwm_voltage_control;
>> >> +     bool voltage_control;
>> >> +     bool gfx_clock_gating;
>> >> +     /* stored values */
>> >> +     u32 system_config;
>> >> +     u32 bootup_uma_clk;
>> >> +     u16 max_voltage;
>> >> +     u16 min_voltage;
>> >> +     u16 boot_voltage;
>> >> +     u16 inter_voltage_low;
>> >> +     u16 inter_voltage_high;
>> >> +     u16 num_of_cycles_in_period;
>> >> +     /* variable */
>> >> +     int crtc_id;
>> >> +     int refresh_rate;
>> >> +};
>> >> +
>> >> +struct igp_ps {
>> >> +     enum rs780_vddc_level min_voltage;
>> >> +     enum rs780_vddc_level max_voltage;
>> >> +     u32 sclk_low;
>> >> +     u32 sclk_high;
>> >> +     u32 flags;
>> >> +};
>> >> +
>> >> +#define RS780_CGFTV_DFLT                 0x0303000f
>> >> +#define RS780_FBDIVTIMERVAL_DFLT         0x2710
>> >> +
>> >> +#define RS780_FVTHROTUTC0_DFLT   0x04010040
>> >> +#define RS780_FVTHROTUTC1_DFLT   0x04010040
>> >> +#define RS780_FVTHROTUTC2_DFLT   0x04010040
>> >> +#define RS780_FVTHROTUTC3_DFLT   0x04010040
>> >> +#define RS780_FVTHROTUTC4_DFLT   0x04010040
>> >> +
>> >> +#define RS780_FVTHROTDTC0_DFLT 0x04010040
>> >> +#define RS780_FVTHROTDTC1_DFLT 0x04010040
>> >> +#define RS780_FVTHROTDTC2_DFLT 0x04010040
>> >> +#define RS780_FVTHROTDTC3_DFLT 0x04010040
>> >> +#define RS780_FVTHROTDTC4_DFLT 0x04010040
>> >> +
>> >> +#define RS780_FVTHROTFBUSREG0_DFLT       0x00001001
>> >> +#define RS780_FVTHROTFBUSREG1_DFLT       0x00002002
>> >> +#define RS780_FVTHROTFBDSREG0_DFLT       0x00004001
>> >> +#define RS780_FVTHROTFBDSREG1_DFLT       0x00020010
>> >> +
>> >> +#define RS780_FVTHROTPWMUSREG0_DFLT      0x00002001
>> >> +#define RS780_FVTHROTPWMUSREG1_DFLT      0x00004003
>> >> +#define RS780_FVTHROTPWMDSREG0_DFLT      0x00002001
>> >> +#define RS780_FVTHROTPWMDSREG1_DFLT      0x00004003
>> >> +
>> >> +#define RS780_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x37
>> >> +#define RS780_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x4b
>> >> +#define RS780_FVTHROTPWMFBDIVRANGEREG2_DFLT  0x8b
>> >> +
>> >> +#define RS780D_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x8b
>> >> +#define RS780D_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x8c
>> >> +#define RS780D_FVTHROTPWMFBDIVRANGEREG2_DFLT  0xb5
>> >> +
>> >> +#define RS880D_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x8d
>> >> +#define RS880D_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x8e
>> >> +#define RS880D_FVTHROTPWMFBDIVRANGEREG2_DFLT  0xBa
>> >> +
>> >> +#define RS780_FVTHROTPWMRANGE0_GPIO_DFLT  0x1a
>> >> +#define RS780_FVTHROTPWMRANGE1_GPIO_DFLT  0x1a
>> >> +#define RS780_FVTHROTPWMRANGE2_GPIO_DFLT  0x0
>> >> +#define RS780_FVTHROTPWMRANGE3_GPIO_DFLT  0x0
>> >> +
>> >> +#define RS780_SLOWCLKFEEDBACKDIV_DFLT 110
>> >> +
>> >> +#define RS780_CGCLKGATING_DFLT           0x0000E204
>> >> +
>> >> +#define RS780_DEFAULT_VCLK_FREQ  53300 /* 10 khz */
>> >> +#define RS780_DEFAULT_DCLK_FREQ  40000 /* 10 khz */
>> >> +
>> >> +#endif
>> >> diff --git a/drivers/gpu/drm/radeon/rs780d.h b/drivers/gpu/drm/radeon/rs780d.h
>> >> new file mode 100644
>> >> index 0000000..b1142ed
>> >> --- /dev/null
>> >> +++ b/drivers/gpu/drm/radeon/rs780d.h
>> >> @@ -0,0 +1,168 @@
>> >> +/*
>> >> + * Copyright 2011 Advanced Micro Devices, Inc.
>> >> + *
>> >> + * Permission is hereby granted, free of charge, to any person obtaining a
>> >> + * copy of this software and associated documentation files (the "Software"),
>> >> + * to deal in the Software without restriction, including without limitation
>> >> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> >> + * and/or sell copies of the Software, and to permit persons to whom the
>> >> + * Software is furnished to do so, subject to the following conditions:
>> >> + *
>> >> + * The above copyright notice and this permission notice shall be included in
>> >> + * all copies or substantial portions of the Software.
>> >> + *
>> >> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> >> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> >> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> >> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
>> >> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>> >> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>> >> + * OTHER DEALINGS IN THE SOFTWARE.
>> >> + *
>> >> + */
>> >> +#ifndef __RS780D_H__
>> >> +#define __RS780D_H__
>> >> +
>> >> +#define CG_SPLL_FUNC_CNTL                                 0x600
>> >> +#       define SPLL_RESET                                (1 << 0)
>> >> +#       define SPLL_SLEEP                                (1 << 1)
>> >> +#       define SPLL_REF_DIV(x)                           ((x) << 2)
>> >> +#       define SPLL_REF_DIV_MASK                         (7 << 2)
>> >> +#       define SPLL_FB_DIV(x)                            ((x) << 5)
>> >> +#       define SPLL_FB_DIV_MASK                          (0xff << 2)
>> >> +#       define SPLL_FB_DIV_SHIFT                         2
>> >> +#       define SPLL_PULSEEN                              (1 << 13)
>> >> +#       define SPLL_PULSENUM(x)                          ((x) << 14)
>> >> +#       define SPLL_PULSENUM_MASK                        (3 << 14)
>> >> +#       define SPLL_SW_HILEN(x)                          ((x) << 16)
>> >> +#       define SPLL_SW_HILEN_MASK                        (0xf << 16)
>> >> +#       define SPLL_SW_LOLEN(x)                          ((x) << 20)
>> >> +#       define SPLL_SW_LOLEN_MASK                        (0xf << 20)
>> >> +#       define SPLL_DIVEN                                (1 << 24)
>> >> +#       define SPLL_BYPASS_EN                            (1 << 25)
>> >> +#       define SPLL_CHG_STATUS                           (1 << 29)
>> >> +#       define SPLL_CTLREQ                               (1 << 30)
>> >> +#       define SPLL_CTLACK                               (1 << 31)
>> >> +
>> >> +/* RS780/RS880 PM */
>> >> +#define      FVTHROT_CNTRL_REG                               0x3000
>> >> +#define              DONT_WAIT_FOR_FBDIV_WRAP                (1 << 0)
>> >> +#define              MINIMUM_CIP(x)                          ((x) << 1)
>> >> +#define              MINIMUM_CIP_SHIFT                       1
>> >> +#define              MINIMUM_CIP_MASK                        0x1fffffe
>> >> +#define              REFRESH_RATE_DIVISOR(x)                 ((x) << 25)
>> >> +#define              REFRESH_RATE_DIVISOR_SHIFT              25
>> >> +#define              REFRESH_RATE_DIVISOR_MASK               (0x3 << 25)
>> >> +#define              ENABLE_FV_THROT                         (1 << 27)
>> >> +#define              ENABLE_FV_UPDATE                        (1 << 28)
>> >> +#define              TREND_SEL_MODE                          (1 << 29)
>> >> +#define              FORCE_TREND_SEL                         (1 << 30)
>> >> +#define              ENABLE_FV_THROT_IO                      (1 << 31)
>> >> +#define      FVTHROT_TARGET_REG                              0x3004
>> >> +#define              TARGET_IDLE_COUNT(x)                    ((x) << 0)
>> >> +#define              TARGET_IDLE_COUNT_MASK                  0xffffff
>> >> +#define              TARGET_IDLE_COUNT_SHIFT                 0
>> >> +#define      FVTHROT_CB1                                     0x3008
>> >> +#define      FVTHROT_CB2                                     0x300c
>> >> +#define      FVTHROT_CB3                                     0x3010
>> >> +#define      FVTHROT_CB4                                     0x3014
>> >> +#define      FVTHROT_UTC0                                    0x3018
>> >> +#define      FVTHROT_UTC1                                    0x301c
>> >> +#define      FVTHROT_UTC2                                    0x3020
>> >> +#define      FVTHROT_UTC3                                    0x3024
>> >> +#define      FVTHROT_UTC4                                    0x3028
>> >> +#define      FVTHROT_DTC0                                    0x302c
>> >> +#define      FVTHROT_DTC1                                    0x3030
>> >> +#define      FVTHROT_DTC2                                    0x3034
>> >> +#define      FVTHROT_DTC3                                    0x3038
>> >> +#define      FVTHROT_DTC4                                    0x303c
>> >> +#define      FVTHROT_FBDIV_REG0                              0x3040
>> >> +#define              MIN_FEEDBACK_DIV(x)                     ((x) << 0)
>> >> +#define              MIN_FEEDBACK_DIV_MASK                   0xfff
>> >> +#define              MIN_FEEDBACK_DIV_SHIFT                  0
>> >> +#define              MAX_FEEDBACK_DIV(x)                     ((x) << 12)
>> >> +#define              MAX_FEEDBACK_DIV_MASK                   (0xfff << 12)
>> >> +#define              MAX_FEEDBACK_DIV_SHIFT                  12
>> >> +#define      FVTHROT_FBDIV_REG1                              0x3044
>> >> +#define              MAX_FEEDBACK_STEP(x)                    ((x) << 0)
>> >> +#define              MAX_FEEDBACK_STEP_MASK                  0xfff
>> >> +#define              MAX_FEEDBACK_STEP_SHIFT                 0
>> >> +#define              STARTING_FEEDBACK_DIV(x)                ((x) << 12)
>> >> +#define              STARTING_FEEDBACK_DIV_MASK              (0xfff << 12)
>> >> +#define              STARTING_FEEDBACK_DIV_SHIFT             12
>> >> +#define              FORCE_FEEDBACK_DIV                      (1 << 24)
>> >> +#define      FVTHROT_FBDIV_REG2                              0x3048
>> >> +#define              FORCED_FEEDBACK_DIV(x)                  ((x) << 0)
>> >> +#define              FORCED_FEEDBACK_DIV_MASK                0xfff
>> >> +#define              FORCED_FEEDBACK_DIV_SHIFT               0
>> >> +#define              FB_DIV_TIMER_VAL(x)                     ((x) << 12)
>> >> +#define              FB_DIV_TIMER_VAL_MASK                   (0xffff << 12)
>> >> +#define              FB_DIV_TIMER_VAL_SHIFT                  12
>> >> +#define      FVTHROT_FB_US_REG0                              0x304c
>> >> +#define      FVTHROT_FB_US_REG1                              0x3050
>> >> +#define      FVTHROT_FB_DS_REG0                              0x3054
>> >> +#define      FVTHROT_FB_DS_REG1                              0x3058
>> >> +#define      FVTHROT_PWM_CTRL_REG0                           0x305c
>> >> +#define              STARTING_PWM_HIGHTIME(x)                ((x) << 0)
>> >> +#define              STARTING_PWM_HIGHTIME_MASK              0xfff
>> >> +#define              STARTING_PWM_HIGHTIME_SHIFT             0
>> >> +#define              NUMBER_OF_CYCLES_IN_PERIOD(x)           ((x) << 12)
>> >> +#define              NUMBER_OF_CYCLES_IN_PERIOD_MASK         (0xfff << 12)
>> >> +#define              NUMBER_OF_CYCLES_IN_PERIOD_SHIFT        12
>> >> +#define              FORCE_STARTING_PWM_HIGHTIME             (1 << 24)
>> >> +#define              INVERT_PWM_WAVEFORM                     (1 << 25)
>> >> +#define      FVTHROT_PWM_CTRL_REG1                           0x3060
>> >> +#define              MIN_PWM_HIGHTIME(x)                     ((x) << 0)
>> >> +#define              MIN_PWM_HIGHTIME_MASK                   0xfff
>> >> +#define              MIN_PWM_HIGHTIME_SHIFT                  0
>> >> +#define              MAX_PWM_HIGHTIME(x)                     ((x) << 12)
>> >> +#define              MAX_PWM_HIGHTIME_MASK                   (0xfff << 12)
>> >> +#define              MAX_PWM_HIGHTIME_SHIFT                  12
>> >> +#define      FVTHROT_PWM_US_REG0                             0x3064
>> >> +#define      FVTHROT_PWM_US_REG1                             0x3068
>> >> +#define      FVTHROT_PWM_DS_REG0                             0x306c
>> >> +#define      FVTHROT_PWM_DS_REG1                             0x3070
>> >> +#define      FVTHROT_STATUS_REG0                             0x3074
>> >> +#define              CURRENT_FEEDBACK_DIV_MASK               0xfff
>> >> +#define              CURRENT_FEEDBACK_DIV_SHIFT              0
>> >> +#define      FVTHROT_STATUS_REG1                             0x3078
>> >> +#define      FVTHROT_STATUS_REG2                             0x307c
>> >> +#define      CG_INTGFX_MISC                                  0x3080
>> >> +#define              FVTHROT_VBLANK_SEL                      (1 << 9)
>> >> +#define      FVTHROT_PWM_FEEDBACK_DIV_REG1                   0x308c
>> >> +#define              RANGE0_PWM_FEEDBACK_DIV(x)              ((x) << 0)
>> >> +#define              RANGE0_PWM_FEEDBACK_DIV_MASK            0xfff
>> >> +#define              RANGE0_PWM_FEEDBACK_DIV_SHIFT           0
>> >> +#define              RANGE_PWM_FEEDBACK_DIV_EN               (1 << 12)
>> >> +#define      FVTHROT_PWM_FEEDBACK_DIV_REG2                   0x3090
>> >> +#define              RANGE1_PWM_FEEDBACK_DIV(x)              ((x) << 0)
>> >> +#define              RANGE1_PWM_FEEDBACK_DIV_MASK            0xfff
>> >> +#define              RANGE1_PWM_FEEDBACK_DIV_SHIFT           0
>> >> +#define              RANGE2_PWM_FEEDBACK_DIV(x)              ((x) << 12)
>> >> +#define              RANGE2_PWM_FEEDBACK_DIV_MASK            (0xfff << 12)
>> >> +#define              RANGE2_PWM_FEEDBACK_DIV_SHIFT           12
>> >> +#define      FVTHROT_PWM_FEEDBACK_DIV_REG3                   0x3094
>> >> +#define              RANGE0_PWM(x)                           ((x) << 0)
>> >> +#define              RANGE0_PWM_MASK                         0xfff
>> >> +#define              RANGE0_PWM_SHIFT                        0
>> >> +#define              RANGE1_PWM(x)                           ((x) << 12)
>> >> +#define              RANGE1_PWM_MASK                         (0xfff << 12)
>> >> +#define              RANGE1_PWM_SHIFT                        12
>> >> +#define      FVTHROT_PWM_FEEDBACK_DIV_REG4                   0x3098
>> >> +#define              RANGE2_PWM(x)                           ((x) << 0)
>> >> +#define              RANGE2_PWM_MASK                         0xfff
>> >> +#define              RANGE2_PWM_SHIFT                        0
>> >> +#define              RANGE3_PWM(x)                           ((x) << 12)
>> >> +#define              RANGE3_PWM_MASK                         (0xfff << 12)
>> >> +#define              RANGE3_PWM_SHIFT                        12
>> >> +#define      FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1              0x30ac
>> >> +#define              RANGE0_SLOW_CLK_FEEDBACK_DIV(x)         ((x) << 0)
>> >> +#define              RANGE0_SLOW_CLK_FEEDBACK_DIV_MASK       0xfff
>> >> +#define              RANGE0_SLOW_CLK_FEEDBACK_DIV_SHIFT      0
>> >> +#define              RANGE_SLOW_CLK_FEEDBACK_DIV_EN          (1 << 12)
>> >> +
>> >> +#define      GFX_MACRO_BYPASS_CNTL                           0x30c0
>> >> +#define              SPLL_BYPASS_CNTL                        (1 << 0)
>> >> +#define              UPLL_BYPASS_CNTL                        (1 << 1)
>> >> +
>> >> +#endif
>> >> --
>> >> 1.7.7.5
>> >>
>> >> _______________________________________________
>> >> dri-devel mailing list
>> >> dri-devel@lists.freedesktop.org
>> >> http://lists.freedesktop.org/mailman/listinfo/dri-devel
diff mbox

Patch

diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
index a131a13..e44b046 100644
--- a/drivers/gpu/drm/radeon/Makefile
+++ b/drivers/gpu/drm/radeon/Makefile
@@ -77,7 +77,7 @@  radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
 	evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \
 	atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
 	si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \
-	r600_dpm.o
+	r600_dpm.o rs780_dpm.o
 
 radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
 radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index d9c8e9a..db3c930 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -1194,6 +1194,18 @@  static struct radeon_asic rs780_asic = {
 		.set_clock_gating = NULL,
 		.get_temperature = &rv6xx_get_temp,
 	},
+	.dpm = {
+		.init = &rs780_dpm_init,
+		.setup_asic = &rs780_dpm_setup_asic,
+		.enable = &rs780_dpm_enable,
+		.disable = &rs780_dpm_disable,
+		.set_power_state = &rs780_dpm_set_power_state,
+		.display_configuration_changed = &rs780_dpm_display_configuration_changed,
+		.fini = &rs780_dpm_fini,
+		.get_sclk = &rs780_dpm_get_sclk,
+		.get_mclk = &rs780_dpm_get_mclk,
+		.print_power_state = &rs780_dpm_print_power_state,
+	},
 	.pflip = {
 		.pre_page_flip = &rs600_pre_page_flip,
 		.page_flip = &rs600_page_flip,
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 8507cae..134bf57 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -396,6 +396,18 @@  int r600_mc_wait_for_idle(struct radeon_device *rdev);
 u32 r600_get_xclk(struct radeon_device *rdev);
 uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev);
 int rv6xx_get_temp(struct radeon_device *rdev);
+/* rs780 dpm */
+int rs780_dpm_init(struct radeon_device *rdev);
+int rs780_dpm_enable(struct radeon_device *rdev);
+void rs780_dpm_disable(struct radeon_device *rdev);
+int rs780_dpm_set_power_state(struct radeon_device *rdev);
+void rs780_dpm_setup_asic(struct radeon_device *rdev);
+void rs780_dpm_display_configuration_changed(struct radeon_device *rdev);
+void rs780_dpm_fini(struct radeon_device *rdev);
+u32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low);
+u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low);
+void rs780_dpm_print_power_state(struct radeon_device *rdev,
+				 struct radeon_ps *ps);
 
 /* uvd */
 int r600_uvd_init(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 4f5422e..853a8a2 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -1030,6 +1030,13 @@  int radeon_pm_init(struct radeon_device *rdev)
 {
 	/* enable dpm on rv6xx+ */
 	switch (rdev->family) {
+	case CHIP_RS780:
+	case CHIP_RS880:
+		if (radeon_dpm == 1)
+			rdev->pm.pm_method = PM_METHOD_DPM;
+		else
+			rdev->pm.pm_method = PM_METHOD_PROFILE;
+		break;
 	default:
 		/* default to profile method */
 		rdev->pm.pm_method = PM_METHOD_PROFILE;
diff --git a/drivers/gpu/drm/radeon/rs780_dpm.c b/drivers/gpu/drm/radeon/rs780_dpm.c
new file mode 100644
index 0000000..f594900
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rs780_dpm.c
@@ -0,0 +1,894 @@ 
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Alex Deucher
+ */
+
+#include "drmP.h"
+#include "radeon.h"
+#include "rs780d.h"
+#include "r600_dpm.h"
+#include "rs780_dpm.h"
+#include "atom.h"
+
+static struct igp_ps *rs780_get_ps(struct radeon_ps *rps)
+{
+	struct igp_ps *ps = rps->ps_priv;
+
+	return ps;
+}
+
+static struct igp_power_info *rs780_get_pi(struct radeon_device *rdev)
+{
+	struct igp_power_info *pi = rdev->pm.dpm.priv;
+
+	return pi;
+}
+
+static void rs780_get_pm_mode_parameters(struct radeon_device *rdev)
+{
+	struct igp_power_info *pi = rs780_get_pi(rdev);
+	struct radeon_mode_info *minfo = &rdev->mode_info;
+	struct drm_crtc *crtc;
+	struct radeon_crtc *radeon_crtc;
+	int i;
+
+	/* defaults */
+	pi->crtc_id = 0;
+	pi->refresh_rate = 60;
+
+	for (i = 0; i < rdev->num_crtc; i++) {
+		crtc = (struct drm_crtc *)minfo->crtcs[i];
+		if (crtc && crtc->enabled) {
+			radeon_crtc = to_radeon_crtc(crtc);
+			pi->crtc_id = radeon_crtc->crtc_id;
+			if (crtc->mode.htotal && crtc->mode.vtotal)
+				pi->refresh_rate =
+					(crtc->mode.clock * 1000) /
+					(crtc->mode.htotal * crtc->mode.vtotal);
+			break;
+		}
+	}
+}
+
+static void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable);
+
+static int rs780_initialize_dpm_power_state(struct radeon_device *rdev)
+{
+	struct atom_clock_dividers dividers;
+	struct igp_ps *default_state = rs780_get_ps(rdev->pm.dpm.boot_ps);
+	int i, ret;
+
+	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+					     default_state->sclk_low, false, &dividers);
+	if (ret)
+		return ret;
+
+	r600_engine_clock_entry_set_reference_divider(rdev, 0, dividers.ref_div);
+	r600_engine_clock_entry_set_feedback_divider(rdev, 0, dividers.fb_div);
+	r600_engine_clock_entry_set_post_divider(rdev, 0, dividers.post_div);
+
+	if (dividers.enable_post_div)
+		r600_engine_clock_entry_enable_post_divider(rdev, 0, true);
+	else
+		r600_engine_clock_entry_enable_post_divider(rdev, 0, false);
+
+	r600_engine_clock_entry_set_step_time(rdev, 0, R600_SST_DFLT);
+	r600_engine_clock_entry_enable_pulse_skipping(rdev, 0, false);
+
+	r600_engine_clock_entry_enable(rdev, 0, true);
+	for (i = 1; i < R600_PM_NUMBER_OF_SCLKS; i++)
+		r600_engine_clock_entry_enable(rdev, i, false);
+
+	r600_enable_mclk_control(rdev, false);
+	r600_voltage_control_enable_pins(rdev, 0);
+
+	return 0;
+}
+
+static int rs780_initialize_dpm_parameters(struct radeon_device *rdev)
+{
+	int ret = 0;
+	int i;
+
+	r600_set_bsp(rdev, R600_BSU_DFLT, R600_BSP_DFLT);
+
+	r600_set_at(rdev, 0, 0, 0, 0);
+
+	r600_set_git(rdev, R600_GICST_DFLT);
+
+	for (i = 0; i < R600_PM_NUMBER_OF_TC; i++)
+		r600_set_tc(rdev, i, 0, 0);
+
+	r600_select_td(rdev, R600_TD_DFLT);
+	r600_set_vrc(rdev, 0);
+
+	r600_set_tpu(rdev, R600_TPU_DFLT);
+	r600_set_tpc(rdev, R600_TPC_DFLT);
+
+	r600_set_sstu(rdev, R600_SSTU_DFLT);
+	r600_set_sst(rdev, R600_SST_DFLT);
+
+	r600_set_fctu(rdev, R600_FCTU_DFLT);
+	r600_set_fct(rdev, R600_FCT_DFLT);
+
+	r600_set_vddc3d_oorsu(rdev, R600_VDDC3DOORSU_DFLT);
+	r600_set_vddc3d_oorphc(rdev, R600_VDDC3DOORPHC_DFLT);
+	r600_set_vddc3d_oorsdc(rdev, R600_VDDC3DOORSDC_DFLT);
+	r600_set_ctxcgtt3d_rphc(rdev, R600_CTXCGTT3DRPHC_DFLT);
+	r600_set_ctxcgtt3d_rsdc(rdev, R600_CTXCGTT3DRSDC_DFLT);
+
+	r600_vid_rt_set_vru(rdev, R600_VRU_DFLT);
+	r600_vid_rt_set_vrt(rdev, R600_VOLTAGERESPONSETIME_DFLT);
+	r600_vid_rt_set_ssu(rdev, R600_SPLLSTEPUNIT_DFLT);
+
+	ret = rs780_initialize_dpm_power_state(rdev);
+
+	r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW,     0);
+	r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM,  0);
+	r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_HIGH,    0);
+
+	r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW,    0);
+	r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
+	r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_HIGH,   0);
+
+	r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW,    0);
+	r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
+	r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_HIGH,   0);
+
+	r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW,    R600_DISPLAY_WATERMARK_HIGH);
+	r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM, R600_DISPLAY_WATERMARK_HIGH);
+	r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_HIGH,   R600_DISPLAY_WATERMARK_HIGH);
+
+	r600_power_level_enable(rdev, R600_POWER_LEVEL_CTXSW, false);
+	r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false);
+	r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false);
+	r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
+
+	r600_power_level_set_enter_index(rdev, R600_POWER_LEVEL_LOW);
+
+	r600_set_vrc(rdev, RS780_CGFTV_DFLT);
+
+	return ret;
+}
+
+static void rs780_start_dpm(struct radeon_device *rdev)
+{
+	r600_enable_sclk_control(rdev, false);
+	r600_enable_mclk_control(rdev, false);
+
+	r600_dynamicpm_enable(rdev, true);
+
+	radeon_wait_for_vblank(rdev, 0);
+	radeon_wait_for_vblank(rdev, 1);
+
+	r600_enable_spll_bypass(rdev, true);
+	r600_wait_for_spll_change(rdev);
+	r600_enable_spll_bypass(rdev, false);
+	r600_wait_for_spll_change(rdev);
+
+	r600_enable_spll_bypass(rdev, true);
+	r600_wait_for_spll_change(rdev);
+	r600_enable_spll_bypass(rdev, false);
+	r600_wait_for_spll_change(rdev);
+
+	r600_enable_sclk_control(rdev, true);
+}
+
+
+static void rs780_preset_ranges_slow_clk_fbdiv_en(struct radeon_device *rdev)
+{
+	WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1, RANGE_SLOW_CLK_FEEDBACK_DIV_EN,
+		 ~RANGE_SLOW_CLK_FEEDBACK_DIV_EN);
+
+	WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1,
+		 RANGE0_SLOW_CLK_FEEDBACK_DIV(RS780_SLOWCLKFEEDBACKDIV_DFLT),
+		 ~RANGE0_SLOW_CLK_FEEDBACK_DIV_MASK);
+}
+
+static void rs780_preset_starting_fbdiv(struct radeon_device *rdev)
+{
+	u32 fbdiv = (RREG32(CG_SPLL_FUNC_CNTL) & SPLL_FB_DIV_MASK) >> SPLL_FB_DIV_SHIFT;
+
+	WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(fbdiv),
+		 ~STARTING_FEEDBACK_DIV_MASK);
+
+	WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(fbdiv),
+		 ~FORCED_FEEDBACK_DIV_MASK);
+
+	WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
+}
+
+static void rs780_voltage_scaling_init(struct radeon_device *rdev)
+{
+	struct igp_power_info *pi = rs780_get_pi(rdev);
+	struct drm_device *dev = rdev->ddev;
+	u32 fv_throt_pwm_fb_div_range[3];
+	u32 fv_throt_pwm_range[4];
+
+	if (dev->pdev->device == 0x9614) {
+		fv_throt_pwm_fb_div_range[0] = RS780D_FVTHROTPWMFBDIVRANGEREG0_DFLT;
+		fv_throt_pwm_fb_div_range[1] = RS780D_FVTHROTPWMFBDIVRANGEREG1_DFLT;
+		fv_throt_pwm_fb_div_range[2] = RS780D_FVTHROTPWMFBDIVRANGEREG2_DFLT;
+	} else if ((dev->pdev->device == 0x9714) ||
+		   (dev->pdev->device == 0x9715)) {
+		fv_throt_pwm_fb_div_range[0] = RS880D_FVTHROTPWMFBDIVRANGEREG0_DFLT;
+		fv_throt_pwm_fb_div_range[1] = RS880D_FVTHROTPWMFBDIVRANGEREG1_DFLT;
+		fv_throt_pwm_fb_div_range[2] = RS880D_FVTHROTPWMFBDIVRANGEREG2_DFLT;
+	} else {
+		fv_throt_pwm_fb_div_range[0] = RS780_FVTHROTPWMFBDIVRANGEREG0_DFLT;
+		fv_throt_pwm_fb_div_range[1] = RS780_FVTHROTPWMFBDIVRANGEREG1_DFLT;
+		fv_throt_pwm_fb_div_range[2] = RS780_FVTHROTPWMFBDIVRANGEREG2_DFLT;
+	}
+
+	if (pi->pwm_voltage_control) {
+		fv_throt_pwm_range[0] = pi->min_voltage;
+		fv_throt_pwm_range[1] = pi->min_voltage;
+		fv_throt_pwm_range[2] = pi->max_voltage;
+		fv_throt_pwm_range[3] = pi->max_voltage;
+	} else {
+		fv_throt_pwm_range[0] = pi->invert_pwm_required ?
+			RS780_FVTHROTPWMRANGE3_GPIO_DFLT : RS780_FVTHROTPWMRANGE0_GPIO_DFLT;
+		fv_throt_pwm_range[1] = pi->invert_pwm_required ?
+			RS780_FVTHROTPWMRANGE2_GPIO_DFLT : RS780_FVTHROTPWMRANGE1_GPIO_DFLT;
+		fv_throt_pwm_range[2] = pi->invert_pwm_required ?
+			RS780_FVTHROTPWMRANGE1_GPIO_DFLT : RS780_FVTHROTPWMRANGE2_GPIO_DFLT;
+		fv_throt_pwm_range[3] = pi->invert_pwm_required ?
+			RS780_FVTHROTPWMRANGE0_GPIO_DFLT : RS780_FVTHROTPWMRANGE3_GPIO_DFLT;
+	}
+
+	WREG32_P(FVTHROT_PWM_CTRL_REG0,
+		 STARTING_PWM_HIGHTIME(pi->max_voltage),
+		 ~STARTING_PWM_HIGHTIME_MASK);
+
+	WREG32_P(FVTHROT_PWM_CTRL_REG0,
+		 NUMBER_OF_CYCLES_IN_PERIOD(pi->num_of_cycles_in_period),
+		 ~NUMBER_OF_CYCLES_IN_PERIOD_MASK);
+
+	WREG32_P(FVTHROT_PWM_CTRL_REG0, FORCE_STARTING_PWM_HIGHTIME,
+		 ~FORCE_STARTING_PWM_HIGHTIME);
+
+	if (pi->invert_pwm_required)
+		WREG32_P(FVTHROT_PWM_CTRL_REG0, INVERT_PWM_WAVEFORM, ~INVERT_PWM_WAVEFORM);
+	else
+		WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~INVERT_PWM_WAVEFORM);
+
+	rs780_voltage_scaling_enable(rdev, true);
+
+	WREG32(FVTHROT_PWM_CTRL_REG1,
+	       (MIN_PWM_HIGHTIME(pi->min_voltage) |
+		MAX_PWM_HIGHTIME(pi->max_voltage)));
+
+	WREG32(FVTHROT_PWM_US_REG0, RS780_FVTHROTPWMUSREG0_DFLT);
+	WREG32(FVTHROT_PWM_US_REG1, RS780_FVTHROTPWMUSREG1_DFLT);
+	WREG32(FVTHROT_PWM_DS_REG0, RS780_FVTHROTPWMDSREG0_DFLT);
+	WREG32(FVTHROT_PWM_DS_REG1, RS780_FVTHROTPWMDSREG1_DFLT);
+
+	WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1,
+		 RANGE0_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[0]),
+		 ~RANGE0_PWM_FEEDBACK_DIV_MASK);
+
+	WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG2,
+	       (RANGE1_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[1]) |
+		RANGE2_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[2])));
+
+	WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG3,
+	       (RANGE0_PWM(fv_throt_pwm_range[1]) |
+		RANGE1_PWM(fv_throt_pwm_range[2])));
+	WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG4,
+	       (RANGE2_PWM(fv_throt_pwm_range[1]) |
+		RANGE3_PWM(fv_throt_pwm_range[2])));
+}
+
+static void rs780_clk_scaling_enable(struct radeon_device *rdev, bool enable)
+{
+	if (enable)
+		WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT | ENABLE_FV_UPDATE,
+			 ~(ENABLE_FV_THROT | ENABLE_FV_UPDATE));
+	else
+		WREG32_P(FVTHROT_CNTRL_REG, 0,
+			 ~(ENABLE_FV_THROT | ENABLE_FV_UPDATE));
+}
+
+static void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable)
+{
+	if (enable)
+		WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT_IO, ~ENABLE_FV_THROT_IO);
+	else
+		WREG32_P(FVTHROT_CNTRL_REG, 0, ~ENABLE_FV_THROT_IO);
+}
+
+static void rs780_set_engine_clock_wfc(struct radeon_device *rdev)
+{
+	WREG32(FVTHROT_UTC0, RS780_FVTHROTUTC0_DFLT);
+	WREG32(FVTHROT_UTC1, RS780_FVTHROTUTC1_DFLT);
+	WREG32(FVTHROT_UTC2, RS780_FVTHROTUTC2_DFLT);
+	WREG32(FVTHROT_UTC3, RS780_FVTHROTUTC3_DFLT);
+	WREG32(FVTHROT_UTC4, RS780_FVTHROTUTC4_DFLT);
+
+	WREG32(FVTHROT_DTC0, RS780_FVTHROTDTC0_DFLT);
+	WREG32(FVTHROT_DTC1, RS780_FVTHROTDTC1_DFLT);
+	WREG32(FVTHROT_DTC2, RS780_FVTHROTDTC2_DFLT);
+	WREG32(FVTHROT_DTC3, RS780_FVTHROTDTC3_DFLT);
+	WREG32(FVTHROT_DTC4, RS780_FVTHROTDTC4_DFLT);
+}
+
+static void rs780_set_engine_clock_sc(struct radeon_device *rdev)
+{
+	WREG32_P(FVTHROT_FBDIV_REG2,
+		 FB_DIV_TIMER_VAL(RS780_FBDIVTIMERVAL_DFLT),
+		 ~FB_DIV_TIMER_VAL_MASK);
+
+	WREG32_P(FVTHROT_CNTRL_REG,
+		 REFRESH_RATE_DIVISOR(0) | MINIMUM_CIP(0xf),
+		 ~(REFRESH_RATE_DIVISOR_MASK | MINIMUM_CIP_MASK));
+}
+
+static void rs780_set_engine_clock_tdc(struct radeon_device *rdev)
+{
+	WREG32_P(FVTHROT_CNTRL_REG, 0, ~(FORCE_TREND_SEL | TREND_SEL_MODE));
+}
+
+static void rs780_set_engine_clock_ssc(struct radeon_device *rdev)
+{
+	WREG32(FVTHROT_FB_US_REG0, RS780_FVTHROTFBUSREG0_DFLT);
+	WREG32(FVTHROT_FB_US_REG1, RS780_FVTHROTFBUSREG1_DFLT);
+	WREG32(FVTHROT_FB_DS_REG0, RS780_FVTHROTFBDSREG0_DFLT);
+	WREG32(FVTHROT_FB_DS_REG1, RS780_FVTHROTFBDSREG1_DFLT);
+
+	WREG32_P(FVTHROT_FBDIV_REG1, MAX_FEEDBACK_STEP(1), ~MAX_FEEDBACK_STEP_MASK);
+}
+
+static void rs780_program_at(struct radeon_device *rdev)
+{
+	struct igp_power_info *pi = rs780_get_pi(rdev);
+
+	WREG32(FVTHROT_TARGET_REG, 30000000 / pi->refresh_rate);
+	WREG32(FVTHROT_CB1, 1000000 * 5 / pi->refresh_rate);
+	WREG32(FVTHROT_CB2, 1000000 * 10 / pi->refresh_rate);
+	WREG32(FVTHROT_CB3, 1000000 * 30 / pi->refresh_rate);
+	WREG32(FVTHROT_CB4, 1000000 * 50 / pi->refresh_rate);
+}
+
+static void rs780_disable_vbios_powersaving(struct radeon_device *rdev)
+{
+	WREG32_P(CG_INTGFX_MISC, 0, ~0xFFF00000);
+}
+
+static void rs780_force_voltage_to_high(struct radeon_device *rdev)
+{
+	struct igp_power_info *pi = rs780_get_pi(rdev);
+	struct igp_ps *current_state = rs780_get_ps(rdev->pm.dpm.current_ps);
+
+	if ((current_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
+	    (current_state->min_voltage == RS780_VDDC_LEVEL_HIGH))
+		return;
+
+	WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
+
+	udelay(1);
+
+	WREG32_P(FVTHROT_PWM_CTRL_REG0,
+		 STARTING_PWM_HIGHTIME(pi->max_voltage),
+		 ~STARTING_PWM_HIGHTIME_MASK);
+
+	WREG32_P(FVTHROT_PWM_CTRL_REG0,
+		 FORCE_STARTING_PWM_HIGHTIME, ~FORCE_STARTING_PWM_HIGHTIME);
+
+	WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1, 0,
+		~RANGE_PWM_FEEDBACK_DIV_EN);
+
+	udelay(1);
+
+	WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
+}
+
+static int rs780_set_engine_clock_scaling(struct radeon_device *rdev)
+{
+	struct atom_clock_dividers min_dividers, max_dividers, current_max_dividers;
+	struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
+	struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
+	int ret;
+
+	if ((new_state->sclk_high == old_state->sclk_high) &&
+	    (new_state->sclk_low == old_state->sclk_low))
+		return 0;
+
+	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+					     new_state->sclk_low, false, &min_dividers);
+	if (ret)
+		return ret;
+
+	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+					     new_state->sclk_high, false, &max_dividers);
+	if (ret)
+		return ret;
+
+	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+					     old_state->sclk_high, false, &current_max_dividers);
+	if (ret)
+		return ret;
+
+	WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
+
+	WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(max_dividers.fb_div),
+		 ~FORCED_FEEDBACK_DIV_MASK);
+	WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(max_dividers.fb_div),
+		 ~STARTING_FEEDBACK_DIV_MASK);
+	WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
+
+	udelay(100);
+
+	WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
+
+	if (max_dividers.fb_div > min_dividers.fb_div) {
+		WREG32_P(FVTHROT_FBDIV_REG0,
+			 MIN_FEEDBACK_DIV(min_dividers.fb_div) |
+			 MAX_FEEDBACK_DIV(max_dividers.fb_div),
+			 ~(MIN_FEEDBACK_DIV_MASK | MAX_FEEDBACK_DIV_MASK));
+
+		WREG32_P(FVTHROT_FBDIV_REG1, 0, ~FORCE_FEEDBACK_DIV);
+	}
+
+	return 0;
+}
+
+static void rs780_set_engine_clock_spc(struct radeon_device *rdev)
+{
+	struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
+	struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
+	struct igp_power_info *pi = rs780_get_pi(rdev);
+
+	if ((new_state->sclk_high == old_state->sclk_high) &&
+	    (new_state->sclk_low == old_state->sclk_low))
+		return;
+
+	if (pi->crtc_id == 0)
+		WREG32_P(CG_INTGFX_MISC, 0, ~FVTHROT_VBLANK_SEL);
+	else
+		WREG32_P(CG_INTGFX_MISC, FVTHROT_VBLANK_SEL, ~FVTHROT_VBLANK_SEL);
+
+}
+
+static void rs780_activate_engine_clk_scaling(struct radeon_device *rdev)
+{
+	struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
+	struct igp_ps *old_state = rs780_get_ps(rdev->pm.dpm.current_ps);
+
+	if ((new_state->sclk_high == old_state->sclk_high) &&
+	    (new_state->sclk_low == old_state->sclk_low))
+		return;
+
+	rs780_clk_scaling_enable(rdev, true);
+}
+
+static u32 rs780_get_voltage_for_vddc_level(struct radeon_device *rdev,
+					    enum rs780_vddc_level vddc)
+{
+	struct igp_power_info *pi = rs780_get_pi(rdev);
+
+	if (vddc == RS780_VDDC_LEVEL_HIGH)
+		return pi->max_voltage;
+	else if (vddc == RS780_VDDC_LEVEL_LOW)
+		return pi->min_voltage;
+	else
+		return pi->max_voltage;
+}
+
+static void rs780_enable_voltage_scaling(struct radeon_device *rdev)
+{
+	struct igp_ps *new_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
+	struct igp_power_info *pi = rs780_get_pi(rdev);
+	enum rs780_vddc_level vddc_high, vddc_low;
+
+	udelay(100);
+
+	if ((new_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
+	    (new_state->min_voltage == RS780_VDDC_LEVEL_HIGH))
+		return;
+
+	vddc_high = rs780_get_voltage_for_vddc_level(rdev,
+						     new_state->max_voltage);
+	vddc_low = rs780_get_voltage_for_vddc_level(rdev,
+						    new_state->min_voltage);
+
+	WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
+
+	udelay(1);
+	if (vddc_high > vddc_low) {
+		WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1,
+			 RANGE_PWM_FEEDBACK_DIV_EN, ~RANGE_PWM_FEEDBACK_DIV_EN);
+
+		WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~FORCE_STARTING_PWM_HIGHTIME);
+	} else if (vddc_high == vddc_low) {
+		if (pi->max_voltage != vddc_high) {
+			WREG32_P(FVTHROT_PWM_CTRL_REG0,
+				 STARTING_PWM_HIGHTIME(vddc_high),
+				 ~STARTING_PWM_HIGHTIME_MASK);
+
+			WREG32_P(FVTHROT_PWM_CTRL_REG0,
+				 FORCE_STARTING_PWM_HIGHTIME,
+				 ~FORCE_STARTING_PWM_HIGHTIME);
+		}
+	}
+
+	WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
+}
+
+int rs780_dpm_enable(struct radeon_device *rdev)
+{
+	struct igp_power_info *pi = rs780_get_pi(rdev);
+
+	rs780_get_pm_mode_parameters(rdev);
+	rs780_disable_vbios_powersaving(rdev);
+
+	if (r600_dynamicpm_enabled(rdev))
+		return -EINVAL;
+	if (rs780_initialize_dpm_parameters(rdev))
+		return -EINVAL;
+	rs780_start_dpm(rdev);
+
+	rs780_preset_ranges_slow_clk_fbdiv_en(rdev);
+	rs780_preset_starting_fbdiv(rdev);
+	if (pi->voltage_control)
+		rs780_voltage_scaling_init(rdev);
+	rs780_clk_scaling_enable(rdev, true);
+	rs780_set_engine_clock_sc(rdev);
+	rs780_set_engine_clock_wfc(rdev);
+	rs780_program_at(rdev);
+	rs780_set_engine_clock_tdc(rdev);
+	rs780_set_engine_clock_ssc(rdev);
+
+	if (pi->gfx_clock_gating)
+		r600_gfx_clockgating_enable(rdev, true);
+
+	return 0;
+}
+
+void rs780_dpm_disable(struct radeon_device *rdev)
+{
+	struct igp_power_info *pi = rs780_get_pi(rdev);
+
+	r600_dynamicpm_enable(rdev, false);
+
+	rs780_clk_scaling_enable(rdev, false);
+	rs780_voltage_scaling_enable(rdev, false);
+
+	if (pi->gfx_clock_gating)
+		r600_gfx_clockgating_enable(rdev, false);
+}
+
+int rs780_dpm_set_power_state(struct radeon_device *rdev)
+{
+	struct igp_power_info *pi = rs780_get_pi(rdev);
+
+	rs780_get_pm_mode_parameters(rdev);
+
+	if (pi->voltage_control) {
+		rs780_force_voltage_to_high(rdev);
+		mdelay(5);
+	}
+
+	rs780_set_engine_clock_scaling(rdev);
+	rs780_set_engine_clock_spc(rdev);
+
+	rs780_activate_engine_clk_scaling(rdev);
+
+	if (pi->voltage_control)
+		rs780_enable_voltage_scaling(rdev);
+
+	return 0;
+}
+
+void rs780_dpm_setup_asic(struct radeon_device *rdev)
+{
+
+}
+
+void rs780_dpm_display_configuration_changed(struct radeon_device *rdev)
+{
+	rs780_get_pm_mode_parameters(rdev);
+	rs780_program_at(rdev);
+}
+
+union igp_info {
+	struct _ATOM_INTEGRATED_SYSTEM_INFO info;
+	struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
+};
+
+union power_info {
+	struct _ATOM_POWERPLAY_INFO info;
+	struct _ATOM_POWERPLAY_INFO_V2 info_2;
+	struct _ATOM_POWERPLAY_INFO_V3 info_3;
+	struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
+	struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
+	struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
+};
+
+union pplib_clock_info {
+	struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
+	struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
+	struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
+	struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
+};
+
+union pplib_power_state {
+	struct _ATOM_PPLIB_STATE v1;
+	struct _ATOM_PPLIB_STATE_V2 v2;
+};
+
+static void 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)
+{
+	rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
+	rps->class = le16_to_cpu(non_clock_info->usClassification);
+	rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
+
+	if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
+		rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
+		rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
+	} else if (r600_is_uvd_state(rps->class, rps->class2)) {
+		rps->vclk = RS780_DEFAULT_VCLK_FREQ;
+		rps->dclk = RS780_DEFAULT_DCLK_FREQ;
+	} else {
+		rps->vclk = 0;
+		rps->dclk = 0;
+	}
+
+	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
+		rdev->pm.dpm.boot_ps = rps;
+	if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
+		rdev->pm.dpm.uvd_ps = rps;
+}
+
+static void rs780_parse_pplib_clock_info(struct radeon_device *rdev,
+					 struct radeon_ps *rps,
+					 union pplib_clock_info *clock_info)
+{
+	struct igp_ps *ps = rs780_get_ps(rps);
+	u32 sclk;
+
+	sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow);
+	sclk |= clock_info->rs780.ucLowEngineClockHigh << 16;
+	ps->sclk_low = sclk;
+	sclk = le16_to_cpu(clock_info->rs780.usHighEngineClockLow);
+	sclk |= clock_info->rs780.ucHighEngineClockHigh << 16;
+	ps->sclk_high = sclk;
+	switch (le16_to_cpu(clock_info->rs780.usVDDC)) {
+	case ATOM_PPLIB_RS780_VOLTAGE_NONE:
+	default:
+		ps->min_voltage = RS780_VDDC_LEVEL_UNKNOWN;
+		ps->max_voltage = RS780_VDDC_LEVEL_UNKNOWN;
+		break;
+	case ATOM_PPLIB_RS780_VOLTAGE_LOW:
+		ps->min_voltage = RS780_VDDC_LEVEL_LOW;
+		ps->max_voltage = RS780_VDDC_LEVEL_LOW;
+		break;
+	case ATOM_PPLIB_RS780_VOLTAGE_HIGH:
+		ps->min_voltage = RS780_VDDC_LEVEL_HIGH;
+		ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
+		break;
+	case ATOM_PPLIB_RS780_VOLTAGE_VARIABLE:
+		ps->min_voltage = RS780_VDDC_LEVEL_LOW;
+		ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
+		break;
+	}
+	ps->flags = le32_to_cpu(clock_info->rs780.ulFlags);
+
+	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
+		ps->sclk_low = rdev->clock.default_sclk;
+		ps->sclk_high = rdev->clock.default_sclk;
+		ps->min_voltage = RS780_VDDC_LEVEL_HIGH;
+		ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
+	}
+}
+
+static int rs780_parse_power_table(struct radeon_device *rdev)
+{
+	struct radeon_mode_info *mode_info = &rdev->mode_info;
+	struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
+	union pplib_power_state *power_state;
+	int i;
+	union pplib_clock_info *clock_info;
+	union power_info *power_info;
+	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
+        u16 data_offset;
+	u8 frev, crev;
+	struct igp_ps *ps;
+
+	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
+				   &frev, &crev, &data_offset))
+		return -EINVAL;
+	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
+
+	rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
+				  power_info->pplib.ucNumStates, GFP_KERNEL);
+	if (!rdev->pm.dpm.ps)
+		return -ENOMEM;
+	rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
+	rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
+	rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
+
+	for (i = 0; i < power_info->pplib.ucNumStates; i++) {
+		power_state = (union pplib_power_state *)
+			(mode_info->atom_context->bios + data_offset +
+			 le16_to_cpu(power_info->pplib.usStateArrayOffset) +
+			 i * power_info->pplib.ucStateEntrySize);
+		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
+			(mode_info->atom_context->bios + data_offset +
+			 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
+			 (power_state->v1.ucNonClockStateIndex *
+			  power_info->pplib.ucNonClockSize));
+		if (power_info->pplib.ucStateEntrySize - 1) {
+			clock_info = (union pplib_clock_info *)
+				(mode_info->atom_context->bios + data_offset +
+				 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
+				 (power_state->v1.ucClockStateIndices[0] *
+				  power_info->pplib.ucClockInfoSize));
+			ps = kzalloc(sizeof(struct igp_ps), GFP_KERNEL);
+			if (ps == NULL) {
+				kfree(rdev->pm.dpm.ps);
+				return -ENOMEM;
+			}
+			rdev->pm.dpm.ps[i].ps_priv = ps;
+			rs780_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
+							 non_clock_info,
+							 power_info->pplib.ucNonClockSize);
+			rs780_parse_pplib_clock_info(rdev,
+						     &rdev->pm.dpm.ps[i],
+						     clock_info);
+		}
+	}
+	rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates;
+	return 0;
+}
+
+int rs780_dpm_init(struct radeon_device *rdev)
+{
+	struct igp_power_info *pi;
+	int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
+	union igp_info *info;
+	u16 data_offset;
+	u8 frev, crev;
+	int ret;
+
+	pi = kzalloc(sizeof(struct igp_power_info), GFP_KERNEL);
+	if (pi == NULL)
+		return -ENOMEM;
+	rdev->pm.dpm.priv = pi;
+
+	ret = rs780_parse_power_table(rdev);
+	if (ret)
+		return ret;
+
+	pi->voltage_control = false;
+	pi->gfx_clock_gating = true;
+
+	if (atom_parse_data_header(rdev->mode_info.atom_context, index, NULL,
+				   &frev, &crev, &data_offset)) {
+		info = (union igp_info *)(rdev->mode_info.atom_context->bios + data_offset);
+
+		/* Get various system informations from bios */
+		switch (crev) {
+		case 1:
+			pi->num_of_cycles_in_period =
+				info->info.ucNumberOfCyclesInPeriod;
+			pi->num_of_cycles_in_period |=
+				info->info.ucNumberOfCyclesInPeriodHi << 8;
+			pi->invert_pwm_required =
+				(pi->num_of_cycles_in_period & 0x8000) ? true : false;
+			pi->boot_voltage = info->info.ucStartingPWM_HighTime;
+			pi->max_voltage = info->info.ucMaxNBVoltage;
+			pi->max_voltage |= info->info.ucMaxNBVoltageHigh << 8;
+			pi->min_voltage = info->info.ucMinNBVoltage;
+			pi->min_voltage |= info->info.ucMinNBVoltageHigh << 8;
+			pi->inter_voltage_low =
+				le16_to_cpu(info->info.usInterNBVoltageLow);
+			pi->inter_voltage_high =
+				le16_to_cpu(info->info.usInterNBVoltageHigh);
+			pi->voltage_control = true;
+			pi->bootup_uma_clk = info->info.usK8MemoryClock * 100;
+			break;
+		case 2:
+			pi->num_of_cycles_in_period =
+				le16_to_cpu(info->info_2.usNumberOfCyclesInPeriod);
+			pi->invert_pwm_required =
+				(pi->num_of_cycles_in_period & 0x8000) ? true : false;
+			pi->boot_voltage =
+				le16_to_cpu(info->info_2.usBootUpNBVoltage);
+			pi->max_voltage =
+				le16_to_cpu(info->info_2.usMaxNBVoltage);
+			pi->min_voltage =
+				le16_to_cpu(info->info_2.usMinNBVoltage);
+			pi->system_config =
+				le32_to_cpu(info->info_2.ulSystemConfig);
+			pi->pwm_voltage_control =
+				(pi->system_config & 0x4) ? true : false;
+			pi->voltage_control = true;
+			pi->bootup_uma_clk = le32_to_cpu(info->info_2.ulBootUpUMAClock);
+			break;
+		default:
+			DRM_ERROR("No integrated system info for your GPU\n");
+			return -EINVAL;
+		}
+		if (pi->min_voltage > pi->max_voltage)
+			pi->voltage_control = false;
+		if (pi->pwm_voltage_control) {
+			if ((pi->num_of_cycles_in_period == 0) ||
+			    (pi->max_voltage == 0) ||
+			    (pi->min_voltage == 0))
+				pi->voltage_control = false;
+		} else {
+			if ((pi->num_of_cycles_in_period == 0) ||
+			    (pi->max_voltage == 0))
+				pi->voltage_control = false;
+		}
+
+		return 0;
+	}
+	radeon_dpm_fini(rdev);
+	return -EINVAL;
+}
+
+void rs780_dpm_print_power_state(struct radeon_device *rdev,
+				 struct radeon_ps *rps)
+{
+	struct igp_ps *ps = rs780_get_ps(rps);
+
+	r600_dpm_print_class_info(rps->class, rps->class2);
+	r600_dpm_print_cap_info(rps->caps);
+	printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+	printk("\t\tpower level 0    sclk: %u vddc_index: %d\n",
+	       ps->sclk_low, ps->min_voltage);
+	printk("\t\tpower level 1    sclk: %u vddc_index: %d\n",
+	       ps->sclk_high, ps->max_voltage);
+	r600_dpm_print_ps_status(rdev, rps);
+}
+
+void rs780_dpm_fini(struct radeon_device *rdev)
+{
+	int i;
+
+	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
+		kfree(rdev->pm.dpm.ps[i].ps_priv);
+	}
+	kfree(rdev->pm.dpm.ps);
+	kfree(rdev->pm.dpm.priv);
+}
+
+u32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low)
+{
+	struct igp_ps *requested_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
+
+	if (low)
+		return requested_state->sclk_low;
+	else
+		return requested_state->sclk_high;
+}
+
+u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low)
+{
+	struct igp_power_info *pi = rs780_get_pi(rdev);
+
+	return pi->bootup_uma_clk;
+}
diff --git a/drivers/gpu/drm/radeon/rs780_dpm.h b/drivers/gpu/drm/radeon/rs780_dpm.h
new file mode 100644
index 0000000..47a40b1
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rs780_dpm.h
@@ -0,0 +1,109 @@ 
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef __RS780_DPM_H__
+#define __RS780_DPM_H__
+
+enum rs780_vddc_level {
+	RS780_VDDC_LEVEL_UNKNOWN = 0,
+	RS780_VDDC_LEVEL_LOW = 1,
+	RS780_VDDC_LEVEL_HIGH = 2,
+};
+
+struct igp_power_info {
+	/* flags */
+	bool invert_pwm_required;
+	bool pwm_voltage_control;
+	bool voltage_control;
+	bool gfx_clock_gating;
+	/* stored values */
+	u32 system_config;
+	u32 bootup_uma_clk;
+	u16 max_voltage;
+	u16 min_voltage;
+	u16 boot_voltage;
+	u16 inter_voltage_low;
+	u16 inter_voltage_high;
+	u16 num_of_cycles_in_period;
+	/* variable */
+	int crtc_id;
+	int refresh_rate;
+};
+
+struct igp_ps {
+	enum rs780_vddc_level min_voltage;
+	enum rs780_vddc_level max_voltage;
+	u32 sclk_low;
+	u32 sclk_high;
+	u32 flags;
+};
+
+#define RS780_CGFTV_DFLT                 0x0303000f
+#define RS780_FBDIVTIMERVAL_DFLT         0x2710
+
+#define RS780_FVTHROTUTC0_DFLT   0x04010040
+#define RS780_FVTHROTUTC1_DFLT   0x04010040
+#define RS780_FVTHROTUTC2_DFLT   0x04010040
+#define RS780_FVTHROTUTC3_DFLT   0x04010040
+#define RS780_FVTHROTUTC4_DFLT   0x04010040
+
+#define RS780_FVTHROTDTC0_DFLT 0x04010040
+#define RS780_FVTHROTDTC1_DFLT 0x04010040
+#define RS780_FVTHROTDTC2_DFLT 0x04010040
+#define RS780_FVTHROTDTC3_DFLT 0x04010040
+#define RS780_FVTHROTDTC4_DFLT 0x04010040
+
+#define RS780_FVTHROTFBUSREG0_DFLT       0x00001001
+#define RS780_FVTHROTFBUSREG1_DFLT       0x00002002
+#define RS780_FVTHROTFBDSREG0_DFLT       0x00004001
+#define RS780_FVTHROTFBDSREG1_DFLT       0x00020010
+
+#define RS780_FVTHROTPWMUSREG0_DFLT      0x00002001
+#define RS780_FVTHROTPWMUSREG1_DFLT      0x00004003
+#define RS780_FVTHROTPWMDSREG0_DFLT      0x00002001
+#define RS780_FVTHROTPWMDSREG1_DFLT      0x00004003
+
+#define RS780_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x37
+#define RS780_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x4b
+#define RS780_FVTHROTPWMFBDIVRANGEREG2_DFLT  0x8b
+
+#define RS780D_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x8b
+#define RS780D_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x8c
+#define RS780D_FVTHROTPWMFBDIVRANGEREG2_DFLT  0xb5
+
+#define RS880D_FVTHROTPWMFBDIVRANGEREG0_DFLT  0x8d
+#define RS880D_FVTHROTPWMFBDIVRANGEREG1_DFLT  0x8e
+#define RS880D_FVTHROTPWMFBDIVRANGEREG2_DFLT  0xBa
+
+#define RS780_FVTHROTPWMRANGE0_GPIO_DFLT  0x1a
+#define RS780_FVTHROTPWMRANGE1_GPIO_DFLT  0x1a
+#define RS780_FVTHROTPWMRANGE2_GPIO_DFLT  0x0
+#define RS780_FVTHROTPWMRANGE3_GPIO_DFLT  0x0
+
+#define RS780_SLOWCLKFEEDBACKDIV_DFLT 110
+
+#define RS780_CGCLKGATING_DFLT           0x0000E204
+
+#define RS780_DEFAULT_VCLK_FREQ  53300 /* 10 khz */
+#define RS780_DEFAULT_DCLK_FREQ  40000 /* 10 khz */
+
+#endif
diff --git a/drivers/gpu/drm/radeon/rs780d.h b/drivers/gpu/drm/radeon/rs780d.h
new file mode 100644
index 0000000..b1142ed
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rs780d.h
@@ -0,0 +1,168 @@ 
+/*
+ * Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef __RS780D_H__
+#define __RS780D_H__
+
+#define CG_SPLL_FUNC_CNTL                                 0x600
+#       define SPLL_RESET                                (1 << 0)
+#       define SPLL_SLEEP                                (1 << 1)
+#       define SPLL_REF_DIV(x)                           ((x) << 2)
+#       define SPLL_REF_DIV_MASK                         (7 << 2)
+#       define SPLL_FB_DIV(x)                            ((x) << 5)
+#       define SPLL_FB_DIV_MASK                          (0xff << 2)
+#       define SPLL_FB_DIV_SHIFT                         2
+#       define SPLL_PULSEEN                              (1 << 13)
+#       define SPLL_PULSENUM(x)                          ((x) << 14)
+#       define SPLL_PULSENUM_MASK                        (3 << 14)
+#       define SPLL_SW_HILEN(x)                          ((x) << 16)
+#       define SPLL_SW_HILEN_MASK                        (0xf << 16)
+#       define SPLL_SW_LOLEN(x)                          ((x) << 20)
+#       define SPLL_SW_LOLEN_MASK                        (0xf << 20)
+#       define SPLL_DIVEN                                (1 << 24)
+#       define SPLL_BYPASS_EN                            (1 << 25)
+#       define SPLL_CHG_STATUS                           (1 << 29)
+#       define SPLL_CTLREQ                               (1 << 30)
+#       define SPLL_CTLACK                               (1 << 31)
+
+/* RS780/RS880 PM */
+#define	FVTHROT_CNTRL_REG				0x3000
+#define		DONT_WAIT_FOR_FBDIV_WRAP		(1 << 0)
+#define		MINIMUM_CIP(x)				((x) << 1)
+#define		MINIMUM_CIP_SHIFT			1
+#define		MINIMUM_CIP_MASK			0x1fffffe
+#define		REFRESH_RATE_DIVISOR(x)			((x) << 25)
+#define		REFRESH_RATE_DIVISOR_SHIFT		25
+#define		REFRESH_RATE_DIVISOR_MASK		(0x3 << 25)
+#define		ENABLE_FV_THROT				(1 << 27)
+#define		ENABLE_FV_UPDATE			(1 << 28)
+#define		TREND_SEL_MODE				(1 << 29)
+#define		FORCE_TREND_SEL				(1 << 30)
+#define		ENABLE_FV_THROT_IO			(1 << 31)
+#define	FVTHROT_TARGET_REG				0x3004
+#define		TARGET_IDLE_COUNT(x)			((x) << 0)
+#define		TARGET_IDLE_COUNT_MASK			0xffffff
+#define		TARGET_IDLE_COUNT_SHIFT			0
+#define	FVTHROT_CB1					0x3008
+#define	FVTHROT_CB2					0x300c
+#define	FVTHROT_CB3					0x3010
+#define	FVTHROT_CB4					0x3014
+#define	FVTHROT_UTC0					0x3018
+#define	FVTHROT_UTC1					0x301c
+#define	FVTHROT_UTC2					0x3020
+#define	FVTHROT_UTC3					0x3024
+#define	FVTHROT_UTC4					0x3028
+#define	FVTHROT_DTC0					0x302c
+#define	FVTHROT_DTC1					0x3030
+#define	FVTHROT_DTC2					0x3034
+#define	FVTHROT_DTC3					0x3038
+#define	FVTHROT_DTC4					0x303c
+#define	FVTHROT_FBDIV_REG0				0x3040
+#define		MIN_FEEDBACK_DIV(x)			((x) << 0)
+#define		MIN_FEEDBACK_DIV_MASK			0xfff
+#define		MIN_FEEDBACK_DIV_SHIFT			0
+#define		MAX_FEEDBACK_DIV(x)			((x) << 12)
+#define		MAX_FEEDBACK_DIV_MASK			(0xfff << 12)
+#define		MAX_FEEDBACK_DIV_SHIFT			12
+#define	FVTHROT_FBDIV_REG1				0x3044
+#define		MAX_FEEDBACK_STEP(x)			((x) << 0)
+#define		MAX_FEEDBACK_STEP_MASK			0xfff
+#define		MAX_FEEDBACK_STEP_SHIFT			0
+#define		STARTING_FEEDBACK_DIV(x)		((x) << 12)
+#define		STARTING_FEEDBACK_DIV_MASK		(0xfff << 12)
+#define		STARTING_FEEDBACK_DIV_SHIFT		12
+#define		FORCE_FEEDBACK_DIV			(1 << 24)
+#define	FVTHROT_FBDIV_REG2				0x3048
+#define		FORCED_FEEDBACK_DIV(x)			((x) << 0)
+#define		FORCED_FEEDBACK_DIV_MASK		0xfff
+#define		FORCED_FEEDBACK_DIV_SHIFT		0
+#define		FB_DIV_TIMER_VAL(x)			((x) << 12)
+#define		FB_DIV_TIMER_VAL_MASK			(0xffff << 12)
+#define		FB_DIV_TIMER_VAL_SHIFT			12
+#define	FVTHROT_FB_US_REG0				0x304c
+#define	FVTHROT_FB_US_REG1				0x3050
+#define	FVTHROT_FB_DS_REG0				0x3054
+#define	FVTHROT_FB_DS_REG1				0x3058
+#define	FVTHROT_PWM_CTRL_REG0				0x305c
+#define		STARTING_PWM_HIGHTIME(x)		((x) << 0)
+#define		STARTING_PWM_HIGHTIME_MASK		0xfff
+#define		STARTING_PWM_HIGHTIME_SHIFT		0
+#define		NUMBER_OF_CYCLES_IN_PERIOD(x)		((x) << 12)
+#define		NUMBER_OF_CYCLES_IN_PERIOD_MASK		(0xfff << 12)
+#define		NUMBER_OF_CYCLES_IN_PERIOD_SHIFT	12
+#define		FORCE_STARTING_PWM_HIGHTIME		(1 << 24)
+#define		INVERT_PWM_WAVEFORM			(1 << 25)
+#define	FVTHROT_PWM_CTRL_REG1				0x3060
+#define		MIN_PWM_HIGHTIME(x)			((x) << 0)
+#define		MIN_PWM_HIGHTIME_MASK			0xfff
+#define		MIN_PWM_HIGHTIME_SHIFT			0
+#define		MAX_PWM_HIGHTIME(x)			((x) << 12)
+#define		MAX_PWM_HIGHTIME_MASK			(0xfff << 12)
+#define		MAX_PWM_HIGHTIME_SHIFT			12
+#define	FVTHROT_PWM_US_REG0				0x3064
+#define	FVTHROT_PWM_US_REG1				0x3068
+#define	FVTHROT_PWM_DS_REG0				0x306c
+#define	FVTHROT_PWM_DS_REG1				0x3070
+#define	FVTHROT_STATUS_REG0				0x3074
+#define		CURRENT_FEEDBACK_DIV_MASK		0xfff
+#define		CURRENT_FEEDBACK_DIV_SHIFT		0
+#define	FVTHROT_STATUS_REG1				0x3078
+#define	FVTHROT_STATUS_REG2				0x307c
+#define	CG_INTGFX_MISC					0x3080
+#define		FVTHROT_VBLANK_SEL			(1 << 9)
+#define	FVTHROT_PWM_FEEDBACK_DIV_REG1			0x308c
+#define		RANGE0_PWM_FEEDBACK_DIV(x)		((x) << 0)
+#define		RANGE0_PWM_FEEDBACK_DIV_MASK		0xfff
+#define		RANGE0_PWM_FEEDBACK_DIV_SHIFT		0
+#define		RANGE_PWM_FEEDBACK_DIV_EN		(1 << 12)
+#define	FVTHROT_PWM_FEEDBACK_DIV_REG2			0x3090
+#define		RANGE1_PWM_FEEDBACK_DIV(x)		((x) << 0)
+#define		RANGE1_PWM_FEEDBACK_DIV_MASK		0xfff
+#define		RANGE1_PWM_FEEDBACK_DIV_SHIFT		0
+#define		RANGE2_PWM_FEEDBACK_DIV(x)		((x) << 12)
+#define		RANGE2_PWM_FEEDBACK_DIV_MASK		(0xfff << 12)
+#define		RANGE2_PWM_FEEDBACK_DIV_SHIFT		12
+#define	FVTHROT_PWM_FEEDBACK_DIV_REG3			0x3094
+#define		RANGE0_PWM(x)				((x) << 0)
+#define		RANGE0_PWM_MASK				0xfff
+#define		RANGE0_PWM_SHIFT			0
+#define		RANGE1_PWM(x)				((x) << 12)
+#define		RANGE1_PWM_MASK				(0xfff << 12)
+#define		RANGE1_PWM_SHIFT			12
+#define	FVTHROT_PWM_FEEDBACK_DIV_REG4			0x3098
+#define		RANGE2_PWM(x)				((x) << 0)
+#define		RANGE2_PWM_MASK				0xfff
+#define		RANGE2_PWM_SHIFT			0
+#define		RANGE3_PWM(x)				((x) << 12)
+#define		RANGE3_PWM_MASK				(0xfff << 12)
+#define		RANGE3_PWM_SHIFT			12
+#define	FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1		0x30ac
+#define		RANGE0_SLOW_CLK_FEEDBACK_DIV(x)		((x) << 0)
+#define		RANGE0_SLOW_CLK_FEEDBACK_DIV_MASK	0xfff
+#define		RANGE0_SLOW_CLK_FEEDBACK_DIV_SHIFT	0
+#define		RANGE_SLOW_CLK_FEEDBACK_DIV_EN		(1 << 12)
+
+#define	GFX_MACRO_BYPASS_CNTL				0x30c0
+#define		SPLL_BYPASS_CNTL			(1 << 0)
+#define		UPLL_BYPASS_CNTL			(1 << 1)
+
+#endif