Message ID | 1372253045-17042-76-git-send-email-alexdeucher@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
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, ÷rs); > + 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, ¤t_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
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, ÷rs); > >> + 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, ¤t_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
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, ÷rs); >> + 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, ¤t_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
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, ÷rs); >> >> + 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, ¤t_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 --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, ÷rs); + 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, ¤t_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