162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright 2011 Advanced Micro Devices, Inc.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
562306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
662306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation
762306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
862306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
962306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
1262306a36Sopenharmony_ci * all copies or substantial portions of the Software.
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1562306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1662306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1762306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1862306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1962306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2062306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci * Authors: Alex Deucher
2362306a36Sopenharmony_ci */
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include <linux/pci.h>
2662306a36Sopenharmony_ci#include <linux/seq_file.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include "atom.h"
2962306a36Sopenharmony_ci#include "r600_dpm.h"
3062306a36Sopenharmony_ci#include "radeon.h"
3162306a36Sopenharmony_ci#include "radeon_asic.h"
3262306a36Sopenharmony_ci#include "rs780_dpm.h"
3362306a36Sopenharmony_ci#include "rs780d.h"
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic struct igp_ps *rs780_get_ps(struct radeon_ps *rps)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	struct igp_ps *ps = rps->ps_priv;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	return ps;
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic struct igp_power_info *rs780_get_pi(struct radeon_device *rdev)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	struct igp_power_info *pi = rdev->pm.dpm.priv;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	return pi;
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic void rs780_get_pm_mode_parameters(struct radeon_device *rdev)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	struct igp_power_info *pi = rs780_get_pi(rdev);
5262306a36Sopenharmony_ci	struct radeon_mode_info *minfo = &rdev->mode_info;
5362306a36Sopenharmony_ci	struct drm_crtc *crtc;
5462306a36Sopenharmony_ci	struct radeon_crtc *radeon_crtc;
5562306a36Sopenharmony_ci	int i;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	/* defaults */
5862306a36Sopenharmony_ci	pi->crtc_id = 0;
5962306a36Sopenharmony_ci	pi->refresh_rate = 60;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	for (i = 0; i < rdev->num_crtc; i++) {
6262306a36Sopenharmony_ci		crtc = (struct drm_crtc *)minfo->crtcs[i];
6362306a36Sopenharmony_ci		if (crtc && crtc->enabled) {
6462306a36Sopenharmony_ci			radeon_crtc = to_radeon_crtc(crtc);
6562306a36Sopenharmony_ci			pi->crtc_id = radeon_crtc->crtc_id;
6662306a36Sopenharmony_ci			if (crtc->mode.htotal && crtc->mode.vtotal)
6762306a36Sopenharmony_ci				pi->refresh_rate = drm_mode_vrefresh(&crtc->mode);
6862306a36Sopenharmony_ci			break;
6962306a36Sopenharmony_ci		}
7062306a36Sopenharmony_ci	}
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic int rs780_initialize_dpm_power_state(struct radeon_device *rdev,
7662306a36Sopenharmony_ci					    struct radeon_ps *boot_ps)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	struct atom_clock_dividers dividers;
7962306a36Sopenharmony_ci	struct igp_ps *default_state = rs780_get_ps(boot_ps);
8062306a36Sopenharmony_ci	int i, ret;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
8362306a36Sopenharmony_ci					     default_state->sclk_low, false, &dividers);
8462306a36Sopenharmony_ci	if (ret)
8562306a36Sopenharmony_ci		return ret;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	r600_engine_clock_entry_set_reference_divider(rdev, 0, dividers.ref_div);
8862306a36Sopenharmony_ci	r600_engine_clock_entry_set_feedback_divider(rdev, 0, dividers.fb_div);
8962306a36Sopenharmony_ci	r600_engine_clock_entry_set_post_divider(rdev, 0, dividers.post_div);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	if (dividers.enable_post_div)
9262306a36Sopenharmony_ci		r600_engine_clock_entry_enable_post_divider(rdev, 0, true);
9362306a36Sopenharmony_ci	else
9462306a36Sopenharmony_ci		r600_engine_clock_entry_enable_post_divider(rdev, 0, false);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	r600_engine_clock_entry_set_step_time(rdev, 0, R600_SST_DFLT);
9762306a36Sopenharmony_ci	r600_engine_clock_entry_enable_pulse_skipping(rdev, 0, false);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	r600_engine_clock_entry_enable(rdev, 0, true);
10062306a36Sopenharmony_ci	for (i = 1; i < R600_PM_NUMBER_OF_SCLKS; i++)
10162306a36Sopenharmony_ci		r600_engine_clock_entry_enable(rdev, i, false);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	r600_enable_mclk_control(rdev, false);
10462306a36Sopenharmony_ci	r600_voltage_control_enable_pins(rdev, 0);
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	return 0;
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistatic int rs780_initialize_dpm_parameters(struct radeon_device *rdev,
11062306a36Sopenharmony_ci					   struct radeon_ps *boot_ps)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	int ret = 0;
11362306a36Sopenharmony_ci	int i;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	r600_set_bsp(rdev, R600_BSU_DFLT, R600_BSP_DFLT);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	r600_set_at(rdev, 0, 0, 0, 0);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	r600_set_git(rdev, R600_GICST_DFLT);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	for (i = 0; i < R600_PM_NUMBER_OF_TC; i++)
12262306a36Sopenharmony_ci		r600_set_tc(rdev, i, 0, 0);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	r600_select_td(rdev, R600_TD_DFLT);
12562306a36Sopenharmony_ci	r600_set_vrc(rdev, 0);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	r600_set_tpu(rdev, R600_TPU_DFLT);
12862306a36Sopenharmony_ci	r600_set_tpc(rdev, R600_TPC_DFLT);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	r600_set_sstu(rdev, R600_SSTU_DFLT);
13162306a36Sopenharmony_ci	r600_set_sst(rdev, R600_SST_DFLT);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	r600_set_fctu(rdev, R600_FCTU_DFLT);
13462306a36Sopenharmony_ci	r600_set_fct(rdev, R600_FCT_DFLT);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	r600_set_vddc3d_oorsu(rdev, R600_VDDC3DOORSU_DFLT);
13762306a36Sopenharmony_ci	r600_set_vddc3d_oorphc(rdev, R600_VDDC3DOORPHC_DFLT);
13862306a36Sopenharmony_ci	r600_set_vddc3d_oorsdc(rdev, R600_VDDC3DOORSDC_DFLT);
13962306a36Sopenharmony_ci	r600_set_ctxcgtt3d_rphc(rdev, R600_CTXCGTT3DRPHC_DFLT);
14062306a36Sopenharmony_ci	r600_set_ctxcgtt3d_rsdc(rdev, R600_CTXCGTT3DRSDC_DFLT);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	r600_vid_rt_set_vru(rdev, R600_VRU_DFLT);
14362306a36Sopenharmony_ci	r600_vid_rt_set_vrt(rdev, R600_VOLTAGERESPONSETIME_DFLT);
14462306a36Sopenharmony_ci	r600_vid_rt_set_ssu(rdev, R600_SPLLSTEPUNIT_DFLT);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	ret = rs780_initialize_dpm_power_state(rdev, boot_ps);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW,     0);
14962306a36Sopenharmony_ci	r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM,  0);
15062306a36Sopenharmony_ci	r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_HIGH,    0);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW,    0);
15362306a36Sopenharmony_ci	r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
15462306a36Sopenharmony_ci	r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_HIGH,   0);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW,    0);
15762306a36Sopenharmony_ci	r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
15862306a36Sopenharmony_ci	r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_HIGH,   0);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW,    R600_DISPLAY_WATERMARK_HIGH);
16162306a36Sopenharmony_ci	r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM, R600_DISPLAY_WATERMARK_HIGH);
16262306a36Sopenharmony_ci	r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_HIGH,   R600_DISPLAY_WATERMARK_HIGH);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	r600_power_level_enable(rdev, R600_POWER_LEVEL_CTXSW, false);
16562306a36Sopenharmony_ci	r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false);
16662306a36Sopenharmony_ci	r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false);
16762306a36Sopenharmony_ci	r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	r600_power_level_set_enter_index(rdev, R600_POWER_LEVEL_LOW);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	r600_set_vrc(rdev, RS780_CGFTV_DFLT);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	return ret;
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic void rs780_start_dpm(struct radeon_device *rdev)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	r600_enable_sclk_control(rdev, false);
17962306a36Sopenharmony_ci	r600_enable_mclk_control(rdev, false);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	r600_dynamicpm_enable(rdev, true);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	radeon_wait_for_vblank(rdev, 0);
18462306a36Sopenharmony_ci	radeon_wait_for_vblank(rdev, 1);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	r600_enable_spll_bypass(rdev, true);
18762306a36Sopenharmony_ci	r600_wait_for_spll_change(rdev);
18862306a36Sopenharmony_ci	r600_enable_spll_bypass(rdev, false);
18962306a36Sopenharmony_ci	r600_wait_for_spll_change(rdev);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	r600_enable_spll_bypass(rdev, true);
19262306a36Sopenharmony_ci	r600_wait_for_spll_change(rdev);
19362306a36Sopenharmony_ci	r600_enable_spll_bypass(rdev, false);
19462306a36Sopenharmony_ci	r600_wait_for_spll_change(rdev);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	r600_enable_sclk_control(rdev, true);
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic void rs780_preset_ranges_slow_clk_fbdiv_en(struct radeon_device *rdev)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1, RANGE_SLOW_CLK_FEEDBACK_DIV_EN,
20362306a36Sopenharmony_ci		 ~RANGE_SLOW_CLK_FEEDBACK_DIV_EN);
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1,
20662306a36Sopenharmony_ci		 RANGE0_SLOW_CLK_FEEDBACK_DIV(RS780_SLOWCLKFEEDBACKDIV_DFLT),
20762306a36Sopenharmony_ci		 ~RANGE0_SLOW_CLK_FEEDBACK_DIV_MASK);
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistatic void rs780_preset_starting_fbdiv(struct radeon_device *rdev)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	u32 fbdiv = (RREG32(CG_SPLL_FUNC_CNTL) & SPLL_FB_DIV_MASK) >> SPLL_FB_DIV_SHIFT;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(fbdiv),
21562306a36Sopenharmony_ci		 ~STARTING_FEEDBACK_DIV_MASK);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(fbdiv),
21862306a36Sopenharmony_ci		 ~FORCED_FEEDBACK_DIV_MASK);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistatic void rs780_voltage_scaling_init(struct radeon_device *rdev)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	struct igp_power_info *pi = rs780_get_pi(rdev);
22662306a36Sopenharmony_ci	u32 fv_throt_pwm_fb_div_range[3];
22762306a36Sopenharmony_ci	u32 fv_throt_pwm_range[4];
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	if (rdev->pdev->device == 0x9614) {
23062306a36Sopenharmony_ci		fv_throt_pwm_fb_div_range[0] = RS780D_FVTHROTPWMFBDIVRANGEREG0_DFLT;
23162306a36Sopenharmony_ci		fv_throt_pwm_fb_div_range[1] = RS780D_FVTHROTPWMFBDIVRANGEREG1_DFLT;
23262306a36Sopenharmony_ci		fv_throt_pwm_fb_div_range[2] = RS780D_FVTHROTPWMFBDIVRANGEREG2_DFLT;
23362306a36Sopenharmony_ci	} else if ((rdev->pdev->device == 0x9714) ||
23462306a36Sopenharmony_ci		   (rdev->pdev->device == 0x9715)) {
23562306a36Sopenharmony_ci		fv_throt_pwm_fb_div_range[0] = RS880D_FVTHROTPWMFBDIVRANGEREG0_DFLT;
23662306a36Sopenharmony_ci		fv_throt_pwm_fb_div_range[1] = RS880D_FVTHROTPWMFBDIVRANGEREG1_DFLT;
23762306a36Sopenharmony_ci		fv_throt_pwm_fb_div_range[2] = RS880D_FVTHROTPWMFBDIVRANGEREG2_DFLT;
23862306a36Sopenharmony_ci	} else {
23962306a36Sopenharmony_ci		fv_throt_pwm_fb_div_range[0] = RS780_FVTHROTPWMFBDIVRANGEREG0_DFLT;
24062306a36Sopenharmony_ci		fv_throt_pwm_fb_div_range[1] = RS780_FVTHROTPWMFBDIVRANGEREG1_DFLT;
24162306a36Sopenharmony_ci		fv_throt_pwm_fb_div_range[2] = RS780_FVTHROTPWMFBDIVRANGEREG2_DFLT;
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	if (pi->pwm_voltage_control) {
24562306a36Sopenharmony_ci		fv_throt_pwm_range[0] = pi->min_voltage;
24662306a36Sopenharmony_ci		fv_throt_pwm_range[1] = pi->min_voltage;
24762306a36Sopenharmony_ci		fv_throt_pwm_range[2] = pi->max_voltage;
24862306a36Sopenharmony_ci		fv_throt_pwm_range[3] = pi->max_voltage;
24962306a36Sopenharmony_ci	} else {
25062306a36Sopenharmony_ci		fv_throt_pwm_range[0] = pi->invert_pwm_required ?
25162306a36Sopenharmony_ci			RS780_FVTHROTPWMRANGE3_GPIO_DFLT : RS780_FVTHROTPWMRANGE0_GPIO_DFLT;
25262306a36Sopenharmony_ci		fv_throt_pwm_range[1] = pi->invert_pwm_required ?
25362306a36Sopenharmony_ci			RS780_FVTHROTPWMRANGE2_GPIO_DFLT : RS780_FVTHROTPWMRANGE1_GPIO_DFLT;
25462306a36Sopenharmony_ci		fv_throt_pwm_range[2] = pi->invert_pwm_required ?
25562306a36Sopenharmony_ci			RS780_FVTHROTPWMRANGE1_GPIO_DFLT : RS780_FVTHROTPWMRANGE2_GPIO_DFLT;
25662306a36Sopenharmony_ci		fv_throt_pwm_range[3] = pi->invert_pwm_required ?
25762306a36Sopenharmony_ci			RS780_FVTHROTPWMRANGE0_GPIO_DFLT : RS780_FVTHROTPWMRANGE3_GPIO_DFLT;
25862306a36Sopenharmony_ci	}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	WREG32_P(FVTHROT_PWM_CTRL_REG0,
26162306a36Sopenharmony_ci		 STARTING_PWM_HIGHTIME(pi->max_voltage),
26262306a36Sopenharmony_ci		 ~STARTING_PWM_HIGHTIME_MASK);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	WREG32_P(FVTHROT_PWM_CTRL_REG0,
26562306a36Sopenharmony_ci		 NUMBER_OF_CYCLES_IN_PERIOD(pi->num_of_cycles_in_period),
26662306a36Sopenharmony_ci		 ~NUMBER_OF_CYCLES_IN_PERIOD_MASK);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	WREG32_P(FVTHROT_PWM_CTRL_REG0, FORCE_STARTING_PWM_HIGHTIME,
26962306a36Sopenharmony_ci		 ~FORCE_STARTING_PWM_HIGHTIME);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	if (pi->invert_pwm_required)
27262306a36Sopenharmony_ci		WREG32_P(FVTHROT_PWM_CTRL_REG0, INVERT_PWM_WAVEFORM, ~INVERT_PWM_WAVEFORM);
27362306a36Sopenharmony_ci	else
27462306a36Sopenharmony_ci		WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~INVERT_PWM_WAVEFORM);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	rs780_voltage_scaling_enable(rdev, true);
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	WREG32(FVTHROT_PWM_CTRL_REG1,
27962306a36Sopenharmony_ci	       (MIN_PWM_HIGHTIME(pi->min_voltage) |
28062306a36Sopenharmony_ci		MAX_PWM_HIGHTIME(pi->max_voltage)));
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	WREG32(FVTHROT_PWM_US_REG0, RS780_FVTHROTPWMUSREG0_DFLT);
28362306a36Sopenharmony_ci	WREG32(FVTHROT_PWM_US_REG1, RS780_FVTHROTPWMUSREG1_DFLT);
28462306a36Sopenharmony_ci	WREG32(FVTHROT_PWM_DS_REG0, RS780_FVTHROTPWMDSREG0_DFLT);
28562306a36Sopenharmony_ci	WREG32(FVTHROT_PWM_DS_REG1, RS780_FVTHROTPWMDSREG1_DFLT);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1,
28862306a36Sopenharmony_ci		 RANGE0_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[0]),
28962306a36Sopenharmony_ci		 ~RANGE0_PWM_FEEDBACK_DIV_MASK);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG2,
29262306a36Sopenharmony_ci	       (RANGE1_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[1]) |
29362306a36Sopenharmony_ci		RANGE2_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[2])));
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG3,
29662306a36Sopenharmony_ci	       (RANGE0_PWM(fv_throt_pwm_range[1]) |
29762306a36Sopenharmony_ci		RANGE1_PWM(fv_throt_pwm_range[2])));
29862306a36Sopenharmony_ci	WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG4,
29962306a36Sopenharmony_ci	       (RANGE2_PWM(fv_throt_pwm_range[1]) |
30062306a36Sopenharmony_ci		RANGE3_PWM(fv_throt_pwm_range[2])));
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_cistatic void rs780_clk_scaling_enable(struct radeon_device *rdev, bool enable)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	if (enable)
30662306a36Sopenharmony_ci		WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT | ENABLE_FV_UPDATE,
30762306a36Sopenharmony_ci			 ~(ENABLE_FV_THROT | ENABLE_FV_UPDATE));
30862306a36Sopenharmony_ci	else
30962306a36Sopenharmony_ci		WREG32_P(FVTHROT_CNTRL_REG, 0,
31062306a36Sopenharmony_ci			 ~(ENABLE_FV_THROT | ENABLE_FV_UPDATE));
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_cistatic void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable)
31462306a36Sopenharmony_ci{
31562306a36Sopenharmony_ci	if (enable)
31662306a36Sopenharmony_ci		WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT_IO, ~ENABLE_FV_THROT_IO);
31762306a36Sopenharmony_ci	else
31862306a36Sopenharmony_ci		WREG32_P(FVTHROT_CNTRL_REG, 0, ~ENABLE_FV_THROT_IO);
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_cistatic void rs780_set_engine_clock_wfc(struct radeon_device *rdev)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	WREG32(FVTHROT_UTC0, RS780_FVTHROTUTC0_DFLT);
32462306a36Sopenharmony_ci	WREG32(FVTHROT_UTC1, RS780_FVTHROTUTC1_DFLT);
32562306a36Sopenharmony_ci	WREG32(FVTHROT_UTC2, RS780_FVTHROTUTC2_DFLT);
32662306a36Sopenharmony_ci	WREG32(FVTHROT_UTC3, RS780_FVTHROTUTC3_DFLT);
32762306a36Sopenharmony_ci	WREG32(FVTHROT_UTC4, RS780_FVTHROTUTC4_DFLT);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	WREG32(FVTHROT_DTC0, RS780_FVTHROTDTC0_DFLT);
33062306a36Sopenharmony_ci	WREG32(FVTHROT_DTC1, RS780_FVTHROTDTC1_DFLT);
33162306a36Sopenharmony_ci	WREG32(FVTHROT_DTC2, RS780_FVTHROTDTC2_DFLT);
33262306a36Sopenharmony_ci	WREG32(FVTHROT_DTC3, RS780_FVTHROTDTC3_DFLT);
33362306a36Sopenharmony_ci	WREG32(FVTHROT_DTC4, RS780_FVTHROTDTC4_DFLT);
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic void rs780_set_engine_clock_sc(struct radeon_device *rdev)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	WREG32_P(FVTHROT_FBDIV_REG2,
33962306a36Sopenharmony_ci		 FB_DIV_TIMER_VAL(RS780_FBDIVTIMERVAL_DFLT),
34062306a36Sopenharmony_ci		 ~FB_DIV_TIMER_VAL_MASK);
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	WREG32_P(FVTHROT_CNTRL_REG,
34362306a36Sopenharmony_ci		 REFRESH_RATE_DIVISOR(0) | MINIMUM_CIP(0xf),
34462306a36Sopenharmony_ci		 ~(REFRESH_RATE_DIVISOR_MASK | MINIMUM_CIP_MASK));
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_cistatic void rs780_set_engine_clock_tdc(struct radeon_device *rdev)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	WREG32_P(FVTHROT_CNTRL_REG, 0, ~(FORCE_TREND_SEL | TREND_SEL_MODE));
35062306a36Sopenharmony_ci}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_cistatic void rs780_set_engine_clock_ssc(struct radeon_device *rdev)
35362306a36Sopenharmony_ci{
35462306a36Sopenharmony_ci	WREG32(FVTHROT_FB_US_REG0, RS780_FVTHROTFBUSREG0_DFLT);
35562306a36Sopenharmony_ci	WREG32(FVTHROT_FB_US_REG1, RS780_FVTHROTFBUSREG1_DFLT);
35662306a36Sopenharmony_ci	WREG32(FVTHROT_FB_DS_REG0, RS780_FVTHROTFBDSREG0_DFLT);
35762306a36Sopenharmony_ci	WREG32(FVTHROT_FB_DS_REG1, RS780_FVTHROTFBDSREG1_DFLT);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	WREG32_P(FVTHROT_FBDIV_REG1, MAX_FEEDBACK_STEP(1), ~MAX_FEEDBACK_STEP_MASK);
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_cistatic void rs780_program_at(struct radeon_device *rdev)
36362306a36Sopenharmony_ci{
36462306a36Sopenharmony_ci	struct igp_power_info *pi = rs780_get_pi(rdev);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	WREG32(FVTHROT_TARGET_REG, 30000000 / pi->refresh_rate);
36762306a36Sopenharmony_ci	WREG32(FVTHROT_CB1, 1000000 * 5 / pi->refresh_rate);
36862306a36Sopenharmony_ci	WREG32(FVTHROT_CB2, 1000000 * 10 / pi->refresh_rate);
36962306a36Sopenharmony_ci	WREG32(FVTHROT_CB3, 1000000 * 30 / pi->refresh_rate);
37062306a36Sopenharmony_ci	WREG32(FVTHROT_CB4, 1000000 * 50 / pi->refresh_rate);
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_cistatic void rs780_disable_vbios_powersaving(struct radeon_device *rdev)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	WREG32_P(CG_INTGFX_MISC, 0, ~0xFFF00000);
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_cistatic void rs780_force_voltage(struct radeon_device *rdev, u16 voltage)
37962306a36Sopenharmony_ci{
38062306a36Sopenharmony_ci	struct igp_ps *current_state = rs780_get_ps(rdev->pm.dpm.current_ps);
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	if ((current_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
38362306a36Sopenharmony_ci	    (current_state->min_voltage == RS780_VDDC_LEVEL_HIGH))
38462306a36Sopenharmony_ci		return;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	udelay(1);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	WREG32_P(FVTHROT_PWM_CTRL_REG0,
39162306a36Sopenharmony_ci		 STARTING_PWM_HIGHTIME(voltage),
39262306a36Sopenharmony_ci		 ~STARTING_PWM_HIGHTIME_MASK);
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	WREG32_P(FVTHROT_PWM_CTRL_REG0,
39562306a36Sopenharmony_ci		 FORCE_STARTING_PWM_HIGHTIME, ~FORCE_STARTING_PWM_HIGHTIME);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1, 0,
39862306a36Sopenharmony_ci		~RANGE_PWM_FEEDBACK_DIV_EN);
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	udelay(1);
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cistatic void rs780_force_fbdiv(struct radeon_device *rdev, u32 fb_div)
40662306a36Sopenharmony_ci{
40762306a36Sopenharmony_ci	struct igp_ps *current_state = rs780_get_ps(rdev->pm.dpm.current_ps);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	if (current_state->sclk_low == current_state->sclk_high)
41062306a36Sopenharmony_ci		return;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(fb_div),
41562306a36Sopenharmony_ci		 ~FORCED_FEEDBACK_DIV_MASK);
41662306a36Sopenharmony_ci	WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(fb_div),
41762306a36Sopenharmony_ci		 ~STARTING_FEEDBACK_DIV_MASK);
41862306a36Sopenharmony_ci	WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	udelay(100);
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
42362306a36Sopenharmony_ci}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_cistatic int rs780_set_engine_clock_scaling(struct radeon_device *rdev,
42662306a36Sopenharmony_ci					  struct radeon_ps *new_ps,
42762306a36Sopenharmony_ci					  struct radeon_ps *old_ps)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	struct atom_clock_dividers min_dividers, max_dividers, current_max_dividers;
43062306a36Sopenharmony_ci	struct igp_ps *new_state = rs780_get_ps(new_ps);
43162306a36Sopenharmony_ci	struct igp_ps *old_state = rs780_get_ps(old_ps);
43262306a36Sopenharmony_ci	int ret;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	if ((new_state->sclk_high == old_state->sclk_high) &&
43562306a36Sopenharmony_ci	    (new_state->sclk_low == old_state->sclk_low))
43662306a36Sopenharmony_ci		return 0;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
43962306a36Sopenharmony_ci					     new_state->sclk_low, false, &min_dividers);
44062306a36Sopenharmony_ci	if (ret)
44162306a36Sopenharmony_ci		return ret;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
44462306a36Sopenharmony_ci					     new_state->sclk_high, false, &max_dividers);
44562306a36Sopenharmony_ci	if (ret)
44662306a36Sopenharmony_ci		return ret;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
44962306a36Sopenharmony_ci					     old_state->sclk_high, false, &current_max_dividers);
45062306a36Sopenharmony_ci	if (ret)
45162306a36Sopenharmony_ci		return ret;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	if ((min_dividers.ref_div != max_dividers.ref_div) ||
45462306a36Sopenharmony_ci	    (min_dividers.post_div != max_dividers.post_div) ||
45562306a36Sopenharmony_ci	    (max_dividers.ref_div != current_max_dividers.ref_div) ||
45662306a36Sopenharmony_ci	    (max_dividers.post_div != current_max_dividers.post_div))
45762306a36Sopenharmony_ci		return -EINVAL;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	rs780_force_fbdiv(rdev, max_dividers.fb_div);
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	if (max_dividers.fb_div > min_dividers.fb_div) {
46262306a36Sopenharmony_ci		WREG32_P(FVTHROT_FBDIV_REG0,
46362306a36Sopenharmony_ci			 MIN_FEEDBACK_DIV(min_dividers.fb_div) |
46462306a36Sopenharmony_ci			 MAX_FEEDBACK_DIV(max_dividers.fb_div),
46562306a36Sopenharmony_ci			 ~(MIN_FEEDBACK_DIV_MASK | MAX_FEEDBACK_DIV_MASK));
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci		WREG32_P(FVTHROT_FBDIV_REG1, 0, ~FORCE_FEEDBACK_DIV);
46862306a36Sopenharmony_ci	}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	return 0;
47162306a36Sopenharmony_ci}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_cistatic void rs780_set_engine_clock_spc(struct radeon_device *rdev,
47462306a36Sopenharmony_ci				       struct radeon_ps *new_ps,
47562306a36Sopenharmony_ci				       struct radeon_ps *old_ps)
47662306a36Sopenharmony_ci{
47762306a36Sopenharmony_ci	struct igp_ps *new_state = rs780_get_ps(new_ps);
47862306a36Sopenharmony_ci	struct igp_ps *old_state = rs780_get_ps(old_ps);
47962306a36Sopenharmony_ci	struct igp_power_info *pi = rs780_get_pi(rdev);
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	if ((new_state->sclk_high == old_state->sclk_high) &&
48262306a36Sopenharmony_ci	    (new_state->sclk_low == old_state->sclk_low))
48362306a36Sopenharmony_ci		return;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	if (pi->crtc_id == 0)
48662306a36Sopenharmony_ci		WREG32_P(CG_INTGFX_MISC, 0, ~FVTHROT_VBLANK_SEL);
48762306a36Sopenharmony_ci	else
48862306a36Sopenharmony_ci		WREG32_P(CG_INTGFX_MISC, FVTHROT_VBLANK_SEL, ~FVTHROT_VBLANK_SEL);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_cistatic void rs780_activate_engine_clk_scaling(struct radeon_device *rdev,
49362306a36Sopenharmony_ci					      struct radeon_ps *new_ps,
49462306a36Sopenharmony_ci					      struct radeon_ps *old_ps)
49562306a36Sopenharmony_ci{
49662306a36Sopenharmony_ci	struct igp_ps *new_state = rs780_get_ps(new_ps);
49762306a36Sopenharmony_ci	struct igp_ps *old_state = rs780_get_ps(old_ps);
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	if ((new_state->sclk_high == old_state->sclk_high) &&
50062306a36Sopenharmony_ci	    (new_state->sclk_low == old_state->sclk_low))
50162306a36Sopenharmony_ci		return;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	if (new_state->sclk_high == new_state->sclk_low)
50462306a36Sopenharmony_ci		return;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	rs780_clk_scaling_enable(rdev, true);
50762306a36Sopenharmony_ci}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_cistatic u32 rs780_get_voltage_for_vddc_level(struct radeon_device *rdev,
51062306a36Sopenharmony_ci					    enum rs780_vddc_level vddc)
51162306a36Sopenharmony_ci{
51262306a36Sopenharmony_ci	struct igp_power_info *pi = rs780_get_pi(rdev);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	if (vddc == RS780_VDDC_LEVEL_HIGH)
51562306a36Sopenharmony_ci		return pi->max_voltage;
51662306a36Sopenharmony_ci	else if (vddc == RS780_VDDC_LEVEL_LOW)
51762306a36Sopenharmony_ci		return pi->min_voltage;
51862306a36Sopenharmony_ci	else
51962306a36Sopenharmony_ci		return pi->max_voltage;
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_cistatic void rs780_enable_voltage_scaling(struct radeon_device *rdev,
52362306a36Sopenharmony_ci					 struct radeon_ps *new_ps)
52462306a36Sopenharmony_ci{
52562306a36Sopenharmony_ci	struct igp_ps *new_state = rs780_get_ps(new_ps);
52662306a36Sopenharmony_ci	struct igp_power_info *pi = rs780_get_pi(rdev);
52762306a36Sopenharmony_ci	enum rs780_vddc_level vddc_high, vddc_low;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	udelay(100);
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	if ((new_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
53262306a36Sopenharmony_ci	    (new_state->min_voltage == RS780_VDDC_LEVEL_HIGH))
53362306a36Sopenharmony_ci		return;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	vddc_high = rs780_get_voltage_for_vddc_level(rdev,
53662306a36Sopenharmony_ci						     new_state->max_voltage);
53762306a36Sopenharmony_ci	vddc_low = rs780_get_voltage_for_vddc_level(rdev,
53862306a36Sopenharmony_ci						    new_state->min_voltage);
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	udelay(1);
54362306a36Sopenharmony_ci	if (vddc_high > vddc_low) {
54462306a36Sopenharmony_ci		WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1,
54562306a36Sopenharmony_ci			 RANGE_PWM_FEEDBACK_DIV_EN, ~RANGE_PWM_FEEDBACK_DIV_EN);
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci		WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~FORCE_STARTING_PWM_HIGHTIME);
54862306a36Sopenharmony_ci	} else if (vddc_high == vddc_low) {
54962306a36Sopenharmony_ci		if (pi->max_voltage != vddc_high) {
55062306a36Sopenharmony_ci			WREG32_P(FVTHROT_PWM_CTRL_REG0,
55162306a36Sopenharmony_ci				 STARTING_PWM_HIGHTIME(vddc_high),
55262306a36Sopenharmony_ci				 ~STARTING_PWM_HIGHTIME_MASK);
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci			WREG32_P(FVTHROT_PWM_CTRL_REG0,
55562306a36Sopenharmony_ci				 FORCE_STARTING_PWM_HIGHTIME,
55662306a36Sopenharmony_ci				 ~FORCE_STARTING_PWM_HIGHTIME);
55762306a36Sopenharmony_ci		}
55862306a36Sopenharmony_ci	}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
56162306a36Sopenharmony_ci}
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_cistatic void rs780_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev,
56462306a36Sopenharmony_ci						     struct radeon_ps *new_ps,
56562306a36Sopenharmony_ci						     struct radeon_ps *old_ps)
56662306a36Sopenharmony_ci{
56762306a36Sopenharmony_ci	struct igp_ps *new_state = rs780_get_ps(new_ps);
56862306a36Sopenharmony_ci	struct igp_ps *current_state = rs780_get_ps(old_ps);
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	if ((new_ps->vclk == old_ps->vclk) &&
57162306a36Sopenharmony_ci	    (new_ps->dclk == old_ps->dclk))
57262306a36Sopenharmony_ci		return;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	if (new_state->sclk_high >= current_state->sclk_high)
57562306a36Sopenharmony_ci		return;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk);
57862306a36Sopenharmony_ci}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_cistatic void rs780_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
58162306a36Sopenharmony_ci						    struct radeon_ps *new_ps,
58262306a36Sopenharmony_ci						    struct radeon_ps *old_ps)
58362306a36Sopenharmony_ci{
58462306a36Sopenharmony_ci	struct igp_ps *new_state = rs780_get_ps(new_ps);
58562306a36Sopenharmony_ci	struct igp_ps *current_state = rs780_get_ps(old_ps);
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	if ((new_ps->vclk == old_ps->vclk) &&
58862306a36Sopenharmony_ci	    (new_ps->dclk == old_ps->dclk))
58962306a36Sopenharmony_ci		return;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	if (new_state->sclk_high < current_state->sclk_high)
59262306a36Sopenharmony_ci		return;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk);
59562306a36Sopenharmony_ci}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ciint rs780_dpm_enable(struct radeon_device *rdev)
59862306a36Sopenharmony_ci{
59962306a36Sopenharmony_ci	struct igp_power_info *pi = rs780_get_pi(rdev);
60062306a36Sopenharmony_ci	struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
60162306a36Sopenharmony_ci	int ret;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	rs780_get_pm_mode_parameters(rdev);
60462306a36Sopenharmony_ci	rs780_disable_vbios_powersaving(rdev);
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	if (r600_dynamicpm_enabled(rdev))
60762306a36Sopenharmony_ci		return -EINVAL;
60862306a36Sopenharmony_ci	ret = rs780_initialize_dpm_parameters(rdev, boot_ps);
60962306a36Sopenharmony_ci	if (ret)
61062306a36Sopenharmony_ci		return ret;
61162306a36Sopenharmony_ci	rs780_start_dpm(rdev);
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	rs780_preset_ranges_slow_clk_fbdiv_en(rdev);
61462306a36Sopenharmony_ci	rs780_preset_starting_fbdiv(rdev);
61562306a36Sopenharmony_ci	if (pi->voltage_control)
61662306a36Sopenharmony_ci		rs780_voltage_scaling_init(rdev);
61762306a36Sopenharmony_ci	rs780_clk_scaling_enable(rdev, true);
61862306a36Sopenharmony_ci	rs780_set_engine_clock_sc(rdev);
61962306a36Sopenharmony_ci	rs780_set_engine_clock_wfc(rdev);
62062306a36Sopenharmony_ci	rs780_program_at(rdev);
62162306a36Sopenharmony_ci	rs780_set_engine_clock_tdc(rdev);
62262306a36Sopenharmony_ci	rs780_set_engine_clock_ssc(rdev);
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	if (pi->gfx_clock_gating)
62562306a36Sopenharmony_ci		r600_gfx_clockgating_enable(rdev, true);
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	return 0;
62862306a36Sopenharmony_ci}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_civoid rs780_dpm_disable(struct radeon_device *rdev)
63162306a36Sopenharmony_ci{
63262306a36Sopenharmony_ci	struct igp_power_info *pi = rs780_get_pi(rdev);
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	r600_dynamicpm_enable(rdev, false);
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	rs780_clk_scaling_enable(rdev, false);
63762306a36Sopenharmony_ci	rs780_voltage_scaling_enable(rdev, false);
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	if (pi->gfx_clock_gating)
64062306a36Sopenharmony_ci		r600_gfx_clockgating_enable(rdev, false);
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	if (rdev->irq.installed &&
64362306a36Sopenharmony_ci	    (rdev->pm.int_thermal_type == THERMAL_TYPE_RV6XX)) {
64462306a36Sopenharmony_ci		rdev->irq.dpm_thermal = false;
64562306a36Sopenharmony_ci		radeon_irq_set(rdev);
64662306a36Sopenharmony_ci	}
64762306a36Sopenharmony_ci}
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ciint rs780_dpm_set_power_state(struct radeon_device *rdev)
65062306a36Sopenharmony_ci{
65162306a36Sopenharmony_ci	struct igp_power_info *pi = rs780_get_pi(rdev);
65262306a36Sopenharmony_ci	struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps;
65362306a36Sopenharmony_ci	struct radeon_ps *old_ps = rdev->pm.dpm.current_ps;
65462306a36Sopenharmony_ci	int ret;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	rs780_get_pm_mode_parameters(rdev);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	rs780_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	if (pi->voltage_control) {
66162306a36Sopenharmony_ci		rs780_force_voltage(rdev, pi->max_voltage);
66262306a36Sopenharmony_ci		mdelay(5);
66362306a36Sopenharmony_ci	}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	ret = rs780_set_engine_clock_scaling(rdev, new_ps, old_ps);
66662306a36Sopenharmony_ci	if (ret)
66762306a36Sopenharmony_ci		return ret;
66862306a36Sopenharmony_ci	rs780_set_engine_clock_spc(rdev, new_ps, old_ps);
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	rs780_activate_engine_clk_scaling(rdev, new_ps, old_ps);
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	if (pi->voltage_control)
67362306a36Sopenharmony_ci		rs780_enable_voltage_scaling(rdev, new_ps);
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	rs780_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	return 0;
67862306a36Sopenharmony_ci}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_civoid rs780_dpm_setup_asic(struct radeon_device *rdev)
68162306a36Sopenharmony_ci{
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci}
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_civoid rs780_dpm_display_configuration_changed(struct radeon_device *rdev)
68662306a36Sopenharmony_ci{
68762306a36Sopenharmony_ci	rs780_get_pm_mode_parameters(rdev);
68862306a36Sopenharmony_ci	rs780_program_at(rdev);
68962306a36Sopenharmony_ci}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ciunion igp_info {
69262306a36Sopenharmony_ci	struct _ATOM_INTEGRATED_SYSTEM_INFO info;
69362306a36Sopenharmony_ci	struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
69462306a36Sopenharmony_ci};
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ciunion power_info {
69762306a36Sopenharmony_ci	struct _ATOM_POWERPLAY_INFO info;
69862306a36Sopenharmony_ci	struct _ATOM_POWERPLAY_INFO_V2 info_2;
69962306a36Sopenharmony_ci	struct _ATOM_POWERPLAY_INFO_V3 info_3;
70062306a36Sopenharmony_ci	struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
70162306a36Sopenharmony_ci	struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
70262306a36Sopenharmony_ci	struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
70362306a36Sopenharmony_ci};
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ciunion pplib_clock_info {
70662306a36Sopenharmony_ci	struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
70762306a36Sopenharmony_ci	struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
70862306a36Sopenharmony_ci	struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
70962306a36Sopenharmony_ci	struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
71062306a36Sopenharmony_ci};
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ciunion pplib_power_state {
71362306a36Sopenharmony_ci	struct _ATOM_PPLIB_STATE v1;
71462306a36Sopenharmony_ci	struct _ATOM_PPLIB_STATE_V2 v2;
71562306a36Sopenharmony_ci};
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_cistatic void rs780_parse_pplib_non_clock_info(struct radeon_device *rdev,
71862306a36Sopenharmony_ci					     struct radeon_ps *rps,
71962306a36Sopenharmony_ci					     struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
72062306a36Sopenharmony_ci					     u8 table_rev)
72162306a36Sopenharmony_ci{
72262306a36Sopenharmony_ci	rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
72362306a36Sopenharmony_ci	rps->class = le16_to_cpu(non_clock_info->usClassification);
72462306a36Sopenharmony_ci	rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
72762306a36Sopenharmony_ci		rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
72862306a36Sopenharmony_ci		rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
72962306a36Sopenharmony_ci	} else {
73062306a36Sopenharmony_ci		rps->vclk = 0;
73162306a36Sopenharmony_ci		rps->dclk = 0;
73262306a36Sopenharmony_ci	}
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	if (r600_is_uvd_state(rps->class, rps->class2)) {
73562306a36Sopenharmony_ci		if ((rps->vclk == 0) || (rps->dclk == 0)) {
73662306a36Sopenharmony_ci			rps->vclk = RS780_DEFAULT_VCLK_FREQ;
73762306a36Sopenharmony_ci			rps->dclk = RS780_DEFAULT_DCLK_FREQ;
73862306a36Sopenharmony_ci		}
73962306a36Sopenharmony_ci	}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
74262306a36Sopenharmony_ci		rdev->pm.dpm.boot_ps = rps;
74362306a36Sopenharmony_ci	if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
74462306a36Sopenharmony_ci		rdev->pm.dpm.uvd_ps = rps;
74562306a36Sopenharmony_ci}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_cistatic void rs780_parse_pplib_clock_info(struct radeon_device *rdev,
74862306a36Sopenharmony_ci					 struct radeon_ps *rps,
74962306a36Sopenharmony_ci					 union pplib_clock_info *clock_info)
75062306a36Sopenharmony_ci{
75162306a36Sopenharmony_ci	struct igp_ps *ps = rs780_get_ps(rps);
75262306a36Sopenharmony_ci	u32 sclk;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow);
75562306a36Sopenharmony_ci	sclk |= clock_info->rs780.ucLowEngineClockHigh << 16;
75662306a36Sopenharmony_ci	ps->sclk_low = sclk;
75762306a36Sopenharmony_ci	sclk = le16_to_cpu(clock_info->rs780.usHighEngineClockLow);
75862306a36Sopenharmony_ci	sclk |= clock_info->rs780.ucHighEngineClockHigh << 16;
75962306a36Sopenharmony_ci	ps->sclk_high = sclk;
76062306a36Sopenharmony_ci	switch (le16_to_cpu(clock_info->rs780.usVDDC)) {
76162306a36Sopenharmony_ci	case ATOM_PPLIB_RS780_VOLTAGE_NONE:
76262306a36Sopenharmony_ci	default:
76362306a36Sopenharmony_ci		ps->min_voltage = RS780_VDDC_LEVEL_UNKNOWN;
76462306a36Sopenharmony_ci		ps->max_voltage = RS780_VDDC_LEVEL_UNKNOWN;
76562306a36Sopenharmony_ci		break;
76662306a36Sopenharmony_ci	case ATOM_PPLIB_RS780_VOLTAGE_LOW:
76762306a36Sopenharmony_ci		ps->min_voltage = RS780_VDDC_LEVEL_LOW;
76862306a36Sopenharmony_ci		ps->max_voltage = RS780_VDDC_LEVEL_LOW;
76962306a36Sopenharmony_ci		break;
77062306a36Sopenharmony_ci	case ATOM_PPLIB_RS780_VOLTAGE_HIGH:
77162306a36Sopenharmony_ci		ps->min_voltage = RS780_VDDC_LEVEL_HIGH;
77262306a36Sopenharmony_ci		ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
77362306a36Sopenharmony_ci		break;
77462306a36Sopenharmony_ci	case ATOM_PPLIB_RS780_VOLTAGE_VARIABLE:
77562306a36Sopenharmony_ci		ps->min_voltage = RS780_VDDC_LEVEL_LOW;
77662306a36Sopenharmony_ci		ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
77762306a36Sopenharmony_ci		break;
77862306a36Sopenharmony_ci	}
77962306a36Sopenharmony_ci	ps->flags = le32_to_cpu(clock_info->rs780.ulFlags);
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
78262306a36Sopenharmony_ci		ps->sclk_low = rdev->clock.default_sclk;
78362306a36Sopenharmony_ci		ps->sclk_high = rdev->clock.default_sclk;
78462306a36Sopenharmony_ci		ps->min_voltage = RS780_VDDC_LEVEL_HIGH;
78562306a36Sopenharmony_ci		ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
78662306a36Sopenharmony_ci	}
78762306a36Sopenharmony_ci}
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_cistatic int rs780_parse_power_table(struct radeon_device *rdev)
79062306a36Sopenharmony_ci{
79162306a36Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
79262306a36Sopenharmony_ci	struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
79362306a36Sopenharmony_ci	union pplib_power_state *power_state;
79462306a36Sopenharmony_ci	int i;
79562306a36Sopenharmony_ci	union pplib_clock_info *clock_info;
79662306a36Sopenharmony_ci	union power_info *power_info;
79762306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
79862306a36Sopenharmony_ci	u16 data_offset;
79962306a36Sopenharmony_ci	u8 frev, crev;
80062306a36Sopenharmony_ci	struct igp_ps *ps;
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
80362306a36Sopenharmony_ci				   &frev, &crev, &data_offset))
80462306a36Sopenharmony_ci		return -EINVAL;
80562306a36Sopenharmony_ci	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	rdev->pm.dpm.ps = kcalloc(power_info->pplib.ucNumStates,
80862306a36Sopenharmony_ci				  sizeof(struct radeon_ps),
80962306a36Sopenharmony_ci				  GFP_KERNEL);
81062306a36Sopenharmony_ci	if (!rdev->pm.dpm.ps)
81162306a36Sopenharmony_ci		return -ENOMEM;
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	for (i = 0; i < power_info->pplib.ucNumStates; i++) {
81462306a36Sopenharmony_ci		power_state = (union pplib_power_state *)
81562306a36Sopenharmony_ci			(mode_info->atom_context->bios + data_offset +
81662306a36Sopenharmony_ci			 le16_to_cpu(power_info->pplib.usStateArrayOffset) +
81762306a36Sopenharmony_ci			 i * power_info->pplib.ucStateEntrySize);
81862306a36Sopenharmony_ci		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
81962306a36Sopenharmony_ci			(mode_info->atom_context->bios + data_offset +
82062306a36Sopenharmony_ci			 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
82162306a36Sopenharmony_ci			 (power_state->v1.ucNonClockStateIndex *
82262306a36Sopenharmony_ci			  power_info->pplib.ucNonClockSize));
82362306a36Sopenharmony_ci		if (power_info->pplib.ucStateEntrySize - 1) {
82462306a36Sopenharmony_ci			clock_info = (union pplib_clock_info *)
82562306a36Sopenharmony_ci				(mode_info->atom_context->bios + data_offset +
82662306a36Sopenharmony_ci				 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
82762306a36Sopenharmony_ci				 (power_state->v1.ucClockStateIndices[0] *
82862306a36Sopenharmony_ci				  power_info->pplib.ucClockInfoSize));
82962306a36Sopenharmony_ci			ps = kzalloc(sizeof(struct igp_ps), GFP_KERNEL);
83062306a36Sopenharmony_ci			if (ps == NULL) {
83162306a36Sopenharmony_ci				kfree(rdev->pm.dpm.ps);
83262306a36Sopenharmony_ci				return -ENOMEM;
83362306a36Sopenharmony_ci			}
83462306a36Sopenharmony_ci			rdev->pm.dpm.ps[i].ps_priv = ps;
83562306a36Sopenharmony_ci			rs780_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
83662306a36Sopenharmony_ci							 non_clock_info,
83762306a36Sopenharmony_ci							 power_info->pplib.ucNonClockSize);
83862306a36Sopenharmony_ci			rs780_parse_pplib_clock_info(rdev,
83962306a36Sopenharmony_ci						     &rdev->pm.dpm.ps[i],
84062306a36Sopenharmony_ci						     clock_info);
84162306a36Sopenharmony_ci		}
84262306a36Sopenharmony_ci	}
84362306a36Sopenharmony_ci	rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates;
84462306a36Sopenharmony_ci	return 0;
84562306a36Sopenharmony_ci}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ciint rs780_dpm_init(struct radeon_device *rdev)
84862306a36Sopenharmony_ci{
84962306a36Sopenharmony_ci	struct igp_power_info *pi;
85062306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
85162306a36Sopenharmony_ci	union igp_info *info;
85262306a36Sopenharmony_ci	u16 data_offset;
85362306a36Sopenharmony_ci	u8 frev, crev;
85462306a36Sopenharmony_ci	int ret;
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	pi = kzalloc(sizeof(struct igp_power_info), GFP_KERNEL);
85762306a36Sopenharmony_ci	if (pi == NULL)
85862306a36Sopenharmony_ci		return -ENOMEM;
85962306a36Sopenharmony_ci	rdev->pm.dpm.priv = pi;
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	ret = r600_get_platform_caps(rdev);
86262306a36Sopenharmony_ci	if (ret)
86362306a36Sopenharmony_ci		return ret;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	ret = rs780_parse_power_table(rdev);
86662306a36Sopenharmony_ci	if (ret)
86762306a36Sopenharmony_ci		return ret;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	pi->voltage_control = false;
87062306a36Sopenharmony_ci	pi->gfx_clock_gating = true;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	if (atom_parse_data_header(rdev->mode_info.atom_context, index, NULL,
87362306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
87462306a36Sopenharmony_ci		info = (union igp_info *)(rdev->mode_info.atom_context->bios + data_offset);
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci		/* Get various system informations from bios */
87762306a36Sopenharmony_ci		switch (crev) {
87862306a36Sopenharmony_ci		case 1:
87962306a36Sopenharmony_ci			pi->num_of_cycles_in_period =
88062306a36Sopenharmony_ci				info->info.ucNumberOfCyclesInPeriod;
88162306a36Sopenharmony_ci			pi->num_of_cycles_in_period |=
88262306a36Sopenharmony_ci				info->info.ucNumberOfCyclesInPeriodHi << 8;
88362306a36Sopenharmony_ci			pi->invert_pwm_required =
88462306a36Sopenharmony_ci				(pi->num_of_cycles_in_period & 0x8000) ? true : false;
88562306a36Sopenharmony_ci			pi->boot_voltage = info->info.ucStartingPWM_HighTime;
88662306a36Sopenharmony_ci			pi->max_voltage = info->info.ucMaxNBVoltage;
88762306a36Sopenharmony_ci			pi->max_voltage |= info->info.ucMaxNBVoltageHigh << 8;
88862306a36Sopenharmony_ci			pi->min_voltage = info->info.ucMinNBVoltage;
88962306a36Sopenharmony_ci			pi->min_voltage |= info->info.ucMinNBVoltageHigh << 8;
89062306a36Sopenharmony_ci			pi->inter_voltage_low =
89162306a36Sopenharmony_ci				le16_to_cpu(info->info.usInterNBVoltageLow);
89262306a36Sopenharmony_ci			pi->inter_voltage_high =
89362306a36Sopenharmony_ci				le16_to_cpu(info->info.usInterNBVoltageHigh);
89462306a36Sopenharmony_ci			pi->voltage_control = true;
89562306a36Sopenharmony_ci			pi->bootup_uma_clk = info->info.usK8MemoryClock * 100;
89662306a36Sopenharmony_ci			break;
89762306a36Sopenharmony_ci		case 2:
89862306a36Sopenharmony_ci			pi->num_of_cycles_in_period =
89962306a36Sopenharmony_ci				le16_to_cpu(info->info_2.usNumberOfCyclesInPeriod);
90062306a36Sopenharmony_ci			pi->invert_pwm_required =
90162306a36Sopenharmony_ci				(pi->num_of_cycles_in_period & 0x8000) ? true : false;
90262306a36Sopenharmony_ci			pi->boot_voltage =
90362306a36Sopenharmony_ci				le16_to_cpu(info->info_2.usBootUpNBVoltage);
90462306a36Sopenharmony_ci			pi->max_voltage =
90562306a36Sopenharmony_ci				le16_to_cpu(info->info_2.usMaxNBVoltage);
90662306a36Sopenharmony_ci			pi->min_voltage =
90762306a36Sopenharmony_ci				le16_to_cpu(info->info_2.usMinNBVoltage);
90862306a36Sopenharmony_ci			pi->system_config =
90962306a36Sopenharmony_ci				le32_to_cpu(info->info_2.ulSystemConfig);
91062306a36Sopenharmony_ci			pi->pwm_voltage_control =
91162306a36Sopenharmony_ci				(pi->system_config & 0x4) ? true : false;
91262306a36Sopenharmony_ci			pi->voltage_control = true;
91362306a36Sopenharmony_ci			pi->bootup_uma_clk = le32_to_cpu(info->info_2.ulBootUpUMAClock);
91462306a36Sopenharmony_ci			break;
91562306a36Sopenharmony_ci		default:
91662306a36Sopenharmony_ci			DRM_ERROR("No integrated system info for your GPU\n");
91762306a36Sopenharmony_ci			return -EINVAL;
91862306a36Sopenharmony_ci		}
91962306a36Sopenharmony_ci		if (pi->min_voltage > pi->max_voltage)
92062306a36Sopenharmony_ci			pi->voltage_control = false;
92162306a36Sopenharmony_ci		if (pi->pwm_voltage_control) {
92262306a36Sopenharmony_ci			if ((pi->num_of_cycles_in_period == 0) ||
92362306a36Sopenharmony_ci			    (pi->max_voltage == 0) ||
92462306a36Sopenharmony_ci			    (pi->min_voltage == 0))
92562306a36Sopenharmony_ci				pi->voltage_control = false;
92662306a36Sopenharmony_ci		} else {
92762306a36Sopenharmony_ci			if ((pi->num_of_cycles_in_period == 0) ||
92862306a36Sopenharmony_ci			    (pi->max_voltage == 0))
92962306a36Sopenharmony_ci				pi->voltage_control = false;
93062306a36Sopenharmony_ci		}
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci		return 0;
93362306a36Sopenharmony_ci	}
93462306a36Sopenharmony_ci	radeon_dpm_fini(rdev);
93562306a36Sopenharmony_ci	return -EINVAL;
93662306a36Sopenharmony_ci}
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_civoid rs780_dpm_print_power_state(struct radeon_device *rdev,
93962306a36Sopenharmony_ci				 struct radeon_ps *rps)
94062306a36Sopenharmony_ci{
94162306a36Sopenharmony_ci	struct igp_ps *ps = rs780_get_ps(rps);
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	r600_dpm_print_class_info(rps->class, rps->class2);
94462306a36Sopenharmony_ci	r600_dpm_print_cap_info(rps->caps);
94562306a36Sopenharmony_ci	printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
94662306a36Sopenharmony_ci	printk("\t\tpower level 0    sclk: %u vddc_index: %d\n",
94762306a36Sopenharmony_ci	       ps->sclk_low, ps->min_voltage);
94862306a36Sopenharmony_ci	printk("\t\tpower level 1    sclk: %u vddc_index: %d\n",
94962306a36Sopenharmony_ci	       ps->sclk_high, ps->max_voltage);
95062306a36Sopenharmony_ci	r600_dpm_print_ps_status(rdev, rps);
95162306a36Sopenharmony_ci}
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_civoid rs780_dpm_fini(struct radeon_device *rdev)
95462306a36Sopenharmony_ci{
95562306a36Sopenharmony_ci	int i;
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
95862306a36Sopenharmony_ci		kfree(rdev->pm.dpm.ps[i].ps_priv);
95962306a36Sopenharmony_ci	}
96062306a36Sopenharmony_ci	kfree(rdev->pm.dpm.ps);
96162306a36Sopenharmony_ci	kfree(rdev->pm.dpm.priv);
96262306a36Sopenharmony_ci}
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ciu32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low)
96562306a36Sopenharmony_ci{
96662306a36Sopenharmony_ci	struct igp_ps *requested_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	if (low)
96962306a36Sopenharmony_ci		return requested_state->sclk_low;
97062306a36Sopenharmony_ci	else
97162306a36Sopenharmony_ci		return requested_state->sclk_high;
97262306a36Sopenharmony_ci}
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ciu32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low)
97562306a36Sopenharmony_ci{
97662306a36Sopenharmony_ci	struct igp_power_info *pi = rs780_get_pi(rdev);
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	return pi->bootup_uma_clk;
97962306a36Sopenharmony_ci}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_civoid rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
98262306a36Sopenharmony_ci						       struct seq_file *m)
98362306a36Sopenharmony_ci{
98462306a36Sopenharmony_ci	struct radeon_ps *rps = rdev->pm.dpm.current_ps;
98562306a36Sopenharmony_ci	struct igp_ps *ps = rs780_get_ps(rps);
98662306a36Sopenharmony_ci	u32 current_fb_div = RREG32(FVTHROT_STATUS_REG0) & CURRENT_FEEDBACK_DIV_MASK;
98762306a36Sopenharmony_ci	u32 func_cntl = RREG32(CG_SPLL_FUNC_CNTL);
98862306a36Sopenharmony_ci	u32 ref_div = ((func_cntl & SPLL_REF_DIV_MASK) >> SPLL_REF_DIV_SHIFT) + 1;
98962306a36Sopenharmony_ci	u32 post_div = ((func_cntl & SPLL_SW_HILEN_MASK) >> SPLL_SW_HILEN_SHIFT) + 1 +
99062306a36Sopenharmony_ci		((func_cntl & SPLL_SW_LOLEN_MASK) >> SPLL_SW_LOLEN_SHIFT) + 1;
99162306a36Sopenharmony_ci	u32 sclk = (rdev->clock.spll.reference_freq * current_fb_div) /
99262306a36Sopenharmony_ci		(post_div * ref_div);
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	seq_printf(m, "uvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	/* guess based on the current sclk */
99762306a36Sopenharmony_ci	if (sclk < (ps->sclk_low + 500))
99862306a36Sopenharmony_ci		seq_printf(m, "power level 0    sclk: %u vddc_index: %d\n",
99962306a36Sopenharmony_ci			   ps->sclk_low, ps->min_voltage);
100062306a36Sopenharmony_ci	else
100162306a36Sopenharmony_ci		seq_printf(m, "power level 1    sclk: %u vddc_index: %d\n",
100262306a36Sopenharmony_ci			   ps->sclk_high, ps->max_voltage);
100362306a36Sopenharmony_ci}
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci/* get the current sclk in 10 khz units */
100662306a36Sopenharmony_ciu32 rs780_dpm_get_current_sclk(struct radeon_device *rdev)
100762306a36Sopenharmony_ci{
100862306a36Sopenharmony_ci	u32 current_fb_div = RREG32(FVTHROT_STATUS_REG0) & CURRENT_FEEDBACK_DIV_MASK;
100962306a36Sopenharmony_ci	u32 func_cntl = RREG32(CG_SPLL_FUNC_CNTL);
101062306a36Sopenharmony_ci	u32 ref_div = ((func_cntl & SPLL_REF_DIV_MASK) >> SPLL_REF_DIV_SHIFT) + 1;
101162306a36Sopenharmony_ci	u32 post_div = ((func_cntl & SPLL_SW_HILEN_MASK) >> SPLL_SW_HILEN_SHIFT) + 1 +
101262306a36Sopenharmony_ci		((func_cntl & SPLL_SW_LOLEN_MASK) >> SPLL_SW_LOLEN_SHIFT) + 1;
101362306a36Sopenharmony_ci	u32 sclk = (rdev->clock.spll.reference_freq * current_fb_div) /
101462306a36Sopenharmony_ci		(post_div * ref_div);
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	return sclk;
101762306a36Sopenharmony_ci}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci/* get the current mclk in 10 khz units */
102062306a36Sopenharmony_ciu32 rs780_dpm_get_current_mclk(struct radeon_device *rdev)
102162306a36Sopenharmony_ci{
102262306a36Sopenharmony_ci	struct igp_power_info *pi = rs780_get_pi(rdev);
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	return pi->bootup_uma_clk;
102562306a36Sopenharmony_ci}
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ciint rs780_dpm_force_performance_level(struct radeon_device *rdev,
102862306a36Sopenharmony_ci				      enum radeon_dpm_forced_level level)
102962306a36Sopenharmony_ci{
103062306a36Sopenharmony_ci	struct igp_power_info *pi = rs780_get_pi(rdev);
103162306a36Sopenharmony_ci	struct radeon_ps *rps = rdev->pm.dpm.current_ps;
103262306a36Sopenharmony_ci	struct igp_ps *ps = rs780_get_ps(rps);
103362306a36Sopenharmony_ci	struct atom_clock_dividers dividers;
103462306a36Sopenharmony_ci	int ret;
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	rs780_clk_scaling_enable(rdev, false);
103762306a36Sopenharmony_ci	rs780_voltage_scaling_enable(rdev, false);
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
104062306a36Sopenharmony_ci		if (pi->voltage_control)
104162306a36Sopenharmony_ci			rs780_force_voltage(rdev, pi->max_voltage);
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci		ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
104462306a36Sopenharmony_ci						     ps->sclk_high, false, &dividers);
104562306a36Sopenharmony_ci		if (ret)
104662306a36Sopenharmony_ci			return ret;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci		rs780_force_fbdiv(rdev, dividers.fb_div);
104962306a36Sopenharmony_ci	} else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
105062306a36Sopenharmony_ci		ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
105162306a36Sopenharmony_ci						     ps->sclk_low, false, &dividers);
105262306a36Sopenharmony_ci		if (ret)
105362306a36Sopenharmony_ci			return ret;
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci		rs780_force_fbdiv(rdev, dividers.fb_div);
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci		if (pi->voltage_control)
105862306a36Sopenharmony_ci			rs780_force_voltage(rdev, pi->min_voltage);
105962306a36Sopenharmony_ci	} else {
106062306a36Sopenharmony_ci		if (pi->voltage_control)
106162306a36Sopenharmony_ci			rs780_force_voltage(rdev, pi->max_voltage);
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci		if (ps->sclk_high != ps->sclk_low) {
106462306a36Sopenharmony_ci			WREG32_P(FVTHROT_FBDIV_REG1, 0, ~FORCE_FEEDBACK_DIV);
106562306a36Sopenharmony_ci			rs780_clk_scaling_enable(rdev, true);
106662306a36Sopenharmony_ci		}
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci		if (pi->voltage_control) {
106962306a36Sopenharmony_ci			rs780_voltage_scaling_enable(rdev, true);
107062306a36Sopenharmony_ci			rs780_enable_voltage_scaling(rdev, rps);
107162306a36Sopenharmony_ci		}
107262306a36Sopenharmony_ci	}
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	rdev->pm.dpm.forced_level = level;
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	return 0;
107762306a36Sopenharmony_ci}
1078