162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright 2012 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 */
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include "radeon.h"
2562306a36Sopenharmony_ci#include "radeon_asic.h"
2662306a36Sopenharmony_ci#include "sumod.h"
2762306a36Sopenharmony_ci#include "r600_dpm.h"
2862306a36Sopenharmony_ci#include "cypress_dpm.h"
2962306a36Sopenharmony_ci#include "sumo_dpm.h"
3062306a36Sopenharmony_ci#include <linux/seq_file.h>
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define SUMO_MAX_DEEPSLEEP_DIVIDER_ID 5
3362306a36Sopenharmony_ci#define SUMO_MINIMUM_ENGINE_CLOCK 800
3462306a36Sopenharmony_ci#define BOOST_DPM_LEVEL 7
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic const u32 sumo_utc[SUMO_PM_NUMBER_OF_TC] =
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	SUMO_UTC_DFLT_00,
3962306a36Sopenharmony_ci	SUMO_UTC_DFLT_01,
4062306a36Sopenharmony_ci	SUMO_UTC_DFLT_02,
4162306a36Sopenharmony_ci	SUMO_UTC_DFLT_03,
4262306a36Sopenharmony_ci	SUMO_UTC_DFLT_04,
4362306a36Sopenharmony_ci	SUMO_UTC_DFLT_05,
4462306a36Sopenharmony_ci	SUMO_UTC_DFLT_06,
4562306a36Sopenharmony_ci	SUMO_UTC_DFLT_07,
4662306a36Sopenharmony_ci	SUMO_UTC_DFLT_08,
4762306a36Sopenharmony_ci	SUMO_UTC_DFLT_09,
4862306a36Sopenharmony_ci	SUMO_UTC_DFLT_10,
4962306a36Sopenharmony_ci	SUMO_UTC_DFLT_11,
5062306a36Sopenharmony_ci	SUMO_UTC_DFLT_12,
5162306a36Sopenharmony_ci	SUMO_UTC_DFLT_13,
5262306a36Sopenharmony_ci	SUMO_UTC_DFLT_14,
5362306a36Sopenharmony_ci};
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic const u32 sumo_dtc[SUMO_PM_NUMBER_OF_TC] =
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	SUMO_DTC_DFLT_00,
5862306a36Sopenharmony_ci	SUMO_DTC_DFLT_01,
5962306a36Sopenharmony_ci	SUMO_DTC_DFLT_02,
6062306a36Sopenharmony_ci	SUMO_DTC_DFLT_03,
6162306a36Sopenharmony_ci	SUMO_DTC_DFLT_04,
6262306a36Sopenharmony_ci	SUMO_DTC_DFLT_05,
6362306a36Sopenharmony_ci	SUMO_DTC_DFLT_06,
6462306a36Sopenharmony_ci	SUMO_DTC_DFLT_07,
6562306a36Sopenharmony_ci	SUMO_DTC_DFLT_08,
6662306a36Sopenharmony_ci	SUMO_DTC_DFLT_09,
6762306a36Sopenharmony_ci	SUMO_DTC_DFLT_10,
6862306a36Sopenharmony_ci	SUMO_DTC_DFLT_11,
6962306a36Sopenharmony_ci	SUMO_DTC_DFLT_12,
7062306a36Sopenharmony_ci	SUMO_DTC_DFLT_13,
7162306a36Sopenharmony_ci	SUMO_DTC_DFLT_14,
7262306a36Sopenharmony_ci};
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic struct sumo_ps *sumo_get_ps(struct radeon_ps *rps)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	struct sumo_ps *ps = rps->ps_priv;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	return ps;
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistruct sumo_power_info *sumo_get_pi(struct radeon_device *rdev)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	struct sumo_power_info *pi = rdev->pm.dpm.priv;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	return pi;
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic void sumo_gfx_clockgating_enable(struct radeon_device *rdev, bool enable)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	if (enable)
9162306a36Sopenharmony_ci		WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN);
9262306a36Sopenharmony_ci	else {
9362306a36Sopenharmony_ci		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
9462306a36Sopenharmony_ci		WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON);
9562306a36Sopenharmony_ci		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON);
9662306a36Sopenharmony_ci		RREG32(GB_ADDR_CONFIG);
9762306a36Sopenharmony_ci	}
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci#define CGCG_CGTT_LOCAL0_MASK 0xE5BFFFFF
10162306a36Sopenharmony_ci#define CGCG_CGTT_LOCAL1_MASK 0xEFFF07FF
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic void sumo_mg_clockgating_enable(struct radeon_device *rdev, bool enable)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	u32 local0;
10662306a36Sopenharmony_ci	u32 local1;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	local0 = RREG32(CG_CGTT_LOCAL_0);
10962306a36Sopenharmony_ci	local1 = RREG32(CG_CGTT_LOCAL_1);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	if (enable) {
11262306a36Sopenharmony_ci		WREG32(CG_CGTT_LOCAL_0, (0 & CGCG_CGTT_LOCAL0_MASK) | (local0 & ~CGCG_CGTT_LOCAL0_MASK) );
11362306a36Sopenharmony_ci		WREG32(CG_CGTT_LOCAL_1, (0 & CGCG_CGTT_LOCAL1_MASK) | (local1 & ~CGCG_CGTT_LOCAL1_MASK) );
11462306a36Sopenharmony_ci	} else {
11562306a36Sopenharmony_ci		WREG32(CG_CGTT_LOCAL_0, (0xFFFFFFFF & CGCG_CGTT_LOCAL0_MASK) | (local0 & ~CGCG_CGTT_LOCAL0_MASK) );
11662306a36Sopenharmony_ci		WREG32(CG_CGTT_LOCAL_1, (0xFFFFCFFF & CGCG_CGTT_LOCAL1_MASK) | (local1 & ~CGCG_CGTT_LOCAL1_MASK) );
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic void sumo_program_git(struct radeon_device *rdev)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	u32 p, u;
12362306a36Sopenharmony_ci	u32 xclk = radeon_get_xclk(rdev);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	r600_calculate_u_and_p(SUMO_GICST_DFLT,
12662306a36Sopenharmony_ci			       xclk, 16, &p, &u);
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	WREG32_P(CG_GIT, CG_GICST(p), ~CG_GICST_MASK);
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic void sumo_program_grsd(struct radeon_device *rdev)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	u32 p, u;
13462306a36Sopenharmony_ci	u32 xclk = radeon_get_xclk(rdev);
13562306a36Sopenharmony_ci	u32 grs = 256 * 25 / 100;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	r600_calculate_u_and_p(1, xclk, 14, &p, &u);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	WREG32(CG_GCOOR, PHC(grs) | SDC(p) | SU(u));
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_civoid sumo_gfx_clockgating_initialize(struct radeon_device *rdev)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	sumo_program_git(rdev);
14562306a36Sopenharmony_ci	sumo_program_grsd(rdev);
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic void sumo_gfx_powergating_initialize(struct radeon_device *rdev)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	u32 rcu_pwr_gating_cntl;
15162306a36Sopenharmony_ci	u32 p, u;
15262306a36Sopenharmony_ci	u32 p_c, p_p, d_p;
15362306a36Sopenharmony_ci	u32 r_t, i_t;
15462306a36Sopenharmony_ci	u32 xclk = radeon_get_xclk(rdev);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	if (rdev->family == CHIP_PALM) {
15762306a36Sopenharmony_ci		p_c = 4;
15862306a36Sopenharmony_ci		d_p = 10;
15962306a36Sopenharmony_ci		r_t = 10;
16062306a36Sopenharmony_ci		i_t = 4;
16162306a36Sopenharmony_ci		p_p = 50 + 1000/200 + 6 * 32;
16262306a36Sopenharmony_ci	} else {
16362306a36Sopenharmony_ci		p_c = 16;
16462306a36Sopenharmony_ci		d_p = 50;
16562306a36Sopenharmony_ci		r_t = 50;
16662306a36Sopenharmony_ci		i_t  = 50;
16762306a36Sopenharmony_ci		p_p = 113;
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	WREG32(CG_SCRATCH2, 0x01B60A17);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	r600_calculate_u_and_p(SUMO_GFXPOWERGATINGT_DFLT,
17362306a36Sopenharmony_ci			       xclk, 16, &p, &u);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	WREG32_P(CG_PWR_GATING_CNTL, PGP(p) | PGU(u),
17662306a36Sopenharmony_ci		 ~(PGP_MASK | PGU_MASK));
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	r600_calculate_u_and_p(SUMO_VOLTAGEDROPT_DFLT,
17962306a36Sopenharmony_ci			       xclk, 16, &p, &u);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	WREG32_P(CG_CG_VOLTAGE_CNTL, PGP(p) | PGU(u),
18262306a36Sopenharmony_ci		 ~(PGP_MASK | PGU_MASK));
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	if (rdev->family == CHIP_PALM) {
18562306a36Sopenharmony_ci		WREG32_RCU(RCU_PWR_GATING_SEQ0, 0x10103210);
18662306a36Sopenharmony_ci		WREG32_RCU(RCU_PWR_GATING_SEQ1, 0x10101010);
18762306a36Sopenharmony_ci	} else {
18862306a36Sopenharmony_ci		WREG32_RCU(RCU_PWR_GATING_SEQ0, 0x76543210);
18962306a36Sopenharmony_ci		WREG32_RCU(RCU_PWR_GATING_SEQ1, 0xFEDCBA98);
19062306a36Sopenharmony_ci	}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL);
19362306a36Sopenharmony_ci	rcu_pwr_gating_cntl &=
19462306a36Sopenharmony_ci		~(RSVD_MASK | PCV_MASK | PGS_MASK);
19562306a36Sopenharmony_ci	rcu_pwr_gating_cntl |= PCV(p_c) | PGS(1) | PWR_GATING_EN;
19662306a36Sopenharmony_ci	if (rdev->family == CHIP_PALM) {
19762306a36Sopenharmony_ci		rcu_pwr_gating_cntl &= ~PCP_MASK;
19862306a36Sopenharmony_ci		rcu_pwr_gating_cntl |= PCP(0x77);
19962306a36Sopenharmony_ci	}
20062306a36Sopenharmony_ci	WREG32_RCU(RCU_PWR_GATING_CNTL, rcu_pwr_gating_cntl);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_2);
20362306a36Sopenharmony_ci	rcu_pwr_gating_cntl &= ~(MPPU_MASK | MPPD_MASK);
20462306a36Sopenharmony_ci	rcu_pwr_gating_cntl |= MPPU(p_p) | MPPD(50);
20562306a36Sopenharmony_ci	WREG32_RCU(RCU_PWR_GATING_CNTL_2, rcu_pwr_gating_cntl);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_3);
20862306a36Sopenharmony_ci	rcu_pwr_gating_cntl &= ~(DPPU_MASK | DPPD_MASK);
20962306a36Sopenharmony_ci	rcu_pwr_gating_cntl |= DPPU(d_p) | DPPD(50);
21062306a36Sopenharmony_ci	WREG32_RCU(RCU_PWR_GATING_CNTL_3, rcu_pwr_gating_cntl);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_4);
21362306a36Sopenharmony_ci	rcu_pwr_gating_cntl &= ~(RT_MASK | IT_MASK);
21462306a36Sopenharmony_ci	rcu_pwr_gating_cntl |= RT(r_t) | IT(i_t);
21562306a36Sopenharmony_ci	WREG32_RCU(RCU_PWR_GATING_CNTL_4, rcu_pwr_gating_cntl);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	if (rdev->family == CHIP_PALM)
21862306a36Sopenharmony_ci		WREG32_RCU(RCU_PWR_GATING_CNTL_5, 0xA02);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	sumo_smu_pg_init(rdev);
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL);
22362306a36Sopenharmony_ci	rcu_pwr_gating_cntl &=
22462306a36Sopenharmony_ci		~(RSVD_MASK | PCV_MASK | PGS_MASK);
22562306a36Sopenharmony_ci	rcu_pwr_gating_cntl |= PCV(p_c) | PGS(4) | PWR_GATING_EN;
22662306a36Sopenharmony_ci	if (rdev->family == CHIP_PALM) {
22762306a36Sopenharmony_ci		rcu_pwr_gating_cntl &= ~PCP_MASK;
22862306a36Sopenharmony_ci		rcu_pwr_gating_cntl |= PCP(0x77);
22962306a36Sopenharmony_ci	}
23062306a36Sopenharmony_ci	WREG32_RCU(RCU_PWR_GATING_CNTL, rcu_pwr_gating_cntl);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	if (rdev->family == CHIP_PALM) {
23362306a36Sopenharmony_ci		rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_2);
23462306a36Sopenharmony_ci		rcu_pwr_gating_cntl &= ~(MPPU_MASK | MPPD_MASK);
23562306a36Sopenharmony_ci		rcu_pwr_gating_cntl |= MPPU(113) | MPPD(50);
23662306a36Sopenharmony_ci		WREG32_RCU(RCU_PWR_GATING_CNTL_2, rcu_pwr_gating_cntl);
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci		rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_3);
23962306a36Sopenharmony_ci		rcu_pwr_gating_cntl &= ~(DPPU_MASK | DPPD_MASK);
24062306a36Sopenharmony_ci		rcu_pwr_gating_cntl |= DPPU(16) | DPPD(50);
24162306a36Sopenharmony_ci		WREG32_RCU(RCU_PWR_GATING_CNTL_3, rcu_pwr_gating_cntl);
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	sumo_smu_pg_init(rdev);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL);
24762306a36Sopenharmony_ci	rcu_pwr_gating_cntl &=
24862306a36Sopenharmony_ci		~(RSVD_MASK | PCV_MASK | PGS_MASK);
24962306a36Sopenharmony_ci	rcu_pwr_gating_cntl |= PGS(5) | PWR_GATING_EN;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	if (rdev->family == CHIP_PALM) {
25262306a36Sopenharmony_ci		rcu_pwr_gating_cntl |= PCV(4);
25362306a36Sopenharmony_ci		rcu_pwr_gating_cntl &= ~PCP_MASK;
25462306a36Sopenharmony_ci		rcu_pwr_gating_cntl |= PCP(0x77);
25562306a36Sopenharmony_ci	} else
25662306a36Sopenharmony_ci		rcu_pwr_gating_cntl |= PCV(11);
25762306a36Sopenharmony_ci	WREG32_RCU(RCU_PWR_GATING_CNTL, rcu_pwr_gating_cntl);
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	if (rdev->family == CHIP_PALM) {
26062306a36Sopenharmony_ci		rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_2);
26162306a36Sopenharmony_ci		rcu_pwr_gating_cntl &= ~(MPPU_MASK | MPPD_MASK);
26262306a36Sopenharmony_ci		rcu_pwr_gating_cntl |= MPPU(113) | MPPD(50);
26362306a36Sopenharmony_ci		WREG32_RCU(RCU_PWR_GATING_CNTL_2, rcu_pwr_gating_cntl);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci		rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_3);
26662306a36Sopenharmony_ci		rcu_pwr_gating_cntl &= ~(DPPU_MASK | DPPD_MASK);
26762306a36Sopenharmony_ci		rcu_pwr_gating_cntl |= DPPU(22) | DPPD(50);
26862306a36Sopenharmony_ci		WREG32_RCU(RCU_PWR_GATING_CNTL_3, rcu_pwr_gating_cntl);
26962306a36Sopenharmony_ci	}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	sumo_smu_pg_init(rdev);
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_cistatic void sumo_gfx_powergating_enable(struct radeon_device *rdev, bool enable)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	if (enable)
27762306a36Sopenharmony_ci		WREG32_P(CG_PWR_GATING_CNTL, DYN_PWR_DOWN_EN, ~DYN_PWR_DOWN_EN);
27862306a36Sopenharmony_ci	else {
27962306a36Sopenharmony_ci		WREG32_P(CG_PWR_GATING_CNTL, 0, ~DYN_PWR_DOWN_EN);
28062306a36Sopenharmony_ci		RREG32(GB_ADDR_CONFIG);
28162306a36Sopenharmony_ci	}
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_cistatic int sumo_enable_clock_power_gating(struct radeon_device *rdev)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	if (pi->enable_gfx_clock_gating)
28962306a36Sopenharmony_ci		sumo_gfx_clockgating_initialize(rdev);
29062306a36Sopenharmony_ci	if (pi->enable_gfx_power_gating)
29162306a36Sopenharmony_ci		sumo_gfx_powergating_initialize(rdev);
29262306a36Sopenharmony_ci	if (pi->enable_mg_clock_gating)
29362306a36Sopenharmony_ci		sumo_mg_clockgating_enable(rdev, true);
29462306a36Sopenharmony_ci	if (pi->enable_gfx_clock_gating)
29562306a36Sopenharmony_ci		sumo_gfx_clockgating_enable(rdev, true);
29662306a36Sopenharmony_ci	if (pi->enable_gfx_power_gating)
29762306a36Sopenharmony_ci		sumo_gfx_powergating_enable(rdev, true);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	return 0;
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_cistatic void sumo_disable_clock_power_gating(struct radeon_device *rdev)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	if (pi->enable_gfx_clock_gating)
30762306a36Sopenharmony_ci		sumo_gfx_clockgating_enable(rdev, false);
30862306a36Sopenharmony_ci	if (pi->enable_gfx_power_gating)
30962306a36Sopenharmony_ci		sumo_gfx_powergating_enable(rdev, false);
31062306a36Sopenharmony_ci	if (pi->enable_mg_clock_gating)
31162306a36Sopenharmony_ci		sumo_mg_clockgating_enable(rdev, false);
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic void sumo_calculate_bsp(struct radeon_device *rdev,
31562306a36Sopenharmony_ci			       u32 high_clk)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
31862306a36Sopenharmony_ci	u32 xclk = radeon_get_xclk(rdev);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	pi->pasi = 65535 * 100 / high_clk;
32162306a36Sopenharmony_ci	pi->asi = 65535 * 100 / high_clk;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	r600_calculate_u_and_p(pi->asi,
32462306a36Sopenharmony_ci			       xclk, 16, &pi->bsp, &pi->bsu);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	r600_calculate_u_and_p(pi->pasi,
32762306a36Sopenharmony_ci			       xclk, 16, &pi->pbsp, &pi->pbsu);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	pi->dsp = BSP(pi->bsp) | BSU(pi->bsu);
33062306a36Sopenharmony_ci	pi->psp = BSP(pi->pbsp) | BSU(pi->pbsu);
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistatic void sumo_init_bsp(struct radeon_device *rdev)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	WREG32(CG_BSP_0, pi->psp);
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_cistatic void sumo_program_bsp(struct radeon_device *rdev,
34262306a36Sopenharmony_ci			     struct radeon_ps *rps)
34362306a36Sopenharmony_ci{
34462306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
34562306a36Sopenharmony_ci	struct sumo_ps *ps = sumo_get_ps(rps);
34662306a36Sopenharmony_ci	u32 i;
34762306a36Sopenharmony_ci	u32 highest_engine_clock = ps->levels[ps->num_levels - 1].sclk;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	if (ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE)
35062306a36Sopenharmony_ci		highest_engine_clock = pi->boost_pl.sclk;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	sumo_calculate_bsp(rdev, highest_engine_clock);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	for (i = 0; i < ps->num_levels - 1; i++)
35562306a36Sopenharmony_ci		WREG32(CG_BSP_0 + (i * 4), pi->dsp);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	WREG32(CG_BSP_0 + (i * 4), pi->psp);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	if (ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE)
36062306a36Sopenharmony_ci		WREG32(CG_BSP_0 + (BOOST_DPM_LEVEL * 4), pi->psp);
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_cistatic void sumo_write_at(struct radeon_device *rdev,
36462306a36Sopenharmony_ci			  u32 index, u32 value)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	if (index == 0)
36762306a36Sopenharmony_ci		WREG32(CG_AT_0, value);
36862306a36Sopenharmony_ci	else if (index == 1)
36962306a36Sopenharmony_ci		WREG32(CG_AT_1, value);
37062306a36Sopenharmony_ci	else if (index == 2)
37162306a36Sopenharmony_ci		WREG32(CG_AT_2, value);
37262306a36Sopenharmony_ci	else if (index == 3)
37362306a36Sopenharmony_ci		WREG32(CG_AT_3, value);
37462306a36Sopenharmony_ci	else if (index == 4)
37562306a36Sopenharmony_ci		WREG32(CG_AT_4, value);
37662306a36Sopenharmony_ci	else if (index == 5)
37762306a36Sopenharmony_ci		WREG32(CG_AT_5, value);
37862306a36Sopenharmony_ci	else if (index == 6)
37962306a36Sopenharmony_ci		WREG32(CG_AT_6, value);
38062306a36Sopenharmony_ci	else if (index == 7)
38162306a36Sopenharmony_ci		WREG32(CG_AT_7, value);
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistatic void sumo_program_at(struct radeon_device *rdev,
38562306a36Sopenharmony_ci			    struct radeon_ps *rps)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
38862306a36Sopenharmony_ci	struct sumo_ps *ps = sumo_get_ps(rps);
38962306a36Sopenharmony_ci	u32 asi;
39062306a36Sopenharmony_ci	u32 i;
39162306a36Sopenharmony_ci	u32 m_a;
39262306a36Sopenharmony_ci	u32 a_t;
39362306a36Sopenharmony_ci	u32 r[SUMO_MAX_HARDWARE_POWERLEVELS];
39462306a36Sopenharmony_ci	u32 l[SUMO_MAX_HARDWARE_POWERLEVELS];
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	r[0] = SUMO_R_DFLT0;
39762306a36Sopenharmony_ci	r[1] = SUMO_R_DFLT1;
39862306a36Sopenharmony_ci	r[2] = SUMO_R_DFLT2;
39962306a36Sopenharmony_ci	r[3] = SUMO_R_DFLT3;
40062306a36Sopenharmony_ci	r[4] = SUMO_R_DFLT4;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	l[0] = SUMO_L_DFLT0;
40362306a36Sopenharmony_ci	l[1] = SUMO_L_DFLT1;
40462306a36Sopenharmony_ci	l[2] = SUMO_L_DFLT2;
40562306a36Sopenharmony_ci	l[3] = SUMO_L_DFLT3;
40662306a36Sopenharmony_ci	l[4] = SUMO_L_DFLT4;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	for (i = 0; i < ps->num_levels; i++) {
40962306a36Sopenharmony_ci		asi = (i == ps->num_levels - 1) ? pi->pasi : pi->asi;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci		m_a = asi * ps->levels[i].sclk / 100;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci		a_t = CG_R(m_a * r[i] / 100) | CG_L(m_a * l[i] / 100);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci		sumo_write_at(rdev, i, a_t);
41662306a36Sopenharmony_ci	}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	if (ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE) {
41962306a36Sopenharmony_ci		asi = pi->pasi;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci		m_a = asi * pi->boost_pl.sclk / 100;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci		a_t = CG_R(m_a * r[ps->num_levels - 1] / 100) |
42462306a36Sopenharmony_ci			CG_L(m_a * l[ps->num_levels - 1] / 100);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci		sumo_write_at(rdev, BOOST_DPM_LEVEL, a_t);
42762306a36Sopenharmony_ci	}
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cistatic void sumo_program_tp(struct radeon_device *rdev)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	int i;
43362306a36Sopenharmony_ci	enum r600_td td = R600_TD_DFLT;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	for (i = 0; i < SUMO_PM_NUMBER_OF_TC; i++) {
43662306a36Sopenharmony_ci		WREG32_P(CG_FFCT_0 + (i * 4), UTC_0(sumo_utc[i]), ~UTC_0_MASK);
43762306a36Sopenharmony_ci		WREG32_P(CG_FFCT_0 + (i * 4), DTC_0(sumo_dtc[i]), ~DTC_0_MASK);
43862306a36Sopenharmony_ci	}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	if (td == R600_TD_AUTO)
44162306a36Sopenharmony_ci		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_FORCE_TREND_SEL);
44262306a36Sopenharmony_ci	else
44362306a36Sopenharmony_ci		WREG32_P(SCLK_PWRMGT_CNTL, FIR_FORCE_TREND_SEL, ~FIR_FORCE_TREND_SEL);
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	if (td == R600_TD_UP)
44662306a36Sopenharmony_ci		WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_TREND_MODE);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	if (td == R600_TD_DOWN)
44962306a36Sopenharmony_ci		WREG32_P(SCLK_PWRMGT_CNTL, FIR_TREND_MODE, ~FIR_TREND_MODE);
45062306a36Sopenharmony_ci}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_civoid sumo_program_vc(struct radeon_device *rdev, u32 vrc)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	WREG32(CG_FTV, vrc);
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_civoid sumo_clear_vc(struct radeon_device *rdev)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	WREG32(CG_FTV, 0);
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_civoid sumo_program_sstp(struct radeon_device *rdev)
46362306a36Sopenharmony_ci{
46462306a36Sopenharmony_ci	u32 p, u;
46562306a36Sopenharmony_ci	u32 xclk = radeon_get_xclk(rdev);
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	r600_calculate_u_and_p(SUMO_SST_DFLT,
46862306a36Sopenharmony_ci			       xclk, 16, &p, &u);
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	WREG32(CG_SSP, SSTU(u) | SST(p));
47162306a36Sopenharmony_ci}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_cistatic void sumo_set_divider_value(struct radeon_device *rdev,
47462306a36Sopenharmony_ci				   u32 index, u32 divider)
47562306a36Sopenharmony_ci{
47662306a36Sopenharmony_ci	u32 reg_index = index / 4;
47762306a36Sopenharmony_ci	u32 field_index = index % 4;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	if (field_index == 0)
48062306a36Sopenharmony_ci		WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
48162306a36Sopenharmony_ci			 SCLK_FSTATE_0_DIV(divider), ~SCLK_FSTATE_0_DIV_MASK);
48262306a36Sopenharmony_ci	else if (field_index == 1)
48362306a36Sopenharmony_ci		WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
48462306a36Sopenharmony_ci			 SCLK_FSTATE_1_DIV(divider), ~SCLK_FSTATE_1_DIV_MASK);
48562306a36Sopenharmony_ci	else if (field_index == 2)
48662306a36Sopenharmony_ci		WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
48762306a36Sopenharmony_ci			 SCLK_FSTATE_2_DIV(divider), ~SCLK_FSTATE_2_DIV_MASK);
48862306a36Sopenharmony_ci	else if (field_index == 3)
48962306a36Sopenharmony_ci		WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
49062306a36Sopenharmony_ci			 SCLK_FSTATE_3_DIV(divider), ~SCLK_FSTATE_3_DIV_MASK);
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cistatic void sumo_set_ds_dividers(struct radeon_device *rdev,
49462306a36Sopenharmony_ci				 u32 index, u32 divider)
49562306a36Sopenharmony_ci{
49662306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	if (pi->enable_sclk_ds) {
49962306a36Sopenharmony_ci		u32 dpm_ctrl = RREG32(CG_SCLK_DPM_CTRL_6);
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci		dpm_ctrl &= ~(0x7 << (index * 3));
50262306a36Sopenharmony_ci		dpm_ctrl |= (divider << (index * 3));
50362306a36Sopenharmony_ci		WREG32(CG_SCLK_DPM_CTRL_6, dpm_ctrl);
50462306a36Sopenharmony_ci	}
50562306a36Sopenharmony_ci}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_cistatic void sumo_set_ss_dividers(struct radeon_device *rdev,
50862306a36Sopenharmony_ci				 u32 index, u32 divider)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	if (pi->enable_sclk_ds) {
51362306a36Sopenharmony_ci		u32 dpm_ctrl = RREG32(CG_SCLK_DPM_CTRL_11);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci		dpm_ctrl &= ~(0x7 << (index * 3));
51662306a36Sopenharmony_ci		dpm_ctrl |= (divider << (index * 3));
51762306a36Sopenharmony_ci		WREG32(CG_SCLK_DPM_CTRL_11, dpm_ctrl);
51862306a36Sopenharmony_ci	}
51962306a36Sopenharmony_ci}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_cistatic void sumo_set_vid(struct radeon_device *rdev, u32 index, u32 vid)
52262306a36Sopenharmony_ci{
52362306a36Sopenharmony_ci	u32 voltage_cntl = RREG32(CG_DPM_VOLTAGE_CNTL);
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	voltage_cntl &= ~(DPM_STATE0_LEVEL_MASK << (index * 2));
52662306a36Sopenharmony_ci	voltage_cntl |= (vid << (DPM_STATE0_LEVEL_SHIFT + index * 2));
52762306a36Sopenharmony_ci	WREG32(CG_DPM_VOLTAGE_CNTL, voltage_cntl);
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_cistatic void sumo_set_allos_gnb_slow(struct radeon_device *rdev, u32 index, u32 gnb_slow)
53162306a36Sopenharmony_ci{
53262306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
53362306a36Sopenharmony_ci	u32 temp = gnb_slow;
53462306a36Sopenharmony_ci	u32 cg_sclk_dpm_ctrl_3;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	if (pi->driver_nbps_policy_disable)
53762306a36Sopenharmony_ci		temp = 1;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	cg_sclk_dpm_ctrl_3 = RREG32(CG_SCLK_DPM_CTRL_3);
54062306a36Sopenharmony_ci	cg_sclk_dpm_ctrl_3 &= ~(GNB_SLOW_FSTATE_0_MASK << index);
54162306a36Sopenharmony_ci	cg_sclk_dpm_ctrl_3 |= (temp << (GNB_SLOW_FSTATE_0_SHIFT + index));
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	WREG32(CG_SCLK_DPM_CTRL_3, cg_sclk_dpm_ctrl_3);
54462306a36Sopenharmony_ci}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_cistatic void sumo_program_power_level(struct radeon_device *rdev,
54762306a36Sopenharmony_ci				     struct sumo_pl *pl, u32 index)
54862306a36Sopenharmony_ci{
54962306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
55062306a36Sopenharmony_ci	int ret;
55162306a36Sopenharmony_ci	struct atom_clock_dividers dividers;
55262306a36Sopenharmony_ci	u32 ds_en = RREG32(DEEP_SLEEP_CNTL) & ENABLE_DS;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
55562306a36Sopenharmony_ci					     pl->sclk, false, &dividers);
55662306a36Sopenharmony_ci	if (ret)
55762306a36Sopenharmony_ci		return;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	sumo_set_divider_value(rdev, index, dividers.post_div);
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	sumo_set_vid(rdev, index, pl->vddc_index);
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	if (pl->ss_divider_index == 0 || pl->ds_divider_index == 0) {
56462306a36Sopenharmony_ci		if (ds_en)
56562306a36Sopenharmony_ci			WREG32_P(DEEP_SLEEP_CNTL, 0, ~ENABLE_DS);
56662306a36Sopenharmony_ci	} else {
56762306a36Sopenharmony_ci		sumo_set_ss_dividers(rdev, index, pl->ss_divider_index);
56862306a36Sopenharmony_ci		sumo_set_ds_dividers(rdev, index, pl->ds_divider_index);
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci		if (!ds_en)
57162306a36Sopenharmony_ci			WREG32_P(DEEP_SLEEP_CNTL, ENABLE_DS, ~ENABLE_DS);
57262306a36Sopenharmony_ci	}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	sumo_set_allos_gnb_slow(rdev, index, pl->allow_gnb_slow);
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	if (pi->enable_boost)
57762306a36Sopenharmony_ci		sumo_set_tdp_limit(rdev, index, pl->sclk_dpm_tdp_limit);
57862306a36Sopenharmony_ci}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_cistatic void sumo_power_level_enable(struct radeon_device *rdev, u32 index, bool enable)
58162306a36Sopenharmony_ci{
58262306a36Sopenharmony_ci	u32 reg_index = index / 4;
58362306a36Sopenharmony_ci	u32 field_index = index % 4;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	if (field_index == 0)
58662306a36Sopenharmony_ci		WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
58762306a36Sopenharmony_ci			 enable ? SCLK_FSTATE_0_VLD : 0, ~SCLK_FSTATE_0_VLD);
58862306a36Sopenharmony_ci	else if (field_index == 1)
58962306a36Sopenharmony_ci		WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
59062306a36Sopenharmony_ci			 enable ? SCLK_FSTATE_1_VLD : 0, ~SCLK_FSTATE_1_VLD);
59162306a36Sopenharmony_ci	else if (field_index == 2)
59262306a36Sopenharmony_ci		WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
59362306a36Sopenharmony_ci			 enable ? SCLK_FSTATE_2_VLD : 0, ~SCLK_FSTATE_2_VLD);
59462306a36Sopenharmony_ci	else if (field_index == 3)
59562306a36Sopenharmony_ci		WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
59662306a36Sopenharmony_ci			 enable ? SCLK_FSTATE_3_VLD : 0, ~SCLK_FSTATE_3_VLD);
59762306a36Sopenharmony_ci}
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_cistatic bool sumo_dpm_enabled(struct radeon_device *rdev)
60062306a36Sopenharmony_ci{
60162306a36Sopenharmony_ci	if (RREG32(CG_SCLK_DPM_CTRL_3) & DPM_SCLK_ENABLE)
60262306a36Sopenharmony_ci		return true;
60362306a36Sopenharmony_ci	else
60462306a36Sopenharmony_ci		return false;
60562306a36Sopenharmony_ci}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_cistatic void sumo_start_dpm(struct radeon_device *rdev)
60862306a36Sopenharmony_ci{
60962306a36Sopenharmony_ci	WREG32_P(CG_SCLK_DPM_CTRL_3, DPM_SCLK_ENABLE, ~DPM_SCLK_ENABLE);
61062306a36Sopenharmony_ci}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_cistatic void sumo_stop_dpm(struct radeon_device *rdev)
61362306a36Sopenharmony_ci{
61462306a36Sopenharmony_ci	WREG32_P(CG_SCLK_DPM_CTRL_3, 0, ~DPM_SCLK_ENABLE);
61562306a36Sopenharmony_ci}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_cistatic void sumo_set_forced_mode(struct radeon_device *rdev, bool enable)
61862306a36Sopenharmony_ci{
61962306a36Sopenharmony_ci	if (enable)
62062306a36Sopenharmony_ci		WREG32_P(CG_SCLK_DPM_CTRL_3, FORCE_SCLK_STATE_EN, ~FORCE_SCLK_STATE_EN);
62162306a36Sopenharmony_ci	else
62262306a36Sopenharmony_ci		WREG32_P(CG_SCLK_DPM_CTRL_3, 0, ~FORCE_SCLK_STATE_EN);
62362306a36Sopenharmony_ci}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_cistatic void sumo_set_forced_mode_enabled(struct radeon_device *rdev)
62662306a36Sopenharmony_ci{
62762306a36Sopenharmony_ci	int i;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	sumo_set_forced_mode(rdev, true);
63062306a36Sopenharmony_ci	for (i = 0; i < rdev->usec_timeout; i++) {
63162306a36Sopenharmony_ci		if (RREG32(CG_SCLK_STATUS) & SCLK_OVERCLK_DETECT)
63262306a36Sopenharmony_ci			break;
63362306a36Sopenharmony_ci		udelay(1);
63462306a36Sopenharmony_ci	}
63562306a36Sopenharmony_ci}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_cistatic void sumo_wait_for_level_0(struct radeon_device *rdev)
63862306a36Sopenharmony_ci{
63962306a36Sopenharmony_ci	int i;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	for (i = 0; i < rdev->usec_timeout; i++) {
64262306a36Sopenharmony_ci		if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_SCLK_INDEX_MASK) == 0)
64362306a36Sopenharmony_ci			break;
64462306a36Sopenharmony_ci		udelay(1);
64562306a36Sopenharmony_ci	}
64662306a36Sopenharmony_ci	for (i = 0; i < rdev->usec_timeout; i++) {
64762306a36Sopenharmony_ci		if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_INDEX_MASK) == 0)
64862306a36Sopenharmony_ci			break;
64962306a36Sopenharmony_ci		udelay(1);
65062306a36Sopenharmony_ci	}
65162306a36Sopenharmony_ci}
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_cistatic void sumo_set_forced_mode_disabled(struct radeon_device *rdev)
65462306a36Sopenharmony_ci{
65562306a36Sopenharmony_ci	sumo_set_forced_mode(rdev, false);
65662306a36Sopenharmony_ci}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_cistatic void sumo_enable_power_level_0(struct radeon_device *rdev)
65962306a36Sopenharmony_ci{
66062306a36Sopenharmony_ci	sumo_power_level_enable(rdev, 0, true);
66162306a36Sopenharmony_ci}
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_cistatic void sumo_patch_boost_state(struct radeon_device *rdev,
66462306a36Sopenharmony_ci				   struct radeon_ps *rps)
66562306a36Sopenharmony_ci{
66662306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
66762306a36Sopenharmony_ci	struct sumo_ps *new_ps = sumo_get_ps(rps);
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	if (new_ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE) {
67062306a36Sopenharmony_ci		pi->boost_pl = new_ps->levels[new_ps->num_levels - 1];
67162306a36Sopenharmony_ci		pi->boost_pl.sclk = pi->sys_info.boost_sclk;
67262306a36Sopenharmony_ci		pi->boost_pl.vddc_index = pi->sys_info.boost_vid_2bit;
67362306a36Sopenharmony_ci		pi->boost_pl.sclk_dpm_tdp_limit = pi->sys_info.sclk_dpm_tdp_limit_boost;
67462306a36Sopenharmony_ci	}
67562306a36Sopenharmony_ci}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_cistatic void sumo_pre_notify_alt_vddnb_change(struct radeon_device *rdev,
67862306a36Sopenharmony_ci					     struct radeon_ps *new_rps,
67962306a36Sopenharmony_ci					     struct radeon_ps *old_rps)
68062306a36Sopenharmony_ci{
68162306a36Sopenharmony_ci	struct sumo_ps *new_ps = sumo_get_ps(new_rps);
68262306a36Sopenharmony_ci	struct sumo_ps *old_ps = sumo_get_ps(old_rps);
68362306a36Sopenharmony_ci	u32 nbps1_old = 0;
68462306a36Sopenharmony_ci	u32 nbps1_new = 0;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	if (old_ps != NULL)
68762306a36Sopenharmony_ci		nbps1_old = (old_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE) ? 1 : 0;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	nbps1_new = (new_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE) ? 1 : 0;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	if (nbps1_old == 1 && nbps1_new == 0)
69262306a36Sopenharmony_ci		sumo_smu_notify_alt_vddnb_change(rdev, 0, 0);
69362306a36Sopenharmony_ci}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_cistatic void sumo_post_notify_alt_vddnb_change(struct radeon_device *rdev,
69662306a36Sopenharmony_ci					      struct radeon_ps *new_rps,
69762306a36Sopenharmony_ci					      struct radeon_ps *old_rps)
69862306a36Sopenharmony_ci{
69962306a36Sopenharmony_ci	struct sumo_ps *new_ps = sumo_get_ps(new_rps);
70062306a36Sopenharmony_ci	struct sumo_ps *old_ps = sumo_get_ps(old_rps);
70162306a36Sopenharmony_ci	u32 nbps1_old = 0;
70262306a36Sopenharmony_ci	u32 nbps1_new = 0;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	if (old_ps != NULL)
70562306a36Sopenharmony_ci		nbps1_old = (old_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE)? 1 : 0;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	nbps1_new = (new_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE)? 1 : 0;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	if (nbps1_old == 0 && nbps1_new == 1)
71062306a36Sopenharmony_ci		sumo_smu_notify_alt_vddnb_change(rdev, 1, 1);
71162306a36Sopenharmony_ci}
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_cistatic void sumo_enable_boost(struct radeon_device *rdev,
71462306a36Sopenharmony_ci			      struct radeon_ps *rps,
71562306a36Sopenharmony_ci			      bool enable)
71662306a36Sopenharmony_ci{
71762306a36Sopenharmony_ci	struct sumo_ps *new_ps = sumo_get_ps(rps);
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	if (enable) {
72062306a36Sopenharmony_ci		if (new_ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE)
72162306a36Sopenharmony_ci			sumo_boost_state_enable(rdev, true);
72262306a36Sopenharmony_ci	} else
72362306a36Sopenharmony_ci		sumo_boost_state_enable(rdev, false);
72462306a36Sopenharmony_ci}
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_cistatic void sumo_set_forced_level(struct radeon_device *rdev, u32 index)
72762306a36Sopenharmony_ci{
72862306a36Sopenharmony_ci	WREG32_P(CG_SCLK_DPM_CTRL_3, FORCE_SCLK_STATE(index), ~FORCE_SCLK_STATE_MASK);
72962306a36Sopenharmony_ci}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_cistatic void sumo_set_forced_level_0(struct radeon_device *rdev)
73262306a36Sopenharmony_ci{
73362306a36Sopenharmony_ci	sumo_set_forced_level(rdev, 0);
73462306a36Sopenharmony_ci}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_cistatic void sumo_program_wl(struct radeon_device *rdev,
73762306a36Sopenharmony_ci			    struct radeon_ps *rps)
73862306a36Sopenharmony_ci{
73962306a36Sopenharmony_ci	struct sumo_ps *new_ps = sumo_get_ps(rps);
74062306a36Sopenharmony_ci	u32 dpm_ctrl4 = RREG32(CG_SCLK_DPM_CTRL_4);
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	dpm_ctrl4 &= 0xFFFFFF00;
74362306a36Sopenharmony_ci	dpm_ctrl4 |= (1 << (new_ps->num_levels - 1));
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	if (new_ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE)
74662306a36Sopenharmony_ci		dpm_ctrl4 |= (1 << BOOST_DPM_LEVEL);
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	WREG32(CG_SCLK_DPM_CTRL_4, dpm_ctrl4);
74962306a36Sopenharmony_ci}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_cistatic void sumo_program_power_levels_0_to_n(struct radeon_device *rdev,
75262306a36Sopenharmony_ci					     struct radeon_ps *new_rps,
75362306a36Sopenharmony_ci					     struct radeon_ps *old_rps)
75462306a36Sopenharmony_ci{
75562306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
75662306a36Sopenharmony_ci	struct sumo_ps *new_ps = sumo_get_ps(new_rps);
75762306a36Sopenharmony_ci	struct sumo_ps *old_ps = sumo_get_ps(old_rps);
75862306a36Sopenharmony_ci	u32 i;
75962306a36Sopenharmony_ci	u32 n_current_state_levels = (old_ps == NULL) ? 1 : old_ps->num_levels;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	for (i = 0; i < new_ps->num_levels; i++) {
76262306a36Sopenharmony_ci		sumo_program_power_level(rdev, &new_ps->levels[i], i);
76362306a36Sopenharmony_ci		sumo_power_level_enable(rdev, i, true);
76462306a36Sopenharmony_ci	}
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	for (i = new_ps->num_levels; i < n_current_state_levels; i++)
76762306a36Sopenharmony_ci		sumo_power_level_enable(rdev, i, false);
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	if (new_ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE)
77062306a36Sopenharmony_ci		sumo_program_power_level(rdev, &pi->boost_pl, BOOST_DPM_LEVEL);
77162306a36Sopenharmony_ci}
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_cistatic void sumo_enable_acpi_pm(struct radeon_device *rdev)
77462306a36Sopenharmony_ci{
77562306a36Sopenharmony_ci	WREG32_P(GENERAL_PWRMGT, STATIC_PM_EN, ~STATIC_PM_EN);
77662306a36Sopenharmony_ci}
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_cistatic void sumo_program_power_level_enter_state(struct radeon_device *rdev)
77962306a36Sopenharmony_ci{
78062306a36Sopenharmony_ci	WREG32_P(CG_SCLK_DPM_CTRL_5, SCLK_FSTATE_BOOTUP(0), ~SCLK_FSTATE_BOOTUP_MASK);
78162306a36Sopenharmony_ci}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_cistatic void sumo_program_acpi_power_level(struct radeon_device *rdev)
78462306a36Sopenharmony_ci{
78562306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
78662306a36Sopenharmony_ci	struct atom_clock_dividers dividers;
78762306a36Sopenharmony_ci	int ret;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
79062306a36Sopenharmony_ci					     pi->acpi_pl.sclk,
79162306a36Sopenharmony_ci					     false, &dividers);
79262306a36Sopenharmony_ci	if (ret)
79362306a36Sopenharmony_ci		return;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	WREG32_P(CG_ACPI_CNTL, SCLK_ACPI_DIV(dividers.post_div), ~SCLK_ACPI_DIV_MASK);
79662306a36Sopenharmony_ci	WREG32_P(CG_ACPI_VOLTAGE_CNTL, 0, ~ACPI_VOLTAGE_EN);
79762306a36Sopenharmony_ci}
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_cistatic void sumo_program_bootup_state(struct radeon_device *rdev)
80062306a36Sopenharmony_ci{
80162306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
80262306a36Sopenharmony_ci	u32 dpm_ctrl4 = RREG32(CG_SCLK_DPM_CTRL_4);
80362306a36Sopenharmony_ci	u32 i;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	sumo_program_power_level(rdev, &pi->boot_pl, 0);
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	dpm_ctrl4 &= 0xFFFFFF00;
80862306a36Sopenharmony_ci	WREG32(CG_SCLK_DPM_CTRL_4, dpm_ctrl4);
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	for (i = 1; i < 8; i++)
81162306a36Sopenharmony_ci		sumo_power_level_enable(rdev, i, false);
81262306a36Sopenharmony_ci}
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_cistatic void sumo_setup_uvd_clocks(struct radeon_device *rdev,
81562306a36Sopenharmony_ci				  struct radeon_ps *new_rps,
81662306a36Sopenharmony_ci				  struct radeon_ps *old_rps)
81762306a36Sopenharmony_ci{
81862306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	if (pi->enable_gfx_power_gating) {
82162306a36Sopenharmony_ci		sumo_gfx_powergating_enable(rdev, false);
82262306a36Sopenharmony_ci	}
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	if (pi->enable_gfx_power_gating) {
82762306a36Sopenharmony_ci		if (!pi->disable_gfx_power_gating_in_uvd ||
82862306a36Sopenharmony_ci		    !r600_is_uvd_state(new_rps->class, new_rps->class2))
82962306a36Sopenharmony_ci			sumo_gfx_powergating_enable(rdev, true);
83062306a36Sopenharmony_ci	}
83162306a36Sopenharmony_ci}
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_cistatic void sumo_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev,
83462306a36Sopenharmony_ci						    struct radeon_ps *new_rps,
83562306a36Sopenharmony_ci						    struct radeon_ps *old_rps)
83662306a36Sopenharmony_ci{
83762306a36Sopenharmony_ci	struct sumo_ps *new_ps = sumo_get_ps(new_rps);
83862306a36Sopenharmony_ci	struct sumo_ps *current_ps = sumo_get_ps(old_rps);
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	if ((new_rps->vclk == old_rps->vclk) &&
84162306a36Sopenharmony_ci	    (new_rps->dclk == old_rps->dclk))
84262306a36Sopenharmony_ci		return;
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	if (new_ps->levels[new_ps->num_levels - 1].sclk >=
84562306a36Sopenharmony_ci	    current_ps->levels[current_ps->num_levels - 1].sclk)
84662306a36Sopenharmony_ci		return;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	sumo_setup_uvd_clocks(rdev, new_rps, old_rps);
84962306a36Sopenharmony_ci}
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_cistatic void sumo_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
85262306a36Sopenharmony_ci						   struct radeon_ps *new_rps,
85362306a36Sopenharmony_ci						   struct radeon_ps *old_rps)
85462306a36Sopenharmony_ci{
85562306a36Sopenharmony_ci	struct sumo_ps *new_ps = sumo_get_ps(new_rps);
85662306a36Sopenharmony_ci	struct sumo_ps *current_ps = sumo_get_ps(old_rps);
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	if ((new_rps->vclk == old_rps->vclk) &&
85962306a36Sopenharmony_ci	    (new_rps->dclk == old_rps->dclk))
86062306a36Sopenharmony_ci		return;
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	if (new_ps->levels[new_ps->num_levels - 1].sclk <
86362306a36Sopenharmony_ci	    current_ps->levels[current_ps->num_levels - 1].sclk)
86462306a36Sopenharmony_ci		return;
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	sumo_setup_uvd_clocks(rdev, new_rps, old_rps);
86762306a36Sopenharmony_ci}
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_civoid sumo_take_smu_control(struct radeon_device *rdev, bool enable)
87062306a36Sopenharmony_ci{
87162306a36Sopenharmony_ci/* This bit selects who handles display phy powergating.
87262306a36Sopenharmony_ci * Clear the bit to let atom handle it.
87362306a36Sopenharmony_ci * Set it to let the driver handle it.
87462306a36Sopenharmony_ci * For now we just let atom handle it.
87562306a36Sopenharmony_ci */
87662306a36Sopenharmony_ci#if 0
87762306a36Sopenharmony_ci	u32 v = RREG32(DOUT_SCRATCH3);
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	if (enable)
88062306a36Sopenharmony_ci		v |= 0x4;
88162306a36Sopenharmony_ci	else
88262306a36Sopenharmony_ci		v &= 0xFFFFFFFB;
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	WREG32(DOUT_SCRATCH3, v);
88562306a36Sopenharmony_ci#endif
88662306a36Sopenharmony_ci}
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_cistatic void sumo_enable_sclk_ds(struct radeon_device *rdev, bool enable)
88962306a36Sopenharmony_ci{
89062306a36Sopenharmony_ci	if (enable) {
89162306a36Sopenharmony_ci		u32 deep_sleep_cntl = RREG32(DEEP_SLEEP_CNTL);
89262306a36Sopenharmony_ci		u32 deep_sleep_cntl2 = RREG32(DEEP_SLEEP_CNTL2);
89362306a36Sopenharmony_ci		u32 t = 1;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci		deep_sleep_cntl &= ~R_DIS;
89662306a36Sopenharmony_ci		deep_sleep_cntl &= ~HS_MASK;
89762306a36Sopenharmony_ci		deep_sleep_cntl |= HS(t > 4095 ? 4095 : t);
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci		deep_sleep_cntl2 |= LB_UFP_EN;
90062306a36Sopenharmony_ci		deep_sleep_cntl2 &= INOUT_C_MASK;
90162306a36Sopenharmony_ci		deep_sleep_cntl2 |= INOUT_C(0xf);
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci		WREG32(DEEP_SLEEP_CNTL2, deep_sleep_cntl2);
90462306a36Sopenharmony_ci		WREG32(DEEP_SLEEP_CNTL, deep_sleep_cntl);
90562306a36Sopenharmony_ci	} else
90662306a36Sopenharmony_ci		WREG32_P(DEEP_SLEEP_CNTL, 0, ~ENABLE_DS);
90762306a36Sopenharmony_ci}
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_cistatic void sumo_program_bootup_at(struct radeon_device *rdev)
91062306a36Sopenharmony_ci{
91162306a36Sopenharmony_ci	WREG32_P(CG_AT_0, CG_R(0xffff), ~CG_R_MASK);
91262306a36Sopenharmony_ci	WREG32_P(CG_AT_0, CG_L(0), ~CG_L_MASK);
91362306a36Sopenharmony_ci}
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_cistatic void sumo_reset_am(struct radeon_device *rdev)
91662306a36Sopenharmony_ci{
91762306a36Sopenharmony_ci	WREG32_P(SCLK_PWRMGT_CNTL, FIR_RESET, ~FIR_RESET);
91862306a36Sopenharmony_ci}
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_cistatic void sumo_start_am(struct radeon_device *rdev)
92162306a36Sopenharmony_ci{
92262306a36Sopenharmony_ci	WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_RESET);
92362306a36Sopenharmony_ci}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_cistatic void sumo_program_ttp(struct radeon_device *rdev)
92662306a36Sopenharmony_ci{
92762306a36Sopenharmony_ci	u32 xclk = radeon_get_xclk(rdev);
92862306a36Sopenharmony_ci	u32 p, u;
92962306a36Sopenharmony_ci	u32 cg_sclk_dpm_ctrl_5 = RREG32(CG_SCLK_DPM_CTRL_5);
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	r600_calculate_u_and_p(1000,
93262306a36Sopenharmony_ci			       xclk, 16, &p, &u);
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	cg_sclk_dpm_ctrl_5 &= ~(TT_TP_MASK | TT_TU_MASK);
93562306a36Sopenharmony_ci	cg_sclk_dpm_ctrl_5 |= TT_TP(p) | TT_TU(u);
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	WREG32(CG_SCLK_DPM_CTRL_5, cg_sclk_dpm_ctrl_5);
93862306a36Sopenharmony_ci}
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_cistatic void sumo_program_ttt(struct radeon_device *rdev)
94162306a36Sopenharmony_ci{
94262306a36Sopenharmony_ci	u32 cg_sclk_dpm_ctrl_3 = RREG32(CG_SCLK_DPM_CTRL_3);
94362306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	cg_sclk_dpm_ctrl_3 &= ~(GNB_TT_MASK | GNB_THERMTHRO_MASK);
94662306a36Sopenharmony_ci	cg_sclk_dpm_ctrl_3 |= GNB_TT(pi->thermal_auto_throttling + 49);
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	WREG32(CG_SCLK_DPM_CTRL_3, cg_sclk_dpm_ctrl_3);
94962306a36Sopenharmony_ci}
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_cistatic void sumo_enable_voltage_scaling(struct radeon_device *rdev, bool enable)
95362306a36Sopenharmony_ci{
95462306a36Sopenharmony_ci	if (enable) {
95562306a36Sopenharmony_ci		WREG32_P(CG_DPM_VOLTAGE_CNTL, DPM_VOLTAGE_EN, ~DPM_VOLTAGE_EN);
95662306a36Sopenharmony_ci		WREG32_P(CG_CG_VOLTAGE_CNTL, 0, ~CG_VOLTAGE_EN);
95762306a36Sopenharmony_ci	} else {
95862306a36Sopenharmony_ci		WREG32_P(CG_CG_VOLTAGE_CNTL, CG_VOLTAGE_EN, ~CG_VOLTAGE_EN);
95962306a36Sopenharmony_ci		WREG32_P(CG_DPM_VOLTAGE_CNTL, 0, ~DPM_VOLTAGE_EN);
96062306a36Sopenharmony_ci	}
96162306a36Sopenharmony_ci}
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_cistatic void sumo_override_cnb_thermal_events(struct radeon_device *rdev)
96462306a36Sopenharmony_ci{
96562306a36Sopenharmony_ci	WREG32_P(CG_SCLK_DPM_CTRL_3, CNB_THERMTHRO_MASK_SCLK,
96662306a36Sopenharmony_ci		 ~CNB_THERMTHRO_MASK_SCLK);
96762306a36Sopenharmony_ci}
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_cistatic void sumo_program_dc_hto(struct radeon_device *rdev)
97062306a36Sopenharmony_ci{
97162306a36Sopenharmony_ci	u32 cg_sclk_dpm_ctrl_4 = RREG32(CG_SCLK_DPM_CTRL_4);
97262306a36Sopenharmony_ci	u32 p, u;
97362306a36Sopenharmony_ci	u32 xclk = radeon_get_xclk(rdev);
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	r600_calculate_u_and_p(100000,
97662306a36Sopenharmony_ci			       xclk, 14, &p, &u);
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	cg_sclk_dpm_ctrl_4 &= ~(DC_HDC_MASK | DC_HU_MASK);
97962306a36Sopenharmony_ci	cg_sclk_dpm_ctrl_4 |= DC_HDC(p) | DC_HU(u);
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	WREG32(CG_SCLK_DPM_CTRL_4, cg_sclk_dpm_ctrl_4);
98262306a36Sopenharmony_ci}
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_cistatic void sumo_force_nbp_state(struct radeon_device *rdev,
98562306a36Sopenharmony_ci				 struct radeon_ps *rps)
98662306a36Sopenharmony_ci{
98762306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
98862306a36Sopenharmony_ci	struct sumo_ps *new_ps = sumo_get_ps(rps);
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	if (!pi->driver_nbps_policy_disable) {
99162306a36Sopenharmony_ci		if (new_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE)
99262306a36Sopenharmony_ci			WREG32_P(CG_SCLK_DPM_CTRL_3, FORCE_NB_PSTATE_1, ~FORCE_NB_PSTATE_1);
99362306a36Sopenharmony_ci		else
99462306a36Sopenharmony_ci			WREG32_P(CG_SCLK_DPM_CTRL_3, 0, ~FORCE_NB_PSTATE_1);
99562306a36Sopenharmony_ci	}
99662306a36Sopenharmony_ci}
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ciu32 sumo_get_sleep_divider_from_id(u32 id)
99962306a36Sopenharmony_ci{
100062306a36Sopenharmony_ci	return 1 << id;
100162306a36Sopenharmony_ci}
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ciu32 sumo_get_sleep_divider_id_from_clock(struct radeon_device *rdev,
100462306a36Sopenharmony_ci					 u32 sclk,
100562306a36Sopenharmony_ci					 u32 min_sclk_in_sr)
100662306a36Sopenharmony_ci{
100762306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
100862306a36Sopenharmony_ci	u32 i;
100962306a36Sopenharmony_ci	u32 temp;
101062306a36Sopenharmony_ci	u32 min = (min_sclk_in_sr > SUMO_MINIMUM_ENGINE_CLOCK) ?
101162306a36Sopenharmony_ci		min_sclk_in_sr : SUMO_MINIMUM_ENGINE_CLOCK;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	if (sclk < min)
101462306a36Sopenharmony_ci		return 0;
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	if (!pi->enable_sclk_ds)
101762306a36Sopenharmony_ci		return 0;
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	for (i = SUMO_MAX_DEEPSLEEP_DIVIDER_ID;  ; i--) {
102062306a36Sopenharmony_ci		temp = sclk / sumo_get_sleep_divider_from_id(i);
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci		if (temp >= min || i == 0)
102362306a36Sopenharmony_ci			break;
102462306a36Sopenharmony_ci	}
102562306a36Sopenharmony_ci	return i;
102662306a36Sopenharmony_ci}
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_cistatic u32 sumo_get_valid_engine_clock(struct radeon_device *rdev,
102962306a36Sopenharmony_ci				       u32 lower_limit)
103062306a36Sopenharmony_ci{
103162306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
103262306a36Sopenharmony_ci	u32 i;
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	for (i = 0; i < pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries; i++) {
103562306a36Sopenharmony_ci		if (pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency >= lower_limit)
103662306a36Sopenharmony_ci			return pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency;
103762306a36Sopenharmony_ci	}
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	return pi->sys_info.sclk_voltage_mapping_table.entries[pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries - 1].sclk_frequency;
104062306a36Sopenharmony_ci}
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_cistatic void sumo_patch_thermal_state(struct radeon_device *rdev,
104362306a36Sopenharmony_ci				     struct sumo_ps *ps,
104462306a36Sopenharmony_ci				     struct sumo_ps *current_ps)
104562306a36Sopenharmony_ci{
104662306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
104762306a36Sopenharmony_ci	u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
104862306a36Sopenharmony_ci	u32 current_vddc;
104962306a36Sopenharmony_ci	u32 current_sclk;
105062306a36Sopenharmony_ci	u32 current_index = 0;
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	if (current_ps) {
105362306a36Sopenharmony_ci		current_vddc = current_ps->levels[current_index].vddc_index;
105462306a36Sopenharmony_ci		current_sclk = current_ps->levels[current_index].sclk;
105562306a36Sopenharmony_ci	} else {
105662306a36Sopenharmony_ci		current_vddc = pi->boot_pl.vddc_index;
105762306a36Sopenharmony_ci		current_sclk = pi->boot_pl.sclk;
105862306a36Sopenharmony_ci	}
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	ps->levels[0].vddc_index = current_vddc;
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	if (ps->levels[0].sclk > current_sclk)
106362306a36Sopenharmony_ci		ps->levels[0].sclk = current_sclk;
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	ps->levels[0].ss_divider_index =
106662306a36Sopenharmony_ci		sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[0].sclk, sclk_in_sr);
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	ps->levels[0].ds_divider_index =
106962306a36Sopenharmony_ci		sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[0].sclk, SUMO_MINIMUM_ENGINE_CLOCK);
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	if (ps->levels[0].ds_divider_index > ps->levels[0].ss_divider_index + 1)
107262306a36Sopenharmony_ci		ps->levels[0].ds_divider_index = ps->levels[0].ss_divider_index + 1;
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	if (ps->levels[0].ss_divider_index == ps->levels[0].ds_divider_index) {
107562306a36Sopenharmony_ci		if (ps->levels[0].ss_divider_index > 1)
107662306a36Sopenharmony_ci			ps->levels[0].ss_divider_index = ps->levels[0].ss_divider_index - 1;
107762306a36Sopenharmony_ci	}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	if (ps->levels[0].ss_divider_index == 0)
108062306a36Sopenharmony_ci		ps->levels[0].ds_divider_index = 0;
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	if (ps->levels[0].ds_divider_index == 0)
108362306a36Sopenharmony_ci		ps->levels[0].ss_divider_index = 0;
108462306a36Sopenharmony_ci}
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_cistatic void sumo_apply_state_adjust_rules(struct radeon_device *rdev,
108762306a36Sopenharmony_ci					  struct radeon_ps *new_rps,
108862306a36Sopenharmony_ci					  struct radeon_ps *old_rps)
108962306a36Sopenharmony_ci{
109062306a36Sopenharmony_ci	struct sumo_ps *ps = sumo_get_ps(new_rps);
109162306a36Sopenharmony_ci	struct sumo_ps *current_ps = sumo_get_ps(old_rps);
109262306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
109362306a36Sopenharmony_ci	u32 min_voltage = 0; /* ??? */
109462306a36Sopenharmony_ci	u32 min_sclk = pi->sys_info.min_sclk; /* XXX check against disp reqs */
109562306a36Sopenharmony_ci	u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
109662306a36Sopenharmony_ci	u32 i;
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	if (new_rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
109962306a36Sopenharmony_ci		return sumo_patch_thermal_state(rdev, ps, current_ps);
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	if (pi->enable_boost) {
110262306a36Sopenharmony_ci		if (new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE)
110362306a36Sopenharmony_ci			ps->flags |= SUMO_POWERSTATE_FLAGS_BOOST_STATE;
110462306a36Sopenharmony_ci	}
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	if ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) ||
110762306a36Sopenharmony_ci	    (new_rps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) ||
110862306a36Sopenharmony_ci	    (new_rps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE))
110962306a36Sopenharmony_ci		ps->flags |= SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE;
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	for (i = 0; i < ps->num_levels; i++) {
111262306a36Sopenharmony_ci		if (ps->levels[i].vddc_index < min_voltage)
111362306a36Sopenharmony_ci			ps->levels[i].vddc_index = min_voltage;
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci		if (ps->levels[i].sclk < min_sclk)
111662306a36Sopenharmony_ci			ps->levels[i].sclk =
111762306a36Sopenharmony_ci				sumo_get_valid_engine_clock(rdev, min_sclk);
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci		ps->levels[i].ss_divider_index =
112062306a36Sopenharmony_ci			sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[i].sclk, sclk_in_sr);
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci		ps->levels[i].ds_divider_index =
112362306a36Sopenharmony_ci			sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[i].sclk, SUMO_MINIMUM_ENGINE_CLOCK);
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci		if (ps->levels[i].ds_divider_index > ps->levels[i].ss_divider_index + 1)
112662306a36Sopenharmony_ci			ps->levels[i].ds_divider_index = ps->levels[i].ss_divider_index + 1;
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci		if (ps->levels[i].ss_divider_index == ps->levels[i].ds_divider_index) {
112962306a36Sopenharmony_ci			if (ps->levels[i].ss_divider_index > 1)
113062306a36Sopenharmony_ci				ps->levels[i].ss_divider_index = ps->levels[i].ss_divider_index - 1;
113162306a36Sopenharmony_ci		}
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci		if (ps->levels[i].ss_divider_index == 0)
113462306a36Sopenharmony_ci			ps->levels[i].ds_divider_index = 0;
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci		if (ps->levels[i].ds_divider_index == 0)
113762306a36Sopenharmony_ci			ps->levels[i].ss_divider_index = 0;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci		if (ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE)
114062306a36Sopenharmony_ci			ps->levels[i].allow_gnb_slow = 1;
114162306a36Sopenharmony_ci		else if ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) ||
114262306a36Sopenharmony_ci			 (new_rps->class2 & ATOM_PPLIB_CLASSIFICATION2_MVC))
114362306a36Sopenharmony_ci			ps->levels[i].allow_gnb_slow = 0;
114462306a36Sopenharmony_ci		else if (i == ps->num_levels - 1)
114562306a36Sopenharmony_ci			ps->levels[i].allow_gnb_slow = 0;
114662306a36Sopenharmony_ci		else
114762306a36Sopenharmony_ci			ps->levels[i].allow_gnb_slow = 1;
114862306a36Sopenharmony_ci	}
114962306a36Sopenharmony_ci}
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_cistatic void sumo_cleanup_asic(struct radeon_device *rdev)
115262306a36Sopenharmony_ci{
115362306a36Sopenharmony_ci	sumo_take_smu_control(rdev, false);
115462306a36Sopenharmony_ci}
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_cistatic int sumo_set_thermal_temperature_range(struct radeon_device *rdev,
115762306a36Sopenharmony_ci					      int min_temp, int max_temp)
115862306a36Sopenharmony_ci{
115962306a36Sopenharmony_ci	int low_temp = 0 * 1000;
116062306a36Sopenharmony_ci	int high_temp = 255 * 1000;
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	if (low_temp < min_temp)
116362306a36Sopenharmony_ci		low_temp = min_temp;
116462306a36Sopenharmony_ci	if (high_temp > max_temp)
116562306a36Sopenharmony_ci		high_temp = max_temp;
116662306a36Sopenharmony_ci	if (high_temp < low_temp) {
116762306a36Sopenharmony_ci		DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp);
116862306a36Sopenharmony_ci		return -EINVAL;
116962306a36Sopenharmony_ci	}
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	WREG32_P(CG_THERMAL_INT, DIG_THERM_INTH(49 + (high_temp / 1000)), ~DIG_THERM_INTH_MASK);
117262306a36Sopenharmony_ci	WREG32_P(CG_THERMAL_INT, DIG_THERM_INTL(49 + (low_temp / 1000)), ~DIG_THERM_INTL_MASK);
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	rdev->pm.dpm.thermal.min_temp = low_temp;
117562306a36Sopenharmony_ci	rdev->pm.dpm.thermal.max_temp = high_temp;
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	return 0;
117862306a36Sopenharmony_ci}
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_cistatic void sumo_update_current_ps(struct radeon_device *rdev,
118162306a36Sopenharmony_ci				   struct radeon_ps *rps)
118262306a36Sopenharmony_ci{
118362306a36Sopenharmony_ci	struct sumo_ps *new_ps = sumo_get_ps(rps);
118462306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	pi->current_rps = *rps;
118762306a36Sopenharmony_ci	pi->current_ps = *new_ps;
118862306a36Sopenharmony_ci	pi->current_rps.ps_priv = &pi->current_ps;
118962306a36Sopenharmony_ci}
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_cistatic void sumo_update_requested_ps(struct radeon_device *rdev,
119262306a36Sopenharmony_ci				     struct radeon_ps *rps)
119362306a36Sopenharmony_ci{
119462306a36Sopenharmony_ci	struct sumo_ps *new_ps = sumo_get_ps(rps);
119562306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	pi->requested_rps = *rps;
119862306a36Sopenharmony_ci	pi->requested_ps = *new_ps;
119962306a36Sopenharmony_ci	pi->requested_rps.ps_priv = &pi->requested_ps;
120062306a36Sopenharmony_ci}
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ciint sumo_dpm_enable(struct radeon_device *rdev)
120362306a36Sopenharmony_ci{
120462306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	if (sumo_dpm_enabled(rdev))
120762306a36Sopenharmony_ci		return -EINVAL;
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	sumo_program_bootup_state(rdev);
121062306a36Sopenharmony_ci	sumo_init_bsp(rdev);
121162306a36Sopenharmony_ci	sumo_reset_am(rdev);
121262306a36Sopenharmony_ci	sumo_program_tp(rdev);
121362306a36Sopenharmony_ci	sumo_program_bootup_at(rdev);
121462306a36Sopenharmony_ci	sumo_start_am(rdev);
121562306a36Sopenharmony_ci	if (pi->enable_auto_thermal_throttling) {
121662306a36Sopenharmony_ci		sumo_program_ttp(rdev);
121762306a36Sopenharmony_ci		sumo_program_ttt(rdev);
121862306a36Sopenharmony_ci	}
121962306a36Sopenharmony_ci	sumo_program_dc_hto(rdev);
122062306a36Sopenharmony_ci	sumo_program_power_level_enter_state(rdev);
122162306a36Sopenharmony_ci	sumo_enable_voltage_scaling(rdev, true);
122262306a36Sopenharmony_ci	sumo_program_sstp(rdev);
122362306a36Sopenharmony_ci	sumo_program_vc(rdev, SUMO_VRC_DFLT);
122462306a36Sopenharmony_ci	sumo_override_cnb_thermal_events(rdev);
122562306a36Sopenharmony_ci	sumo_start_dpm(rdev);
122662306a36Sopenharmony_ci	sumo_wait_for_level_0(rdev);
122762306a36Sopenharmony_ci	if (pi->enable_sclk_ds)
122862306a36Sopenharmony_ci		sumo_enable_sclk_ds(rdev, true);
122962306a36Sopenharmony_ci	if (pi->enable_boost)
123062306a36Sopenharmony_ci		sumo_enable_boost_timer(rdev);
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	sumo_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	return 0;
123562306a36Sopenharmony_ci}
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ciint sumo_dpm_late_enable(struct radeon_device *rdev)
123862306a36Sopenharmony_ci{
123962306a36Sopenharmony_ci	int ret;
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	ret = sumo_enable_clock_power_gating(rdev);
124262306a36Sopenharmony_ci	if (ret)
124362306a36Sopenharmony_ci		return ret;
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	if (rdev->irq.installed &&
124662306a36Sopenharmony_ci	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
124762306a36Sopenharmony_ci		ret = sumo_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
124862306a36Sopenharmony_ci		if (ret)
124962306a36Sopenharmony_ci			return ret;
125062306a36Sopenharmony_ci		rdev->irq.dpm_thermal = true;
125162306a36Sopenharmony_ci		radeon_irq_set(rdev);
125262306a36Sopenharmony_ci	}
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	return 0;
125562306a36Sopenharmony_ci}
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_civoid sumo_dpm_disable(struct radeon_device *rdev)
125862306a36Sopenharmony_ci{
125962306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	if (!sumo_dpm_enabled(rdev))
126262306a36Sopenharmony_ci		return;
126362306a36Sopenharmony_ci	sumo_disable_clock_power_gating(rdev);
126462306a36Sopenharmony_ci	if (pi->enable_sclk_ds)
126562306a36Sopenharmony_ci		sumo_enable_sclk_ds(rdev, false);
126662306a36Sopenharmony_ci	sumo_clear_vc(rdev);
126762306a36Sopenharmony_ci	sumo_wait_for_level_0(rdev);
126862306a36Sopenharmony_ci	sumo_stop_dpm(rdev);
126962306a36Sopenharmony_ci	sumo_enable_voltage_scaling(rdev, false);
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	if (rdev->irq.installed &&
127262306a36Sopenharmony_ci	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
127362306a36Sopenharmony_ci		rdev->irq.dpm_thermal = false;
127462306a36Sopenharmony_ci		radeon_irq_set(rdev);
127562306a36Sopenharmony_ci	}
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	sumo_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
127862306a36Sopenharmony_ci}
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ciint sumo_dpm_pre_set_power_state(struct radeon_device *rdev)
128162306a36Sopenharmony_ci{
128262306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
128362306a36Sopenharmony_ci	struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps;
128462306a36Sopenharmony_ci	struct radeon_ps *new_ps = &requested_ps;
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	sumo_update_requested_ps(rdev, new_ps);
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	if (pi->enable_dynamic_patch_ps)
128962306a36Sopenharmony_ci		sumo_apply_state_adjust_rules(rdev,
129062306a36Sopenharmony_ci					      &pi->requested_rps,
129162306a36Sopenharmony_ci					      &pi->current_rps);
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	return 0;
129462306a36Sopenharmony_ci}
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ciint sumo_dpm_set_power_state(struct radeon_device *rdev)
129762306a36Sopenharmony_ci{
129862306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
129962306a36Sopenharmony_ci	struct radeon_ps *new_ps = &pi->requested_rps;
130062306a36Sopenharmony_ci	struct radeon_ps *old_ps = &pi->current_rps;
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	if (pi->enable_dpm)
130362306a36Sopenharmony_ci		sumo_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
130462306a36Sopenharmony_ci	if (pi->enable_boost) {
130562306a36Sopenharmony_ci		sumo_enable_boost(rdev, new_ps, false);
130662306a36Sopenharmony_ci		sumo_patch_boost_state(rdev, new_ps);
130762306a36Sopenharmony_ci	}
130862306a36Sopenharmony_ci	if (pi->enable_dpm) {
130962306a36Sopenharmony_ci		sumo_pre_notify_alt_vddnb_change(rdev, new_ps, old_ps);
131062306a36Sopenharmony_ci		sumo_enable_power_level_0(rdev);
131162306a36Sopenharmony_ci		sumo_set_forced_level_0(rdev);
131262306a36Sopenharmony_ci		sumo_set_forced_mode_enabled(rdev);
131362306a36Sopenharmony_ci		sumo_wait_for_level_0(rdev);
131462306a36Sopenharmony_ci		sumo_program_power_levels_0_to_n(rdev, new_ps, old_ps);
131562306a36Sopenharmony_ci		sumo_program_wl(rdev, new_ps);
131662306a36Sopenharmony_ci		sumo_program_bsp(rdev, new_ps);
131762306a36Sopenharmony_ci		sumo_program_at(rdev, new_ps);
131862306a36Sopenharmony_ci		sumo_force_nbp_state(rdev, new_ps);
131962306a36Sopenharmony_ci		sumo_set_forced_mode_disabled(rdev);
132062306a36Sopenharmony_ci		sumo_set_forced_mode_enabled(rdev);
132162306a36Sopenharmony_ci		sumo_set_forced_mode_disabled(rdev);
132262306a36Sopenharmony_ci		sumo_post_notify_alt_vddnb_change(rdev, new_ps, old_ps);
132362306a36Sopenharmony_ci	}
132462306a36Sopenharmony_ci	if (pi->enable_boost)
132562306a36Sopenharmony_ci		sumo_enable_boost(rdev, new_ps, true);
132662306a36Sopenharmony_ci	if (pi->enable_dpm)
132762306a36Sopenharmony_ci		sumo_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	return 0;
133062306a36Sopenharmony_ci}
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_civoid sumo_dpm_post_set_power_state(struct radeon_device *rdev)
133362306a36Sopenharmony_ci{
133462306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
133562306a36Sopenharmony_ci	struct radeon_ps *new_ps = &pi->requested_rps;
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	sumo_update_current_ps(rdev, new_ps);
133862306a36Sopenharmony_ci}
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci#if 0
134162306a36Sopenharmony_civoid sumo_dpm_reset_asic(struct radeon_device *rdev)
134262306a36Sopenharmony_ci{
134362306a36Sopenharmony_ci	sumo_program_bootup_state(rdev);
134462306a36Sopenharmony_ci	sumo_enable_power_level_0(rdev);
134562306a36Sopenharmony_ci	sumo_set_forced_level_0(rdev);
134662306a36Sopenharmony_ci	sumo_set_forced_mode_enabled(rdev);
134762306a36Sopenharmony_ci	sumo_wait_for_level_0(rdev);
134862306a36Sopenharmony_ci	sumo_set_forced_mode_disabled(rdev);
134962306a36Sopenharmony_ci	sumo_set_forced_mode_enabled(rdev);
135062306a36Sopenharmony_ci	sumo_set_forced_mode_disabled(rdev);
135162306a36Sopenharmony_ci}
135262306a36Sopenharmony_ci#endif
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_civoid sumo_dpm_setup_asic(struct radeon_device *rdev)
135562306a36Sopenharmony_ci{
135662306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	sumo_initialize_m3_arb(rdev);
135962306a36Sopenharmony_ci	pi->fw_version = sumo_get_running_fw_version(rdev);
136062306a36Sopenharmony_ci	DRM_INFO("Found smc ucode version: 0x%08x\n", pi->fw_version);
136162306a36Sopenharmony_ci	sumo_program_acpi_power_level(rdev);
136262306a36Sopenharmony_ci	sumo_enable_acpi_pm(rdev);
136362306a36Sopenharmony_ci	sumo_take_smu_control(rdev, true);
136462306a36Sopenharmony_ci}
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_civoid sumo_dpm_display_configuration_changed(struct radeon_device *rdev)
136762306a36Sopenharmony_ci{
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci}
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ciunion power_info {
137262306a36Sopenharmony_ci	struct _ATOM_POWERPLAY_INFO info;
137362306a36Sopenharmony_ci	struct _ATOM_POWERPLAY_INFO_V2 info_2;
137462306a36Sopenharmony_ci	struct _ATOM_POWERPLAY_INFO_V3 info_3;
137562306a36Sopenharmony_ci	struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
137662306a36Sopenharmony_ci	struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
137762306a36Sopenharmony_ci	struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
137862306a36Sopenharmony_ci};
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ciunion pplib_clock_info {
138162306a36Sopenharmony_ci	struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
138262306a36Sopenharmony_ci	struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
138362306a36Sopenharmony_ci	struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
138462306a36Sopenharmony_ci	struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
138562306a36Sopenharmony_ci};
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ciunion pplib_power_state {
138862306a36Sopenharmony_ci	struct _ATOM_PPLIB_STATE v1;
138962306a36Sopenharmony_ci	struct _ATOM_PPLIB_STATE_V2 v2;
139062306a36Sopenharmony_ci};
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_cistatic void sumo_patch_boot_state(struct radeon_device *rdev,
139362306a36Sopenharmony_ci				  struct sumo_ps *ps)
139462306a36Sopenharmony_ci{
139562306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	ps->num_levels = 1;
139862306a36Sopenharmony_ci	ps->flags = 0;
139962306a36Sopenharmony_ci	ps->levels[0] = pi->boot_pl;
140062306a36Sopenharmony_ci}
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_cistatic void sumo_parse_pplib_non_clock_info(struct radeon_device *rdev,
140362306a36Sopenharmony_ci					    struct radeon_ps *rps,
140462306a36Sopenharmony_ci					    struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
140562306a36Sopenharmony_ci					    u8 table_rev)
140662306a36Sopenharmony_ci{
140762306a36Sopenharmony_ci	struct sumo_ps *ps = sumo_get_ps(rps);
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
141062306a36Sopenharmony_ci	rps->class = le16_to_cpu(non_clock_info->usClassification);
141162306a36Sopenharmony_ci	rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
141462306a36Sopenharmony_ci		rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
141562306a36Sopenharmony_ci		rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
141662306a36Sopenharmony_ci	} else {
141762306a36Sopenharmony_ci		rps->vclk = 0;
141862306a36Sopenharmony_ci		rps->dclk = 0;
141962306a36Sopenharmony_ci	}
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
142262306a36Sopenharmony_ci		rdev->pm.dpm.boot_ps = rps;
142362306a36Sopenharmony_ci		sumo_patch_boot_state(rdev, ps);
142462306a36Sopenharmony_ci	}
142562306a36Sopenharmony_ci	if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
142662306a36Sopenharmony_ci		rdev->pm.dpm.uvd_ps = rps;
142762306a36Sopenharmony_ci}
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_cistatic void sumo_parse_pplib_clock_info(struct radeon_device *rdev,
143062306a36Sopenharmony_ci					struct radeon_ps *rps, int index,
143162306a36Sopenharmony_ci					union pplib_clock_info *clock_info)
143262306a36Sopenharmony_ci{
143362306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
143462306a36Sopenharmony_ci	struct sumo_ps *ps = sumo_get_ps(rps);
143562306a36Sopenharmony_ci	struct sumo_pl *pl = &ps->levels[index];
143662306a36Sopenharmony_ci	u32 sclk;
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci	sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow);
143962306a36Sopenharmony_ci	sclk |= clock_info->sumo.ucEngineClockHigh << 16;
144062306a36Sopenharmony_ci	pl->sclk = sclk;
144162306a36Sopenharmony_ci	pl->vddc_index = clock_info->sumo.vddcIndex;
144262306a36Sopenharmony_ci	pl->sclk_dpm_tdp_limit = clock_info->sumo.tdpLimit;
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	ps->num_levels = index + 1;
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	if (pi->enable_sclk_ds) {
144762306a36Sopenharmony_ci		pl->ds_divider_index = 5;
144862306a36Sopenharmony_ci		pl->ss_divider_index = 4;
144962306a36Sopenharmony_ci	}
145062306a36Sopenharmony_ci}
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_cistatic int sumo_parse_power_table(struct radeon_device *rdev)
145362306a36Sopenharmony_ci{
145462306a36Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
145562306a36Sopenharmony_ci	struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
145662306a36Sopenharmony_ci	union pplib_power_state *power_state;
145762306a36Sopenharmony_ci	int i, j, k, non_clock_array_index, clock_array_index;
145862306a36Sopenharmony_ci	union pplib_clock_info *clock_info;
145962306a36Sopenharmony_ci	struct _StateArray *state_array;
146062306a36Sopenharmony_ci	struct _ClockInfoArray *clock_info_array;
146162306a36Sopenharmony_ci	struct _NonClockInfoArray *non_clock_info_array;
146262306a36Sopenharmony_ci	union power_info *power_info;
146362306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
146462306a36Sopenharmony_ci	u16 data_offset;
146562306a36Sopenharmony_ci	u8 frev, crev;
146662306a36Sopenharmony_ci	u8 *power_state_offset;
146762306a36Sopenharmony_ci	struct sumo_ps *ps;
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
147062306a36Sopenharmony_ci				   &frev, &crev, &data_offset))
147162306a36Sopenharmony_ci		return -EINVAL;
147262306a36Sopenharmony_ci	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci	state_array = (struct _StateArray *)
147562306a36Sopenharmony_ci		(mode_info->atom_context->bios + data_offset +
147662306a36Sopenharmony_ci		 le16_to_cpu(power_info->pplib.usStateArrayOffset));
147762306a36Sopenharmony_ci	clock_info_array = (struct _ClockInfoArray *)
147862306a36Sopenharmony_ci		(mode_info->atom_context->bios + data_offset +
147962306a36Sopenharmony_ci		 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset));
148062306a36Sopenharmony_ci	non_clock_info_array = (struct _NonClockInfoArray *)
148162306a36Sopenharmony_ci		(mode_info->atom_context->bios + data_offset +
148262306a36Sopenharmony_ci		 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci	rdev->pm.dpm.ps = kcalloc(state_array->ucNumEntries,
148562306a36Sopenharmony_ci				  sizeof(struct radeon_ps),
148662306a36Sopenharmony_ci				  GFP_KERNEL);
148762306a36Sopenharmony_ci	if (!rdev->pm.dpm.ps)
148862306a36Sopenharmony_ci		return -ENOMEM;
148962306a36Sopenharmony_ci	power_state_offset = (u8 *)state_array->states;
149062306a36Sopenharmony_ci	for (i = 0; i < state_array->ucNumEntries; i++) {
149162306a36Sopenharmony_ci		u8 *idx;
149262306a36Sopenharmony_ci		power_state = (union pplib_power_state *)power_state_offset;
149362306a36Sopenharmony_ci		non_clock_array_index = power_state->v2.nonClockInfoIndex;
149462306a36Sopenharmony_ci		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
149562306a36Sopenharmony_ci			&non_clock_info_array->nonClockInfo[non_clock_array_index];
149662306a36Sopenharmony_ci		if (!rdev->pm.power_state[i].clock_info) {
149762306a36Sopenharmony_ci			kfree(rdev->pm.dpm.ps);
149862306a36Sopenharmony_ci			return -EINVAL;
149962306a36Sopenharmony_ci		}
150062306a36Sopenharmony_ci		ps = kzalloc(sizeof(struct sumo_ps), GFP_KERNEL);
150162306a36Sopenharmony_ci		if (ps == NULL) {
150262306a36Sopenharmony_ci			kfree(rdev->pm.dpm.ps);
150362306a36Sopenharmony_ci			return -ENOMEM;
150462306a36Sopenharmony_ci		}
150562306a36Sopenharmony_ci		rdev->pm.dpm.ps[i].ps_priv = ps;
150662306a36Sopenharmony_ci		k = 0;
150762306a36Sopenharmony_ci		idx = (u8 *)&power_state->v2.clockInfoIndex[0];
150862306a36Sopenharmony_ci		for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) {
150962306a36Sopenharmony_ci			clock_array_index = idx[j];
151062306a36Sopenharmony_ci			if (k >= SUMO_MAX_HARDWARE_POWERLEVELS)
151162306a36Sopenharmony_ci				break;
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci			clock_info = (union pplib_clock_info *)
151462306a36Sopenharmony_ci				((u8 *)&clock_info_array->clockInfo[0] +
151562306a36Sopenharmony_ci				 (clock_array_index * clock_info_array->ucEntrySize));
151662306a36Sopenharmony_ci			sumo_parse_pplib_clock_info(rdev,
151762306a36Sopenharmony_ci						    &rdev->pm.dpm.ps[i], k,
151862306a36Sopenharmony_ci						    clock_info);
151962306a36Sopenharmony_ci			k++;
152062306a36Sopenharmony_ci		}
152162306a36Sopenharmony_ci		sumo_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
152262306a36Sopenharmony_ci						non_clock_info,
152362306a36Sopenharmony_ci						non_clock_info_array->ucEntrySize);
152462306a36Sopenharmony_ci		power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
152562306a36Sopenharmony_ci	}
152662306a36Sopenharmony_ci	rdev->pm.dpm.num_ps = state_array->ucNumEntries;
152762306a36Sopenharmony_ci	return 0;
152862306a36Sopenharmony_ci}
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ciu32 sumo_convert_vid2_to_vid7(struct radeon_device *rdev,
153162306a36Sopenharmony_ci			      struct sumo_vid_mapping_table *vid_mapping_table,
153262306a36Sopenharmony_ci			      u32 vid_2bit)
153362306a36Sopenharmony_ci{
153462306a36Sopenharmony_ci	u32 i;
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci	for (i = 0; i < vid_mapping_table->num_entries; i++) {
153762306a36Sopenharmony_ci		if (vid_mapping_table->entries[i].vid_2bit == vid_2bit)
153862306a36Sopenharmony_ci			return vid_mapping_table->entries[i].vid_7bit;
153962306a36Sopenharmony_ci	}
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	return vid_mapping_table->entries[vid_mapping_table->num_entries - 1].vid_7bit;
154262306a36Sopenharmony_ci}
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci#if 0
154562306a36Sopenharmony_ciu32 sumo_convert_vid7_to_vid2(struct radeon_device *rdev,
154662306a36Sopenharmony_ci			      struct sumo_vid_mapping_table *vid_mapping_table,
154762306a36Sopenharmony_ci			      u32 vid_7bit)
154862306a36Sopenharmony_ci{
154962306a36Sopenharmony_ci	u32 i;
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	for (i = 0; i < vid_mapping_table->num_entries; i++) {
155262306a36Sopenharmony_ci		if (vid_mapping_table->entries[i].vid_7bit == vid_7bit)
155362306a36Sopenharmony_ci			return vid_mapping_table->entries[i].vid_2bit;
155462306a36Sopenharmony_ci	}
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	return vid_mapping_table->entries[vid_mapping_table->num_entries - 1].vid_2bit;
155762306a36Sopenharmony_ci}
155862306a36Sopenharmony_ci#endif
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_cistatic u16 sumo_convert_voltage_index_to_value(struct radeon_device *rdev,
156162306a36Sopenharmony_ci					       u32 vid_2bit)
156262306a36Sopenharmony_ci{
156362306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
156462306a36Sopenharmony_ci	u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, &pi->sys_info.vid_mapping_table, vid_2bit);
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	if (vid_7bit > 0x7C)
156762306a36Sopenharmony_ci		return 0;
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci	return (15500 - vid_7bit * 125 + 5) / 10;
157062306a36Sopenharmony_ci}
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_cistatic void sumo_construct_display_voltage_mapping_table(struct radeon_device *rdev,
157362306a36Sopenharmony_ci							 struct sumo_disp_clock_voltage_mapping_table *disp_clk_voltage_mapping_table,
157462306a36Sopenharmony_ci							 ATOM_CLK_VOLT_CAPABILITY *table)
157562306a36Sopenharmony_ci{
157662306a36Sopenharmony_ci	u32 i;
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci	for (i = 0; i < SUMO_MAX_NUMBER_VOLTAGES; i++) {
157962306a36Sopenharmony_ci		if (table[i].ulMaximumSupportedCLK == 0)
158062306a36Sopenharmony_ci			break;
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci		disp_clk_voltage_mapping_table->display_clock_frequency[i] =
158362306a36Sopenharmony_ci			table[i].ulMaximumSupportedCLK;
158462306a36Sopenharmony_ci	}
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci	disp_clk_voltage_mapping_table->num_max_voltage_levels = i;
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	if (disp_clk_voltage_mapping_table->num_max_voltage_levels == 0) {
158962306a36Sopenharmony_ci		disp_clk_voltage_mapping_table->display_clock_frequency[0] = 80000;
159062306a36Sopenharmony_ci		disp_clk_voltage_mapping_table->num_max_voltage_levels = 1;
159162306a36Sopenharmony_ci	}
159262306a36Sopenharmony_ci}
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_civoid sumo_construct_sclk_voltage_mapping_table(struct radeon_device *rdev,
159562306a36Sopenharmony_ci					       struct sumo_sclk_voltage_mapping_table *sclk_voltage_mapping_table,
159662306a36Sopenharmony_ci					       ATOM_AVAILABLE_SCLK_LIST *table)
159762306a36Sopenharmony_ci{
159862306a36Sopenharmony_ci	u32 i;
159962306a36Sopenharmony_ci	u32 n = 0;
160062306a36Sopenharmony_ci	u32 prev_sclk = 0;
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ci	for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) {
160362306a36Sopenharmony_ci		if (table[i].ulSupportedSCLK > prev_sclk) {
160462306a36Sopenharmony_ci			sclk_voltage_mapping_table->entries[n].sclk_frequency =
160562306a36Sopenharmony_ci				table[i].ulSupportedSCLK;
160662306a36Sopenharmony_ci			sclk_voltage_mapping_table->entries[n].vid_2bit =
160762306a36Sopenharmony_ci				table[i].usVoltageIndex;
160862306a36Sopenharmony_ci			prev_sclk = table[i].ulSupportedSCLK;
160962306a36Sopenharmony_ci			n++;
161062306a36Sopenharmony_ci		}
161162306a36Sopenharmony_ci	}
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	sclk_voltage_mapping_table->num_max_dpm_entries = n;
161462306a36Sopenharmony_ci}
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_civoid sumo_construct_vid_mapping_table(struct radeon_device *rdev,
161762306a36Sopenharmony_ci				      struct sumo_vid_mapping_table *vid_mapping_table,
161862306a36Sopenharmony_ci				      ATOM_AVAILABLE_SCLK_LIST *table)
161962306a36Sopenharmony_ci{
162062306a36Sopenharmony_ci	u32 i, j;
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci	for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) {
162362306a36Sopenharmony_ci		if (table[i].ulSupportedSCLK != 0) {
162462306a36Sopenharmony_ci			vid_mapping_table->entries[table[i].usVoltageIndex].vid_7bit =
162562306a36Sopenharmony_ci				table[i].usVoltageID;
162662306a36Sopenharmony_ci			vid_mapping_table->entries[table[i].usVoltageIndex].vid_2bit =
162762306a36Sopenharmony_ci				table[i].usVoltageIndex;
162862306a36Sopenharmony_ci		}
162962306a36Sopenharmony_ci	}
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci	for (i = 0; i < SUMO_MAX_NUMBER_VOLTAGES; i++) {
163262306a36Sopenharmony_ci		if (vid_mapping_table->entries[i].vid_7bit == 0) {
163362306a36Sopenharmony_ci			for (j = i + 1; j < SUMO_MAX_NUMBER_VOLTAGES; j++) {
163462306a36Sopenharmony_ci				if (vid_mapping_table->entries[j].vid_7bit != 0) {
163562306a36Sopenharmony_ci					vid_mapping_table->entries[i] =
163662306a36Sopenharmony_ci						vid_mapping_table->entries[j];
163762306a36Sopenharmony_ci					vid_mapping_table->entries[j].vid_7bit = 0;
163862306a36Sopenharmony_ci					break;
163962306a36Sopenharmony_ci				}
164062306a36Sopenharmony_ci			}
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci			if (j == SUMO_MAX_NUMBER_VOLTAGES)
164362306a36Sopenharmony_ci				break;
164462306a36Sopenharmony_ci		}
164562306a36Sopenharmony_ci	}
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci	vid_mapping_table->num_entries = i;
164862306a36Sopenharmony_ci}
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ciunion igp_info {
165162306a36Sopenharmony_ci	struct _ATOM_INTEGRATED_SYSTEM_INFO info;
165262306a36Sopenharmony_ci	struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
165362306a36Sopenharmony_ci	struct _ATOM_INTEGRATED_SYSTEM_INFO_V5 info_5;
165462306a36Sopenharmony_ci	struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6;
165562306a36Sopenharmony_ci};
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_cistatic int sumo_parse_sys_info_table(struct radeon_device *rdev)
165862306a36Sopenharmony_ci{
165962306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
166062306a36Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
166162306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
166262306a36Sopenharmony_ci	union igp_info *igp_info;
166362306a36Sopenharmony_ci	u8 frev, crev;
166462306a36Sopenharmony_ci	u16 data_offset;
166562306a36Sopenharmony_ci	int i;
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
166862306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
166962306a36Sopenharmony_ci		igp_info = (union igp_info *)(mode_info->atom_context->bios +
167062306a36Sopenharmony_ci					      data_offset);
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci		if (crev != 6) {
167362306a36Sopenharmony_ci			DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
167462306a36Sopenharmony_ci			return -EINVAL;
167562306a36Sopenharmony_ci		}
167662306a36Sopenharmony_ci		pi->sys_info.bootup_sclk = le32_to_cpu(igp_info->info_6.ulBootUpEngineClock);
167762306a36Sopenharmony_ci		pi->sys_info.min_sclk = le32_to_cpu(igp_info->info_6.ulMinEngineClock);
167862306a36Sopenharmony_ci		pi->sys_info.bootup_uma_clk = le32_to_cpu(igp_info->info_6.ulBootUpUMAClock);
167962306a36Sopenharmony_ci		pi->sys_info.bootup_nb_voltage_index =
168062306a36Sopenharmony_ci			le16_to_cpu(igp_info->info_6.usBootUpNBVoltage);
168162306a36Sopenharmony_ci		if (igp_info->info_6.ucHtcTmpLmt == 0)
168262306a36Sopenharmony_ci			pi->sys_info.htc_tmp_lmt = 203;
168362306a36Sopenharmony_ci		else
168462306a36Sopenharmony_ci			pi->sys_info.htc_tmp_lmt = igp_info->info_6.ucHtcTmpLmt;
168562306a36Sopenharmony_ci		if (igp_info->info_6.ucHtcHystLmt == 0)
168662306a36Sopenharmony_ci			pi->sys_info.htc_hyst_lmt = 5;
168762306a36Sopenharmony_ci		else
168862306a36Sopenharmony_ci			pi->sys_info.htc_hyst_lmt = igp_info->info_6.ucHtcHystLmt;
168962306a36Sopenharmony_ci		if (pi->sys_info.htc_tmp_lmt <= pi->sys_info.htc_hyst_lmt) {
169062306a36Sopenharmony_ci			DRM_ERROR("The htcTmpLmt should be larger than htcHystLmt.\n");
169162306a36Sopenharmony_ci		}
169262306a36Sopenharmony_ci		for (i = 0; i < NUMBER_OF_M3ARB_PARAM_SETS; i++) {
169362306a36Sopenharmony_ci			pi->sys_info.csr_m3_arb_cntl_default[i] =
169462306a36Sopenharmony_ci				le32_to_cpu(igp_info->info_6.ulCSR_M3_ARB_CNTL_DEFAULT[i]);
169562306a36Sopenharmony_ci			pi->sys_info.csr_m3_arb_cntl_uvd[i] =
169662306a36Sopenharmony_ci				le32_to_cpu(igp_info->info_6.ulCSR_M3_ARB_CNTL_UVD[i]);
169762306a36Sopenharmony_ci			pi->sys_info.csr_m3_arb_cntl_fs3d[i] =
169862306a36Sopenharmony_ci				le32_to_cpu(igp_info->info_6.ulCSR_M3_ARB_CNTL_FS3D[i]);
169962306a36Sopenharmony_ci		}
170062306a36Sopenharmony_ci		pi->sys_info.sclk_dpm_boost_margin =
170162306a36Sopenharmony_ci			le32_to_cpu(igp_info->info_6.SclkDpmBoostMargin);
170262306a36Sopenharmony_ci		pi->sys_info.sclk_dpm_throttle_margin =
170362306a36Sopenharmony_ci			le32_to_cpu(igp_info->info_6.SclkDpmThrottleMargin);
170462306a36Sopenharmony_ci		pi->sys_info.sclk_dpm_tdp_limit_pg =
170562306a36Sopenharmony_ci			le16_to_cpu(igp_info->info_6.SclkDpmTdpLimitPG);
170662306a36Sopenharmony_ci		pi->sys_info.gnb_tdp_limit = le16_to_cpu(igp_info->info_6.GnbTdpLimit);
170762306a36Sopenharmony_ci		pi->sys_info.sclk_dpm_tdp_limit_boost =
170862306a36Sopenharmony_ci			le16_to_cpu(igp_info->info_6.SclkDpmTdpLimitBoost);
170962306a36Sopenharmony_ci		pi->sys_info.boost_sclk = le32_to_cpu(igp_info->info_6.ulBoostEngineCLock);
171062306a36Sopenharmony_ci		pi->sys_info.boost_vid_2bit = igp_info->info_6.ulBoostVid_2bit;
171162306a36Sopenharmony_ci		if (igp_info->info_6.EnableBoost)
171262306a36Sopenharmony_ci			pi->sys_info.enable_boost = true;
171362306a36Sopenharmony_ci		else
171462306a36Sopenharmony_ci			pi->sys_info.enable_boost = false;
171562306a36Sopenharmony_ci		sumo_construct_display_voltage_mapping_table(rdev,
171662306a36Sopenharmony_ci							     &pi->sys_info.disp_clk_voltage_mapping_table,
171762306a36Sopenharmony_ci							     igp_info->info_6.sDISPCLK_Voltage);
171862306a36Sopenharmony_ci		sumo_construct_sclk_voltage_mapping_table(rdev,
171962306a36Sopenharmony_ci							  &pi->sys_info.sclk_voltage_mapping_table,
172062306a36Sopenharmony_ci							  igp_info->info_6.sAvail_SCLK);
172162306a36Sopenharmony_ci		sumo_construct_vid_mapping_table(rdev, &pi->sys_info.vid_mapping_table,
172262306a36Sopenharmony_ci						 igp_info->info_6.sAvail_SCLK);
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci	}
172562306a36Sopenharmony_ci	return 0;
172662306a36Sopenharmony_ci}
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_cistatic void sumo_construct_boot_and_acpi_state(struct radeon_device *rdev)
172962306a36Sopenharmony_ci{
173062306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	pi->boot_pl.sclk = pi->sys_info.bootup_sclk;
173362306a36Sopenharmony_ci	pi->boot_pl.vddc_index = pi->sys_info.bootup_nb_voltage_index;
173462306a36Sopenharmony_ci	pi->boot_pl.ds_divider_index = 0;
173562306a36Sopenharmony_ci	pi->boot_pl.ss_divider_index = 0;
173662306a36Sopenharmony_ci	pi->boot_pl.allow_gnb_slow = 1;
173762306a36Sopenharmony_ci	pi->acpi_pl = pi->boot_pl;
173862306a36Sopenharmony_ci	pi->current_ps.num_levels = 1;
173962306a36Sopenharmony_ci	pi->current_ps.levels[0] = pi->boot_pl;
174062306a36Sopenharmony_ci}
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ciint sumo_dpm_init(struct radeon_device *rdev)
174362306a36Sopenharmony_ci{
174462306a36Sopenharmony_ci	struct sumo_power_info *pi;
174562306a36Sopenharmony_ci	u32 hw_rev = (RREG32(HW_REV) & ATI_REV_ID_MASK) >> ATI_REV_ID_SHIFT;
174662306a36Sopenharmony_ci	int ret;
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_ci	pi = kzalloc(sizeof(struct sumo_power_info), GFP_KERNEL);
174962306a36Sopenharmony_ci	if (pi == NULL)
175062306a36Sopenharmony_ci		return -ENOMEM;
175162306a36Sopenharmony_ci	rdev->pm.dpm.priv = pi;
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci	pi->driver_nbps_policy_disable = false;
175462306a36Sopenharmony_ci	if ((rdev->family == CHIP_PALM) && (hw_rev < 3))
175562306a36Sopenharmony_ci		pi->disable_gfx_power_gating_in_uvd = true;
175662306a36Sopenharmony_ci	else
175762306a36Sopenharmony_ci		pi->disable_gfx_power_gating_in_uvd = false;
175862306a36Sopenharmony_ci	pi->enable_alt_vddnb = true;
175962306a36Sopenharmony_ci	pi->enable_sclk_ds = true;
176062306a36Sopenharmony_ci	pi->enable_dynamic_m3_arbiter = false;
176162306a36Sopenharmony_ci	pi->enable_dynamic_patch_ps = true;
176262306a36Sopenharmony_ci	/* Some PALM chips don't seem to properly ungate gfx when UVD is in use;
176362306a36Sopenharmony_ci	 * for now just disable gfx PG.
176462306a36Sopenharmony_ci	 */
176562306a36Sopenharmony_ci	if (rdev->family == CHIP_PALM)
176662306a36Sopenharmony_ci		pi->enable_gfx_power_gating = false;
176762306a36Sopenharmony_ci	else
176862306a36Sopenharmony_ci		pi->enable_gfx_power_gating = true;
176962306a36Sopenharmony_ci	pi->enable_gfx_clock_gating = true;
177062306a36Sopenharmony_ci	pi->enable_mg_clock_gating = true;
177162306a36Sopenharmony_ci	pi->enable_auto_thermal_throttling = true;
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci	ret = sumo_parse_sys_info_table(rdev);
177462306a36Sopenharmony_ci	if (ret)
177562306a36Sopenharmony_ci		return ret;
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	sumo_construct_boot_and_acpi_state(rdev);
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci	ret = r600_get_platform_caps(rdev);
178062306a36Sopenharmony_ci	if (ret)
178162306a36Sopenharmony_ci		return ret;
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci	ret = sumo_parse_power_table(rdev);
178462306a36Sopenharmony_ci	if (ret)
178562306a36Sopenharmony_ci		return ret;
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_ci	pi->pasi = CYPRESS_HASI_DFLT;
178862306a36Sopenharmony_ci	pi->asi = RV770_ASI_DFLT;
178962306a36Sopenharmony_ci	pi->thermal_auto_throttling = pi->sys_info.htc_tmp_lmt;
179062306a36Sopenharmony_ci	pi->enable_boost = pi->sys_info.enable_boost;
179162306a36Sopenharmony_ci	pi->enable_dpm = true;
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	return 0;
179462306a36Sopenharmony_ci}
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_civoid sumo_dpm_print_power_state(struct radeon_device *rdev,
179762306a36Sopenharmony_ci				struct radeon_ps *rps)
179862306a36Sopenharmony_ci{
179962306a36Sopenharmony_ci	int i;
180062306a36Sopenharmony_ci	struct sumo_ps *ps = sumo_get_ps(rps);
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_ci	r600_dpm_print_class_info(rps->class, rps->class2);
180362306a36Sopenharmony_ci	r600_dpm_print_cap_info(rps->caps);
180462306a36Sopenharmony_ci	printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
180562306a36Sopenharmony_ci	for (i = 0; i < ps->num_levels; i++) {
180662306a36Sopenharmony_ci		struct sumo_pl *pl = &ps->levels[i];
180762306a36Sopenharmony_ci		printk("\t\tpower level %d    sclk: %u vddc: %u\n",
180862306a36Sopenharmony_ci		       i, pl->sclk,
180962306a36Sopenharmony_ci		       sumo_convert_voltage_index_to_value(rdev, pl->vddc_index));
181062306a36Sopenharmony_ci	}
181162306a36Sopenharmony_ci	r600_dpm_print_ps_status(rdev, rps);
181262306a36Sopenharmony_ci}
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_civoid sumo_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
181562306a36Sopenharmony_ci						      struct seq_file *m)
181662306a36Sopenharmony_ci{
181762306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
181862306a36Sopenharmony_ci	struct radeon_ps *rps = &pi->current_rps;
181962306a36Sopenharmony_ci	struct sumo_ps *ps = sumo_get_ps(rps);
182062306a36Sopenharmony_ci	struct sumo_pl *pl;
182162306a36Sopenharmony_ci	u32 current_index =
182262306a36Sopenharmony_ci		(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_INDEX_MASK) >>
182362306a36Sopenharmony_ci		CURR_INDEX_SHIFT;
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci	if (current_index == BOOST_DPM_LEVEL) {
182662306a36Sopenharmony_ci		pl = &pi->boost_pl;
182762306a36Sopenharmony_ci		seq_printf(m, "uvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
182862306a36Sopenharmony_ci		seq_printf(m, "power level %d    sclk: %u vddc: %u\n",
182962306a36Sopenharmony_ci			   current_index, pl->sclk,
183062306a36Sopenharmony_ci			   sumo_convert_voltage_index_to_value(rdev, pl->vddc_index));
183162306a36Sopenharmony_ci	} else if (current_index >= ps->num_levels) {
183262306a36Sopenharmony_ci		seq_printf(m, "invalid dpm profile %d\n", current_index);
183362306a36Sopenharmony_ci	} else {
183462306a36Sopenharmony_ci		pl = &ps->levels[current_index];
183562306a36Sopenharmony_ci		seq_printf(m, "uvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
183662306a36Sopenharmony_ci		seq_printf(m, "power level %d    sclk: %u vddc: %u\n",
183762306a36Sopenharmony_ci			   current_index, pl->sclk,
183862306a36Sopenharmony_ci			   sumo_convert_voltage_index_to_value(rdev, pl->vddc_index));
183962306a36Sopenharmony_ci	}
184062306a36Sopenharmony_ci}
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ciu32 sumo_dpm_get_current_sclk(struct radeon_device *rdev)
184362306a36Sopenharmony_ci{
184462306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
184562306a36Sopenharmony_ci	struct radeon_ps *rps = &pi->current_rps;
184662306a36Sopenharmony_ci	struct sumo_ps *ps = sumo_get_ps(rps);
184762306a36Sopenharmony_ci	struct sumo_pl *pl;
184862306a36Sopenharmony_ci	u32 current_index =
184962306a36Sopenharmony_ci		(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_INDEX_MASK) >>
185062306a36Sopenharmony_ci		CURR_INDEX_SHIFT;
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci	if (current_index == BOOST_DPM_LEVEL) {
185362306a36Sopenharmony_ci		pl = &pi->boost_pl;
185462306a36Sopenharmony_ci		return pl->sclk;
185562306a36Sopenharmony_ci	} else if (current_index >= ps->num_levels) {
185662306a36Sopenharmony_ci		return 0;
185762306a36Sopenharmony_ci	} else {
185862306a36Sopenharmony_ci		pl = &ps->levels[current_index];
185962306a36Sopenharmony_ci		return pl->sclk;
186062306a36Sopenharmony_ci	}
186162306a36Sopenharmony_ci}
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ciu32 sumo_dpm_get_current_mclk(struct radeon_device *rdev)
186462306a36Sopenharmony_ci{
186562306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	return pi->sys_info.bootup_uma_clk;
186862306a36Sopenharmony_ci}
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ciu16 sumo_dpm_get_current_vddc(struct radeon_device *rdev)
187162306a36Sopenharmony_ci{
187262306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
187362306a36Sopenharmony_ci	struct radeon_ps *rps = &pi->current_rps;
187462306a36Sopenharmony_ci	struct sumo_ps *ps = sumo_get_ps(rps);
187562306a36Sopenharmony_ci	struct sumo_pl *pl;
187662306a36Sopenharmony_ci	u32 current_index =
187762306a36Sopenharmony_ci		(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_INDEX_MASK) >>
187862306a36Sopenharmony_ci		CURR_INDEX_SHIFT;
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci	if (current_index == BOOST_DPM_LEVEL) {
188162306a36Sopenharmony_ci		pl = &pi->boost_pl;
188262306a36Sopenharmony_ci	} else if (current_index >= ps->num_levels) {
188362306a36Sopenharmony_ci		return 0;
188462306a36Sopenharmony_ci	} else {
188562306a36Sopenharmony_ci		pl = &ps->levels[current_index];
188662306a36Sopenharmony_ci	}
188762306a36Sopenharmony_ci	return sumo_convert_voltage_index_to_value(rdev, pl->vddc_index);
188862306a36Sopenharmony_ci}
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_civoid sumo_dpm_fini(struct radeon_device *rdev)
189162306a36Sopenharmony_ci{
189262306a36Sopenharmony_ci	int i;
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	sumo_cleanup_asic(rdev); /* ??? */
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
189762306a36Sopenharmony_ci		kfree(rdev->pm.dpm.ps[i].ps_priv);
189862306a36Sopenharmony_ci	}
189962306a36Sopenharmony_ci	kfree(rdev->pm.dpm.ps);
190062306a36Sopenharmony_ci	kfree(rdev->pm.dpm.priv);
190162306a36Sopenharmony_ci}
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ciu32 sumo_dpm_get_sclk(struct radeon_device *rdev, bool low)
190462306a36Sopenharmony_ci{
190562306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
190662306a36Sopenharmony_ci	struct sumo_ps *requested_state = sumo_get_ps(&pi->requested_rps);
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_ci	if (low)
190962306a36Sopenharmony_ci		return requested_state->levels[0].sclk;
191062306a36Sopenharmony_ci	else
191162306a36Sopenharmony_ci		return requested_state->levels[requested_state->num_levels - 1].sclk;
191262306a36Sopenharmony_ci}
191362306a36Sopenharmony_ci
191462306a36Sopenharmony_ciu32 sumo_dpm_get_mclk(struct radeon_device *rdev, bool low)
191562306a36Sopenharmony_ci{
191662306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_ci	return pi->sys_info.bootup_uma_clk;
191962306a36Sopenharmony_ci}
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ciint sumo_dpm_force_performance_level(struct radeon_device *rdev,
192262306a36Sopenharmony_ci				     enum radeon_dpm_forced_level level)
192362306a36Sopenharmony_ci{
192462306a36Sopenharmony_ci	struct sumo_power_info *pi = sumo_get_pi(rdev);
192562306a36Sopenharmony_ci	struct radeon_ps *rps = &pi->current_rps;
192662306a36Sopenharmony_ci	struct sumo_ps *ps = sumo_get_ps(rps);
192762306a36Sopenharmony_ci	int i;
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci	if (ps->num_levels <= 1)
193062306a36Sopenharmony_ci		return 0;
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci	if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
193362306a36Sopenharmony_ci		if (pi->enable_boost)
193462306a36Sopenharmony_ci			sumo_enable_boost(rdev, rps, false);
193562306a36Sopenharmony_ci		sumo_power_level_enable(rdev, ps->num_levels - 1, true);
193662306a36Sopenharmony_ci		sumo_set_forced_level(rdev, ps->num_levels - 1);
193762306a36Sopenharmony_ci		sumo_set_forced_mode_enabled(rdev);
193862306a36Sopenharmony_ci		for (i = 0; i < ps->num_levels - 1; i++) {
193962306a36Sopenharmony_ci			sumo_power_level_enable(rdev, i, false);
194062306a36Sopenharmony_ci		}
194162306a36Sopenharmony_ci		sumo_set_forced_mode(rdev, false);
194262306a36Sopenharmony_ci		sumo_set_forced_mode_enabled(rdev);
194362306a36Sopenharmony_ci		sumo_set_forced_mode(rdev, false);
194462306a36Sopenharmony_ci	} else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
194562306a36Sopenharmony_ci		if (pi->enable_boost)
194662306a36Sopenharmony_ci			sumo_enable_boost(rdev, rps, false);
194762306a36Sopenharmony_ci		sumo_power_level_enable(rdev, 0, true);
194862306a36Sopenharmony_ci		sumo_set_forced_level(rdev, 0);
194962306a36Sopenharmony_ci		sumo_set_forced_mode_enabled(rdev);
195062306a36Sopenharmony_ci		for (i = 1; i < ps->num_levels; i++) {
195162306a36Sopenharmony_ci			sumo_power_level_enable(rdev, i, false);
195262306a36Sopenharmony_ci		}
195362306a36Sopenharmony_ci		sumo_set_forced_mode(rdev, false);
195462306a36Sopenharmony_ci		sumo_set_forced_mode_enabled(rdev);
195562306a36Sopenharmony_ci		sumo_set_forced_mode(rdev, false);
195662306a36Sopenharmony_ci	} else {
195762306a36Sopenharmony_ci		for (i = 0; i < ps->num_levels; i++) {
195862306a36Sopenharmony_ci			sumo_power_level_enable(rdev, i, true);
195962306a36Sopenharmony_ci		}
196062306a36Sopenharmony_ci		if (pi->enable_boost)
196162306a36Sopenharmony_ci			sumo_enable_boost(rdev, rps, true);
196262306a36Sopenharmony_ci	}
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci	rdev->pm.dpm.forced_level = level;
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci	return 0;
196762306a36Sopenharmony_ci}
1968