162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright 2013 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 <linux/pci.h>
2562306a36Sopenharmony_ci#include <linux/seq_file.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include "cikd.h"
2862306a36Sopenharmony_ci#include "kv_dpm.h"
2962306a36Sopenharmony_ci#include "r600_dpm.h"
3062306a36Sopenharmony_ci#include "radeon.h"
3162306a36Sopenharmony_ci#include "radeon_asic.h"
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define KV_MAX_DEEPSLEEP_DIVIDER_ID     5
3462306a36Sopenharmony_ci#define KV_MINIMUM_ENGINE_CLOCK         800
3562306a36Sopenharmony_ci#define SMC_RAM_END                     0x40000
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic int kv_enable_nb_dpm(struct radeon_device *rdev,
3862306a36Sopenharmony_ci			    bool enable);
3962306a36Sopenharmony_cistatic void kv_init_graphics_levels(struct radeon_device *rdev);
4062306a36Sopenharmony_cistatic int kv_calculate_ds_divider(struct radeon_device *rdev);
4162306a36Sopenharmony_cistatic int kv_calculate_nbps_level_settings(struct radeon_device *rdev);
4262306a36Sopenharmony_cistatic int kv_calculate_dpm_settings(struct radeon_device *rdev);
4362306a36Sopenharmony_cistatic void kv_enable_new_levels(struct radeon_device *rdev);
4462306a36Sopenharmony_cistatic void kv_program_nbps_index_settings(struct radeon_device *rdev,
4562306a36Sopenharmony_ci					   struct radeon_ps *new_rps);
4662306a36Sopenharmony_cistatic int kv_set_enabled_level(struct radeon_device *rdev, u32 level);
4762306a36Sopenharmony_cistatic int kv_set_enabled_levels(struct radeon_device *rdev);
4862306a36Sopenharmony_cistatic int kv_force_dpm_highest(struct radeon_device *rdev);
4962306a36Sopenharmony_cistatic int kv_force_dpm_lowest(struct radeon_device *rdev);
5062306a36Sopenharmony_cistatic void kv_apply_state_adjust_rules(struct radeon_device *rdev,
5162306a36Sopenharmony_ci					struct radeon_ps *new_rps,
5262306a36Sopenharmony_ci					struct radeon_ps *old_rps);
5362306a36Sopenharmony_cistatic int kv_set_thermal_temperature_range(struct radeon_device *rdev,
5462306a36Sopenharmony_ci					    int min_temp, int max_temp);
5562306a36Sopenharmony_cistatic int kv_init_fps_limits(struct radeon_device *rdev);
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_civoid kv_dpm_powergate_uvd(struct radeon_device *rdev, bool gate);
5862306a36Sopenharmony_cistatic void kv_dpm_powergate_vce(struct radeon_device *rdev, bool gate);
5962306a36Sopenharmony_cistatic void kv_dpm_powergate_samu(struct radeon_device *rdev, bool gate);
6062306a36Sopenharmony_cistatic void kv_dpm_powergate_acp(struct radeon_device *rdev, bool gate);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ciextern void cik_enter_rlc_safe_mode(struct radeon_device *rdev);
6362306a36Sopenharmony_ciextern void cik_exit_rlc_safe_mode(struct radeon_device *rdev);
6462306a36Sopenharmony_ciextern void cik_update_cg(struct radeon_device *rdev,
6562306a36Sopenharmony_ci			  u32 block, bool enable);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic const struct kv_pt_config_reg didt_config_kv[] =
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	{ 0x10, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND },
7062306a36Sopenharmony_ci	{ 0x10, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND },
7162306a36Sopenharmony_ci	{ 0x10, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND },
7262306a36Sopenharmony_ci	{ 0x10, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND },
7362306a36Sopenharmony_ci	{ 0x11, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND },
7462306a36Sopenharmony_ci	{ 0x11, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND },
7562306a36Sopenharmony_ci	{ 0x11, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND },
7662306a36Sopenharmony_ci	{ 0x11, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND },
7762306a36Sopenharmony_ci	{ 0x12, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND },
7862306a36Sopenharmony_ci	{ 0x12, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND },
7962306a36Sopenharmony_ci	{ 0x12, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND },
8062306a36Sopenharmony_ci	{ 0x12, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND },
8162306a36Sopenharmony_ci	{ 0x2, 0x00003fff, 0, 0x4, KV_CONFIGREG_DIDT_IND },
8262306a36Sopenharmony_ci	{ 0x2, 0x03ff0000, 16, 0x80, KV_CONFIGREG_DIDT_IND },
8362306a36Sopenharmony_ci	{ 0x2, 0x78000000, 27, 0x3, KV_CONFIGREG_DIDT_IND },
8462306a36Sopenharmony_ci	{ 0x1, 0x0000ffff, 0, 0x3FFF, KV_CONFIGREG_DIDT_IND },
8562306a36Sopenharmony_ci	{ 0x1, 0xffff0000, 16, 0x3FFF, KV_CONFIGREG_DIDT_IND },
8662306a36Sopenharmony_ci	{ 0x0, 0x00000001, 0, 0x0, KV_CONFIGREG_DIDT_IND },
8762306a36Sopenharmony_ci	{ 0x30, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND },
8862306a36Sopenharmony_ci	{ 0x30, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND },
8962306a36Sopenharmony_ci	{ 0x30, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND },
9062306a36Sopenharmony_ci	{ 0x30, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND },
9162306a36Sopenharmony_ci	{ 0x31, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND },
9262306a36Sopenharmony_ci	{ 0x31, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND },
9362306a36Sopenharmony_ci	{ 0x31, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND },
9462306a36Sopenharmony_ci	{ 0x31, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND },
9562306a36Sopenharmony_ci	{ 0x32, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND },
9662306a36Sopenharmony_ci	{ 0x32, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND },
9762306a36Sopenharmony_ci	{ 0x32, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND },
9862306a36Sopenharmony_ci	{ 0x32, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND },
9962306a36Sopenharmony_ci	{ 0x22, 0x00003fff, 0, 0x4, KV_CONFIGREG_DIDT_IND },
10062306a36Sopenharmony_ci	{ 0x22, 0x03ff0000, 16, 0x80, KV_CONFIGREG_DIDT_IND },
10162306a36Sopenharmony_ci	{ 0x22, 0x78000000, 27, 0x3, KV_CONFIGREG_DIDT_IND },
10262306a36Sopenharmony_ci	{ 0x21, 0x0000ffff, 0, 0x3FFF, KV_CONFIGREG_DIDT_IND },
10362306a36Sopenharmony_ci	{ 0x21, 0xffff0000, 16, 0x3FFF, KV_CONFIGREG_DIDT_IND },
10462306a36Sopenharmony_ci	{ 0x20, 0x00000001, 0, 0x0, KV_CONFIGREG_DIDT_IND },
10562306a36Sopenharmony_ci	{ 0x50, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND },
10662306a36Sopenharmony_ci	{ 0x50, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND },
10762306a36Sopenharmony_ci	{ 0x50, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND },
10862306a36Sopenharmony_ci	{ 0x50, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND },
10962306a36Sopenharmony_ci	{ 0x51, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND },
11062306a36Sopenharmony_ci	{ 0x51, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND },
11162306a36Sopenharmony_ci	{ 0x51, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND },
11262306a36Sopenharmony_ci	{ 0x51, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND },
11362306a36Sopenharmony_ci	{ 0x52, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND },
11462306a36Sopenharmony_ci	{ 0x52, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND },
11562306a36Sopenharmony_ci	{ 0x52, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND },
11662306a36Sopenharmony_ci	{ 0x52, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND },
11762306a36Sopenharmony_ci	{ 0x42, 0x00003fff, 0, 0x4, KV_CONFIGREG_DIDT_IND },
11862306a36Sopenharmony_ci	{ 0x42, 0x03ff0000, 16, 0x80, KV_CONFIGREG_DIDT_IND },
11962306a36Sopenharmony_ci	{ 0x42, 0x78000000, 27, 0x3, KV_CONFIGREG_DIDT_IND },
12062306a36Sopenharmony_ci	{ 0x41, 0x0000ffff, 0, 0x3FFF, KV_CONFIGREG_DIDT_IND },
12162306a36Sopenharmony_ci	{ 0x41, 0xffff0000, 16, 0x3FFF, KV_CONFIGREG_DIDT_IND },
12262306a36Sopenharmony_ci	{ 0x40, 0x00000001, 0, 0x0, KV_CONFIGREG_DIDT_IND },
12362306a36Sopenharmony_ci	{ 0x70, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND },
12462306a36Sopenharmony_ci	{ 0x70, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND },
12562306a36Sopenharmony_ci	{ 0x70, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND },
12662306a36Sopenharmony_ci	{ 0x70, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND },
12762306a36Sopenharmony_ci	{ 0x71, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND },
12862306a36Sopenharmony_ci	{ 0x71, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND },
12962306a36Sopenharmony_ci	{ 0x71, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND },
13062306a36Sopenharmony_ci	{ 0x71, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND },
13162306a36Sopenharmony_ci	{ 0x72, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND },
13262306a36Sopenharmony_ci	{ 0x72, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND },
13362306a36Sopenharmony_ci	{ 0x72, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND },
13462306a36Sopenharmony_ci	{ 0x72, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND },
13562306a36Sopenharmony_ci	{ 0x62, 0x00003fff, 0, 0x4, KV_CONFIGREG_DIDT_IND },
13662306a36Sopenharmony_ci	{ 0x62, 0x03ff0000, 16, 0x80, KV_CONFIGREG_DIDT_IND },
13762306a36Sopenharmony_ci	{ 0x62, 0x78000000, 27, 0x3, KV_CONFIGREG_DIDT_IND },
13862306a36Sopenharmony_ci	{ 0x61, 0x0000ffff, 0, 0x3FFF, KV_CONFIGREG_DIDT_IND },
13962306a36Sopenharmony_ci	{ 0x61, 0xffff0000, 16, 0x3FFF, KV_CONFIGREG_DIDT_IND },
14062306a36Sopenharmony_ci	{ 0x60, 0x00000001, 0, 0x0, KV_CONFIGREG_DIDT_IND },
14162306a36Sopenharmony_ci	{ 0xFFFFFFFF }
14262306a36Sopenharmony_ci};
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic struct kv_ps *kv_get_ps(struct radeon_ps *rps)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	struct kv_ps *ps = rps->ps_priv;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	return ps;
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic struct kv_power_info *kv_get_pi(struct radeon_device *rdev)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	struct kv_power_info *pi = rdev->pm.dpm.priv;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	return pi;
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistatic int kv_program_pt_config_registers(struct radeon_device *rdev,
15962306a36Sopenharmony_ci					  const struct kv_pt_config_reg *cac_config_regs)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	const struct kv_pt_config_reg *config_regs = cac_config_regs;
16262306a36Sopenharmony_ci	u32 data;
16362306a36Sopenharmony_ci	u32 cache = 0;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	if (config_regs == NULL)
16662306a36Sopenharmony_ci		return -EINVAL;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	while (config_regs->offset != 0xFFFFFFFF) {
16962306a36Sopenharmony_ci		if (config_regs->type == KV_CONFIGREG_CACHE) {
17062306a36Sopenharmony_ci			cache |= ((config_regs->value << config_regs->shift) & config_regs->mask);
17162306a36Sopenharmony_ci		} else {
17262306a36Sopenharmony_ci			switch (config_regs->type) {
17362306a36Sopenharmony_ci			case KV_CONFIGREG_SMC_IND:
17462306a36Sopenharmony_ci				data = RREG32_SMC(config_regs->offset);
17562306a36Sopenharmony_ci				break;
17662306a36Sopenharmony_ci			case KV_CONFIGREG_DIDT_IND:
17762306a36Sopenharmony_ci				data = RREG32_DIDT(config_regs->offset);
17862306a36Sopenharmony_ci				break;
17962306a36Sopenharmony_ci			default:
18062306a36Sopenharmony_ci				data = RREG32(config_regs->offset << 2);
18162306a36Sopenharmony_ci				break;
18262306a36Sopenharmony_ci			}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci			data &= ~config_regs->mask;
18562306a36Sopenharmony_ci			data |= ((config_regs->value << config_regs->shift) & config_regs->mask);
18662306a36Sopenharmony_ci			data |= cache;
18762306a36Sopenharmony_ci			cache = 0;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci			switch (config_regs->type) {
19062306a36Sopenharmony_ci			case KV_CONFIGREG_SMC_IND:
19162306a36Sopenharmony_ci				WREG32_SMC(config_regs->offset, data);
19262306a36Sopenharmony_ci				break;
19362306a36Sopenharmony_ci			case KV_CONFIGREG_DIDT_IND:
19462306a36Sopenharmony_ci				WREG32_DIDT(config_regs->offset, data);
19562306a36Sopenharmony_ci				break;
19662306a36Sopenharmony_ci			default:
19762306a36Sopenharmony_ci				WREG32(config_regs->offset << 2, data);
19862306a36Sopenharmony_ci				break;
19962306a36Sopenharmony_ci			}
20062306a36Sopenharmony_ci		}
20162306a36Sopenharmony_ci		config_regs++;
20262306a36Sopenharmony_ci	}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	return 0;
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistatic void kv_do_enable_didt(struct radeon_device *rdev, bool enable)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
21062306a36Sopenharmony_ci	u32 data;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	if (pi->caps_sq_ramping) {
21362306a36Sopenharmony_ci		data = RREG32_DIDT(DIDT_SQ_CTRL0);
21462306a36Sopenharmony_ci		if (enable)
21562306a36Sopenharmony_ci			data |= DIDT_CTRL_EN;
21662306a36Sopenharmony_ci		else
21762306a36Sopenharmony_ci			data &= ~DIDT_CTRL_EN;
21862306a36Sopenharmony_ci		WREG32_DIDT(DIDT_SQ_CTRL0, data);
21962306a36Sopenharmony_ci	}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	if (pi->caps_db_ramping) {
22262306a36Sopenharmony_ci		data = RREG32_DIDT(DIDT_DB_CTRL0);
22362306a36Sopenharmony_ci		if (enable)
22462306a36Sopenharmony_ci			data |= DIDT_CTRL_EN;
22562306a36Sopenharmony_ci		else
22662306a36Sopenharmony_ci			data &= ~DIDT_CTRL_EN;
22762306a36Sopenharmony_ci		WREG32_DIDT(DIDT_DB_CTRL0, data);
22862306a36Sopenharmony_ci	}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	if (pi->caps_td_ramping) {
23162306a36Sopenharmony_ci		data = RREG32_DIDT(DIDT_TD_CTRL0);
23262306a36Sopenharmony_ci		if (enable)
23362306a36Sopenharmony_ci			data |= DIDT_CTRL_EN;
23462306a36Sopenharmony_ci		else
23562306a36Sopenharmony_ci			data &= ~DIDT_CTRL_EN;
23662306a36Sopenharmony_ci		WREG32_DIDT(DIDT_TD_CTRL0, data);
23762306a36Sopenharmony_ci	}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	if (pi->caps_tcp_ramping) {
24062306a36Sopenharmony_ci		data = RREG32_DIDT(DIDT_TCP_CTRL0);
24162306a36Sopenharmony_ci		if (enable)
24262306a36Sopenharmony_ci			data |= DIDT_CTRL_EN;
24362306a36Sopenharmony_ci		else
24462306a36Sopenharmony_ci			data &= ~DIDT_CTRL_EN;
24562306a36Sopenharmony_ci		WREG32_DIDT(DIDT_TCP_CTRL0, data);
24662306a36Sopenharmony_ci	}
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic int kv_enable_didt(struct radeon_device *rdev, bool enable)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
25262306a36Sopenharmony_ci	int ret;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	if (pi->caps_sq_ramping ||
25562306a36Sopenharmony_ci	    pi->caps_db_ramping ||
25662306a36Sopenharmony_ci	    pi->caps_td_ramping ||
25762306a36Sopenharmony_ci	    pi->caps_tcp_ramping) {
25862306a36Sopenharmony_ci		cik_enter_rlc_safe_mode(rdev);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci		if (enable) {
26162306a36Sopenharmony_ci			ret = kv_program_pt_config_registers(rdev, didt_config_kv);
26262306a36Sopenharmony_ci			if (ret) {
26362306a36Sopenharmony_ci				cik_exit_rlc_safe_mode(rdev);
26462306a36Sopenharmony_ci				return ret;
26562306a36Sopenharmony_ci			}
26662306a36Sopenharmony_ci		}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci		kv_do_enable_didt(rdev, enable);
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci		cik_exit_rlc_safe_mode(rdev);
27162306a36Sopenharmony_ci	}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	return 0;
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic int kv_enable_smc_cac(struct radeon_device *rdev, bool enable)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
27962306a36Sopenharmony_ci	int ret = 0;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	if (pi->caps_cac) {
28262306a36Sopenharmony_ci		if (enable) {
28362306a36Sopenharmony_ci			ret = kv_notify_message_to_smu(rdev, PPSMC_MSG_EnableCac);
28462306a36Sopenharmony_ci			if (ret)
28562306a36Sopenharmony_ci				pi->cac_enabled = false;
28662306a36Sopenharmony_ci			else
28762306a36Sopenharmony_ci				pi->cac_enabled = true;
28862306a36Sopenharmony_ci		} else if (pi->cac_enabled) {
28962306a36Sopenharmony_ci			kv_notify_message_to_smu(rdev, PPSMC_MSG_DisableCac);
29062306a36Sopenharmony_ci			pi->cac_enabled = false;
29162306a36Sopenharmony_ci		}
29262306a36Sopenharmony_ci	}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	return ret;
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_cistatic int kv_process_firmware_header(struct radeon_device *rdev)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
30062306a36Sopenharmony_ci	u32 tmp;
30162306a36Sopenharmony_ci	int ret;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	ret = kv_read_smc_sram_dword(rdev, SMU7_FIRMWARE_HEADER_LOCATION +
30462306a36Sopenharmony_ci				     offsetof(SMU7_Firmware_Header, DpmTable),
30562306a36Sopenharmony_ci				     &tmp, pi->sram_end);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	if (ret == 0)
30862306a36Sopenharmony_ci		pi->dpm_table_start = tmp;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	ret = kv_read_smc_sram_dword(rdev, SMU7_FIRMWARE_HEADER_LOCATION +
31162306a36Sopenharmony_ci				     offsetof(SMU7_Firmware_Header, SoftRegisters),
31262306a36Sopenharmony_ci				     &tmp, pi->sram_end);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	if (ret == 0)
31562306a36Sopenharmony_ci		pi->soft_regs_start = tmp;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	return ret;
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_cistatic int kv_enable_dpm_voltage_scaling(struct radeon_device *rdev)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
32362306a36Sopenharmony_ci	int ret;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	pi->graphics_voltage_change_enable = 1;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	ret = kv_copy_bytes_to_smc(rdev,
32862306a36Sopenharmony_ci				   pi->dpm_table_start +
32962306a36Sopenharmony_ci				   offsetof(SMU7_Fusion_DpmTable, GraphicsVoltageChangeEnable),
33062306a36Sopenharmony_ci				   &pi->graphics_voltage_change_enable,
33162306a36Sopenharmony_ci				   sizeof(u8), pi->sram_end);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	return ret;
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic int kv_set_dpm_interval(struct radeon_device *rdev)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
33962306a36Sopenharmony_ci	int ret;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	pi->graphics_interval = 1;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	ret = kv_copy_bytes_to_smc(rdev,
34462306a36Sopenharmony_ci				   pi->dpm_table_start +
34562306a36Sopenharmony_ci				   offsetof(SMU7_Fusion_DpmTable, GraphicsInterval),
34662306a36Sopenharmony_ci				   &pi->graphics_interval,
34762306a36Sopenharmony_ci				   sizeof(u8), pi->sram_end);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	return ret;
35062306a36Sopenharmony_ci}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_cistatic int kv_set_dpm_boot_state(struct radeon_device *rdev)
35362306a36Sopenharmony_ci{
35462306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
35562306a36Sopenharmony_ci	int ret;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	ret = kv_copy_bytes_to_smc(rdev,
35862306a36Sopenharmony_ci				   pi->dpm_table_start +
35962306a36Sopenharmony_ci				   offsetof(SMU7_Fusion_DpmTable, GraphicsBootLevel),
36062306a36Sopenharmony_ci				   &pi->graphics_boot_level,
36162306a36Sopenharmony_ci				   sizeof(u8), pi->sram_end);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	return ret;
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistatic void kv_program_vc(struct radeon_device *rdev)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	WREG32_SMC(CG_FTV_0, 0x3FFFC100);
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_cistatic void kv_clear_vc(struct radeon_device *rdev)
37262306a36Sopenharmony_ci{
37362306a36Sopenharmony_ci	WREG32_SMC(CG_FTV_0, 0);
37462306a36Sopenharmony_ci}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_cistatic int kv_set_divider_value(struct radeon_device *rdev,
37762306a36Sopenharmony_ci				u32 index, u32 sclk)
37862306a36Sopenharmony_ci{
37962306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
38062306a36Sopenharmony_ci	struct atom_clock_dividers dividers;
38162306a36Sopenharmony_ci	int ret;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
38462306a36Sopenharmony_ci					     sclk, false, &dividers);
38562306a36Sopenharmony_ci	if (ret)
38662306a36Sopenharmony_ci		return ret;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	pi->graphics_level[index].SclkDid = (u8)dividers.post_div;
38962306a36Sopenharmony_ci	pi->graphics_level[index].SclkFrequency = cpu_to_be32(sclk);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	return 0;
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cistatic u32 kv_convert_vid2_to_vid7(struct radeon_device *rdev,
39562306a36Sopenharmony_ci				   struct sumo_vid_mapping_table *vid_mapping_table,
39662306a36Sopenharmony_ci				   u32 vid_2bit)
39762306a36Sopenharmony_ci{
39862306a36Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *vddc_sclk_table =
39962306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
40062306a36Sopenharmony_ci	u32 i;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	if (vddc_sclk_table && vddc_sclk_table->count) {
40362306a36Sopenharmony_ci		if (vid_2bit < vddc_sclk_table->count)
40462306a36Sopenharmony_ci			return vddc_sclk_table->entries[vid_2bit].v;
40562306a36Sopenharmony_ci		else
40662306a36Sopenharmony_ci			return vddc_sclk_table->entries[vddc_sclk_table->count - 1].v;
40762306a36Sopenharmony_ci	} else {
40862306a36Sopenharmony_ci		for (i = 0; i < vid_mapping_table->num_entries; i++) {
40962306a36Sopenharmony_ci			if (vid_mapping_table->entries[i].vid_2bit == vid_2bit)
41062306a36Sopenharmony_ci				return vid_mapping_table->entries[i].vid_7bit;
41162306a36Sopenharmony_ci		}
41262306a36Sopenharmony_ci		return vid_mapping_table->entries[vid_mapping_table->num_entries - 1].vid_7bit;
41362306a36Sopenharmony_ci	}
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_cistatic u32 kv_convert_vid7_to_vid2(struct radeon_device *rdev,
41762306a36Sopenharmony_ci				   struct sumo_vid_mapping_table *vid_mapping_table,
41862306a36Sopenharmony_ci				   u32 vid_7bit)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *vddc_sclk_table =
42162306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
42262306a36Sopenharmony_ci	u32 i;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	if (vddc_sclk_table && vddc_sclk_table->count) {
42562306a36Sopenharmony_ci		for (i = 0; i < vddc_sclk_table->count; i++) {
42662306a36Sopenharmony_ci			if (vddc_sclk_table->entries[i].v == vid_7bit)
42762306a36Sopenharmony_ci				return i;
42862306a36Sopenharmony_ci		}
42962306a36Sopenharmony_ci		return vddc_sclk_table->count - 1;
43062306a36Sopenharmony_ci	} else {
43162306a36Sopenharmony_ci		for (i = 0; i < vid_mapping_table->num_entries; i++) {
43262306a36Sopenharmony_ci			if (vid_mapping_table->entries[i].vid_7bit == vid_7bit)
43362306a36Sopenharmony_ci				return vid_mapping_table->entries[i].vid_2bit;
43462306a36Sopenharmony_ci		}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci		return vid_mapping_table->entries[vid_mapping_table->num_entries - 1].vid_2bit;
43762306a36Sopenharmony_ci	}
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_cistatic u16 kv_convert_8bit_index_to_voltage(struct radeon_device *rdev,
44162306a36Sopenharmony_ci					    u16 voltage)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci	return 6200 - (voltage * 25);
44462306a36Sopenharmony_ci}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_cistatic u16 kv_convert_2bit_index_to_voltage(struct radeon_device *rdev,
44762306a36Sopenharmony_ci					    u32 vid_2bit)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
45062306a36Sopenharmony_ci	u32 vid_8bit = kv_convert_vid2_to_vid7(rdev,
45162306a36Sopenharmony_ci					       &pi->sys_info.vid_mapping_table,
45262306a36Sopenharmony_ci					       vid_2bit);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	return kv_convert_8bit_index_to_voltage(rdev, (u16)vid_8bit);
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_cistatic int kv_set_vid(struct radeon_device *rdev, u32 index, u32 vid)
45962306a36Sopenharmony_ci{
46062306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	pi->graphics_level[index].VoltageDownH = (u8)pi->voltage_drop_t;
46362306a36Sopenharmony_ci	pi->graphics_level[index].MinVddNb =
46462306a36Sopenharmony_ci		cpu_to_be32(kv_convert_2bit_index_to_voltage(rdev, vid));
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	return 0;
46762306a36Sopenharmony_ci}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_cistatic int kv_set_at(struct radeon_device *rdev, u32 index, u32 at)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	pi->graphics_level[index].AT = cpu_to_be16((u16)at);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	return 0;
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic void kv_dpm_power_level_enable(struct radeon_device *rdev,
47962306a36Sopenharmony_ci				      u32 index, bool enable)
48062306a36Sopenharmony_ci{
48162306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	pi->graphics_level[index].EnabledForActivity = enable ? 1 : 0;
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_cistatic void kv_start_dpm(struct radeon_device *rdev)
48762306a36Sopenharmony_ci{
48862306a36Sopenharmony_ci	u32 tmp = RREG32_SMC(GENERAL_PWRMGT);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	tmp |= GLOBAL_PWRMGT_EN;
49162306a36Sopenharmony_ci	WREG32_SMC(GENERAL_PWRMGT, tmp);
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	kv_smc_dpm_enable(rdev, true);
49462306a36Sopenharmony_ci}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_cistatic void kv_stop_dpm(struct radeon_device *rdev)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	kv_smc_dpm_enable(rdev, false);
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_cistatic void kv_start_am(struct radeon_device *rdev)
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	u32 sclk_pwrmgt_cntl = RREG32_SMC(SCLK_PWRMGT_CNTL);
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	sclk_pwrmgt_cntl &= ~(RESET_SCLK_CNT | RESET_BUSY_CNT);
50662306a36Sopenharmony_ci	sclk_pwrmgt_cntl |= DYNAMIC_PM_EN;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	WREG32_SMC(SCLK_PWRMGT_CNTL, sclk_pwrmgt_cntl);
50962306a36Sopenharmony_ci}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_cistatic void kv_reset_am(struct radeon_device *rdev)
51262306a36Sopenharmony_ci{
51362306a36Sopenharmony_ci	u32 sclk_pwrmgt_cntl = RREG32_SMC(SCLK_PWRMGT_CNTL);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	sclk_pwrmgt_cntl |= (RESET_SCLK_CNT | RESET_BUSY_CNT);
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	WREG32_SMC(SCLK_PWRMGT_CNTL, sclk_pwrmgt_cntl);
51862306a36Sopenharmony_ci}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_cistatic int kv_freeze_sclk_dpm(struct radeon_device *rdev, bool freeze)
52162306a36Sopenharmony_ci{
52262306a36Sopenharmony_ci	return kv_notify_message_to_smu(rdev, freeze ?
52362306a36Sopenharmony_ci					PPSMC_MSG_SCLKDPM_FreezeLevel : PPSMC_MSG_SCLKDPM_UnfreezeLevel);
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_cistatic int kv_force_lowest_valid(struct radeon_device *rdev)
52762306a36Sopenharmony_ci{
52862306a36Sopenharmony_ci	return kv_force_dpm_lowest(rdev);
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_cistatic int kv_unforce_levels(struct radeon_device *rdev)
53262306a36Sopenharmony_ci{
53362306a36Sopenharmony_ci	if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS)
53462306a36Sopenharmony_ci		return kv_notify_message_to_smu(rdev, PPSMC_MSG_NoForcedLevel);
53562306a36Sopenharmony_ci	else
53662306a36Sopenharmony_ci		return kv_set_enabled_levels(rdev);
53762306a36Sopenharmony_ci}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_cistatic int kv_update_sclk_t(struct radeon_device *rdev)
54062306a36Sopenharmony_ci{
54162306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
54262306a36Sopenharmony_ci	u32 low_sclk_interrupt_t = 0;
54362306a36Sopenharmony_ci	int ret = 0;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	if (pi->caps_sclk_throttle_low_notification) {
54662306a36Sopenharmony_ci		low_sclk_interrupt_t = cpu_to_be32(pi->low_sclk_interrupt_t);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci		ret = kv_copy_bytes_to_smc(rdev,
54962306a36Sopenharmony_ci					   pi->dpm_table_start +
55062306a36Sopenharmony_ci					   offsetof(SMU7_Fusion_DpmTable, LowSclkInterruptT),
55162306a36Sopenharmony_ci					   (u8 *)&low_sclk_interrupt_t,
55262306a36Sopenharmony_ci					   sizeof(u32), pi->sram_end);
55362306a36Sopenharmony_ci	}
55462306a36Sopenharmony_ci	return ret;
55562306a36Sopenharmony_ci}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_cistatic int kv_program_bootup_state(struct radeon_device *rdev)
55862306a36Sopenharmony_ci{
55962306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
56062306a36Sopenharmony_ci	u32 i;
56162306a36Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *table =
56262306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	if (table && table->count) {
56562306a36Sopenharmony_ci		for (i = pi->graphics_dpm_level_count - 1; i > 0; i--) {
56662306a36Sopenharmony_ci			if (table->entries[i].clk == pi->boot_pl.sclk)
56762306a36Sopenharmony_ci				break;
56862306a36Sopenharmony_ci		}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci		pi->graphics_boot_level = (u8)i;
57162306a36Sopenharmony_ci		kv_dpm_power_level_enable(rdev, i, true);
57262306a36Sopenharmony_ci	} else {
57362306a36Sopenharmony_ci		struct sumo_sclk_voltage_mapping_table *table =
57462306a36Sopenharmony_ci			&pi->sys_info.sclk_voltage_mapping_table;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci		if (table->num_max_dpm_entries == 0)
57762306a36Sopenharmony_ci			return -EINVAL;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci		for (i = pi->graphics_dpm_level_count - 1; i > 0; i--) {
58062306a36Sopenharmony_ci			if (table->entries[i].sclk_frequency == pi->boot_pl.sclk)
58162306a36Sopenharmony_ci				break;
58262306a36Sopenharmony_ci		}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci		pi->graphics_boot_level = (u8)i;
58562306a36Sopenharmony_ci		kv_dpm_power_level_enable(rdev, i, true);
58662306a36Sopenharmony_ci	}
58762306a36Sopenharmony_ci	return 0;
58862306a36Sopenharmony_ci}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_cistatic int kv_enable_auto_thermal_throttling(struct radeon_device *rdev)
59162306a36Sopenharmony_ci{
59262306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
59362306a36Sopenharmony_ci	int ret;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	pi->graphics_therm_throttle_enable = 1;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	ret = kv_copy_bytes_to_smc(rdev,
59862306a36Sopenharmony_ci				   pi->dpm_table_start +
59962306a36Sopenharmony_ci				   offsetof(SMU7_Fusion_DpmTable, GraphicsThermThrottleEnable),
60062306a36Sopenharmony_ci				   &pi->graphics_therm_throttle_enable,
60162306a36Sopenharmony_ci				   sizeof(u8), pi->sram_end);
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	return ret;
60462306a36Sopenharmony_ci}
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_cistatic int kv_upload_dpm_settings(struct radeon_device *rdev)
60762306a36Sopenharmony_ci{
60862306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
60962306a36Sopenharmony_ci	int ret;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	ret = kv_copy_bytes_to_smc(rdev,
61262306a36Sopenharmony_ci				   pi->dpm_table_start +
61362306a36Sopenharmony_ci				   offsetof(SMU7_Fusion_DpmTable, GraphicsLevel),
61462306a36Sopenharmony_ci				   (u8 *)&pi->graphics_level,
61562306a36Sopenharmony_ci				   sizeof(SMU7_Fusion_GraphicsLevel) * SMU7_MAX_LEVELS_GRAPHICS,
61662306a36Sopenharmony_ci				   pi->sram_end);
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	if (ret)
61962306a36Sopenharmony_ci		return ret;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	ret = kv_copy_bytes_to_smc(rdev,
62262306a36Sopenharmony_ci				   pi->dpm_table_start +
62362306a36Sopenharmony_ci				   offsetof(SMU7_Fusion_DpmTable, GraphicsDpmLevelCount),
62462306a36Sopenharmony_ci				   &pi->graphics_dpm_level_count,
62562306a36Sopenharmony_ci				   sizeof(u8), pi->sram_end);
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	return ret;
62862306a36Sopenharmony_ci}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_cistatic u32 kv_get_clock_difference(u32 a, u32 b)
63162306a36Sopenharmony_ci{
63262306a36Sopenharmony_ci	return (a >= b) ? a - b : b - a;
63362306a36Sopenharmony_ci}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_cistatic u32 kv_get_clk_bypass(struct radeon_device *rdev, u32 clk)
63662306a36Sopenharmony_ci{
63762306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
63862306a36Sopenharmony_ci	u32 value;
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	if (pi->caps_enable_dfs_bypass) {
64162306a36Sopenharmony_ci		if (kv_get_clock_difference(clk, 40000) < 200)
64262306a36Sopenharmony_ci			value = 3;
64362306a36Sopenharmony_ci		else if (kv_get_clock_difference(clk, 30000) < 200)
64462306a36Sopenharmony_ci			value = 2;
64562306a36Sopenharmony_ci		else if (kv_get_clock_difference(clk, 20000) < 200)
64662306a36Sopenharmony_ci			value = 7;
64762306a36Sopenharmony_ci		else if (kv_get_clock_difference(clk, 15000) < 200)
64862306a36Sopenharmony_ci			value = 6;
64962306a36Sopenharmony_ci		else if (kv_get_clock_difference(clk, 10000) < 200)
65062306a36Sopenharmony_ci			value = 8;
65162306a36Sopenharmony_ci		else
65262306a36Sopenharmony_ci			value = 0;
65362306a36Sopenharmony_ci	} else {
65462306a36Sopenharmony_ci		value = 0;
65562306a36Sopenharmony_ci	}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	return value;
65862306a36Sopenharmony_ci}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_cistatic int kv_populate_uvd_table(struct radeon_device *rdev)
66162306a36Sopenharmony_ci{
66262306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
66362306a36Sopenharmony_ci	struct radeon_uvd_clock_voltage_dependency_table *table =
66462306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table;
66562306a36Sopenharmony_ci	struct atom_clock_dividers dividers;
66662306a36Sopenharmony_ci	int ret;
66762306a36Sopenharmony_ci	u32 i;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	if (table == NULL || table->count == 0)
67062306a36Sopenharmony_ci		return 0;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	pi->uvd_level_count = 0;
67362306a36Sopenharmony_ci	for (i = 0; i < table->count; i++) {
67462306a36Sopenharmony_ci		if (pi->high_voltage_t &&
67562306a36Sopenharmony_ci		    (pi->high_voltage_t < table->entries[i].v))
67662306a36Sopenharmony_ci			break;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci		pi->uvd_level[i].VclkFrequency = cpu_to_be32(table->entries[i].vclk);
67962306a36Sopenharmony_ci		pi->uvd_level[i].DclkFrequency = cpu_to_be32(table->entries[i].dclk);
68062306a36Sopenharmony_ci		pi->uvd_level[i].MinVddNb = cpu_to_be16(table->entries[i].v);
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci		pi->uvd_level[i].VClkBypassCntl =
68362306a36Sopenharmony_ci			(u8)kv_get_clk_bypass(rdev, table->entries[i].vclk);
68462306a36Sopenharmony_ci		pi->uvd_level[i].DClkBypassCntl =
68562306a36Sopenharmony_ci			(u8)kv_get_clk_bypass(rdev, table->entries[i].dclk);
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci		ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
68862306a36Sopenharmony_ci						     table->entries[i].vclk, false, &dividers);
68962306a36Sopenharmony_ci		if (ret)
69062306a36Sopenharmony_ci			return ret;
69162306a36Sopenharmony_ci		pi->uvd_level[i].VclkDivider = (u8)dividers.post_div;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci		ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
69462306a36Sopenharmony_ci						     table->entries[i].dclk, false, &dividers);
69562306a36Sopenharmony_ci		if (ret)
69662306a36Sopenharmony_ci			return ret;
69762306a36Sopenharmony_ci		pi->uvd_level[i].DclkDivider = (u8)dividers.post_div;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci		pi->uvd_level_count++;
70062306a36Sopenharmony_ci	}
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	ret = kv_copy_bytes_to_smc(rdev,
70362306a36Sopenharmony_ci				   pi->dpm_table_start +
70462306a36Sopenharmony_ci				   offsetof(SMU7_Fusion_DpmTable, UvdLevelCount),
70562306a36Sopenharmony_ci				   (u8 *)&pi->uvd_level_count,
70662306a36Sopenharmony_ci				   sizeof(u8), pi->sram_end);
70762306a36Sopenharmony_ci	if (ret)
70862306a36Sopenharmony_ci		return ret;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	pi->uvd_interval = 1;
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	ret = kv_copy_bytes_to_smc(rdev,
71362306a36Sopenharmony_ci				   pi->dpm_table_start +
71462306a36Sopenharmony_ci				   offsetof(SMU7_Fusion_DpmTable, UVDInterval),
71562306a36Sopenharmony_ci				   &pi->uvd_interval,
71662306a36Sopenharmony_ci				   sizeof(u8), pi->sram_end);
71762306a36Sopenharmony_ci	if (ret)
71862306a36Sopenharmony_ci		return ret;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	ret = kv_copy_bytes_to_smc(rdev,
72162306a36Sopenharmony_ci				   pi->dpm_table_start +
72262306a36Sopenharmony_ci				   offsetof(SMU7_Fusion_DpmTable, UvdLevel),
72362306a36Sopenharmony_ci				   (u8 *)&pi->uvd_level,
72462306a36Sopenharmony_ci				   sizeof(SMU7_Fusion_UvdLevel) * SMU7_MAX_LEVELS_UVD,
72562306a36Sopenharmony_ci				   pi->sram_end);
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	return ret;
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_cistatic int kv_populate_vce_table(struct radeon_device *rdev)
73262306a36Sopenharmony_ci{
73362306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
73462306a36Sopenharmony_ci	int ret;
73562306a36Sopenharmony_ci	u32 i;
73662306a36Sopenharmony_ci	struct radeon_vce_clock_voltage_dependency_table *table =
73762306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
73862306a36Sopenharmony_ci	struct atom_clock_dividers dividers;
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	if (table == NULL || table->count == 0)
74162306a36Sopenharmony_ci		return 0;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	pi->vce_level_count = 0;
74462306a36Sopenharmony_ci	for (i = 0; i < table->count; i++) {
74562306a36Sopenharmony_ci		if (pi->high_voltage_t &&
74662306a36Sopenharmony_ci		    pi->high_voltage_t < table->entries[i].v)
74762306a36Sopenharmony_ci			break;
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci		pi->vce_level[i].Frequency = cpu_to_be32(table->entries[i].evclk);
75062306a36Sopenharmony_ci		pi->vce_level[i].MinVoltage = cpu_to_be16(table->entries[i].v);
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci		pi->vce_level[i].ClkBypassCntl =
75362306a36Sopenharmony_ci			(u8)kv_get_clk_bypass(rdev, table->entries[i].evclk);
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci		ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
75662306a36Sopenharmony_ci						     table->entries[i].evclk, false, &dividers);
75762306a36Sopenharmony_ci		if (ret)
75862306a36Sopenharmony_ci			return ret;
75962306a36Sopenharmony_ci		pi->vce_level[i].Divider = (u8)dividers.post_div;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci		pi->vce_level_count++;
76262306a36Sopenharmony_ci	}
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	ret = kv_copy_bytes_to_smc(rdev,
76562306a36Sopenharmony_ci				   pi->dpm_table_start +
76662306a36Sopenharmony_ci				   offsetof(SMU7_Fusion_DpmTable, VceLevelCount),
76762306a36Sopenharmony_ci				   (u8 *)&pi->vce_level_count,
76862306a36Sopenharmony_ci				   sizeof(u8),
76962306a36Sopenharmony_ci				   pi->sram_end);
77062306a36Sopenharmony_ci	if (ret)
77162306a36Sopenharmony_ci		return ret;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	pi->vce_interval = 1;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	ret = kv_copy_bytes_to_smc(rdev,
77662306a36Sopenharmony_ci				   pi->dpm_table_start +
77762306a36Sopenharmony_ci				   offsetof(SMU7_Fusion_DpmTable, VCEInterval),
77862306a36Sopenharmony_ci				   (u8 *)&pi->vce_interval,
77962306a36Sopenharmony_ci				   sizeof(u8),
78062306a36Sopenharmony_ci				   pi->sram_end);
78162306a36Sopenharmony_ci	if (ret)
78262306a36Sopenharmony_ci		return ret;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	ret = kv_copy_bytes_to_smc(rdev,
78562306a36Sopenharmony_ci				   pi->dpm_table_start +
78662306a36Sopenharmony_ci				   offsetof(SMU7_Fusion_DpmTable, VceLevel),
78762306a36Sopenharmony_ci				   (u8 *)&pi->vce_level,
78862306a36Sopenharmony_ci				   sizeof(SMU7_Fusion_ExtClkLevel) * SMU7_MAX_LEVELS_VCE,
78962306a36Sopenharmony_ci				   pi->sram_end);
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	return ret;
79262306a36Sopenharmony_ci}
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_cistatic int kv_populate_samu_table(struct radeon_device *rdev)
79562306a36Sopenharmony_ci{
79662306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
79762306a36Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *table =
79862306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table;
79962306a36Sopenharmony_ci	struct atom_clock_dividers dividers;
80062306a36Sopenharmony_ci	int ret;
80162306a36Sopenharmony_ci	u32 i;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	if (table == NULL || table->count == 0)
80462306a36Sopenharmony_ci		return 0;
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	pi->samu_level_count = 0;
80762306a36Sopenharmony_ci	for (i = 0; i < table->count; i++) {
80862306a36Sopenharmony_ci		if (pi->high_voltage_t &&
80962306a36Sopenharmony_ci		    pi->high_voltage_t < table->entries[i].v)
81062306a36Sopenharmony_ci			break;
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci		pi->samu_level[i].Frequency = cpu_to_be32(table->entries[i].clk);
81362306a36Sopenharmony_ci		pi->samu_level[i].MinVoltage = cpu_to_be16(table->entries[i].v);
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci		pi->samu_level[i].ClkBypassCntl =
81662306a36Sopenharmony_ci			(u8)kv_get_clk_bypass(rdev, table->entries[i].clk);
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci		ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
81962306a36Sopenharmony_ci						     table->entries[i].clk, false, &dividers);
82062306a36Sopenharmony_ci		if (ret)
82162306a36Sopenharmony_ci			return ret;
82262306a36Sopenharmony_ci		pi->samu_level[i].Divider = (u8)dividers.post_div;
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci		pi->samu_level_count++;
82562306a36Sopenharmony_ci	}
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	ret = kv_copy_bytes_to_smc(rdev,
82862306a36Sopenharmony_ci				   pi->dpm_table_start +
82962306a36Sopenharmony_ci				   offsetof(SMU7_Fusion_DpmTable, SamuLevelCount),
83062306a36Sopenharmony_ci				   (u8 *)&pi->samu_level_count,
83162306a36Sopenharmony_ci				   sizeof(u8),
83262306a36Sopenharmony_ci				   pi->sram_end);
83362306a36Sopenharmony_ci	if (ret)
83462306a36Sopenharmony_ci		return ret;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	pi->samu_interval = 1;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	ret = kv_copy_bytes_to_smc(rdev,
83962306a36Sopenharmony_ci				   pi->dpm_table_start +
84062306a36Sopenharmony_ci				   offsetof(SMU7_Fusion_DpmTable, SAMUInterval),
84162306a36Sopenharmony_ci				   (u8 *)&pi->samu_interval,
84262306a36Sopenharmony_ci				   sizeof(u8),
84362306a36Sopenharmony_ci				   pi->sram_end);
84462306a36Sopenharmony_ci	if (ret)
84562306a36Sopenharmony_ci		return ret;
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	ret = kv_copy_bytes_to_smc(rdev,
84862306a36Sopenharmony_ci				   pi->dpm_table_start +
84962306a36Sopenharmony_ci				   offsetof(SMU7_Fusion_DpmTable, SamuLevel),
85062306a36Sopenharmony_ci				   (u8 *)&pi->samu_level,
85162306a36Sopenharmony_ci				   sizeof(SMU7_Fusion_ExtClkLevel) * SMU7_MAX_LEVELS_SAMU,
85262306a36Sopenharmony_ci				   pi->sram_end);
85362306a36Sopenharmony_ci	if (ret)
85462306a36Sopenharmony_ci		return ret;
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	return ret;
85762306a36Sopenharmony_ci}
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_cistatic int kv_populate_acp_table(struct radeon_device *rdev)
86162306a36Sopenharmony_ci{
86262306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
86362306a36Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *table =
86462306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table;
86562306a36Sopenharmony_ci	struct atom_clock_dividers dividers;
86662306a36Sopenharmony_ci	int ret;
86762306a36Sopenharmony_ci	u32 i;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	if (table == NULL || table->count == 0)
87062306a36Sopenharmony_ci		return 0;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	pi->acp_level_count = 0;
87362306a36Sopenharmony_ci	for (i = 0; i < table->count; i++) {
87462306a36Sopenharmony_ci		pi->acp_level[i].Frequency = cpu_to_be32(table->entries[i].clk);
87562306a36Sopenharmony_ci		pi->acp_level[i].MinVoltage = cpu_to_be16(table->entries[i].v);
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci		ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
87862306a36Sopenharmony_ci						     table->entries[i].clk, false, &dividers);
87962306a36Sopenharmony_ci		if (ret)
88062306a36Sopenharmony_ci			return ret;
88162306a36Sopenharmony_ci		pi->acp_level[i].Divider = (u8)dividers.post_div;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci		pi->acp_level_count++;
88462306a36Sopenharmony_ci	}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	ret = kv_copy_bytes_to_smc(rdev,
88762306a36Sopenharmony_ci				   pi->dpm_table_start +
88862306a36Sopenharmony_ci				   offsetof(SMU7_Fusion_DpmTable, AcpLevelCount),
88962306a36Sopenharmony_ci				   (u8 *)&pi->acp_level_count,
89062306a36Sopenharmony_ci				   sizeof(u8),
89162306a36Sopenharmony_ci				   pi->sram_end);
89262306a36Sopenharmony_ci	if (ret)
89362306a36Sopenharmony_ci		return ret;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	pi->acp_interval = 1;
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	ret = kv_copy_bytes_to_smc(rdev,
89862306a36Sopenharmony_ci				   pi->dpm_table_start +
89962306a36Sopenharmony_ci				   offsetof(SMU7_Fusion_DpmTable, ACPInterval),
90062306a36Sopenharmony_ci				   (u8 *)&pi->acp_interval,
90162306a36Sopenharmony_ci				   sizeof(u8),
90262306a36Sopenharmony_ci				   pi->sram_end);
90362306a36Sopenharmony_ci	if (ret)
90462306a36Sopenharmony_ci		return ret;
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	ret = kv_copy_bytes_to_smc(rdev,
90762306a36Sopenharmony_ci				   pi->dpm_table_start +
90862306a36Sopenharmony_ci				   offsetof(SMU7_Fusion_DpmTable, AcpLevel),
90962306a36Sopenharmony_ci				   (u8 *)&pi->acp_level,
91062306a36Sopenharmony_ci				   sizeof(SMU7_Fusion_ExtClkLevel) * SMU7_MAX_LEVELS_ACP,
91162306a36Sopenharmony_ci				   pi->sram_end);
91262306a36Sopenharmony_ci	if (ret)
91362306a36Sopenharmony_ci		return ret;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	return ret;
91662306a36Sopenharmony_ci}
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_cistatic void kv_calculate_dfs_bypass_settings(struct radeon_device *rdev)
91962306a36Sopenharmony_ci{
92062306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
92162306a36Sopenharmony_ci	u32 i;
92262306a36Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *table =
92362306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	if (table && table->count) {
92662306a36Sopenharmony_ci		for (i = 0; i < pi->graphics_dpm_level_count; i++) {
92762306a36Sopenharmony_ci			if (pi->caps_enable_dfs_bypass) {
92862306a36Sopenharmony_ci				if (kv_get_clock_difference(table->entries[i].clk, 40000) < 200)
92962306a36Sopenharmony_ci					pi->graphics_level[i].ClkBypassCntl = 3;
93062306a36Sopenharmony_ci				else if (kv_get_clock_difference(table->entries[i].clk, 30000) < 200)
93162306a36Sopenharmony_ci					pi->graphics_level[i].ClkBypassCntl = 2;
93262306a36Sopenharmony_ci				else if (kv_get_clock_difference(table->entries[i].clk, 26600) < 200)
93362306a36Sopenharmony_ci					pi->graphics_level[i].ClkBypassCntl = 7;
93462306a36Sopenharmony_ci				else if (kv_get_clock_difference(table->entries[i].clk , 20000) < 200)
93562306a36Sopenharmony_ci					pi->graphics_level[i].ClkBypassCntl = 6;
93662306a36Sopenharmony_ci				else if (kv_get_clock_difference(table->entries[i].clk , 10000) < 200)
93762306a36Sopenharmony_ci					pi->graphics_level[i].ClkBypassCntl = 8;
93862306a36Sopenharmony_ci				else
93962306a36Sopenharmony_ci					pi->graphics_level[i].ClkBypassCntl = 0;
94062306a36Sopenharmony_ci			} else {
94162306a36Sopenharmony_ci				pi->graphics_level[i].ClkBypassCntl = 0;
94262306a36Sopenharmony_ci			}
94362306a36Sopenharmony_ci		}
94462306a36Sopenharmony_ci	} else {
94562306a36Sopenharmony_ci		struct sumo_sclk_voltage_mapping_table *table =
94662306a36Sopenharmony_ci			&pi->sys_info.sclk_voltage_mapping_table;
94762306a36Sopenharmony_ci		for (i = 0; i < pi->graphics_dpm_level_count; i++) {
94862306a36Sopenharmony_ci			if (pi->caps_enable_dfs_bypass) {
94962306a36Sopenharmony_ci				if (kv_get_clock_difference(table->entries[i].sclk_frequency, 40000) < 200)
95062306a36Sopenharmony_ci					pi->graphics_level[i].ClkBypassCntl = 3;
95162306a36Sopenharmony_ci				else if (kv_get_clock_difference(table->entries[i].sclk_frequency, 30000) < 200)
95262306a36Sopenharmony_ci					pi->graphics_level[i].ClkBypassCntl = 2;
95362306a36Sopenharmony_ci				else if (kv_get_clock_difference(table->entries[i].sclk_frequency, 26600) < 200)
95462306a36Sopenharmony_ci					pi->graphics_level[i].ClkBypassCntl = 7;
95562306a36Sopenharmony_ci				else if (kv_get_clock_difference(table->entries[i].sclk_frequency, 20000) < 200)
95662306a36Sopenharmony_ci					pi->graphics_level[i].ClkBypassCntl = 6;
95762306a36Sopenharmony_ci				else if (kv_get_clock_difference(table->entries[i].sclk_frequency, 10000) < 200)
95862306a36Sopenharmony_ci					pi->graphics_level[i].ClkBypassCntl = 8;
95962306a36Sopenharmony_ci				else
96062306a36Sopenharmony_ci					pi->graphics_level[i].ClkBypassCntl = 0;
96162306a36Sopenharmony_ci			} else {
96262306a36Sopenharmony_ci				pi->graphics_level[i].ClkBypassCntl = 0;
96362306a36Sopenharmony_ci			}
96462306a36Sopenharmony_ci		}
96562306a36Sopenharmony_ci	}
96662306a36Sopenharmony_ci}
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_cistatic int kv_enable_ulv(struct radeon_device *rdev, bool enable)
96962306a36Sopenharmony_ci{
97062306a36Sopenharmony_ci	return kv_notify_message_to_smu(rdev, enable ?
97162306a36Sopenharmony_ci					PPSMC_MSG_EnableULV : PPSMC_MSG_DisableULV);
97262306a36Sopenharmony_ci}
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_cistatic void kv_reset_acp_boot_level(struct radeon_device *rdev)
97562306a36Sopenharmony_ci{
97662306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	pi->acp_boot_level = 0xff;
97962306a36Sopenharmony_ci}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_cistatic void kv_update_current_ps(struct radeon_device *rdev,
98262306a36Sopenharmony_ci				 struct radeon_ps *rps)
98362306a36Sopenharmony_ci{
98462306a36Sopenharmony_ci	struct kv_ps *new_ps = kv_get_ps(rps);
98562306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	pi->current_rps = *rps;
98862306a36Sopenharmony_ci	pi->current_ps = *new_ps;
98962306a36Sopenharmony_ci	pi->current_rps.ps_priv = &pi->current_ps;
99062306a36Sopenharmony_ci}
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_cistatic void kv_update_requested_ps(struct radeon_device *rdev,
99362306a36Sopenharmony_ci				   struct radeon_ps *rps)
99462306a36Sopenharmony_ci{
99562306a36Sopenharmony_ci	struct kv_ps *new_ps = kv_get_ps(rps);
99662306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	pi->requested_rps = *rps;
99962306a36Sopenharmony_ci	pi->requested_ps = *new_ps;
100062306a36Sopenharmony_ci	pi->requested_rps.ps_priv = &pi->requested_ps;
100162306a36Sopenharmony_ci}
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_civoid kv_dpm_enable_bapm(struct radeon_device *rdev, bool enable)
100462306a36Sopenharmony_ci{
100562306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
100662306a36Sopenharmony_ci	int ret;
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	if (pi->bapm_enable) {
100962306a36Sopenharmony_ci		ret = kv_smc_bapm_enable(rdev, enable);
101062306a36Sopenharmony_ci		if (ret)
101162306a36Sopenharmony_ci			DRM_ERROR("kv_smc_bapm_enable failed\n");
101262306a36Sopenharmony_ci	}
101362306a36Sopenharmony_ci}
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_cistatic void kv_enable_thermal_int(struct radeon_device *rdev, bool enable)
101662306a36Sopenharmony_ci{
101762306a36Sopenharmony_ci	u32 thermal_int;
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	thermal_int = RREG32_SMC(CG_THERMAL_INT_CTRL);
102062306a36Sopenharmony_ci	if (enable)
102162306a36Sopenharmony_ci		thermal_int |= THERM_INTH_MASK | THERM_INTL_MASK;
102262306a36Sopenharmony_ci	else
102362306a36Sopenharmony_ci		thermal_int &= ~(THERM_INTH_MASK | THERM_INTL_MASK);
102462306a36Sopenharmony_ci	WREG32_SMC(CG_THERMAL_INT_CTRL, thermal_int);
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci}
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ciint kv_dpm_enable(struct radeon_device *rdev)
102962306a36Sopenharmony_ci{
103062306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
103162306a36Sopenharmony_ci	int ret;
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	ret = kv_process_firmware_header(rdev);
103462306a36Sopenharmony_ci	if (ret) {
103562306a36Sopenharmony_ci		DRM_ERROR("kv_process_firmware_header failed\n");
103662306a36Sopenharmony_ci		return ret;
103762306a36Sopenharmony_ci	}
103862306a36Sopenharmony_ci	kv_init_fps_limits(rdev);
103962306a36Sopenharmony_ci	kv_init_graphics_levels(rdev);
104062306a36Sopenharmony_ci	ret = kv_program_bootup_state(rdev);
104162306a36Sopenharmony_ci	if (ret) {
104262306a36Sopenharmony_ci		DRM_ERROR("kv_program_bootup_state failed\n");
104362306a36Sopenharmony_ci		return ret;
104462306a36Sopenharmony_ci	}
104562306a36Sopenharmony_ci	kv_calculate_dfs_bypass_settings(rdev);
104662306a36Sopenharmony_ci	ret = kv_upload_dpm_settings(rdev);
104762306a36Sopenharmony_ci	if (ret) {
104862306a36Sopenharmony_ci		DRM_ERROR("kv_upload_dpm_settings failed\n");
104962306a36Sopenharmony_ci		return ret;
105062306a36Sopenharmony_ci	}
105162306a36Sopenharmony_ci	ret = kv_populate_uvd_table(rdev);
105262306a36Sopenharmony_ci	if (ret) {
105362306a36Sopenharmony_ci		DRM_ERROR("kv_populate_uvd_table failed\n");
105462306a36Sopenharmony_ci		return ret;
105562306a36Sopenharmony_ci	}
105662306a36Sopenharmony_ci	ret = kv_populate_vce_table(rdev);
105762306a36Sopenharmony_ci	if (ret) {
105862306a36Sopenharmony_ci		DRM_ERROR("kv_populate_vce_table failed\n");
105962306a36Sopenharmony_ci		return ret;
106062306a36Sopenharmony_ci	}
106162306a36Sopenharmony_ci	ret = kv_populate_samu_table(rdev);
106262306a36Sopenharmony_ci	if (ret) {
106362306a36Sopenharmony_ci		DRM_ERROR("kv_populate_samu_table failed\n");
106462306a36Sopenharmony_ci		return ret;
106562306a36Sopenharmony_ci	}
106662306a36Sopenharmony_ci	ret = kv_populate_acp_table(rdev);
106762306a36Sopenharmony_ci	if (ret) {
106862306a36Sopenharmony_ci		DRM_ERROR("kv_populate_acp_table failed\n");
106962306a36Sopenharmony_ci		return ret;
107062306a36Sopenharmony_ci	}
107162306a36Sopenharmony_ci	kv_program_vc(rdev);
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	kv_start_am(rdev);
107462306a36Sopenharmony_ci	if (pi->enable_auto_thermal_throttling) {
107562306a36Sopenharmony_ci		ret = kv_enable_auto_thermal_throttling(rdev);
107662306a36Sopenharmony_ci		if (ret) {
107762306a36Sopenharmony_ci			DRM_ERROR("kv_enable_auto_thermal_throttling failed\n");
107862306a36Sopenharmony_ci			return ret;
107962306a36Sopenharmony_ci		}
108062306a36Sopenharmony_ci	}
108162306a36Sopenharmony_ci	ret = kv_enable_dpm_voltage_scaling(rdev);
108262306a36Sopenharmony_ci	if (ret) {
108362306a36Sopenharmony_ci		DRM_ERROR("kv_enable_dpm_voltage_scaling failed\n");
108462306a36Sopenharmony_ci		return ret;
108562306a36Sopenharmony_ci	}
108662306a36Sopenharmony_ci	ret = kv_set_dpm_interval(rdev);
108762306a36Sopenharmony_ci	if (ret) {
108862306a36Sopenharmony_ci		DRM_ERROR("kv_set_dpm_interval failed\n");
108962306a36Sopenharmony_ci		return ret;
109062306a36Sopenharmony_ci	}
109162306a36Sopenharmony_ci	ret = kv_set_dpm_boot_state(rdev);
109262306a36Sopenharmony_ci	if (ret) {
109362306a36Sopenharmony_ci		DRM_ERROR("kv_set_dpm_boot_state failed\n");
109462306a36Sopenharmony_ci		return ret;
109562306a36Sopenharmony_ci	}
109662306a36Sopenharmony_ci	ret = kv_enable_ulv(rdev, true);
109762306a36Sopenharmony_ci	if (ret) {
109862306a36Sopenharmony_ci		DRM_ERROR("kv_enable_ulv failed\n");
109962306a36Sopenharmony_ci		return ret;
110062306a36Sopenharmony_ci	}
110162306a36Sopenharmony_ci	kv_start_dpm(rdev);
110262306a36Sopenharmony_ci	ret = kv_enable_didt(rdev, true);
110362306a36Sopenharmony_ci	if (ret) {
110462306a36Sopenharmony_ci		DRM_ERROR("kv_enable_didt failed\n");
110562306a36Sopenharmony_ci		return ret;
110662306a36Sopenharmony_ci	}
110762306a36Sopenharmony_ci	ret = kv_enable_smc_cac(rdev, true);
110862306a36Sopenharmony_ci	if (ret) {
110962306a36Sopenharmony_ci		DRM_ERROR("kv_enable_smc_cac failed\n");
111062306a36Sopenharmony_ci		return ret;
111162306a36Sopenharmony_ci	}
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	kv_reset_acp_boot_level(rdev);
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	ret = kv_smc_bapm_enable(rdev, false);
111662306a36Sopenharmony_ci	if (ret) {
111762306a36Sopenharmony_ci		DRM_ERROR("kv_smc_bapm_enable failed\n");
111862306a36Sopenharmony_ci		return ret;
111962306a36Sopenharmony_ci	}
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	kv_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci	return ret;
112462306a36Sopenharmony_ci}
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ciint kv_dpm_late_enable(struct radeon_device *rdev)
112762306a36Sopenharmony_ci{
112862306a36Sopenharmony_ci	int ret = 0;
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	if (rdev->irq.installed &&
113162306a36Sopenharmony_ci	    r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
113262306a36Sopenharmony_ci		ret = kv_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
113362306a36Sopenharmony_ci		if (ret) {
113462306a36Sopenharmony_ci			DRM_ERROR("kv_set_thermal_temperature_range failed\n");
113562306a36Sopenharmony_ci			return ret;
113662306a36Sopenharmony_ci		}
113762306a36Sopenharmony_ci		kv_enable_thermal_int(rdev, true);
113862306a36Sopenharmony_ci	}
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	/* powerdown unused blocks for now */
114162306a36Sopenharmony_ci	kv_dpm_powergate_acp(rdev, true);
114262306a36Sopenharmony_ci	kv_dpm_powergate_samu(rdev, true);
114362306a36Sopenharmony_ci	kv_dpm_powergate_vce(rdev, true);
114462306a36Sopenharmony_ci	kv_dpm_powergate_uvd(rdev, true);
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	return ret;
114762306a36Sopenharmony_ci}
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_civoid kv_dpm_disable(struct radeon_device *rdev)
115062306a36Sopenharmony_ci{
115162306a36Sopenharmony_ci	kv_smc_bapm_enable(rdev, false);
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	if (rdev->family == CHIP_MULLINS)
115462306a36Sopenharmony_ci		kv_enable_nb_dpm(rdev, false);
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	/* powerup blocks */
115762306a36Sopenharmony_ci	kv_dpm_powergate_acp(rdev, false);
115862306a36Sopenharmony_ci	kv_dpm_powergate_samu(rdev, false);
115962306a36Sopenharmony_ci	kv_dpm_powergate_vce(rdev, false);
116062306a36Sopenharmony_ci	kv_dpm_powergate_uvd(rdev, false);
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	kv_enable_smc_cac(rdev, false);
116362306a36Sopenharmony_ci	kv_enable_didt(rdev, false);
116462306a36Sopenharmony_ci	kv_clear_vc(rdev);
116562306a36Sopenharmony_ci	kv_stop_dpm(rdev);
116662306a36Sopenharmony_ci	kv_enable_ulv(rdev, false);
116762306a36Sopenharmony_ci	kv_reset_am(rdev);
116862306a36Sopenharmony_ci	kv_enable_thermal_int(rdev, false);
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	kv_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
117162306a36Sopenharmony_ci}
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_cistatic void kv_init_sclk_t(struct radeon_device *rdev)
117462306a36Sopenharmony_ci{
117562306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	pi->low_sclk_interrupt_t = 0;
117862306a36Sopenharmony_ci}
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_cistatic int kv_init_fps_limits(struct radeon_device *rdev)
118162306a36Sopenharmony_ci{
118262306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
118362306a36Sopenharmony_ci	int ret = 0;
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	if (pi->caps_fps) {
118662306a36Sopenharmony_ci		u16 tmp;
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci		tmp = 45;
118962306a36Sopenharmony_ci		pi->fps_high_t = cpu_to_be16(tmp);
119062306a36Sopenharmony_ci		ret = kv_copy_bytes_to_smc(rdev,
119162306a36Sopenharmony_ci					   pi->dpm_table_start +
119262306a36Sopenharmony_ci					   offsetof(SMU7_Fusion_DpmTable, FpsHighT),
119362306a36Sopenharmony_ci					   (u8 *)&pi->fps_high_t,
119462306a36Sopenharmony_ci					   sizeof(u16), pi->sram_end);
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci		tmp = 30;
119762306a36Sopenharmony_ci		pi->fps_low_t = cpu_to_be16(tmp);
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci		ret = kv_copy_bytes_to_smc(rdev,
120062306a36Sopenharmony_ci					   pi->dpm_table_start +
120162306a36Sopenharmony_ci					   offsetof(SMU7_Fusion_DpmTable, FpsLowT),
120262306a36Sopenharmony_ci					   (u8 *)&pi->fps_low_t,
120362306a36Sopenharmony_ci					   sizeof(u16), pi->sram_end);
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	}
120662306a36Sopenharmony_ci	return ret;
120762306a36Sopenharmony_ci}
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_cistatic void kv_init_powergate_state(struct radeon_device *rdev)
121062306a36Sopenharmony_ci{
121162306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	pi->uvd_power_gated = false;
121462306a36Sopenharmony_ci	pi->vce_power_gated = false;
121562306a36Sopenharmony_ci	pi->samu_power_gated = false;
121662306a36Sopenharmony_ci	pi->acp_power_gated = false;
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci}
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_cistatic int kv_enable_uvd_dpm(struct radeon_device *rdev, bool enable)
122162306a36Sopenharmony_ci{
122262306a36Sopenharmony_ci	return kv_notify_message_to_smu(rdev, enable ?
122362306a36Sopenharmony_ci					PPSMC_MSG_UVDDPM_Enable : PPSMC_MSG_UVDDPM_Disable);
122462306a36Sopenharmony_ci}
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_cistatic int kv_enable_vce_dpm(struct radeon_device *rdev, bool enable)
122762306a36Sopenharmony_ci{
122862306a36Sopenharmony_ci	return kv_notify_message_to_smu(rdev, enable ?
122962306a36Sopenharmony_ci					PPSMC_MSG_VCEDPM_Enable : PPSMC_MSG_VCEDPM_Disable);
123062306a36Sopenharmony_ci}
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_cistatic int kv_enable_samu_dpm(struct radeon_device *rdev, bool enable)
123362306a36Sopenharmony_ci{
123462306a36Sopenharmony_ci	return kv_notify_message_to_smu(rdev, enable ?
123562306a36Sopenharmony_ci					PPSMC_MSG_SAMUDPM_Enable : PPSMC_MSG_SAMUDPM_Disable);
123662306a36Sopenharmony_ci}
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_cistatic int kv_enable_acp_dpm(struct radeon_device *rdev, bool enable)
123962306a36Sopenharmony_ci{
124062306a36Sopenharmony_ci	return kv_notify_message_to_smu(rdev, enable ?
124162306a36Sopenharmony_ci					PPSMC_MSG_ACPDPM_Enable : PPSMC_MSG_ACPDPM_Disable);
124262306a36Sopenharmony_ci}
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_cistatic int kv_update_uvd_dpm(struct radeon_device *rdev, bool gate)
124562306a36Sopenharmony_ci{
124662306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
124762306a36Sopenharmony_ci	struct radeon_uvd_clock_voltage_dependency_table *table =
124862306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table;
124962306a36Sopenharmony_ci	int ret;
125062306a36Sopenharmony_ci	u32 mask;
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	if (!gate) {
125362306a36Sopenharmony_ci		if (table->count)
125462306a36Sopenharmony_ci			pi->uvd_boot_level = table->count - 1;
125562306a36Sopenharmony_ci		else
125662306a36Sopenharmony_ci			pi->uvd_boot_level = 0;
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci		if (!pi->caps_uvd_dpm || pi->caps_stable_p_state) {
125962306a36Sopenharmony_ci			mask = 1 << pi->uvd_boot_level;
126062306a36Sopenharmony_ci		} else {
126162306a36Sopenharmony_ci			mask = 0x1f;
126262306a36Sopenharmony_ci		}
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci		ret = kv_copy_bytes_to_smc(rdev,
126562306a36Sopenharmony_ci					   pi->dpm_table_start +
126662306a36Sopenharmony_ci					   offsetof(SMU7_Fusion_DpmTable, UvdBootLevel),
126762306a36Sopenharmony_ci					   (uint8_t *)&pi->uvd_boot_level,
126862306a36Sopenharmony_ci					   sizeof(u8), pi->sram_end);
126962306a36Sopenharmony_ci		if (ret)
127062306a36Sopenharmony_ci			return ret;
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci		kv_send_msg_to_smc_with_parameter(rdev,
127362306a36Sopenharmony_ci						  PPSMC_MSG_UVDDPM_SetEnabledMask,
127462306a36Sopenharmony_ci						  mask);
127562306a36Sopenharmony_ci	}
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	return kv_enable_uvd_dpm(rdev, !gate);
127862306a36Sopenharmony_ci}
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_cistatic u8 kv_get_vce_boot_level(struct radeon_device *rdev, u32 evclk)
128162306a36Sopenharmony_ci{
128262306a36Sopenharmony_ci	u8 i;
128362306a36Sopenharmony_ci	struct radeon_vce_clock_voltage_dependency_table *table =
128462306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	for (i = 0; i < table->count; i++) {
128762306a36Sopenharmony_ci		if (table->entries[i].evclk >= evclk)
128862306a36Sopenharmony_ci			break;
128962306a36Sopenharmony_ci	}
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	return i;
129262306a36Sopenharmony_ci}
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_cistatic int kv_update_vce_dpm(struct radeon_device *rdev,
129562306a36Sopenharmony_ci			     struct radeon_ps *radeon_new_state,
129662306a36Sopenharmony_ci			     struct radeon_ps *radeon_current_state)
129762306a36Sopenharmony_ci{
129862306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
129962306a36Sopenharmony_ci	struct radeon_vce_clock_voltage_dependency_table *table =
130062306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
130162306a36Sopenharmony_ci	int ret;
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	if (radeon_new_state->evclk > 0 && radeon_current_state->evclk == 0) {
130462306a36Sopenharmony_ci		kv_dpm_powergate_vce(rdev, false);
130562306a36Sopenharmony_ci		/* turn the clocks on when encoding */
130662306a36Sopenharmony_ci		cik_update_cg(rdev, RADEON_CG_BLOCK_VCE, false);
130762306a36Sopenharmony_ci		if (pi->caps_stable_p_state)
130862306a36Sopenharmony_ci			pi->vce_boot_level = table->count - 1;
130962306a36Sopenharmony_ci		else
131062306a36Sopenharmony_ci			pi->vce_boot_level = kv_get_vce_boot_level(rdev, radeon_new_state->evclk);
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci		ret = kv_copy_bytes_to_smc(rdev,
131362306a36Sopenharmony_ci					   pi->dpm_table_start +
131462306a36Sopenharmony_ci					   offsetof(SMU7_Fusion_DpmTable, VceBootLevel),
131562306a36Sopenharmony_ci					   (u8 *)&pi->vce_boot_level,
131662306a36Sopenharmony_ci					   sizeof(u8),
131762306a36Sopenharmony_ci					   pi->sram_end);
131862306a36Sopenharmony_ci		if (ret)
131962306a36Sopenharmony_ci			return ret;
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci		if (pi->caps_stable_p_state)
132262306a36Sopenharmony_ci			kv_send_msg_to_smc_with_parameter(rdev,
132362306a36Sopenharmony_ci							  PPSMC_MSG_VCEDPM_SetEnabledMask,
132462306a36Sopenharmony_ci							  (1 << pi->vce_boot_level));
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci		kv_enable_vce_dpm(rdev, true);
132762306a36Sopenharmony_ci	} else if (radeon_new_state->evclk == 0 && radeon_current_state->evclk > 0) {
132862306a36Sopenharmony_ci		kv_enable_vce_dpm(rdev, false);
132962306a36Sopenharmony_ci		/* turn the clocks off when not encoding */
133062306a36Sopenharmony_ci		cik_update_cg(rdev, RADEON_CG_BLOCK_VCE, true);
133162306a36Sopenharmony_ci		kv_dpm_powergate_vce(rdev, true);
133262306a36Sopenharmony_ci	}
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	return 0;
133562306a36Sopenharmony_ci}
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_cistatic int kv_update_samu_dpm(struct radeon_device *rdev, bool gate)
133862306a36Sopenharmony_ci{
133962306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
134062306a36Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *table =
134162306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table;
134262306a36Sopenharmony_ci	int ret;
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	if (!gate) {
134562306a36Sopenharmony_ci		if (pi->caps_stable_p_state)
134662306a36Sopenharmony_ci			pi->samu_boot_level = table->count - 1;
134762306a36Sopenharmony_ci		else
134862306a36Sopenharmony_ci			pi->samu_boot_level = 0;
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci		ret = kv_copy_bytes_to_smc(rdev,
135162306a36Sopenharmony_ci					   pi->dpm_table_start +
135262306a36Sopenharmony_ci					   offsetof(SMU7_Fusion_DpmTable, SamuBootLevel),
135362306a36Sopenharmony_ci					   (u8 *)&pi->samu_boot_level,
135462306a36Sopenharmony_ci					   sizeof(u8),
135562306a36Sopenharmony_ci					   pi->sram_end);
135662306a36Sopenharmony_ci		if (ret)
135762306a36Sopenharmony_ci			return ret;
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci		if (pi->caps_stable_p_state)
136062306a36Sopenharmony_ci			kv_send_msg_to_smc_with_parameter(rdev,
136162306a36Sopenharmony_ci							  PPSMC_MSG_SAMUDPM_SetEnabledMask,
136262306a36Sopenharmony_ci							  (1 << pi->samu_boot_level));
136362306a36Sopenharmony_ci	}
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	return kv_enable_samu_dpm(rdev, !gate);
136662306a36Sopenharmony_ci}
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_cistatic u8 kv_get_acp_boot_level(struct radeon_device *rdev)
136962306a36Sopenharmony_ci{
137062306a36Sopenharmony_ci	u8 i;
137162306a36Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *table =
137262306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table;
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	for (i = 0; i < table->count; i++) {
137562306a36Sopenharmony_ci		if (table->entries[i].clk >= 0) /* XXX */
137662306a36Sopenharmony_ci			break;
137762306a36Sopenharmony_ci	}
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	if (i >= table->count)
138062306a36Sopenharmony_ci		i = table->count - 1;
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	return i;
138362306a36Sopenharmony_ci}
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_cistatic void kv_update_acp_boot_level(struct radeon_device *rdev)
138662306a36Sopenharmony_ci{
138762306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
138862306a36Sopenharmony_ci	u8 acp_boot_level;
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci	if (!pi->caps_stable_p_state) {
139162306a36Sopenharmony_ci		acp_boot_level = kv_get_acp_boot_level(rdev);
139262306a36Sopenharmony_ci		if (acp_boot_level != pi->acp_boot_level) {
139362306a36Sopenharmony_ci			pi->acp_boot_level = acp_boot_level;
139462306a36Sopenharmony_ci			kv_send_msg_to_smc_with_parameter(rdev,
139562306a36Sopenharmony_ci							  PPSMC_MSG_ACPDPM_SetEnabledMask,
139662306a36Sopenharmony_ci							  (1 << pi->acp_boot_level));
139762306a36Sopenharmony_ci		}
139862306a36Sopenharmony_ci	}
139962306a36Sopenharmony_ci}
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_cistatic int kv_update_acp_dpm(struct radeon_device *rdev, bool gate)
140262306a36Sopenharmony_ci{
140362306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
140462306a36Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *table =
140562306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table;
140662306a36Sopenharmony_ci	int ret;
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci	if (!gate) {
140962306a36Sopenharmony_ci		if (pi->caps_stable_p_state)
141062306a36Sopenharmony_ci			pi->acp_boot_level = table->count - 1;
141162306a36Sopenharmony_ci		else
141262306a36Sopenharmony_ci			pi->acp_boot_level = kv_get_acp_boot_level(rdev);
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci		ret = kv_copy_bytes_to_smc(rdev,
141562306a36Sopenharmony_ci					   pi->dpm_table_start +
141662306a36Sopenharmony_ci					   offsetof(SMU7_Fusion_DpmTable, AcpBootLevel),
141762306a36Sopenharmony_ci					   (u8 *)&pi->acp_boot_level,
141862306a36Sopenharmony_ci					   sizeof(u8),
141962306a36Sopenharmony_ci					   pi->sram_end);
142062306a36Sopenharmony_ci		if (ret)
142162306a36Sopenharmony_ci			return ret;
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci		if (pi->caps_stable_p_state)
142462306a36Sopenharmony_ci			kv_send_msg_to_smc_with_parameter(rdev,
142562306a36Sopenharmony_ci							  PPSMC_MSG_ACPDPM_SetEnabledMask,
142662306a36Sopenharmony_ci							  (1 << pi->acp_boot_level));
142762306a36Sopenharmony_ci	}
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	return kv_enable_acp_dpm(rdev, !gate);
143062306a36Sopenharmony_ci}
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_civoid kv_dpm_powergate_uvd(struct radeon_device *rdev, bool gate)
143362306a36Sopenharmony_ci{
143462306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	if (pi->uvd_power_gated == gate)
143762306a36Sopenharmony_ci		return;
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	pi->uvd_power_gated = gate;
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	if (gate) {
144262306a36Sopenharmony_ci		if (pi->caps_uvd_pg) {
144362306a36Sopenharmony_ci			uvd_v1_0_stop(rdev);
144462306a36Sopenharmony_ci			cik_update_cg(rdev, RADEON_CG_BLOCK_UVD, false);
144562306a36Sopenharmony_ci		}
144662306a36Sopenharmony_ci		kv_update_uvd_dpm(rdev, gate);
144762306a36Sopenharmony_ci		if (pi->caps_uvd_pg)
144862306a36Sopenharmony_ci			kv_notify_message_to_smu(rdev, PPSMC_MSG_UVDPowerOFF);
144962306a36Sopenharmony_ci	} else {
145062306a36Sopenharmony_ci		if (pi->caps_uvd_pg) {
145162306a36Sopenharmony_ci			kv_notify_message_to_smu(rdev, PPSMC_MSG_UVDPowerON);
145262306a36Sopenharmony_ci			uvd_v4_2_resume(rdev);
145362306a36Sopenharmony_ci			uvd_v1_0_start(rdev);
145462306a36Sopenharmony_ci			cik_update_cg(rdev, RADEON_CG_BLOCK_UVD, true);
145562306a36Sopenharmony_ci		}
145662306a36Sopenharmony_ci		kv_update_uvd_dpm(rdev, gate);
145762306a36Sopenharmony_ci	}
145862306a36Sopenharmony_ci}
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_cistatic void kv_dpm_powergate_vce(struct radeon_device *rdev, bool gate)
146162306a36Sopenharmony_ci{
146262306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci	if (pi->vce_power_gated == gate)
146562306a36Sopenharmony_ci		return;
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	pi->vce_power_gated = gate;
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	if (gate) {
147062306a36Sopenharmony_ci		if (pi->caps_vce_pg) {
147162306a36Sopenharmony_ci			/* XXX do we need a vce_v1_0_stop() ?  */
147262306a36Sopenharmony_ci			kv_notify_message_to_smu(rdev, PPSMC_MSG_VCEPowerOFF);
147362306a36Sopenharmony_ci		}
147462306a36Sopenharmony_ci	} else {
147562306a36Sopenharmony_ci		if (pi->caps_vce_pg) {
147662306a36Sopenharmony_ci			kv_notify_message_to_smu(rdev, PPSMC_MSG_VCEPowerON);
147762306a36Sopenharmony_ci			vce_v2_0_resume(rdev);
147862306a36Sopenharmony_ci			vce_v1_0_start(rdev);
147962306a36Sopenharmony_ci		}
148062306a36Sopenharmony_ci	}
148162306a36Sopenharmony_ci}
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_cistatic void kv_dpm_powergate_samu(struct radeon_device *rdev, bool gate)
148462306a36Sopenharmony_ci{
148562306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	if (pi->samu_power_gated == gate)
148862306a36Sopenharmony_ci		return;
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	pi->samu_power_gated = gate;
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	if (gate) {
149362306a36Sopenharmony_ci		kv_update_samu_dpm(rdev, true);
149462306a36Sopenharmony_ci		if (pi->caps_samu_pg)
149562306a36Sopenharmony_ci			kv_notify_message_to_smu(rdev, PPSMC_MSG_SAMPowerOFF);
149662306a36Sopenharmony_ci	} else {
149762306a36Sopenharmony_ci		if (pi->caps_samu_pg)
149862306a36Sopenharmony_ci			kv_notify_message_to_smu(rdev, PPSMC_MSG_SAMPowerON);
149962306a36Sopenharmony_ci		kv_update_samu_dpm(rdev, false);
150062306a36Sopenharmony_ci	}
150162306a36Sopenharmony_ci}
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_cistatic void kv_dpm_powergate_acp(struct radeon_device *rdev, bool gate)
150462306a36Sopenharmony_ci{
150562306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci	if (pi->acp_power_gated == gate)
150862306a36Sopenharmony_ci		return;
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci	if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS)
151162306a36Sopenharmony_ci		return;
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	pi->acp_power_gated = gate;
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci	if (gate) {
151662306a36Sopenharmony_ci		kv_update_acp_dpm(rdev, true);
151762306a36Sopenharmony_ci		if (pi->caps_acp_pg)
151862306a36Sopenharmony_ci			kv_notify_message_to_smu(rdev, PPSMC_MSG_ACPPowerOFF);
151962306a36Sopenharmony_ci	} else {
152062306a36Sopenharmony_ci		if (pi->caps_acp_pg)
152162306a36Sopenharmony_ci			kv_notify_message_to_smu(rdev, PPSMC_MSG_ACPPowerON);
152262306a36Sopenharmony_ci		kv_update_acp_dpm(rdev, false);
152362306a36Sopenharmony_ci	}
152462306a36Sopenharmony_ci}
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_cistatic void kv_set_valid_clock_range(struct radeon_device *rdev,
152762306a36Sopenharmony_ci				     struct radeon_ps *new_rps)
152862306a36Sopenharmony_ci{
152962306a36Sopenharmony_ci	struct kv_ps *new_ps = kv_get_ps(new_rps);
153062306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
153162306a36Sopenharmony_ci	u32 i;
153262306a36Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *table =
153362306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	if (table && table->count) {
153662306a36Sopenharmony_ci		for (i = 0; i < pi->graphics_dpm_level_count; i++) {
153762306a36Sopenharmony_ci			if ((table->entries[i].clk >= new_ps->levels[0].sclk) ||
153862306a36Sopenharmony_ci			    (i == (pi->graphics_dpm_level_count - 1))) {
153962306a36Sopenharmony_ci				pi->lowest_valid = i;
154062306a36Sopenharmony_ci				break;
154162306a36Sopenharmony_ci			}
154262306a36Sopenharmony_ci		}
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci		for (i = pi->graphics_dpm_level_count - 1; i > 0; i--) {
154562306a36Sopenharmony_ci			if (table->entries[i].clk <= new_ps->levels[new_ps->num_levels - 1].sclk)
154662306a36Sopenharmony_ci				break;
154762306a36Sopenharmony_ci		}
154862306a36Sopenharmony_ci		pi->highest_valid = i;
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci		if (pi->lowest_valid > pi->highest_valid) {
155162306a36Sopenharmony_ci			if ((new_ps->levels[0].sclk - table->entries[pi->highest_valid].clk) >
155262306a36Sopenharmony_ci			    (table->entries[pi->lowest_valid].clk - new_ps->levels[new_ps->num_levels - 1].sclk))
155362306a36Sopenharmony_ci				pi->highest_valid = pi->lowest_valid;
155462306a36Sopenharmony_ci			else
155562306a36Sopenharmony_ci				pi->lowest_valid =  pi->highest_valid;
155662306a36Sopenharmony_ci		}
155762306a36Sopenharmony_ci	} else {
155862306a36Sopenharmony_ci		struct sumo_sclk_voltage_mapping_table *table =
155962306a36Sopenharmony_ci			&pi->sys_info.sclk_voltage_mapping_table;
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci		for (i = 0; i < (int)pi->graphics_dpm_level_count; i++) {
156262306a36Sopenharmony_ci			if (table->entries[i].sclk_frequency >= new_ps->levels[0].sclk ||
156362306a36Sopenharmony_ci			    i == (int)(pi->graphics_dpm_level_count - 1)) {
156462306a36Sopenharmony_ci				pi->lowest_valid = i;
156562306a36Sopenharmony_ci				break;
156662306a36Sopenharmony_ci			}
156762306a36Sopenharmony_ci		}
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci		for (i = pi->graphics_dpm_level_count - 1; i > 0; i--) {
157062306a36Sopenharmony_ci			if (table->entries[i].sclk_frequency <=
157162306a36Sopenharmony_ci			    new_ps->levels[new_ps->num_levels - 1].sclk)
157262306a36Sopenharmony_ci				break;
157362306a36Sopenharmony_ci		}
157462306a36Sopenharmony_ci		pi->highest_valid = i;
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci		if (pi->lowest_valid > pi->highest_valid) {
157762306a36Sopenharmony_ci			if ((new_ps->levels[0].sclk -
157862306a36Sopenharmony_ci			     table->entries[pi->highest_valid].sclk_frequency) >
157962306a36Sopenharmony_ci			    (table->entries[pi->lowest_valid].sclk_frequency -
158062306a36Sopenharmony_ci			     new_ps->levels[new_ps->num_levels -1].sclk))
158162306a36Sopenharmony_ci				pi->highest_valid = pi->lowest_valid;
158262306a36Sopenharmony_ci			else
158362306a36Sopenharmony_ci				pi->lowest_valid =  pi->highest_valid;
158462306a36Sopenharmony_ci		}
158562306a36Sopenharmony_ci	}
158662306a36Sopenharmony_ci}
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_cistatic int kv_update_dfs_bypass_settings(struct radeon_device *rdev,
158962306a36Sopenharmony_ci					 struct radeon_ps *new_rps)
159062306a36Sopenharmony_ci{
159162306a36Sopenharmony_ci	struct kv_ps *new_ps = kv_get_ps(new_rps);
159262306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
159362306a36Sopenharmony_ci	int ret = 0;
159462306a36Sopenharmony_ci	u8 clk_bypass_cntl;
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	if (pi->caps_enable_dfs_bypass) {
159762306a36Sopenharmony_ci		clk_bypass_cntl = new_ps->need_dfs_bypass ?
159862306a36Sopenharmony_ci			pi->graphics_level[pi->graphics_boot_level].ClkBypassCntl : 0;
159962306a36Sopenharmony_ci		ret = kv_copy_bytes_to_smc(rdev,
160062306a36Sopenharmony_ci					   (pi->dpm_table_start +
160162306a36Sopenharmony_ci					    offsetof(SMU7_Fusion_DpmTable, GraphicsLevel) +
160262306a36Sopenharmony_ci					    (pi->graphics_boot_level * sizeof(SMU7_Fusion_GraphicsLevel)) +
160362306a36Sopenharmony_ci					    offsetof(SMU7_Fusion_GraphicsLevel, ClkBypassCntl)),
160462306a36Sopenharmony_ci					   &clk_bypass_cntl,
160562306a36Sopenharmony_ci					   sizeof(u8), pi->sram_end);
160662306a36Sopenharmony_ci	}
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci	return ret;
160962306a36Sopenharmony_ci}
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_cistatic int kv_enable_nb_dpm(struct radeon_device *rdev,
161262306a36Sopenharmony_ci			    bool enable)
161362306a36Sopenharmony_ci{
161462306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
161562306a36Sopenharmony_ci	int ret = 0;
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci	if (enable) {
161862306a36Sopenharmony_ci		if (pi->enable_nb_dpm && !pi->nb_dpm_enabled) {
161962306a36Sopenharmony_ci			ret = kv_notify_message_to_smu(rdev, PPSMC_MSG_NBDPM_Enable);
162062306a36Sopenharmony_ci			if (ret == 0)
162162306a36Sopenharmony_ci				pi->nb_dpm_enabled = true;
162262306a36Sopenharmony_ci		}
162362306a36Sopenharmony_ci	} else {
162462306a36Sopenharmony_ci		if (pi->enable_nb_dpm && pi->nb_dpm_enabled) {
162562306a36Sopenharmony_ci			ret = kv_notify_message_to_smu(rdev, PPSMC_MSG_NBDPM_Disable);
162662306a36Sopenharmony_ci			if (ret == 0)
162762306a36Sopenharmony_ci				pi->nb_dpm_enabled = false;
162862306a36Sopenharmony_ci		}
162962306a36Sopenharmony_ci	}
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci	return ret;
163262306a36Sopenharmony_ci}
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ciint kv_dpm_force_performance_level(struct radeon_device *rdev,
163562306a36Sopenharmony_ci				   enum radeon_dpm_forced_level level)
163662306a36Sopenharmony_ci{
163762306a36Sopenharmony_ci	int ret;
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
164062306a36Sopenharmony_ci		ret = kv_force_dpm_highest(rdev);
164162306a36Sopenharmony_ci		if (ret)
164262306a36Sopenharmony_ci			return ret;
164362306a36Sopenharmony_ci	} else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
164462306a36Sopenharmony_ci		ret = kv_force_dpm_lowest(rdev);
164562306a36Sopenharmony_ci		if (ret)
164662306a36Sopenharmony_ci			return ret;
164762306a36Sopenharmony_ci	} else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) {
164862306a36Sopenharmony_ci		ret = kv_unforce_levels(rdev);
164962306a36Sopenharmony_ci		if (ret)
165062306a36Sopenharmony_ci			return ret;
165162306a36Sopenharmony_ci	}
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci	rdev->pm.dpm.forced_level = level;
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci	return 0;
165662306a36Sopenharmony_ci}
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ciint kv_dpm_pre_set_power_state(struct radeon_device *rdev)
165962306a36Sopenharmony_ci{
166062306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
166162306a36Sopenharmony_ci	struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps;
166262306a36Sopenharmony_ci	struct radeon_ps *new_ps = &requested_ps;
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	kv_update_requested_ps(rdev, new_ps);
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci	kv_apply_state_adjust_rules(rdev,
166762306a36Sopenharmony_ci				    &pi->requested_rps,
166862306a36Sopenharmony_ci				    &pi->current_rps);
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci	return 0;
167162306a36Sopenharmony_ci}
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ciint kv_dpm_set_power_state(struct radeon_device *rdev)
167462306a36Sopenharmony_ci{
167562306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
167662306a36Sopenharmony_ci	struct radeon_ps *new_ps = &pi->requested_rps;
167762306a36Sopenharmony_ci	struct radeon_ps *old_ps = &pi->current_rps;
167862306a36Sopenharmony_ci	int ret;
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci	if (pi->bapm_enable) {
168162306a36Sopenharmony_ci		ret = kv_smc_bapm_enable(rdev, rdev->pm.dpm.ac_power);
168262306a36Sopenharmony_ci		if (ret) {
168362306a36Sopenharmony_ci			DRM_ERROR("kv_smc_bapm_enable failed\n");
168462306a36Sopenharmony_ci			return ret;
168562306a36Sopenharmony_ci		}
168662306a36Sopenharmony_ci	}
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci	if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) {
168962306a36Sopenharmony_ci		if (pi->enable_dpm) {
169062306a36Sopenharmony_ci			kv_set_valid_clock_range(rdev, new_ps);
169162306a36Sopenharmony_ci			kv_update_dfs_bypass_settings(rdev, new_ps);
169262306a36Sopenharmony_ci			ret = kv_calculate_ds_divider(rdev);
169362306a36Sopenharmony_ci			if (ret) {
169462306a36Sopenharmony_ci				DRM_ERROR("kv_calculate_ds_divider failed\n");
169562306a36Sopenharmony_ci				return ret;
169662306a36Sopenharmony_ci			}
169762306a36Sopenharmony_ci			kv_calculate_nbps_level_settings(rdev);
169862306a36Sopenharmony_ci			kv_calculate_dpm_settings(rdev);
169962306a36Sopenharmony_ci			kv_force_lowest_valid(rdev);
170062306a36Sopenharmony_ci			kv_enable_new_levels(rdev);
170162306a36Sopenharmony_ci			kv_upload_dpm_settings(rdev);
170262306a36Sopenharmony_ci			kv_program_nbps_index_settings(rdev, new_ps);
170362306a36Sopenharmony_ci			kv_unforce_levels(rdev);
170462306a36Sopenharmony_ci			kv_set_enabled_levels(rdev);
170562306a36Sopenharmony_ci			kv_force_lowest_valid(rdev);
170662306a36Sopenharmony_ci			kv_unforce_levels(rdev);
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci			ret = kv_update_vce_dpm(rdev, new_ps, old_ps);
170962306a36Sopenharmony_ci			if (ret) {
171062306a36Sopenharmony_ci				DRM_ERROR("kv_update_vce_dpm failed\n");
171162306a36Sopenharmony_ci				return ret;
171262306a36Sopenharmony_ci			}
171362306a36Sopenharmony_ci			kv_update_sclk_t(rdev);
171462306a36Sopenharmony_ci			if (rdev->family == CHIP_MULLINS)
171562306a36Sopenharmony_ci				kv_enable_nb_dpm(rdev, true);
171662306a36Sopenharmony_ci		}
171762306a36Sopenharmony_ci	} else {
171862306a36Sopenharmony_ci		if (pi->enable_dpm) {
171962306a36Sopenharmony_ci			kv_set_valid_clock_range(rdev, new_ps);
172062306a36Sopenharmony_ci			kv_update_dfs_bypass_settings(rdev, new_ps);
172162306a36Sopenharmony_ci			ret = kv_calculate_ds_divider(rdev);
172262306a36Sopenharmony_ci			if (ret) {
172362306a36Sopenharmony_ci				DRM_ERROR("kv_calculate_ds_divider failed\n");
172462306a36Sopenharmony_ci				return ret;
172562306a36Sopenharmony_ci			}
172662306a36Sopenharmony_ci			kv_calculate_nbps_level_settings(rdev);
172762306a36Sopenharmony_ci			kv_calculate_dpm_settings(rdev);
172862306a36Sopenharmony_ci			kv_freeze_sclk_dpm(rdev, true);
172962306a36Sopenharmony_ci			kv_upload_dpm_settings(rdev);
173062306a36Sopenharmony_ci			kv_program_nbps_index_settings(rdev, new_ps);
173162306a36Sopenharmony_ci			kv_freeze_sclk_dpm(rdev, false);
173262306a36Sopenharmony_ci			kv_set_enabled_levels(rdev);
173362306a36Sopenharmony_ci			ret = kv_update_vce_dpm(rdev, new_ps, old_ps);
173462306a36Sopenharmony_ci			if (ret) {
173562306a36Sopenharmony_ci				DRM_ERROR("kv_update_vce_dpm failed\n");
173662306a36Sopenharmony_ci				return ret;
173762306a36Sopenharmony_ci			}
173862306a36Sopenharmony_ci			kv_update_acp_boot_level(rdev);
173962306a36Sopenharmony_ci			kv_update_sclk_t(rdev);
174062306a36Sopenharmony_ci			kv_enable_nb_dpm(rdev, true);
174162306a36Sopenharmony_ci		}
174262306a36Sopenharmony_ci	}
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_ci	return 0;
174562306a36Sopenharmony_ci}
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_civoid kv_dpm_post_set_power_state(struct radeon_device *rdev)
174862306a36Sopenharmony_ci{
174962306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
175062306a36Sopenharmony_ci	struct radeon_ps *new_ps = &pi->requested_rps;
175162306a36Sopenharmony_ci
175262306a36Sopenharmony_ci	kv_update_current_ps(rdev, new_ps);
175362306a36Sopenharmony_ci}
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_civoid kv_dpm_setup_asic(struct radeon_device *rdev)
175662306a36Sopenharmony_ci{
175762306a36Sopenharmony_ci	sumo_take_smu_control(rdev, true);
175862306a36Sopenharmony_ci	kv_init_powergate_state(rdev);
175962306a36Sopenharmony_ci	kv_init_sclk_t(rdev);
176062306a36Sopenharmony_ci}
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci//XXX use sumo_dpm_display_configuration_changed
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_cistatic void kv_construct_max_power_limits_table(struct radeon_device *rdev,
176562306a36Sopenharmony_ci						struct radeon_clock_and_voltage_limits *table)
176662306a36Sopenharmony_ci{
176762306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	if (pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries > 0) {
177062306a36Sopenharmony_ci		int idx = pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries - 1;
177162306a36Sopenharmony_ci		table->sclk =
177262306a36Sopenharmony_ci			pi->sys_info.sclk_voltage_mapping_table.entries[idx].sclk_frequency;
177362306a36Sopenharmony_ci		table->vddc =
177462306a36Sopenharmony_ci			kv_convert_2bit_index_to_voltage(rdev,
177562306a36Sopenharmony_ci							 pi->sys_info.sclk_voltage_mapping_table.entries[idx].vid_2bit);
177662306a36Sopenharmony_ci	}
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci	table->mclk = pi->sys_info.nbp_memory_clock[0];
177962306a36Sopenharmony_ci}
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_cistatic void kv_patch_voltage_values(struct radeon_device *rdev)
178262306a36Sopenharmony_ci{
178362306a36Sopenharmony_ci	int i;
178462306a36Sopenharmony_ci	struct radeon_uvd_clock_voltage_dependency_table *uvd_table =
178562306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table;
178662306a36Sopenharmony_ci	struct radeon_vce_clock_voltage_dependency_table *vce_table =
178762306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
178862306a36Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *samu_table =
178962306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table;
179062306a36Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *acp_table =
179162306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table;
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	if (uvd_table->count) {
179462306a36Sopenharmony_ci		for (i = 0; i < uvd_table->count; i++)
179562306a36Sopenharmony_ci			uvd_table->entries[i].v =
179662306a36Sopenharmony_ci				kv_convert_8bit_index_to_voltage(rdev,
179762306a36Sopenharmony_ci								 uvd_table->entries[i].v);
179862306a36Sopenharmony_ci	}
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci	if (vce_table->count) {
180162306a36Sopenharmony_ci		for (i = 0; i < vce_table->count; i++)
180262306a36Sopenharmony_ci			vce_table->entries[i].v =
180362306a36Sopenharmony_ci				kv_convert_8bit_index_to_voltage(rdev,
180462306a36Sopenharmony_ci								 vce_table->entries[i].v);
180562306a36Sopenharmony_ci	}
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	if (samu_table->count) {
180862306a36Sopenharmony_ci		for (i = 0; i < samu_table->count; i++)
180962306a36Sopenharmony_ci			samu_table->entries[i].v =
181062306a36Sopenharmony_ci				kv_convert_8bit_index_to_voltage(rdev,
181162306a36Sopenharmony_ci								 samu_table->entries[i].v);
181262306a36Sopenharmony_ci	}
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci	if (acp_table->count) {
181562306a36Sopenharmony_ci		for (i = 0; i < acp_table->count; i++)
181662306a36Sopenharmony_ci			acp_table->entries[i].v =
181762306a36Sopenharmony_ci				kv_convert_8bit_index_to_voltage(rdev,
181862306a36Sopenharmony_ci								 acp_table->entries[i].v);
181962306a36Sopenharmony_ci	}
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci}
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_cistatic void kv_construct_boot_state(struct radeon_device *rdev)
182462306a36Sopenharmony_ci{
182562306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_ci	pi->boot_pl.sclk = pi->sys_info.bootup_sclk;
182862306a36Sopenharmony_ci	pi->boot_pl.vddc_index = pi->sys_info.bootup_nb_voltage_index;
182962306a36Sopenharmony_ci	pi->boot_pl.ds_divider_index = 0;
183062306a36Sopenharmony_ci	pi->boot_pl.ss_divider_index = 0;
183162306a36Sopenharmony_ci	pi->boot_pl.allow_gnb_slow = 1;
183262306a36Sopenharmony_ci	pi->boot_pl.force_nbp_state = 0;
183362306a36Sopenharmony_ci	pi->boot_pl.display_wm = 0;
183462306a36Sopenharmony_ci	pi->boot_pl.vce_wm = 0;
183562306a36Sopenharmony_ci}
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_cistatic int kv_force_dpm_highest(struct radeon_device *rdev)
183862306a36Sopenharmony_ci{
183962306a36Sopenharmony_ci	int ret;
184062306a36Sopenharmony_ci	u32 enable_mask, i;
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci	ret = kv_dpm_get_enable_mask(rdev, &enable_mask);
184362306a36Sopenharmony_ci	if (ret)
184462306a36Sopenharmony_ci		return ret;
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci	for (i = SMU7_MAX_LEVELS_GRAPHICS - 1; i > 0; i--) {
184762306a36Sopenharmony_ci		if (enable_mask & (1 << i))
184862306a36Sopenharmony_ci			break;
184962306a36Sopenharmony_ci	}
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_ci	if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS)
185262306a36Sopenharmony_ci		return kv_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_DPM_ForceState, i);
185362306a36Sopenharmony_ci	else
185462306a36Sopenharmony_ci		return kv_set_enabled_level(rdev, i);
185562306a36Sopenharmony_ci}
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_cistatic int kv_force_dpm_lowest(struct radeon_device *rdev)
185862306a36Sopenharmony_ci{
185962306a36Sopenharmony_ci	int ret;
186062306a36Sopenharmony_ci	u32 enable_mask, i;
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	ret = kv_dpm_get_enable_mask(rdev, &enable_mask);
186362306a36Sopenharmony_ci	if (ret)
186462306a36Sopenharmony_ci		return ret;
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci	for (i = 0; i < SMU7_MAX_LEVELS_GRAPHICS; i++) {
186762306a36Sopenharmony_ci		if (enable_mask & (1 << i))
186862306a36Sopenharmony_ci			break;
186962306a36Sopenharmony_ci	}
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci	if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS)
187262306a36Sopenharmony_ci		return kv_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_DPM_ForceState, i);
187362306a36Sopenharmony_ci	else
187462306a36Sopenharmony_ci		return kv_set_enabled_level(rdev, i);
187562306a36Sopenharmony_ci}
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_cistatic u8 kv_get_sleep_divider_id_from_clock(struct radeon_device *rdev,
187862306a36Sopenharmony_ci					     u32 sclk, u32 min_sclk_in_sr)
187962306a36Sopenharmony_ci{
188062306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
188162306a36Sopenharmony_ci	u32 i;
188262306a36Sopenharmony_ci	u32 temp;
188362306a36Sopenharmony_ci	u32 min = (min_sclk_in_sr > KV_MINIMUM_ENGINE_CLOCK) ?
188462306a36Sopenharmony_ci		min_sclk_in_sr : KV_MINIMUM_ENGINE_CLOCK;
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci	if (sclk < min)
188762306a36Sopenharmony_ci		return 0;
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci	if (!pi->caps_sclk_ds)
189062306a36Sopenharmony_ci		return 0;
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci	for (i = KV_MAX_DEEPSLEEP_DIVIDER_ID; i > 0; i--) {
189362306a36Sopenharmony_ci		temp = sclk / sumo_get_sleep_divider_from_id(i);
189462306a36Sopenharmony_ci		if (temp >= min)
189562306a36Sopenharmony_ci			break;
189662306a36Sopenharmony_ci	}
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci	return (u8)i;
189962306a36Sopenharmony_ci}
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_cistatic int kv_get_high_voltage_limit(struct radeon_device *rdev, int *limit)
190262306a36Sopenharmony_ci{
190362306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
190462306a36Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *table =
190562306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
190662306a36Sopenharmony_ci	int i;
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_ci	if (table && table->count) {
190962306a36Sopenharmony_ci		for (i = table->count - 1; i >= 0; i--) {
191062306a36Sopenharmony_ci			if (pi->high_voltage_t &&
191162306a36Sopenharmony_ci			    (kv_convert_8bit_index_to_voltage(rdev, table->entries[i].v) <=
191262306a36Sopenharmony_ci			     pi->high_voltage_t)) {
191362306a36Sopenharmony_ci				*limit = i;
191462306a36Sopenharmony_ci				return 0;
191562306a36Sopenharmony_ci			}
191662306a36Sopenharmony_ci		}
191762306a36Sopenharmony_ci	} else {
191862306a36Sopenharmony_ci		struct sumo_sclk_voltage_mapping_table *table =
191962306a36Sopenharmony_ci			&pi->sys_info.sclk_voltage_mapping_table;
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci		for (i = table->num_max_dpm_entries - 1; i >= 0; i--) {
192262306a36Sopenharmony_ci			if (pi->high_voltage_t &&
192362306a36Sopenharmony_ci			    (kv_convert_2bit_index_to_voltage(rdev, table->entries[i].vid_2bit) <=
192462306a36Sopenharmony_ci			     pi->high_voltage_t)) {
192562306a36Sopenharmony_ci				*limit = i;
192662306a36Sopenharmony_ci				return 0;
192762306a36Sopenharmony_ci			}
192862306a36Sopenharmony_ci		}
192962306a36Sopenharmony_ci	}
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_ci	*limit = 0;
193262306a36Sopenharmony_ci	return 0;
193362306a36Sopenharmony_ci}
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_cistatic void kv_apply_state_adjust_rules(struct radeon_device *rdev,
193662306a36Sopenharmony_ci					struct radeon_ps *new_rps,
193762306a36Sopenharmony_ci					struct radeon_ps *old_rps)
193862306a36Sopenharmony_ci{
193962306a36Sopenharmony_ci	struct kv_ps *ps = kv_get_ps(new_rps);
194062306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
194162306a36Sopenharmony_ci	u32 min_sclk = 10000; /* ??? */
194262306a36Sopenharmony_ci	u32 sclk, mclk = 0;
194362306a36Sopenharmony_ci	int i, limit;
194462306a36Sopenharmony_ci	bool force_high;
194562306a36Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *table =
194662306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
194762306a36Sopenharmony_ci	u32 stable_p_state_sclk = 0;
194862306a36Sopenharmony_ci	struct radeon_clock_and_voltage_limits *max_limits =
194962306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ci	if (new_rps->vce_active) {
195262306a36Sopenharmony_ci		new_rps->evclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].evclk;
195362306a36Sopenharmony_ci		new_rps->ecclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].ecclk;
195462306a36Sopenharmony_ci	} else {
195562306a36Sopenharmony_ci		new_rps->evclk = 0;
195662306a36Sopenharmony_ci		new_rps->ecclk = 0;
195762306a36Sopenharmony_ci	}
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci	mclk = max_limits->mclk;
196062306a36Sopenharmony_ci	sclk = min_sclk;
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_ci	if (pi->caps_stable_p_state) {
196362306a36Sopenharmony_ci		stable_p_state_sclk = (max_limits->sclk * 75) / 100;
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci		for (i = table->count - 1; i >= 0; i--) {
196662306a36Sopenharmony_ci			if (stable_p_state_sclk >= table->entries[i].clk) {
196762306a36Sopenharmony_ci				stable_p_state_sclk = table->entries[i].clk;
196862306a36Sopenharmony_ci				break;
196962306a36Sopenharmony_ci			}
197062306a36Sopenharmony_ci		}
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci		if (i > 0)
197362306a36Sopenharmony_ci			stable_p_state_sclk = table->entries[0].clk;
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ci		sclk = stable_p_state_sclk;
197662306a36Sopenharmony_ci	}
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci	if (new_rps->vce_active) {
197962306a36Sopenharmony_ci		if (sclk < rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk)
198062306a36Sopenharmony_ci			sclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk;
198162306a36Sopenharmony_ci	}
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci	ps->need_dfs_bypass = true;
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci	for (i = 0; i < ps->num_levels; i++) {
198662306a36Sopenharmony_ci		if (ps->levels[i].sclk < sclk)
198762306a36Sopenharmony_ci			ps->levels[i].sclk = sclk;
198862306a36Sopenharmony_ci	}
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci	if (table && table->count) {
199162306a36Sopenharmony_ci		for (i = 0; i < ps->num_levels; i++) {
199262306a36Sopenharmony_ci			if (pi->high_voltage_t &&
199362306a36Sopenharmony_ci			    (pi->high_voltage_t <
199462306a36Sopenharmony_ci			     kv_convert_8bit_index_to_voltage(rdev, ps->levels[i].vddc_index))) {
199562306a36Sopenharmony_ci				kv_get_high_voltage_limit(rdev, &limit);
199662306a36Sopenharmony_ci				ps->levels[i].sclk = table->entries[limit].clk;
199762306a36Sopenharmony_ci			}
199862306a36Sopenharmony_ci		}
199962306a36Sopenharmony_ci	} else {
200062306a36Sopenharmony_ci		struct sumo_sclk_voltage_mapping_table *table =
200162306a36Sopenharmony_ci			&pi->sys_info.sclk_voltage_mapping_table;
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_ci		for (i = 0; i < ps->num_levels; i++) {
200462306a36Sopenharmony_ci			if (pi->high_voltage_t &&
200562306a36Sopenharmony_ci			    (pi->high_voltage_t <
200662306a36Sopenharmony_ci			     kv_convert_8bit_index_to_voltage(rdev, ps->levels[i].vddc_index))) {
200762306a36Sopenharmony_ci				kv_get_high_voltage_limit(rdev, &limit);
200862306a36Sopenharmony_ci				ps->levels[i].sclk = table->entries[limit].sclk_frequency;
200962306a36Sopenharmony_ci			}
201062306a36Sopenharmony_ci		}
201162306a36Sopenharmony_ci	}
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_ci	if (pi->caps_stable_p_state) {
201462306a36Sopenharmony_ci		for (i = 0; i < ps->num_levels; i++) {
201562306a36Sopenharmony_ci			ps->levels[i].sclk = stable_p_state_sclk;
201662306a36Sopenharmony_ci		}
201762306a36Sopenharmony_ci	}
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci	pi->video_start = new_rps->dclk || new_rps->vclk ||
202062306a36Sopenharmony_ci		new_rps->evclk || new_rps->ecclk;
202162306a36Sopenharmony_ci
202262306a36Sopenharmony_ci	if ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) ==
202362306a36Sopenharmony_ci	    ATOM_PPLIB_CLASSIFICATION_UI_BATTERY)
202462306a36Sopenharmony_ci		pi->battery_state = true;
202562306a36Sopenharmony_ci	else
202662306a36Sopenharmony_ci		pi->battery_state = false;
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) {
202962306a36Sopenharmony_ci		ps->dpm0_pg_nb_ps_lo = 0x1;
203062306a36Sopenharmony_ci		ps->dpm0_pg_nb_ps_hi = 0x0;
203162306a36Sopenharmony_ci		ps->dpmx_nb_ps_lo = 0x1;
203262306a36Sopenharmony_ci		ps->dpmx_nb_ps_hi = 0x0;
203362306a36Sopenharmony_ci	} else {
203462306a36Sopenharmony_ci		ps->dpm0_pg_nb_ps_lo = 0x3;
203562306a36Sopenharmony_ci		ps->dpm0_pg_nb_ps_hi = 0x0;
203662306a36Sopenharmony_ci		ps->dpmx_nb_ps_lo = 0x3;
203762306a36Sopenharmony_ci		ps->dpmx_nb_ps_hi = 0x0;
203862306a36Sopenharmony_ci
203962306a36Sopenharmony_ci		if (pi->sys_info.nb_dpm_enable) {
204062306a36Sopenharmony_ci			force_high = (mclk >= pi->sys_info.nbp_memory_clock[3]) ||
204162306a36Sopenharmony_ci				pi->video_start || (rdev->pm.dpm.new_active_crtc_count >= 3) ||
204262306a36Sopenharmony_ci				pi->disable_nb_ps3_in_battery;
204362306a36Sopenharmony_ci			ps->dpm0_pg_nb_ps_lo = force_high ? 0x2 : 0x3;
204462306a36Sopenharmony_ci			ps->dpm0_pg_nb_ps_hi = 0x2;
204562306a36Sopenharmony_ci			ps->dpmx_nb_ps_lo = force_high ? 0x2 : 0x3;
204662306a36Sopenharmony_ci			ps->dpmx_nb_ps_hi = 0x2;
204762306a36Sopenharmony_ci		}
204862306a36Sopenharmony_ci	}
204962306a36Sopenharmony_ci}
205062306a36Sopenharmony_ci
205162306a36Sopenharmony_cistatic void kv_dpm_power_level_enabled_for_throttle(struct radeon_device *rdev,
205262306a36Sopenharmony_ci						    u32 index, bool enable)
205362306a36Sopenharmony_ci{
205462306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	pi->graphics_level[index].EnabledForThrottle = enable ? 1 : 0;
205762306a36Sopenharmony_ci}
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_cistatic int kv_calculate_ds_divider(struct radeon_device *rdev)
206062306a36Sopenharmony_ci{
206162306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
206262306a36Sopenharmony_ci	u32 sclk_in_sr = 10000; /* ??? */
206362306a36Sopenharmony_ci	u32 i;
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ci	if (pi->lowest_valid > pi->highest_valid)
206662306a36Sopenharmony_ci		return -EINVAL;
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ci	for (i = pi->lowest_valid; i <= pi->highest_valid; i++) {
206962306a36Sopenharmony_ci		pi->graphics_level[i].DeepSleepDivId =
207062306a36Sopenharmony_ci			kv_get_sleep_divider_id_from_clock(rdev,
207162306a36Sopenharmony_ci							   be32_to_cpu(pi->graphics_level[i].SclkFrequency),
207262306a36Sopenharmony_ci							   sclk_in_sr);
207362306a36Sopenharmony_ci	}
207462306a36Sopenharmony_ci	return 0;
207562306a36Sopenharmony_ci}
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_cistatic int kv_calculate_nbps_level_settings(struct radeon_device *rdev)
207862306a36Sopenharmony_ci{
207962306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
208062306a36Sopenharmony_ci	u32 i;
208162306a36Sopenharmony_ci	bool force_high;
208262306a36Sopenharmony_ci	struct radeon_clock_and_voltage_limits *max_limits =
208362306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
208462306a36Sopenharmony_ci	u32 mclk = max_limits->mclk;
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci	if (pi->lowest_valid > pi->highest_valid)
208762306a36Sopenharmony_ci		return -EINVAL;
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_ci	if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) {
209062306a36Sopenharmony_ci		for (i = pi->lowest_valid; i <= pi->highest_valid; i++) {
209162306a36Sopenharmony_ci			pi->graphics_level[i].GnbSlow = 1;
209262306a36Sopenharmony_ci			pi->graphics_level[i].ForceNbPs1 = 0;
209362306a36Sopenharmony_ci			pi->graphics_level[i].UpH = 0;
209462306a36Sopenharmony_ci		}
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_ci		if (!pi->sys_info.nb_dpm_enable)
209762306a36Sopenharmony_ci			return 0;
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_ci		force_high = ((mclk >= pi->sys_info.nbp_memory_clock[3]) ||
210062306a36Sopenharmony_ci			      (rdev->pm.dpm.new_active_crtc_count >= 3) || pi->video_start);
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci		if (force_high) {
210362306a36Sopenharmony_ci			for (i = pi->lowest_valid; i <= pi->highest_valid; i++)
210462306a36Sopenharmony_ci				pi->graphics_level[i].GnbSlow = 0;
210562306a36Sopenharmony_ci		} else {
210662306a36Sopenharmony_ci			if (pi->battery_state)
210762306a36Sopenharmony_ci				pi->graphics_level[0].ForceNbPs1 = 1;
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_ci			pi->graphics_level[1].GnbSlow = 0;
211062306a36Sopenharmony_ci			pi->graphics_level[2].GnbSlow = 0;
211162306a36Sopenharmony_ci			pi->graphics_level[3].GnbSlow = 0;
211262306a36Sopenharmony_ci			pi->graphics_level[4].GnbSlow = 0;
211362306a36Sopenharmony_ci		}
211462306a36Sopenharmony_ci	} else {
211562306a36Sopenharmony_ci		for (i = pi->lowest_valid; i <= pi->highest_valid; i++) {
211662306a36Sopenharmony_ci			pi->graphics_level[i].GnbSlow = 1;
211762306a36Sopenharmony_ci			pi->graphics_level[i].ForceNbPs1 = 0;
211862306a36Sopenharmony_ci			pi->graphics_level[i].UpH = 0;
211962306a36Sopenharmony_ci		}
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci		if (pi->sys_info.nb_dpm_enable && pi->battery_state) {
212262306a36Sopenharmony_ci			pi->graphics_level[pi->lowest_valid].UpH = 0x28;
212362306a36Sopenharmony_ci			pi->graphics_level[pi->lowest_valid].GnbSlow = 0;
212462306a36Sopenharmony_ci			if (pi->lowest_valid != pi->highest_valid)
212562306a36Sopenharmony_ci				pi->graphics_level[pi->lowest_valid].ForceNbPs1 = 1;
212662306a36Sopenharmony_ci		}
212762306a36Sopenharmony_ci	}
212862306a36Sopenharmony_ci	return 0;
212962306a36Sopenharmony_ci}
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_cistatic int kv_calculate_dpm_settings(struct radeon_device *rdev)
213262306a36Sopenharmony_ci{
213362306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
213462306a36Sopenharmony_ci	u32 i;
213562306a36Sopenharmony_ci
213662306a36Sopenharmony_ci	if (pi->lowest_valid > pi->highest_valid)
213762306a36Sopenharmony_ci		return -EINVAL;
213862306a36Sopenharmony_ci
213962306a36Sopenharmony_ci	for (i = pi->lowest_valid; i <= pi->highest_valid; i++)
214062306a36Sopenharmony_ci		pi->graphics_level[i].DisplayWatermark = (i == pi->highest_valid) ? 1 : 0;
214162306a36Sopenharmony_ci
214262306a36Sopenharmony_ci	return 0;
214362306a36Sopenharmony_ci}
214462306a36Sopenharmony_ci
214562306a36Sopenharmony_cistatic void kv_init_graphics_levels(struct radeon_device *rdev)
214662306a36Sopenharmony_ci{
214762306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
214862306a36Sopenharmony_ci	u32 i;
214962306a36Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *table =
215062306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
215162306a36Sopenharmony_ci
215262306a36Sopenharmony_ci	if (table && table->count) {
215362306a36Sopenharmony_ci		u32 vid_2bit;
215462306a36Sopenharmony_ci
215562306a36Sopenharmony_ci		pi->graphics_dpm_level_count = 0;
215662306a36Sopenharmony_ci		for (i = 0; i < table->count; i++) {
215762306a36Sopenharmony_ci			if (pi->high_voltage_t &&
215862306a36Sopenharmony_ci			    (pi->high_voltage_t <
215962306a36Sopenharmony_ci			     kv_convert_8bit_index_to_voltage(rdev, table->entries[i].v)))
216062306a36Sopenharmony_ci				break;
216162306a36Sopenharmony_ci
216262306a36Sopenharmony_ci			kv_set_divider_value(rdev, i, table->entries[i].clk);
216362306a36Sopenharmony_ci			vid_2bit = kv_convert_vid7_to_vid2(rdev,
216462306a36Sopenharmony_ci							   &pi->sys_info.vid_mapping_table,
216562306a36Sopenharmony_ci							   table->entries[i].v);
216662306a36Sopenharmony_ci			kv_set_vid(rdev, i, vid_2bit);
216762306a36Sopenharmony_ci			kv_set_at(rdev, i, pi->at[i]);
216862306a36Sopenharmony_ci			kv_dpm_power_level_enabled_for_throttle(rdev, i, true);
216962306a36Sopenharmony_ci			pi->graphics_dpm_level_count++;
217062306a36Sopenharmony_ci		}
217162306a36Sopenharmony_ci	} else {
217262306a36Sopenharmony_ci		struct sumo_sclk_voltage_mapping_table *table =
217362306a36Sopenharmony_ci			&pi->sys_info.sclk_voltage_mapping_table;
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ci		pi->graphics_dpm_level_count = 0;
217662306a36Sopenharmony_ci		for (i = 0; i < table->num_max_dpm_entries; i++) {
217762306a36Sopenharmony_ci			if (pi->high_voltage_t &&
217862306a36Sopenharmony_ci			    pi->high_voltage_t <
217962306a36Sopenharmony_ci			    kv_convert_2bit_index_to_voltage(rdev, table->entries[i].vid_2bit))
218062306a36Sopenharmony_ci				break;
218162306a36Sopenharmony_ci
218262306a36Sopenharmony_ci			kv_set_divider_value(rdev, i, table->entries[i].sclk_frequency);
218362306a36Sopenharmony_ci			kv_set_vid(rdev, i, table->entries[i].vid_2bit);
218462306a36Sopenharmony_ci			kv_set_at(rdev, i, pi->at[i]);
218562306a36Sopenharmony_ci			kv_dpm_power_level_enabled_for_throttle(rdev, i, true);
218662306a36Sopenharmony_ci			pi->graphics_dpm_level_count++;
218762306a36Sopenharmony_ci		}
218862306a36Sopenharmony_ci	}
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci	for (i = 0; i < SMU7_MAX_LEVELS_GRAPHICS; i++)
219162306a36Sopenharmony_ci		kv_dpm_power_level_enable(rdev, i, false);
219262306a36Sopenharmony_ci}
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_cistatic void kv_enable_new_levels(struct radeon_device *rdev)
219562306a36Sopenharmony_ci{
219662306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
219762306a36Sopenharmony_ci	u32 i;
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci	for (i = 0; i < SMU7_MAX_LEVELS_GRAPHICS; i++) {
220062306a36Sopenharmony_ci		if (i >= pi->lowest_valid && i <= pi->highest_valid)
220162306a36Sopenharmony_ci			kv_dpm_power_level_enable(rdev, i, true);
220262306a36Sopenharmony_ci	}
220362306a36Sopenharmony_ci}
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_cistatic int kv_set_enabled_level(struct radeon_device *rdev, u32 level)
220662306a36Sopenharmony_ci{
220762306a36Sopenharmony_ci	u32 new_mask = (1 << level);
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	return kv_send_msg_to_smc_with_parameter(rdev,
221062306a36Sopenharmony_ci						 PPSMC_MSG_SCLKDPM_SetEnabledMask,
221162306a36Sopenharmony_ci						 new_mask);
221262306a36Sopenharmony_ci}
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_cistatic int kv_set_enabled_levels(struct radeon_device *rdev)
221562306a36Sopenharmony_ci{
221662306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
221762306a36Sopenharmony_ci	u32 i, new_mask = 0;
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	for (i = pi->lowest_valid; i <= pi->highest_valid; i++)
222062306a36Sopenharmony_ci		new_mask |= (1 << i);
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci	return kv_send_msg_to_smc_with_parameter(rdev,
222362306a36Sopenharmony_ci						 PPSMC_MSG_SCLKDPM_SetEnabledMask,
222462306a36Sopenharmony_ci						 new_mask);
222562306a36Sopenharmony_ci}
222662306a36Sopenharmony_ci
222762306a36Sopenharmony_cistatic void kv_program_nbps_index_settings(struct radeon_device *rdev,
222862306a36Sopenharmony_ci					   struct radeon_ps *new_rps)
222962306a36Sopenharmony_ci{
223062306a36Sopenharmony_ci	struct kv_ps *new_ps = kv_get_ps(new_rps);
223162306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
223262306a36Sopenharmony_ci	u32 nbdpmconfig1;
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci	if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS)
223562306a36Sopenharmony_ci		return;
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci	if (pi->sys_info.nb_dpm_enable) {
223862306a36Sopenharmony_ci		nbdpmconfig1 = RREG32_SMC(NB_DPM_CONFIG_1);
223962306a36Sopenharmony_ci		nbdpmconfig1 &= ~(Dpm0PgNbPsLo_MASK | Dpm0PgNbPsHi_MASK |
224062306a36Sopenharmony_ci				  DpmXNbPsLo_MASK | DpmXNbPsHi_MASK);
224162306a36Sopenharmony_ci		nbdpmconfig1 |= (Dpm0PgNbPsLo(new_ps->dpm0_pg_nb_ps_lo) |
224262306a36Sopenharmony_ci				 Dpm0PgNbPsHi(new_ps->dpm0_pg_nb_ps_hi) |
224362306a36Sopenharmony_ci				 DpmXNbPsLo(new_ps->dpmx_nb_ps_lo) |
224462306a36Sopenharmony_ci				 DpmXNbPsHi(new_ps->dpmx_nb_ps_hi));
224562306a36Sopenharmony_ci		WREG32_SMC(NB_DPM_CONFIG_1, nbdpmconfig1);
224662306a36Sopenharmony_ci	}
224762306a36Sopenharmony_ci}
224862306a36Sopenharmony_ci
224962306a36Sopenharmony_cistatic int kv_set_thermal_temperature_range(struct radeon_device *rdev,
225062306a36Sopenharmony_ci					    int min_temp, int max_temp)
225162306a36Sopenharmony_ci{
225262306a36Sopenharmony_ci	int low_temp = 0 * 1000;
225362306a36Sopenharmony_ci	int high_temp = 255 * 1000;
225462306a36Sopenharmony_ci	u32 tmp;
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci	if (low_temp < min_temp)
225762306a36Sopenharmony_ci		low_temp = min_temp;
225862306a36Sopenharmony_ci	if (high_temp > max_temp)
225962306a36Sopenharmony_ci		high_temp = max_temp;
226062306a36Sopenharmony_ci	if (high_temp < low_temp) {
226162306a36Sopenharmony_ci		DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp);
226262306a36Sopenharmony_ci		return -EINVAL;
226362306a36Sopenharmony_ci	}
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci	tmp = RREG32_SMC(CG_THERMAL_INT_CTRL);
226662306a36Sopenharmony_ci	tmp &= ~(DIG_THERM_INTH_MASK | DIG_THERM_INTL_MASK);
226762306a36Sopenharmony_ci	tmp |= (DIG_THERM_INTH(49 + (high_temp / 1000)) |
226862306a36Sopenharmony_ci		DIG_THERM_INTL(49 + (low_temp / 1000)));
226962306a36Sopenharmony_ci	WREG32_SMC(CG_THERMAL_INT_CTRL, tmp);
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ci	rdev->pm.dpm.thermal.min_temp = low_temp;
227262306a36Sopenharmony_ci	rdev->pm.dpm.thermal.max_temp = high_temp;
227362306a36Sopenharmony_ci
227462306a36Sopenharmony_ci	return 0;
227562306a36Sopenharmony_ci}
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ciunion igp_info {
227862306a36Sopenharmony_ci	struct _ATOM_INTEGRATED_SYSTEM_INFO info;
227962306a36Sopenharmony_ci	struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
228062306a36Sopenharmony_ci	struct _ATOM_INTEGRATED_SYSTEM_INFO_V5 info_5;
228162306a36Sopenharmony_ci	struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6;
228262306a36Sopenharmony_ci	struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;
228362306a36Sopenharmony_ci	struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 info_8;
228462306a36Sopenharmony_ci};
228562306a36Sopenharmony_ci
228662306a36Sopenharmony_cistatic int kv_parse_sys_info_table(struct radeon_device *rdev)
228762306a36Sopenharmony_ci{
228862306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
228962306a36Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
229062306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
229162306a36Sopenharmony_ci	union igp_info *igp_info;
229262306a36Sopenharmony_ci	u8 frev, crev;
229362306a36Sopenharmony_ci	u16 data_offset;
229462306a36Sopenharmony_ci	int i;
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_ci	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
229762306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
229862306a36Sopenharmony_ci		igp_info = (union igp_info *)(mode_info->atom_context->bios +
229962306a36Sopenharmony_ci					      data_offset);
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci		if (crev != 8) {
230262306a36Sopenharmony_ci			DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
230362306a36Sopenharmony_ci			return -EINVAL;
230462306a36Sopenharmony_ci		}
230562306a36Sopenharmony_ci		pi->sys_info.bootup_sclk = le32_to_cpu(igp_info->info_8.ulBootUpEngineClock);
230662306a36Sopenharmony_ci		pi->sys_info.bootup_uma_clk = le32_to_cpu(igp_info->info_8.ulBootUpUMAClock);
230762306a36Sopenharmony_ci		pi->sys_info.bootup_nb_voltage_index =
230862306a36Sopenharmony_ci			le16_to_cpu(igp_info->info_8.usBootUpNBVoltage);
230962306a36Sopenharmony_ci		if (igp_info->info_8.ucHtcTmpLmt == 0)
231062306a36Sopenharmony_ci			pi->sys_info.htc_tmp_lmt = 203;
231162306a36Sopenharmony_ci		else
231262306a36Sopenharmony_ci			pi->sys_info.htc_tmp_lmt = igp_info->info_8.ucHtcTmpLmt;
231362306a36Sopenharmony_ci		if (igp_info->info_8.ucHtcHystLmt == 0)
231462306a36Sopenharmony_ci			pi->sys_info.htc_hyst_lmt = 5;
231562306a36Sopenharmony_ci		else
231662306a36Sopenharmony_ci			pi->sys_info.htc_hyst_lmt = igp_info->info_8.ucHtcHystLmt;
231762306a36Sopenharmony_ci		if (pi->sys_info.htc_tmp_lmt <= pi->sys_info.htc_hyst_lmt) {
231862306a36Sopenharmony_ci			DRM_ERROR("The htcTmpLmt should be larger than htcHystLmt.\n");
231962306a36Sopenharmony_ci		}
232062306a36Sopenharmony_ci
232162306a36Sopenharmony_ci		if (le32_to_cpu(igp_info->info_8.ulSystemConfig) & (1 << 3))
232262306a36Sopenharmony_ci			pi->sys_info.nb_dpm_enable = true;
232362306a36Sopenharmony_ci		else
232462306a36Sopenharmony_ci			pi->sys_info.nb_dpm_enable = false;
232562306a36Sopenharmony_ci
232662306a36Sopenharmony_ci		for (i = 0; i < KV_NUM_NBPSTATES; i++) {
232762306a36Sopenharmony_ci			pi->sys_info.nbp_memory_clock[i] =
232862306a36Sopenharmony_ci				le32_to_cpu(igp_info->info_8.ulNbpStateMemclkFreq[i]);
232962306a36Sopenharmony_ci			pi->sys_info.nbp_n_clock[i] =
233062306a36Sopenharmony_ci				le32_to_cpu(igp_info->info_8.ulNbpStateNClkFreq[i]);
233162306a36Sopenharmony_ci		}
233262306a36Sopenharmony_ci		if (le32_to_cpu(igp_info->info_8.ulGPUCapInfo) &
233362306a36Sopenharmony_ci		    SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS)
233462306a36Sopenharmony_ci			pi->caps_enable_dfs_bypass = true;
233562306a36Sopenharmony_ci
233662306a36Sopenharmony_ci		sumo_construct_sclk_voltage_mapping_table(rdev,
233762306a36Sopenharmony_ci							  &pi->sys_info.sclk_voltage_mapping_table,
233862306a36Sopenharmony_ci							  igp_info->info_8.sAvail_SCLK);
233962306a36Sopenharmony_ci
234062306a36Sopenharmony_ci		sumo_construct_vid_mapping_table(rdev,
234162306a36Sopenharmony_ci						 &pi->sys_info.vid_mapping_table,
234262306a36Sopenharmony_ci						 igp_info->info_8.sAvail_SCLK);
234362306a36Sopenharmony_ci
234462306a36Sopenharmony_ci		kv_construct_max_power_limits_table(rdev,
234562306a36Sopenharmony_ci						    &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac);
234662306a36Sopenharmony_ci	}
234762306a36Sopenharmony_ci	return 0;
234862306a36Sopenharmony_ci}
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_ciunion power_info {
235162306a36Sopenharmony_ci	struct _ATOM_POWERPLAY_INFO info;
235262306a36Sopenharmony_ci	struct _ATOM_POWERPLAY_INFO_V2 info_2;
235362306a36Sopenharmony_ci	struct _ATOM_POWERPLAY_INFO_V3 info_3;
235462306a36Sopenharmony_ci	struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
235562306a36Sopenharmony_ci	struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
235662306a36Sopenharmony_ci	struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
235762306a36Sopenharmony_ci};
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ciunion pplib_clock_info {
236062306a36Sopenharmony_ci	struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
236162306a36Sopenharmony_ci	struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
236262306a36Sopenharmony_ci	struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
236362306a36Sopenharmony_ci	struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
236462306a36Sopenharmony_ci};
236562306a36Sopenharmony_ci
236662306a36Sopenharmony_ciunion pplib_power_state {
236762306a36Sopenharmony_ci	struct _ATOM_PPLIB_STATE v1;
236862306a36Sopenharmony_ci	struct _ATOM_PPLIB_STATE_V2 v2;
236962306a36Sopenharmony_ci};
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_cistatic void kv_patch_boot_state(struct radeon_device *rdev,
237262306a36Sopenharmony_ci				struct kv_ps *ps)
237362306a36Sopenharmony_ci{
237462306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
237562306a36Sopenharmony_ci
237662306a36Sopenharmony_ci	ps->num_levels = 1;
237762306a36Sopenharmony_ci	ps->levels[0] = pi->boot_pl;
237862306a36Sopenharmony_ci}
237962306a36Sopenharmony_ci
238062306a36Sopenharmony_cistatic void kv_parse_pplib_non_clock_info(struct radeon_device *rdev,
238162306a36Sopenharmony_ci					  struct radeon_ps *rps,
238262306a36Sopenharmony_ci					  struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
238362306a36Sopenharmony_ci					  u8 table_rev)
238462306a36Sopenharmony_ci{
238562306a36Sopenharmony_ci	struct kv_ps *ps = kv_get_ps(rps);
238662306a36Sopenharmony_ci
238762306a36Sopenharmony_ci	rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
238862306a36Sopenharmony_ci	rps->class = le16_to_cpu(non_clock_info->usClassification);
238962306a36Sopenharmony_ci	rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
239062306a36Sopenharmony_ci
239162306a36Sopenharmony_ci	if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
239262306a36Sopenharmony_ci		rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
239362306a36Sopenharmony_ci		rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
239462306a36Sopenharmony_ci	} else {
239562306a36Sopenharmony_ci		rps->vclk = 0;
239662306a36Sopenharmony_ci		rps->dclk = 0;
239762306a36Sopenharmony_ci	}
239862306a36Sopenharmony_ci
239962306a36Sopenharmony_ci	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
240062306a36Sopenharmony_ci		rdev->pm.dpm.boot_ps = rps;
240162306a36Sopenharmony_ci		kv_patch_boot_state(rdev, ps);
240262306a36Sopenharmony_ci	}
240362306a36Sopenharmony_ci	if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
240462306a36Sopenharmony_ci		rdev->pm.dpm.uvd_ps = rps;
240562306a36Sopenharmony_ci}
240662306a36Sopenharmony_ci
240762306a36Sopenharmony_cistatic void kv_parse_pplib_clock_info(struct radeon_device *rdev,
240862306a36Sopenharmony_ci				      struct radeon_ps *rps, int index,
240962306a36Sopenharmony_ci					union pplib_clock_info *clock_info)
241062306a36Sopenharmony_ci{
241162306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
241262306a36Sopenharmony_ci	struct kv_ps *ps = kv_get_ps(rps);
241362306a36Sopenharmony_ci	struct kv_pl *pl = &ps->levels[index];
241462306a36Sopenharmony_ci	u32 sclk;
241562306a36Sopenharmony_ci
241662306a36Sopenharmony_ci	sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow);
241762306a36Sopenharmony_ci	sclk |= clock_info->sumo.ucEngineClockHigh << 16;
241862306a36Sopenharmony_ci	pl->sclk = sclk;
241962306a36Sopenharmony_ci	pl->vddc_index = clock_info->sumo.vddcIndex;
242062306a36Sopenharmony_ci
242162306a36Sopenharmony_ci	ps->num_levels = index + 1;
242262306a36Sopenharmony_ci
242362306a36Sopenharmony_ci	if (pi->caps_sclk_ds) {
242462306a36Sopenharmony_ci		pl->ds_divider_index = 5;
242562306a36Sopenharmony_ci		pl->ss_divider_index = 5;
242662306a36Sopenharmony_ci	}
242762306a36Sopenharmony_ci}
242862306a36Sopenharmony_ci
242962306a36Sopenharmony_cistatic int kv_parse_power_table(struct radeon_device *rdev)
243062306a36Sopenharmony_ci{
243162306a36Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
243262306a36Sopenharmony_ci	struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
243362306a36Sopenharmony_ci	union pplib_power_state *power_state;
243462306a36Sopenharmony_ci	int i, j, k, non_clock_array_index, clock_array_index;
243562306a36Sopenharmony_ci	union pplib_clock_info *clock_info;
243662306a36Sopenharmony_ci	struct _StateArray *state_array;
243762306a36Sopenharmony_ci	struct _ClockInfoArray *clock_info_array;
243862306a36Sopenharmony_ci	struct _NonClockInfoArray *non_clock_info_array;
243962306a36Sopenharmony_ci	union power_info *power_info;
244062306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
244162306a36Sopenharmony_ci	u16 data_offset;
244262306a36Sopenharmony_ci	u8 frev, crev;
244362306a36Sopenharmony_ci	u8 *power_state_offset;
244462306a36Sopenharmony_ci	struct kv_ps *ps;
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_ci	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
244762306a36Sopenharmony_ci				   &frev, &crev, &data_offset))
244862306a36Sopenharmony_ci		return -EINVAL;
244962306a36Sopenharmony_ci	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_ci	state_array = (struct _StateArray *)
245262306a36Sopenharmony_ci		(mode_info->atom_context->bios + data_offset +
245362306a36Sopenharmony_ci		 le16_to_cpu(power_info->pplib.usStateArrayOffset));
245462306a36Sopenharmony_ci	clock_info_array = (struct _ClockInfoArray *)
245562306a36Sopenharmony_ci		(mode_info->atom_context->bios + data_offset +
245662306a36Sopenharmony_ci		 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset));
245762306a36Sopenharmony_ci	non_clock_info_array = (struct _NonClockInfoArray *)
245862306a36Sopenharmony_ci		(mode_info->atom_context->bios + data_offset +
245962306a36Sopenharmony_ci		 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ci	rdev->pm.dpm.ps = kcalloc(state_array->ucNumEntries,
246262306a36Sopenharmony_ci				  sizeof(struct radeon_ps),
246362306a36Sopenharmony_ci				  GFP_KERNEL);
246462306a36Sopenharmony_ci	if (!rdev->pm.dpm.ps)
246562306a36Sopenharmony_ci		return -ENOMEM;
246662306a36Sopenharmony_ci	power_state_offset = (u8 *)state_array->states;
246762306a36Sopenharmony_ci	for (i = 0; i < state_array->ucNumEntries; i++) {
246862306a36Sopenharmony_ci		u8 *idx;
246962306a36Sopenharmony_ci		power_state = (union pplib_power_state *)power_state_offset;
247062306a36Sopenharmony_ci		non_clock_array_index = power_state->v2.nonClockInfoIndex;
247162306a36Sopenharmony_ci		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
247262306a36Sopenharmony_ci			&non_clock_info_array->nonClockInfo[non_clock_array_index];
247362306a36Sopenharmony_ci		if (!rdev->pm.power_state[i].clock_info)
247462306a36Sopenharmony_ci			return -EINVAL;
247562306a36Sopenharmony_ci		ps = kzalloc(sizeof(struct kv_ps), GFP_KERNEL);
247662306a36Sopenharmony_ci		if (ps == NULL) {
247762306a36Sopenharmony_ci			kfree(rdev->pm.dpm.ps);
247862306a36Sopenharmony_ci			return -ENOMEM;
247962306a36Sopenharmony_ci		}
248062306a36Sopenharmony_ci		rdev->pm.dpm.ps[i].ps_priv = ps;
248162306a36Sopenharmony_ci		k = 0;
248262306a36Sopenharmony_ci		idx = (u8 *)&power_state->v2.clockInfoIndex[0];
248362306a36Sopenharmony_ci		for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) {
248462306a36Sopenharmony_ci			clock_array_index = idx[j];
248562306a36Sopenharmony_ci			if (clock_array_index >= clock_info_array->ucNumEntries)
248662306a36Sopenharmony_ci				continue;
248762306a36Sopenharmony_ci			if (k >= SUMO_MAX_HARDWARE_POWERLEVELS)
248862306a36Sopenharmony_ci				break;
248962306a36Sopenharmony_ci			clock_info = (union pplib_clock_info *)
249062306a36Sopenharmony_ci				((u8 *)&clock_info_array->clockInfo[0] +
249162306a36Sopenharmony_ci				 (clock_array_index * clock_info_array->ucEntrySize));
249262306a36Sopenharmony_ci			kv_parse_pplib_clock_info(rdev,
249362306a36Sopenharmony_ci						  &rdev->pm.dpm.ps[i], k,
249462306a36Sopenharmony_ci						  clock_info);
249562306a36Sopenharmony_ci			k++;
249662306a36Sopenharmony_ci		}
249762306a36Sopenharmony_ci		kv_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
249862306a36Sopenharmony_ci					      non_clock_info,
249962306a36Sopenharmony_ci					      non_clock_info_array->ucEntrySize);
250062306a36Sopenharmony_ci		power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
250162306a36Sopenharmony_ci	}
250262306a36Sopenharmony_ci	rdev->pm.dpm.num_ps = state_array->ucNumEntries;
250362306a36Sopenharmony_ci
250462306a36Sopenharmony_ci	/* fill in the vce power states */
250562306a36Sopenharmony_ci	for (i = 0; i < RADEON_MAX_VCE_LEVELS; i++) {
250662306a36Sopenharmony_ci		u32 sclk;
250762306a36Sopenharmony_ci		clock_array_index = rdev->pm.dpm.vce_states[i].clk_idx;
250862306a36Sopenharmony_ci		clock_info = (union pplib_clock_info *)
250962306a36Sopenharmony_ci			&clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
251062306a36Sopenharmony_ci		sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow);
251162306a36Sopenharmony_ci		sclk |= clock_info->sumo.ucEngineClockHigh << 16;
251262306a36Sopenharmony_ci		rdev->pm.dpm.vce_states[i].sclk = sclk;
251362306a36Sopenharmony_ci		rdev->pm.dpm.vce_states[i].mclk = 0;
251462306a36Sopenharmony_ci	}
251562306a36Sopenharmony_ci
251662306a36Sopenharmony_ci	return 0;
251762306a36Sopenharmony_ci}
251862306a36Sopenharmony_ci
251962306a36Sopenharmony_ciint kv_dpm_init(struct radeon_device *rdev)
252062306a36Sopenharmony_ci{
252162306a36Sopenharmony_ci	struct kv_power_info *pi;
252262306a36Sopenharmony_ci	int ret, i;
252362306a36Sopenharmony_ci
252462306a36Sopenharmony_ci	pi = kzalloc(sizeof(struct kv_power_info), GFP_KERNEL);
252562306a36Sopenharmony_ci	if (pi == NULL)
252662306a36Sopenharmony_ci		return -ENOMEM;
252762306a36Sopenharmony_ci	rdev->pm.dpm.priv = pi;
252862306a36Sopenharmony_ci
252962306a36Sopenharmony_ci	ret = r600_get_platform_caps(rdev);
253062306a36Sopenharmony_ci	if (ret)
253162306a36Sopenharmony_ci		return ret;
253262306a36Sopenharmony_ci
253362306a36Sopenharmony_ci	ret = r600_parse_extended_power_table(rdev);
253462306a36Sopenharmony_ci	if (ret)
253562306a36Sopenharmony_ci		return ret;
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_ci	for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++)
253862306a36Sopenharmony_ci		pi->at[i] = TRINITY_AT_DFLT;
253962306a36Sopenharmony_ci
254062306a36Sopenharmony_ci	pi->sram_end = SMC_RAM_END;
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_ci	/* Enabling nb dpm on an asrock system prevents dpm from working */
254362306a36Sopenharmony_ci	if (rdev->pdev->subsystem_vendor == 0x1849)
254462306a36Sopenharmony_ci		pi->enable_nb_dpm = false;
254562306a36Sopenharmony_ci	else
254662306a36Sopenharmony_ci		pi->enable_nb_dpm = true;
254762306a36Sopenharmony_ci
254862306a36Sopenharmony_ci	pi->caps_power_containment = true;
254962306a36Sopenharmony_ci	pi->caps_cac = true;
255062306a36Sopenharmony_ci	pi->enable_didt = false;
255162306a36Sopenharmony_ci	if (pi->enable_didt) {
255262306a36Sopenharmony_ci		pi->caps_sq_ramping = true;
255362306a36Sopenharmony_ci		pi->caps_db_ramping = true;
255462306a36Sopenharmony_ci		pi->caps_td_ramping = true;
255562306a36Sopenharmony_ci		pi->caps_tcp_ramping = true;
255662306a36Sopenharmony_ci	}
255762306a36Sopenharmony_ci
255862306a36Sopenharmony_ci	pi->caps_sclk_ds = true;
255962306a36Sopenharmony_ci	pi->enable_auto_thermal_throttling = true;
256062306a36Sopenharmony_ci	pi->disable_nb_ps3_in_battery = false;
256162306a36Sopenharmony_ci	if (radeon_bapm == -1) {
256262306a36Sopenharmony_ci		/* only enable bapm on KB, ML by default */
256362306a36Sopenharmony_ci		if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS)
256462306a36Sopenharmony_ci			pi->bapm_enable = true;
256562306a36Sopenharmony_ci		else
256662306a36Sopenharmony_ci			pi->bapm_enable = false;
256762306a36Sopenharmony_ci	} else if (radeon_bapm == 0) {
256862306a36Sopenharmony_ci		pi->bapm_enable = false;
256962306a36Sopenharmony_ci	} else {
257062306a36Sopenharmony_ci		pi->bapm_enable = true;
257162306a36Sopenharmony_ci	}
257262306a36Sopenharmony_ci	pi->voltage_drop_t = 0;
257362306a36Sopenharmony_ci	pi->caps_sclk_throttle_low_notification = false;
257462306a36Sopenharmony_ci	pi->caps_fps = false; /* true? */
257562306a36Sopenharmony_ci	pi->caps_uvd_pg = true;
257662306a36Sopenharmony_ci	pi->caps_uvd_dpm = true;
257762306a36Sopenharmony_ci	pi->caps_vce_pg = false; /* XXX true */
257862306a36Sopenharmony_ci	pi->caps_samu_pg = false;
257962306a36Sopenharmony_ci	pi->caps_acp_pg = false;
258062306a36Sopenharmony_ci	pi->caps_stable_p_state = false;
258162306a36Sopenharmony_ci
258262306a36Sopenharmony_ci	ret = kv_parse_sys_info_table(rdev);
258362306a36Sopenharmony_ci	if (ret)
258462306a36Sopenharmony_ci		return ret;
258562306a36Sopenharmony_ci
258662306a36Sopenharmony_ci	kv_patch_voltage_values(rdev);
258762306a36Sopenharmony_ci	kv_construct_boot_state(rdev);
258862306a36Sopenharmony_ci
258962306a36Sopenharmony_ci	ret = kv_parse_power_table(rdev);
259062306a36Sopenharmony_ci	if (ret)
259162306a36Sopenharmony_ci		return ret;
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_ci	pi->enable_dpm = true;
259462306a36Sopenharmony_ci
259562306a36Sopenharmony_ci	return 0;
259662306a36Sopenharmony_ci}
259762306a36Sopenharmony_ci
259862306a36Sopenharmony_civoid kv_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
259962306a36Sopenharmony_ci						    struct seq_file *m)
260062306a36Sopenharmony_ci{
260162306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
260262306a36Sopenharmony_ci	u32 current_index =
260362306a36Sopenharmony_ci		(RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_SCLK_INDEX_MASK) >>
260462306a36Sopenharmony_ci		CURR_SCLK_INDEX_SHIFT;
260562306a36Sopenharmony_ci	u32 sclk, tmp;
260662306a36Sopenharmony_ci	u16 vddc;
260762306a36Sopenharmony_ci
260862306a36Sopenharmony_ci	if (current_index >= SMU__NUM_SCLK_DPM_STATE) {
260962306a36Sopenharmony_ci		seq_printf(m, "invalid dpm profile %d\n", current_index);
261062306a36Sopenharmony_ci	} else {
261162306a36Sopenharmony_ci		sclk = be32_to_cpu(pi->graphics_level[current_index].SclkFrequency);
261262306a36Sopenharmony_ci		tmp = (RREG32_SMC(SMU_VOLTAGE_STATUS) & SMU_VOLTAGE_CURRENT_LEVEL_MASK) >>
261362306a36Sopenharmony_ci			SMU_VOLTAGE_CURRENT_LEVEL_SHIFT;
261462306a36Sopenharmony_ci		vddc = kv_convert_8bit_index_to_voltage(rdev, (u16)tmp);
261562306a36Sopenharmony_ci		seq_printf(m, "uvd    %sabled\n", pi->uvd_power_gated ? "dis" : "en");
261662306a36Sopenharmony_ci		seq_printf(m, "vce    %sabled\n", pi->vce_power_gated ? "dis" : "en");
261762306a36Sopenharmony_ci		seq_printf(m, "power level %d    sclk: %u vddc: %u\n",
261862306a36Sopenharmony_ci			   current_index, sclk, vddc);
261962306a36Sopenharmony_ci	}
262062306a36Sopenharmony_ci}
262162306a36Sopenharmony_ci
262262306a36Sopenharmony_ciu32 kv_dpm_get_current_sclk(struct radeon_device *rdev)
262362306a36Sopenharmony_ci{
262462306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
262562306a36Sopenharmony_ci	u32 current_index =
262662306a36Sopenharmony_ci		(RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_SCLK_INDEX_MASK) >>
262762306a36Sopenharmony_ci		CURR_SCLK_INDEX_SHIFT;
262862306a36Sopenharmony_ci	u32 sclk;
262962306a36Sopenharmony_ci
263062306a36Sopenharmony_ci	if (current_index >= SMU__NUM_SCLK_DPM_STATE) {
263162306a36Sopenharmony_ci		return 0;
263262306a36Sopenharmony_ci	} else {
263362306a36Sopenharmony_ci		sclk = be32_to_cpu(pi->graphics_level[current_index].SclkFrequency);
263462306a36Sopenharmony_ci		return sclk;
263562306a36Sopenharmony_ci	}
263662306a36Sopenharmony_ci}
263762306a36Sopenharmony_ci
263862306a36Sopenharmony_ciu32 kv_dpm_get_current_mclk(struct radeon_device *rdev)
263962306a36Sopenharmony_ci{
264062306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
264162306a36Sopenharmony_ci
264262306a36Sopenharmony_ci	return pi->sys_info.bootup_uma_clk;
264362306a36Sopenharmony_ci}
264462306a36Sopenharmony_ci
264562306a36Sopenharmony_civoid kv_dpm_print_power_state(struct radeon_device *rdev,
264662306a36Sopenharmony_ci			      struct radeon_ps *rps)
264762306a36Sopenharmony_ci{
264862306a36Sopenharmony_ci	int i;
264962306a36Sopenharmony_ci	struct kv_ps *ps = kv_get_ps(rps);
265062306a36Sopenharmony_ci
265162306a36Sopenharmony_ci	r600_dpm_print_class_info(rps->class, rps->class2);
265262306a36Sopenharmony_ci	r600_dpm_print_cap_info(rps->caps);
265362306a36Sopenharmony_ci	printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
265462306a36Sopenharmony_ci	for (i = 0; i < ps->num_levels; i++) {
265562306a36Sopenharmony_ci		struct kv_pl *pl = &ps->levels[i];
265662306a36Sopenharmony_ci		printk("\t\tpower level %d    sclk: %u vddc: %u\n",
265762306a36Sopenharmony_ci		       i, pl->sclk,
265862306a36Sopenharmony_ci		       kv_convert_8bit_index_to_voltage(rdev, pl->vddc_index));
265962306a36Sopenharmony_ci	}
266062306a36Sopenharmony_ci	r600_dpm_print_ps_status(rdev, rps);
266162306a36Sopenharmony_ci}
266262306a36Sopenharmony_ci
266362306a36Sopenharmony_civoid kv_dpm_fini(struct radeon_device *rdev)
266462306a36Sopenharmony_ci{
266562306a36Sopenharmony_ci	int i;
266662306a36Sopenharmony_ci
266762306a36Sopenharmony_ci	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
266862306a36Sopenharmony_ci		kfree(rdev->pm.dpm.ps[i].ps_priv);
266962306a36Sopenharmony_ci	}
267062306a36Sopenharmony_ci	kfree(rdev->pm.dpm.ps);
267162306a36Sopenharmony_ci	kfree(rdev->pm.dpm.priv);
267262306a36Sopenharmony_ci	r600_free_extended_power_table(rdev);
267362306a36Sopenharmony_ci}
267462306a36Sopenharmony_ci
267562306a36Sopenharmony_civoid kv_dpm_display_configuration_changed(struct radeon_device *rdev)
267662306a36Sopenharmony_ci{
267762306a36Sopenharmony_ci
267862306a36Sopenharmony_ci}
267962306a36Sopenharmony_ci
268062306a36Sopenharmony_ciu32 kv_dpm_get_sclk(struct radeon_device *rdev, bool low)
268162306a36Sopenharmony_ci{
268262306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
268362306a36Sopenharmony_ci	struct kv_ps *requested_state = kv_get_ps(&pi->requested_rps);
268462306a36Sopenharmony_ci
268562306a36Sopenharmony_ci	if (low)
268662306a36Sopenharmony_ci		return requested_state->levels[0].sclk;
268762306a36Sopenharmony_ci	else
268862306a36Sopenharmony_ci		return requested_state->levels[requested_state->num_levels - 1].sclk;
268962306a36Sopenharmony_ci}
269062306a36Sopenharmony_ci
269162306a36Sopenharmony_ciu32 kv_dpm_get_mclk(struct radeon_device *rdev, bool low)
269262306a36Sopenharmony_ci{
269362306a36Sopenharmony_ci	struct kv_power_info *pi = kv_get_pi(rdev);
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_ci	return pi->sys_info.bootup_uma_clk;
269662306a36Sopenharmony_ci}
269762306a36Sopenharmony_ci
2698