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/firmware.h>
2562306a36Sopenharmony_ci#include <linux/pci.h>
2662306a36Sopenharmony_ci#include <linux/seq_file.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include "atom.h"
2962306a36Sopenharmony_ci#include "ci_dpm.h"
3062306a36Sopenharmony_ci#include "cik.h"
3162306a36Sopenharmony_ci#include "cikd.h"
3262306a36Sopenharmony_ci#include "r600_dpm.h"
3362306a36Sopenharmony_ci#include "radeon.h"
3462306a36Sopenharmony_ci#include "radeon_asic.h"
3562306a36Sopenharmony_ci#include "radeon_ucode.h"
3662306a36Sopenharmony_ci#include "si_dpm.h"
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define MC_CG_ARB_FREQ_F0           0x0a
3962306a36Sopenharmony_ci#define MC_CG_ARB_FREQ_F1           0x0b
4062306a36Sopenharmony_ci#define MC_CG_ARB_FREQ_F2           0x0c
4162306a36Sopenharmony_ci#define MC_CG_ARB_FREQ_F3           0x0d
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define SMC_RAM_END 0x40000
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#define VOLTAGE_SCALE               4
4662306a36Sopenharmony_ci#define VOLTAGE_VID_OFFSET_SCALE1    625
4762306a36Sopenharmony_ci#define VOLTAGE_VID_OFFSET_SCALE2    100
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic const struct ci_pt_defaults defaults_hawaii_xt =
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	1, 0xF, 0xFD, 0x19, 5, 0x14, 0, 0xB0000,
5262306a36Sopenharmony_ci	{ 0x2E,  0x00,  0x00,  0x88,  0x00,  0x00,  0x72,  0x60,  0x51,  0xA7,  0x79,  0x6B,  0x90,  0xBD,  0x79  },
5362306a36Sopenharmony_ci	{ 0x217, 0x217, 0x217, 0x242, 0x242, 0x242, 0x269, 0x269, 0x269, 0x2A1, 0x2A1, 0x2A1, 0x2C9, 0x2C9, 0x2C9 }
5462306a36Sopenharmony_ci};
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic const struct ci_pt_defaults defaults_hawaii_pro =
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	1, 0xF, 0xFD, 0x19, 5, 0x14, 0, 0x65062,
5962306a36Sopenharmony_ci	{ 0x2E,  0x00,  0x00,  0x88,  0x00,  0x00,  0x72,  0x60,  0x51,  0xA7,  0x79,  0x6B,  0x90,  0xBD,  0x79  },
6062306a36Sopenharmony_ci	{ 0x217, 0x217, 0x217, 0x242, 0x242, 0x242, 0x269, 0x269, 0x269, 0x2A1, 0x2A1, 0x2A1, 0x2C9, 0x2C9, 0x2C9 }
6162306a36Sopenharmony_ci};
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic const struct ci_pt_defaults defaults_bonaire_xt =
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	1, 0xF, 0xFD, 0x19, 5, 45, 0, 0xB0000,
6662306a36Sopenharmony_ci	{ 0x79,  0x253, 0x25D, 0xAE,  0x72,  0x80,  0x83,  0x86,  0x6F,  0xC8,  0xC9,  0xC9,  0x2F,  0x4D,  0x61  },
6762306a36Sopenharmony_ci	{ 0x17C, 0x172, 0x180, 0x1BC, 0x1B3, 0x1BD, 0x206, 0x200, 0x203, 0x25D, 0x25A, 0x255, 0x2C3, 0x2C5, 0x2B4 }
6862306a36Sopenharmony_ci};
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic const struct ci_pt_defaults defaults_saturn_xt =
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	1, 0xF, 0xFD, 0x19, 5, 55, 0, 0x70000,
7362306a36Sopenharmony_ci	{ 0x8C,  0x247, 0x249, 0xA6,  0x80,  0x81,  0x8B,  0x89,  0x86,  0xC9,  0xCA,  0xC9,  0x4D,  0x4D,  0x4D  },
7462306a36Sopenharmony_ci	{ 0x187, 0x187, 0x187, 0x1C7, 0x1C7, 0x1C7, 0x210, 0x210, 0x210, 0x266, 0x266, 0x266, 0x2C9, 0x2C9, 0x2C9 }
7562306a36Sopenharmony_ci};
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic const struct ci_pt_config_reg didt_config_ci[] =
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	{ 0x10, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
8062306a36Sopenharmony_ci	{ 0x10, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
8162306a36Sopenharmony_ci	{ 0x10, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
8262306a36Sopenharmony_ci	{ 0x10, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
8362306a36Sopenharmony_ci	{ 0x11, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
8462306a36Sopenharmony_ci	{ 0x11, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
8562306a36Sopenharmony_ci	{ 0x11, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
8662306a36Sopenharmony_ci	{ 0x11, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
8762306a36Sopenharmony_ci	{ 0x12, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
8862306a36Sopenharmony_ci	{ 0x12, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
8962306a36Sopenharmony_ci	{ 0x12, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
9062306a36Sopenharmony_ci	{ 0x12, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
9162306a36Sopenharmony_ci	{ 0x2, 0x00003fff, 0, 0x4, CISLANDS_CONFIGREG_DIDT_IND },
9262306a36Sopenharmony_ci	{ 0x2, 0x03ff0000, 16, 0x80, CISLANDS_CONFIGREG_DIDT_IND },
9362306a36Sopenharmony_ci	{ 0x2, 0x78000000, 27, 0x3, CISLANDS_CONFIGREG_DIDT_IND },
9462306a36Sopenharmony_ci	{ 0x1, 0x0000ffff, 0, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
9562306a36Sopenharmony_ci	{ 0x1, 0xffff0000, 16, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
9662306a36Sopenharmony_ci	{ 0x0, 0x00000001, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
9762306a36Sopenharmony_ci	{ 0x30, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
9862306a36Sopenharmony_ci	{ 0x30, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
9962306a36Sopenharmony_ci	{ 0x30, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
10062306a36Sopenharmony_ci	{ 0x30, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
10162306a36Sopenharmony_ci	{ 0x31, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
10262306a36Sopenharmony_ci	{ 0x31, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
10362306a36Sopenharmony_ci	{ 0x31, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
10462306a36Sopenharmony_ci	{ 0x31, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
10562306a36Sopenharmony_ci	{ 0x32, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
10662306a36Sopenharmony_ci	{ 0x32, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
10762306a36Sopenharmony_ci	{ 0x32, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
10862306a36Sopenharmony_ci	{ 0x32, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
10962306a36Sopenharmony_ci	{ 0x22, 0x00003fff, 0, 0x4, CISLANDS_CONFIGREG_DIDT_IND },
11062306a36Sopenharmony_ci	{ 0x22, 0x03ff0000, 16, 0x80, CISLANDS_CONFIGREG_DIDT_IND },
11162306a36Sopenharmony_ci	{ 0x22, 0x78000000, 27, 0x3, CISLANDS_CONFIGREG_DIDT_IND },
11262306a36Sopenharmony_ci	{ 0x21, 0x0000ffff, 0, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
11362306a36Sopenharmony_ci	{ 0x21, 0xffff0000, 16, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
11462306a36Sopenharmony_ci	{ 0x20, 0x00000001, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
11562306a36Sopenharmony_ci	{ 0x50, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
11662306a36Sopenharmony_ci	{ 0x50, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
11762306a36Sopenharmony_ci	{ 0x50, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
11862306a36Sopenharmony_ci	{ 0x50, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
11962306a36Sopenharmony_ci	{ 0x51, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
12062306a36Sopenharmony_ci	{ 0x51, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
12162306a36Sopenharmony_ci	{ 0x51, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
12262306a36Sopenharmony_ci	{ 0x51, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
12362306a36Sopenharmony_ci	{ 0x52, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
12462306a36Sopenharmony_ci	{ 0x52, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
12562306a36Sopenharmony_ci	{ 0x52, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
12662306a36Sopenharmony_ci	{ 0x52, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
12762306a36Sopenharmony_ci	{ 0x42, 0x00003fff, 0, 0x4, CISLANDS_CONFIGREG_DIDT_IND },
12862306a36Sopenharmony_ci	{ 0x42, 0x03ff0000, 16, 0x80, CISLANDS_CONFIGREG_DIDT_IND },
12962306a36Sopenharmony_ci	{ 0x42, 0x78000000, 27, 0x3, CISLANDS_CONFIGREG_DIDT_IND },
13062306a36Sopenharmony_ci	{ 0x41, 0x0000ffff, 0, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
13162306a36Sopenharmony_ci	{ 0x41, 0xffff0000, 16, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
13262306a36Sopenharmony_ci	{ 0x40, 0x00000001, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
13362306a36Sopenharmony_ci	{ 0x70, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
13462306a36Sopenharmony_ci	{ 0x70, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
13562306a36Sopenharmony_ci	{ 0x70, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
13662306a36Sopenharmony_ci	{ 0x70, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
13762306a36Sopenharmony_ci	{ 0x71, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
13862306a36Sopenharmony_ci	{ 0x71, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
13962306a36Sopenharmony_ci	{ 0x71, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
14062306a36Sopenharmony_ci	{ 0x71, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
14162306a36Sopenharmony_ci	{ 0x72, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
14262306a36Sopenharmony_ci	{ 0x72, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
14362306a36Sopenharmony_ci	{ 0x72, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
14462306a36Sopenharmony_ci	{ 0x72, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
14562306a36Sopenharmony_ci	{ 0x62, 0x00003fff, 0, 0x4, CISLANDS_CONFIGREG_DIDT_IND },
14662306a36Sopenharmony_ci	{ 0x62, 0x03ff0000, 16, 0x80, CISLANDS_CONFIGREG_DIDT_IND },
14762306a36Sopenharmony_ci	{ 0x62, 0x78000000, 27, 0x3, CISLANDS_CONFIGREG_DIDT_IND },
14862306a36Sopenharmony_ci	{ 0x61, 0x0000ffff, 0, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
14962306a36Sopenharmony_ci	{ 0x61, 0xffff0000, 16, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
15062306a36Sopenharmony_ci	{ 0x60, 0x00000001, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
15162306a36Sopenharmony_ci	{ 0xFFFFFFFF }
15262306a36Sopenharmony_ci};
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ciextern u8 rv770_get_memory_module_index(struct radeon_device *rdev);
15562306a36Sopenharmony_ciextern int ni_copy_and_switch_arb_sets(struct radeon_device *rdev,
15662306a36Sopenharmony_ci				       u32 arb_freq_src, u32 arb_freq_dest);
15762306a36Sopenharmony_cistatic int ci_get_std_voltage_value_sidd(struct radeon_device *rdev,
15862306a36Sopenharmony_ci					 struct atom_voltage_table_entry *voltage_table,
15962306a36Sopenharmony_ci					 u16 *std_voltage_hi_sidd, u16 *std_voltage_lo_sidd);
16062306a36Sopenharmony_cistatic int ci_set_power_limit(struct radeon_device *rdev, u32 n);
16162306a36Sopenharmony_cistatic int ci_set_overdrive_target_tdp(struct radeon_device *rdev,
16262306a36Sopenharmony_ci				       u32 target_tdp);
16362306a36Sopenharmony_cistatic int ci_update_uvd_dpm(struct radeon_device *rdev, bool gate);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic PPSMC_Result ci_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg);
16662306a36Sopenharmony_cistatic PPSMC_Result ci_send_msg_to_smc_with_parameter(struct radeon_device *rdev,
16762306a36Sopenharmony_ci						      PPSMC_Msg msg, u32 parameter);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic void ci_thermal_start_smc_fan_control(struct radeon_device *rdev);
17062306a36Sopenharmony_cistatic void ci_fan_ctrl_set_default_mode(struct radeon_device *rdev);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_cistatic struct ci_power_info *ci_get_pi(struct radeon_device *rdev)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	struct ci_power_info *pi = rdev->pm.dpm.priv;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	return pi;
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic struct ci_ps *ci_get_ps(struct radeon_ps *rps)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	struct ci_ps *ps = rps->ps_priv;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	return ps;
18462306a36Sopenharmony_ci}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cistatic void ci_initialize_powertune_defaults(struct radeon_device *rdev)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	switch (rdev->pdev->device) {
19162306a36Sopenharmony_ci	case 0x6649:
19262306a36Sopenharmony_ci	case 0x6650:
19362306a36Sopenharmony_ci	case 0x6651:
19462306a36Sopenharmony_ci	case 0x6658:
19562306a36Sopenharmony_ci	case 0x665C:
19662306a36Sopenharmony_ci	case 0x665D:
19762306a36Sopenharmony_ci	default:
19862306a36Sopenharmony_ci		pi->powertune_defaults = &defaults_bonaire_xt;
19962306a36Sopenharmony_ci		break;
20062306a36Sopenharmony_ci	case 0x6640:
20162306a36Sopenharmony_ci	case 0x6641:
20262306a36Sopenharmony_ci	case 0x6646:
20362306a36Sopenharmony_ci	case 0x6647:
20462306a36Sopenharmony_ci		pi->powertune_defaults = &defaults_saturn_xt;
20562306a36Sopenharmony_ci		break;
20662306a36Sopenharmony_ci	case 0x67B8:
20762306a36Sopenharmony_ci	case 0x67B0:
20862306a36Sopenharmony_ci		pi->powertune_defaults = &defaults_hawaii_xt;
20962306a36Sopenharmony_ci		break;
21062306a36Sopenharmony_ci	case 0x67BA:
21162306a36Sopenharmony_ci	case 0x67B1:
21262306a36Sopenharmony_ci		pi->powertune_defaults = &defaults_hawaii_pro;
21362306a36Sopenharmony_ci		break;
21462306a36Sopenharmony_ci	case 0x67A0:
21562306a36Sopenharmony_ci	case 0x67A1:
21662306a36Sopenharmony_ci	case 0x67A2:
21762306a36Sopenharmony_ci	case 0x67A8:
21862306a36Sopenharmony_ci	case 0x67A9:
21962306a36Sopenharmony_ci	case 0x67AA:
22062306a36Sopenharmony_ci	case 0x67B9:
22162306a36Sopenharmony_ci	case 0x67BE:
22262306a36Sopenharmony_ci		pi->powertune_defaults = &defaults_bonaire_xt;
22362306a36Sopenharmony_ci		break;
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	pi->dte_tj_offset = 0;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	pi->caps_power_containment = true;
22962306a36Sopenharmony_ci	pi->caps_cac = false;
23062306a36Sopenharmony_ci	pi->caps_sq_ramping = false;
23162306a36Sopenharmony_ci	pi->caps_db_ramping = false;
23262306a36Sopenharmony_ci	pi->caps_td_ramping = false;
23362306a36Sopenharmony_ci	pi->caps_tcp_ramping = false;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	if (pi->caps_power_containment) {
23662306a36Sopenharmony_ci		pi->caps_cac = true;
23762306a36Sopenharmony_ci		if (rdev->family == CHIP_HAWAII)
23862306a36Sopenharmony_ci			pi->enable_bapm_feature = false;
23962306a36Sopenharmony_ci		else
24062306a36Sopenharmony_ci			pi->enable_bapm_feature = true;
24162306a36Sopenharmony_ci		pi->enable_tdc_limit_feature = true;
24262306a36Sopenharmony_ci		pi->enable_pkg_pwr_tracking_feature = true;
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_cistatic u8 ci_convert_to_vid(u16 vddc)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	return (6200 - (vddc * VOLTAGE_SCALE)) / 25;
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic int ci_populate_bapm_vddc_vid_sidd(struct radeon_device *rdev)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
25462306a36Sopenharmony_ci	u8 *hi_vid = pi->smc_powertune_table.BapmVddCVidHiSidd;
25562306a36Sopenharmony_ci	u8 *lo_vid = pi->smc_powertune_table.BapmVddCVidLoSidd;
25662306a36Sopenharmony_ci	u8 *hi2_vid = pi->smc_powertune_table.BapmVddCVidHiSidd2;
25762306a36Sopenharmony_ci	u32 i;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	if (rdev->pm.dpm.dyn_state.cac_leakage_table.entries == NULL)
26062306a36Sopenharmony_ci		return -EINVAL;
26162306a36Sopenharmony_ci	if (rdev->pm.dpm.dyn_state.cac_leakage_table.count > 8)
26262306a36Sopenharmony_ci		return -EINVAL;
26362306a36Sopenharmony_ci	if (rdev->pm.dpm.dyn_state.cac_leakage_table.count !=
26462306a36Sopenharmony_ci	    rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count)
26562306a36Sopenharmony_ci		return -EINVAL;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	for (i = 0; i < rdev->pm.dpm.dyn_state.cac_leakage_table.count; i++) {
26862306a36Sopenharmony_ci		if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_EVV) {
26962306a36Sopenharmony_ci			lo_vid[i] = ci_convert_to_vid(rdev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc1);
27062306a36Sopenharmony_ci			hi_vid[i] = ci_convert_to_vid(rdev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc2);
27162306a36Sopenharmony_ci			hi2_vid[i] = ci_convert_to_vid(rdev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc3);
27262306a36Sopenharmony_ci		} else {
27362306a36Sopenharmony_ci			lo_vid[i] = ci_convert_to_vid(rdev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc);
27462306a36Sopenharmony_ci			hi_vid[i] = ci_convert_to_vid((u16)rdev->pm.dpm.dyn_state.cac_leakage_table.entries[i].leakage);
27562306a36Sopenharmony_ci		}
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci	return 0;
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_cistatic int ci_populate_vddc_vid(struct radeon_device *rdev)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
28362306a36Sopenharmony_ci	u8 *vid = pi->smc_powertune_table.VddCVid;
28462306a36Sopenharmony_ci	u32 i;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	if (pi->vddc_voltage_table.count > 8)
28762306a36Sopenharmony_ci		return -EINVAL;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	for (i = 0; i < pi->vddc_voltage_table.count; i++)
29062306a36Sopenharmony_ci		vid[i] = ci_convert_to_vid(pi->vddc_voltage_table.entries[i].value);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	return 0;
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistatic int ci_populate_svi_load_line(struct radeon_device *rdev)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
29862306a36Sopenharmony_ci	const struct ci_pt_defaults *pt_defaults = pi->powertune_defaults;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	pi->smc_powertune_table.SviLoadLineEn = pt_defaults->svi_load_line_en;
30162306a36Sopenharmony_ci	pi->smc_powertune_table.SviLoadLineVddC = pt_defaults->svi_load_line_vddc;
30262306a36Sopenharmony_ci	pi->smc_powertune_table.SviLoadLineTrimVddC = 3;
30362306a36Sopenharmony_ci	pi->smc_powertune_table.SviLoadLineOffsetVddC = 0;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	return 0;
30662306a36Sopenharmony_ci}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_cistatic int ci_populate_tdc_limit(struct radeon_device *rdev)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
31162306a36Sopenharmony_ci	const struct ci_pt_defaults *pt_defaults = pi->powertune_defaults;
31262306a36Sopenharmony_ci	u16 tdc_limit;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	tdc_limit = rdev->pm.dpm.dyn_state.cac_tdp_table->tdc * 256;
31562306a36Sopenharmony_ci	pi->smc_powertune_table.TDC_VDDC_PkgLimit = cpu_to_be16(tdc_limit);
31662306a36Sopenharmony_ci	pi->smc_powertune_table.TDC_VDDC_ThrottleReleaseLimitPerc =
31762306a36Sopenharmony_ci		pt_defaults->tdc_vddc_throttle_release_limit_perc;
31862306a36Sopenharmony_ci	pi->smc_powertune_table.TDC_MAWt = pt_defaults->tdc_mawt;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	return 0;
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic int ci_populate_dw8(struct radeon_device *rdev)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
32662306a36Sopenharmony_ci	const struct ci_pt_defaults *pt_defaults = pi->powertune_defaults;
32762306a36Sopenharmony_ci	int ret;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	ret = ci_read_smc_sram_dword(rdev,
33062306a36Sopenharmony_ci				     SMU7_FIRMWARE_HEADER_LOCATION +
33162306a36Sopenharmony_ci				     offsetof(SMU7_Firmware_Header, PmFuseTable) +
33262306a36Sopenharmony_ci				     offsetof(SMU7_Discrete_PmFuses, TdcWaterfallCtl),
33362306a36Sopenharmony_ci				     (u32 *)&pi->smc_powertune_table.TdcWaterfallCtl,
33462306a36Sopenharmony_ci				     pi->sram_end);
33562306a36Sopenharmony_ci	if (ret)
33662306a36Sopenharmony_ci		return -EINVAL;
33762306a36Sopenharmony_ci	else
33862306a36Sopenharmony_ci		pi->smc_powertune_table.TdcWaterfallCtl = pt_defaults->tdc_waterfall_ctl;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	return 0;
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic int ci_populate_fuzzy_fan(struct radeon_device *rdev)
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	if ((rdev->pm.dpm.fan.fan_output_sensitivity & (1 << 15)) ||
34862306a36Sopenharmony_ci	    (rdev->pm.dpm.fan.fan_output_sensitivity == 0))
34962306a36Sopenharmony_ci		rdev->pm.dpm.fan.fan_output_sensitivity =
35062306a36Sopenharmony_ci			rdev->pm.dpm.fan.default_fan_output_sensitivity;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	pi->smc_powertune_table.FuzzyFan_PwmSetDelta =
35362306a36Sopenharmony_ci		cpu_to_be16(rdev->pm.dpm.fan.fan_output_sensitivity);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	return 0;
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic int ci_min_max_v_gnbl_pm_lid_from_bapm_vddc(struct radeon_device *rdev)
35962306a36Sopenharmony_ci{
36062306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
36162306a36Sopenharmony_ci	u8 *hi_vid = pi->smc_powertune_table.BapmVddCVidHiSidd;
36262306a36Sopenharmony_ci	u8 *lo_vid = pi->smc_powertune_table.BapmVddCVidLoSidd;
36362306a36Sopenharmony_ci	int i, min, max;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	min = max = hi_vid[0];
36662306a36Sopenharmony_ci	for (i = 0; i < 8; i++) {
36762306a36Sopenharmony_ci		if (0 != hi_vid[i]) {
36862306a36Sopenharmony_ci			if (min > hi_vid[i])
36962306a36Sopenharmony_ci				min = hi_vid[i];
37062306a36Sopenharmony_ci			if (max < hi_vid[i])
37162306a36Sopenharmony_ci				max = hi_vid[i];
37262306a36Sopenharmony_ci		}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci		if (0 != lo_vid[i]) {
37562306a36Sopenharmony_ci			if (min > lo_vid[i])
37662306a36Sopenharmony_ci				min = lo_vid[i];
37762306a36Sopenharmony_ci			if (max < lo_vid[i])
37862306a36Sopenharmony_ci				max = lo_vid[i];
37962306a36Sopenharmony_ci		}
38062306a36Sopenharmony_ci	}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	if ((min == 0) || (max == 0))
38362306a36Sopenharmony_ci		return -EINVAL;
38462306a36Sopenharmony_ci	pi->smc_powertune_table.GnbLPMLMaxVid = (u8)max;
38562306a36Sopenharmony_ci	pi->smc_powertune_table.GnbLPMLMinVid = (u8)min;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	return 0;
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_cistatic int ci_populate_bapm_vddc_base_leakage_sidd(struct radeon_device *rdev)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
39362306a36Sopenharmony_ci	u16 hi_sidd, lo_sidd;
39462306a36Sopenharmony_ci	struct radeon_cac_tdp_table *cac_tdp_table =
39562306a36Sopenharmony_ci		rdev->pm.dpm.dyn_state.cac_tdp_table;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	hi_sidd = cac_tdp_table->high_cac_leakage / 100 * 256;
39862306a36Sopenharmony_ci	lo_sidd = cac_tdp_table->low_cac_leakage / 100 * 256;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	pi->smc_powertune_table.BapmVddCBaseLeakageHiSidd = cpu_to_be16(hi_sidd);
40162306a36Sopenharmony_ci	pi->smc_powertune_table.BapmVddCBaseLeakageLoSidd = cpu_to_be16(lo_sidd);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	return 0;
40462306a36Sopenharmony_ci}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_cistatic int ci_populate_bapm_parameters_in_dpm_table(struct radeon_device *rdev)
40762306a36Sopenharmony_ci{
40862306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
40962306a36Sopenharmony_ci	const struct ci_pt_defaults *pt_defaults = pi->powertune_defaults;
41062306a36Sopenharmony_ci	SMU7_Discrete_DpmTable  *dpm_table = &pi->smc_state_table;
41162306a36Sopenharmony_ci	struct radeon_cac_tdp_table *cac_tdp_table =
41262306a36Sopenharmony_ci		rdev->pm.dpm.dyn_state.cac_tdp_table;
41362306a36Sopenharmony_ci	struct radeon_ppm_table *ppm = rdev->pm.dpm.dyn_state.ppm_table;
41462306a36Sopenharmony_ci	int i, j, k;
41562306a36Sopenharmony_ci	const u16 *def1;
41662306a36Sopenharmony_ci	const u16 *def2;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	dpm_table->DefaultTdp = cac_tdp_table->tdp * 256;
41962306a36Sopenharmony_ci	dpm_table->TargetTdp = cac_tdp_table->configurable_tdp * 256;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	dpm_table->DTETjOffset = (u8)pi->dte_tj_offset;
42262306a36Sopenharmony_ci	dpm_table->GpuTjMax =
42362306a36Sopenharmony_ci		(u8)(pi->thermal_temp_setting.temperature_high / 1000);
42462306a36Sopenharmony_ci	dpm_table->GpuTjHyst = 8;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	dpm_table->DTEAmbientTempBase = pt_defaults->dte_ambient_temp_base;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	if (ppm) {
42962306a36Sopenharmony_ci		dpm_table->PPM_PkgPwrLimit = cpu_to_be16((u16)ppm->dgpu_tdp * 256 / 1000);
43062306a36Sopenharmony_ci		dpm_table->PPM_TemperatureLimit = cpu_to_be16((u16)ppm->tj_max * 256);
43162306a36Sopenharmony_ci	} else {
43262306a36Sopenharmony_ci		dpm_table->PPM_PkgPwrLimit = cpu_to_be16(0);
43362306a36Sopenharmony_ci		dpm_table->PPM_TemperatureLimit = cpu_to_be16(0);
43462306a36Sopenharmony_ci	}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	dpm_table->BAPM_TEMP_GRADIENT = cpu_to_be32(pt_defaults->bapm_temp_gradient);
43762306a36Sopenharmony_ci	def1 = pt_defaults->bapmti_r;
43862306a36Sopenharmony_ci	def2 = pt_defaults->bapmti_rc;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	for (i = 0; i < SMU7_DTE_ITERATIONS; i++) {
44162306a36Sopenharmony_ci		for (j = 0; j < SMU7_DTE_SOURCES; j++) {
44262306a36Sopenharmony_ci			for (k = 0; k < SMU7_DTE_SINKS; k++) {
44362306a36Sopenharmony_ci				dpm_table->BAPMTI_R[i][j][k] = cpu_to_be16(*def1);
44462306a36Sopenharmony_ci				dpm_table->BAPMTI_RC[i][j][k] = cpu_to_be16(*def2);
44562306a36Sopenharmony_ci				def1++;
44662306a36Sopenharmony_ci				def2++;
44762306a36Sopenharmony_ci			}
44862306a36Sopenharmony_ci		}
44962306a36Sopenharmony_ci	}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	return 0;
45262306a36Sopenharmony_ci}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_cistatic int ci_populate_pm_base(struct radeon_device *rdev)
45562306a36Sopenharmony_ci{
45662306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
45762306a36Sopenharmony_ci	u32 pm_fuse_table_offset;
45862306a36Sopenharmony_ci	int ret;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	if (pi->caps_power_containment) {
46162306a36Sopenharmony_ci		ret = ci_read_smc_sram_dword(rdev,
46262306a36Sopenharmony_ci					     SMU7_FIRMWARE_HEADER_LOCATION +
46362306a36Sopenharmony_ci					     offsetof(SMU7_Firmware_Header, PmFuseTable),
46462306a36Sopenharmony_ci					     &pm_fuse_table_offset, pi->sram_end);
46562306a36Sopenharmony_ci		if (ret)
46662306a36Sopenharmony_ci			return ret;
46762306a36Sopenharmony_ci		ret = ci_populate_bapm_vddc_vid_sidd(rdev);
46862306a36Sopenharmony_ci		if (ret)
46962306a36Sopenharmony_ci			return ret;
47062306a36Sopenharmony_ci		ret = ci_populate_vddc_vid(rdev);
47162306a36Sopenharmony_ci		if (ret)
47262306a36Sopenharmony_ci			return ret;
47362306a36Sopenharmony_ci		ret = ci_populate_svi_load_line(rdev);
47462306a36Sopenharmony_ci		if (ret)
47562306a36Sopenharmony_ci			return ret;
47662306a36Sopenharmony_ci		ret = ci_populate_tdc_limit(rdev);
47762306a36Sopenharmony_ci		if (ret)
47862306a36Sopenharmony_ci			return ret;
47962306a36Sopenharmony_ci		ret = ci_populate_dw8(rdev);
48062306a36Sopenharmony_ci		if (ret)
48162306a36Sopenharmony_ci			return ret;
48262306a36Sopenharmony_ci		ret = ci_populate_fuzzy_fan(rdev);
48362306a36Sopenharmony_ci		if (ret)
48462306a36Sopenharmony_ci			return ret;
48562306a36Sopenharmony_ci		ret = ci_min_max_v_gnbl_pm_lid_from_bapm_vddc(rdev);
48662306a36Sopenharmony_ci		if (ret)
48762306a36Sopenharmony_ci			return ret;
48862306a36Sopenharmony_ci		ret = ci_populate_bapm_vddc_base_leakage_sidd(rdev);
48962306a36Sopenharmony_ci		if (ret)
49062306a36Sopenharmony_ci			return ret;
49162306a36Sopenharmony_ci		ret = ci_copy_bytes_to_smc(rdev, pm_fuse_table_offset,
49262306a36Sopenharmony_ci					   (u8 *)&pi->smc_powertune_table,
49362306a36Sopenharmony_ci					   sizeof(SMU7_Discrete_PmFuses), pi->sram_end);
49462306a36Sopenharmony_ci		if (ret)
49562306a36Sopenharmony_ci			return ret;
49662306a36Sopenharmony_ci	}
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	return 0;
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_cistatic void ci_do_enable_didt(struct radeon_device *rdev, const bool enable)
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
50462306a36Sopenharmony_ci	u32 data;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	if (pi->caps_sq_ramping) {
50762306a36Sopenharmony_ci		data = RREG32_DIDT(DIDT_SQ_CTRL0);
50862306a36Sopenharmony_ci		if (enable)
50962306a36Sopenharmony_ci			data |= DIDT_CTRL_EN;
51062306a36Sopenharmony_ci		else
51162306a36Sopenharmony_ci			data &= ~DIDT_CTRL_EN;
51262306a36Sopenharmony_ci		WREG32_DIDT(DIDT_SQ_CTRL0, data);
51362306a36Sopenharmony_ci	}
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	if (pi->caps_db_ramping) {
51662306a36Sopenharmony_ci		data = RREG32_DIDT(DIDT_DB_CTRL0);
51762306a36Sopenharmony_ci		if (enable)
51862306a36Sopenharmony_ci			data |= DIDT_CTRL_EN;
51962306a36Sopenharmony_ci		else
52062306a36Sopenharmony_ci			data &= ~DIDT_CTRL_EN;
52162306a36Sopenharmony_ci		WREG32_DIDT(DIDT_DB_CTRL0, data);
52262306a36Sopenharmony_ci	}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	if (pi->caps_td_ramping) {
52562306a36Sopenharmony_ci		data = RREG32_DIDT(DIDT_TD_CTRL0);
52662306a36Sopenharmony_ci		if (enable)
52762306a36Sopenharmony_ci			data |= DIDT_CTRL_EN;
52862306a36Sopenharmony_ci		else
52962306a36Sopenharmony_ci			data &= ~DIDT_CTRL_EN;
53062306a36Sopenharmony_ci		WREG32_DIDT(DIDT_TD_CTRL0, data);
53162306a36Sopenharmony_ci	}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	if (pi->caps_tcp_ramping) {
53462306a36Sopenharmony_ci		data = RREG32_DIDT(DIDT_TCP_CTRL0);
53562306a36Sopenharmony_ci		if (enable)
53662306a36Sopenharmony_ci			data |= DIDT_CTRL_EN;
53762306a36Sopenharmony_ci		else
53862306a36Sopenharmony_ci			data &= ~DIDT_CTRL_EN;
53962306a36Sopenharmony_ci		WREG32_DIDT(DIDT_TCP_CTRL0, data);
54062306a36Sopenharmony_ci	}
54162306a36Sopenharmony_ci}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_cistatic int ci_program_pt_config_registers(struct radeon_device *rdev,
54462306a36Sopenharmony_ci					  const struct ci_pt_config_reg *cac_config_regs)
54562306a36Sopenharmony_ci{
54662306a36Sopenharmony_ci	const struct ci_pt_config_reg *config_regs = cac_config_regs;
54762306a36Sopenharmony_ci	u32 data;
54862306a36Sopenharmony_ci	u32 cache = 0;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	if (config_regs == NULL)
55162306a36Sopenharmony_ci		return -EINVAL;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	while (config_regs->offset != 0xFFFFFFFF) {
55462306a36Sopenharmony_ci		if (config_regs->type == CISLANDS_CONFIGREG_CACHE) {
55562306a36Sopenharmony_ci			cache |= ((config_regs->value << config_regs->shift) & config_regs->mask);
55662306a36Sopenharmony_ci		} else {
55762306a36Sopenharmony_ci			switch (config_regs->type) {
55862306a36Sopenharmony_ci			case CISLANDS_CONFIGREG_SMC_IND:
55962306a36Sopenharmony_ci				data = RREG32_SMC(config_regs->offset);
56062306a36Sopenharmony_ci				break;
56162306a36Sopenharmony_ci			case CISLANDS_CONFIGREG_DIDT_IND:
56262306a36Sopenharmony_ci				data = RREG32_DIDT(config_regs->offset);
56362306a36Sopenharmony_ci				break;
56462306a36Sopenharmony_ci			default:
56562306a36Sopenharmony_ci				data = RREG32(config_regs->offset << 2);
56662306a36Sopenharmony_ci				break;
56762306a36Sopenharmony_ci			}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci			data &= ~config_regs->mask;
57062306a36Sopenharmony_ci			data |= ((config_regs->value << config_regs->shift) & config_regs->mask);
57162306a36Sopenharmony_ci			data |= cache;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci			switch (config_regs->type) {
57462306a36Sopenharmony_ci			case CISLANDS_CONFIGREG_SMC_IND:
57562306a36Sopenharmony_ci				WREG32_SMC(config_regs->offset, data);
57662306a36Sopenharmony_ci				break;
57762306a36Sopenharmony_ci			case CISLANDS_CONFIGREG_DIDT_IND:
57862306a36Sopenharmony_ci				WREG32_DIDT(config_regs->offset, data);
57962306a36Sopenharmony_ci				break;
58062306a36Sopenharmony_ci			default:
58162306a36Sopenharmony_ci				WREG32(config_regs->offset << 2, data);
58262306a36Sopenharmony_ci				break;
58362306a36Sopenharmony_ci			}
58462306a36Sopenharmony_ci			cache = 0;
58562306a36Sopenharmony_ci		}
58662306a36Sopenharmony_ci		config_regs++;
58762306a36Sopenharmony_ci	}
58862306a36Sopenharmony_ci	return 0;
58962306a36Sopenharmony_ci}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_cistatic int ci_enable_didt(struct radeon_device *rdev, bool enable)
59262306a36Sopenharmony_ci{
59362306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
59462306a36Sopenharmony_ci	int ret;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	if (pi->caps_sq_ramping || pi->caps_db_ramping ||
59762306a36Sopenharmony_ci	    pi->caps_td_ramping || pi->caps_tcp_ramping) {
59862306a36Sopenharmony_ci		cik_enter_rlc_safe_mode(rdev);
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci		if (enable) {
60162306a36Sopenharmony_ci			ret = ci_program_pt_config_registers(rdev, didt_config_ci);
60262306a36Sopenharmony_ci			if (ret) {
60362306a36Sopenharmony_ci				cik_exit_rlc_safe_mode(rdev);
60462306a36Sopenharmony_ci				return ret;
60562306a36Sopenharmony_ci			}
60662306a36Sopenharmony_ci		}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci		ci_do_enable_didt(rdev, enable);
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci		cik_exit_rlc_safe_mode(rdev);
61162306a36Sopenharmony_ci	}
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	return 0;
61462306a36Sopenharmony_ci}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_cistatic int ci_enable_power_containment(struct radeon_device *rdev, bool enable)
61762306a36Sopenharmony_ci{
61862306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
61962306a36Sopenharmony_ci	PPSMC_Result smc_result;
62062306a36Sopenharmony_ci	int ret = 0;
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	if (enable) {
62362306a36Sopenharmony_ci		pi->power_containment_features = 0;
62462306a36Sopenharmony_ci		if (pi->caps_power_containment) {
62562306a36Sopenharmony_ci			if (pi->enable_bapm_feature) {
62662306a36Sopenharmony_ci				smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_EnableDTE);
62762306a36Sopenharmony_ci				if (smc_result != PPSMC_Result_OK)
62862306a36Sopenharmony_ci					ret = -EINVAL;
62962306a36Sopenharmony_ci				else
63062306a36Sopenharmony_ci					pi->power_containment_features |= POWERCONTAINMENT_FEATURE_BAPM;
63162306a36Sopenharmony_ci			}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci			if (pi->enable_tdc_limit_feature) {
63462306a36Sopenharmony_ci				smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_TDCLimitEnable);
63562306a36Sopenharmony_ci				if (smc_result != PPSMC_Result_OK)
63662306a36Sopenharmony_ci					ret = -EINVAL;
63762306a36Sopenharmony_ci				else
63862306a36Sopenharmony_ci					pi->power_containment_features |= POWERCONTAINMENT_FEATURE_TDCLimit;
63962306a36Sopenharmony_ci			}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci			if (pi->enable_pkg_pwr_tracking_feature) {
64262306a36Sopenharmony_ci				smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_PkgPwrLimitEnable);
64362306a36Sopenharmony_ci				if (smc_result != PPSMC_Result_OK) {
64462306a36Sopenharmony_ci					ret = -EINVAL;
64562306a36Sopenharmony_ci				} else {
64662306a36Sopenharmony_ci					struct radeon_cac_tdp_table *cac_tdp_table =
64762306a36Sopenharmony_ci						rdev->pm.dpm.dyn_state.cac_tdp_table;
64862306a36Sopenharmony_ci					u32 default_pwr_limit =
64962306a36Sopenharmony_ci						(u32)(cac_tdp_table->maximum_power_delivery_limit * 256);
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci					pi->power_containment_features |= POWERCONTAINMENT_FEATURE_PkgPwrLimit;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci					ci_set_power_limit(rdev, default_pwr_limit);
65462306a36Sopenharmony_ci				}
65562306a36Sopenharmony_ci			}
65662306a36Sopenharmony_ci		}
65762306a36Sopenharmony_ci	} else {
65862306a36Sopenharmony_ci		if (pi->caps_power_containment && pi->power_containment_features) {
65962306a36Sopenharmony_ci			if (pi->power_containment_features & POWERCONTAINMENT_FEATURE_TDCLimit)
66062306a36Sopenharmony_ci				ci_send_msg_to_smc(rdev, PPSMC_MSG_TDCLimitDisable);
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci			if (pi->power_containment_features & POWERCONTAINMENT_FEATURE_BAPM)
66362306a36Sopenharmony_ci				ci_send_msg_to_smc(rdev, PPSMC_MSG_DisableDTE);
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci			if (pi->power_containment_features & POWERCONTAINMENT_FEATURE_PkgPwrLimit)
66662306a36Sopenharmony_ci				ci_send_msg_to_smc(rdev, PPSMC_MSG_PkgPwrLimitDisable);
66762306a36Sopenharmony_ci			pi->power_containment_features = 0;
66862306a36Sopenharmony_ci		}
66962306a36Sopenharmony_ci	}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	return ret;
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_cistatic int ci_enable_smc_cac(struct radeon_device *rdev, bool enable)
67562306a36Sopenharmony_ci{
67662306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
67762306a36Sopenharmony_ci	PPSMC_Result smc_result;
67862306a36Sopenharmony_ci	int ret = 0;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	if (pi->caps_cac) {
68162306a36Sopenharmony_ci		if (enable) {
68262306a36Sopenharmony_ci			smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_EnableCac);
68362306a36Sopenharmony_ci			if (smc_result != PPSMC_Result_OK) {
68462306a36Sopenharmony_ci				ret = -EINVAL;
68562306a36Sopenharmony_ci				pi->cac_enabled = false;
68662306a36Sopenharmony_ci			} else {
68762306a36Sopenharmony_ci				pi->cac_enabled = true;
68862306a36Sopenharmony_ci			}
68962306a36Sopenharmony_ci		} else if (pi->cac_enabled) {
69062306a36Sopenharmony_ci			ci_send_msg_to_smc(rdev, PPSMC_MSG_DisableCac);
69162306a36Sopenharmony_ci			pi->cac_enabled = false;
69262306a36Sopenharmony_ci		}
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	return ret;
69662306a36Sopenharmony_ci}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_cistatic int ci_enable_thermal_based_sclk_dpm(struct radeon_device *rdev,
69962306a36Sopenharmony_ci					    bool enable)
70062306a36Sopenharmony_ci{
70162306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
70262306a36Sopenharmony_ci	PPSMC_Result smc_result = PPSMC_Result_OK;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	if (pi->thermal_sclk_dpm_enabled) {
70562306a36Sopenharmony_ci		if (enable)
70662306a36Sopenharmony_ci			smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_ENABLE_THERMAL_DPM);
70762306a36Sopenharmony_ci		else
70862306a36Sopenharmony_ci			smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_DISABLE_THERMAL_DPM);
70962306a36Sopenharmony_ci	}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	if (smc_result == PPSMC_Result_OK)
71262306a36Sopenharmony_ci		return 0;
71362306a36Sopenharmony_ci	else
71462306a36Sopenharmony_ci		return -EINVAL;
71562306a36Sopenharmony_ci}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_cistatic int ci_power_control_set_level(struct radeon_device *rdev)
71862306a36Sopenharmony_ci{
71962306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
72062306a36Sopenharmony_ci	struct radeon_cac_tdp_table *cac_tdp_table =
72162306a36Sopenharmony_ci		rdev->pm.dpm.dyn_state.cac_tdp_table;
72262306a36Sopenharmony_ci	s32 adjust_percent;
72362306a36Sopenharmony_ci	s32 target_tdp;
72462306a36Sopenharmony_ci	int ret = 0;
72562306a36Sopenharmony_ci	bool adjust_polarity = false; /* ??? */
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	if (pi->caps_power_containment) {
72862306a36Sopenharmony_ci		adjust_percent = adjust_polarity ?
72962306a36Sopenharmony_ci			rdev->pm.dpm.tdp_adjustment : (-1 * rdev->pm.dpm.tdp_adjustment);
73062306a36Sopenharmony_ci		target_tdp = ((100 + adjust_percent) *
73162306a36Sopenharmony_ci			      (s32)cac_tdp_table->configurable_tdp) / 100;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci		ret = ci_set_overdrive_target_tdp(rdev, (u32)target_tdp);
73462306a36Sopenharmony_ci	}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	return ret;
73762306a36Sopenharmony_ci}
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_civoid ci_dpm_powergate_uvd(struct radeon_device *rdev, bool gate)
74062306a36Sopenharmony_ci{
74162306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	if (pi->uvd_power_gated == gate)
74462306a36Sopenharmony_ci		return;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	pi->uvd_power_gated = gate;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	ci_update_uvd_dpm(rdev, gate);
74962306a36Sopenharmony_ci}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_cibool ci_dpm_vblank_too_short(struct radeon_device *rdev)
75262306a36Sopenharmony_ci{
75362306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
75462306a36Sopenharmony_ci	u32 vblank_time = r600_dpm_get_vblank_time(rdev);
75562306a36Sopenharmony_ci	u32 switch_limit = pi->mem_gddr5 ? 450 : 300;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	/* disable mclk switching if the refresh is >120Hz, even if the
75862306a36Sopenharmony_ci        * blanking period would allow it
75962306a36Sopenharmony_ci        */
76062306a36Sopenharmony_ci	if (r600_dpm_get_vrefresh(rdev) > 120)
76162306a36Sopenharmony_ci		return true;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	if (vblank_time < switch_limit)
76462306a36Sopenharmony_ci		return true;
76562306a36Sopenharmony_ci	else
76662306a36Sopenharmony_ci		return false;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci}
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_cistatic void ci_apply_state_adjust_rules(struct radeon_device *rdev,
77162306a36Sopenharmony_ci					struct radeon_ps *rps)
77262306a36Sopenharmony_ci{
77362306a36Sopenharmony_ci	struct ci_ps *ps = ci_get_ps(rps);
77462306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
77562306a36Sopenharmony_ci	struct radeon_clock_and_voltage_limits *max_limits;
77662306a36Sopenharmony_ci	bool disable_mclk_switching;
77762306a36Sopenharmony_ci	u32 sclk, mclk;
77862306a36Sopenharmony_ci	int i;
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	if (rps->vce_active) {
78162306a36Sopenharmony_ci		rps->evclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].evclk;
78262306a36Sopenharmony_ci		rps->ecclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].ecclk;
78362306a36Sopenharmony_ci	} else {
78462306a36Sopenharmony_ci		rps->evclk = 0;
78562306a36Sopenharmony_ci		rps->ecclk = 0;
78662306a36Sopenharmony_ci	}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	if ((rdev->pm.dpm.new_active_crtc_count > 1) ||
78962306a36Sopenharmony_ci	    ci_dpm_vblank_too_short(rdev))
79062306a36Sopenharmony_ci		disable_mclk_switching = true;
79162306a36Sopenharmony_ci	else
79262306a36Sopenharmony_ci		disable_mclk_switching = false;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY)
79562306a36Sopenharmony_ci		pi->battery_state = true;
79662306a36Sopenharmony_ci	else
79762306a36Sopenharmony_ci		pi->battery_state = false;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	if (rdev->pm.dpm.ac_power)
80062306a36Sopenharmony_ci		max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
80162306a36Sopenharmony_ci	else
80262306a36Sopenharmony_ci		max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	if (rdev->pm.dpm.ac_power == false) {
80562306a36Sopenharmony_ci		for (i = 0; i < ps->performance_level_count; i++) {
80662306a36Sopenharmony_ci			if (ps->performance_levels[i].mclk > max_limits->mclk)
80762306a36Sopenharmony_ci				ps->performance_levels[i].mclk = max_limits->mclk;
80862306a36Sopenharmony_ci			if (ps->performance_levels[i].sclk > max_limits->sclk)
80962306a36Sopenharmony_ci				ps->performance_levels[i].sclk = max_limits->sclk;
81062306a36Sopenharmony_ci		}
81162306a36Sopenharmony_ci	}
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	/* XXX validate the min clocks required for display */
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	if (disable_mclk_switching) {
81662306a36Sopenharmony_ci		mclk  = ps->performance_levels[ps->performance_level_count - 1].mclk;
81762306a36Sopenharmony_ci		sclk = ps->performance_levels[0].sclk;
81862306a36Sopenharmony_ci	} else {
81962306a36Sopenharmony_ci		mclk = ps->performance_levels[0].mclk;
82062306a36Sopenharmony_ci		sclk = ps->performance_levels[0].sclk;
82162306a36Sopenharmony_ci	}
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	if (rps->vce_active) {
82462306a36Sopenharmony_ci		if (sclk < rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk)
82562306a36Sopenharmony_ci			sclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk;
82662306a36Sopenharmony_ci		if (mclk < rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].mclk)
82762306a36Sopenharmony_ci			mclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].mclk;
82862306a36Sopenharmony_ci	}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	ps->performance_levels[0].sclk = sclk;
83162306a36Sopenharmony_ci	ps->performance_levels[0].mclk = mclk;
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	if (ps->performance_levels[1].sclk < ps->performance_levels[0].sclk)
83462306a36Sopenharmony_ci		ps->performance_levels[1].sclk = ps->performance_levels[0].sclk;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	if (disable_mclk_switching) {
83762306a36Sopenharmony_ci		if (ps->performance_levels[0].mclk < ps->performance_levels[1].mclk)
83862306a36Sopenharmony_ci			ps->performance_levels[0].mclk = ps->performance_levels[1].mclk;
83962306a36Sopenharmony_ci	} else {
84062306a36Sopenharmony_ci		if (ps->performance_levels[1].mclk < ps->performance_levels[0].mclk)
84162306a36Sopenharmony_ci			ps->performance_levels[1].mclk = ps->performance_levels[0].mclk;
84262306a36Sopenharmony_ci	}
84362306a36Sopenharmony_ci}
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_cistatic int ci_thermal_set_temperature_range(struct radeon_device *rdev,
84662306a36Sopenharmony_ci					    int min_temp, int max_temp)
84762306a36Sopenharmony_ci{
84862306a36Sopenharmony_ci	int low_temp = 0 * 1000;
84962306a36Sopenharmony_ci	int high_temp = 255 * 1000;
85062306a36Sopenharmony_ci	u32 tmp;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	if (low_temp < min_temp)
85362306a36Sopenharmony_ci		low_temp = min_temp;
85462306a36Sopenharmony_ci	if (high_temp > max_temp)
85562306a36Sopenharmony_ci		high_temp = max_temp;
85662306a36Sopenharmony_ci	if (high_temp < low_temp) {
85762306a36Sopenharmony_ci		DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp);
85862306a36Sopenharmony_ci		return -EINVAL;
85962306a36Sopenharmony_ci	}
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	tmp = RREG32_SMC(CG_THERMAL_INT);
86262306a36Sopenharmony_ci	tmp &= ~(CI_DIG_THERM_INTH_MASK | CI_DIG_THERM_INTL_MASK);
86362306a36Sopenharmony_ci	tmp |= CI_DIG_THERM_INTH(high_temp / 1000) |
86462306a36Sopenharmony_ci		CI_DIG_THERM_INTL(low_temp / 1000);
86562306a36Sopenharmony_ci	WREG32_SMC(CG_THERMAL_INT, tmp);
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci#if 0
86862306a36Sopenharmony_ci	/* XXX: need to figure out how to handle this properly */
86962306a36Sopenharmony_ci	tmp = RREG32_SMC(CG_THERMAL_CTRL);
87062306a36Sopenharmony_ci	tmp &= DIG_THERM_DPM_MASK;
87162306a36Sopenharmony_ci	tmp |= DIG_THERM_DPM(high_temp / 1000);
87262306a36Sopenharmony_ci	WREG32_SMC(CG_THERMAL_CTRL, tmp);
87362306a36Sopenharmony_ci#endif
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	rdev->pm.dpm.thermal.min_temp = low_temp;
87662306a36Sopenharmony_ci	rdev->pm.dpm.thermal.max_temp = high_temp;
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	return 0;
87962306a36Sopenharmony_ci}
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_cistatic int ci_thermal_enable_alert(struct radeon_device *rdev,
88262306a36Sopenharmony_ci				   bool enable)
88362306a36Sopenharmony_ci{
88462306a36Sopenharmony_ci	u32 thermal_int = RREG32_SMC(CG_THERMAL_INT);
88562306a36Sopenharmony_ci	PPSMC_Result result;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	if (enable) {
88862306a36Sopenharmony_ci		thermal_int &= ~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
88962306a36Sopenharmony_ci		WREG32_SMC(CG_THERMAL_INT, thermal_int);
89062306a36Sopenharmony_ci		rdev->irq.dpm_thermal = false;
89162306a36Sopenharmony_ci		result = ci_send_msg_to_smc(rdev, PPSMC_MSG_Thermal_Cntl_Enable);
89262306a36Sopenharmony_ci		if (result != PPSMC_Result_OK) {
89362306a36Sopenharmony_ci			DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");
89462306a36Sopenharmony_ci			return -EINVAL;
89562306a36Sopenharmony_ci		}
89662306a36Sopenharmony_ci	} else {
89762306a36Sopenharmony_ci		thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW;
89862306a36Sopenharmony_ci		WREG32_SMC(CG_THERMAL_INT, thermal_int);
89962306a36Sopenharmony_ci		rdev->irq.dpm_thermal = true;
90062306a36Sopenharmony_ci		result = ci_send_msg_to_smc(rdev, PPSMC_MSG_Thermal_Cntl_Disable);
90162306a36Sopenharmony_ci		if (result != PPSMC_Result_OK) {
90262306a36Sopenharmony_ci			DRM_DEBUG_KMS("Could not disable thermal interrupts.\n");
90362306a36Sopenharmony_ci			return -EINVAL;
90462306a36Sopenharmony_ci		}
90562306a36Sopenharmony_ci	}
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	return 0;
90862306a36Sopenharmony_ci}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_cistatic void ci_fan_ctrl_set_static_mode(struct radeon_device *rdev, u32 mode)
91162306a36Sopenharmony_ci{
91262306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
91362306a36Sopenharmony_ci	u32 tmp;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	if (pi->fan_ctrl_is_in_default_mode) {
91662306a36Sopenharmony_ci		tmp = (RREG32_SMC(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK) >> FDO_PWM_MODE_SHIFT;
91762306a36Sopenharmony_ci		pi->fan_ctrl_default_mode = tmp;
91862306a36Sopenharmony_ci		tmp = (RREG32_SMC(CG_FDO_CTRL2) & TMIN_MASK) >> TMIN_SHIFT;
91962306a36Sopenharmony_ci		pi->t_min = tmp;
92062306a36Sopenharmony_ci		pi->fan_ctrl_is_in_default_mode = false;
92162306a36Sopenharmony_ci	}
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	tmp = RREG32_SMC(CG_FDO_CTRL2) & ~TMIN_MASK;
92462306a36Sopenharmony_ci	tmp |= TMIN(0);
92562306a36Sopenharmony_ci	WREG32_SMC(CG_FDO_CTRL2, tmp);
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	tmp = RREG32_SMC(CG_FDO_CTRL2) & ~FDO_PWM_MODE_MASK;
92862306a36Sopenharmony_ci	tmp |= FDO_PWM_MODE(mode);
92962306a36Sopenharmony_ci	WREG32_SMC(CG_FDO_CTRL2, tmp);
93062306a36Sopenharmony_ci}
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_cistatic int ci_thermal_setup_fan_table(struct radeon_device *rdev)
93362306a36Sopenharmony_ci{
93462306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
93562306a36Sopenharmony_ci	SMU7_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
93662306a36Sopenharmony_ci	u32 duty100;
93762306a36Sopenharmony_ci	u32 t_diff1, t_diff2, pwm_diff1, pwm_diff2;
93862306a36Sopenharmony_ci	u16 fdo_min, slope1, slope2;
93962306a36Sopenharmony_ci	u32 reference_clock, tmp;
94062306a36Sopenharmony_ci	int ret;
94162306a36Sopenharmony_ci	u64 tmp64;
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	if (!pi->fan_table_start) {
94462306a36Sopenharmony_ci		rdev->pm.dpm.fan.ucode_fan_control = false;
94562306a36Sopenharmony_ci		return 0;
94662306a36Sopenharmony_ci	}
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	duty100 = (RREG32_SMC(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	if (duty100 == 0) {
95162306a36Sopenharmony_ci		rdev->pm.dpm.fan.ucode_fan_control = false;
95262306a36Sopenharmony_ci		return 0;
95362306a36Sopenharmony_ci	}
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	tmp64 = (u64)rdev->pm.dpm.fan.pwm_min * duty100;
95662306a36Sopenharmony_ci	do_div(tmp64, 10000);
95762306a36Sopenharmony_ci	fdo_min = (u16)tmp64;
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	t_diff1 = rdev->pm.dpm.fan.t_med - rdev->pm.dpm.fan.t_min;
96062306a36Sopenharmony_ci	t_diff2 = rdev->pm.dpm.fan.t_high - rdev->pm.dpm.fan.t_med;
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	pwm_diff1 = rdev->pm.dpm.fan.pwm_med - rdev->pm.dpm.fan.pwm_min;
96362306a36Sopenharmony_ci	pwm_diff2 = rdev->pm.dpm.fan.pwm_high - rdev->pm.dpm.fan.pwm_med;
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	slope1 = (u16)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
96662306a36Sopenharmony_ci	slope2 = (u16)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	fan_table.TempMin = cpu_to_be16((50 + rdev->pm.dpm.fan.t_min) / 100);
96962306a36Sopenharmony_ci	fan_table.TempMed = cpu_to_be16((50 + rdev->pm.dpm.fan.t_med) / 100);
97062306a36Sopenharmony_ci	fan_table.TempMax = cpu_to_be16((50 + rdev->pm.dpm.fan.t_max) / 100);
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	fan_table.Slope1 = cpu_to_be16(slope1);
97362306a36Sopenharmony_ci	fan_table.Slope2 = cpu_to_be16(slope2);
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	fan_table.FdoMin = cpu_to_be16(fdo_min);
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	fan_table.HystDown = cpu_to_be16(rdev->pm.dpm.fan.t_hyst);
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	fan_table.HystUp = cpu_to_be16(1);
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	fan_table.HystSlope = cpu_to_be16(1);
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	fan_table.TempRespLim = cpu_to_be16(5);
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	reference_clock = radeon_get_xclk(rdev);
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	fan_table.RefreshPeriod = cpu_to_be32((rdev->pm.dpm.fan.cycle_delay *
98862306a36Sopenharmony_ci					       reference_clock) / 1600);
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	fan_table.FdoMax = cpu_to_be16((u16)duty100);
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	tmp = (RREG32_SMC(CG_MULT_THERMAL_CTRL) & TEMP_SEL_MASK) >> TEMP_SEL_SHIFT;
99362306a36Sopenharmony_ci	fan_table.TempSrc = (uint8_t)tmp;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	ret = ci_copy_bytes_to_smc(rdev,
99662306a36Sopenharmony_ci				   pi->fan_table_start,
99762306a36Sopenharmony_ci				   (u8 *)(&fan_table),
99862306a36Sopenharmony_ci				   sizeof(fan_table),
99962306a36Sopenharmony_ci				   pi->sram_end);
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	if (ret) {
100262306a36Sopenharmony_ci		DRM_ERROR("Failed to load fan table to the SMC.");
100362306a36Sopenharmony_ci		rdev->pm.dpm.fan.ucode_fan_control = false;
100462306a36Sopenharmony_ci	}
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	return 0;
100762306a36Sopenharmony_ci}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_cistatic int ci_fan_ctrl_start_smc_fan_control(struct radeon_device *rdev)
101062306a36Sopenharmony_ci{
101162306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
101262306a36Sopenharmony_ci	PPSMC_Result ret;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	if (pi->caps_od_fuzzy_fan_control_support) {
101562306a36Sopenharmony_ci		ret = ci_send_msg_to_smc_with_parameter(rdev,
101662306a36Sopenharmony_ci							PPSMC_StartFanControl,
101762306a36Sopenharmony_ci							FAN_CONTROL_FUZZY);
101862306a36Sopenharmony_ci		if (ret != PPSMC_Result_OK)
101962306a36Sopenharmony_ci			return -EINVAL;
102062306a36Sopenharmony_ci		ret = ci_send_msg_to_smc_with_parameter(rdev,
102162306a36Sopenharmony_ci							PPSMC_MSG_SetFanPwmMax,
102262306a36Sopenharmony_ci							rdev->pm.dpm.fan.default_max_fan_pwm);
102362306a36Sopenharmony_ci		if (ret != PPSMC_Result_OK)
102462306a36Sopenharmony_ci			return -EINVAL;
102562306a36Sopenharmony_ci	} else {
102662306a36Sopenharmony_ci		ret = ci_send_msg_to_smc_with_parameter(rdev,
102762306a36Sopenharmony_ci							PPSMC_StartFanControl,
102862306a36Sopenharmony_ci							FAN_CONTROL_TABLE);
102962306a36Sopenharmony_ci		if (ret != PPSMC_Result_OK)
103062306a36Sopenharmony_ci			return -EINVAL;
103162306a36Sopenharmony_ci	}
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	pi->fan_is_controlled_by_smc = true;
103462306a36Sopenharmony_ci	return 0;
103562306a36Sopenharmony_ci}
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_cistatic int ci_fan_ctrl_stop_smc_fan_control(struct radeon_device *rdev)
103862306a36Sopenharmony_ci{
103962306a36Sopenharmony_ci	PPSMC_Result ret;
104062306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	ret = ci_send_msg_to_smc(rdev, PPSMC_StopFanControl);
104362306a36Sopenharmony_ci	if (ret == PPSMC_Result_OK) {
104462306a36Sopenharmony_ci		pi->fan_is_controlled_by_smc = false;
104562306a36Sopenharmony_ci		return 0;
104662306a36Sopenharmony_ci	} else
104762306a36Sopenharmony_ci		return -EINVAL;
104862306a36Sopenharmony_ci}
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ciint ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
105162306a36Sopenharmony_ci					     u32 *speed)
105262306a36Sopenharmony_ci{
105362306a36Sopenharmony_ci	u32 duty, duty100;
105462306a36Sopenharmony_ci	u64 tmp64;
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	if (rdev->pm.no_fan)
105762306a36Sopenharmony_ci		return -ENOENT;
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	duty100 = (RREG32_SMC(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
106062306a36Sopenharmony_ci	duty = (RREG32_SMC(CG_THERMAL_STATUS) & FDO_PWM_DUTY_MASK) >> FDO_PWM_DUTY_SHIFT;
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	if (duty100 == 0)
106362306a36Sopenharmony_ci		return -EINVAL;
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	tmp64 = (u64)duty * 100;
106662306a36Sopenharmony_ci	do_div(tmp64, duty100);
106762306a36Sopenharmony_ci	*speed = (u32)tmp64;
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci	if (*speed > 100)
107062306a36Sopenharmony_ci		*speed = 100;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	return 0;
107362306a36Sopenharmony_ci}
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ciint ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
107662306a36Sopenharmony_ci					     u32 speed)
107762306a36Sopenharmony_ci{
107862306a36Sopenharmony_ci	u32 tmp;
107962306a36Sopenharmony_ci	u32 duty, duty100;
108062306a36Sopenharmony_ci	u64 tmp64;
108162306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	if (rdev->pm.no_fan)
108462306a36Sopenharmony_ci		return -ENOENT;
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	if (pi->fan_is_controlled_by_smc)
108762306a36Sopenharmony_ci		return -EINVAL;
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	if (speed > 100)
109062306a36Sopenharmony_ci		return -EINVAL;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	duty100 = (RREG32_SMC(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	if (duty100 == 0)
109562306a36Sopenharmony_ci		return -EINVAL;
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	tmp64 = (u64)speed * duty100;
109862306a36Sopenharmony_ci	do_div(tmp64, 100);
109962306a36Sopenharmony_ci	duty = (u32)tmp64;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	tmp = RREG32_SMC(CG_FDO_CTRL0) & ~FDO_STATIC_DUTY_MASK;
110262306a36Sopenharmony_ci	tmp |= FDO_STATIC_DUTY(duty);
110362306a36Sopenharmony_ci	WREG32_SMC(CG_FDO_CTRL0, tmp);
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	return 0;
110662306a36Sopenharmony_ci}
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_civoid ci_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode)
110962306a36Sopenharmony_ci{
111062306a36Sopenharmony_ci	if (mode) {
111162306a36Sopenharmony_ci		/* stop auto-manage */
111262306a36Sopenharmony_ci		if (rdev->pm.dpm.fan.ucode_fan_control)
111362306a36Sopenharmony_ci			ci_fan_ctrl_stop_smc_fan_control(rdev);
111462306a36Sopenharmony_ci		ci_fan_ctrl_set_static_mode(rdev, mode);
111562306a36Sopenharmony_ci	} else {
111662306a36Sopenharmony_ci		/* restart auto-manage */
111762306a36Sopenharmony_ci		if (rdev->pm.dpm.fan.ucode_fan_control)
111862306a36Sopenharmony_ci			ci_thermal_start_smc_fan_control(rdev);
111962306a36Sopenharmony_ci		else
112062306a36Sopenharmony_ci			ci_fan_ctrl_set_default_mode(rdev);
112162306a36Sopenharmony_ci	}
112262306a36Sopenharmony_ci}
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ciu32 ci_fan_ctrl_get_mode(struct radeon_device *rdev)
112562306a36Sopenharmony_ci{
112662306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
112762306a36Sopenharmony_ci	u32 tmp;
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	if (pi->fan_is_controlled_by_smc)
113062306a36Sopenharmony_ci		return 0;
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	tmp = RREG32_SMC(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK;
113362306a36Sopenharmony_ci	return (tmp >> FDO_PWM_MODE_SHIFT);
113462306a36Sopenharmony_ci}
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci#if 0
113762306a36Sopenharmony_cistatic int ci_fan_ctrl_get_fan_speed_rpm(struct radeon_device *rdev,
113862306a36Sopenharmony_ci					 u32 *speed)
113962306a36Sopenharmony_ci{
114062306a36Sopenharmony_ci	u32 tach_period;
114162306a36Sopenharmony_ci	u32 xclk = radeon_get_xclk(rdev);
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	if (rdev->pm.no_fan)
114462306a36Sopenharmony_ci		return -ENOENT;
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	if (rdev->pm.fan_pulses_per_revolution == 0)
114762306a36Sopenharmony_ci		return -ENOENT;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	tach_period = (RREG32_SMC(CG_TACH_STATUS) & TACH_PERIOD_MASK) >> TACH_PERIOD_SHIFT;
115062306a36Sopenharmony_ci	if (tach_period == 0)
115162306a36Sopenharmony_ci		return -ENOENT;
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	*speed = 60 * xclk * 10000 / tach_period;
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	return 0;
115662306a36Sopenharmony_ci}
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_cistatic int ci_fan_ctrl_set_fan_speed_rpm(struct radeon_device *rdev,
115962306a36Sopenharmony_ci					 u32 speed)
116062306a36Sopenharmony_ci{
116162306a36Sopenharmony_ci	u32 tach_period, tmp;
116262306a36Sopenharmony_ci	u32 xclk = radeon_get_xclk(rdev);
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	if (rdev->pm.no_fan)
116562306a36Sopenharmony_ci		return -ENOENT;
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci	if (rdev->pm.fan_pulses_per_revolution == 0)
116862306a36Sopenharmony_ci		return -ENOENT;
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	if ((speed < rdev->pm.fan_min_rpm) ||
117162306a36Sopenharmony_ci	    (speed > rdev->pm.fan_max_rpm))
117262306a36Sopenharmony_ci		return -EINVAL;
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	if (rdev->pm.dpm.fan.ucode_fan_control)
117562306a36Sopenharmony_ci		ci_fan_ctrl_stop_smc_fan_control(rdev);
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	tach_period = 60 * xclk * 10000 / (8 * speed);
117862306a36Sopenharmony_ci	tmp = RREG32_SMC(CG_TACH_CTRL) & ~TARGET_PERIOD_MASK;
117962306a36Sopenharmony_ci	tmp |= TARGET_PERIOD(tach_period);
118062306a36Sopenharmony_ci	WREG32_SMC(CG_TACH_CTRL, tmp);
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	ci_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC_RPM);
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	return 0;
118562306a36Sopenharmony_ci}
118662306a36Sopenharmony_ci#endif
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_cistatic void ci_fan_ctrl_set_default_mode(struct radeon_device *rdev)
118962306a36Sopenharmony_ci{
119062306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
119162306a36Sopenharmony_ci	u32 tmp;
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	if (!pi->fan_ctrl_is_in_default_mode) {
119462306a36Sopenharmony_ci		tmp = RREG32_SMC(CG_FDO_CTRL2) & ~FDO_PWM_MODE_MASK;
119562306a36Sopenharmony_ci		tmp |= FDO_PWM_MODE(pi->fan_ctrl_default_mode);
119662306a36Sopenharmony_ci		WREG32_SMC(CG_FDO_CTRL2, tmp);
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci		tmp = RREG32_SMC(CG_FDO_CTRL2) & ~TMIN_MASK;
119962306a36Sopenharmony_ci		tmp |= TMIN(pi->t_min);
120062306a36Sopenharmony_ci		WREG32_SMC(CG_FDO_CTRL2, tmp);
120162306a36Sopenharmony_ci		pi->fan_ctrl_is_in_default_mode = true;
120262306a36Sopenharmony_ci	}
120362306a36Sopenharmony_ci}
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_cistatic void ci_thermal_start_smc_fan_control(struct radeon_device *rdev)
120662306a36Sopenharmony_ci{
120762306a36Sopenharmony_ci	if (rdev->pm.dpm.fan.ucode_fan_control) {
120862306a36Sopenharmony_ci		ci_fan_ctrl_start_smc_fan_control(rdev);
120962306a36Sopenharmony_ci		ci_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC);
121062306a36Sopenharmony_ci	}
121162306a36Sopenharmony_ci}
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_cistatic void ci_thermal_initialize(struct radeon_device *rdev)
121462306a36Sopenharmony_ci{
121562306a36Sopenharmony_ci	u32 tmp;
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	if (rdev->pm.fan_pulses_per_revolution) {
121862306a36Sopenharmony_ci		tmp = RREG32_SMC(CG_TACH_CTRL) & ~EDGE_PER_REV_MASK;
121962306a36Sopenharmony_ci		tmp |= EDGE_PER_REV(rdev->pm.fan_pulses_per_revolution -1);
122062306a36Sopenharmony_ci		WREG32_SMC(CG_TACH_CTRL, tmp);
122162306a36Sopenharmony_ci	}
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	tmp = RREG32_SMC(CG_FDO_CTRL2) & ~TACH_PWM_RESP_RATE_MASK;
122462306a36Sopenharmony_ci	tmp |= TACH_PWM_RESP_RATE(0x28);
122562306a36Sopenharmony_ci	WREG32_SMC(CG_FDO_CTRL2, tmp);
122662306a36Sopenharmony_ci}
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_cistatic int ci_thermal_start_thermal_controller(struct radeon_device *rdev)
122962306a36Sopenharmony_ci{
123062306a36Sopenharmony_ci	int ret;
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	ci_thermal_initialize(rdev);
123362306a36Sopenharmony_ci	ret = ci_thermal_set_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
123462306a36Sopenharmony_ci	if (ret)
123562306a36Sopenharmony_ci		return ret;
123662306a36Sopenharmony_ci	ret = ci_thermal_enable_alert(rdev, true);
123762306a36Sopenharmony_ci	if (ret)
123862306a36Sopenharmony_ci		return ret;
123962306a36Sopenharmony_ci	if (rdev->pm.dpm.fan.ucode_fan_control) {
124062306a36Sopenharmony_ci		ret = ci_thermal_setup_fan_table(rdev);
124162306a36Sopenharmony_ci		if (ret)
124262306a36Sopenharmony_ci			return ret;
124362306a36Sopenharmony_ci		ci_thermal_start_smc_fan_control(rdev);
124462306a36Sopenharmony_ci	}
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci	return 0;
124762306a36Sopenharmony_ci}
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_cistatic void ci_thermal_stop_thermal_controller(struct radeon_device *rdev)
125062306a36Sopenharmony_ci{
125162306a36Sopenharmony_ci	if (!rdev->pm.no_fan)
125262306a36Sopenharmony_ci		ci_fan_ctrl_set_default_mode(rdev);
125362306a36Sopenharmony_ci}
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci#if 0
125662306a36Sopenharmony_cistatic int ci_read_smc_soft_register(struct radeon_device *rdev,
125762306a36Sopenharmony_ci				     u16 reg_offset, u32 *value)
125862306a36Sopenharmony_ci{
125962306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	return ci_read_smc_sram_dword(rdev,
126262306a36Sopenharmony_ci				      pi->soft_regs_start + reg_offset,
126362306a36Sopenharmony_ci				      value, pi->sram_end);
126462306a36Sopenharmony_ci}
126562306a36Sopenharmony_ci#endif
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_cistatic int ci_write_smc_soft_register(struct radeon_device *rdev,
126862306a36Sopenharmony_ci				      u16 reg_offset, u32 value)
126962306a36Sopenharmony_ci{
127062306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	return ci_write_smc_sram_dword(rdev,
127362306a36Sopenharmony_ci				       pi->soft_regs_start + reg_offset,
127462306a36Sopenharmony_ci				       value, pi->sram_end);
127562306a36Sopenharmony_ci}
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_cistatic void ci_init_fps_limits(struct radeon_device *rdev)
127862306a36Sopenharmony_ci{
127962306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
128062306a36Sopenharmony_ci	SMU7_Discrete_DpmTable *table = &pi->smc_state_table;
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	if (pi->caps_fps) {
128362306a36Sopenharmony_ci		u16 tmp;
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci		tmp = 45;
128662306a36Sopenharmony_ci		table->FpsHighT = cpu_to_be16(tmp);
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci		tmp = 30;
128962306a36Sopenharmony_ci		table->FpsLowT = cpu_to_be16(tmp);
129062306a36Sopenharmony_ci	}
129162306a36Sopenharmony_ci}
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_cistatic int ci_update_sclk_t(struct radeon_device *rdev)
129462306a36Sopenharmony_ci{
129562306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
129662306a36Sopenharmony_ci	int ret = 0;
129762306a36Sopenharmony_ci	u32 low_sclk_interrupt_t = 0;
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci	if (pi->caps_sclk_throttle_low_notification) {
130062306a36Sopenharmony_ci		low_sclk_interrupt_t = cpu_to_be32(pi->low_sclk_interrupt_t);
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci		ret = ci_copy_bytes_to_smc(rdev,
130362306a36Sopenharmony_ci					   pi->dpm_table_start +
130462306a36Sopenharmony_ci					   offsetof(SMU7_Discrete_DpmTable, LowSclkInterruptT),
130562306a36Sopenharmony_ci					   (u8 *)&low_sclk_interrupt_t,
130662306a36Sopenharmony_ci					   sizeof(u32), pi->sram_end);
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	}
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	return ret;
131162306a36Sopenharmony_ci}
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_cistatic void ci_get_leakage_voltages(struct radeon_device *rdev)
131462306a36Sopenharmony_ci{
131562306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
131662306a36Sopenharmony_ci	u16 leakage_id, virtual_voltage_id;
131762306a36Sopenharmony_ci	u16 vddc, vddci;
131862306a36Sopenharmony_ci	int i;
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	pi->vddc_leakage.count = 0;
132162306a36Sopenharmony_ci	pi->vddci_leakage.count = 0;
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_EVV) {
132462306a36Sopenharmony_ci		for (i = 0; i < CISLANDS_MAX_LEAKAGE_COUNT; i++) {
132562306a36Sopenharmony_ci			virtual_voltage_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i;
132662306a36Sopenharmony_ci			if (radeon_atom_get_voltage_evv(rdev, virtual_voltage_id, &vddc) != 0)
132762306a36Sopenharmony_ci				continue;
132862306a36Sopenharmony_ci			if (vddc != 0 && vddc != virtual_voltage_id) {
132962306a36Sopenharmony_ci				pi->vddc_leakage.actual_voltage[pi->vddc_leakage.count] = vddc;
133062306a36Sopenharmony_ci				pi->vddc_leakage.leakage_id[pi->vddc_leakage.count] = virtual_voltage_id;
133162306a36Sopenharmony_ci				pi->vddc_leakage.count++;
133262306a36Sopenharmony_ci			}
133362306a36Sopenharmony_ci		}
133462306a36Sopenharmony_ci	} else if (radeon_atom_get_leakage_id_from_vbios(rdev, &leakage_id) == 0) {
133562306a36Sopenharmony_ci		for (i = 0; i < CISLANDS_MAX_LEAKAGE_COUNT; i++) {
133662306a36Sopenharmony_ci			virtual_voltage_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i;
133762306a36Sopenharmony_ci			if (radeon_atom_get_leakage_vddc_based_on_leakage_params(rdev, &vddc, &vddci,
133862306a36Sopenharmony_ci										 virtual_voltage_id,
133962306a36Sopenharmony_ci										 leakage_id) == 0) {
134062306a36Sopenharmony_ci				if (vddc != 0 && vddc != virtual_voltage_id) {
134162306a36Sopenharmony_ci					pi->vddc_leakage.actual_voltage[pi->vddc_leakage.count] = vddc;
134262306a36Sopenharmony_ci					pi->vddc_leakage.leakage_id[pi->vddc_leakage.count] = virtual_voltage_id;
134362306a36Sopenharmony_ci					pi->vddc_leakage.count++;
134462306a36Sopenharmony_ci				}
134562306a36Sopenharmony_ci				if (vddci != 0 && vddci != virtual_voltage_id) {
134662306a36Sopenharmony_ci					pi->vddci_leakage.actual_voltage[pi->vddci_leakage.count] = vddci;
134762306a36Sopenharmony_ci					pi->vddci_leakage.leakage_id[pi->vddci_leakage.count] = virtual_voltage_id;
134862306a36Sopenharmony_ci					pi->vddci_leakage.count++;
134962306a36Sopenharmony_ci				}
135062306a36Sopenharmony_ci			}
135162306a36Sopenharmony_ci		}
135262306a36Sopenharmony_ci	}
135362306a36Sopenharmony_ci}
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_cistatic void ci_set_dpm_event_sources(struct radeon_device *rdev, u32 sources)
135662306a36Sopenharmony_ci{
135762306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
135862306a36Sopenharmony_ci	bool want_thermal_protection;
135962306a36Sopenharmony_ci	u32 tmp;
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci	switch (sources) {
136262306a36Sopenharmony_ci	case 0:
136362306a36Sopenharmony_ci	default:
136462306a36Sopenharmony_ci		want_thermal_protection = false;
136562306a36Sopenharmony_ci		break;
136662306a36Sopenharmony_ci	case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL):
136762306a36Sopenharmony_ci		want_thermal_protection = true;
136862306a36Sopenharmony_ci		break;
136962306a36Sopenharmony_ci	case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL):
137062306a36Sopenharmony_ci		want_thermal_protection = true;
137162306a36Sopenharmony_ci		break;
137262306a36Sopenharmony_ci	case ((1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL) |
137362306a36Sopenharmony_ci	      (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL)):
137462306a36Sopenharmony_ci		want_thermal_protection = true;
137562306a36Sopenharmony_ci		break;
137662306a36Sopenharmony_ci	}
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci	if (want_thermal_protection) {
137962306a36Sopenharmony_ci		tmp = RREG32_SMC(GENERAL_PWRMGT);
138062306a36Sopenharmony_ci		if (pi->thermal_protection)
138162306a36Sopenharmony_ci			tmp &= ~THERMAL_PROTECTION_DIS;
138262306a36Sopenharmony_ci		else
138362306a36Sopenharmony_ci			tmp |= THERMAL_PROTECTION_DIS;
138462306a36Sopenharmony_ci		WREG32_SMC(GENERAL_PWRMGT, tmp);
138562306a36Sopenharmony_ci	} else {
138662306a36Sopenharmony_ci		tmp = RREG32_SMC(GENERAL_PWRMGT);
138762306a36Sopenharmony_ci		tmp |= THERMAL_PROTECTION_DIS;
138862306a36Sopenharmony_ci		WREG32_SMC(GENERAL_PWRMGT, tmp);
138962306a36Sopenharmony_ci	}
139062306a36Sopenharmony_ci}
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_cistatic void ci_enable_auto_throttle_source(struct radeon_device *rdev,
139362306a36Sopenharmony_ci					   enum radeon_dpm_auto_throttle_src source,
139462306a36Sopenharmony_ci					   bool enable)
139562306a36Sopenharmony_ci{
139662306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	if (enable) {
139962306a36Sopenharmony_ci		if (!(pi->active_auto_throttle_sources & (1 << source))) {
140062306a36Sopenharmony_ci			pi->active_auto_throttle_sources |= 1 << source;
140162306a36Sopenharmony_ci			ci_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources);
140262306a36Sopenharmony_ci		}
140362306a36Sopenharmony_ci	} else {
140462306a36Sopenharmony_ci		if (pi->active_auto_throttle_sources & (1 << source)) {
140562306a36Sopenharmony_ci			pi->active_auto_throttle_sources &= ~(1 << source);
140662306a36Sopenharmony_ci			ci_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources);
140762306a36Sopenharmony_ci		}
140862306a36Sopenharmony_ci	}
140962306a36Sopenharmony_ci}
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_cistatic void ci_enable_vr_hot_gpio_interrupt(struct radeon_device *rdev)
141262306a36Sopenharmony_ci{
141362306a36Sopenharmony_ci	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_REGULATOR_HOT)
141462306a36Sopenharmony_ci		ci_send_msg_to_smc(rdev, PPSMC_MSG_EnableVRHotGPIOInterrupt);
141562306a36Sopenharmony_ci}
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_cistatic int ci_unfreeze_sclk_mclk_dpm(struct radeon_device *rdev)
141862306a36Sopenharmony_ci{
141962306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
142062306a36Sopenharmony_ci	PPSMC_Result smc_result;
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	if (!pi->need_update_smu7_dpm_table)
142362306a36Sopenharmony_ci		return 0;
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci	if ((!pi->sclk_dpm_key_disabled) &&
142662306a36Sopenharmony_ci	    (pi->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_UPDATE_SCLK))) {
142762306a36Sopenharmony_ci		smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_SCLKDPM_UnfreezeLevel);
142862306a36Sopenharmony_ci		if (smc_result != PPSMC_Result_OK)
142962306a36Sopenharmony_ci			return -EINVAL;
143062306a36Sopenharmony_ci	}
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	if ((!pi->mclk_dpm_key_disabled) &&
143362306a36Sopenharmony_ci	    (pi->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)) {
143462306a36Sopenharmony_ci		smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_MCLKDPM_UnfreezeLevel);
143562306a36Sopenharmony_ci		if (smc_result != PPSMC_Result_OK)
143662306a36Sopenharmony_ci			return -EINVAL;
143762306a36Sopenharmony_ci	}
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	pi->need_update_smu7_dpm_table = 0;
144062306a36Sopenharmony_ci	return 0;
144162306a36Sopenharmony_ci}
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_cistatic int ci_enable_sclk_mclk_dpm(struct radeon_device *rdev, bool enable)
144462306a36Sopenharmony_ci{
144562306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
144662306a36Sopenharmony_ci	PPSMC_Result smc_result;
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci	if (enable) {
144962306a36Sopenharmony_ci		if (!pi->sclk_dpm_key_disabled) {
145062306a36Sopenharmony_ci			smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_DPM_Enable);
145162306a36Sopenharmony_ci			if (smc_result != PPSMC_Result_OK)
145262306a36Sopenharmony_ci				return -EINVAL;
145362306a36Sopenharmony_ci		}
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci		if (!pi->mclk_dpm_key_disabled) {
145662306a36Sopenharmony_ci			smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_MCLKDPM_Enable);
145762306a36Sopenharmony_ci			if (smc_result != PPSMC_Result_OK)
145862306a36Sopenharmony_ci				return -EINVAL;
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci			WREG32_P(MC_SEQ_CNTL_3, CAC_EN, ~CAC_EN);
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci			WREG32_SMC(LCAC_MC0_CNTL, 0x05);
146362306a36Sopenharmony_ci			WREG32_SMC(LCAC_MC1_CNTL, 0x05);
146462306a36Sopenharmony_ci			WREG32_SMC(LCAC_CPL_CNTL, 0x100005);
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci			udelay(10);
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci			WREG32_SMC(LCAC_MC0_CNTL, 0x400005);
146962306a36Sopenharmony_ci			WREG32_SMC(LCAC_MC1_CNTL, 0x400005);
147062306a36Sopenharmony_ci			WREG32_SMC(LCAC_CPL_CNTL, 0x500005);
147162306a36Sopenharmony_ci		}
147262306a36Sopenharmony_ci	} else {
147362306a36Sopenharmony_ci		if (!pi->sclk_dpm_key_disabled) {
147462306a36Sopenharmony_ci			smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_DPM_Disable);
147562306a36Sopenharmony_ci			if (smc_result != PPSMC_Result_OK)
147662306a36Sopenharmony_ci				return -EINVAL;
147762306a36Sopenharmony_ci		}
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci		if (!pi->mclk_dpm_key_disabled) {
148062306a36Sopenharmony_ci			smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_MCLKDPM_Disable);
148162306a36Sopenharmony_ci			if (smc_result != PPSMC_Result_OK)
148262306a36Sopenharmony_ci				return -EINVAL;
148362306a36Sopenharmony_ci		}
148462306a36Sopenharmony_ci	}
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	return 0;
148762306a36Sopenharmony_ci}
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_cistatic int ci_start_dpm(struct radeon_device *rdev)
149062306a36Sopenharmony_ci{
149162306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
149262306a36Sopenharmony_ci	PPSMC_Result smc_result;
149362306a36Sopenharmony_ci	int ret;
149462306a36Sopenharmony_ci	u32 tmp;
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	tmp = RREG32_SMC(GENERAL_PWRMGT);
149762306a36Sopenharmony_ci	tmp |= GLOBAL_PWRMGT_EN;
149862306a36Sopenharmony_ci	WREG32_SMC(GENERAL_PWRMGT, tmp);
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	tmp = RREG32_SMC(SCLK_PWRMGT_CNTL);
150162306a36Sopenharmony_ci	tmp |= DYNAMIC_PM_EN;
150262306a36Sopenharmony_ci	WREG32_SMC(SCLK_PWRMGT_CNTL, tmp);
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci	ci_write_smc_soft_register(rdev, offsetof(SMU7_SoftRegisters, VoltageChangeTimeout), 0x1000);
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	WREG32_P(BIF_LNCNT_RESET, 0, ~RESET_LNCNT_EN);
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_Voltage_Cntl_Enable);
150962306a36Sopenharmony_ci	if (smc_result != PPSMC_Result_OK)
151062306a36Sopenharmony_ci		return -EINVAL;
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ci	ret = ci_enable_sclk_mclk_dpm(rdev, true);
151362306a36Sopenharmony_ci	if (ret)
151462306a36Sopenharmony_ci		return ret;
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci	if (!pi->pcie_dpm_key_disabled) {
151762306a36Sopenharmony_ci		smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_PCIeDPM_Enable);
151862306a36Sopenharmony_ci		if (smc_result != PPSMC_Result_OK)
151962306a36Sopenharmony_ci			return -EINVAL;
152062306a36Sopenharmony_ci	}
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	return 0;
152362306a36Sopenharmony_ci}
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_cistatic int ci_freeze_sclk_mclk_dpm(struct radeon_device *rdev)
152662306a36Sopenharmony_ci{
152762306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
152862306a36Sopenharmony_ci	PPSMC_Result smc_result;
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	if (!pi->need_update_smu7_dpm_table)
153162306a36Sopenharmony_ci		return 0;
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	if ((!pi->sclk_dpm_key_disabled) &&
153462306a36Sopenharmony_ci	    (pi->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_UPDATE_SCLK))) {
153562306a36Sopenharmony_ci		smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_SCLKDPM_FreezeLevel);
153662306a36Sopenharmony_ci		if (smc_result != PPSMC_Result_OK)
153762306a36Sopenharmony_ci			return -EINVAL;
153862306a36Sopenharmony_ci	}
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci	if ((!pi->mclk_dpm_key_disabled) &&
154162306a36Sopenharmony_ci	    (pi->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)) {
154262306a36Sopenharmony_ci		smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_MCLKDPM_FreezeLevel);
154362306a36Sopenharmony_ci		if (smc_result != PPSMC_Result_OK)
154462306a36Sopenharmony_ci			return -EINVAL;
154562306a36Sopenharmony_ci	}
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci	return 0;
154862306a36Sopenharmony_ci}
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_cistatic int ci_stop_dpm(struct radeon_device *rdev)
155162306a36Sopenharmony_ci{
155262306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
155362306a36Sopenharmony_ci	PPSMC_Result smc_result;
155462306a36Sopenharmony_ci	int ret;
155562306a36Sopenharmony_ci	u32 tmp;
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci	tmp = RREG32_SMC(GENERAL_PWRMGT);
155862306a36Sopenharmony_ci	tmp &= ~GLOBAL_PWRMGT_EN;
155962306a36Sopenharmony_ci	WREG32_SMC(GENERAL_PWRMGT, tmp);
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci	tmp = RREG32_SMC(SCLK_PWRMGT_CNTL);
156262306a36Sopenharmony_ci	tmp &= ~DYNAMIC_PM_EN;
156362306a36Sopenharmony_ci	WREG32_SMC(SCLK_PWRMGT_CNTL, tmp);
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci	if (!pi->pcie_dpm_key_disabled) {
156662306a36Sopenharmony_ci		smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_PCIeDPM_Disable);
156762306a36Sopenharmony_ci		if (smc_result != PPSMC_Result_OK)
156862306a36Sopenharmony_ci			return -EINVAL;
156962306a36Sopenharmony_ci	}
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	ret = ci_enable_sclk_mclk_dpm(rdev, false);
157262306a36Sopenharmony_ci	if (ret)
157362306a36Sopenharmony_ci		return ret;
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_Voltage_Cntl_Disable);
157662306a36Sopenharmony_ci	if (smc_result != PPSMC_Result_OK)
157762306a36Sopenharmony_ci		return -EINVAL;
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	return 0;
158062306a36Sopenharmony_ci}
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_cistatic void ci_enable_sclk_control(struct radeon_device *rdev, bool enable)
158362306a36Sopenharmony_ci{
158462306a36Sopenharmony_ci	u32 tmp = RREG32_SMC(SCLK_PWRMGT_CNTL);
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci	if (enable)
158762306a36Sopenharmony_ci		tmp &= ~SCLK_PWRMGT_OFF;
158862306a36Sopenharmony_ci	else
158962306a36Sopenharmony_ci		tmp |= SCLK_PWRMGT_OFF;
159062306a36Sopenharmony_ci	WREG32_SMC(SCLK_PWRMGT_CNTL, tmp);
159162306a36Sopenharmony_ci}
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci#if 0
159462306a36Sopenharmony_cistatic int ci_notify_hw_of_power_source(struct radeon_device *rdev,
159562306a36Sopenharmony_ci					bool ac_power)
159662306a36Sopenharmony_ci{
159762306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
159862306a36Sopenharmony_ci	struct radeon_cac_tdp_table *cac_tdp_table =
159962306a36Sopenharmony_ci		rdev->pm.dpm.dyn_state.cac_tdp_table;
160062306a36Sopenharmony_ci	u32 power_limit;
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ci	if (ac_power)
160362306a36Sopenharmony_ci		power_limit = (u32)(cac_tdp_table->maximum_power_delivery_limit * 256);
160462306a36Sopenharmony_ci	else
160562306a36Sopenharmony_ci		power_limit = (u32)(cac_tdp_table->battery_power_limit * 256);
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci	ci_set_power_limit(rdev, power_limit);
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci	if (pi->caps_automatic_dc_transition) {
161062306a36Sopenharmony_ci		if (ac_power)
161162306a36Sopenharmony_ci			ci_send_msg_to_smc(rdev, PPSMC_MSG_RunningOnAC);
161262306a36Sopenharmony_ci		else
161362306a36Sopenharmony_ci			ci_send_msg_to_smc(rdev, PPSMC_MSG_Remove_DC_Clamp);
161462306a36Sopenharmony_ci	}
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci	return 0;
161762306a36Sopenharmony_ci}
161862306a36Sopenharmony_ci#endif
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_cistatic PPSMC_Result ci_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg)
162162306a36Sopenharmony_ci{
162262306a36Sopenharmony_ci	u32 tmp;
162362306a36Sopenharmony_ci	int i;
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	if (!ci_is_smc_running(rdev))
162662306a36Sopenharmony_ci		return PPSMC_Result_Failed;
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	WREG32(SMC_MESSAGE_0, msg);
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci	for (i = 0; i < rdev->usec_timeout; i++) {
163162306a36Sopenharmony_ci		tmp = RREG32(SMC_RESP_0);
163262306a36Sopenharmony_ci		if (tmp != 0)
163362306a36Sopenharmony_ci			break;
163462306a36Sopenharmony_ci		udelay(1);
163562306a36Sopenharmony_ci	}
163662306a36Sopenharmony_ci	tmp = RREG32(SMC_RESP_0);
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci	return (PPSMC_Result)tmp;
163962306a36Sopenharmony_ci}
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_cistatic PPSMC_Result ci_send_msg_to_smc_with_parameter(struct radeon_device *rdev,
164262306a36Sopenharmony_ci						      PPSMC_Msg msg, u32 parameter)
164362306a36Sopenharmony_ci{
164462306a36Sopenharmony_ci	WREG32(SMC_MSG_ARG_0, parameter);
164562306a36Sopenharmony_ci	return ci_send_msg_to_smc(rdev, msg);
164662306a36Sopenharmony_ci}
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_cistatic PPSMC_Result ci_send_msg_to_smc_return_parameter(struct radeon_device *rdev,
164962306a36Sopenharmony_ci							PPSMC_Msg msg, u32 *parameter)
165062306a36Sopenharmony_ci{
165162306a36Sopenharmony_ci	PPSMC_Result smc_result;
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci	smc_result = ci_send_msg_to_smc(rdev, msg);
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci	if ((smc_result == PPSMC_Result_OK) && parameter)
165662306a36Sopenharmony_ci		*parameter = RREG32(SMC_MSG_ARG_0);
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci	return smc_result;
165962306a36Sopenharmony_ci}
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_cistatic int ci_dpm_force_state_sclk(struct radeon_device *rdev, u32 n)
166262306a36Sopenharmony_ci{
166362306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci	if (!pi->sclk_dpm_key_disabled) {
166662306a36Sopenharmony_ci		PPSMC_Result smc_result =
166762306a36Sopenharmony_ci			ci_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SCLKDPM_SetEnabledMask, 1 << n);
166862306a36Sopenharmony_ci		if (smc_result != PPSMC_Result_OK)
166962306a36Sopenharmony_ci			return -EINVAL;
167062306a36Sopenharmony_ci	}
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	return 0;
167362306a36Sopenharmony_ci}
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_cistatic int ci_dpm_force_state_mclk(struct radeon_device *rdev, u32 n)
167662306a36Sopenharmony_ci{
167762306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci	if (!pi->mclk_dpm_key_disabled) {
168062306a36Sopenharmony_ci		PPSMC_Result smc_result =
168162306a36Sopenharmony_ci			ci_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_MCLKDPM_SetEnabledMask, 1 << n);
168262306a36Sopenharmony_ci		if (smc_result != PPSMC_Result_OK)
168362306a36Sopenharmony_ci			return -EINVAL;
168462306a36Sopenharmony_ci	}
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci	return 0;
168762306a36Sopenharmony_ci}
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_cistatic int ci_dpm_force_state_pcie(struct radeon_device *rdev, u32 n)
169062306a36Sopenharmony_ci{
169162306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci	if (!pi->pcie_dpm_key_disabled) {
169462306a36Sopenharmony_ci		PPSMC_Result smc_result =
169562306a36Sopenharmony_ci			ci_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_PCIeDPM_ForceLevel, n);
169662306a36Sopenharmony_ci		if (smc_result != PPSMC_Result_OK)
169762306a36Sopenharmony_ci			return -EINVAL;
169862306a36Sopenharmony_ci	}
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	return 0;
170162306a36Sopenharmony_ci}
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_cistatic int ci_set_power_limit(struct radeon_device *rdev, u32 n)
170462306a36Sopenharmony_ci{
170562306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_ci	if (pi->power_containment_features & POWERCONTAINMENT_FEATURE_PkgPwrLimit) {
170862306a36Sopenharmony_ci		PPSMC_Result smc_result =
170962306a36Sopenharmony_ci			ci_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_PkgPwrSetLimit, n);
171062306a36Sopenharmony_ci		if (smc_result != PPSMC_Result_OK)
171162306a36Sopenharmony_ci			return -EINVAL;
171262306a36Sopenharmony_ci	}
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_ci	return 0;
171562306a36Sopenharmony_ci}
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_cistatic int ci_set_overdrive_target_tdp(struct radeon_device *rdev,
171862306a36Sopenharmony_ci				       u32 target_tdp)
171962306a36Sopenharmony_ci{
172062306a36Sopenharmony_ci	PPSMC_Result smc_result =
172162306a36Sopenharmony_ci		ci_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_OverDriveSetTargetTdp, target_tdp);
172262306a36Sopenharmony_ci	if (smc_result != PPSMC_Result_OK)
172362306a36Sopenharmony_ci		return -EINVAL;
172462306a36Sopenharmony_ci	return 0;
172562306a36Sopenharmony_ci}
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci#if 0
172862306a36Sopenharmony_cistatic int ci_set_boot_state(struct radeon_device *rdev)
172962306a36Sopenharmony_ci{
173062306a36Sopenharmony_ci	return ci_enable_sclk_mclk_dpm(rdev, false);
173162306a36Sopenharmony_ci}
173262306a36Sopenharmony_ci#endif
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_cistatic u32 ci_get_average_sclk_freq(struct radeon_device *rdev)
173562306a36Sopenharmony_ci{
173662306a36Sopenharmony_ci	u32 sclk_freq;
173762306a36Sopenharmony_ci	PPSMC_Result smc_result =
173862306a36Sopenharmony_ci		ci_send_msg_to_smc_return_parameter(rdev,
173962306a36Sopenharmony_ci						    PPSMC_MSG_API_GetSclkFrequency,
174062306a36Sopenharmony_ci						    &sclk_freq);
174162306a36Sopenharmony_ci	if (smc_result != PPSMC_Result_OK)
174262306a36Sopenharmony_ci		sclk_freq = 0;
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_ci	return sclk_freq;
174562306a36Sopenharmony_ci}
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_cistatic u32 ci_get_average_mclk_freq(struct radeon_device *rdev)
174862306a36Sopenharmony_ci{
174962306a36Sopenharmony_ci	u32 mclk_freq;
175062306a36Sopenharmony_ci	PPSMC_Result smc_result =
175162306a36Sopenharmony_ci		ci_send_msg_to_smc_return_parameter(rdev,
175262306a36Sopenharmony_ci						    PPSMC_MSG_API_GetMclkFrequency,
175362306a36Sopenharmony_ci						    &mclk_freq);
175462306a36Sopenharmony_ci	if (smc_result != PPSMC_Result_OK)
175562306a36Sopenharmony_ci		mclk_freq = 0;
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	return mclk_freq;
175862306a36Sopenharmony_ci}
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_cistatic void ci_dpm_start_smc(struct radeon_device *rdev)
176162306a36Sopenharmony_ci{
176262306a36Sopenharmony_ci	int i;
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci	ci_program_jump_on_start(rdev);
176562306a36Sopenharmony_ci	ci_start_smc_clock(rdev);
176662306a36Sopenharmony_ci	ci_start_smc(rdev);
176762306a36Sopenharmony_ci	for (i = 0; i < rdev->usec_timeout; i++) {
176862306a36Sopenharmony_ci		if (RREG32_SMC(FIRMWARE_FLAGS) & INTERRUPTS_ENABLED)
176962306a36Sopenharmony_ci			break;
177062306a36Sopenharmony_ci	}
177162306a36Sopenharmony_ci}
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_cistatic void ci_dpm_stop_smc(struct radeon_device *rdev)
177462306a36Sopenharmony_ci{
177562306a36Sopenharmony_ci	ci_reset_smc(rdev);
177662306a36Sopenharmony_ci	ci_stop_smc_clock(rdev);
177762306a36Sopenharmony_ci}
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_cistatic int ci_process_firmware_header(struct radeon_device *rdev)
178062306a36Sopenharmony_ci{
178162306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
178262306a36Sopenharmony_ci	u32 tmp;
178362306a36Sopenharmony_ci	int ret;
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	ret = ci_read_smc_sram_dword(rdev,
178662306a36Sopenharmony_ci				     SMU7_FIRMWARE_HEADER_LOCATION +
178762306a36Sopenharmony_ci				     offsetof(SMU7_Firmware_Header, DpmTable),
178862306a36Sopenharmony_ci				     &tmp, pi->sram_end);
178962306a36Sopenharmony_ci	if (ret)
179062306a36Sopenharmony_ci		return ret;
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	pi->dpm_table_start = tmp;
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci	ret = ci_read_smc_sram_dword(rdev,
179562306a36Sopenharmony_ci				     SMU7_FIRMWARE_HEADER_LOCATION +
179662306a36Sopenharmony_ci				     offsetof(SMU7_Firmware_Header, SoftRegisters),
179762306a36Sopenharmony_ci				     &tmp, pi->sram_end);
179862306a36Sopenharmony_ci	if (ret)
179962306a36Sopenharmony_ci		return ret;
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci	pi->soft_regs_start = tmp;
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci	ret = ci_read_smc_sram_dword(rdev,
180462306a36Sopenharmony_ci				     SMU7_FIRMWARE_HEADER_LOCATION +
180562306a36Sopenharmony_ci				     offsetof(SMU7_Firmware_Header, mcRegisterTable),
180662306a36Sopenharmony_ci				     &tmp, pi->sram_end);
180762306a36Sopenharmony_ci	if (ret)
180862306a36Sopenharmony_ci		return ret;
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	pi->mc_reg_table_start = tmp;
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci	ret = ci_read_smc_sram_dword(rdev,
181362306a36Sopenharmony_ci				     SMU7_FIRMWARE_HEADER_LOCATION +
181462306a36Sopenharmony_ci				     offsetof(SMU7_Firmware_Header, FanTable),
181562306a36Sopenharmony_ci				     &tmp, pi->sram_end);
181662306a36Sopenharmony_ci	if (ret)
181762306a36Sopenharmony_ci		return ret;
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	pi->fan_table_start = tmp;
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci	ret = ci_read_smc_sram_dword(rdev,
182262306a36Sopenharmony_ci				     SMU7_FIRMWARE_HEADER_LOCATION +
182362306a36Sopenharmony_ci				     offsetof(SMU7_Firmware_Header, mcArbDramTimingTable),
182462306a36Sopenharmony_ci				     &tmp, pi->sram_end);
182562306a36Sopenharmony_ci	if (ret)
182662306a36Sopenharmony_ci		return ret;
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci	pi->arb_table_start = tmp;
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci	return 0;
183162306a36Sopenharmony_ci}
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_cistatic void ci_read_clock_registers(struct radeon_device *rdev)
183462306a36Sopenharmony_ci{
183562306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci	pi->clock_registers.cg_spll_func_cntl =
183862306a36Sopenharmony_ci		RREG32_SMC(CG_SPLL_FUNC_CNTL);
183962306a36Sopenharmony_ci	pi->clock_registers.cg_spll_func_cntl_2 =
184062306a36Sopenharmony_ci		RREG32_SMC(CG_SPLL_FUNC_CNTL_2);
184162306a36Sopenharmony_ci	pi->clock_registers.cg_spll_func_cntl_3 =
184262306a36Sopenharmony_ci		RREG32_SMC(CG_SPLL_FUNC_CNTL_3);
184362306a36Sopenharmony_ci	pi->clock_registers.cg_spll_func_cntl_4 =
184462306a36Sopenharmony_ci		RREG32_SMC(CG_SPLL_FUNC_CNTL_4);
184562306a36Sopenharmony_ci	pi->clock_registers.cg_spll_spread_spectrum =
184662306a36Sopenharmony_ci		RREG32_SMC(CG_SPLL_SPREAD_SPECTRUM);
184762306a36Sopenharmony_ci	pi->clock_registers.cg_spll_spread_spectrum_2 =
184862306a36Sopenharmony_ci		RREG32_SMC(CG_SPLL_SPREAD_SPECTRUM_2);
184962306a36Sopenharmony_ci	pi->clock_registers.dll_cntl = RREG32(DLL_CNTL);
185062306a36Sopenharmony_ci	pi->clock_registers.mclk_pwrmgt_cntl = RREG32(MCLK_PWRMGT_CNTL);
185162306a36Sopenharmony_ci	pi->clock_registers.mpll_ad_func_cntl = RREG32(MPLL_AD_FUNC_CNTL);
185262306a36Sopenharmony_ci	pi->clock_registers.mpll_dq_func_cntl = RREG32(MPLL_DQ_FUNC_CNTL);
185362306a36Sopenharmony_ci	pi->clock_registers.mpll_func_cntl = RREG32(MPLL_FUNC_CNTL);
185462306a36Sopenharmony_ci	pi->clock_registers.mpll_func_cntl_1 = RREG32(MPLL_FUNC_CNTL_1);
185562306a36Sopenharmony_ci	pi->clock_registers.mpll_func_cntl_2 = RREG32(MPLL_FUNC_CNTL_2);
185662306a36Sopenharmony_ci	pi->clock_registers.mpll_ss1 = RREG32(MPLL_SS1);
185762306a36Sopenharmony_ci	pi->clock_registers.mpll_ss2 = RREG32(MPLL_SS2);
185862306a36Sopenharmony_ci}
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_cistatic void ci_init_sclk_t(struct radeon_device *rdev)
186162306a36Sopenharmony_ci{
186262306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci	pi->low_sclk_interrupt_t = 0;
186562306a36Sopenharmony_ci}
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_cistatic void ci_enable_thermal_protection(struct radeon_device *rdev,
186862306a36Sopenharmony_ci					 bool enable)
186962306a36Sopenharmony_ci{
187062306a36Sopenharmony_ci	u32 tmp = RREG32_SMC(GENERAL_PWRMGT);
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_ci	if (enable)
187362306a36Sopenharmony_ci		tmp &= ~THERMAL_PROTECTION_DIS;
187462306a36Sopenharmony_ci	else
187562306a36Sopenharmony_ci		tmp |= THERMAL_PROTECTION_DIS;
187662306a36Sopenharmony_ci	WREG32_SMC(GENERAL_PWRMGT, tmp);
187762306a36Sopenharmony_ci}
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_cistatic void ci_enable_acpi_power_management(struct radeon_device *rdev)
188062306a36Sopenharmony_ci{
188162306a36Sopenharmony_ci	u32 tmp = RREG32_SMC(GENERAL_PWRMGT);
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci	tmp |= STATIC_PM_EN;
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci	WREG32_SMC(GENERAL_PWRMGT, tmp);
188662306a36Sopenharmony_ci}
188762306a36Sopenharmony_ci
188862306a36Sopenharmony_ci#if 0
188962306a36Sopenharmony_cistatic int ci_enter_ulp_state(struct radeon_device *rdev)
189062306a36Sopenharmony_ci{
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci	WREG32(SMC_MESSAGE_0, PPSMC_MSG_SwitchToMinimumPower);
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	udelay(25000);
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci	return 0;
189762306a36Sopenharmony_ci}
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_cistatic int ci_exit_ulp_state(struct radeon_device *rdev)
190062306a36Sopenharmony_ci{
190162306a36Sopenharmony_ci	int i;
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci	WREG32(SMC_MESSAGE_0, PPSMC_MSG_ResumeFromMinimumPower);
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	udelay(7000);
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci	for (i = 0; i < rdev->usec_timeout; i++) {
190862306a36Sopenharmony_ci		if (RREG32(SMC_RESP_0) == 1)
190962306a36Sopenharmony_ci			break;
191062306a36Sopenharmony_ci		udelay(1000);
191162306a36Sopenharmony_ci	}
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	return 0;
191462306a36Sopenharmony_ci}
191562306a36Sopenharmony_ci#endif
191662306a36Sopenharmony_ci
191762306a36Sopenharmony_cistatic int ci_notify_smc_display_change(struct radeon_device *rdev,
191862306a36Sopenharmony_ci					bool has_display)
191962306a36Sopenharmony_ci{
192062306a36Sopenharmony_ci	PPSMC_Msg msg = has_display ? PPSMC_MSG_HasDisplay : PPSMC_MSG_NoDisplay;
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci	return (ci_send_msg_to_smc(rdev, msg) == PPSMC_Result_OK) ?  0 : -EINVAL;
192362306a36Sopenharmony_ci}
192462306a36Sopenharmony_ci
192562306a36Sopenharmony_cistatic int ci_enable_ds_master_switch(struct radeon_device *rdev,
192662306a36Sopenharmony_ci				      bool enable)
192762306a36Sopenharmony_ci{
192862306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci	if (enable) {
193162306a36Sopenharmony_ci		if (pi->caps_sclk_ds) {
193262306a36Sopenharmony_ci			if (ci_send_msg_to_smc(rdev, PPSMC_MSG_MASTER_DeepSleep_ON) != PPSMC_Result_OK)
193362306a36Sopenharmony_ci				return -EINVAL;
193462306a36Sopenharmony_ci		} else {
193562306a36Sopenharmony_ci			if (ci_send_msg_to_smc(rdev, PPSMC_MSG_MASTER_DeepSleep_OFF) != PPSMC_Result_OK)
193662306a36Sopenharmony_ci				return -EINVAL;
193762306a36Sopenharmony_ci		}
193862306a36Sopenharmony_ci	} else {
193962306a36Sopenharmony_ci		if (pi->caps_sclk_ds) {
194062306a36Sopenharmony_ci			if (ci_send_msg_to_smc(rdev, PPSMC_MSG_MASTER_DeepSleep_OFF) != PPSMC_Result_OK)
194162306a36Sopenharmony_ci				return -EINVAL;
194262306a36Sopenharmony_ci		}
194362306a36Sopenharmony_ci	}
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_ci	return 0;
194662306a36Sopenharmony_ci}
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_cistatic void ci_program_display_gap(struct radeon_device *rdev)
194962306a36Sopenharmony_ci{
195062306a36Sopenharmony_ci	u32 tmp = RREG32_SMC(CG_DISPLAY_GAP_CNTL);
195162306a36Sopenharmony_ci	u32 pre_vbi_time_in_us;
195262306a36Sopenharmony_ci	u32 frame_time_in_us;
195362306a36Sopenharmony_ci	u32 ref_clock = rdev->clock.spll.reference_freq;
195462306a36Sopenharmony_ci	u32 refresh_rate = r600_dpm_get_vrefresh(rdev);
195562306a36Sopenharmony_ci	u32 vblank_time = r600_dpm_get_vblank_time(rdev);
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_ci	tmp &= ~DISP_GAP_MASK;
195862306a36Sopenharmony_ci	if (rdev->pm.dpm.new_active_crtc_count > 0)
195962306a36Sopenharmony_ci		tmp |= DISP_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM);
196062306a36Sopenharmony_ci	else
196162306a36Sopenharmony_ci		tmp |= DISP_GAP(R600_PM_DISPLAY_GAP_IGNORE);
196262306a36Sopenharmony_ci	WREG32_SMC(CG_DISPLAY_GAP_CNTL, tmp);
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci	if (refresh_rate == 0)
196562306a36Sopenharmony_ci		refresh_rate = 60;
196662306a36Sopenharmony_ci	if (vblank_time == 0xffffffff)
196762306a36Sopenharmony_ci		vblank_time = 500;
196862306a36Sopenharmony_ci	frame_time_in_us = 1000000 / refresh_rate;
196962306a36Sopenharmony_ci	pre_vbi_time_in_us =
197062306a36Sopenharmony_ci		frame_time_in_us - 200 - vblank_time;
197162306a36Sopenharmony_ci	tmp = pre_vbi_time_in_us * (ref_clock / 100);
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci	WREG32_SMC(CG_DISPLAY_GAP_CNTL2, tmp);
197462306a36Sopenharmony_ci	ci_write_smc_soft_register(rdev, offsetof(SMU7_SoftRegisters, PreVBlankGap), 0x64);
197562306a36Sopenharmony_ci	ci_write_smc_soft_register(rdev, offsetof(SMU7_SoftRegisters, VBlankTimeout), (frame_time_in_us - pre_vbi_time_in_us));
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci	ci_notify_smc_display_change(rdev, (rdev->pm.dpm.new_active_crtc_count == 1));
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci}
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_cistatic void ci_enable_spread_spectrum(struct radeon_device *rdev, bool enable)
198362306a36Sopenharmony_ci{
198462306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
198562306a36Sopenharmony_ci	u32 tmp;
198662306a36Sopenharmony_ci
198762306a36Sopenharmony_ci	if (enable) {
198862306a36Sopenharmony_ci		if (pi->caps_sclk_ss_support) {
198962306a36Sopenharmony_ci			tmp = RREG32_SMC(GENERAL_PWRMGT);
199062306a36Sopenharmony_ci			tmp |= DYN_SPREAD_SPECTRUM_EN;
199162306a36Sopenharmony_ci			WREG32_SMC(GENERAL_PWRMGT, tmp);
199262306a36Sopenharmony_ci		}
199362306a36Sopenharmony_ci	} else {
199462306a36Sopenharmony_ci		tmp = RREG32_SMC(CG_SPLL_SPREAD_SPECTRUM);
199562306a36Sopenharmony_ci		tmp &= ~SSEN;
199662306a36Sopenharmony_ci		WREG32_SMC(CG_SPLL_SPREAD_SPECTRUM, tmp);
199762306a36Sopenharmony_ci
199862306a36Sopenharmony_ci		tmp = RREG32_SMC(GENERAL_PWRMGT);
199962306a36Sopenharmony_ci		tmp &= ~DYN_SPREAD_SPECTRUM_EN;
200062306a36Sopenharmony_ci		WREG32_SMC(GENERAL_PWRMGT, tmp);
200162306a36Sopenharmony_ci	}
200262306a36Sopenharmony_ci}
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_cistatic void ci_program_sstp(struct radeon_device *rdev)
200562306a36Sopenharmony_ci{
200662306a36Sopenharmony_ci	WREG32_SMC(CG_SSP, (SSTU(R600_SSTU_DFLT) | SST(R600_SST_DFLT)));
200762306a36Sopenharmony_ci}
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_cistatic void ci_enable_display_gap(struct radeon_device *rdev)
201062306a36Sopenharmony_ci{
201162306a36Sopenharmony_ci	u32 tmp = RREG32_SMC(CG_DISPLAY_GAP_CNTL);
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_ci	tmp &= ~(DISP_GAP_MASK | DISP_GAP_MCHG_MASK);
201462306a36Sopenharmony_ci	tmp |= (DISP_GAP(R600_PM_DISPLAY_GAP_IGNORE) |
201562306a36Sopenharmony_ci		DISP_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK));
201662306a36Sopenharmony_ci
201762306a36Sopenharmony_ci	WREG32_SMC(CG_DISPLAY_GAP_CNTL, tmp);
201862306a36Sopenharmony_ci}
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_cistatic void ci_program_vc(struct radeon_device *rdev)
202162306a36Sopenharmony_ci{
202262306a36Sopenharmony_ci	u32 tmp;
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_ci	tmp = RREG32_SMC(SCLK_PWRMGT_CNTL);
202562306a36Sopenharmony_ci	tmp &= ~(RESET_SCLK_CNT | RESET_BUSY_CNT);
202662306a36Sopenharmony_ci	WREG32_SMC(SCLK_PWRMGT_CNTL, tmp);
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	WREG32_SMC(CG_FTV_0, CISLANDS_VRC_DFLT0);
202962306a36Sopenharmony_ci	WREG32_SMC(CG_FTV_1, CISLANDS_VRC_DFLT1);
203062306a36Sopenharmony_ci	WREG32_SMC(CG_FTV_2, CISLANDS_VRC_DFLT2);
203162306a36Sopenharmony_ci	WREG32_SMC(CG_FTV_3, CISLANDS_VRC_DFLT3);
203262306a36Sopenharmony_ci	WREG32_SMC(CG_FTV_4, CISLANDS_VRC_DFLT4);
203362306a36Sopenharmony_ci	WREG32_SMC(CG_FTV_5, CISLANDS_VRC_DFLT5);
203462306a36Sopenharmony_ci	WREG32_SMC(CG_FTV_6, CISLANDS_VRC_DFLT6);
203562306a36Sopenharmony_ci	WREG32_SMC(CG_FTV_7, CISLANDS_VRC_DFLT7);
203662306a36Sopenharmony_ci}
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_cistatic void ci_clear_vc(struct radeon_device *rdev)
203962306a36Sopenharmony_ci{
204062306a36Sopenharmony_ci	u32 tmp;
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci	tmp = RREG32_SMC(SCLK_PWRMGT_CNTL);
204362306a36Sopenharmony_ci	tmp |= (RESET_SCLK_CNT | RESET_BUSY_CNT);
204462306a36Sopenharmony_ci	WREG32_SMC(SCLK_PWRMGT_CNTL, tmp);
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci	WREG32_SMC(CG_FTV_0, 0);
204762306a36Sopenharmony_ci	WREG32_SMC(CG_FTV_1, 0);
204862306a36Sopenharmony_ci	WREG32_SMC(CG_FTV_2, 0);
204962306a36Sopenharmony_ci	WREG32_SMC(CG_FTV_3, 0);
205062306a36Sopenharmony_ci	WREG32_SMC(CG_FTV_4, 0);
205162306a36Sopenharmony_ci	WREG32_SMC(CG_FTV_5, 0);
205262306a36Sopenharmony_ci	WREG32_SMC(CG_FTV_6, 0);
205362306a36Sopenharmony_ci	WREG32_SMC(CG_FTV_7, 0);
205462306a36Sopenharmony_ci}
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_cistatic int ci_upload_firmware(struct radeon_device *rdev)
205762306a36Sopenharmony_ci{
205862306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
205962306a36Sopenharmony_ci	int i;
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci	for (i = 0; i < rdev->usec_timeout; i++) {
206262306a36Sopenharmony_ci		if (RREG32_SMC(RCU_UC_EVENTS) & BOOT_SEQ_DONE)
206362306a36Sopenharmony_ci			break;
206462306a36Sopenharmony_ci	}
206562306a36Sopenharmony_ci	WREG32_SMC(SMC_SYSCON_MISC_CNTL, 1);
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_ci	ci_stop_smc_clock(rdev);
206862306a36Sopenharmony_ci	ci_reset_smc(rdev);
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_ci	return ci_load_smc_ucode(rdev, pi->sram_end);
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_ci}
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_cistatic int ci_get_svi2_voltage_table(struct radeon_device *rdev,
207562306a36Sopenharmony_ci				     struct radeon_clock_voltage_dependency_table *voltage_dependency_table,
207662306a36Sopenharmony_ci				     struct atom_voltage_table *voltage_table)
207762306a36Sopenharmony_ci{
207862306a36Sopenharmony_ci	u32 i;
207962306a36Sopenharmony_ci
208062306a36Sopenharmony_ci	if (voltage_dependency_table == NULL)
208162306a36Sopenharmony_ci		return -EINVAL;
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_ci	voltage_table->mask_low = 0;
208462306a36Sopenharmony_ci	voltage_table->phase_delay = 0;
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci	voltage_table->count = voltage_dependency_table->count;
208762306a36Sopenharmony_ci	for (i = 0; i < voltage_table->count; i++) {
208862306a36Sopenharmony_ci		voltage_table->entries[i].value = voltage_dependency_table->entries[i].v;
208962306a36Sopenharmony_ci		voltage_table->entries[i].smio_low = 0;
209062306a36Sopenharmony_ci	}
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ci	return 0;
209362306a36Sopenharmony_ci}
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_cistatic int ci_construct_voltage_tables(struct radeon_device *rdev)
209662306a36Sopenharmony_ci{
209762306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
209862306a36Sopenharmony_ci	int ret;
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci	if (pi->voltage_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO) {
210162306a36Sopenharmony_ci		ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_VDDC,
210262306a36Sopenharmony_ci						    VOLTAGE_OBJ_GPIO_LUT,
210362306a36Sopenharmony_ci						    &pi->vddc_voltage_table);
210462306a36Sopenharmony_ci		if (ret)
210562306a36Sopenharmony_ci			return ret;
210662306a36Sopenharmony_ci	} else if (pi->voltage_control == CISLANDS_VOLTAGE_CONTROL_BY_SVID2) {
210762306a36Sopenharmony_ci		ret = ci_get_svi2_voltage_table(rdev,
210862306a36Sopenharmony_ci						&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
210962306a36Sopenharmony_ci						&pi->vddc_voltage_table);
211062306a36Sopenharmony_ci		if (ret)
211162306a36Sopenharmony_ci			return ret;
211262306a36Sopenharmony_ci	}
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_ci	if (pi->vddc_voltage_table.count > SMU7_MAX_LEVELS_VDDC)
211562306a36Sopenharmony_ci		si_trim_voltage_table_to_fit_state_table(rdev, SMU7_MAX_LEVELS_VDDC,
211662306a36Sopenharmony_ci							 &pi->vddc_voltage_table);
211762306a36Sopenharmony_ci
211862306a36Sopenharmony_ci	if (pi->vddci_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO) {
211962306a36Sopenharmony_ci		ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_VDDCI,
212062306a36Sopenharmony_ci						    VOLTAGE_OBJ_GPIO_LUT,
212162306a36Sopenharmony_ci						    &pi->vddci_voltage_table);
212262306a36Sopenharmony_ci		if (ret)
212362306a36Sopenharmony_ci			return ret;
212462306a36Sopenharmony_ci	} else if (pi->vddci_control == CISLANDS_VOLTAGE_CONTROL_BY_SVID2) {
212562306a36Sopenharmony_ci		ret = ci_get_svi2_voltage_table(rdev,
212662306a36Sopenharmony_ci						&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
212762306a36Sopenharmony_ci						&pi->vddci_voltage_table);
212862306a36Sopenharmony_ci		if (ret)
212962306a36Sopenharmony_ci			return ret;
213062306a36Sopenharmony_ci	}
213162306a36Sopenharmony_ci
213262306a36Sopenharmony_ci	if (pi->vddci_voltage_table.count > SMU7_MAX_LEVELS_VDDCI)
213362306a36Sopenharmony_ci		si_trim_voltage_table_to_fit_state_table(rdev, SMU7_MAX_LEVELS_VDDCI,
213462306a36Sopenharmony_ci							 &pi->vddci_voltage_table);
213562306a36Sopenharmony_ci
213662306a36Sopenharmony_ci	if (pi->mvdd_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO) {
213762306a36Sopenharmony_ci		ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_MVDDC,
213862306a36Sopenharmony_ci						    VOLTAGE_OBJ_GPIO_LUT,
213962306a36Sopenharmony_ci						    &pi->mvdd_voltage_table);
214062306a36Sopenharmony_ci		if (ret)
214162306a36Sopenharmony_ci			return ret;
214262306a36Sopenharmony_ci	} else if (pi->mvdd_control == CISLANDS_VOLTAGE_CONTROL_BY_SVID2) {
214362306a36Sopenharmony_ci		ret = ci_get_svi2_voltage_table(rdev,
214462306a36Sopenharmony_ci						&rdev->pm.dpm.dyn_state.mvdd_dependency_on_mclk,
214562306a36Sopenharmony_ci						&pi->mvdd_voltage_table);
214662306a36Sopenharmony_ci		if (ret)
214762306a36Sopenharmony_ci			return ret;
214862306a36Sopenharmony_ci	}
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci	if (pi->mvdd_voltage_table.count > SMU7_MAX_LEVELS_MVDD)
215162306a36Sopenharmony_ci		si_trim_voltage_table_to_fit_state_table(rdev, SMU7_MAX_LEVELS_MVDD,
215262306a36Sopenharmony_ci							 &pi->mvdd_voltage_table);
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci	return 0;
215562306a36Sopenharmony_ci}
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_cistatic void ci_populate_smc_voltage_table(struct radeon_device *rdev,
215862306a36Sopenharmony_ci					  struct atom_voltage_table_entry *voltage_table,
215962306a36Sopenharmony_ci					  SMU7_Discrete_VoltageLevel *smc_voltage_table)
216062306a36Sopenharmony_ci{
216162306a36Sopenharmony_ci	int ret;
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_ci	ret = ci_get_std_voltage_value_sidd(rdev, voltage_table,
216462306a36Sopenharmony_ci					    &smc_voltage_table->StdVoltageHiSidd,
216562306a36Sopenharmony_ci					    &smc_voltage_table->StdVoltageLoSidd);
216662306a36Sopenharmony_ci
216762306a36Sopenharmony_ci	if (ret) {
216862306a36Sopenharmony_ci		smc_voltage_table->StdVoltageHiSidd = voltage_table->value * VOLTAGE_SCALE;
216962306a36Sopenharmony_ci		smc_voltage_table->StdVoltageLoSidd = voltage_table->value * VOLTAGE_SCALE;
217062306a36Sopenharmony_ci	}
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_ci	smc_voltage_table->Voltage = cpu_to_be16(voltage_table->value * VOLTAGE_SCALE);
217362306a36Sopenharmony_ci	smc_voltage_table->StdVoltageHiSidd =
217462306a36Sopenharmony_ci		cpu_to_be16(smc_voltage_table->StdVoltageHiSidd);
217562306a36Sopenharmony_ci	smc_voltage_table->StdVoltageLoSidd =
217662306a36Sopenharmony_ci		cpu_to_be16(smc_voltage_table->StdVoltageLoSidd);
217762306a36Sopenharmony_ci}
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_cistatic int ci_populate_smc_vddc_table(struct radeon_device *rdev,
218062306a36Sopenharmony_ci				      SMU7_Discrete_DpmTable *table)
218162306a36Sopenharmony_ci{
218262306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
218362306a36Sopenharmony_ci	unsigned int count;
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_ci	table->VddcLevelCount = pi->vddc_voltage_table.count;
218662306a36Sopenharmony_ci	for (count = 0; count < table->VddcLevelCount; count++) {
218762306a36Sopenharmony_ci		ci_populate_smc_voltage_table(rdev,
218862306a36Sopenharmony_ci					      &pi->vddc_voltage_table.entries[count],
218962306a36Sopenharmony_ci					      &table->VddcLevel[count]);
219062306a36Sopenharmony_ci
219162306a36Sopenharmony_ci		if (pi->voltage_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO)
219262306a36Sopenharmony_ci			table->VddcLevel[count].Smio |=
219362306a36Sopenharmony_ci				pi->vddc_voltage_table.entries[count].smio_low;
219462306a36Sopenharmony_ci		else
219562306a36Sopenharmony_ci			table->VddcLevel[count].Smio = 0;
219662306a36Sopenharmony_ci	}
219762306a36Sopenharmony_ci	table->VddcLevelCount = cpu_to_be32(table->VddcLevelCount);
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci	return 0;
220062306a36Sopenharmony_ci}
220162306a36Sopenharmony_ci
220262306a36Sopenharmony_cistatic int ci_populate_smc_vddci_table(struct radeon_device *rdev,
220362306a36Sopenharmony_ci				       SMU7_Discrete_DpmTable *table)
220462306a36Sopenharmony_ci{
220562306a36Sopenharmony_ci	unsigned int count;
220662306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
220762306a36Sopenharmony_ci
220862306a36Sopenharmony_ci	table->VddciLevelCount = pi->vddci_voltage_table.count;
220962306a36Sopenharmony_ci	for (count = 0; count < table->VddciLevelCount; count++) {
221062306a36Sopenharmony_ci		ci_populate_smc_voltage_table(rdev,
221162306a36Sopenharmony_ci					      &pi->vddci_voltage_table.entries[count],
221262306a36Sopenharmony_ci					      &table->VddciLevel[count]);
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci		if (pi->vddci_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO)
221562306a36Sopenharmony_ci			table->VddciLevel[count].Smio |=
221662306a36Sopenharmony_ci				pi->vddci_voltage_table.entries[count].smio_low;
221762306a36Sopenharmony_ci		else
221862306a36Sopenharmony_ci			table->VddciLevel[count].Smio = 0;
221962306a36Sopenharmony_ci	}
222062306a36Sopenharmony_ci	table->VddciLevelCount = cpu_to_be32(table->VddciLevelCount);
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci	return 0;
222362306a36Sopenharmony_ci}
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_cistatic int ci_populate_smc_mvdd_table(struct radeon_device *rdev,
222662306a36Sopenharmony_ci				      SMU7_Discrete_DpmTable *table)
222762306a36Sopenharmony_ci{
222862306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
222962306a36Sopenharmony_ci	unsigned int count;
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_ci	table->MvddLevelCount = pi->mvdd_voltage_table.count;
223262306a36Sopenharmony_ci	for (count = 0; count < table->MvddLevelCount; count++) {
223362306a36Sopenharmony_ci		ci_populate_smc_voltage_table(rdev,
223462306a36Sopenharmony_ci					      &pi->mvdd_voltage_table.entries[count],
223562306a36Sopenharmony_ci					      &table->MvddLevel[count]);
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci		if (pi->mvdd_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO)
223862306a36Sopenharmony_ci			table->MvddLevel[count].Smio |=
223962306a36Sopenharmony_ci				pi->mvdd_voltage_table.entries[count].smio_low;
224062306a36Sopenharmony_ci		else
224162306a36Sopenharmony_ci			table->MvddLevel[count].Smio = 0;
224262306a36Sopenharmony_ci	}
224362306a36Sopenharmony_ci	table->MvddLevelCount = cpu_to_be32(table->MvddLevelCount);
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_ci	return 0;
224662306a36Sopenharmony_ci}
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_cistatic int ci_populate_smc_voltage_tables(struct radeon_device *rdev,
224962306a36Sopenharmony_ci					  SMU7_Discrete_DpmTable *table)
225062306a36Sopenharmony_ci{
225162306a36Sopenharmony_ci	int ret;
225262306a36Sopenharmony_ci
225362306a36Sopenharmony_ci	ret = ci_populate_smc_vddc_table(rdev, table);
225462306a36Sopenharmony_ci	if (ret)
225562306a36Sopenharmony_ci		return ret;
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_ci	ret = ci_populate_smc_vddci_table(rdev, table);
225862306a36Sopenharmony_ci	if (ret)
225962306a36Sopenharmony_ci		return ret;
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_ci	ret = ci_populate_smc_mvdd_table(rdev, table);
226262306a36Sopenharmony_ci	if (ret)
226362306a36Sopenharmony_ci		return ret;
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci	return 0;
226662306a36Sopenharmony_ci}
226762306a36Sopenharmony_ci
226862306a36Sopenharmony_cistatic int ci_populate_mvdd_value(struct radeon_device *rdev, u32 mclk,
226962306a36Sopenharmony_ci				  SMU7_Discrete_VoltageLevel *voltage)
227062306a36Sopenharmony_ci{
227162306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
227262306a36Sopenharmony_ci	u32 i = 0;
227362306a36Sopenharmony_ci
227462306a36Sopenharmony_ci	if (pi->mvdd_control != CISLANDS_VOLTAGE_CONTROL_NONE) {
227562306a36Sopenharmony_ci		for (i = 0; i < rdev->pm.dpm.dyn_state.mvdd_dependency_on_mclk.count; i++) {
227662306a36Sopenharmony_ci			if (mclk <= rdev->pm.dpm.dyn_state.mvdd_dependency_on_mclk.entries[i].clk) {
227762306a36Sopenharmony_ci				voltage->Voltage = pi->mvdd_voltage_table.entries[i].value;
227862306a36Sopenharmony_ci				break;
227962306a36Sopenharmony_ci			}
228062306a36Sopenharmony_ci		}
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci		if (i >= rdev->pm.dpm.dyn_state.mvdd_dependency_on_mclk.count)
228362306a36Sopenharmony_ci			return -EINVAL;
228462306a36Sopenharmony_ci	}
228562306a36Sopenharmony_ci
228662306a36Sopenharmony_ci	return -EINVAL;
228762306a36Sopenharmony_ci}
228862306a36Sopenharmony_ci
228962306a36Sopenharmony_cistatic int ci_get_std_voltage_value_sidd(struct radeon_device *rdev,
229062306a36Sopenharmony_ci					 struct atom_voltage_table_entry *voltage_table,
229162306a36Sopenharmony_ci					 u16 *std_voltage_hi_sidd, u16 *std_voltage_lo_sidd)
229262306a36Sopenharmony_ci{
229362306a36Sopenharmony_ci	u16 v_index, idx;
229462306a36Sopenharmony_ci	bool voltage_found = false;
229562306a36Sopenharmony_ci	*std_voltage_hi_sidd = voltage_table->value * VOLTAGE_SCALE;
229662306a36Sopenharmony_ci	*std_voltage_lo_sidd = voltage_table->value * VOLTAGE_SCALE;
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_ci	if (rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries == NULL)
229962306a36Sopenharmony_ci		return -EINVAL;
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci	if (rdev->pm.dpm.dyn_state.cac_leakage_table.entries) {
230262306a36Sopenharmony_ci		for (v_index = 0; (u32)v_index < rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count; v_index++) {
230362306a36Sopenharmony_ci			if (voltage_table->value ==
230462306a36Sopenharmony_ci			    rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[v_index].v) {
230562306a36Sopenharmony_ci				voltage_found = true;
230662306a36Sopenharmony_ci				if ((u32)v_index < rdev->pm.dpm.dyn_state.cac_leakage_table.count)
230762306a36Sopenharmony_ci					idx = v_index;
230862306a36Sopenharmony_ci				else
230962306a36Sopenharmony_ci					idx = rdev->pm.dpm.dyn_state.cac_leakage_table.count - 1;
231062306a36Sopenharmony_ci				*std_voltage_lo_sidd =
231162306a36Sopenharmony_ci					rdev->pm.dpm.dyn_state.cac_leakage_table.entries[idx].vddc * VOLTAGE_SCALE;
231262306a36Sopenharmony_ci				*std_voltage_hi_sidd =
231362306a36Sopenharmony_ci					rdev->pm.dpm.dyn_state.cac_leakage_table.entries[idx].leakage * VOLTAGE_SCALE;
231462306a36Sopenharmony_ci				break;
231562306a36Sopenharmony_ci			}
231662306a36Sopenharmony_ci		}
231762306a36Sopenharmony_ci
231862306a36Sopenharmony_ci		if (!voltage_found) {
231962306a36Sopenharmony_ci			for (v_index = 0; (u32)v_index < rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count; v_index++) {
232062306a36Sopenharmony_ci				if (voltage_table->value <=
232162306a36Sopenharmony_ci				    rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[v_index].v) {
232262306a36Sopenharmony_ci					voltage_found = true;
232362306a36Sopenharmony_ci					if ((u32)v_index < rdev->pm.dpm.dyn_state.cac_leakage_table.count)
232462306a36Sopenharmony_ci						idx = v_index;
232562306a36Sopenharmony_ci					else
232662306a36Sopenharmony_ci						idx = rdev->pm.dpm.dyn_state.cac_leakage_table.count - 1;
232762306a36Sopenharmony_ci					*std_voltage_lo_sidd =
232862306a36Sopenharmony_ci						rdev->pm.dpm.dyn_state.cac_leakage_table.entries[idx].vddc * VOLTAGE_SCALE;
232962306a36Sopenharmony_ci					*std_voltage_hi_sidd =
233062306a36Sopenharmony_ci						rdev->pm.dpm.dyn_state.cac_leakage_table.entries[idx].leakage * VOLTAGE_SCALE;
233162306a36Sopenharmony_ci					break;
233262306a36Sopenharmony_ci				}
233362306a36Sopenharmony_ci			}
233462306a36Sopenharmony_ci		}
233562306a36Sopenharmony_ci	}
233662306a36Sopenharmony_ci
233762306a36Sopenharmony_ci	return 0;
233862306a36Sopenharmony_ci}
233962306a36Sopenharmony_ci
234062306a36Sopenharmony_cistatic void ci_populate_phase_value_based_on_sclk(struct radeon_device *rdev,
234162306a36Sopenharmony_ci						  const struct radeon_phase_shedding_limits_table *limits,
234262306a36Sopenharmony_ci						  u32 sclk,
234362306a36Sopenharmony_ci						  u32 *phase_shedding)
234462306a36Sopenharmony_ci{
234562306a36Sopenharmony_ci	unsigned int i;
234662306a36Sopenharmony_ci
234762306a36Sopenharmony_ci	*phase_shedding = 1;
234862306a36Sopenharmony_ci
234962306a36Sopenharmony_ci	for (i = 0; i < limits->count; i++) {
235062306a36Sopenharmony_ci		if (sclk < limits->entries[i].sclk) {
235162306a36Sopenharmony_ci			*phase_shedding = i;
235262306a36Sopenharmony_ci			break;
235362306a36Sopenharmony_ci		}
235462306a36Sopenharmony_ci	}
235562306a36Sopenharmony_ci}
235662306a36Sopenharmony_ci
235762306a36Sopenharmony_cistatic void ci_populate_phase_value_based_on_mclk(struct radeon_device *rdev,
235862306a36Sopenharmony_ci						  const struct radeon_phase_shedding_limits_table *limits,
235962306a36Sopenharmony_ci						  u32 mclk,
236062306a36Sopenharmony_ci						  u32 *phase_shedding)
236162306a36Sopenharmony_ci{
236262306a36Sopenharmony_ci	unsigned int i;
236362306a36Sopenharmony_ci
236462306a36Sopenharmony_ci	*phase_shedding = 1;
236562306a36Sopenharmony_ci
236662306a36Sopenharmony_ci	for (i = 0; i < limits->count; i++) {
236762306a36Sopenharmony_ci		if (mclk < limits->entries[i].mclk) {
236862306a36Sopenharmony_ci			*phase_shedding = i;
236962306a36Sopenharmony_ci			break;
237062306a36Sopenharmony_ci		}
237162306a36Sopenharmony_ci	}
237262306a36Sopenharmony_ci}
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_cistatic int ci_init_arb_table_index(struct radeon_device *rdev)
237562306a36Sopenharmony_ci{
237662306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
237762306a36Sopenharmony_ci	u32 tmp;
237862306a36Sopenharmony_ci	int ret;
237962306a36Sopenharmony_ci
238062306a36Sopenharmony_ci	ret = ci_read_smc_sram_dword(rdev, pi->arb_table_start,
238162306a36Sopenharmony_ci				     &tmp, pi->sram_end);
238262306a36Sopenharmony_ci	if (ret)
238362306a36Sopenharmony_ci		return ret;
238462306a36Sopenharmony_ci
238562306a36Sopenharmony_ci	tmp &= 0x00FFFFFF;
238662306a36Sopenharmony_ci	tmp |= MC_CG_ARB_FREQ_F1 << 24;
238762306a36Sopenharmony_ci
238862306a36Sopenharmony_ci	return ci_write_smc_sram_dword(rdev, pi->arb_table_start,
238962306a36Sopenharmony_ci				       tmp, pi->sram_end);
239062306a36Sopenharmony_ci}
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_cistatic int ci_get_dependency_volt_by_clk(struct radeon_device *rdev,
239362306a36Sopenharmony_ci					 struct radeon_clock_voltage_dependency_table *allowed_clock_voltage_table,
239462306a36Sopenharmony_ci					 u32 clock, u32 *voltage)
239562306a36Sopenharmony_ci{
239662306a36Sopenharmony_ci	u32 i = 0;
239762306a36Sopenharmony_ci
239862306a36Sopenharmony_ci	if (allowed_clock_voltage_table->count == 0)
239962306a36Sopenharmony_ci		return -EINVAL;
240062306a36Sopenharmony_ci
240162306a36Sopenharmony_ci	for (i = 0; i < allowed_clock_voltage_table->count; i++) {
240262306a36Sopenharmony_ci		if (allowed_clock_voltage_table->entries[i].clk >= clock) {
240362306a36Sopenharmony_ci			*voltage = allowed_clock_voltage_table->entries[i].v;
240462306a36Sopenharmony_ci			return 0;
240562306a36Sopenharmony_ci		}
240662306a36Sopenharmony_ci	}
240762306a36Sopenharmony_ci
240862306a36Sopenharmony_ci	*voltage = allowed_clock_voltage_table->entries[i-1].v;
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci	return 0;
241162306a36Sopenharmony_ci}
241262306a36Sopenharmony_ci
241362306a36Sopenharmony_cistatic u8 ci_get_sleep_divider_id_from_clock(struct radeon_device *rdev,
241462306a36Sopenharmony_ci					     u32 sclk, u32 min_sclk_in_sr)
241562306a36Sopenharmony_ci{
241662306a36Sopenharmony_ci	u32 i;
241762306a36Sopenharmony_ci	u32 tmp;
241862306a36Sopenharmony_ci	u32 min = (min_sclk_in_sr > CISLAND_MINIMUM_ENGINE_CLOCK) ?
241962306a36Sopenharmony_ci		min_sclk_in_sr : CISLAND_MINIMUM_ENGINE_CLOCK;
242062306a36Sopenharmony_ci
242162306a36Sopenharmony_ci	if (sclk < min)
242262306a36Sopenharmony_ci		return 0;
242362306a36Sopenharmony_ci
242462306a36Sopenharmony_ci	for (i = CISLAND_MAX_DEEPSLEEP_DIVIDER_ID;  ; i--) {
242562306a36Sopenharmony_ci		tmp = sclk / (1 << i);
242662306a36Sopenharmony_ci		if (tmp >= min || i == 0)
242762306a36Sopenharmony_ci			break;
242862306a36Sopenharmony_ci	}
242962306a36Sopenharmony_ci
243062306a36Sopenharmony_ci	return (u8)i;
243162306a36Sopenharmony_ci}
243262306a36Sopenharmony_ci
243362306a36Sopenharmony_cistatic int ci_initial_switch_from_arb_f0_to_f1(struct radeon_device *rdev)
243462306a36Sopenharmony_ci{
243562306a36Sopenharmony_ci	return ni_copy_and_switch_arb_sets(rdev, MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1);
243662306a36Sopenharmony_ci}
243762306a36Sopenharmony_ci
243862306a36Sopenharmony_cistatic int ci_reset_to_default(struct radeon_device *rdev)
243962306a36Sopenharmony_ci{
244062306a36Sopenharmony_ci	return (ci_send_msg_to_smc(rdev, PPSMC_MSG_ResetToDefaults) == PPSMC_Result_OK) ?
244162306a36Sopenharmony_ci		0 : -EINVAL;
244262306a36Sopenharmony_ci}
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_cistatic int ci_force_switch_to_arb_f0(struct radeon_device *rdev)
244562306a36Sopenharmony_ci{
244662306a36Sopenharmony_ci	u32 tmp;
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ci	tmp = (RREG32_SMC(SMC_SCRATCH9) & 0x0000ff00) >> 8;
244962306a36Sopenharmony_ci
245062306a36Sopenharmony_ci	if (tmp == MC_CG_ARB_FREQ_F0)
245162306a36Sopenharmony_ci		return 0;
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_ci	return ni_copy_and_switch_arb_sets(rdev, tmp, MC_CG_ARB_FREQ_F0);
245462306a36Sopenharmony_ci}
245562306a36Sopenharmony_ci
245662306a36Sopenharmony_cistatic void ci_register_patching_mc_arb(struct radeon_device *rdev,
245762306a36Sopenharmony_ci					const u32 engine_clock,
245862306a36Sopenharmony_ci					const u32 memory_clock,
245962306a36Sopenharmony_ci					u32 *dram_timimg2)
246062306a36Sopenharmony_ci{
246162306a36Sopenharmony_ci	bool patch;
246262306a36Sopenharmony_ci	u32 tmp, tmp2;
246362306a36Sopenharmony_ci
246462306a36Sopenharmony_ci	tmp = RREG32(MC_SEQ_MISC0);
246562306a36Sopenharmony_ci	patch = ((tmp & 0x0000f00) == 0x300) ? true : false;
246662306a36Sopenharmony_ci
246762306a36Sopenharmony_ci	if (patch &&
246862306a36Sopenharmony_ci	    ((rdev->pdev->device == 0x67B0) ||
246962306a36Sopenharmony_ci	     (rdev->pdev->device == 0x67B1))) {
247062306a36Sopenharmony_ci		if ((memory_clock > 100000) && (memory_clock <= 125000)) {
247162306a36Sopenharmony_ci			tmp2 = (((0x31 * engine_clock) / 125000) - 1) & 0xff;
247262306a36Sopenharmony_ci			*dram_timimg2 &= ~0x00ff0000;
247362306a36Sopenharmony_ci			*dram_timimg2 |= tmp2 << 16;
247462306a36Sopenharmony_ci		} else if ((memory_clock > 125000) && (memory_clock <= 137500)) {
247562306a36Sopenharmony_ci			tmp2 = (((0x36 * engine_clock) / 137500) - 1) & 0xff;
247662306a36Sopenharmony_ci			*dram_timimg2 &= ~0x00ff0000;
247762306a36Sopenharmony_ci			*dram_timimg2 |= tmp2 << 16;
247862306a36Sopenharmony_ci		}
247962306a36Sopenharmony_ci	}
248062306a36Sopenharmony_ci}
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_ci
248362306a36Sopenharmony_cistatic int ci_populate_memory_timing_parameters(struct radeon_device *rdev,
248462306a36Sopenharmony_ci						u32 sclk,
248562306a36Sopenharmony_ci						u32 mclk,
248662306a36Sopenharmony_ci						SMU7_Discrete_MCArbDramTimingTableEntry *arb_regs)
248762306a36Sopenharmony_ci{
248862306a36Sopenharmony_ci	u32 dram_timing;
248962306a36Sopenharmony_ci	u32 dram_timing2;
249062306a36Sopenharmony_ci	u32 burst_time;
249162306a36Sopenharmony_ci
249262306a36Sopenharmony_ci	radeon_atom_set_engine_dram_timings(rdev, sclk, mclk);
249362306a36Sopenharmony_ci
249462306a36Sopenharmony_ci	dram_timing  = RREG32(MC_ARB_DRAM_TIMING);
249562306a36Sopenharmony_ci	dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2);
249662306a36Sopenharmony_ci	burst_time = RREG32(MC_ARB_BURST_TIME) & STATE0_MASK;
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci	ci_register_patching_mc_arb(rdev, sclk, mclk, &dram_timing2);
249962306a36Sopenharmony_ci
250062306a36Sopenharmony_ci	arb_regs->McArbDramTiming  = cpu_to_be32(dram_timing);
250162306a36Sopenharmony_ci	arb_regs->McArbDramTiming2 = cpu_to_be32(dram_timing2);
250262306a36Sopenharmony_ci	arb_regs->McArbBurstTime = (u8)burst_time;
250362306a36Sopenharmony_ci
250462306a36Sopenharmony_ci	return 0;
250562306a36Sopenharmony_ci}
250662306a36Sopenharmony_ci
250762306a36Sopenharmony_cistatic int ci_do_program_memory_timing_parameters(struct radeon_device *rdev)
250862306a36Sopenharmony_ci{
250962306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
251062306a36Sopenharmony_ci	SMU7_Discrete_MCArbDramTimingTable arb_regs;
251162306a36Sopenharmony_ci	u32 i, j;
251262306a36Sopenharmony_ci	int ret =  0;
251362306a36Sopenharmony_ci
251462306a36Sopenharmony_ci	memset(&arb_regs, 0, sizeof(SMU7_Discrete_MCArbDramTimingTable));
251562306a36Sopenharmony_ci
251662306a36Sopenharmony_ci	for (i = 0; i < pi->dpm_table.sclk_table.count; i++) {
251762306a36Sopenharmony_ci		for (j = 0; j < pi->dpm_table.mclk_table.count; j++) {
251862306a36Sopenharmony_ci			ret = ci_populate_memory_timing_parameters(rdev,
251962306a36Sopenharmony_ci								   pi->dpm_table.sclk_table.dpm_levels[i].value,
252062306a36Sopenharmony_ci								   pi->dpm_table.mclk_table.dpm_levels[j].value,
252162306a36Sopenharmony_ci								   &arb_regs.entries[i][j]);
252262306a36Sopenharmony_ci			if (ret)
252362306a36Sopenharmony_ci				break;
252462306a36Sopenharmony_ci		}
252562306a36Sopenharmony_ci	}
252662306a36Sopenharmony_ci
252762306a36Sopenharmony_ci	if (ret == 0)
252862306a36Sopenharmony_ci		ret = ci_copy_bytes_to_smc(rdev,
252962306a36Sopenharmony_ci					   pi->arb_table_start,
253062306a36Sopenharmony_ci					   (u8 *)&arb_regs,
253162306a36Sopenharmony_ci					   sizeof(SMU7_Discrete_MCArbDramTimingTable),
253262306a36Sopenharmony_ci					   pi->sram_end);
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_ci	return ret;
253562306a36Sopenharmony_ci}
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_cistatic int ci_program_memory_timing_parameters(struct radeon_device *rdev)
253862306a36Sopenharmony_ci{
253962306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
254062306a36Sopenharmony_ci
254162306a36Sopenharmony_ci	if (pi->need_update_smu7_dpm_table == 0)
254262306a36Sopenharmony_ci		return 0;
254362306a36Sopenharmony_ci
254462306a36Sopenharmony_ci	return ci_do_program_memory_timing_parameters(rdev);
254562306a36Sopenharmony_ci}
254662306a36Sopenharmony_ci
254762306a36Sopenharmony_cistatic void ci_populate_smc_initial_state(struct radeon_device *rdev,
254862306a36Sopenharmony_ci					  struct radeon_ps *radeon_boot_state)
254962306a36Sopenharmony_ci{
255062306a36Sopenharmony_ci	struct ci_ps *boot_state = ci_get_ps(radeon_boot_state);
255162306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
255262306a36Sopenharmony_ci	u32 level = 0;
255362306a36Sopenharmony_ci
255462306a36Sopenharmony_ci	for (level = 0; level < rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count; level++) {
255562306a36Sopenharmony_ci		if (rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[level].clk >=
255662306a36Sopenharmony_ci		    boot_state->performance_levels[0].sclk) {
255762306a36Sopenharmony_ci			pi->smc_state_table.GraphicsBootLevel = level;
255862306a36Sopenharmony_ci			break;
255962306a36Sopenharmony_ci		}
256062306a36Sopenharmony_ci	}
256162306a36Sopenharmony_ci
256262306a36Sopenharmony_ci	for (level = 0; level < rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk.count; level++) {
256362306a36Sopenharmony_ci		if (rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries[level].clk >=
256462306a36Sopenharmony_ci		    boot_state->performance_levels[0].mclk) {
256562306a36Sopenharmony_ci			pi->smc_state_table.MemoryBootLevel = level;
256662306a36Sopenharmony_ci			break;
256762306a36Sopenharmony_ci		}
256862306a36Sopenharmony_ci	}
256962306a36Sopenharmony_ci}
257062306a36Sopenharmony_ci
257162306a36Sopenharmony_cistatic u32 ci_get_dpm_level_enable_mask_value(struct ci_single_dpm_table *dpm_table)
257262306a36Sopenharmony_ci{
257362306a36Sopenharmony_ci	u32 i;
257462306a36Sopenharmony_ci	u32 mask_value = 0;
257562306a36Sopenharmony_ci
257662306a36Sopenharmony_ci	for (i = dpm_table->count; i > 0; i--) {
257762306a36Sopenharmony_ci		mask_value = mask_value << 1;
257862306a36Sopenharmony_ci		if (dpm_table->dpm_levels[i-1].enabled)
257962306a36Sopenharmony_ci			mask_value |= 0x1;
258062306a36Sopenharmony_ci		else
258162306a36Sopenharmony_ci			mask_value &= 0xFFFFFFFE;
258262306a36Sopenharmony_ci	}
258362306a36Sopenharmony_ci
258462306a36Sopenharmony_ci	return mask_value;
258562306a36Sopenharmony_ci}
258662306a36Sopenharmony_ci
258762306a36Sopenharmony_cistatic void ci_populate_smc_link_level(struct radeon_device *rdev,
258862306a36Sopenharmony_ci				       SMU7_Discrete_DpmTable *table)
258962306a36Sopenharmony_ci{
259062306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
259162306a36Sopenharmony_ci	struct ci_dpm_table *dpm_table = &pi->dpm_table;
259262306a36Sopenharmony_ci	u32 i;
259362306a36Sopenharmony_ci
259462306a36Sopenharmony_ci	for (i = 0; i < dpm_table->pcie_speed_table.count; i++) {
259562306a36Sopenharmony_ci		table->LinkLevel[i].PcieGenSpeed =
259662306a36Sopenharmony_ci			(u8)dpm_table->pcie_speed_table.dpm_levels[i].value;
259762306a36Sopenharmony_ci		table->LinkLevel[i].PcieLaneCount =
259862306a36Sopenharmony_ci			r600_encode_pci_lane_width(dpm_table->pcie_speed_table.dpm_levels[i].param1);
259962306a36Sopenharmony_ci		table->LinkLevel[i].EnabledForActivity = 1;
260062306a36Sopenharmony_ci		table->LinkLevel[i].DownT = cpu_to_be32(5);
260162306a36Sopenharmony_ci		table->LinkLevel[i].UpT = cpu_to_be32(30);
260262306a36Sopenharmony_ci	}
260362306a36Sopenharmony_ci
260462306a36Sopenharmony_ci	pi->smc_state_table.LinkLevelCount = (u8)dpm_table->pcie_speed_table.count;
260562306a36Sopenharmony_ci	pi->dpm_level_enable_mask.pcie_dpm_enable_mask =
260662306a36Sopenharmony_ci		ci_get_dpm_level_enable_mask_value(&dpm_table->pcie_speed_table);
260762306a36Sopenharmony_ci}
260862306a36Sopenharmony_ci
260962306a36Sopenharmony_cistatic int ci_populate_smc_uvd_level(struct radeon_device *rdev,
261062306a36Sopenharmony_ci				     SMU7_Discrete_DpmTable *table)
261162306a36Sopenharmony_ci{
261262306a36Sopenharmony_ci	u32 count;
261362306a36Sopenharmony_ci	struct atom_clock_dividers dividers;
261462306a36Sopenharmony_ci	int ret = -EINVAL;
261562306a36Sopenharmony_ci
261662306a36Sopenharmony_ci	table->UvdLevelCount =
261762306a36Sopenharmony_ci		rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count;
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_ci	for (count = 0; count < table->UvdLevelCount; count++) {
262062306a36Sopenharmony_ci		table->UvdLevel[count].VclkFrequency =
262162306a36Sopenharmony_ci			rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[count].vclk;
262262306a36Sopenharmony_ci		table->UvdLevel[count].DclkFrequency =
262362306a36Sopenharmony_ci			rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[count].dclk;
262462306a36Sopenharmony_ci		table->UvdLevel[count].MinVddc =
262562306a36Sopenharmony_ci			rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[count].v * VOLTAGE_SCALE;
262662306a36Sopenharmony_ci		table->UvdLevel[count].MinVddcPhases = 1;
262762306a36Sopenharmony_ci
262862306a36Sopenharmony_ci		ret = radeon_atom_get_clock_dividers(rdev,
262962306a36Sopenharmony_ci						     COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
263062306a36Sopenharmony_ci						     table->UvdLevel[count].VclkFrequency, false, &dividers);
263162306a36Sopenharmony_ci		if (ret)
263262306a36Sopenharmony_ci			return ret;
263362306a36Sopenharmony_ci
263462306a36Sopenharmony_ci		table->UvdLevel[count].VclkDivider = (u8)dividers.post_divider;
263562306a36Sopenharmony_ci
263662306a36Sopenharmony_ci		ret = radeon_atom_get_clock_dividers(rdev,
263762306a36Sopenharmony_ci						     COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
263862306a36Sopenharmony_ci						     table->UvdLevel[count].DclkFrequency, false, &dividers);
263962306a36Sopenharmony_ci		if (ret)
264062306a36Sopenharmony_ci			return ret;
264162306a36Sopenharmony_ci
264262306a36Sopenharmony_ci		table->UvdLevel[count].DclkDivider = (u8)dividers.post_divider;
264362306a36Sopenharmony_ci
264462306a36Sopenharmony_ci		table->UvdLevel[count].VclkFrequency = cpu_to_be32(table->UvdLevel[count].VclkFrequency);
264562306a36Sopenharmony_ci		table->UvdLevel[count].DclkFrequency = cpu_to_be32(table->UvdLevel[count].DclkFrequency);
264662306a36Sopenharmony_ci		table->UvdLevel[count].MinVddc = cpu_to_be16(table->UvdLevel[count].MinVddc);
264762306a36Sopenharmony_ci	}
264862306a36Sopenharmony_ci
264962306a36Sopenharmony_ci	return ret;
265062306a36Sopenharmony_ci}
265162306a36Sopenharmony_ci
265262306a36Sopenharmony_cistatic int ci_populate_smc_vce_level(struct radeon_device *rdev,
265362306a36Sopenharmony_ci				     SMU7_Discrete_DpmTable *table)
265462306a36Sopenharmony_ci{
265562306a36Sopenharmony_ci	u32 count;
265662306a36Sopenharmony_ci	struct atom_clock_dividers dividers;
265762306a36Sopenharmony_ci	int ret = -EINVAL;
265862306a36Sopenharmony_ci
265962306a36Sopenharmony_ci	table->VceLevelCount =
266062306a36Sopenharmony_ci		rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.count;
266162306a36Sopenharmony_ci
266262306a36Sopenharmony_ci	for (count = 0; count < table->VceLevelCount; count++) {
266362306a36Sopenharmony_ci		table->VceLevel[count].Frequency =
266462306a36Sopenharmony_ci			rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[count].evclk;
266562306a36Sopenharmony_ci		table->VceLevel[count].MinVoltage =
266662306a36Sopenharmony_ci			(u16)rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[count].v * VOLTAGE_SCALE;
266762306a36Sopenharmony_ci		table->VceLevel[count].MinPhases = 1;
266862306a36Sopenharmony_ci
266962306a36Sopenharmony_ci		ret = radeon_atom_get_clock_dividers(rdev,
267062306a36Sopenharmony_ci						     COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
267162306a36Sopenharmony_ci						     table->VceLevel[count].Frequency, false, &dividers);
267262306a36Sopenharmony_ci		if (ret)
267362306a36Sopenharmony_ci			return ret;
267462306a36Sopenharmony_ci
267562306a36Sopenharmony_ci		table->VceLevel[count].Divider = (u8)dividers.post_divider;
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_ci		table->VceLevel[count].Frequency = cpu_to_be32(table->VceLevel[count].Frequency);
267862306a36Sopenharmony_ci		table->VceLevel[count].MinVoltage = cpu_to_be16(table->VceLevel[count].MinVoltage);
267962306a36Sopenharmony_ci	}
268062306a36Sopenharmony_ci
268162306a36Sopenharmony_ci	return ret;
268262306a36Sopenharmony_ci
268362306a36Sopenharmony_ci}
268462306a36Sopenharmony_ci
268562306a36Sopenharmony_cistatic int ci_populate_smc_acp_level(struct radeon_device *rdev,
268662306a36Sopenharmony_ci				     SMU7_Discrete_DpmTable *table)
268762306a36Sopenharmony_ci{
268862306a36Sopenharmony_ci	u32 count;
268962306a36Sopenharmony_ci	struct atom_clock_dividers dividers;
269062306a36Sopenharmony_ci	int ret = -EINVAL;
269162306a36Sopenharmony_ci
269262306a36Sopenharmony_ci	table->AcpLevelCount = (u8)
269362306a36Sopenharmony_ci		(rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.count);
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_ci	for (count = 0; count < table->AcpLevelCount; count++) {
269662306a36Sopenharmony_ci		table->AcpLevel[count].Frequency =
269762306a36Sopenharmony_ci			rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries[count].clk;
269862306a36Sopenharmony_ci		table->AcpLevel[count].MinVoltage =
269962306a36Sopenharmony_ci			rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries[count].v;
270062306a36Sopenharmony_ci		table->AcpLevel[count].MinPhases = 1;
270162306a36Sopenharmony_ci
270262306a36Sopenharmony_ci		ret = radeon_atom_get_clock_dividers(rdev,
270362306a36Sopenharmony_ci						     COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
270462306a36Sopenharmony_ci						     table->AcpLevel[count].Frequency, false, &dividers);
270562306a36Sopenharmony_ci		if (ret)
270662306a36Sopenharmony_ci			return ret;
270762306a36Sopenharmony_ci
270862306a36Sopenharmony_ci		table->AcpLevel[count].Divider = (u8)dividers.post_divider;
270962306a36Sopenharmony_ci
271062306a36Sopenharmony_ci		table->AcpLevel[count].Frequency = cpu_to_be32(table->AcpLevel[count].Frequency);
271162306a36Sopenharmony_ci		table->AcpLevel[count].MinVoltage = cpu_to_be16(table->AcpLevel[count].MinVoltage);
271262306a36Sopenharmony_ci	}
271362306a36Sopenharmony_ci
271462306a36Sopenharmony_ci	return ret;
271562306a36Sopenharmony_ci}
271662306a36Sopenharmony_ci
271762306a36Sopenharmony_cistatic int ci_populate_smc_samu_level(struct radeon_device *rdev,
271862306a36Sopenharmony_ci				      SMU7_Discrete_DpmTable *table)
271962306a36Sopenharmony_ci{
272062306a36Sopenharmony_ci	u32 count;
272162306a36Sopenharmony_ci	struct atom_clock_dividers dividers;
272262306a36Sopenharmony_ci	int ret = -EINVAL;
272362306a36Sopenharmony_ci
272462306a36Sopenharmony_ci	table->SamuLevelCount =
272562306a36Sopenharmony_ci		rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.count;
272662306a36Sopenharmony_ci
272762306a36Sopenharmony_ci	for (count = 0; count < table->SamuLevelCount; count++) {
272862306a36Sopenharmony_ci		table->SamuLevel[count].Frequency =
272962306a36Sopenharmony_ci			rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries[count].clk;
273062306a36Sopenharmony_ci		table->SamuLevel[count].MinVoltage =
273162306a36Sopenharmony_ci			rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries[count].v * VOLTAGE_SCALE;
273262306a36Sopenharmony_ci		table->SamuLevel[count].MinPhases = 1;
273362306a36Sopenharmony_ci
273462306a36Sopenharmony_ci		ret = radeon_atom_get_clock_dividers(rdev,
273562306a36Sopenharmony_ci						     COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
273662306a36Sopenharmony_ci						     table->SamuLevel[count].Frequency, false, &dividers);
273762306a36Sopenharmony_ci		if (ret)
273862306a36Sopenharmony_ci			return ret;
273962306a36Sopenharmony_ci
274062306a36Sopenharmony_ci		table->SamuLevel[count].Divider = (u8)dividers.post_divider;
274162306a36Sopenharmony_ci
274262306a36Sopenharmony_ci		table->SamuLevel[count].Frequency = cpu_to_be32(table->SamuLevel[count].Frequency);
274362306a36Sopenharmony_ci		table->SamuLevel[count].MinVoltage = cpu_to_be16(table->SamuLevel[count].MinVoltage);
274462306a36Sopenharmony_ci	}
274562306a36Sopenharmony_ci
274662306a36Sopenharmony_ci	return ret;
274762306a36Sopenharmony_ci}
274862306a36Sopenharmony_ci
274962306a36Sopenharmony_cistatic int ci_calculate_mclk_params(struct radeon_device *rdev,
275062306a36Sopenharmony_ci				    u32 memory_clock,
275162306a36Sopenharmony_ci				    SMU7_Discrete_MemoryLevel *mclk,
275262306a36Sopenharmony_ci				    bool strobe_mode,
275362306a36Sopenharmony_ci				    bool dll_state_on)
275462306a36Sopenharmony_ci{
275562306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
275662306a36Sopenharmony_ci	u32  dll_cntl = pi->clock_registers.dll_cntl;
275762306a36Sopenharmony_ci	u32  mclk_pwrmgt_cntl = pi->clock_registers.mclk_pwrmgt_cntl;
275862306a36Sopenharmony_ci	u32  mpll_ad_func_cntl = pi->clock_registers.mpll_ad_func_cntl;
275962306a36Sopenharmony_ci	u32  mpll_dq_func_cntl = pi->clock_registers.mpll_dq_func_cntl;
276062306a36Sopenharmony_ci	u32  mpll_func_cntl = pi->clock_registers.mpll_func_cntl;
276162306a36Sopenharmony_ci	u32  mpll_func_cntl_1 = pi->clock_registers.mpll_func_cntl_1;
276262306a36Sopenharmony_ci	u32  mpll_func_cntl_2 = pi->clock_registers.mpll_func_cntl_2;
276362306a36Sopenharmony_ci	u32  mpll_ss1 = pi->clock_registers.mpll_ss1;
276462306a36Sopenharmony_ci	u32  mpll_ss2 = pi->clock_registers.mpll_ss2;
276562306a36Sopenharmony_ci	struct atom_mpll_param mpll_param;
276662306a36Sopenharmony_ci	int ret;
276762306a36Sopenharmony_ci
276862306a36Sopenharmony_ci	ret = radeon_atom_get_memory_pll_dividers(rdev, memory_clock, strobe_mode, &mpll_param);
276962306a36Sopenharmony_ci	if (ret)
277062306a36Sopenharmony_ci		return ret;
277162306a36Sopenharmony_ci
277262306a36Sopenharmony_ci	mpll_func_cntl &= ~BWCTRL_MASK;
277362306a36Sopenharmony_ci	mpll_func_cntl |= BWCTRL(mpll_param.bwcntl);
277462306a36Sopenharmony_ci
277562306a36Sopenharmony_ci	mpll_func_cntl_1 &= ~(CLKF_MASK | CLKFRAC_MASK | VCO_MODE_MASK);
277662306a36Sopenharmony_ci	mpll_func_cntl_1 |= CLKF(mpll_param.clkf) |
277762306a36Sopenharmony_ci		CLKFRAC(mpll_param.clkfrac) | VCO_MODE(mpll_param.vco_mode);
277862306a36Sopenharmony_ci
277962306a36Sopenharmony_ci	mpll_ad_func_cntl &= ~YCLK_POST_DIV_MASK;
278062306a36Sopenharmony_ci	mpll_ad_func_cntl |= YCLK_POST_DIV(mpll_param.post_div);
278162306a36Sopenharmony_ci
278262306a36Sopenharmony_ci	if (pi->mem_gddr5) {
278362306a36Sopenharmony_ci		mpll_dq_func_cntl &= ~(YCLK_SEL_MASK | YCLK_POST_DIV_MASK);
278462306a36Sopenharmony_ci		mpll_dq_func_cntl |= YCLK_SEL(mpll_param.yclk_sel) |
278562306a36Sopenharmony_ci			YCLK_POST_DIV(mpll_param.post_div);
278662306a36Sopenharmony_ci	}
278762306a36Sopenharmony_ci
278862306a36Sopenharmony_ci	if (pi->caps_mclk_ss_support) {
278962306a36Sopenharmony_ci		struct radeon_atom_ss ss;
279062306a36Sopenharmony_ci		u32 freq_nom;
279162306a36Sopenharmony_ci		u32 tmp;
279262306a36Sopenharmony_ci		u32 reference_clock = rdev->clock.mpll.reference_freq;
279362306a36Sopenharmony_ci
279462306a36Sopenharmony_ci		if (mpll_param.qdr == 1)
279562306a36Sopenharmony_ci			freq_nom = memory_clock * 4 * (1 << mpll_param.post_div);
279662306a36Sopenharmony_ci		else
279762306a36Sopenharmony_ci			freq_nom = memory_clock * 2 * (1 << mpll_param.post_div);
279862306a36Sopenharmony_ci
279962306a36Sopenharmony_ci		tmp = (freq_nom / reference_clock);
280062306a36Sopenharmony_ci		tmp = tmp * tmp;
280162306a36Sopenharmony_ci		if (radeon_atombios_get_asic_ss_info(rdev, &ss,
280262306a36Sopenharmony_ci						     ASIC_INTERNAL_MEMORY_SS, freq_nom)) {
280362306a36Sopenharmony_ci			u32 clks = reference_clock * 5 / ss.rate;
280462306a36Sopenharmony_ci			u32 clkv = (u32)((((131 * ss.percentage * ss.rate) / 100) * tmp) / freq_nom);
280562306a36Sopenharmony_ci
280662306a36Sopenharmony_ci			mpll_ss1 &= ~CLKV_MASK;
280762306a36Sopenharmony_ci			mpll_ss1 |= CLKV(clkv);
280862306a36Sopenharmony_ci
280962306a36Sopenharmony_ci			mpll_ss2 &= ~CLKS_MASK;
281062306a36Sopenharmony_ci			mpll_ss2 |= CLKS(clks);
281162306a36Sopenharmony_ci		}
281262306a36Sopenharmony_ci	}
281362306a36Sopenharmony_ci
281462306a36Sopenharmony_ci	mclk_pwrmgt_cntl &= ~DLL_SPEED_MASK;
281562306a36Sopenharmony_ci	mclk_pwrmgt_cntl |= DLL_SPEED(mpll_param.dll_speed);
281662306a36Sopenharmony_ci
281762306a36Sopenharmony_ci	if (dll_state_on)
281862306a36Sopenharmony_ci		mclk_pwrmgt_cntl |= MRDCK0_PDNB | MRDCK1_PDNB;
281962306a36Sopenharmony_ci	else
282062306a36Sopenharmony_ci		mclk_pwrmgt_cntl &= ~(MRDCK0_PDNB | MRDCK1_PDNB);
282162306a36Sopenharmony_ci
282262306a36Sopenharmony_ci	mclk->MclkFrequency = memory_clock;
282362306a36Sopenharmony_ci	mclk->MpllFuncCntl = mpll_func_cntl;
282462306a36Sopenharmony_ci	mclk->MpllFuncCntl_1 = mpll_func_cntl_1;
282562306a36Sopenharmony_ci	mclk->MpllFuncCntl_2 = mpll_func_cntl_2;
282662306a36Sopenharmony_ci	mclk->MpllAdFuncCntl = mpll_ad_func_cntl;
282762306a36Sopenharmony_ci	mclk->MpllDqFuncCntl = mpll_dq_func_cntl;
282862306a36Sopenharmony_ci	mclk->MclkPwrmgtCntl = mclk_pwrmgt_cntl;
282962306a36Sopenharmony_ci	mclk->DllCntl = dll_cntl;
283062306a36Sopenharmony_ci	mclk->MpllSs1 = mpll_ss1;
283162306a36Sopenharmony_ci	mclk->MpllSs2 = mpll_ss2;
283262306a36Sopenharmony_ci
283362306a36Sopenharmony_ci	return 0;
283462306a36Sopenharmony_ci}
283562306a36Sopenharmony_ci
283662306a36Sopenharmony_cistatic int ci_populate_single_memory_level(struct radeon_device *rdev,
283762306a36Sopenharmony_ci					   u32 memory_clock,
283862306a36Sopenharmony_ci					   SMU7_Discrete_MemoryLevel *memory_level)
283962306a36Sopenharmony_ci{
284062306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
284162306a36Sopenharmony_ci	int ret;
284262306a36Sopenharmony_ci	bool dll_state_on;
284362306a36Sopenharmony_ci
284462306a36Sopenharmony_ci	if (rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries) {
284562306a36Sopenharmony_ci		ret = ci_get_dependency_volt_by_clk(rdev,
284662306a36Sopenharmony_ci						    &rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
284762306a36Sopenharmony_ci						    memory_clock, &memory_level->MinVddc);
284862306a36Sopenharmony_ci		if (ret)
284962306a36Sopenharmony_ci			return ret;
285062306a36Sopenharmony_ci	}
285162306a36Sopenharmony_ci
285262306a36Sopenharmony_ci	if (rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries) {
285362306a36Sopenharmony_ci		ret = ci_get_dependency_volt_by_clk(rdev,
285462306a36Sopenharmony_ci						    &rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
285562306a36Sopenharmony_ci						    memory_clock, &memory_level->MinVddci);
285662306a36Sopenharmony_ci		if (ret)
285762306a36Sopenharmony_ci			return ret;
285862306a36Sopenharmony_ci	}
285962306a36Sopenharmony_ci
286062306a36Sopenharmony_ci	if (rdev->pm.dpm.dyn_state.mvdd_dependency_on_mclk.entries) {
286162306a36Sopenharmony_ci		ret = ci_get_dependency_volt_by_clk(rdev,
286262306a36Sopenharmony_ci						    &rdev->pm.dpm.dyn_state.mvdd_dependency_on_mclk,
286362306a36Sopenharmony_ci						    memory_clock, &memory_level->MinMvdd);
286462306a36Sopenharmony_ci		if (ret)
286562306a36Sopenharmony_ci			return ret;
286662306a36Sopenharmony_ci	}
286762306a36Sopenharmony_ci
286862306a36Sopenharmony_ci	memory_level->MinVddcPhases = 1;
286962306a36Sopenharmony_ci
287062306a36Sopenharmony_ci	if (pi->vddc_phase_shed_control)
287162306a36Sopenharmony_ci		ci_populate_phase_value_based_on_mclk(rdev,
287262306a36Sopenharmony_ci						      &rdev->pm.dpm.dyn_state.phase_shedding_limits_table,
287362306a36Sopenharmony_ci						      memory_clock,
287462306a36Sopenharmony_ci						      &memory_level->MinVddcPhases);
287562306a36Sopenharmony_ci
287662306a36Sopenharmony_ci	memory_level->EnabledForThrottle = 1;
287762306a36Sopenharmony_ci	memory_level->UpH = 0;
287862306a36Sopenharmony_ci	memory_level->DownH = 100;
287962306a36Sopenharmony_ci	memory_level->VoltageDownH = 0;
288062306a36Sopenharmony_ci	memory_level->ActivityLevel = (u16)pi->mclk_activity_target;
288162306a36Sopenharmony_ci
288262306a36Sopenharmony_ci	memory_level->StutterEnable = false;
288362306a36Sopenharmony_ci	memory_level->StrobeEnable = false;
288462306a36Sopenharmony_ci	memory_level->EdcReadEnable = false;
288562306a36Sopenharmony_ci	memory_level->EdcWriteEnable = false;
288662306a36Sopenharmony_ci	memory_level->RttEnable = false;
288762306a36Sopenharmony_ci
288862306a36Sopenharmony_ci	memory_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
288962306a36Sopenharmony_ci
289062306a36Sopenharmony_ci	if (pi->mclk_stutter_mode_threshold &&
289162306a36Sopenharmony_ci	    (memory_clock <= pi->mclk_stutter_mode_threshold) &&
289262306a36Sopenharmony_ci	    (pi->uvd_enabled == false) &&
289362306a36Sopenharmony_ci	    (RREG32(DPG_PIPE_STUTTER_CONTROL) & STUTTER_ENABLE) &&
289462306a36Sopenharmony_ci	    (rdev->pm.dpm.new_active_crtc_count <= 2))
289562306a36Sopenharmony_ci		memory_level->StutterEnable = true;
289662306a36Sopenharmony_ci
289762306a36Sopenharmony_ci	if (pi->mclk_strobe_mode_threshold &&
289862306a36Sopenharmony_ci	    (memory_clock <= pi->mclk_strobe_mode_threshold))
289962306a36Sopenharmony_ci		memory_level->StrobeEnable = 1;
290062306a36Sopenharmony_ci
290162306a36Sopenharmony_ci	if (pi->mem_gddr5) {
290262306a36Sopenharmony_ci		memory_level->StrobeRatio =
290362306a36Sopenharmony_ci			si_get_mclk_frequency_ratio(memory_clock, memory_level->StrobeEnable);
290462306a36Sopenharmony_ci		if (pi->mclk_edc_enable_threshold &&
290562306a36Sopenharmony_ci		    (memory_clock > pi->mclk_edc_enable_threshold))
290662306a36Sopenharmony_ci			memory_level->EdcReadEnable = true;
290762306a36Sopenharmony_ci
290862306a36Sopenharmony_ci		if (pi->mclk_edc_wr_enable_threshold &&
290962306a36Sopenharmony_ci		    (memory_clock > pi->mclk_edc_wr_enable_threshold))
291062306a36Sopenharmony_ci			memory_level->EdcWriteEnable = true;
291162306a36Sopenharmony_ci
291262306a36Sopenharmony_ci		if (memory_level->StrobeEnable) {
291362306a36Sopenharmony_ci			if (si_get_mclk_frequency_ratio(memory_clock, true) >=
291462306a36Sopenharmony_ci			    ((RREG32(MC_SEQ_MISC7) >> 16) & 0xf))
291562306a36Sopenharmony_ci				dll_state_on = ((RREG32(MC_SEQ_MISC5) >> 1) & 0x1) ? true : false;
291662306a36Sopenharmony_ci			else
291762306a36Sopenharmony_ci				dll_state_on = ((RREG32(MC_SEQ_MISC6) >> 1) & 0x1) ? true : false;
291862306a36Sopenharmony_ci		} else {
291962306a36Sopenharmony_ci			dll_state_on = pi->dll_default_on;
292062306a36Sopenharmony_ci		}
292162306a36Sopenharmony_ci	} else {
292262306a36Sopenharmony_ci		memory_level->StrobeRatio = si_get_ddr3_mclk_frequency_ratio(memory_clock);
292362306a36Sopenharmony_ci		dll_state_on = ((RREG32(MC_SEQ_MISC5) >> 1) & 0x1) ? true : false;
292462306a36Sopenharmony_ci	}
292562306a36Sopenharmony_ci
292662306a36Sopenharmony_ci	ret = ci_calculate_mclk_params(rdev, memory_clock, memory_level, memory_level->StrobeEnable, dll_state_on);
292762306a36Sopenharmony_ci	if (ret)
292862306a36Sopenharmony_ci		return ret;
292962306a36Sopenharmony_ci
293062306a36Sopenharmony_ci	memory_level->MinVddc = cpu_to_be32(memory_level->MinVddc * VOLTAGE_SCALE);
293162306a36Sopenharmony_ci	memory_level->MinVddcPhases = cpu_to_be32(memory_level->MinVddcPhases);
293262306a36Sopenharmony_ci	memory_level->MinVddci = cpu_to_be32(memory_level->MinVddci * VOLTAGE_SCALE);
293362306a36Sopenharmony_ci	memory_level->MinMvdd = cpu_to_be32(memory_level->MinMvdd * VOLTAGE_SCALE);
293462306a36Sopenharmony_ci
293562306a36Sopenharmony_ci	memory_level->MclkFrequency = cpu_to_be32(memory_level->MclkFrequency);
293662306a36Sopenharmony_ci	memory_level->ActivityLevel = cpu_to_be16(memory_level->ActivityLevel);
293762306a36Sopenharmony_ci	memory_level->MpllFuncCntl = cpu_to_be32(memory_level->MpllFuncCntl);
293862306a36Sopenharmony_ci	memory_level->MpllFuncCntl_1 = cpu_to_be32(memory_level->MpllFuncCntl_1);
293962306a36Sopenharmony_ci	memory_level->MpllFuncCntl_2 = cpu_to_be32(memory_level->MpllFuncCntl_2);
294062306a36Sopenharmony_ci	memory_level->MpllAdFuncCntl = cpu_to_be32(memory_level->MpllAdFuncCntl);
294162306a36Sopenharmony_ci	memory_level->MpllDqFuncCntl = cpu_to_be32(memory_level->MpllDqFuncCntl);
294262306a36Sopenharmony_ci	memory_level->MclkPwrmgtCntl = cpu_to_be32(memory_level->MclkPwrmgtCntl);
294362306a36Sopenharmony_ci	memory_level->DllCntl = cpu_to_be32(memory_level->DllCntl);
294462306a36Sopenharmony_ci	memory_level->MpllSs1 = cpu_to_be32(memory_level->MpllSs1);
294562306a36Sopenharmony_ci	memory_level->MpllSs2 = cpu_to_be32(memory_level->MpllSs2);
294662306a36Sopenharmony_ci
294762306a36Sopenharmony_ci	return 0;
294862306a36Sopenharmony_ci}
294962306a36Sopenharmony_ci
295062306a36Sopenharmony_cistatic int ci_populate_smc_acpi_level(struct radeon_device *rdev,
295162306a36Sopenharmony_ci				      SMU7_Discrete_DpmTable *table)
295262306a36Sopenharmony_ci{
295362306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
295462306a36Sopenharmony_ci	struct atom_clock_dividers dividers;
295562306a36Sopenharmony_ci	SMU7_Discrete_VoltageLevel voltage_level;
295662306a36Sopenharmony_ci	u32 spll_func_cntl = pi->clock_registers.cg_spll_func_cntl;
295762306a36Sopenharmony_ci	u32 spll_func_cntl_2 = pi->clock_registers.cg_spll_func_cntl_2;
295862306a36Sopenharmony_ci	u32 dll_cntl = pi->clock_registers.dll_cntl;
295962306a36Sopenharmony_ci	u32 mclk_pwrmgt_cntl = pi->clock_registers.mclk_pwrmgt_cntl;
296062306a36Sopenharmony_ci	int ret;
296162306a36Sopenharmony_ci
296262306a36Sopenharmony_ci	table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC;
296362306a36Sopenharmony_ci
296462306a36Sopenharmony_ci	if (pi->acpi_vddc)
296562306a36Sopenharmony_ci		table->ACPILevel.MinVddc = cpu_to_be32(pi->acpi_vddc * VOLTAGE_SCALE);
296662306a36Sopenharmony_ci	else
296762306a36Sopenharmony_ci		table->ACPILevel.MinVddc = cpu_to_be32(pi->min_vddc_in_pp_table * VOLTAGE_SCALE);
296862306a36Sopenharmony_ci
296962306a36Sopenharmony_ci	table->ACPILevel.MinVddcPhases = pi->vddc_phase_shed_control ? 0 : 1;
297062306a36Sopenharmony_ci
297162306a36Sopenharmony_ci	table->ACPILevel.SclkFrequency = rdev->clock.spll.reference_freq;
297262306a36Sopenharmony_ci
297362306a36Sopenharmony_ci	ret = radeon_atom_get_clock_dividers(rdev,
297462306a36Sopenharmony_ci					     COMPUTE_GPUCLK_INPUT_FLAG_SCLK,
297562306a36Sopenharmony_ci					     table->ACPILevel.SclkFrequency, false, &dividers);
297662306a36Sopenharmony_ci	if (ret)
297762306a36Sopenharmony_ci		return ret;
297862306a36Sopenharmony_ci
297962306a36Sopenharmony_ci	table->ACPILevel.SclkDid = (u8)dividers.post_divider;
298062306a36Sopenharmony_ci	table->ACPILevel.DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
298162306a36Sopenharmony_ci	table->ACPILevel.DeepSleepDivId = 0;
298262306a36Sopenharmony_ci
298362306a36Sopenharmony_ci	spll_func_cntl &= ~SPLL_PWRON;
298462306a36Sopenharmony_ci	spll_func_cntl |= SPLL_RESET;
298562306a36Sopenharmony_ci
298662306a36Sopenharmony_ci	spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
298762306a36Sopenharmony_ci	spll_func_cntl_2 |= SCLK_MUX_SEL(4);
298862306a36Sopenharmony_ci
298962306a36Sopenharmony_ci	table->ACPILevel.CgSpllFuncCntl = spll_func_cntl;
299062306a36Sopenharmony_ci	table->ACPILevel.CgSpllFuncCntl2 = spll_func_cntl_2;
299162306a36Sopenharmony_ci	table->ACPILevel.CgSpllFuncCntl3 = pi->clock_registers.cg_spll_func_cntl_3;
299262306a36Sopenharmony_ci	table->ACPILevel.CgSpllFuncCntl4 = pi->clock_registers.cg_spll_func_cntl_4;
299362306a36Sopenharmony_ci	table->ACPILevel.SpllSpreadSpectrum = pi->clock_registers.cg_spll_spread_spectrum;
299462306a36Sopenharmony_ci	table->ACPILevel.SpllSpreadSpectrum2 = pi->clock_registers.cg_spll_spread_spectrum_2;
299562306a36Sopenharmony_ci	table->ACPILevel.CcPwrDynRm = 0;
299662306a36Sopenharmony_ci	table->ACPILevel.CcPwrDynRm1 = 0;
299762306a36Sopenharmony_ci
299862306a36Sopenharmony_ci	table->ACPILevel.Flags = cpu_to_be32(table->ACPILevel.Flags);
299962306a36Sopenharmony_ci	table->ACPILevel.MinVddcPhases = cpu_to_be32(table->ACPILevel.MinVddcPhases);
300062306a36Sopenharmony_ci	table->ACPILevel.SclkFrequency = cpu_to_be32(table->ACPILevel.SclkFrequency);
300162306a36Sopenharmony_ci	table->ACPILevel.CgSpllFuncCntl = cpu_to_be32(table->ACPILevel.CgSpllFuncCntl);
300262306a36Sopenharmony_ci	table->ACPILevel.CgSpllFuncCntl2 = cpu_to_be32(table->ACPILevel.CgSpllFuncCntl2);
300362306a36Sopenharmony_ci	table->ACPILevel.CgSpllFuncCntl3 = cpu_to_be32(table->ACPILevel.CgSpllFuncCntl3);
300462306a36Sopenharmony_ci	table->ACPILevel.CgSpllFuncCntl4 = cpu_to_be32(table->ACPILevel.CgSpllFuncCntl4);
300562306a36Sopenharmony_ci	table->ACPILevel.SpllSpreadSpectrum = cpu_to_be32(table->ACPILevel.SpllSpreadSpectrum);
300662306a36Sopenharmony_ci	table->ACPILevel.SpllSpreadSpectrum2 = cpu_to_be32(table->ACPILevel.SpllSpreadSpectrum2);
300762306a36Sopenharmony_ci	table->ACPILevel.CcPwrDynRm = cpu_to_be32(table->ACPILevel.CcPwrDynRm);
300862306a36Sopenharmony_ci	table->ACPILevel.CcPwrDynRm1 = cpu_to_be32(table->ACPILevel.CcPwrDynRm1);
300962306a36Sopenharmony_ci
301062306a36Sopenharmony_ci	table->MemoryACPILevel.MinVddc = table->ACPILevel.MinVddc;
301162306a36Sopenharmony_ci	table->MemoryACPILevel.MinVddcPhases = table->ACPILevel.MinVddcPhases;
301262306a36Sopenharmony_ci
301362306a36Sopenharmony_ci	if (pi->vddci_control != CISLANDS_VOLTAGE_CONTROL_NONE) {
301462306a36Sopenharmony_ci		if (pi->acpi_vddci)
301562306a36Sopenharmony_ci			table->MemoryACPILevel.MinVddci =
301662306a36Sopenharmony_ci				cpu_to_be32(pi->acpi_vddci * VOLTAGE_SCALE);
301762306a36Sopenharmony_ci		else
301862306a36Sopenharmony_ci			table->MemoryACPILevel.MinVddci =
301962306a36Sopenharmony_ci				cpu_to_be32(pi->min_vddci_in_pp_table * VOLTAGE_SCALE);
302062306a36Sopenharmony_ci	}
302162306a36Sopenharmony_ci
302262306a36Sopenharmony_ci	if (ci_populate_mvdd_value(rdev, 0, &voltage_level))
302362306a36Sopenharmony_ci		table->MemoryACPILevel.MinMvdd = 0;
302462306a36Sopenharmony_ci	else
302562306a36Sopenharmony_ci		table->MemoryACPILevel.MinMvdd =
302662306a36Sopenharmony_ci			cpu_to_be32(voltage_level.Voltage * VOLTAGE_SCALE);
302762306a36Sopenharmony_ci
302862306a36Sopenharmony_ci	mclk_pwrmgt_cntl |= MRDCK0_RESET | MRDCK1_RESET;
302962306a36Sopenharmony_ci	mclk_pwrmgt_cntl &= ~(MRDCK0_PDNB | MRDCK1_PDNB);
303062306a36Sopenharmony_ci
303162306a36Sopenharmony_ci	dll_cntl &= ~(MRDCK0_BYPASS | MRDCK1_BYPASS);
303262306a36Sopenharmony_ci
303362306a36Sopenharmony_ci	table->MemoryACPILevel.DllCntl = cpu_to_be32(dll_cntl);
303462306a36Sopenharmony_ci	table->MemoryACPILevel.MclkPwrmgtCntl = cpu_to_be32(mclk_pwrmgt_cntl);
303562306a36Sopenharmony_ci	table->MemoryACPILevel.MpllAdFuncCntl =
303662306a36Sopenharmony_ci		cpu_to_be32(pi->clock_registers.mpll_ad_func_cntl);
303762306a36Sopenharmony_ci	table->MemoryACPILevel.MpllDqFuncCntl =
303862306a36Sopenharmony_ci		cpu_to_be32(pi->clock_registers.mpll_dq_func_cntl);
303962306a36Sopenharmony_ci	table->MemoryACPILevel.MpllFuncCntl =
304062306a36Sopenharmony_ci		cpu_to_be32(pi->clock_registers.mpll_func_cntl);
304162306a36Sopenharmony_ci	table->MemoryACPILevel.MpllFuncCntl_1 =
304262306a36Sopenharmony_ci		cpu_to_be32(pi->clock_registers.mpll_func_cntl_1);
304362306a36Sopenharmony_ci	table->MemoryACPILevel.MpllFuncCntl_2 =
304462306a36Sopenharmony_ci		cpu_to_be32(pi->clock_registers.mpll_func_cntl_2);
304562306a36Sopenharmony_ci	table->MemoryACPILevel.MpllSs1 = cpu_to_be32(pi->clock_registers.mpll_ss1);
304662306a36Sopenharmony_ci	table->MemoryACPILevel.MpllSs2 = cpu_to_be32(pi->clock_registers.mpll_ss2);
304762306a36Sopenharmony_ci
304862306a36Sopenharmony_ci	table->MemoryACPILevel.EnabledForThrottle = 0;
304962306a36Sopenharmony_ci	table->MemoryACPILevel.EnabledForActivity = 0;
305062306a36Sopenharmony_ci	table->MemoryACPILevel.UpH = 0;
305162306a36Sopenharmony_ci	table->MemoryACPILevel.DownH = 100;
305262306a36Sopenharmony_ci	table->MemoryACPILevel.VoltageDownH = 0;
305362306a36Sopenharmony_ci	table->MemoryACPILevel.ActivityLevel =
305462306a36Sopenharmony_ci		cpu_to_be16((u16)pi->mclk_activity_target);
305562306a36Sopenharmony_ci
305662306a36Sopenharmony_ci	table->MemoryACPILevel.StutterEnable = false;
305762306a36Sopenharmony_ci	table->MemoryACPILevel.StrobeEnable = false;
305862306a36Sopenharmony_ci	table->MemoryACPILevel.EdcReadEnable = false;
305962306a36Sopenharmony_ci	table->MemoryACPILevel.EdcWriteEnable = false;
306062306a36Sopenharmony_ci	table->MemoryACPILevel.RttEnable = false;
306162306a36Sopenharmony_ci
306262306a36Sopenharmony_ci	return 0;
306362306a36Sopenharmony_ci}
306462306a36Sopenharmony_ci
306562306a36Sopenharmony_ci
306662306a36Sopenharmony_cistatic int ci_enable_ulv(struct radeon_device *rdev, bool enable)
306762306a36Sopenharmony_ci{
306862306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
306962306a36Sopenharmony_ci	struct ci_ulv_parm *ulv = &pi->ulv;
307062306a36Sopenharmony_ci
307162306a36Sopenharmony_ci	if (ulv->supported) {
307262306a36Sopenharmony_ci		if (enable)
307362306a36Sopenharmony_ci			return (ci_send_msg_to_smc(rdev, PPSMC_MSG_EnableULV) == PPSMC_Result_OK) ?
307462306a36Sopenharmony_ci				0 : -EINVAL;
307562306a36Sopenharmony_ci		else
307662306a36Sopenharmony_ci			return (ci_send_msg_to_smc(rdev, PPSMC_MSG_DisableULV) == PPSMC_Result_OK) ?
307762306a36Sopenharmony_ci				0 : -EINVAL;
307862306a36Sopenharmony_ci	}
307962306a36Sopenharmony_ci
308062306a36Sopenharmony_ci	return 0;
308162306a36Sopenharmony_ci}
308262306a36Sopenharmony_ci
308362306a36Sopenharmony_cistatic int ci_populate_ulv_level(struct radeon_device *rdev,
308462306a36Sopenharmony_ci				 SMU7_Discrete_Ulv *state)
308562306a36Sopenharmony_ci{
308662306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
308762306a36Sopenharmony_ci	u16 ulv_voltage = rdev->pm.dpm.backbias_response_time;
308862306a36Sopenharmony_ci
308962306a36Sopenharmony_ci	state->CcPwrDynRm = 0;
309062306a36Sopenharmony_ci	state->CcPwrDynRm1 = 0;
309162306a36Sopenharmony_ci
309262306a36Sopenharmony_ci	if (ulv_voltage == 0) {
309362306a36Sopenharmony_ci		pi->ulv.supported = false;
309462306a36Sopenharmony_ci		return 0;
309562306a36Sopenharmony_ci	}
309662306a36Sopenharmony_ci
309762306a36Sopenharmony_ci	if (pi->voltage_control != CISLANDS_VOLTAGE_CONTROL_BY_SVID2) {
309862306a36Sopenharmony_ci		if (ulv_voltage > rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[0].v)
309962306a36Sopenharmony_ci			state->VddcOffset = 0;
310062306a36Sopenharmony_ci		else
310162306a36Sopenharmony_ci			state->VddcOffset =
310262306a36Sopenharmony_ci				rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[0].v - ulv_voltage;
310362306a36Sopenharmony_ci	} else {
310462306a36Sopenharmony_ci		if (ulv_voltage > rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[0].v)
310562306a36Sopenharmony_ci			state->VddcOffsetVid = 0;
310662306a36Sopenharmony_ci		else
310762306a36Sopenharmony_ci			state->VddcOffsetVid = (u8)
310862306a36Sopenharmony_ci				((rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[0].v - ulv_voltage) *
310962306a36Sopenharmony_ci				 VOLTAGE_VID_OFFSET_SCALE2 / VOLTAGE_VID_OFFSET_SCALE1);
311062306a36Sopenharmony_ci	}
311162306a36Sopenharmony_ci	state->VddcPhase = pi->vddc_phase_shed_control ? 0 : 1;
311262306a36Sopenharmony_ci
311362306a36Sopenharmony_ci	state->CcPwrDynRm = cpu_to_be32(state->CcPwrDynRm);
311462306a36Sopenharmony_ci	state->CcPwrDynRm1 = cpu_to_be32(state->CcPwrDynRm1);
311562306a36Sopenharmony_ci	state->VddcOffset = cpu_to_be16(state->VddcOffset);
311662306a36Sopenharmony_ci
311762306a36Sopenharmony_ci	return 0;
311862306a36Sopenharmony_ci}
311962306a36Sopenharmony_ci
312062306a36Sopenharmony_cistatic int ci_calculate_sclk_params(struct radeon_device *rdev,
312162306a36Sopenharmony_ci				    u32 engine_clock,
312262306a36Sopenharmony_ci				    SMU7_Discrete_GraphicsLevel *sclk)
312362306a36Sopenharmony_ci{
312462306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
312562306a36Sopenharmony_ci	struct atom_clock_dividers dividers;
312662306a36Sopenharmony_ci	u32 spll_func_cntl_3 = pi->clock_registers.cg_spll_func_cntl_3;
312762306a36Sopenharmony_ci	u32 spll_func_cntl_4 = pi->clock_registers.cg_spll_func_cntl_4;
312862306a36Sopenharmony_ci	u32 cg_spll_spread_spectrum = pi->clock_registers.cg_spll_spread_spectrum;
312962306a36Sopenharmony_ci	u32 cg_spll_spread_spectrum_2 = pi->clock_registers.cg_spll_spread_spectrum_2;
313062306a36Sopenharmony_ci	u32 reference_clock = rdev->clock.spll.reference_freq;
313162306a36Sopenharmony_ci	u32 reference_divider;
313262306a36Sopenharmony_ci	u32 fbdiv;
313362306a36Sopenharmony_ci	int ret;
313462306a36Sopenharmony_ci
313562306a36Sopenharmony_ci	ret = radeon_atom_get_clock_dividers(rdev,
313662306a36Sopenharmony_ci					     COMPUTE_GPUCLK_INPUT_FLAG_SCLK,
313762306a36Sopenharmony_ci					     engine_clock, false, &dividers);
313862306a36Sopenharmony_ci	if (ret)
313962306a36Sopenharmony_ci		return ret;
314062306a36Sopenharmony_ci
314162306a36Sopenharmony_ci	reference_divider = 1 + dividers.ref_div;
314262306a36Sopenharmony_ci	fbdiv = dividers.fb_div & 0x3FFFFFF;
314362306a36Sopenharmony_ci
314462306a36Sopenharmony_ci	spll_func_cntl_3 &= ~SPLL_FB_DIV_MASK;
314562306a36Sopenharmony_ci	spll_func_cntl_3 |= SPLL_FB_DIV(fbdiv);
314662306a36Sopenharmony_ci	spll_func_cntl_3 |= SPLL_DITHEN;
314762306a36Sopenharmony_ci
314862306a36Sopenharmony_ci	if (pi->caps_sclk_ss_support) {
314962306a36Sopenharmony_ci		struct radeon_atom_ss ss;
315062306a36Sopenharmony_ci		u32 vco_freq = engine_clock * dividers.post_div;
315162306a36Sopenharmony_ci
315262306a36Sopenharmony_ci		if (radeon_atombios_get_asic_ss_info(rdev, &ss,
315362306a36Sopenharmony_ci						     ASIC_INTERNAL_ENGINE_SS, vco_freq)) {
315462306a36Sopenharmony_ci			u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate);
315562306a36Sopenharmony_ci			u32 clk_v = 4 * ss.percentage * fbdiv / (clk_s * 10000);
315662306a36Sopenharmony_ci
315762306a36Sopenharmony_ci			cg_spll_spread_spectrum &= ~CLK_S_MASK;
315862306a36Sopenharmony_ci			cg_spll_spread_spectrum |= CLK_S(clk_s);
315962306a36Sopenharmony_ci			cg_spll_spread_spectrum |= SSEN;
316062306a36Sopenharmony_ci
316162306a36Sopenharmony_ci			cg_spll_spread_spectrum_2 &= ~CLK_V_MASK;
316262306a36Sopenharmony_ci			cg_spll_spread_spectrum_2 |= CLK_V(clk_v);
316362306a36Sopenharmony_ci		}
316462306a36Sopenharmony_ci	}
316562306a36Sopenharmony_ci
316662306a36Sopenharmony_ci	sclk->SclkFrequency = engine_clock;
316762306a36Sopenharmony_ci	sclk->CgSpllFuncCntl3 = spll_func_cntl_3;
316862306a36Sopenharmony_ci	sclk->CgSpllFuncCntl4 = spll_func_cntl_4;
316962306a36Sopenharmony_ci	sclk->SpllSpreadSpectrum = cg_spll_spread_spectrum;
317062306a36Sopenharmony_ci	sclk->SpllSpreadSpectrum2  = cg_spll_spread_spectrum_2;
317162306a36Sopenharmony_ci	sclk->SclkDid = (u8)dividers.post_divider;
317262306a36Sopenharmony_ci
317362306a36Sopenharmony_ci	return 0;
317462306a36Sopenharmony_ci}
317562306a36Sopenharmony_ci
317662306a36Sopenharmony_cistatic int ci_populate_single_graphic_level(struct radeon_device *rdev,
317762306a36Sopenharmony_ci					    u32 engine_clock,
317862306a36Sopenharmony_ci					    u16 sclk_activity_level_t,
317962306a36Sopenharmony_ci					    SMU7_Discrete_GraphicsLevel *graphic_level)
318062306a36Sopenharmony_ci{
318162306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
318262306a36Sopenharmony_ci	int ret;
318362306a36Sopenharmony_ci
318462306a36Sopenharmony_ci	ret = ci_calculate_sclk_params(rdev, engine_clock, graphic_level);
318562306a36Sopenharmony_ci	if (ret)
318662306a36Sopenharmony_ci		return ret;
318762306a36Sopenharmony_ci
318862306a36Sopenharmony_ci	ret = ci_get_dependency_volt_by_clk(rdev,
318962306a36Sopenharmony_ci					    &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
319062306a36Sopenharmony_ci					    engine_clock, &graphic_level->MinVddc);
319162306a36Sopenharmony_ci	if (ret)
319262306a36Sopenharmony_ci		return ret;
319362306a36Sopenharmony_ci
319462306a36Sopenharmony_ci	graphic_level->SclkFrequency = engine_clock;
319562306a36Sopenharmony_ci
319662306a36Sopenharmony_ci	graphic_level->Flags =  0;
319762306a36Sopenharmony_ci	graphic_level->MinVddcPhases = 1;
319862306a36Sopenharmony_ci
319962306a36Sopenharmony_ci	if (pi->vddc_phase_shed_control)
320062306a36Sopenharmony_ci		ci_populate_phase_value_based_on_sclk(rdev,
320162306a36Sopenharmony_ci						      &rdev->pm.dpm.dyn_state.phase_shedding_limits_table,
320262306a36Sopenharmony_ci						      engine_clock,
320362306a36Sopenharmony_ci						      &graphic_level->MinVddcPhases);
320462306a36Sopenharmony_ci
320562306a36Sopenharmony_ci	graphic_level->ActivityLevel = sclk_activity_level_t;
320662306a36Sopenharmony_ci
320762306a36Sopenharmony_ci	graphic_level->CcPwrDynRm = 0;
320862306a36Sopenharmony_ci	graphic_level->CcPwrDynRm1 = 0;
320962306a36Sopenharmony_ci	graphic_level->EnabledForThrottle = 1;
321062306a36Sopenharmony_ci	graphic_level->UpH = 0;
321162306a36Sopenharmony_ci	graphic_level->DownH = 0;
321262306a36Sopenharmony_ci	graphic_level->VoltageDownH = 0;
321362306a36Sopenharmony_ci	graphic_level->PowerThrottle = 0;
321462306a36Sopenharmony_ci
321562306a36Sopenharmony_ci	if (pi->caps_sclk_ds)
321662306a36Sopenharmony_ci		graphic_level->DeepSleepDivId = ci_get_sleep_divider_id_from_clock(rdev,
321762306a36Sopenharmony_ci										   engine_clock,
321862306a36Sopenharmony_ci										   CISLAND_MINIMUM_ENGINE_CLOCK);
321962306a36Sopenharmony_ci
322062306a36Sopenharmony_ci	graphic_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
322162306a36Sopenharmony_ci
322262306a36Sopenharmony_ci	graphic_level->Flags = cpu_to_be32(graphic_level->Flags);
322362306a36Sopenharmony_ci	graphic_level->MinVddc = cpu_to_be32(graphic_level->MinVddc * VOLTAGE_SCALE);
322462306a36Sopenharmony_ci	graphic_level->MinVddcPhases = cpu_to_be32(graphic_level->MinVddcPhases);
322562306a36Sopenharmony_ci	graphic_level->SclkFrequency = cpu_to_be32(graphic_level->SclkFrequency);
322662306a36Sopenharmony_ci	graphic_level->ActivityLevel = cpu_to_be16(graphic_level->ActivityLevel);
322762306a36Sopenharmony_ci	graphic_level->CgSpllFuncCntl3 = cpu_to_be32(graphic_level->CgSpllFuncCntl3);
322862306a36Sopenharmony_ci	graphic_level->CgSpllFuncCntl4 = cpu_to_be32(graphic_level->CgSpllFuncCntl4);
322962306a36Sopenharmony_ci	graphic_level->SpllSpreadSpectrum = cpu_to_be32(graphic_level->SpllSpreadSpectrum);
323062306a36Sopenharmony_ci	graphic_level->SpllSpreadSpectrum2 = cpu_to_be32(graphic_level->SpllSpreadSpectrum2);
323162306a36Sopenharmony_ci	graphic_level->CcPwrDynRm = cpu_to_be32(graphic_level->CcPwrDynRm);
323262306a36Sopenharmony_ci	graphic_level->CcPwrDynRm1 = cpu_to_be32(graphic_level->CcPwrDynRm1);
323362306a36Sopenharmony_ci
323462306a36Sopenharmony_ci	return 0;
323562306a36Sopenharmony_ci}
323662306a36Sopenharmony_ci
323762306a36Sopenharmony_cistatic int ci_populate_all_graphic_levels(struct radeon_device *rdev)
323862306a36Sopenharmony_ci{
323962306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
324062306a36Sopenharmony_ci	struct ci_dpm_table *dpm_table = &pi->dpm_table;
324162306a36Sopenharmony_ci	u32 level_array_address = pi->dpm_table_start +
324262306a36Sopenharmony_ci		offsetof(SMU7_Discrete_DpmTable, GraphicsLevel);
324362306a36Sopenharmony_ci	u32 level_array_size = sizeof(SMU7_Discrete_GraphicsLevel) *
324462306a36Sopenharmony_ci		SMU7_MAX_LEVELS_GRAPHICS;
324562306a36Sopenharmony_ci	SMU7_Discrete_GraphicsLevel *levels = pi->smc_state_table.GraphicsLevel;
324662306a36Sopenharmony_ci	u32 i, ret;
324762306a36Sopenharmony_ci
324862306a36Sopenharmony_ci	memset(levels, 0, level_array_size);
324962306a36Sopenharmony_ci
325062306a36Sopenharmony_ci	for (i = 0; i < dpm_table->sclk_table.count; i++) {
325162306a36Sopenharmony_ci		ret = ci_populate_single_graphic_level(rdev,
325262306a36Sopenharmony_ci						       dpm_table->sclk_table.dpm_levels[i].value,
325362306a36Sopenharmony_ci						       (u16)pi->activity_target[i],
325462306a36Sopenharmony_ci						       &pi->smc_state_table.GraphicsLevel[i]);
325562306a36Sopenharmony_ci		if (ret)
325662306a36Sopenharmony_ci			return ret;
325762306a36Sopenharmony_ci		if (i > 1)
325862306a36Sopenharmony_ci			pi->smc_state_table.GraphicsLevel[i].DeepSleepDivId = 0;
325962306a36Sopenharmony_ci		if (i == (dpm_table->sclk_table.count - 1))
326062306a36Sopenharmony_ci			pi->smc_state_table.GraphicsLevel[i].DisplayWatermark =
326162306a36Sopenharmony_ci				PPSMC_DISPLAY_WATERMARK_HIGH;
326262306a36Sopenharmony_ci	}
326362306a36Sopenharmony_ci	pi->smc_state_table.GraphicsLevel[0].EnabledForActivity = 1;
326462306a36Sopenharmony_ci
326562306a36Sopenharmony_ci	pi->smc_state_table.GraphicsDpmLevelCount = (u8)dpm_table->sclk_table.count;
326662306a36Sopenharmony_ci	pi->dpm_level_enable_mask.sclk_dpm_enable_mask =
326762306a36Sopenharmony_ci		ci_get_dpm_level_enable_mask_value(&dpm_table->sclk_table);
326862306a36Sopenharmony_ci
326962306a36Sopenharmony_ci	ret = ci_copy_bytes_to_smc(rdev, level_array_address,
327062306a36Sopenharmony_ci				   (u8 *)levels, level_array_size,
327162306a36Sopenharmony_ci				   pi->sram_end);
327262306a36Sopenharmony_ci	if (ret)
327362306a36Sopenharmony_ci		return ret;
327462306a36Sopenharmony_ci
327562306a36Sopenharmony_ci	return 0;
327662306a36Sopenharmony_ci}
327762306a36Sopenharmony_ci
327862306a36Sopenharmony_cistatic int ci_populate_ulv_state(struct radeon_device *rdev,
327962306a36Sopenharmony_ci				 SMU7_Discrete_Ulv *ulv_level)
328062306a36Sopenharmony_ci{
328162306a36Sopenharmony_ci	return ci_populate_ulv_level(rdev, ulv_level);
328262306a36Sopenharmony_ci}
328362306a36Sopenharmony_ci
328462306a36Sopenharmony_cistatic int ci_populate_all_memory_levels(struct radeon_device *rdev)
328562306a36Sopenharmony_ci{
328662306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
328762306a36Sopenharmony_ci	struct ci_dpm_table *dpm_table = &pi->dpm_table;
328862306a36Sopenharmony_ci	u32 level_array_address = pi->dpm_table_start +
328962306a36Sopenharmony_ci		offsetof(SMU7_Discrete_DpmTable, MemoryLevel);
329062306a36Sopenharmony_ci	u32 level_array_size = sizeof(SMU7_Discrete_MemoryLevel) *
329162306a36Sopenharmony_ci		SMU7_MAX_LEVELS_MEMORY;
329262306a36Sopenharmony_ci	SMU7_Discrete_MemoryLevel *levels = pi->smc_state_table.MemoryLevel;
329362306a36Sopenharmony_ci	u32 i, ret;
329462306a36Sopenharmony_ci
329562306a36Sopenharmony_ci	memset(levels, 0, level_array_size);
329662306a36Sopenharmony_ci
329762306a36Sopenharmony_ci	for (i = 0; i < dpm_table->mclk_table.count; i++) {
329862306a36Sopenharmony_ci		if (dpm_table->mclk_table.dpm_levels[i].value == 0)
329962306a36Sopenharmony_ci			return -EINVAL;
330062306a36Sopenharmony_ci		ret = ci_populate_single_memory_level(rdev,
330162306a36Sopenharmony_ci						      dpm_table->mclk_table.dpm_levels[i].value,
330262306a36Sopenharmony_ci						      &pi->smc_state_table.MemoryLevel[i]);
330362306a36Sopenharmony_ci		if (ret)
330462306a36Sopenharmony_ci			return ret;
330562306a36Sopenharmony_ci	}
330662306a36Sopenharmony_ci
330762306a36Sopenharmony_ci	pi->smc_state_table.MemoryLevel[0].EnabledForActivity = 1;
330862306a36Sopenharmony_ci
330962306a36Sopenharmony_ci	if ((dpm_table->mclk_table.count >= 2) &&
331062306a36Sopenharmony_ci	    ((rdev->pdev->device == 0x67B0) || (rdev->pdev->device == 0x67B1))) {
331162306a36Sopenharmony_ci		pi->smc_state_table.MemoryLevel[1].MinVddc =
331262306a36Sopenharmony_ci			pi->smc_state_table.MemoryLevel[0].MinVddc;
331362306a36Sopenharmony_ci		pi->smc_state_table.MemoryLevel[1].MinVddcPhases =
331462306a36Sopenharmony_ci			pi->smc_state_table.MemoryLevel[0].MinVddcPhases;
331562306a36Sopenharmony_ci	}
331662306a36Sopenharmony_ci
331762306a36Sopenharmony_ci	pi->smc_state_table.MemoryLevel[0].ActivityLevel = cpu_to_be16(0x1F);
331862306a36Sopenharmony_ci
331962306a36Sopenharmony_ci	pi->smc_state_table.MemoryDpmLevelCount = (u8)dpm_table->mclk_table.count;
332062306a36Sopenharmony_ci	pi->dpm_level_enable_mask.mclk_dpm_enable_mask =
332162306a36Sopenharmony_ci		ci_get_dpm_level_enable_mask_value(&dpm_table->mclk_table);
332262306a36Sopenharmony_ci
332362306a36Sopenharmony_ci	pi->smc_state_table.MemoryLevel[dpm_table->mclk_table.count - 1].DisplayWatermark =
332462306a36Sopenharmony_ci		PPSMC_DISPLAY_WATERMARK_HIGH;
332562306a36Sopenharmony_ci
332662306a36Sopenharmony_ci	ret = ci_copy_bytes_to_smc(rdev, level_array_address,
332762306a36Sopenharmony_ci				   (u8 *)levels, level_array_size,
332862306a36Sopenharmony_ci				   pi->sram_end);
332962306a36Sopenharmony_ci	if (ret)
333062306a36Sopenharmony_ci		return ret;
333162306a36Sopenharmony_ci
333262306a36Sopenharmony_ci	return 0;
333362306a36Sopenharmony_ci}
333462306a36Sopenharmony_ci
333562306a36Sopenharmony_cistatic void ci_reset_single_dpm_table(struct radeon_device *rdev,
333662306a36Sopenharmony_ci				      struct ci_single_dpm_table* dpm_table,
333762306a36Sopenharmony_ci				      u32 count)
333862306a36Sopenharmony_ci{
333962306a36Sopenharmony_ci	u32 i;
334062306a36Sopenharmony_ci
334162306a36Sopenharmony_ci	dpm_table->count = count;
334262306a36Sopenharmony_ci	for (i = 0; i < MAX_REGULAR_DPM_NUMBER; i++)
334362306a36Sopenharmony_ci		dpm_table->dpm_levels[i].enabled = false;
334462306a36Sopenharmony_ci}
334562306a36Sopenharmony_ci
334662306a36Sopenharmony_cistatic void ci_setup_pcie_table_entry(struct ci_single_dpm_table* dpm_table,
334762306a36Sopenharmony_ci				      u32 index, u32 pcie_gen, u32 pcie_lanes)
334862306a36Sopenharmony_ci{
334962306a36Sopenharmony_ci	dpm_table->dpm_levels[index].value = pcie_gen;
335062306a36Sopenharmony_ci	dpm_table->dpm_levels[index].param1 = pcie_lanes;
335162306a36Sopenharmony_ci	dpm_table->dpm_levels[index].enabled = true;
335262306a36Sopenharmony_ci}
335362306a36Sopenharmony_ci
335462306a36Sopenharmony_cistatic int ci_setup_default_pcie_tables(struct radeon_device *rdev)
335562306a36Sopenharmony_ci{
335662306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
335762306a36Sopenharmony_ci
335862306a36Sopenharmony_ci	if (!pi->use_pcie_performance_levels && !pi->use_pcie_powersaving_levels)
335962306a36Sopenharmony_ci		return -EINVAL;
336062306a36Sopenharmony_ci
336162306a36Sopenharmony_ci	if (pi->use_pcie_performance_levels && !pi->use_pcie_powersaving_levels) {
336262306a36Sopenharmony_ci		pi->pcie_gen_powersaving = pi->pcie_gen_performance;
336362306a36Sopenharmony_ci		pi->pcie_lane_powersaving = pi->pcie_lane_performance;
336462306a36Sopenharmony_ci	} else if (!pi->use_pcie_performance_levels && pi->use_pcie_powersaving_levels) {
336562306a36Sopenharmony_ci		pi->pcie_gen_performance = pi->pcie_gen_powersaving;
336662306a36Sopenharmony_ci		pi->pcie_lane_performance = pi->pcie_lane_powersaving;
336762306a36Sopenharmony_ci	}
336862306a36Sopenharmony_ci
336962306a36Sopenharmony_ci	ci_reset_single_dpm_table(rdev,
337062306a36Sopenharmony_ci				  &pi->dpm_table.pcie_speed_table,
337162306a36Sopenharmony_ci				  SMU7_MAX_LEVELS_LINK);
337262306a36Sopenharmony_ci
337362306a36Sopenharmony_ci	if (rdev->family == CHIP_BONAIRE)
337462306a36Sopenharmony_ci		ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 0,
337562306a36Sopenharmony_ci					  pi->pcie_gen_powersaving.min,
337662306a36Sopenharmony_ci					  pi->pcie_lane_powersaving.max);
337762306a36Sopenharmony_ci	else
337862306a36Sopenharmony_ci		ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 0,
337962306a36Sopenharmony_ci					  pi->pcie_gen_powersaving.min,
338062306a36Sopenharmony_ci					  pi->pcie_lane_powersaving.min);
338162306a36Sopenharmony_ci	ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 1,
338262306a36Sopenharmony_ci				  pi->pcie_gen_performance.min,
338362306a36Sopenharmony_ci				  pi->pcie_lane_performance.min);
338462306a36Sopenharmony_ci	ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 2,
338562306a36Sopenharmony_ci				  pi->pcie_gen_powersaving.min,
338662306a36Sopenharmony_ci				  pi->pcie_lane_powersaving.max);
338762306a36Sopenharmony_ci	ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 3,
338862306a36Sopenharmony_ci				  pi->pcie_gen_performance.min,
338962306a36Sopenharmony_ci				  pi->pcie_lane_performance.max);
339062306a36Sopenharmony_ci	ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 4,
339162306a36Sopenharmony_ci				  pi->pcie_gen_powersaving.max,
339262306a36Sopenharmony_ci				  pi->pcie_lane_powersaving.max);
339362306a36Sopenharmony_ci	ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 5,
339462306a36Sopenharmony_ci				  pi->pcie_gen_performance.max,
339562306a36Sopenharmony_ci				  pi->pcie_lane_performance.max);
339662306a36Sopenharmony_ci
339762306a36Sopenharmony_ci	pi->dpm_table.pcie_speed_table.count = 6;
339862306a36Sopenharmony_ci
339962306a36Sopenharmony_ci	return 0;
340062306a36Sopenharmony_ci}
340162306a36Sopenharmony_ci
340262306a36Sopenharmony_cistatic int ci_setup_default_dpm_tables(struct radeon_device *rdev)
340362306a36Sopenharmony_ci{
340462306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
340562306a36Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *allowed_sclk_vddc_table =
340662306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
340762306a36Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *allowed_mclk_table =
340862306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk;
340962306a36Sopenharmony_ci	struct radeon_cac_leakage_table *std_voltage_table =
341062306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.cac_leakage_table;
341162306a36Sopenharmony_ci	u32 i;
341262306a36Sopenharmony_ci
341362306a36Sopenharmony_ci	if (allowed_sclk_vddc_table == NULL)
341462306a36Sopenharmony_ci		return -EINVAL;
341562306a36Sopenharmony_ci	if (allowed_sclk_vddc_table->count < 1)
341662306a36Sopenharmony_ci		return -EINVAL;
341762306a36Sopenharmony_ci	if (allowed_mclk_table == NULL)
341862306a36Sopenharmony_ci		return -EINVAL;
341962306a36Sopenharmony_ci	if (allowed_mclk_table->count < 1)
342062306a36Sopenharmony_ci		return -EINVAL;
342162306a36Sopenharmony_ci
342262306a36Sopenharmony_ci	memset(&pi->dpm_table, 0, sizeof(struct ci_dpm_table));
342362306a36Sopenharmony_ci
342462306a36Sopenharmony_ci	ci_reset_single_dpm_table(rdev,
342562306a36Sopenharmony_ci				  &pi->dpm_table.sclk_table,
342662306a36Sopenharmony_ci				  SMU7_MAX_LEVELS_GRAPHICS);
342762306a36Sopenharmony_ci	ci_reset_single_dpm_table(rdev,
342862306a36Sopenharmony_ci				  &pi->dpm_table.mclk_table,
342962306a36Sopenharmony_ci				  SMU7_MAX_LEVELS_MEMORY);
343062306a36Sopenharmony_ci	ci_reset_single_dpm_table(rdev,
343162306a36Sopenharmony_ci				  &pi->dpm_table.vddc_table,
343262306a36Sopenharmony_ci				  SMU7_MAX_LEVELS_VDDC);
343362306a36Sopenharmony_ci	ci_reset_single_dpm_table(rdev,
343462306a36Sopenharmony_ci				  &pi->dpm_table.vddci_table,
343562306a36Sopenharmony_ci				  SMU7_MAX_LEVELS_VDDCI);
343662306a36Sopenharmony_ci	ci_reset_single_dpm_table(rdev,
343762306a36Sopenharmony_ci				  &pi->dpm_table.mvdd_table,
343862306a36Sopenharmony_ci				  SMU7_MAX_LEVELS_MVDD);
343962306a36Sopenharmony_ci
344062306a36Sopenharmony_ci	pi->dpm_table.sclk_table.count = 0;
344162306a36Sopenharmony_ci	for (i = 0; i < allowed_sclk_vddc_table->count; i++) {
344262306a36Sopenharmony_ci		if ((i == 0) ||
344362306a36Sopenharmony_ci		    (pi->dpm_table.sclk_table.dpm_levels[pi->dpm_table.sclk_table.count-1].value !=
344462306a36Sopenharmony_ci		     allowed_sclk_vddc_table->entries[i].clk)) {
344562306a36Sopenharmony_ci			pi->dpm_table.sclk_table.dpm_levels[pi->dpm_table.sclk_table.count].value =
344662306a36Sopenharmony_ci				allowed_sclk_vddc_table->entries[i].clk;
344762306a36Sopenharmony_ci			pi->dpm_table.sclk_table.dpm_levels[pi->dpm_table.sclk_table.count].enabled =
344862306a36Sopenharmony_ci				(i == 0) ? true : false;
344962306a36Sopenharmony_ci			pi->dpm_table.sclk_table.count++;
345062306a36Sopenharmony_ci		}
345162306a36Sopenharmony_ci	}
345262306a36Sopenharmony_ci
345362306a36Sopenharmony_ci	pi->dpm_table.mclk_table.count = 0;
345462306a36Sopenharmony_ci	for (i = 0; i < allowed_mclk_table->count; i++) {
345562306a36Sopenharmony_ci		if ((i == 0) ||
345662306a36Sopenharmony_ci		    (pi->dpm_table.mclk_table.dpm_levels[pi->dpm_table.mclk_table.count-1].value !=
345762306a36Sopenharmony_ci		     allowed_mclk_table->entries[i].clk)) {
345862306a36Sopenharmony_ci			pi->dpm_table.mclk_table.dpm_levels[pi->dpm_table.mclk_table.count].value =
345962306a36Sopenharmony_ci				allowed_mclk_table->entries[i].clk;
346062306a36Sopenharmony_ci			pi->dpm_table.mclk_table.dpm_levels[pi->dpm_table.mclk_table.count].enabled =
346162306a36Sopenharmony_ci				(i == 0) ? true : false;
346262306a36Sopenharmony_ci			pi->dpm_table.mclk_table.count++;
346362306a36Sopenharmony_ci		}
346462306a36Sopenharmony_ci	}
346562306a36Sopenharmony_ci
346662306a36Sopenharmony_ci	for (i = 0; i < allowed_sclk_vddc_table->count; i++) {
346762306a36Sopenharmony_ci		pi->dpm_table.vddc_table.dpm_levels[i].value =
346862306a36Sopenharmony_ci			allowed_sclk_vddc_table->entries[i].v;
346962306a36Sopenharmony_ci		pi->dpm_table.vddc_table.dpm_levels[i].param1 =
347062306a36Sopenharmony_ci			std_voltage_table->entries[i].leakage;
347162306a36Sopenharmony_ci		pi->dpm_table.vddc_table.dpm_levels[i].enabled = true;
347262306a36Sopenharmony_ci	}
347362306a36Sopenharmony_ci	pi->dpm_table.vddc_table.count = allowed_sclk_vddc_table->count;
347462306a36Sopenharmony_ci
347562306a36Sopenharmony_ci	allowed_mclk_table = &rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk;
347662306a36Sopenharmony_ci	if (allowed_mclk_table) {
347762306a36Sopenharmony_ci		for (i = 0; i < allowed_mclk_table->count; i++) {
347862306a36Sopenharmony_ci			pi->dpm_table.vddci_table.dpm_levels[i].value =
347962306a36Sopenharmony_ci				allowed_mclk_table->entries[i].v;
348062306a36Sopenharmony_ci			pi->dpm_table.vddci_table.dpm_levels[i].enabled = true;
348162306a36Sopenharmony_ci		}
348262306a36Sopenharmony_ci		pi->dpm_table.vddci_table.count = allowed_mclk_table->count;
348362306a36Sopenharmony_ci	}
348462306a36Sopenharmony_ci
348562306a36Sopenharmony_ci	allowed_mclk_table = &rdev->pm.dpm.dyn_state.mvdd_dependency_on_mclk;
348662306a36Sopenharmony_ci	if (allowed_mclk_table) {
348762306a36Sopenharmony_ci		for (i = 0; i < allowed_mclk_table->count; i++) {
348862306a36Sopenharmony_ci			pi->dpm_table.mvdd_table.dpm_levels[i].value =
348962306a36Sopenharmony_ci				allowed_mclk_table->entries[i].v;
349062306a36Sopenharmony_ci			pi->dpm_table.mvdd_table.dpm_levels[i].enabled = true;
349162306a36Sopenharmony_ci		}
349262306a36Sopenharmony_ci		pi->dpm_table.mvdd_table.count = allowed_mclk_table->count;
349362306a36Sopenharmony_ci	}
349462306a36Sopenharmony_ci
349562306a36Sopenharmony_ci	ci_setup_default_pcie_tables(rdev);
349662306a36Sopenharmony_ci
349762306a36Sopenharmony_ci	return 0;
349862306a36Sopenharmony_ci}
349962306a36Sopenharmony_ci
350062306a36Sopenharmony_cistatic int ci_find_boot_level(struct ci_single_dpm_table *table,
350162306a36Sopenharmony_ci			      u32 value, u32 *boot_level)
350262306a36Sopenharmony_ci{
350362306a36Sopenharmony_ci	u32 i;
350462306a36Sopenharmony_ci	int ret = -EINVAL;
350562306a36Sopenharmony_ci
350662306a36Sopenharmony_ci	for(i = 0; i < table->count; i++) {
350762306a36Sopenharmony_ci		if (value == table->dpm_levels[i].value) {
350862306a36Sopenharmony_ci			*boot_level = i;
350962306a36Sopenharmony_ci			ret = 0;
351062306a36Sopenharmony_ci		}
351162306a36Sopenharmony_ci	}
351262306a36Sopenharmony_ci
351362306a36Sopenharmony_ci	return ret;
351462306a36Sopenharmony_ci}
351562306a36Sopenharmony_ci
351662306a36Sopenharmony_cistatic int ci_init_smc_table(struct radeon_device *rdev)
351762306a36Sopenharmony_ci{
351862306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
351962306a36Sopenharmony_ci	struct ci_ulv_parm *ulv = &pi->ulv;
352062306a36Sopenharmony_ci	struct radeon_ps *radeon_boot_state = rdev->pm.dpm.boot_ps;
352162306a36Sopenharmony_ci	SMU7_Discrete_DpmTable *table = &pi->smc_state_table;
352262306a36Sopenharmony_ci	int ret;
352362306a36Sopenharmony_ci
352462306a36Sopenharmony_ci	ret = ci_setup_default_dpm_tables(rdev);
352562306a36Sopenharmony_ci	if (ret)
352662306a36Sopenharmony_ci		return ret;
352762306a36Sopenharmony_ci
352862306a36Sopenharmony_ci	if (pi->voltage_control != CISLANDS_VOLTAGE_CONTROL_NONE)
352962306a36Sopenharmony_ci		ci_populate_smc_voltage_tables(rdev, table);
353062306a36Sopenharmony_ci
353162306a36Sopenharmony_ci	ci_init_fps_limits(rdev);
353262306a36Sopenharmony_ci
353362306a36Sopenharmony_ci	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC)
353462306a36Sopenharmony_ci		table->SystemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
353562306a36Sopenharmony_ci
353662306a36Sopenharmony_ci	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC)
353762306a36Sopenharmony_ci		table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
353862306a36Sopenharmony_ci
353962306a36Sopenharmony_ci	if (pi->mem_gddr5)
354062306a36Sopenharmony_ci		table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
354162306a36Sopenharmony_ci
354262306a36Sopenharmony_ci	if (ulv->supported) {
354362306a36Sopenharmony_ci		ret = ci_populate_ulv_state(rdev, &pi->smc_state_table.Ulv);
354462306a36Sopenharmony_ci		if (ret)
354562306a36Sopenharmony_ci			return ret;
354662306a36Sopenharmony_ci		WREG32_SMC(CG_ULV_PARAMETER, ulv->cg_ulv_parameter);
354762306a36Sopenharmony_ci	}
354862306a36Sopenharmony_ci
354962306a36Sopenharmony_ci	ret = ci_populate_all_graphic_levels(rdev);
355062306a36Sopenharmony_ci	if (ret)
355162306a36Sopenharmony_ci		return ret;
355262306a36Sopenharmony_ci
355362306a36Sopenharmony_ci	ret = ci_populate_all_memory_levels(rdev);
355462306a36Sopenharmony_ci	if (ret)
355562306a36Sopenharmony_ci		return ret;
355662306a36Sopenharmony_ci
355762306a36Sopenharmony_ci	ci_populate_smc_link_level(rdev, table);
355862306a36Sopenharmony_ci
355962306a36Sopenharmony_ci	ret = ci_populate_smc_acpi_level(rdev, table);
356062306a36Sopenharmony_ci	if (ret)
356162306a36Sopenharmony_ci		return ret;
356262306a36Sopenharmony_ci
356362306a36Sopenharmony_ci	ret = ci_populate_smc_vce_level(rdev, table);
356462306a36Sopenharmony_ci	if (ret)
356562306a36Sopenharmony_ci		return ret;
356662306a36Sopenharmony_ci
356762306a36Sopenharmony_ci	ret = ci_populate_smc_acp_level(rdev, table);
356862306a36Sopenharmony_ci	if (ret)
356962306a36Sopenharmony_ci		return ret;
357062306a36Sopenharmony_ci
357162306a36Sopenharmony_ci	ret = ci_populate_smc_samu_level(rdev, table);
357262306a36Sopenharmony_ci	if (ret)
357362306a36Sopenharmony_ci		return ret;
357462306a36Sopenharmony_ci
357562306a36Sopenharmony_ci	ret = ci_do_program_memory_timing_parameters(rdev);
357662306a36Sopenharmony_ci	if (ret)
357762306a36Sopenharmony_ci		return ret;
357862306a36Sopenharmony_ci
357962306a36Sopenharmony_ci	ret = ci_populate_smc_uvd_level(rdev, table);
358062306a36Sopenharmony_ci	if (ret)
358162306a36Sopenharmony_ci		return ret;
358262306a36Sopenharmony_ci
358362306a36Sopenharmony_ci	table->UvdBootLevel  = 0;
358462306a36Sopenharmony_ci	table->VceBootLevel  = 0;
358562306a36Sopenharmony_ci	table->AcpBootLevel  = 0;
358662306a36Sopenharmony_ci	table->SamuBootLevel  = 0;
358762306a36Sopenharmony_ci	table->GraphicsBootLevel  = 0;
358862306a36Sopenharmony_ci	table->MemoryBootLevel  = 0;
358962306a36Sopenharmony_ci
359062306a36Sopenharmony_ci	ret = ci_find_boot_level(&pi->dpm_table.sclk_table,
359162306a36Sopenharmony_ci				 pi->vbios_boot_state.sclk_bootup_value,
359262306a36Sopenharmony_ci				 (u32 *)&pi->smc_state_table.GraphicsBootLevel);
359362306a36Sopenharmony_ci
359462306a36Sopenharmony_ci	ret = ci_find_boot_level(&pi->dpm_table.mclk_table,
359562306a36Sopenharmony_ci				 pi->vbios_boot_state.mclk_bootup_value,
359662306a36Sopenharmony_ci				 (u32 *)&pi->smc_state_table.MemoryBootLevel);
359762306a36Sopenharmony_ci
359862306a36Sopenharmony_ci	table->BootVddc = pi->vbios_boot_state.vddc_bootup_value;
359962306a36Sopenharmony_ci	table->BootVddci = pi->vbios_boot_state.vddci_bootup_value;
360062306a36Sopenharmony_ci	table->BootMVdd = pi->vbios_boot_state.mvdd_bootup_value;
360162306a36Sopenharmony_ci
360262306a36Sopenharmony_ci	ci_populate_smc_initial_state(rdev, radeon_boot_state);
360362306a36Sopenharmony_ci
360462306a36Sopenharmony_ci	ret = ci_populate_bapm_parameters_in_dpm_table(rdev);
360562306a36Sopenharmony_ci	if (ret)
360662306a36Sopenharmony_ci		return ret;
360762306a36Sopenharmony_ci
360862306a36Sopenharmony_ci	table->UVDInterval = 1;
360962306a36Sopenharmony_ci	table->VCEInterval = 1;
361062306a36Sopenharmony_ci	table->ACPInterval = 1;
361162306a36Sopenharmony_ci	table->SAMUInterval = 1;
361262306a36Sopenharmony_ci	table->GraphicsVoltageChangeEnable = 1;
361362306a36Sopenharmony_ci	table->GraphicsThermThrottleEnable = 1;
361462306a36Sopenharmony_ci	table->GraphicsInterval = 1;
361562306a36Sopenharmony_ci	table->VoltageInterval = 1;
361662306a36Sopenharmony_ci	table->ThermalInterval = 1;
361762306a36Sopenharmony_ci	table->TemperatureLimitHigh = (u16)((pi->thermal_temp_setting.temperature_high *
361862306a36Sopenharmony_ci					     CISLANDS_Q88_FORMAT_CONVERSION_UNIT) / 1000);
361962306a36Sopenharmony_ci	table->TemperatureLimitLow = (u16)((pi->thermal_temp_setting.temperature_low *
362062306a36Sopenharmony_ci					    CISLANDS_Q88_FORMAT_CONVERSION_UNIT) / 1000);
362162306a36Sopenharmony_ci	table->MemoryVoltageChangeEnable = 1;
362262306a36Sopenharmony_ci	table->MemoryInterval = 1;
362362306a36Sopenharmony_ci	table->VoltageResponseTime = 0;
362462306a36Sopenharmony_ci	table->VddcVddciDelta = 4000;
362562306a36Sopenharmony_ci	table->PhaseResponseTime = 0;
362662306a36Sopenharmony_ci	table->MemoryThermThrottleEnable = 1;
362762306a36Sopenharmony_ci	table->PCIeBootLinkLevel = pi->dpm_table.pcie_speed_table.count - 1;
362862306a36Sopenharmony_ci	table->PCIeGenInterval = 1;
362962306a36Sopenharmony_ci	if (pi->voltage_control == CISLANDS_VOLTAGE_CONTROL_BY_SVID2)
363062306a36Sopenharmony_ci		table->SVI2Enable  = 1;
363162306a36Sopenharmony_ci	else
363262306a36Sopenharmony_ci		table->SVI2Enable  = 0;
363362306a36Sopenharmony_ci
363462306a36Sopenharmony_ci	table->ThermGpio = 17;
363562306a36Sopenharmony_ci	table->SclkStepSize = 0x4000;
363662306a36Sopenharmony_ci
363762306a36Sopenharmony_ci	table->SystemFlags = cpu_to_be32(table->SystemFlags);
363862306a36Sopenharmony_ci	table->SmioMaskVddcVid = cpu_to_be32(table->SmioMaskVddcVid);
363962306a36Sopenharmony_ci	table->SmioMaskVddcPhase = cpu_to_be32(table->SmioMaskVddcPhase);
364062306a36Sopenharmony_ci	table->SmioMaskVddciVid = cpu_to_be32(table->SmioMaskVddciVid);
364162306a36Sopenharmony_ci	table->SmioMaskMvddVid = cpu_to_be32(table->SmioMaskMvddVid);
364262306a36Sopenharmony_ci	table->SclkStepSize = cpu_to_be32(table->SclkStepSize);
364362306a36Sopenharmony_ci	table->TemperatureLimitHigh = cpu_to_be16(table->TemperatureLimitHigh);
364462306a36Sopenharmony_ci	table->TemperatureLimitLow = cpu_to_be16(table->TemperatureLimitLow);
364562306a36Sopenharmony_ci	table->VddcVddciDelta = cpu_to_be16(table->VddcVddciDelta);
364662306a36Sopenharmony_ci	table->VoltageResponseTime = cpu_to_be16(table->VoltageResponseTime);
364762306a36Sopenharmony_ci	table->PhaseResponseTime = cpu_to_be16(table->PhaseResponseTime);
364862306a36Sopenharmony_ci	table->BootVddc = cpu_to_be16(table->BootVddc * VOLTAGE_SCALE);
364962306a36Sopenharmony_ci	table->BootVddci = cpu_to_be16(table->BootVddci * VOLTAGE_SCALE);
365062306a36Sopenharmony_ci	table->BootMVdd = cpu_to_be16(table->BootMVdd * VOLTAGE_SCALE);
365162306a36Sopenharmony_ci
365262306a36Sopenharmony_ci	ret = ci_copy_bytes_to_smc(rdev,
365362306a36Sopenharmony_ci				   pi->dpm_table_start +
365462306a36Sopenharmony_ci				   offsetof(SMU7_Discrete_DpmTable, SystemFlags),
365562306a36Sopenharmony_ci				   (u8 *)&table->SystemFlags,
365662306a36Sopenharmony_ci				   sizeof(SMU7_Discrete_DpmTable) - 3 * sizeof(SMU7_PIDController),
365762306a36Sopenharmony_ci				   pi->sram_end);
365862306a36Sopenharmony_ci	if (ret)
365962306a36Sopenharmony_ci		return ret;
366062306a36Sopenharmony_ci
366162306a36Sopenharmony_ci	return 0;
366262306a36Sopenharmony_ci}
366362306a36Sopenharmony_ci
366462306a36Sopenharmony_cistatic void ci_trim_single_dpm_states(struct radeon_device *rdev,
366562306a36Sopenharmony_ci				      struct ci_single_dpm_table *dpm_table,
366662306a36Sopenharmony_ci				      u32 low_limit, u32 high_limit)
366762306a36Sopenharmony_ci{
366862306a36Sopenharmony_ci	u32 i;
366962306a36Sopenharmony_ci
367062306a36Sopenharmony_ci	for (i = 0; i < dpm_table->count; i++) {
367162306a36Sopenharmony_ci		if ((dpm_table->dpm_levels[i].value < low_limit) ||
367262306a36Sopenharmony_ci		    (dpm_table->dpm_levels[i].value > high_limit))
367362306a36Sopenharmony_ci			dpm_table->dpm_levels[i].enabled = false;
367462306a36Sopenharmony_ci		else
367562306a36Sopenharmony_ci			dpm_table->dpm_levels[i].enabled = true;
367662306a36Sopenharmony_ci	}
367762306a36Sopenharmony_ci}
367862306a36Sopenharmony_ci
367962306a36Sopenharmony_cistatic void ci_trim_pcie_dpm_states(struct radeon_device *rdev,
368062306a36Sopenharmony_ci				    u32 speed_low, u32 lanes_low,
368162306a36Sopenharmony_ci				    u32 speed_high, u32 lanes_high)
368262306a36Sopenharmony_ci{
368362306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
368462306a36Sopenharmony_ci	struct ci_single_dpm_table *pcie_table = &pi->dpm_table.pcie_speed_table;
368562306a36Sopenharmony_ci	u32 i, j;
368662306a36Sopenharmony_ci
368762306a36Sopenharmony_ci	for (i = 0; i < pcie_table->count; i++) {
368862306a36Sopenharmony_ci		if ((pcie_table->dpm_levels[i].value < speed_low) ||
368962306a36Sopenharmony_ci		    (pcie_table->dpm_levels[i].param1 < lanes_low) ||
369062306a36Sopenharmony_ci		    (pcie_table->dpm_levels[i].value > speed_high) ||
369162306a36Sopenharmony_ci		    (pcie_table->dpm_levels[i].param1 > lanes_high))
369262306a36Sopenharmony_ci			pcie_table->dpm_levels[i].enabled = false;
369362306a36Sopenharmony_ci		else
369462306a36Sopenharmony_ci			pcie_table->dpm_levels[i].enabled = true;
369562306a36Sopenharmony_ci	}
369662306a36Sopenharmony_ci
369762306a36Sopenharmony_ci	for (i = 0; i < pcie_table->count; i++) {
369862306a36Sopenharmony_ci		if (pcie_table->dpm_levels[i].enabled) {
369962306a36Sopenharmony_ci			for (j = i + 1; j < pcie_table->count; j++) {
370062306a36Sopenharmony_ci				if (pcie_table->dpm_levels[j].enabled) {
370162306a36Sopenharmony_ci					if ((pcie_table->dpm_levels[i].value == pcie_table->dpm_levels[j].value) &&
370262306a36Sopenharmony_ci					    (pcie_table->dpm_levels[i].param1 == pcie_table->dpm_levels[j].param1))
370362306a36Sopenharmony_ci						pcie_table->dpm_levels[j].enabled = false;
370462306a36Sopenharmony_ci				}
370562306a36Sopenharmony_ci			}
370662306a36Sopenharmony_ci		}
370762306a36Sopenharmony_ci	}
370862306a36Sopenharmony_ci}
370962306a36Sopenharmony_ci
371062306a36Sopenharmony_cistatic int ci_trim_dpm_states(struct radeon_device *rdev,
371162306a36Sopenharmony_ci			      struct radeon_ps *radeon_state)
371262306a36Sopenharmony_ci{
371362306a36Sopenharmony_ci	struct ci_ps *state = ci_get_ps(radeon_state);
371462306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
371562306a36Sopenharmony_ci	u32 high_limit_count;
371662306a36Sopenharmony_ci
371762306a36Sopenharmony_ci	if (state->performance_level_count < 1)
371862306a36Sopenharmony_ci		return -EINVAL;
371962306a36Sopenharmony_ci
372062306a36Sopenharmony_ci	if (state->performance_level_count == 1)
372162306a36Sopenharmony_ci		high_limit_count = 0;
372262306a36Sopenharmony_ci	else
372362306a36Sopenharmony_ci		high_limit_count = 1;
372462306a36Sopenharmony_ci
372562306a36Sopenharmony_ci	ci_trim_single_dpm_states(rdev,
372662306a36Sopenharmony_ci				  &pi->dpm_table.sclk_table,
372762306a36Sopenharmony_ci				  state->performance_levels[0].sclk,
372862306a36Sopenharmony_ci				  state->performance_levels[high_limit_count].sclk);
372962306a36Sopenharmony_ci
373062306a36Sopenharmony_ci	ci_trim_single_dpm_states(rdev,
373162306a36Sopenharmony_ci				  &pi->dpm_table.mclk_table,
373262306a36Sopenharmony_ci				  state->performance_levels[0].mclk,
373362306a36Sopenharmony_ci				  state->performance_levels[high_limit_count].mclk);
373462306a36Sopenharmony_ci
373562306a36Sopenharmony_ci	ci_trim_pcie_dpm_states(rdev,
373662306a36Sopenharmony_ci				state->performance_levels[0].pcie_gen,
373762306a36Sopenharmony_ci				state->performance_levels[0].pcie_lane,
373862306a36Sopenharmony_ci				state->performance_levels[high_limit_count].pcie_gen,
373962306a36Sopenharmony_ci				state->performance_levels[high_limit_count].pcie_lane);
374062306a36Sopenharmony_ci
374162306a36Sopenharmony_ci	return 0;
374262306a36Sopenharmony_ci}
374362306a36Sopenharmony_ci
374462306a36Sopenharmony_cistatic int ci_apply_disp_minimum_voltage_request(struct radeon_device *rdev)
374562306a36Sopenharmony_ci{
374662306a36Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *disp_voltage_table =
374762306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk;
374862306a36Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *vddc_table =
374962306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
375062306a36Sopenharmony_ci	u32 requested_voltage = 0;
375162306a36Sopenharmony_ci	u32 i;
375262306a36Sopenharmony_ci
375362306a36Sopenharmony_ci	if (disp_voltage_table == NULL)
375462306a36Sopenharmony_ci		return -EINVAL;
375562306a36Sopenharmony_ci	if (!disp_voltage_table->count)
375662306a36Sopenharmony_ci		return -EINVAL;
375762306a36Sopenharmony_ci
375862306a36Sopenharmony_ci	for (i = 0; i < disp_voltage_table->count; i++) {
375962306a36Sopenharmony_ci		if (rdev->clock.current_dispclk == disp_voltage_table->entries[i].clk)
376062306a36Sopenharmony_ci			requested_voltage = disp_voltage_table->entries[i].v;
376162306a36Sopenharmony_ci	}
376262306a36Sopenharmony_ci
376362306a36Sopenharmony_ci	for (i = 0; i < vddc_table->count; i++) {
376462306a36Sopenharmony_ci		if (requested_voltage <= vddc_table->entries[i].v) {
376562306a36Sopenharmony_ci			requested_voltage = vddc_table->entries[i].v;
376662306a36Sopenharmony_ci			return (ci_send_msg_to_smc_with_parameter(rdev,
376762306a36Sopenharmony_ci								  PPSMC_MSG_VddC_Request,
376862306a36Sopenharmony_ci								  requested_voltage * VOLTAGE_SCALE) == PPSMC_Result_OK) ?
376962306a36Sopenharmony_ci				0 : -EINVAL;
377062306a36Sopenharmony_ci		}
377162306a36Sopenharmony_ci	}
377262306a36Sopenharmony_ci
377362306a36Sopenharmony_ci	return -EINVAL;
377462306a36Sopenharmony_ci}
377562306a36Sopenharmony_ci
377662306a36Sopenharmony_cistatic int ci_upload_dpm_level_enable_mask(struct radeon_device *rdev)
377762306a36Sopenharmony_ci{
377862306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
377962306a36Sopenharmony_ci	PPSMC_Result result;
378062306a36Sopenharmony_ci
378162306a36Sopenharmony_ci	ci_apply_disp_minimum_voltage_request(rdev);
378262306a36Sopenharmony_ci
378362306a36Sopenharmony_ci	if (!pi->sclk_dpm_key_disabled) {
378462306a36Sopenharmony_ci		if (pi->dpm_level_enable_mask.sclk_dpm_enable_mask) {
378562306a36Sopenharmony_ci			result = ci_send_msg_to_smc_with_parameter(rdev,
378662306a36Sopenharmony_ci								   PPSMC_MSG_SCLKDPM_SetEnabledMask,
378762306a36Sopenharmony_ci								   pi->dpm_level_enable_mask.sclk_dpm_enable_mask);
378862306a36Sopenharmony_ci			if (result != PPSMC_Result_OK)
378962306a36Sopenharmony_ci				return -EINVAL;
379062306a36Sopenharmony_ci		}
379162306a36Sopenharmony_ci	}
379262306a36Sopenharmony_ci
379362306a36Sopenharmony_ci	if (!pi->mclk_dpm_key_disabled) {
379462306a36Sopenharmony_ci		if (pi->dpm_level_enable_mask.mclk_dpm_enable_mask) {
379562306a36Sopenharmony_ci			result = ci_send_msg_to_smc_with_parameter(rdev,
379662306a36Sopenharmony_ci								   PPSMC_MSG_MCLKDPM_SetEnabledMask,
379762306a36Sopenharmony_ci								   pi->dpm_level_enable_mask.mclk_dpm_enable_mask);
379862306a36Sopenharmony_ci			if (result != PPSMC_Result_OK)
379962306a36Sopenharmony_ci				return -EINVAL;
380062306a36Sopenharmony_ci		}
380162306a36Sopenharmony_ci	}
380262306a36Sopenharmony_ci#if 0
380362306a36Sopenharmony_ci	if (!pi->pcie_dpm_key_disabled) {
380462306a36Sopenharmony_ci		if (pi->dpm_level_enable_mask.pcie_dpm_enable_mask) {
380562306a36Sopenharmony_ci			result = ci_send_msg_to_smc_with_parameter(rdev,
380662306a36Sopenharmony_ci								   PPSMC_MSG_PCIeDPM_SetEnabledMask,
380762306a36Sopenharmony_ci								   pi->dpm_level_enable_mask.pcie_dpm_enable_mask);
380862306a36Sopenharmony_ci			if (result != PPSMC_Result_OK)
380962306a36Sopenharmony_ci				return -EINVAL;
381062306a36Sopenharmony_ci		}
381162306a36Sopenharmony_ci	}
381262306a36Sopenharmony_ci#endif
381362306a36Sopenharmony_ci	return 0;
381462306a36Sopenharmony_ci}
381562306a36Sopenharmony_ci
381662306a36Sopenharmony_cistatic void ci_find_dpm_states_clocks_in_dpm_table(struct radeon_device *rdev,
381762306a36Sopenharmony_ci						   struct radeon_ps *radeon_state)
381862306a36Sopenharmony_ci{
381962306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
382062306a36Sopenharmony_ci	struct ci_ps *state = ci_get_ps(radeon_state);
382162306a36Sopenharmony_ci	struct ci_single_dpm_table *sclk_table = &pi->dpm_table.sclk_table;
382262306a36Sopenharmony_ci	u32 sclk = state->performance_levels[state->performance_level_count-1].sclk;
382362306a36Sopenharmony_ci	struct ci_single_dpm_table *mclk_table = &pi->dpm_table.mclk_table;
382462306a36Sopenharmony_ci	u32 mclk = state->performance_levels[state->performance_level_count-1].mclk;
382562306a36Sopenharmony_ci	u32 i;
382662306a36Sopenharmony_ci
382762306a36Sopenharmony_ci	pi->need_update_smu7_dpm_table = 0;
382862306a36Sopenharmony_ci
382962306a36Sopenharmony_ci	for (i = 0; i < sclk_table->count; i++) {
383062306a36Sopenharmony_ci		if (sclk == sclk_table->dpm_levels[i].value)
383162306a36Sopenharmony_ci			break;
383262306a36Sopenharmony_ci	}
383362306a36Sopenharmony_ci
383462306a36Sopenharmony_ci	if (i >= sclk_table->count) {
383562306a36Sopenharmony_ci		pi->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK;
383662306a36Sopenharmony_ci	} else {
383762306a36Sopenharmony_ci		/* XXX The current code always reprogrammed the sclk levels,
383862306a36Sopenharmony_ci		 * but we don't currently handle disp sclk requirements
383962306a36Sopenharmony_ci		 * so just skip it.
384062306a36Sopenharmony_ci		 */
384162306a36Sopenharmony_ci		if (CISLAND_MINIMUM_ENGINE_CLOCK != CISLAND_MINIMUM_ENGINE_CLOCK)
384262306a36Sopenharmony_ci			pi->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_SCLK;
384362306a36Sopenharmony_ci	}
384462306a36Sopenharmony_ci
384562306a36Sopenharmony_ci	for (i = 0; i < mclk_table->count; i++) {
384662306a36Sopenharmony_ci		if (mclk == mclk_table->dpm_levels[i].value)
384762306a36Sopenharmony_ci			break;
384862306a36Sopenharmony_ci	}
384962306a36Sopenharmony_ci
385062306a36Sopenharmony_ci	if (i >= mclk_table->count)
385162306a36Sopenharmony_ci		pi->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_MCLK;
385262306a36Sopenharmony_ci
385362306a36Sopenharmony_ci	if (rdev->pm.dpm.current_active_crtc_count !=
385462306a36Sopenharmony_ci	    rdev->pm.dpm.new_active_crtc_count)
385562306a36Sopenharmony_ci		pi->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_MCLK;
385662306a36Sopenharmony_ci}
385762306a36Sopenharmony_ci
385862306a36Sopenharmony_cistatic int ci_populate_and_upload_sclk_mclk_dpm_levels(struct radeon_device *rdev,
385962306a36Sopenharmony_ci						       struct radeon_ps *radeon_state)
386062306a36Sopenharmony_ci{
386162306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
386262306a36Sopenharmony_ci	struct ci_ps *state = ci_get_ps(radeon_state);
386362306a36Sopenharmony_ci	u32 sclk = state->performance_levels[state->performance_level_count-1].sclk;
386462306a36Sopenharmony_ci	u32 mclk = state->performance_levels[state->performance_level_count-1].mclk;
386562306a36Sopenharmony_ci	struct ci_dpm_table *dpm_table = &pi->dpm_table;
386662306a36Sopenharmony_ci	int ret;
386762306a36Sopenharmony_ci
386862306a36Sopenharmony_ci	if (!pi->need_update_smu7_dpm_table)
386962306a36Sopenharmony_ci		return 0;
387062306a36Sopenharmony_ci
387162306a36Sopenharmony_ci	if (pi->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_SCLK)
387262306a36Sopenharmony_ci		dpm_table->sclk_table.dpm_levels[dpm_table->sclk_table.count-1].value = sclk;
387362306a36Sopenharmony_ci
387462306a36Sopenharmony_ci	if (pi->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)
387562306a36Sopenharmony_ci		dpm_table->mclk_table.dpm_levels[dpm_table->mclk_table.count-1].value = mclk;
387662306a36Sopenharmony_ci
387762306a36Sopenharmony_ci	if (pi->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_UPDATE_SCLK)) {
387862306a36Sopenharmony_ci		ret = ci_populate_all_graphic_levels(rdev);
387962306a36Sopenharmony_ci		if (ret)
388062306a36Sopenharmony_ci			return ret;
388162306a36Sopenharmony_ci	}
388262306a36Sopenharmony_ci
388362306a36Sopenharmony_ci	if (pi->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_MCLK | DPMTABLE_UPDATE_MCLK)) {
388462306a36Sopenharmony_ci		ret = ci_populate_all_memory_levels(rdev);
388562306a36Sopenharmony_ci		if (ret)
388662306a36Sopenharmony_ci			return ret;
388762306a36Sopenharmony_ci	}
388862306a36Sopenharmony_ci
388962306a36Sopenharmony_ci	return 0;
389062306a36Sopenharmony_ci}
389162306a36Sopenharmony_ci
389262306a36Sopenharmony_cistatic int ci_enable_uvd_dpm(struct radeon_device *rdev, bool enable)
389362306a36Sopenharmony_ci{
389462306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
389562306a36Sopenharmony_ci	const struct radeon_clock_and_voltage_limits *max_limits;
389662306a36Sopenharmony_ci	int i;
389762306a36Sopenharmony_ci
389862306a36Sopenharmony_ci	if (rdev->pm.dpm.ac_power)
389962306a36Sopenharmony_ci		max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
390062306a36Sopenharmony_ci	else
390162306a36Sopenharmony_ci		max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
390262306a36Sopenharmony_ci
390362306a36Sopenharmony_ci	if (enable) {
390462306a36Sopenharmony_ci		pi->dpm_level_enable_mask.uvd_dpm_enable_mask = 0;
390562306a36Sopenharmony_ci
390662306a36Sopenharmony_ci		for (i = rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count - 1; i >= 0; i--) {
390762306a36Sopenharmony_ci			if (rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[i].v <= max_limits->vddc) {
390862306a36Sopenharmony_ci				pi->dpm_level_enable_mask.uvd_dpm_enable_mask |= 1 << i;
390962306a36Sopenharmony_ci
391062306a36Sopenharmony_ci				if (!pi->caps_uvd_dpm)
391162306a36Sopenharmony_ci					break;
391262306a36Sopenharmony_ci			}
391362306a36Sopenharmony_ci		}
391462306a36Sopenharmony_ci
391562306a36Sopenharmony_ci		ci_send_msg_to_smc_with_parameter(rdev,
391662306a36Sopenharmony_ci						  PPSMC_MSG_UVDDPM_SetEnabledMask,
391762306a36Sopenharmony_ci						  pi->dpm_level_enable_mask.uvd_dpm_enable_mask);
391862306a36Sopenharmony_ci
391962306a36Sopenharmony_ci		if (pi->last_mclk_dpm_enable_mask & 0x1) {
392062306a36Sopenharmony_ci			pi->uvd_enabled = true;
392162306a36Sopenharmony_ci			pi->dpm_level_enable_mask.mclk_dpm_enable_mask &= 0xFFFFFFFE;
392262306a36Sopenharmony_ci			ci_send_msg_to_smc_with_parameter(rdev,
392362306a36Sopenharmony_ci							  PPSMC_MSG_MCLKDPM_SetEnabledMask,
392462306a36Sopenharmony_ci							  pi->dpm_level_enable_mask.mclk_dpm_enable_mask);
392562306a36Sopenharmony_ci		}
392662306a36Sopenharmony_ci	} else {
392762306a36Sopenharmony_ci		if (pi->last_mclk_dpm_enable_mask & 0x1) {
392862306a36Sopenharmony_ci			pi->uvd_enabled = false;
392962306a36Sopenharmony_ci			pi->dpm_level_enable_mask.mclk_dpm_enable_mask |= 1;
393062306a36Sopenharmony_ci			ci_send_msg_to_smc_with_parameter(rdev,
393162306a36Sopenharmony_ci							  PPSMC_MSG_MCLKDPM_SetEnabledMask,
393262306a36Sopenharmony_ci							  pi->dpm_level_enable_mask.mclk_dpm_enable_mask);
393362306a36Sopenharmony_ci		}
393462306a36Sopenharmony_ci	}
393562306a36Sopenharmony_ci
393662306a36Sopenharmony_ci	return (ci_send_msg_to_smc(rdev, enable ?
393762306a36Sopenharmony_ci				   PPSMC_MSG_UVDDPM_Enable : PPSMC_MSG_UVDDPM_Disable) == PPSMC_Result_OK) ?
393862306a36Sopenharmony_ci		0 : -EINVAL;
393962306a36Sopenharmony_ci}
394062306a36Sopenharmony_ci
394162306a36Sopenharmony_cistatic int ci_enable_vce_dpm(struct radeon_device *rdev, bool enable)
394262306a36Sopenharmony_ci{
394362306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
394462306a36Sopenharmony_ci	const struct radeon_clock_and_voltage_limits *max_limits;
394562306a36Sopenharmony_ci	int i;
394662306a36Sopenharmony_ci
394762306a36Sopenharmony_ci	if (rdev->pm.dpm.ac_power)
394862306a36Sopenharmony_ci		max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
394962306a36Sopenharmony_ci	else
395062306a36Sopenharmony_ci		max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
395162306a36Sopenharmony_ci
395262306a36Sopenharmony_ci	if (enable) {
395362306a36Sopenharmony_ci		pi->dpm_level_enable_mask.vce_dpm_enable_mask = 0;
395462306a36Sopenharmony_ci		for (i = rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.count - 1; i >= 0; i--) {
395562306a36Sopenharmony_ci			if (rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[i].v <= max_limits->vddc) {
395662306a36Sopenharmony_ci				pi->dpm_level_enable_mask.vce_dpm_enable_mask |= 1 << i;
395762306a36Sopenharmony_ci
395862306a36Sopenharmony_ci				if (!pi->caps_vce_dpm)
395962306a36Sopenharmony_ci					break;
396062306a36Sopenharmony_ci			}
396162306a36Sopenharmony_ci		}
396262306a36Sopenharmony_ci
396362306a36Sopenharmony_ci		ci_send_msg_to_smc_with_parameter(rdev,
396462306a36Sopenharmony_ci						  PPSMC_MSG_VCEDPM_SetEnabledMask,
396562306a36Sopenharmony_ci						  pi->dpm_level_enable_mask.vce_dpm_enable_mask);
396662306a36Sopenharmony_ci	}
396762306a36Sopenharmony_ci
396862306a36Sopenharmony_ci	return (ci_send_msg_to_smc(rdev, enable ?
396962306a36Sopenharmony_ci				   PPSMC_MSG_VCEDPM_Enable : PPSMC_MSG_VCEDPM_Disable) == PPSMC_Result_OK) ?
397062306a36Sopenharmony_ci		0 : -EINVAL;
397162306a36Sopenharmony_ci}
397262306a36Sopenharmony_ci
397362306a36Sopenharmony_ci#if 0
397462306a36Sopenharmony_cistatic int ci_enable_samu_dpm(struct radeon_device *rdev, bool enable)
397562306a36Sopenharmony_ci{
397662306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
397762306a36Sopenharmony_ci	const struct radeon_clock_and_voltage_limits *max_limits;
397862306a36Sopenharmony_ci	int i;
397962306a36Sopenharmony_ci
398062306a36Sopenharmony_ci	if (rdev->pm.dpm.ac_power)
398162306a36Sopenharmony_ci		max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
398262306a36Sopenharmony_ci	else
398362306a36Sopenharmony_ci		max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
398462306a36Sopenharmony_ci
398562306a36Sopenharmony_ci	if (enable) {
398662306a36Sopenharmony_ci		pi->dpm_level_enable_mask.samu_dpm_enable_mask = 0;
398762306a36Sopenharmony_ci		for (i = rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.count - 1; i >= 0; i--) {
398862306a36Sopenharmony_ci			if (rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries[i].v <= max_limits->vddc) {
398962306a36Sopenharmony_ci				pi->dpm_level_enable_mask.samu_dpm_enable_mask |= 1 << i;
399062306a36Sopenharmony_ci
399162306a36Sopenharmony_ci				if (!pi->caps_samu_dpm)
399262306a36Sopenharmony_ci					break;
399362306a36Sopenharmony_ci			}
399462306a36Sopenharmony_ci		}
399562306a36Sopenharmony_ci
399662306a36Sopenharmony_ci		ci_send_msg_to_smc_with_parameter(rdev,
399762306a36Sopenharmony_ci						  PPSMC_MSG_SAMUDPM_SetEnabledMask,
399862306a36Sopenharmony_ci						  pi->dpm_level_enable_mask.samu_dpm_enable_mask);
399962306a36Sopenharmony_ci	}
400062306a36Sopenharmony_ci	return (ci_send_msg_to_smc(rdev, enable ?
400162306a36Sopenharmony_ci				   PPSMC_MSG_SAMUDPM_Enable : PPSMC_MSG_SAMUDPM_Disable) == PPSMC_Result_OK) ?
400262306a36Sopenharmony_ci		0 : -EINVAL;
400362306a36Sopenharmony_ci}
400462306a36Sopenharmony_ci
400562306a36Sopenharmony_cistatic int ci_enable_acp_dpm(struct radeon_device *rdev, bool enable)
400662306a36Sopenharmony_ci{
400762306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
400862306a36Sopenharmony_ci	const struct radeon_clock_and_voltage_limits *max_limits;
400962306a36Sopenharmony_ci	int i;
401062306a36Sopenharmony_ci
401162306a36Sopenharmony_ci	if (rdev->pm.dpm.ac_power)
401262306a36Sopenharmony_ci		max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
401362306a36Sopenharmony_ci	else
401462306a36Sopenharmony_ci		max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
401562306a36Sopenharmony_ci
401662306a36Sopenharmony_ci	if (enable) {
401762306a36Sopenharmony_ci		pi->dpm_level_enable_mask.acp_dpm_enable_mask = 0;
401862306a36Sopenharmony_ci		for (i = rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.count - 1; i >= 0; i--) {
401962306a36Sopenharmony_ci			if (rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries[i].v <= max_limits->vddc) {
402062306a36Sopenharmony_ci				pi->dpm_level_enable_mask.acp_dpm_enable_mask |= 1 << i;
402162306a36Sopenharmony_ci
402262306a36Sopenharmony_ci				if (!pi->caps_acp_dpm)
402362306a36Sopenharmony_ci					break;
402462306a36Sopenharmony_ci			}
402562306a36Sopenharmony_ci		}
402662306a36Sopenharmony_ci
402762306a36Sopenharmony_ci		ci_send_msg_to_smc_with_parameter(rdev,
402862306a36Sopenharmony_ci						  PPSMC_MSG_ACPDPM_SetEnabledMask,
402962306a36Sopenharmony_ci						  pi->dpm_level_enable_mask.acp_dpm_enable_mask);
403062306a36Sopenharmony_ci	}
403162306a36Sopenharmony_ci
403262306a36Sopenharmony_ci	return (ci_send_msg_to_smc(rdev, enable ?
403362306a36Sopenharmony_ci				   PPSMC_MSG_ACPDPM_Enable : PPSMC_MSG_ACPDPM_Disable) == PPSMC_Result_OK) ?
403462306a36Sopenharmony_ci		0 : -EINVAL;
403562306a36Sopenharmony_ci}
403662306a36Sopenharmony_ci#endif
403762306a36Sopenharmony_ci
403862306a36Sopenharmony_cistatic int ci_update_uvd_dpm(struct radeon_device *rdev, bool gate)
403962306a36Sopenharmony_ci{
404062306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
404162306a36Sopenharmony_ci	u32 tmp;
404262306a36Sopenharmony_ci
404362306a36Sopenharmony_ci	if (!gate) {
404462306a36Sopenharmony_ci		if (pi->caps_uvd_dpm ||
404562306a36Sopenharmony_ci		    (rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count <= 0))
404662306a36Sopenharmony_ci			pi->smc_state_table.UvdBootLevel = 0;
404762306a36Sopenharmony_ci		else
404862306a36Sopenharmony_ci			pi->smc_state_table.UvdBootLevel =
404962306a36Sopenharmony_ci				rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count - 1;
405062306a36Sopenharmony_ci
405162306a36Sopenharmony_ci		tmp = RREG32_SMC(DPM_TABLE_475);
405262306a36Sopenharmony_ci		tmp &= ~UvdBootLevel_MASK;
405362306a36Sopenharmony_ci		tmp |= UvdBootLevel(pi->smc_state_table.UvdBootLevel);
405462306a36Sopenharmony_ci		WREG32_SMC(DPM_TABLE_475, tmp);
405562306a36Sopenharmony_ci	}
405662306a36Sopenharmony_ci
405762306a36Sopenharmony_ci	return ci_enable_uvd_dpm(rdev, !gate);
405862306a36Sopenharmony_ci}
405962306a36Sopenharmony_ci
406062306a36Sopenharmony_cistatic u8 ci_get_vce_boot_level(struct radeon_device *rdev)
406162306a36Sopenharmony_ci{
406262306a36Sopenharmony_ci	u8 i;
406362306a36Sopenharmony_ci	u32 min_evclk = 30000; /* ??? */
406462306a36Sopenharmony_ci	struct radeon_vce_clock_voltage_dependency_table *table =
406562306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
406662306a36Sopenharmony_ci
406762306a36Sopenharmony_ci	for (i = 0; i < table->count; i++) {
406862306a36Sopenharmony_ci		if (table->entries[i].evclk >= min_evclk)
406962306a36Sopenharmony_ci			return i;
407062306a36Sopenharmony_ci	}
407162306a36Sopenharmony_ci
407262306a36Sopenharmony_ci	return table->count - 1;
407362306a36Sopenharmony_ci}
407462306a36Sopenharmony_ci
407562306a36Sopenharmony_cistatic int ci_update_vce_dpm(struct radeon_device *rdev,
407662306a36Sopenharmony_ci			     struct radeon_ps *radeon_new_state,
407762306a36Sopenharmony_ci			     struct radeon_ps *radeon_current_state)
407862306a36Sopenharmony_ci{
407962306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
408062306a36Sopenharmony_ci	int ret = 0;
408162306a36Sopenharmony_ci	u32 tmp;
408262306a36Sopenharmony_ci
408362306a36Sopenharmony_ci	if (radeon_current_state->evclk != radeon_new_state->evclk) {
408462306a36Sopenharmony_ci		if (radeon_new_state->evclk) {
408562306a36Sopenharmony_ci			/* turn the clocks on when encoding */
408662306a36Sopenharmony_ci			cik_update_cg(rdev, RADEON_CG_BLOCK_VCE, false);
408762306a36Sopenharmony_ci
408862306a36Sopenharmony_ci			pi->smc_state_table.VceBootLevel = ci_get_vce_boot_level(rdev);
408962306a36Sopenharmony_ci			tmp = RREG32_SMC(DPM_TABLE_475);
409062306a36Sopenharmony_ci			tmp &= ~VceBootLevel_MASK;
409162306a36Sopenharmony_ci			tmp |= VceBootLevel(pi->smc_state_table.VceBootLevel);
409262306a36Sopenharmony_ci			WREG32_SMC(DPM_TABLE_475, tmp);
409362306a36Sopenharmony_ci
409462306a36Sopenharmony_ci			ret = ci_enable_vce_dpm(rdev, true);
409562306a36Sopenharmony_ci		} else {
409662306a36Sopenharmony_ci			/* turn the clocks off when not encoding */
409762306a36Sopenharmony_ci			cik_update_cg(rdev, RADEON_CG_BLOCK_VCE, true);
409862306a36Sopenharmony_ci
409962306a36Sopenharmony_ci			ret = ci_enable_vce_dpm(rdev, false);
410062306a36Sopenharmony_ci		}
410162306a36Sopenharmony_ci	}
410262306a36Sopenharmony_ci	return ret;
410362306a36Sopenharmony_ci}
410462306a36Sopenharmony_ci
410562306a36Sopenharmony_ci#if 0
410662306a36Sopenharmony_cistatic int ci_update_samu_dpm(struct radeon_device *rdev, bool gate)
410762306a36Sopenharmony_ci{
410862306a36Sopenharmony_ci	return ci_enable_samu_dpm(rdev, gate);
410962306a36Sopenharmony_ci}
411062306a36Sopenharmony_ci
411162306a36Sopenharmony_cistatic int ci_update_acp_dpm(struct radeon_device *rdev, bool gate)
411262306a36Sopenharmony_ci{
411362306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
411462306a36Sopenharmony_ci	u32 tmp;
411562306a36Sopenharmony_ci
411662306a36Sopenharmony_ci	if (!gate) {
411762306a36Sopenharmony_ci		pi->smc_state_table.AcpBootLevel = 0;
411862306a36Sopenharmony_ci
411962306a36Sopenharmony_ci		tmp = RREG32_SMC(DPM_TABLE_475);
412062306a36Sopenharmony_ci		tmp &= ~AcpBootLevel_MASK;
412162306a36Sopenharmony_ci		tmp |= AcpBootLevel(pi->smc_state_table.AcpBootLevel);
412262306a36Sopenharmony_ci		WREG32_SMC(DPM_TABLE_475, tmp);
412362306a36Sopenharmony_ci	}
412462306a36Sopenharmony_ci
412562306a36Sopenharmony_ci	return ci_enable_acp_dpm(rdev, !gate);
412662306a36Sopenharmony_ci}
412762306a36Sopenharmony_ci#endif
412862306a36Sopenharmony_ci
412962306a36Sopenharmony_cistatic int ci_generate_dpm_level_enable_mask(struct radeon_device *rdev,
413062306a36Sopenharmony_ci					     struct radeon_ps *radeon_state)
413162306a36Sopenharmony_ci{
413262306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
413362306a36Sopenharmony_ci	int ret;
413462306a36Sopenharmony_ci
413562306a36Sopenharmony_ci	ret = ci_trim_dpm_states(rdev, radeon_state);
413662306a36Sopenharmony_ci	if (ret)
413762306a36Sopenharmony_ci		return ret;
413862306a36Sopenharmony_ci
413962306a36Sopenharmony_ci	pi->dpm_level_enable_mask.sclk_dpm_enable_mask =
414062306a36Sopenharmony_ci		ci_get_dpm_level_enable_mask_value(&pi->dpm_table.sclk_table);
414162306a36Sopenharmony_ci	pi->dpm_level_enable_mask.mclk_dpm_enable_mask =
414262306a36Sopenharmony_ci		ci_get_dpm_level_enable_mask_value(&pi->dpm_table.mclk_table);
414362306a36Sopenharmony_ci	pi->last_mclk_dpm_enable_mask =
414462306a36Sopenharmony_ci		pi->dpm_level_enable_mask.mclk_dpm_enable_mask;
414562306a36Sopenharmony_ci	if (pi->uvd_enabled) {
414662306a36Sopenharmony_ci		if (pi->dpm_level_enable_mask.mclk_dpm_enable_mask & 1)
414762306a36Sopenharmony_ci			pi->dpm_level_enable_mask.mclk_dpm_enable_mask &= 0xFFFFFFFE;
414862306a36Sopenharmony_ci	}
414962306a36Sopenharmony_ci	pi->dpm_level_enable_mask.pcie_dpm_enable_mask =
415062306a36Sopenharmony_ci		ci_get_dpm_level_enable_mask_value(&pi->dpm_table.pcie_speed_table);
415162306a36Sopenharmony_ci
415262306a36Sopenharmony_ci	return 0;
415362306a36Sopenharmony_ci}
415462306a36Sopenharmony_ci
415562306a36Sopenharmony_cistatic u32 ci_get_lowest_enabled_level(struct radeon_device *rdev,
415662306a36Sopenharmony_ci				       u32 level_mask)
415762306a36Sopenharmony_ci{
415862306a36Sopenharmony_ci	u32 level = 0;
415962306a36Sopenharmony_ci
416062306a36Sopenharmony_ci	while ((level_mask & (1 << level)) == 0)
416162306a36Sopenharmony_ci		level++;
416262306a36Sopenharmony_ci
416362306a36Sopenharmony_ci	return level;
416462306a36Sopenharmony_ci}
416562306a36Sopenharmony_ci
416662306a36Sopenharmony_ci
416762306a36Sopenharmony_ciint ci_dpm_force_performance_level(struct radeon_device *rdev,
416862306a36Sopenharmony_ci				   enum radeon_dpm_forced_level level)
416962306a36Sopenharmony_ci{
417062306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
417162306a36Sopenharmony_ci	u32 tmp, levels, i;
417262306a36Sopenharmony_ci	int ret;
417362306a36Sopenharmony_ci
417462306a36Sopenharmony_ci	if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
417562306a36Sopenharmony_ci		if ((!pi->pcie_dpm_key_disabled) &&
417662306a36Sopenharmony_ci		    pi->dpm_level_enable_mask.pcie_dpm_enable_mask) {
417762306a36Sopenharmony_ci			levels = 0;
417862306a36Sopenharmony_ci			tmp = pi->dpm_level_enable_mask.pcie_dpm_enable_mask;
417962306a36Sopenharmony_ci			while (tmp >>= 1)
418062306a36Sopenharmony_ci				levels++;
418162306a36Sopenharmony_ci			if (levels) {
418262306a36Sopenharmony_ci				ret = ci_dpm_force_state_pcie(rdev, level);
418362306a36Sopenharmony_ci				if (ret)
418462306a36Sopenharmony_ci					return ret;
418562306a36Sopenharmony_ci				for (i = 0; i < rdev->usec_timeout; i++) {
418662306a36Sopenharmony_ci					tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX_1) &
418762306a36Sopenharmony_ci					       CURR_PCIE_INDEX_MASK) >> CURR_PCIE_INDEX_SHIFT;
418862306a36Sopenharmony_ci					if (tmp == levels)
418962306a36Sopenharmony_ci						break;
419062306a36Sopenharmony_ci					udelay(1);
419162306a36Sopenharmony_ci				}
419262306a36Sopenharmony_ci			}
419362306a36Sopenharmony_ci		}
419462306a36Sopenharmony_ci		if ((!pi->sclk_dpm_key_disabled) &&
419562306a36Sopenharmony_ci		    pi->dpm_level_enable_mask.sclk_dpm_enable_mask) {
419662306a36Sopenharmony_ci			levels = 0;
419762306a36Sopenharmony_ci			tmp = pi->dpm_level_enable_mask.sclk_dpm_enable_mask;
419862306a36Sopenharmony_ci			while (tmp >>= 1)
419962306a36Sopenharmony_ci				levels++;
420062306a36Sopenharmony_ci			if (levels) {
420162306a36Sopenharmony_ci				ret = ci_dpm_force_state_sclk(rdev, levels);
420262306a36Sopenharmony_ci				if (ret)
420362306a36Sopenharmony_ci					return ret;
420462306a36Sopenharmony_ci				for (i = 0; i < rdev->usec_timeout; i++) {
420562306a36Sopenharmony_ci					tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) &
420662306a36Sopenharmony_ci					       CURR_SCLK_INDEX_MASK) >> CURR_SCLK_INDEX_SHIFT;
420762306a36Sopenharmony_ci					if (tmp == levels)
420862306a36Sopenharmony_ci						break;
420962306a36Sopenharmony_ci					udelay(1);
421062306a36Sopenharmony_ci				}
421162306a36Sopenharmony_ci			}
421262306a36Sopenharmony_ci		}
421362306a36Sopenharmony_ci		if ((!pi->mclk_dpm_key_disabled) &&
421462306a36Sopenharmony_ci		    pi->dpm_level_enable_mask.mclk_dpm_enable_mask) {
421562306a36Sopenharmony_ci			levels = 0;
421662306a36Sopenharmony_ci			tmp = pi->dpm_level_enable_mask.mclk_dpm_enable_mask;
421762306a36Sopenharmony_ci			while (tmp >>= 1)
421862306a36Sopenharmony_ci				levels++;
421962306a36Sopenharmony_ci			if (levels) {
422062306a36Sopenharmony_ci				ret = ci_dpm_force_state_mclk(rdev, levels);
422162306a36Sopenharmony_ci				if (ret)
422262306a36Sopenharmony_ci					return ret;
422362306a36Sopenharmony_ci				for (i = 0; i < rdev->usec_timeout; i++) {
422462306a36Sopenharmony_ci					tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) &
422562306a36Sopenharmony_ci					       CURR_MCLK_INDEX_MASK) >> CURR_MCLK_INDEX_SHIFT;
422662306a36Sopenharmony_ci					if (tmp == levels)
422762306a36Sopenharmony_ci						break;
422862306a36Sopenharmony_ci					udelay(1);
422962306a36Sopenharmony_ci				}
423062306a36Sopenharmony_ci			}
423162306a36Sopenharmony_ci		}
423262306a36Sopenharmony_ci	} else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
423362306a36Sopenharmony_ci		if ((!pi->sclk_dpm_key_disabled) &&
423462306a36Sopenharmony_ci		    pi->dpm_level_enable_mask.sclk_dpm_enable_mask) {
423562306a36Sopenharmony_ci			levels = ci_get_lowest_enabled_level(rdev,
423662306a36Sopenharmony_ci							     pi->dpm_level_enable_mask.sclk_dpm_enable_mask);
423762306a36Sopenharmony_ci			ret = ci_dpm_force_state_sclk(rdev, levels);
423862306a36Sopenharmony_ci			if (ret)
423962306a36Sopenharmony_ci				return ret;
424062306a36Sopenharmony_ci			for (i = 0; i < rdev->usec_timeout; i++) {
424162306a36Sopenharmony_ci				tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) &
424262306a36Sopenharmony_ci				       CURR_SCLK_INDEX_MASK) >> CURR_SCLK_INDEX_SHIFT;
424362306a36Sopenharmony_ci				if (tmp == levels)
424462306a36Sopenharmony_ci					break;
424562306a36Sopenharmony_ci				udelay(1);
424662306a36Sopenharmony_ci			}
424762306a36Sopenharmony_ci		}
424862306a36Sopenharmony_ci		if ((!pi->mclk_dpm_key_disabled) &&
424962306a36Sopenharmony_ci		    pi->dpm_level_enable_mask.mclk_dpm_enable_mask) {
425062306a36Sopenharmony_ci			levels = ci_get_lowest_enabled_level(rdev,
425162306a36Sopenharmony_ci							     pi->dpm_level_enable_mask.mclk_dpm_enable_mask);
425262306a36Sopenharmony_ci			ret = ci_dpm_force_state_mclk(rdev, levels);
425362306a36Sopenharmony_ci			if (ret)
425462306a36Sopenharmony_ci				return ret;
425562306a36Sopenharmony_ci			for (i = 0; i < rdev->usec_timeout; i++) {
425662306a36Sopenharmony_ci				tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) &
425762306a36Sopenharmony_ci				       CURR_MCLK_INDEX_MASK) >> CURR_MCLK_INDEX_SHIFT;
425862306a36Sopenharmony_ci				if (tmp == levels)
425962306a36Sopenharmony_ci					break;
426062306a36Sopenharmony_ci				udelay(1);
426162306a36Sopenharmony_ci			}
426262306a36Sopenharmony_ci		}
426362306a36Sopenharmony_ci		if ((!pi->pcie_dpm_key_disabled) &&
426462306a36Sopenharmony_ci		    pi->dpm_level_enable_mask.pcie_dpm_enable_mask) {
426562306a36Sopenharmony_ci			levels = ci_get_lowest_enabled_level(rdev,
426662306a36Sopenharmony_ci							     pi->dpm_level_enable_mask.pcie_dpm_enable_mask);
426762306a36Sopenharmony_ci			ret = ci_dpm_force_state_pcie(rdev, levels);
426862306a36Sopenharmony_ci			if (ret)
426962306a36Sopenharmony_ci				return ret;
427062306a36Sopenharmony_ci			for (i = 0; i < rdev->usec_timeout; i++) {
427162306a36Sopenharmony_ci				tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX_1) &
427262306a36Sopenharmony_ci				       CURR_PCIE_INDEX_MASK) >> CURR_PCIE_INDEX_SHIFT;
427362306a36Sopenharmony_ci				if (tmp == levels)
427462306a36Sopenharmony_ci					break;
427562306a36Sopenharmony_ci				udelay(1);
427662306a36Sopenharmony_ci			}
427762306a36Sopenharmony_ci		}
427862306a36Sopenharmony_ci	} else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) {
427962306a36Sopenharmony_ci		if (!pi->pcie_dpm_key_disabled) {
428062306a36Sopenharmony_ci			PPSMC_Result smc_result;
428162306a36Sopenharmony_ci
428262306a36Sopenharmony_ci			smc_result = ci_send_msg_to_smc(rdev,
428362306a36Sopenharmony_ci							PPSMC_MSG_PCIeDPM_UnForceLevel);
428462306a36Sopenharmony_ci			if (smc_result != PPSMC_Result_OK)
428562306a36Sopenharmony_ci				return -EINVAL;
428662306a36Sopenharmony_ci		}
428762306a36Sopenharmony_ci		ret = ci_upload_dpm_level_enable_mask(rdev);
428862306a36Sopenharmony_ci		if (ret)
428962306a36Sopenharmony_ci			return ret;
429062306a36Sopenharmony_ci	}
429162306a36Sopenharmony_ci
429262306a36Sopenharmony_ci	rdev->pm.dpm.forced_level = level;
429362306a36Sopenharmony_ci
429462306a36Sopenharmony_ci	return 0;
429562306a36Sopenharmony_ci}
429662306a36Sopenharmony_ci
429762306a36Sopenharmony_cistatic int ci_set_mc_special_registers(struct radeon_device *rdev,
429862306a36Sopenharmony_ci				       struct ci_mc_reg_table *table)
429962306a36Sopenharmony_ci{
430062306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
430162306a36Sopenharmony_ci	u8 i, j, k;
430262306a36Sopenharmony_ci	u32 temp_reg;
430362306a36Sopenharmony_ci
430462306a36Sopenharmony_ci	for (i = 0, j = table->last; i < table->last; i++) {
430562306a36Sopenharmony_ci		if (j >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
430662306a36Sopenharmony_ci			return -EINVAL;
430762306a36Sopenharmony_ci		switch(table->mc_reg_address[i].s1 << 2) {
430862306a36Sopenharmony_ci		case MC_SEQ_MISC1:
430962306a36Sopenharmony_ci			temp_reg = RREG32(MC_PMG_CMD_EMRS);
431062306a36Sopenharmony_ci			table->mc_reg_address[j].s1 = MC_PMG_CMD_EMRS >> 2;
431162306a36Sopenharmony_ci			table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_EMRS_LP >> 2;
431262306a36Sopenharmony_ci			for (k = 0; k < table->num_entries; k++) {
431362306a36Sopenharmony_ci				table->mc_reg_table_entry[k].mc_data[j] =
431462306a36Sopenharmony_ci					((temp_reg & 0xffff0000)) | ((table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16);
431562306a36Sopenharmony_ci			}
431662306a36Sopenharmony_ci			j++;
431762306a36Sopenharmony_ci			if (j >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
431862306a36Sopenharmony_ci				return -EINVAL;
431962306a36Sopenharmony_ci
432062306a36Sopenharmony_ci			temp_reg = RREG32(MC_PMG_CMD_MRS);
432162306a36Sopenharmony_ci			table->mc_reg_address[j].s1 = MC_PMG_CMD_MRS >> 2;
432262306a36Sopenharmony_ci			table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_MRS_LP >> 2;
432362306a36Sopenharmony_ci			for (k = 0; k < table->num_entries; k++) {
432462306a36Sopenharmony_ci				table->mc_reg_table_entry[k].mc_data[j] =
432562306a36Sopenharmony_ci					(temp_reg & 0xffff0000) | (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
432662306a36Sopenharmony_ci				if (!pi->mem_gddr5)
432762306a36Sopenharmony_ci					table->mc_reg_table_entry[k].mc_data[j] |= 0x100;
432862306a36Sopenharmony_ci			}
432962306a36Sopenharmony_ci			j++;
433062306a36Sopenharmony_ci			if (j >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
433162306a36Sopenharmony_ci				return -EINVAL;
433262306a36Sopenharmony_ci
433362306a36Sopenharmony_ci			if (!pi->mem_gddr5) {
433462306a36Sopenharmony_ci				table->mc_reg_address[j].s1 = MC_PMG_AUTO_CMD >> 2;
433562306a36Sopenharmony_ci				table->mc_reg_address[j].s0 = MC_PMG_AUTO_CMD >> 2;
433662306a36Sopenharmony_ci				for (k = 0; k < table->num_entries; k++) {
433762306a36Sopenharmony_ci					table->mc_reg_table_entry[k].mc_data[j] =
433862306a36Sopenharmony_ci						(table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16;
433962306a36Sopenharmony_ci				}
434062306a36Sopenharmony_ci				j++;
434162306a36Sopenharmony_ci				if (j > SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
434262306a36Sopenharmony_ci					return -EINVAL;
434362306a36Sopenharmony_ci			}
434462306a36Sopenharmony_ci			break;
434562306a36Sopenharmony_ci		case MC_SEQ_RESERVE_M:
434662306a36Sopenharmony_ci			temp_reg = RREG32(MC_PMG_CMD_MRS1);
434762306a36Sopenharmony_ci			table->mc_reg_address[j].s1 = MC_PMG_CMD_MRS1 >> 2;
434862306a36Sopenharmony_ci			table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_MRS1_LP >> 2;
434962306a36Sopenharmony_ci			for (k = 0; k < table->num_entries; k++) {
435062306a36Sopenharmony_ci				table->mc_reg_table_entry[k].mc_data[j] =
435162306a36Sopenharmony_ci					(temp_reg & 0xffff0000) | (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
435262306a36Sopenharmony_ci			}
435362306a36Sopenharmony_ci			j++;
435462306a36Sopenharmony_ci			if (j > SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
435562306a36Sopenharmony_ci				return -EINVAL;
435662306a36Sopenharmony_ci			break;
435762306a36Sopenharmony_ci		default:
435862306a36Sopenharmony_ci			break;
435962306a36Sopenharmony_ci		}
436062306a36Sopenharmony_ci
436162306a36Sopenharmony_ci	}
436262306a36Sopenharmony_ci
436362306a36Sopenharmony_ci	table->last = j;
436462306a36Sopenharmony_ci
436562306a36Sopenharmony_ci	return 0;
436662306a36Sopenharmony_ci}
436762306a36Sopenharmony_ci
436862306a36Sopenharmony_cistatic bool ci_check_s0_mc_reg_index(u16 in_reg, u16 *out_reg)
436962306a36Sopenharmony_ci{
437062306a36Sopenharmony_ci	bool result = true;
437162306a36Sopenharmony_ci
437262306a36Sopenharmony_ci	switch(in_reg) {
437362306a36Sopenharmony_ci	case MC_SEQ_RAS_TIMING >> 2:
437462306a36Sopenharmony_ci		*out_reg = MC_SEQ_RAS_TIMING_LP >> 2;
437562306a36Sopenharmony_ci		break;
437662306a36Sopenharmony_ci	case MC_SEQ_DLL_STBY >> 2:
437762306a36Sopenharmony_ci		*out_reg = MC_SEQ_DLL_STBY_LP >> 2;
437862306a36Sopenharmony_ci		break;
437962306a36Sopenharmony_ci	case MC_SEQ_G5PDX_CMD0 >> 2:
438062306a36Sopenharmony_ci		*out_reg = MC_SEQ_G5PDX_CMD0_LP >> 2;
438162306a36Sopenharmony_ci		break;
438262306a36Sopenharmony_ci	case MC_SEQ_G5PDX_CMD1 >> 2:
438362306a36Sopenharmony_ci		*out_reg = MC_SEQ_G5PDX_CMD1_LP >> 2;
438462306a36Sopenharmony_ci		break;
438562306a36Sopenharmony_ci	case MC_SEQ_G5PDX_CTRL >> 2:
438662306a36Sopenharmony_ci		*out_reg = MC_SEQ_G5PDX_CTRL_LP >> 2;
438762306a36Sopenharmony_ci		break;
438862306a36Sopenharmony_ci	case MC_SEQ_CAS_TIMING >> 2:
438962306a36Sopenharmony_ci		*out_reg = MC_SEQ_CAS_TIMING_LP >> 2;
439062306a36Sopenharmony_ci		break;
439162306a36Sopenharmony_ci	case MC_SEQ_MISC_TIMING >> 2:
439262306a36Sopenharmony_ci		*out_reg = MC_SEQ_MISC_TIMING_LP >> 2;
439362306a36Sopenharmony_ci		break;
439462306a36Sopenharmony_ci	case MC_SEQ_MISC_TIMING2 >> 2:
439562306a36Sopenharmony_ci		*out_reg = MC_SEQ_MISC_TIMING2_LP >> 2;
439662306a36Sopenharmony_ci		break;
439762306a36Sopenharmony_ci	case MC_SEQ_PMG_DVS_CMD >> 2:
439862306a36Sopenharmony_ci		*out_reg = MC_SEQ_PMG_DVS_CMD_LP >> 2;
439962306a36Sopenharmony_ci		break;
440062306a36Sopenharmony_ci	case MC_SEQ_PMG_DVS_CTL >> 2:
440162306a36Sopenharmony_ci		*out_reg = MC_SEQ_PMG_DVS_CTL_LP >> 2;
440262306a36Sopenharmony_ci		break;
440362306a36Sopenharmony_ci	case MC_SEQ_RD_CTL_D0 >> 2:
440462306a36Sopenharmony_ci		*out_reg = MC_SEQ_RD_CTL_D0_LP >> 2;
440562306a36Sopenharmony_ci		break;
440662306a36Sopenharmony_ci	case MC_SEQ_RD_CTL_D1 >> 2:
440762306a36Sopenharmony_ci		*out_reg = MC_SEQ_RD_CTL_D1_LP >> 2;
440862306a36Sopenharmony_ci		break;
440962306a36Sopenharmony_ci	case MC_SEQ_WR_CTL_D0 >> 2:
441062306a36Sopenharmony_ci		*out_reg = MC_SEQ_WR_CTL_D0_LP >> 2;
441162306a36Sopenharmony_ci		break;
441262306a36Sopenharmony_ci	case MC_SEQ_WR_CTL_D1 >> 2:
441362306a36Sopenharmony_ci		*out_reg = MC_SEQ_WR_CTL_D1_LP >> 2;
441462306a36Sopenharmony_ci		break;
441562306a36Sopenharmony_ci	case MC_PMG_CMD_EMRS >> 2:
441662306a36Sopenharmony_ci		*out_reg = MC_SEQ_PMG_CMD_EMRS_LP >> 2;
441762306a36Sopenharmony_ci		break;
441862306a36Sopenharmony_ci	case MC_PMG_CMD_MRS >> 2:
441962306a36Sopenharmony_ci		*out_reg = MC_SEQ_PMG_CMD_MRS_LP >> 2;
442062306a36Sopenharmony_ci		break;
442162306a36Sopenharmony_ci	case MC_PMG_CMD_MRS1 >> 2:
442262306a36Sopenharmony_ci		*out_reg = MC_SEQ_PMG_CMD_MRS1_LP >> 2;
442362306a36Sopenharmony_ci		break;
442462306a36Sopenharmony_ci	case MC_SEQ_PMG_TIMING >> 2:
442562306a36Sopenharmony_ci		*out_reg = MC_SEQ_PMG_TIMING_LP >> 2;
442662306a36Sopenharmony_ci		break;
442762306a36Sopenharmony_ci	case MC_PMG_CMD_MRS2 >> 2:
442862306a36Sopenharmony_ci		*out_reg = MC_SEQ_PMG_CMD_MRS2_LP >> 2;
442962306a36Sopenharmony_ci		break;
443062306a36Sopenharmony_ci	case MC_SEQ_WR_CTL_2 >> 2:
443162306a36Sopenharmony_ci		*out_reg = MC_SEQ_WR_CTL_2_LP >> 2;
443262306a36Sopenharmony_ci		break;
443362306a36Sopenharmony_ci	default:
443462306a36Sopenharmony_ci		result = false;
443562306a36Sopenharmony_ci		break;
443662306a36Sopenharmony_ci	}
443762306a36Sopenharmony_ci
443862306a36Sopenharmony_ci	return result;
443962306a36Sopenharmony_ci}
444062306a36Sopenharmony_ci
444162306a36Sopenharmony_cistatic void ci_set_valid_flag(struct ci_mc_reg_table *table)
444262306a36Sopenharmony_ci{
444362306a36Sopenharmony_ci	u8 i, j;
444462306a36Sopenharmony_ci
444562306a36Sopenharmony_ci	for (i = 0; i < table->last; i++) {
444662306a36Sopenharmony_ci		for (j = 1; j < table->num_entries; j++) {
444762306a36Sopenharmony_ci			if (table->mc_reg_table_entry[j-1].mc_data[i] !=
444862306a36Sopenharmony_ci			    table->mc_reg_table_entry[j].mc_data[i]) {
444962306a36Sopenharmony_ci				table->valid_flag |= 1 << i;
445062306a36Sopenharmony_ci				break;
445162306a36Sopenharmony_ci			}
445262306a36Sopenharmony_ci		}
445362306a36Sopenharmony_ci	}
445462306a36Sopenharmony_ci}
445562306a36Sopenharmony_ci
445662306a36Sopenharmony_cistatic void ci_set_s0_mc_reg_index(struct ci_mc_reg_table *table)
445762306a36Sopenharmony_ci{
445862306a36Sopenharmony_ci	u32 i;
445962306a36Sopenharmony_ci	u16 address;
446062306a36Sopenharmony_ci
446162306a36Sopenharmony_ci	for (i = 0; i < table->last; i++) {
446262306a36Sopenharmony_ci		table->mc_reg_address[i].s0 =
446362306a36Sopenharmony_ci			ci_check_s0_mc_reg_index(table->mc_reg_address[i].s1, &address) ?
446462306a36Sopenharmony_ci			address : table->mc_reg_address[i].s1;
446562306a36Sopenharmony_ci	}
446662306a36Sopenharmony_ci}
446762306a36Sopenharmony_ci
446862306a36Sopenharmony_cistatic int ci_copy_vbios_mc_reg_table(const struct atom_mc_reg_table *table,
446962306a36Sopenharmony_ci				      struct ci_mc_reg_table *ci_table)
447062306a36Sopenharmony_ci{
447162306a36Sopenharmony_ci	u8 i, j;
447262306a36Sopenharmony_ci
447362306a36Sopenharmony_ci	if (table->last > SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
447462306a36Sopenharmony_ci		return -EINVAL;
447562306a36Sopenharmony_ci	if (table->num_entries > MAX_AC_TIMING_ENTRIES)
447662306a36Sopenharmony_ci		return -EINVAL;
447762306a36Sopenharmony_ci
447862306a36Sopenharmony_ci	for (i = 0; i < table->last; i++)
447962306a36Sopenharmony_ci		ci_table->mc_reg_address[i].s1 = table->mc_reg_address[i].s1;
448062306a36Sopenharmony_ci
448162306a36Sopenharmony_ci	ci_table->last = table->last;
448262306a36Sopenharmony_ci
448362306a36Sopenharmony_ci	for (i = 0; i < table->num_entries; i++) {
448462306a36Sopenharmony_ci		ci_table->mc_reg_table_entry[i].mclk_max =
448562306a36Sopenharmony_ci			table->mc_reg_table_entry[i].mclk_max;
448662306a36Sopenharmony_ci		for (j = 0; j < table->last; j++)
448762306a36Sopenharmony_ci			ci_table->mc_reg_table_entry[i].mc_data[j] =
448862306a36Sopenharmony_ci				table->mc_reg_table_entry[i].mc_data[j];
448962306a36Sopenharmony_ci	}
449062306a36Sopenharmony_ci	ci_table->num_entries = table->num_entries;
449162306a36Sopenharmony_ci
449262306a36Sopenharmony_ci	return 0;
449362306a36Sopenharmony_ci}
449462306a36Sopenharmony_ci
449562306a36Sopenharmony_cistatic int ci_register_patching_mc_seq(struct radeon_device *rdev,
449662306a36Sopenharmony_ci				       struct ci_mc_reg_table *table)
449762306a36Sopenharmony_ci{
449862306a36Sopenharmony_ci	u8 i, k;
449962306a36Sopenharmony_ci	u32 tmp;
450062306a36Sopenharmony_ci	bool patch;
450162306a36Sopenharmony_ci
450262306a36Sopenharmony_ci	tmp = RREG32(MC_SEQ_MISC0);
450362306a36Sopenharmony_ci	patch = ((tmp & 0x0000f00) == 0x300) ? true : false;
450462306a36Sopenharmony_ci
450562306a36Sopenharmony_ci	if (patch &&
450662306a36Sopenharmony_ci	    ((rdev->pdev->device == 0x67B0) ||
450762306a36Sopenharmony_ci	     (rdev->pdev->device == 0x67B1))) {
450862306a36Sopenharmony_ci		for (i = 0; i < table->last; i++) {
450962306a36Sopenharmony_ci			if (table->last >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
451062306a36Sopenharmony_ci				return -EINVAL;
451162306a36Sopenharmony_ci			switch(table->mc_reg_address[i].s1 >> 2) {
451262306a36Sopenharmony_ci			case MC_SEQ_MISC1:
451362306a36Sopenharmony_ci				for (k = 0; k < table->num_entries; k++) {
451462306a36Sopenharmony_ci					if ((table->mc_reg_table_entry[k].mclk_max == 125000) ||
451562306a36Sopenharmony_ci					    (table->mc_reg_table_entry[k].mclk_max == 137500))
451662306a36Sopenharmony_ci						table->mc_reg_table_entry[k].mc_data[i] =
451762306a36Sopenharmony_ci							(table->mc_reg_table_entry[k].mc_data[i] & 0xFFFFFFF8) |
451862306a36Sopenharmony_ci							0x00000007;
451962306a36Sopenharmony_ci				}
452062306a36Sopenharmony_ci				break;
452162306a36Sopenharmony_ci			case MC_SEQ_WR_CTL_D0:
452262306a36Sopenharmony_ci				for (k = 0; k < table->num_entries; k++) {
452362306a36Sopenharmony_ci					if ((table->mc_reg_table_entry[k].mclk_max == 125000) ||
452462306a36Sopenharmony_ci					    (table->mc_reg_table_entry[k].mclk_max == 137500))
452562306a36Sopenharmony_ci						table->mc_reg_table_entry[k].mc_data[i] =
452662306a36Sopenharmony_ci							(table->mc_reg_table_entry[k].mc_data[i] & 0xFFFF0F00) |
452762306a36Sopenharmony_ci							0x0000D0DD;
452862306a36Sopenharmony_ci				}
452962306a36Sopenharmony_ci				break;
453062306a36Sopenharmony_ci			case MC_SEQ_WR_CTL_D1:
453162306a36Sopenharmony_ci				for (k = 0; k < table->num_entries; k++) {
453262306a36Sopenharmony_ci					if ((table->mc_reg_table_entry[k].mclk_max == 125000) ||
453362306a36Sopenharmony_ci					    (table->mc_reg_table_entry[k].mclk_max == 137500))
453462306a36Sopenharmony_ci						table->mc_reg_table_entry[k].mc_data[i] =
453562306a36Sopenharmony_ci							(table->mc_reg_table_entry[k].mc_data[i] & 0xFFFF0F00) |
453662306a36Sopenharmony_ci							0x0000D0DD;
453762306a36Sopenharmony_ci				}
453862306a36Sopenharmony_ci				break;
453962306a36Sopenharmony_ci			case MC_SEQ_WR_CTL_2:
454062306a36Sopenharmony_ci				for (k = 0; k < table->num_entries; k++) {
454162306a36Sopenharmony_ci					if ((table->mc_reg_table_entry[k].mclk_max == 125000) ||
454262306a36Sopenharmony_ci					    (table->mc_reg_table_entry[k].mclk_max == 137500))
454362306a36Sopenharmony_ci						table->mc_reg_table_entry[k].mc_data[i] = 0;
454462306a36Sopenharmony_ci				}
454562306a36Sopenharmony_ci				break;
454662306a36Sopenharmony_ci			case MC_SEQ_CAS_TIMING:
454762306a36Sopenharmony_ci				for (k = 0; k < table->num_entries; k++) {
454862306a36Sopenharmony_ci					if (table->mc_reg_table_entry[k].mclk_max == 125000)
454962306a36Sopenharmony_ci						table->mc_reg_table_entry[k].mc_data[i] =
455062306a36Sopenharmony_ci							(table->mc_reg_table_entry[k].mc_data[i] & 0xFFE0FE0F) |
455162306a36Sopenharmony_ci							0x000C0140;
455262306a36Sopenharmony_ci					else if (table->mc_reg_table_entry[k].mclk_max == 137500)
455362306a36Sopenharmony_ci						table->mc_reg_table_entry[k].mc_data[i] =
455462306a36Sopenharmony_ci							(table->mc_reg_table_entry[k].mc_data[i] & 0xFFE0FE0F) |
455562306a36Sopenharmony_ci							0x000C0150;
455662306a36Sopenharmony_ci				}
455762306a36Sopenharmony_ci				break;
455862306a36Sopenharmony_ci			case MC_SEQ_MISC_TIMING:
455962306a36Sopenharmony_ci				for (k = 0; k < table->num_entries; k++) {
456062306a36Sopenharmony_ci					if (table->mc_reg_table_entry[k].mclk_max == 125000)
456162306a36Sopenharmony_ci						table->mc_reg_table_entry[k].mc_data[i] =
456262306a36Sopenharmony_ci							(table->mc_reg_table_entry[k].mc_data[i] & 0xFFFFFFE0) |
456362306a36Sopenharmony_ci							0x00000030;
456462306a36Sopenharmony_ci					else if (table->mc_reg_table_entry[k].mclk_max == 137500)
456562306a36Sopenharmony_ci						table->mc_reg_table_entry[k].mc_data[i] =
456662306a36Sopenharmony_ci							(table->mc_reg_table_entry[k].mc_data[i] & 0xFFFFFFE0) |
456762306a36Sopenharmony_ci							0x00000035;
456862306a36Sopenharmony_ci				}
456962306a36Sopenharmony_ci				break;
457062306a36Sopenharmony_ci			default:
457162306a36Sopenharmony_ci				break;
457262306a36Sopenharmony_ci			}
457362306a36Sopenharmony_ci		}
457462306a36Sopenharmony_ci
457562306a36Sopenharmony_ci		WREG32(MC_SEQ_IO_DEBUG_INDEX, 3);
457662306a36Sopenharmony_ci		tmp = RREG32(MC_SEQ_IO_DEBUG_DATA);
457762306a36Sopenharmony_ci		tmp = (tmp & 0xFFF8FFFF) | (1 << 16);
457862306a36Sopenharmony_ci		WREG32(MC_SEQ_IO_DEBUG_INDEX, 3);
457962306a36Sopenharmony_ci		WREG32(MC_SEQ_IO_DEBUG_DATA, tmp);
458062306a36Sopenharmony_ci	}
458162306a36Sopenharmony_ci
458262306a36Sopenharmony_ci	return 0;
458362306a36Sopenharmony_ci}
458462306a36Sopenharmony_ci
458562306a36Sopenharmony_cistatic int ci_initialize_mc_reg_table(struct radeon_device *rdev)
458662306a36Sopenharmony_ci{
458762306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
458862306a36Sopenharmony_ci	struct atom_mc_reg_table *table;
458962306a36Sopenharmony_ci	struct ci_mc_reg_table *ci_table = &pi->mc_reg_table;
459062306a36Sopenharmony_ci	u8 module_index = rv770_get_memory_module_index(rdev);
459162306a36Sopenharmony_ci	int ret;
459262306a36Sopenharmony_ci
459362306a36Sopenharmony_ci	table = kzalloc(sizeof(struct atom_mc_reg_table), GFP_KERNEL);
459462306a36Sopenharmony_ci	if (!table)
459562306a36Sopenharmony_ci		return -ENOMEM;
459662306a36Sopenharmony_ci
459762306a36Sopenharmony_ci	WREG32(MC_SEQ_RAS_TIMING_LP, RREG32(MC_SEQ_RAS_TIMING));
459862306a36Sopenharmony_ci	WREG32(MC_SEQ_CAS_TIMING_LP, RREG32(MC_SEQ_CAS_TIMING));
459962306a36Sopenharmony_ci	WREG32(MC_SEQ_DLL_STBY_LP, RREG32(MC_SEQ_DLL_STBY));
460062306a36Sopenharmony_ci	WREG32(MC_SEQ_G5PDX_CMD0_LP, RREG32(MC_SEQ_G5PDX_CMD0));
460162306a36Sopenharmony_ci	WREG32(MC_SEQ_G5PDX_CMD1_LP, RREG32(MC_SEQ_G5PDX_CMD1));
460262306a36Sopenharmony_ci	WREG32(MC_SEQ_G5PDX_CTRL_LP, RREG32(MC_SEQ_G5PDX_CTRL));
460362306a36Sopenharmony_ci	WREG32(MC_SEQ_PMG_DVS_CMD_LP, RREG32(MC_SEQ_PMG_DVS_CMD));
460462306a36Sopenharmony_ci	WREG32(MC_SEQ_PMG_DVS_CTL_LP, RREG32(MC_SEQ_PMG_DVS_CTL));
460562306a36Sopenharmony_ci	WREG32(MC_SEQ_MISC_TIMING_LP, RREG32(MC_SEQ_MISC_TIMING));
460662306a36Sopenharmony_ci	WREG32(MC_SEQ_MISC_TIMING2_LP, RREG32(MC_SEQ_MISC_TIMING2));
460762306a36Sopenharmony_ci	WREG32(MC_SEQ_PMG_CMD_EMRS_LP, RREG32(MC_PMG_CMD_EMRS));
460862306a36Sopenharmony_ci	WREG32(MC_SEQ_PMG_CMD_MRS_LP, RREG32(MC_PMG_CMD_MRS));
460962306a36Sopenharmony_ci	WREG32(MC_SEQ_PMG_CMD_MRS1_LP, RREG32(MC_PMG_CMD_MRS1));
461062306a36Sopenharmony_ci	WREG32(MC_SEQ_WR_CTL_D0_LP, RREG32(MC_SEQ_WR_CTL_D0));
461162306a36Sopenharmony_ci	WREG32(MC_SEQ_WR_CTL_D1_LP, RREG32(MC_SEQ_WR_CTL_D1));
461262306a36Sopenharmony_ci	WREG32(MC_SEQ_RD_CTL_D0_LP, RREG32(MC_SEQ_RD_CTL_D0));
461362306a36Sopenharmony_ci	WREG32(MC_SEQ_RD_CTL_D1_LP, RREG32(MC_SEQ_RD_CTL_D1));
461462306a36Sopenharmony_ci	WREG32(MC_SEQ_PMG_TIMING_LP, RREG32(MC_SEQ_PMG_TIMING));
461562306a36Sopenharmony_ci	WREG32(MC_SEQ_PMG_CMD_MRS2_LP, RREG32(MC_PMG_CMD_MRS2));
461662306a36Sopenharmony_ci	WREG32(MC_SEQ_WR_CTL_2_LP, RREG32(MC_SEQ_WR_CTL_2));
461762306a36Sopenharmony_ci
461862306a36Sopenharmony_ci	ret = radeon_atom_init_mc_reg_table(rdev, module_index, table);
461962306a36Sopenharmony_ci	if (ret)
462062306a36Sopenharmony_ci		goto init_mc_done;
462162306a36Sopenharmony_ci
462262306a36Sopenharmony_ci	ret = ci_copy_vbios_mc_reg_table(table, ci_table);
462362306a36Sopenharmony_ci	if (ret)
462462306a36Sopenharmony_ci		goto init_mc_done;
462562306a36Sopenharmony_ci
462662306a36Sopenharmony_ci	ci_set_s0_mc_reg_index(ci_table);
462762306a36Sopenharmony_ci
462862306a36Sopenharmony_ci	ret = ci_register_patching_mc_seq(rdev, ci_table);
462962306a36Sopenharmony_ci	if (ret)
463062306a36Sopenharmony_ci		goto init_mc_done;
463162306a36Sopenharmony_ci
463262306a36Sopenharmony_ci	ret = ci_set_mc_special_registers(rdev, ci_table);
463362306a36Sopenharmony_ci	if (ret)
463462306a36Sopenharmony_ci		goto init_mc_done;
463562306a36Sopenharmony_ci
463662306a36Sopenharmony_ci	ci_set_valid_flag(ci_table);
463762306a36Sopenharmony_ci
463862306a36Sopenharmony_ciinit_mc_done:
463962306a36Sopenharmony_ci	kfree(table);
464062306a36Sopenharmony_ci
464162306a36Sopenharmony_ci	return ret;
464262306a36Sopenharmony_ci}
464362306a36Sopenharmony_ci
464462306a36Sopenharmony_cistatic int ci_populate_mc_reg_addresses(struct radeon_device *rdev,
464562306a36Sopenharmony_ci					SMU7_Discrete_MCRegisters *mc_reg_table)
464662306a36Sopenharmony_ci{
464762306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
464862306a36Sopenharmony_ci	u32 i, j;
464962306a36Sopenharmony_ci
465062306a36Sopenharmony_ci	for (i = 0, j = 0; j < pi->mc_reg_table.last; j++) {
465162306a36Sopenharmony_ci		if (pi->mc_reg_table.valid_flag & (1 << j)) {
465262306a36Sopenharmony_ci			if (i >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
465362306a36Sopenharmony_ci				return -EINVAL;
465462306a36Sopenharmony_ci			mc_reg_table->address[i].s0 = cpu_to_be16(pi->mc_reg_table.mc_reg_address[j].s0);
465562306a36Sopenharmony_ci			mc_reg_table->address[i].s1 = cpu_to_be16(pi->mc_reg_table.mc_reg_address[j].s1);
465662306a36Sopenharmony_ci			i++;
465762306a36Sopenharmony_ci		}
465862306a36Sopenharmony_ci	}
465962306a36Sopenharmony_ci
466062306a36Sopenharmony_ci	mc_reg_table->last = (u8)i;
466162306a36Sopenharmony_ci
466262306a36Sopenharmony_ci	return 0;
466362306a36Sopenharmony_ci}
466462306a36Sopenharmony_ci
466562306a36Sopenharmony_cistatic void ci_convert_mc_registers(const struct ci_mc_reg_entry *entry,
466662306a36Sopenharmony_ci				    SMU7_Discrete_MCRegisterSet *data,
466762306a36Sopenharmony_ci				    u32 num_entries, u32 valid_flag)
466862306a36Sopenharmony_ci{
466962306a36Sopenharmony_ci	u32 i, j;
467062306a36Sopenharmony_ci
467162306a36Sopenharmony_ci	for (i = 0, j = 0; j < num_entries; j++) {
467262306a36Sopenharmony_ci		if (valid_flag & (1 << j)) {
467362306a36Sopenharmony_ci			data->value[i] = cpu_to_be32(entry->mc_data[j]);
467462306a36Sopenharmony_ci			i++;
467562306a36Sopenharmony_ci		}
467662306a36Sopenharmony_ci	}
467762306a36Sopenharmony_ci}
467862306a36Sopenharmony_ci
467962306a36Sopenharmony_cistatic void ci_convert_mc_reg_table_entry_to_smc(struct radeon_device *rdev,
468062306a36Sopenharmony_ci						 const u32 memory_clock,
468162306a36Sopenharmony_ci						 SMU7_Discrete_MCRegisterSet *mc_reg_table_data)
468262306a36Sopenharmony_ci{
468362306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
468462306a36Sopenharmony_ci	u32 i = 0;
468562306a36Sopenharmony_ci
468662306a36Sopenharmony_ci	for(i = 0; i < pi->mc_reg_table.num_entries; i++) {
468762306a36Sopenharmony_ci		if (memory_clock <= pi->mc_reg_table.mc_reg_table_entry[i].mclk_max)
468862306a36Sopenharmony_ci			break;
468962306a36Sopenharmony_ci	}
469062306a36Sopenharmony_ci
469162306a36Sopenharmony_ci	if ((i == pi->mc_reg_table.num_entries) && (i > 0))
469262306a36Sopenharmony_ci		--i;
469362306a36Sopenharmony_ci
469462306a36Sopenharmony_ci	ci_convert_mc_registers(&pi->mc_reg_table.mc_reg_table_entry[i],
469562306a36Sopenharmony_ci				mc_reg_table_data, pi->mc_reg_table.last,
469662306a36Sopenharmony_ci				pi->mc_reg_table.valid_flag);
469762306a36Sopenharmony_ci}
469862306a36Sopenharmony_ci
469962306a36Sopenharmony_cistatic void ci_convert_mc_reg_table_to_smc(struct radeon_device *rdev,
470062306a36Sopenharmony_ci					   SMU7_Discrete_MCRegisters *mc_reg_table)
470162306a36Sopenharmony_ci{
470262306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
470362306a36Sopenharmony_ci	u32 i;
470462306a36Sopenharmony_ci
470562306a36Sopenharmony_ci	for (i = 0; i < pi->dpm_table.mclk_table.count; i++)
470662306a36Sopenharmony_ci		ci_convert_mc_reg_table_entry_to_smc(rdev,
470762306a36Sopenharmony_ci						     pi->dpm_table.mclk_table.dpm_levels[i].value,
470862306a36Sopenharmony_ci						     &mc_reg_table->data[i]);
470962306a36Sopenharmony_ci}
471062306a36Sopenharmony_ci
471162306a36Sopenharmony_cistatic int ci_populate_initial_mc_reg_table(struct radeon_device *rdev)
471262306a36Sopenharmony_ci{
471362306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
471462306a36Sopenharmony_ci	int ret;
471562306a36Sopenharmony_ci
471662306a36Sopenharmony_ci	memset(&pi->smc_mc_reg_table, 0, sizeof(SMU7_Discrete_MCRegisters));
471762306a36Sopenharmony_ci
471862306a36Sopenharmony_ci	ret = ci_populate_mc_reg_addresses(rdev, &pi->smc_mc_reg_table);
471962306a36Sopenharmony_ci	if (ret)
472062306a36Sopenharmony_ci		return ret;
472162306a36Sopenharmony_ci	ci_convert_mc_reg_table_to_smc(rdev, &pi->smc_mc_reg_table);
472262306a36Sopenharmony_ci
472362306a36Sopenharmony_ci	return ci_copy_bytes_to_smc(rdev,
472462306a36Sopenharmony_ci				    pi->mc_reg_table_start,
472562306a36Sopenharmony_ci				    (u8 *)&pi->smc_mc_reg_table,
472662306a36Sopenharmony_ci				    sizeof(SMU7_Discrete_MCRegisters),
472762306a36Sopenharmony_ci				    pi->sram_end);
472862306a36Sopenharmony_ci}
472962306a36Sopenharmony_ci
473062306a36Sopenharmony_cistatic int ci_update_and_upload_mc_reg_table(struct radeon_device *rdev)
473162306a36Sopenharmony_ci{
473262306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
473362306a36Sopenharmony_ci
473462306a36Sopenharmony_ci	if (!(pi->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK))
473562306a36Sopenharmony_ci		return 0;
473662306a36Sopenharmony_ci
473762306a36Sopenharmony_ci	memset(&pi->smc_mc_reg_table, 0, sizeof(SMU7_Discrete_MCRegisters));
473862306a36Sopenharmony_ci
473962306a36Sopenharmony_ci	ci_convert_mc_reg_table_to_smc(rdev, &pi->smc_mc_reg_table);
474062306a36Sopenharmony_ci
474162306a36Sopenharmony_ci	return ci_copy_bytes_to_smc(rdev,
474262306a36Sopenharmony_ci				    pi->mc_reg_table_start +
474362306a36Sopenharmony_ci				    offsetof(SMU7_Discrete_MCRegisters, data[0]),
474462306a36Sopenharmony_ci				    (u8 *)&pi->smc_mc_reg_table.data[0],
474562306a36Sopenharmony_ci				    sizeof(SMU7_Discrete_MCRegisterSet) *
474662306a36Sopenharmony_ci				    pi->dpm_table.mclk_table.count,
474762306a36Sopenharmony_ci				    pi->sram_end);
474862306a36Sopenharmony_ci}
474962306a36Sopenharmony_ci
475062306a36Sopenharmony_cistatic void ci_enable_voltage_control(struct radeon_device *rdev)
475162306a36Sopenharmony_ci{
475262306a36Sopenharmony_ci	u32 tmp = RREG32_SMC(GENERAL_PWRMGT);
475362306a36Sopenharmony_ci
475462306a36Sopenharmony_ci	tmp |= VOLT_PWRMGT_EN;
475562306a36Sopenharmony_ci	WREG32_SMC(GENERAL_PWRMGT, tmp);
475662306a36Sopenharmony_ci}
475762306a36Sopenharmony_ci
475862306a36Sopenharmony_cistatic enum radeon_pcie_gen ci_get_maximum_link_speed(struct radeon_device *rdev,
475962306a36Sopenharmony_ci						      struct radeon_ps *radeon_state)
476062306a36Sopenharmony_ci{
476162306a36Sopenharmony_ci	struct ci_ps *state = ci_get_ps(radeon_state);
476262306a36Sopenharmony_ci	int i;
476362306a36Sopenharmony_ci	u16 pcie_speed, max_speed = 0;
476462306a36Sopenharmony_ci
476562306a36Sopenharmony_ci	for (i = 0; i < state->performance_level_count; i++) {
476662306a36Sopenharmony_ci		pcie_speed = state->performance_levels[i].pcie_gen;
476762306a36Sopenharmony_ci		if (max_speed < pcie_speed)
476862306a36Sopenharmony_ci			max_speed = pcie_speed;
476962306a36Sopenharmony_ci	}
477062306a36Sopenharmony_ci
477162306a36Sopenharmony_ci	return max_speed;
477262306a36Sopenharmony_ci}
477362306a36Sopenharmony_ci
477462306a36Sopenharmony_cistatic u16 ci_get_current_pcie_speed(struct radeon_device *rdev)
477562306a36Sopenharmony_ci{
477662306a36Sopenharmony_ci	u32 speed_cntl = 0;
477762306a36Sopenharmony_ci
477862306a36Sopenharmony_ci	speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL) & LC_CURRENT_DATA_RATE_MASK;
477962306a36Sopenharmony_ci	speed_cntl >>= LC_CURRENT_DATA_RATE_SHIFT;
478062306a36Sopenharmony_ci
478162306a36Sopenharmony_ci	return (u16)speed_cntl;
478262306a36Sopenharmony_ci}
478362306a36Sopenharmony_ci
478462306a36Sopenharmony_cistatic int ci_get_current_pcie_lane_number(struct radeon_device *rdev)
478562306a36Sopenharmony_ci{
478662306a36Sopenharmony_ci	u32 link_width = 0;
478762306a36Sopenharmony_ci
478862306a36Sopenharmony_ci	link_width = RREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL) & LC_LINK_WIDTH_RD_MASK;
478962306a36Sopenharmony_ci	link_width >>= LC_LINK_WIDTH_RD_SHIFT;
479062306a36Sopenharmony_ci
479162306a36Sopenharmony_ci	switch (link_width) {
479262306a36Sopenharmony_ci	case RADEON_PCIE_LC_LINK_WIDTH_X1:
479362306a36Sopenharmony_ci		return 1;
479462306a36Sopenharmony_ci	case RADEON_PCIE_LC_LINK_WIDTH_X2:
479562306a36Sopenharmony_ci		return 2;
479662306a36Sopenharmony_ci	case RADEON_PCIE_LC_LINK_WIDTH_X4:
479762306a36Sopenharmony_ci		return 4;
479862306a36Sopenharmony_ci	case RADEON_PCIE_LC_LINK_WIDTH_X8:
479962306a36Sopenharmony_ci		return 8;
480062306a36Sopenharmony_ci	case RADEON_PCIE_LC_LINK_WIDTH_X12:
480162306a36Sopenharmony_ci		/* not actually supported */
480262306a36Sopenharmony_ci		return 12;
480362306a36Sopenharmony_ci	case RADEON_PCIE_LC_LINK_WIDTH_X0:
480462306a36Sopenharmony_ci	case RADEON_PCIE_LC_LINK_WIDTH_X16:
480562306a36Sopenharmony_ci	default:
480662306a36Sopenharmony_ci		return 16;
480762306a36Sopenharmony_ci	}
480862306a36Sopenharmony_ci}
480962306a36Sopenharmony_ci
481062306a36Sopenharmony_cistatic void ci_request_link_speed_change_before_state_change(struct radeon_device *rdev,
481162306a36Sopenharmony_ci							     struct radeon_ps *radeon_new_state,
481262306a36Sopenharmony_ci							     struct radeon_ps *radeon_current_state)
481362306a36Sopenharmony_ci{
481462306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
481562306a36Sopenharmony_ci	enum radeon_pcie_gen target_link_speed =
481662306a36Sopenharmony_ci		ci_get_maximum_link_speed(rdev, radeon_new_state);
481762306a36Sopenharmony_ci	enum radeon_pcie_gen current_link_speed;
481862306a36Sopenharmony_ci
481962306a36Sopenharmony_ci	if (pi->force_pcie_gen == RADEON_PCIE_GEN_INVALID)
482062306a36Sopenharmony_ci		current_link_speed = ci_get_maximum_link_speed(rdev, radeon_current_state);
482162306a36Sopenharmony_ci	else
482262306a36Sopenharmony_ci		current_link_speed = pi->force_pcie_gen;
482362306a36Sopenharmony_ci
482462306a36Sopenharmony_ci	pi->force_pcie_gen = RADEON_PCIE_GEN_INVALID;
482562306a36Sopenharmony_ci	pi->pspp_notify_required = false;
482662306a36Sopenharmony_ci	if (target_link_speed > current_link_speed) {
482762306a36Sopenharmony_ci		switch (target_link_speed) {
482862306a36Sopenharmony_ci#ifdef CONFIG_ACPI
482962306a36Sopenharmony_ci		case RADEON_PCIE_GEN3:
483062306a36Sopenharmony_ci			if (radeon_acpi_pcie_performance_request(rdev, PCIE_PERF_REQ_PECI_GEN3, false) == 0)
483162306a36Sopenharmony_ci				break;
483262306a36Sopenharmony_ci			pi->force_pcie_gen = RADEON_PCIE_GEN2;
483362306a36Sopenharmony_ci			if (current_link_speed == RADEON_PCIE_GEN2)
483462306a36Sopenharmony_ci				break;
483562306a36Sopenharmony_ci			fallthrough;
483662306a36Sopenharmony_ci		case RADEON_PCIE_GEN2:
483762306a36Sopenharmony_ci			if (radeon_acpi_pcie_performance_request(rdev, PCIE_PERF_REQ_PECI_GEN2, false) == 0)
483862306a36Sopenharmony_ci				break;
483962306a36Sopenharmony_ci			fallthrough;
484062306a36Sopenharmony_ci#endif
484162306a36Sopenharmony_ci		default:
484262306a36Sopenharmony_ci			pi->force_pcie_gen = ci_get_current_pcie_speed(rdev);
484362306a36Sopenharmony_ci			break;
484462306a36Sopenharmony_ci		}
484562306a36Sopenharmony_ci	} else {
484662306a36Sopenharmony_ci		if (target_link_speed < current_link_speed)
484762306a36Sopenharmony_ci			pi->pspp_notify_required = true;
484862306a36Sopenharmony_ci	}
484962306a36Sopenharmony_ci}
485062306a36Sopenharmony_ci
485162306a36Sopenharmony_cistatic void ci_notify_link_speed_change_after_state_change(struct radeon_device *rdev,
485262306a36Sopenharmony_ci							   struct radeon_ps *radeon_new_state,
485362306a36Sopenharmony_ci							   struct radeon_ps *radeon_current_state)
485462306a36Sopenharmony_ci{
485562306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
485662306a36Sopenharmony_ci	enum radeon_pcie_gen target_link_speed =
485762306a36Sopenharmony_ci		ci_get_maximum_link_speed(rdev, radeon_new_state);
485862306a36Sopenharmony_ci	u8 request;
485962306a36Sopenharmony_ci
486062306a36Sopenharmony_ci	if (pi->pspp_notify_required) {
486162306a36Sopenharmony_ci		if (target_link_speed == RADEON_PCIE_GEN3)
486262306a36Sopenharmony_ci			request = PCIE_PERF_REQ_PECI_GEN3;
486362306a36Sopenharmony_ci		else if (target_link_speed == RADEON_PCIE_GEN2)
486462306a36Sopenharmony_ci			request = PCIE_PERF_REQ_PECI_GEN2;
486562306a36Sopenharmony_ci		else
486662306a36Sopenharmony_ci			request = PCIE_PERF_REQ_PECI_GEN1;
486762306a36Sopenharmony_ci
486862306a36Sopenharmony_ci		if ((request == PCIE_PERF_REQ_PECI_GEN1) &&
486962306a36Sopenharmony_ci		    (ci_get_current_pcie_speed(rdev) > 0))
487062306a36Sopenharmony_ci			return;
487162306a36Sopenharmony_ci
487262306a36Sopenharmony_ci#ifdef CONFIG_ACPI
487362306a36Sopenharmony_ci		radeon_acpi_pcie_performance_request(rdev, request, false);
487462306a36Sopenharmony_ci#endif
487562306a36Sopenharmony_ci	}
487662306a36Sopenharmony_ci}
487762306a36Sopenharmony_ci
487862306a36Sopenharmony_cistatic int ci_set_private_data_variables_based_on_pptable(struct radeon_device *rdev)
487962306a36Sopenharmony_ci{
488062306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
488162306a36Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *allowed_sclk_vddc_table =
488262306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
488362306a36Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *allowed_mclk_vddc_table =
488462306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk;
488562306a36Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *allowed_mclk_vddci_table =
488662306a36Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk;
488762306a36Sopenharmony_ci
488862306a36Sopenharmony_ci	if (allowed_sclk_vddc_table == NULL)
488962306a36Sopenharmony_ci		return -EINVAL;
489062306a36Sopenharmony_ci	if (allowed_sclk_vddc_table->count < 1)
489162306a36Sopenharmony_ci		return -EINVAL;
489262306a36Sopenharmony_ci	if (allowed_mclk_vddc_table == NULL)
489362306a36Sopenharmony_ci		return -EINVAL;
489462306a36Sopenharmony_ci	if (allowed_mclk_vddc_table->count < 1)
489562306a36Sopenharmony_ci		return -EINVAL;
489662306a36Sopenharmony_ci	if (allowed_mclk_vddci_table == NULL)
489762306a36Sopenharmony_ci		return -EINVAL;
489862306a36Sopenharmony_ci	if (allowed_mclk_vddci_table->count < 1)
489962306a36Sopenharmony_ci		return -EINVAL;
490062306a36Sopenharmony_ci
490162306a36Sopenharmony_ci	pi->min_vddc_in_pp_table = allowed_sclk_vddc_table->entries[0].v;
490262306a36Sopenharmony_ci	pi->max_vddc_in_pp_table =
490362306a36Sopenharmony_ci		allowed_sclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].v;
490462306a36Sopenharmony_ci
490562306a36Sopenharmony_ci	pi->min_vddci_in_pp_table = allowed_mclk_vddci_table->entries[0].v;
490662306a36Sopenharmony_ci	pi->max_vddci_in_pp_table =
490762306a36Sopenharmony_ci		allowed_mclk_vddci_table->entries[allowed_mclk_vddci_table->count - 1].v;
490862306a36Sopenharmony_ci
490962306a36Sopenharmony_ci	rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk =
491062306a36Sopenharmony_ci		allowed_sclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].clk;
491162306a36Sopenharmony_ci	rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.mclk =
491262306a36Sopenharmony_ci		allowed_mclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].clk;
491362306a36Sopenharmony_ci	rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddc =
491462306a36Sopenharmony_ci		allowed_sclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].v;
491562306a36Sopenharmony_ci	rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddci =
491662306a36Sopenharmony_ci		allowed_mclk_vddci_table->entries[allowed_mclk_vddci_table->count - 1].v;
491762306a36Sopenharmony_ci
491862306a36Sopenharmony_ci	return 0;
491962306a36Sopenharmony_ci}
492062306a36Sopenharmony_ci
492162306a36Sopenharmony_cistatic void ci_patch_with_vddc_leakage(struct radeon_device *rdev, u16 *vddc)
492262306a36Sopenharmony_ci{
492362306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
492462306a36Sopenharmony_ci	struct ci_leakage_voltage *leakage_table = &pi->vddc_leakage;
492562306a36Sopenharmony_ci	u32 leakage_index;
492662306a36Sopenharmony_ci
492762306a36Sopenharmony_ci	for (leakage_index = 0; leakage_index < leakage_table->count; leakage_index++) {
492862306a36Sopenharmony_ci		if (leakage_table->leakage_id[leakage_index] == *vddc) {
492962306a36Sopenharmony_ci			*vddc = leakage_table->actual_voltage[leakage_index];
493062306a36Sopenharmony_ci			break;
493162306a36Sopenharmony_ci		}
493262306a36Sopenharmony_ci	}
493362306a36Sopenharmony_ci}
493462306a36Sopenharmony_ci
493562306a36Sopenharmony_cistatic void ci_patch_with_vddci_leakage(struct radeon_device *rdev, u16 *vddci)
493662306a36Sopenharmony_ci{
493762306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
493862306a36Sopenharmony_ci	struct ci_leakage_voltage *leakage_table = &pi->vddci_leakage;
493962306a36Sopenharmony_ci	u32 leakage_index;
494062306a36Sopenharmony_ci
494162306a36Sopenharmony_ci	for (leakage_index = 0; leakage_index < leakage_table->count; leakage_index++) {
494262306a36Sopenharmony_ci		if (leakage_table->leakage_id[leakage_index] == *vddci) {
494362306a36Sopenharmony_ci			*vddci = leakage_table->actual_voltage[leakage_index];
494462306a36Sopenharmony_ci			break;
494562306a36Sopenharmony_ci		}
494662306a36Sopenharmony_ci	}
494762306a36Sopenharmony_ci}
494862306a36Sopenharmony_ci
494962306a36Sopenharmony_cistatic void ci_patch_clock_voltage_dependency_table_with_vddc_leakage(struct radeon_device *rdev,
495062306a36Sopenharmony_ci								      struct radeon_clock_voltage_dependency_table *table)
495162306a36Sopenharmony_ci{
495262306a36Sopenharmony_ci	u32 i;
495362306a36Sopenharmony_ci
495462306a36Sopenharmony_ci	if (table) {
495562306a36Sopenharmony_ci		for (i = 0; i < table->count; i++)
495662306a36Sopenharmony_ci			ci_patch_with_vddc_leakage(rdev, &table->entries[i].v);
495762306a36Sopenharmony_ci	}
495862306a36Sopenharmony_ci}
495962306a36Sopenharmony_ci
496062306a36Sopenharmony_cistatic void ci_patch_clock_voltage_dependency_table_with_vddci_leakage(struct radeon_device *rdev,
496162306a36Sopenharmony_ci								       struct radeon_clock_voltage_dependency_table *table)
496262306a36Sopenharmony_ci{
496362306a36Sopenharmony_ci	u32 i;
496462306a36Sopenharmony_ci
496562306a36Sopenharmony_ci	if (table) {
496662306a36Sopenharmony_ci		for (i = 0; i < table->count; i++)
496762306a36Sopenharmony_ci			ci_patch_with_vddci_leakage(rdev, &table->entries[i].v);
496862306a36Sopenharmony_ci	}
496962306a36Sopenharmony_ci}
497062306a36Sopenharmony_ci
497162306a36Sopenharmony_cistatic void ci_patch_vce_clock_voltage_dependency_table_with_vddc_leakage(struct radeon_device *rdev,
497262306a36Sopenharmony_ci									  struct radeon_vce_clock_voltage_dependency_table *table)
497362306a36Sopenharmony_ci{
497462306a36Sopenharmony_ci	u32 i;
497562306a36Sopenharmony_ci
497662306a36Sopenharmony_ci	if (table) {
497762306a36Sopenharmony_ci		for (i = 0; i < table->count; i++)
497862306a36Sopenharmony_ci			ci_patch_with_vddc_leakage(rdev, &table->entries[i].v);
497962306a36Sopenharmony_ci	}
498062306a36Sopenharmony_ci}
498162306a36Sopenharmony_ci
498262306a36Sopenharmony_cistatic void ci_patch_uvd_clock_voltage_dependency_table_with_vddc_leakage(struct radeon_device *rdev,
498362306a36Sopenharmony_ci									  struct radeon_uvd_clock_voltage_dependency_table *table)
498462306a36Sopenharmony_ci{
498562306a36Sopenharmony_ci	u32 i;
498662306a36Sopenharmony_ci
498762306a36Sopenharmony_ci	if (table) {
498862306a36Sopenharmony_ci		for (i = 0; i < table->count; i++)
498962306a36Sopenharmony_ci			ci_patch_with_vddc_leakage(rdev, &table->entries[i].v);
499062306a36Sopenharmony_ci	}
499162306a36Sopenharmony_ci}
499262306a36Sopenharmony_ci
499362306a36Sopenharmony_cistatic void ci_patch_vddc_phase_shed_limit_table_with_vddc_leakage(struct radeon_device *rdev,
499462306a36Sopenharmony_ci								   struct radeon_phase_shedding_limits_table *table)
499562306a36Sopenharmony_ci{
499662306a36Sopenharmony_ci	u32 i;
499762306a36Sopenharmony_ci
499862306a36Sopenharmony_ci	if (table) {
499962306a36Sopenharmony_ci		for (i = 0; i < table->count; i++)
500062306a36Sopenharmony_ci			ci_patch_with_vddc_leakage(rdev, &table->entries[i].voltage);
500162306a36Sopenharmony_ci	}
500262306a36Sopenharmony_ci}
500362306a36Sopenharmony_ci
500462306a36Sopenharmony_cistatic void ci_patch_clock_voltage_limits_with_vddc_leakage(struct radeon_device *rdev,
500562306a36Sopenharmony_ci							    struct radeon_clock_and_voltage_limits *table)
500662306a36Sopenharmony_ci{
500762306a36Sopenharmony_ci	if (table) {
500862306a36Sopenharmony_ci		ci_patch_with_vddc_leakage(rdev, (u16 *)&table->vddc);
500962306a36Sopenharmony_ci		ci_patch_with_vddci_leakage(rdev, (u16 *)&table->vddci);
501062306a36Sopenharmony_ci	}
501162306a36Sopenharmony_ci}
501262306a36Sopenharmony_ci
501362306a36Sopenharmony_cistatic void ci_patch_cac_leakage_table_with_vddc_leakage(struct radeon_device *rdev,
501462306a36Sopenharmony_ci							 struct radeon_cac_leakage_table *table)
501562306a36Sopenharmony_ci{
501662306a36Sopenharmony_ci	u32 i;
501762306a36Sopenharmony_ci
501862306a36Sopenharmony_ci	if (table) {
501962306a36Sopenharmony_ci		for (i = 0; i < table->count; i++)
502062306a36Sopenharmony_ci			ci_patch_with_vddc_leakage(rdev, &table->entries[i].vddc);
502162306a36Sopenharmony_ci	}
502262306a36Sopenharmony_ci}
502362306a36Sopenharmony_ci
502462306a36Sopenharmony_cistatic void ci_patch_dependency_tables_with_leakage(struct radeon_device *rdev)
502562306a36Sopenharmony_ci{
502662306a36Sopenharmony_ci
502762306a36Sopenharmony_ci	ci_patch_clock_voltage_dependency_table_with_vddc_leakage(rdev,
502862306a36Sopenharmony_ci								  &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk);
502962306a36Sopenharmony_ci	ci_patch_clock_voltage_dependency_table_with_vddc_leakage(rdev,
503062306a36Sopenharmony_ci								  &rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk);
503162306a36Sopenharmony_ci	ci_patch_clock_voltage_dependency_table_with_vddc_leakage(rdev,
503262306a36Sopenharmony_ci								  &rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk);
503362306a36Sopenharmony_ci	ci_patch_clock_voltage_dependency_table_with_vddci_leakage(rdev,
503462306a36Sopenharmony_ci								   &rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk);
503562306a36Sopenharmony_ci	ci_patch_vce_clock_voltage_dependency_table_with_vddc_leakage(rdev,
503662306a36Sopenharmony_ci								      &rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table);
503762306a36Sopenharmony_ci	ci_patch_uvd_clock_voltage_dependency_table_with_vddc_leakage(rdev,
503862306a36Sopenharmony_ci								      &rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table);
503962306a36Sopenharmony_ci	ci_patch_clock_voltage_dependency_table_with_vddc_leakage(rdev,
504062306a36Sopenharmony_ci								  &rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table);
504162306a36Sopenharmony_ci	ci_patch_clock_voltage_dependency_table_with_vddc_leakage(rdev,
504262306a36Sopenharmony_ci								  &rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table);
504362306a36Sopenharmony_ci	ci_patch_vddc_phase_shed_limit_table_with_vddc_leakage(rdev,
504462306a36Sopenharmony_ci							       &rdev->pm.dpm.dyn_state.phase_shedding_limits_table);
504562306a36Sopenharmony_ci	ci_patch_clock_voltage_limits_with_vddc_leakage(rdev,
504662306a36Sopenharmony_ci							&rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac);
504762306a36Sopenharmony_ci	ci_patch_clock_voltage_limits_with_vddc_leakage(rdev,
504862306a36Sopenharmony_ci							&rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc);
504962306a36Sopenharmony_ci	ci_patch_cac_leakage_table_with_vddc_leakage(rdev,
505062306a36Sopenharmony_ci						     &rdev->pm.dpm.dyn_state.cac_leakage_table);
505162306a36Sopenharmony_ci
505262306a36Sopenharmony_ci}
505362306a36Sopenharmony_ci
505462306a36Sopenharmony_cistatic void ci_get_memory_type(struct radeon_device *rdev)
505562306a36Sopenharmony_ci{
505662306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
505762306a36Sopenharmony_ci	u32 tmp;
505862306a36Sopenharmony_ci
505962306a36Sopenharmony_ci	tmp = RREG32(MC_SEQ_MISC0);
506062306a36Sopenharmony_ci
506162306a36Sopenharmony_ci	if (((tmp & MC_SEQ_MISC0_GDDR5_MASK) >> MC_SEQ_MISC0_GDDR5_SHIFT) ==
506262306a36Sopenharmony_ci	    MC_SEQ_MISC0_GDDR5_VALUE)
506362306a36Sopenharmony_ci		pi->mem_gddr5 = true;
506462306a36Sopenharmony_ci	else
506562306a36Sopenharmony_ci		pi->mem_gddr5 = false;
506662306a36Sopenharmony_ci
506762306a36Sopenharmony_ci}
506862306a36Sopenharmony_ci
506962306a36Sopenharmony_cistatic void ci_update_current_ps(struct radeon_device *rdev,
507062306a36Sopenharmony_ci				 struct radeon_ps *rps)
507162306a36Sopenharmony_ci{
507262306a36Sopenharmony_ci	struct ci_ps *new_ps = ci_get_ps(rps);
507362306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
507462306a36Sopenharmony_ci
507562306a36Sopenharmony_ci	pi->current_rps = *rps;
507662306a36Sopenharmony_ci	pi->current_ps = *new_ps;
507762306a36Sopenharmony_ci	pi->current_rps.ps_priv = &pi->current_ps;
507862306a36Sopenharmony_ci}
507962306a36Sopenharmony_ci
508062306a36Sopenharmony_cistatic void ci_update_requested_ps(struct radeon_device *rdev,
508162306a36Sopenharmony_ci				   struct radeon_ps *rps)
508262306a36Sopenharmony_ci{
508362306a36Sopenharmony_ci	struct ci_ps *new_ps = ci_get_ps(rps);
508462306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
508562306a36Sopenharmony_ci
508662306a36Sopenharmony_ci	pi->requested_rps = *rps;
508762306a36Sopenharmony_ci	pi->requested_ps = *new_ps;
508862306a36Sopenharmony_ci	pi->requested_rps.ps_priv = &pi->requested_ps;
508962306a36Sopenharmony_ci}
509062306a36Sopenharmony_ci
509162306a36Sopenharmony_ciint ci_dpm_pre_set_power_state(struct radeon_device *rdev)
509262306a36Sopenharmony_ci{
509362306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
509462306a36Sopenharmony_ci	struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps;
509562306a36Sopenharmony_ci	struct radeon_ps *new_ps = &requested_ps;
509662306a36Sopenharmony_ci
509762306a36Sopenharmony_ci	ci_update_requested_ps(rdev, new_ps);
509862306a36Sopenharmony_ci
509962306a36Sopenharmony_ci	ci_apply_state_adjust_rules(rdev, &pi->requested_rps);
510062306a36Sopenharmony_ci
510162306a36Sopenharmony_ci	return 0;
510262306a36Sopenharmony_ci}
510362306a36Sopenharmony_ci
510462306a36Sopenharmony_civoid ci_dpm_post_set_power_state(struct radeon_device *rdev)
510562306a36Sopenharmony_ci{
510662306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
510762306a36Sopenharmony_ci	struct radeon_ps *new_ps = &pi->requested_rps;
510862306a36Sopenharmony_ci
510962306a36Sopenharmony_ci	ci_update_current_ps(rdev, new_ps);
511062306a36Sopenharmony_ci}
511162306a36Sopenharmony_ci
511262306a36Sopenharmony_ci
511362306a36Sopenharmony_civoid ci_dpm_setup_asic(struct radeon_device *rdev)
511462306a36Sopenharmony_ci{
511562306a36Sopenharmony_ci	int r;
511662306a36Sopenharmony_ci
511762306a36Sopenharmony_ci	r = ci_mc_load_microcode(rdev);
511862306a36Sopenharmony_ci	if (r)
511962306a36Sopenharmony_ci		DRM_ERROR("Failed to load MC firmware!\n");
512062306a36Sopenharmony_ci	ci_read_clock_registers(rdev);
512162306a36Sopenharmony_ci	ci_get_memory_type(rdev);
512262306a36Sopenharmony_ci	ci_enable_acpi_power_management(rdev);
512362306a36Sopenharmony_ci	ci_init_sclk_t(rdev);
512462306a36Sopenharmony_ci}
512562306a36Sopenharmony_ci
512662306a36Sopenharmony_ciint ci_dpm_enable(struct radeon_device *rdev)
512762306a36Sopenharmony_ci{
512862306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
512962306a36Sopenharmony_ci	struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
513062306a36Sopenharmony_ci	int ret;
513162306a36Sopenharmony_ci
513262306a36Sopenharmony_ci	if (ci_is_smc_running(rdev))
513362306a36Sopenharmony_ci		return -EINVAL;
513462306a36Sopenharmony_ci	if (pi->voltage_control != CISLANDS_VOLTAGE_CONTROL_NONE) {
513562306a36Sopenharmony_ci		ci_enable_voltage_control(rdev);
513662306a36Sopenharmony_ci		ret = ci_construct_voltage_tables(rdev);
513762306a36Sopenharmony_ci		if (ret) {
513862306a36Sopenharmony_ci			DRM_ERROR("ci_construct_voltage_tables failed\n");
513962306a36Sopenharmony_ci			return ret;
514062306a36Sopenharmony_ci		}
514162306a36Sopenharmony_ci	}
514262306a36Sopenharmony_ci	if (pi->caps_dynamic_ac_timing) {
514362306a36Sopenharmony_ci		ret = ci_initialize_mc_reg_table(rdev);
514462306a36Sopenharmony_ci		if (ret)
514562306a36Sopenharmony_ci			pi->caps_dynamic_ac_timing = false;
514662306a36Sopenharmony_ci	}
514762306a36Sopenharmony_ci	if (pi->dynamic_ss)
514862306a36Sopenharmony_ci		ci_enable_spread_spectrum(rdev, true);
514962306a36Sopenharmony_ci	if (pi->thermal_protection)
515062306a36Sopenharmony_ci		ci_enable_thermal_protection(rdev, true);
515162306a36Sopenharmony_ci	ci_program_sstp(rdev);
515262306a36Sopenharmony_ci	ci_enable_display_gap(rdev);
515362306a36Sopenharmony_ci	ci_program_vc(rdev);
515462306a36Sopenharmony_ci	ret = ci_upload_firmware(rdev);
515562306a36Sopenharmony_ci	if (ret) {
515662306a36Sopenharmony_ci		DRM_ERROR("ci_upload_firmware failed\n");
515762306a36Sopenharmony_ci		return ret;
515862306a36Sopenharmony_ci	}
515962306a36Sopenharmony_ci	ret = ci_process_firmware_header(rdev);
516062306a36Sopenharmony_ci	if (ret) {
516162306a36Sopenharmony_ci		DRM_ERROR("ci_process_firmware_header failed\n");
516262306a36Sopenharmony_ci		return ret;
516362306a36Sopenharmony_ci	}
516462306a36Sopenharmony_ci	ret = ci_initial_switch_from_arb_f0_to_f1(rdev);
516562306a36Sopenharmony_ci	if (ret) {
516662306a36Sopenharmony_ci		DRM_ERROR("ci_initial_switch_from_arb_f0_to_f1 failed\n");
516762306a36Sopenharmony_ci		return ret;
516862306a36Sopenharmony_ci	}
516962306a36Sopenharmony_ci	ret = ci_init_smc_table(rdev);
517062306a36Sopenharmony_ci	if (ret) {
517162306a36Sopenharmony_ci		DRM_ERROR("ci_init_smc_table failed\n");
517262306a36Sopenharmony_ci		return ret;
517362306a36Sopenharmony_ci	}
517462306a36Sopenharmony_ci	ret = ci_init_arb_table_index(rdev);
517562306a36Sopenharmony_ci	if (ret) {
517662306a36Sopenharmony_ci		DRM_ERROR("ci_init_arb_table_index failed\n");
517762306a36Sopenharmony_ci		return ret;
517862306a36Sopenharmony_ci	}
517962306a36Sopenharmony_ci	if (pi->caps_dynamic_ac_timing) {
518062306a36Sopenharmony_ci		ret = ci_populate_initial_mc_reg_table(rdev);
518162306a36Sopenharmony_ci		if (ret) {
518262306a36Sopenharmony_ci			DRM_ERROR("ci_populate_initial_mc_reg_table failed\n");
518362306a36Sopenharmony_ci			return ret;
518462306a36Sopenharmony_ci		}
518562306a36Sopenharmony_ci	}
518662306a36Sopenharmony_ci	ret = ci_populate_pm_base(rdev);
518762306a36Sopenharmony_ci	if (ret) {
518862306a36Sopenharmony_ci		DRM_ERROR("ci_populate_pm_base failed\n");
518962306a36Sopenharmony_ci		return ret;
519062306a36Sopenharmony_ci	}
519162306a36Sopenharmony_ci	ci_dpm_start_smc(rdev);
519262306a36Sopenharmony_ci	ci_enable_vr_hot_gpio_interrupt(rdev);
519362306a36Sopenharmony_ci	ret = ci_notify_smc_display_change(rdev, false);
519462306a36Sopenharmony_ci	if (ret) {
519562306a36Sopenharmony_ci		DRM_ERROR("ci_notify_smc_display_change failed\n");
519662306a36Sopenharmony_ci		return ret;
519762306a36Sopenharmony_ci	}
519862306a36Sopenharmony_ci	ci_enable_sclk_control(rdev, true);
519962306a36Sopenharmony_ci	ret = ci_enable_ulv(rdev, true);
520062306a36Sopenharmony_ci	if (ret) {
520162306a36Sopenharmony_ci		DRM_ERROR("ci_enable_ulv failed\n");
520262306a36Sopenharmony_ci		return ret;
520362306a36Sopenharmony_ci	}
520462306a36Sopenharmony_ci	ret = ci_enable_ds_master_switch(rdev, true);
520562306a36Sopenharmony_ci	if (ret) {
520662306a36Sopenharmony_ci		DRM_ERROR("ci_enable_ds_master_switch failed\n");
520762306a36Sopenharmony_ci		return ret;
520862306a36Sopenharmony_ci	}
520962306a36Sopenharmony_ci	ret = ci_start_dpm(rdev);
521062306a36Sopenharmony_ci	if (ret) {
521162306a36Sopenharmony_ci		DRM_ERROR("ci_start_dpm failed\n");
521262306a36Sopenharmony_ci		return ret;
521362306a36Sopenharmony_ci	}
521462306a36Sopenharmony_ci	ret = ci_enable_didt(rdev, true);
521562306a36Sopenharmony_ci	if (ret) {
521662306a36Sopenharmony_ci		DRM_ERROR("ci_enable_didt failed\n");
521762306a36Sopenharmony_ci		return ret;
521862306a36Sopenharmony_ci	}
521962306a36Sopenharmony_ci	ret = ci_enable_smc_cac(rdev, true);
522062306a36Sopenharmony_ci	if (ret) {
522162306a36Sopenharmony_ci		DRM_ERROR("ci_enable_smc_cac failed\n");
522262306a36Sopenharmony_ci		return ret;
522362306a36Sopenharmony_ci	}
522462306a36Sopenharmony_ci	ret = ci_enable_power_containment(rdev, true);
522562306a36Sopenharmony_ci	if (ret) {
522662306a36Sopenharmony_ci		DRM_ERROR("ci_enable_power_containment failed\n");
522762306a36Sopenharmony_ci		return ret;
522862306a36Sopenharmony_ci	}
522962306a36Sopenharmony_ci
523062306a36Sopenharmony_ci	ret = ci_power_control_set_level(rdev);
523162306a36Sopenharmony_ci	if (ret) {
523262306a36Sopenharmony_ci		DRM_ERROR("ci_power_control_set_level failed\n");
523362306a36Sopenharmony_ci		return ret;
523462306a36Sopenharmony_ci	}
523562306a36Sopenharmony_ci
523662306a36Sopenharmony_ci	ci_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
523762306a36Sopenharmony_ci
523862306a36Sopenharmony_ci	ret = ci_enable_thermal_based_sclk_dpm(rdev, true);
523962306a36Sopenharmony_ci	if (ret) {
524062306a36Sopenharmony_ci		DRM_ERROR("ci_enable_thermal_based_sclk_dpm failed\n");
524162306a36Sopenharmony_ci		return ret;
524262306a36Sopenharmony_ci	}
524362306a36Sopenharmony_ci
524462306a36Sopenharmony_ci	ci_thermal_start_thermal_controller(rdev);
524562306a36Sopenharmony_ci
524662306a36Sopenharmony_ci	ci_update_current_ps(rdev, boot_ps);
524762306a36Sopenharmony_ci
524862306a36Sopenharmony_ci	return 0;
524962306a36Sopenharmony_ci}
525062306a36Sopenharmony_ci
525162306a36Sopenharmony_cistatic int ci_set_temperature_range(struct radeon_device *rdev)
525262306a36Sopenharmony_ci{
525362306a36Sopenharmony_ci	int ret;
525462306a36Sopenharmony_ci
525562306a36Sopenharmony_ci	ret = ci_thermal_enable_alert(rdev, false);
525662306a36Sopenharmony_ci	if (ret)
525762306a36Sopenharmony_ci		return ret;
525862306a36Sopenharmony_ci	ret = ci_thermal_set_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
525962306a36Sopenharmony_ci	if (ret)
526062306a36Sopenharmony_ci		return ret;
526162306a36Sopenharmony_ci	ret = ci_thermal_enable_alert(rdev, true);
526262306a36Sopenharmony_ci	if (ret)
526362306a36Sopenharmony_ci		return ret;
526462306a36Sopenharmony_ci
526562306a36Sopenharmony_ci	return ret;
526662306a36Sopenharmony_ci}
526762306a36Sopenharmony_ci
526862306a36Sopenharmony_ciint ci_dpm_late_enable(struct radeon_device *rdev)
526962306a36Sopenharmony_ci{
527062306a36Sopenharmony_ci	int ret;
527162306a36Sopenharmony_ci
527262306a36Sopenharmony_ci	ret = ci_set_temperature_range(rdev);
527362306a36Sopenharmony_ci	if (ret)
527462306a36Sopenharmony_ci		return ret;
527562306a36Sopenharmony_ci
527662306a36Sopenharmony_ci	ci_dpm_powergate_uvd(rdev, true);
527762306a36Sopenharmony_ci
527862306a36Sopenharmony_ci	return 0;
527962306a36Sopenharmony_ci}
528062306a36Sopenharmony_ci
528162306a36Sopenharmony_civoid ci_dpm_disable(struct radeon_device *rdev)
528262306a36Sopenharmony_ci{
528362306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
528462306a36Sopenharmony_ci	struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
528562306a36Sopenharmony_ci
528662306a36Sopenharmony_ci	ci_dpm_powergate_uvd(rdev, false);
528762306a36Sopenharmony_ci
528862306a36Sopenharmony_ci	if (!ci_is_smc_running(rdev))
528962306a36Sopenharmony_ci		return;
529062306a36Sopenharmony_ci
529162306a36Sopenharmony_ci	ci_thermal_stop_thermal_controller(rdev);
529262306a36Sopenharmony_ci
529362306a36Sopenharmony_ci	if (pi->thermal_protection)
529462306a36Sopenharmony_ci		ci_enable_thermal_protection(rdev, false);
529562306a36Sopenharmony_ci	ci_enable_power_containment(rdev, false);
529662306a36Sopenharmony_ci	ci_enable_smc_cac(rdev, false);
529762306a36Sopenharmony_ci	ci_enable_didt(rdev, false);
529862306a36Sopenharmony_ci	ci_enable_spread_spectrum(rdev, false);
529962306a36Sopenharmony_ci	ci_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, false);
530062306a36Sopenharmony_ci	ci_stop_dpm(rdev);
530162306a36Sopenharmony_ci	ci_enable_ds_master_switch(rdev, false);
530262306a36Sopenharmony_ci	ci_enable_ulv(rdev, false);
530362306a36Sopenharmony_ci	ci_clear_vc(rdev);
530462306a36Sopenharmony_ci	ci_reset_to_default(rdev);
530562306a36Sopenharmony_ci	ci_dpm_stop_smc(rdev);
530662306a36Sopenharmony_ci	ci_force_switch_to_arb_f0(rdev);
530762306a36Sopenharmony_ci	ci_enable_thermal_based_sclk_dpm(rdev, false);
530862306a36Sopenharmony_ci
530962306a36Sopenharmony_ci	ci_update_current_ps(rdev, boot_ps);
531062306a36Sopenharmony_ci}
531162306a36Sopenharmony_ci
531262306a36Sopenharmony_ciint ci_dpm_set_power_state(struct radeon_device *rdev)
531362306a36Sopenharmony_ci{
531462306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
531562306a36Sopenharmony_ci	struct radeon_ps *new_ps = &pi->requested_rps;
531662306a36Sopenharmony_ci	struct radeon_ps *old_ps = &pi->current_rps;
531762306a36Sopenharmony_ci	int ret;
531862306a36Sopenharmony_ci
531962306a36Sopenharmony_ci	ci_find_dpm_states_clocks_in_dpm_table(rdev, new_ps);
532062306a36Sopenharmony_ci	if (pi->pcie_performance_request)
532162306a36Sopenharmony_ci		ci_request_link_speed_change_before_state_change(rdev, new_ps, old_ps);
532262306a36Sopenharmony_ci	ret = ci_freeze_sclk_mclk_dpm(rdev);
532362306a36Sopenharmony_ci	if (ret) {
532462306a36Sopenharmony_ci		DRM_ERROR("ci_freeze_sclk_mclk_dpm failed\n");
532562306a36Sopenharmony_ci		return ret;
532662306a36Sopenharmony_ci	}
532762306a36Sopenharmony_ci	ret = ci_populate_and_upload_sclk_mclk_dpm_levels(rdev, new_ps);
532862306a36Sopenharmony_ci	if (ret) {
532962306a36Sopenharmony_ci		DRM_ERROR("ci_populate_and_upload_sclk_mclk_dpm_levels failed\n");
533062306a36Sopenharmony_ci		return ret;
533162306a36Sopenharmony_ci	}
533262306a36Sopenharmony_ci	ret = ci_generate_dpm_level_enable_mask(rdev, new_ps);
533362306a36Sopenharmony_ci	if (ret) {
533462306a36Sopenharmony_ci		DRM_ERROR("ci_generate_dpm_level_enable_mask failed\n");
533562306a36Sopenharmony_ci		return ret;
533662306a36Sopenharmony_ci	}
533762306a36Sopenharmony_ci
533862306a36Sopenharmony_ci	ret = ci_update_vce_dpm(rdev, new_ps, old_ps);
533962306a36Sopenharmony_ci	if (ret) {
534062306a36Sopenharmony_ci		DRM_ERROR("ci_update_vce_dpm failed\n");
534162306a36Sopenharmony_ci		return ret;
534262306a36Sopenharmony_ci	}
534362306a36Sopenharmony_ci
534462306a36Sopenharmony_ci	ret = ci_update_sclk_t(rdev);
534562306a36Sopenharmony_ci	if (ret) {
534662306a36Sopenharmony_ci		DRM_ERROR("ci_update_sclk_t failed\n");
534762306a36Sopenharmony_ci		return ret;
534862306a36Sopenharmony_ci	}
534962306a36Sopenharmony_ci	if (pi->caps_dynamic_ac_timing) {
535062306a36Sopenharmony_ci		ret = ci_update_and_upload_mc_reg_table(rdev);
535162306a36Sopenharmony_ci		if (ret) {
535262306a36Sopenharmony_ci			DRM_ERROR("ci_update_and_upload_mc_reg_table failed\n");
535362306a36Sopenharmony_ci			return ret;
535462306a36Sopenharmony_ci		}
535562306a36Sopenharmony_ci	}
535662306a36Sopenharmony_ci	ret = ci_program_memory_timing_parameters(rdev);
535762306a36Sopenharmony_ci	if (ret) {
535862306a36Sopenharmony_ci		DRM_ERROR("ci_program_memory_timing_parameters failed\n");
535962306a36Sopenharmony_ci		return ret;
536062306a36Sopenharmony_ci	}
536162306a36Sopenharmony_ci	ret = ci_unfreeze_sclk_mclk_dpm(rdev);
536262306a36Sopenharmony_ci	if (ret) {
536362306a36Sopenharmony_ci		DRM_ERROR("ci_unfreeze_sclk_mclk_dpm failed\n");
536462306a36Sopenharmony_ci		return ret;
536562306a36Sopenharmony_ci	}
536662306a36Sopenharmony_ci	ret = ci_upload_dpm_level_enable_mask(rdev);
536762306a36Sopenharmony_ci	if (ret) {
536862306a36Sopenharmony_ci		DRM_ERROR("ci_upload_dpm_level_enable_mask failed\n");
536962306a36Sopenharmony_ci		return ret;
537062306a36Sopenharmony_ci	}
537162306a36Sopenharmony_ci	if (pi->pcie_performance_request)
537262306a36Sopenharmony_ci		ci_notify_link_speed_change_after_state_change(rdev, new_ps, old_ps);
537362306a36Sopenharmony_ci
537462306a36Sopenharmony_ci	return 0;
537562306a36Sopenharmony_ci}
537662306a36Sopenharmony_ci
537762306a36Sopenharmony_ci#if 0
537862306a36Sopenharmony_civoid ci_dpm_reset_asic(struct radeon_device *rdev)
537962306a36Sopenharmony_ci{
538062306a36Sopenharmony_ci	ci_set_boot_state(rdev);
538162306a36Sopenharmony_ci}
538262306a36Sopenharmony_ci#endif
538362306a36Sopenharmony_ci
538462306a36Sopenharmony_civoid ci_dpm_display_configuration_changed(struct radeon_device *rdev)
538562306a36Sopenharmony_ci{
538662306a36Sopenharmony_ci	ci_program_display_gap(rdev);
538762306a36Sopenharmony_ci}
538862306a36Sopenharmony_ci
538962306a36Sopenharmony_ciunion power_info {
539062306a36Sopenharmony_ci	struct _ATOM_POWERPLAY_INFO info;
539162306a36Sopenharmony_ci	struct _ATOM_POWERPLAY_INFO_V2 info_2;
539262306a36Sopenharmony_ci	struct _ATOM_POWERPLAY_INFO_V3 info_3;
539362306a36Sopenharmony_ci	struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
539462306a36Sopenharmony_ci	struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
539562306a36Sopenharmony_ci	struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
539662306a36Sopenharmony_ci};
539762306a36Sopenharmony_ci
539862306a36Sopenharmony_ciunion pplib_clock_info {
539962306a36Sopenharmony_ci	struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
540062306a36Sopenharmony_ci	struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
540162306a36Sopenharmony_ci	struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
540262306a36Sopenharmony_ci	struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
540362306a36Sopenharmony_ci	struct _ATOM_PPLIB_SI_CLOCK_INFO si;
540462306a36Sopenharmony_ci	struct _ATOM_PPLIB_CI_CLOCK_INFO ci;
540562306a36Sopenharmony_ci};
540662306a36Sopenharmony_ci
540762306a36Sopenharmony_ciunion pplib_power_state {
540862306a36Sopenharmony_ci	struct _ATOM_PPLIB_STATE v1;
540962306a36Sopenharmony_ci	struct _ATOM_PPLIB_STATE_V2 v2;
541062306a36Sopenharmony_ci};
541162306a36Sopenharmony_ci
541262306a36Sopenharmony_cistatic void ci_parse_pplib_non_clock_info(struct radeon_device *rdev,
541362306a36Sopenharmony_ci					  struct radeon_ps *rps,
541462306a36Sopenharmony_ci					  struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
541562306a36Sopenharmony_ci					  u8 table_rev)
541662306a36Sopenharmony_ci{
541762306a36Sopenharmony_ci	rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
541862306a36Sopenharmony_ci	rps->class = le16_to_cpu(non_clock_info->usClassification);
541962306a36Sopenharmony_ci	rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
542062306a36Sopenharmony_ci
542162306a36Sopenharmony_ci	if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
542262306a36Sopenharmony_ci		rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
542362306a36Sopenharmony_ci		rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
542462306a36Sopenharmony_ci	} else {
542562306a36Sopenharmony_ci		rps->vclk = 0;
542662306a36Sopenharmony_ci		rps->dclk = 0;
542762306a36Sopenharmony_ci	}
542862306a36Sopenharmony_ci
542962306a36Sopenharmony_ci	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
543062306a36Sopenharmony_ci		rdev->pm.dpm.boot_ps = rps;
543162306a36Sopenharmony_ci	if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
543262306a36Sopenharmony_ci		rdev->pm.dpm.uvd_ps = rps;
543362306a36Sopenharmony_ci}
543462306a36Sopenharmony_ci
543562306a36Sopenharmony_cistatic void ci_parse_pplib_clock_info(struct radeon_device *rdev,
543662306a36Sopenharmony_ci				      struct radeon_ps *rps, int index,
543762306a36Sopenharmony_ci				      union pplib_clock_info *clock_info)
543862306a36Sopenharmony_ci{
543962306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
544062306a36Sopenharmony_ci	struct ci_ps *ps = ci_get_ps(rps);
544162306a36Sopenharmony_ci	struct ci_pl *pl = &ps->performance_levels[index];
544262306a36Sopenharmony_ci
544362306a36Sopenharmony_ci	ps->performance_level_count = index + 1;
544462306a36Sopenharmony_ci
544562306a36Sopenharmony_ci	pl->sclk = le16_to_cpu(clock_info->ci.usEngineClockLow);
544662306a36Sopenharmony_ci	pl->sclk |= clock_info->ci.ucEngineClockHigh << 16;
544762306a36Sopenharmony_ci	pl->mclk = le16_to_cpu(clock_info->ci.usMemoryClockLow);
544862306a36Sopenharmony_ci	pl->mclk |= clock_info->ci.ucMemoryClockHigh << 16;
544962306a36Sopenharmony_ci
545062306a36Sopenharmony_ci	pl->pcie_gen = r600_get_pcie_gen_support(rdev,
545162306a36Sopenharmony_ci						 pi->sys_pcie_mask,
545262306a36Sopenharmony_ci						 pi->vbios_boot_state.pcie_gen_bootup_value,
545362306a36Sopenharmony_ci						 clock_info->ci.ucPCIEGen);
545462306a36Sopenharmony_ci	pl->pcie_lane = r600_get_pcie_lane_support(rdev,
545562306a36Sopenharmony_ci						   pi->vbios_boot_state.pcie_lane_bootup_value,
545662306a36Sopenharmony_ci						   le16_to_cpu(clock_info->ci.usPCIELane));
545762306a36Sopenharmony_ci
545862306a36Sopenharmony_ci	if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) {
545962306a36Sopenharmony_ci		pi->acpi_pcie_gen = pl->pcie_gen;
546062306a36Sopenharmony_ci	}
546162306a36Sopenharmony_ci
546262306a36Sopenharmony_ci	if (rps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) {
546362306a36Sopenharmony_ci		pi->ulv.supported = true;
546462306a36Sopenharmony_ci		pi->ulv.pl = *pl;
546562306a36Sopenharmony_ci		pi->ulv.cg_ulv_parameter = CISLANDS_CGULVPARAMETER_DFLT;
546662306a36Sopenharmony_ci	}
546762306a36Sopenharmony_ci
546862306a36Sopenharmony_ci	/* patch up boot state */
546962306a36Sopenharmony_ci	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
547062306a36Sopenharmony_ci		pl->mclk = pi->vbios_boot_state.mclk_bootup_value;
547162306a36Sopenharmony_ci		pl->sclk = pi->vbios_boot_state.sclk_bootup_value;
547262306a36Sopenharmony_ci		pl->pcie_gen = pi->vbios_boot_state.pcie_gen_bootup_value;
547362306a36Sopenharmony_ci		pl->pcie_lane = pi->vbios_boot_state.pcie_lane_bootup_value;
547462306a36Sopenharmony_ci	}
547562306a36Sopenharmony_ci
547662306a36Sopenharmony_ci	switch (rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) {
547762306a36Sopenharmony_ci	case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY:
547862306a36Sopenharmony_ci		pi->use_pcie_powersaving_levels = true;
547962306a36Sopenharmony_ci		if (pi->pcie_gen_powersaving.max < pl->pcie_gen)
548062306a36Sopenharmony_ci			pi->pcie_gen_powersaving.max = pl->pcie_gen;
548162306a36Sopenharmony_ci		if (pi->pcie_gen_powersaving.min > pl->pcie_gen)
548262306a36Sopenharmony_ci			pi->pcie_gen_powersaving.min = pl->pcie_gen;
548362306a36Sopenharmony_ci		if (pi->pcie_lane_powersaving.max < pl->pcie_lane)
548462306a36Sopenharmony_ci			pi->pcie_lane_powersaving.max = pl->pcie_lane;
548562306a36Sopenharmony_ci		if (pi->pcie_lane_powersaving.min > pl->pcie_lane)
548662306a36Sopenharmony_ci			pi->pcie_lane_powersaving.min = pl->pcie_lane;
548762306a36Sopenharmony_ci		break;
548862306a36Sopenharmony_ci	case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE:
548962306a36Sopenharmony_ci		pi->use_pcie_performance_levels = true;
549062306a36Sopenharmony_ci		if (pi->pcie_gen_performance.max < pl->pcie_gen)
549162306a36Sopenharmony_ci			pi->pcie_gen_performance.max = pl->pcie_gen;
549262306a36Sopenharmony_ci		if (pi->pcie_gen_performance.min > pl->pcie_gen)
549362306a36Sopenharmony_ci			pi->pcie_gen_performance.min = pl->pcie_gen;
549462306a36Sopenharmony_ci		if (pi->pcie_lane_performance.max < pl->pcie_lane)
549562306a36Sopenharmony_ci			pi->pcie_lane_performance.max = pl->pcie_lane;
549662306a36Sopenharmony_ci		if (pi->pcie_lane_performance.min > pl->pcie_lane)
549762306a36Sopenharmony_ci			pi->pcie_lane_performance.min = pl->pcie_lane;
549862306a36Sopenharmony_ci		break;
549962306a36Sopenharmony_ci	default:
550062306a36Sopenharmony_ci		break;
550162306a36Sopenharmony_ci	}
550262306a36Sopenharmony_ci}
550362306a36Sopenharmony_ci
550462306a36Sopenharmony_cistatic int ci_parse_power_table(struct radeon_device *rdev)
550562306a36Sopenharmony_ci{
550662306a36Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
550762306a36Sopenharmony_ci	struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
550862306a36Sopenharmony_ci	union pplib_power_state *power_state;
550962306a36Sopenharmony_ci	int i, j, k, non_clock_array_index, clock_array_index;
551062306a36Sopenharmony_ci	union pplib_clock_info *clock_info;
551162306a36Sopenharmony_ci	struct _StateArray *state_array;
551262306a36Sopenharmony_ci	struct _ClockInfoArray *clock_info_array;
551362306a36Sopenharmony_ci	struct _NonClockInfoArray *non_clock_info_array;
551462306a36Sopenharmony_ci	union power_info *power_info;
551562306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
551662306a36Sopenharmony_ci	u16 data_offset;
551762306a36Sopenharmony_ci	u8 frev, crev;
551862306a36Sopenharmony_ci	u8 *power_state_offset;
551962306a36Sopenharmony_ci	struct ci_ps *ps;
552062306a36Sopenharmony_ci	int ret;
552162306a36Sopenharmony_ci
552262306a36Sopenharmony_ci	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
552362306a36Sopenharmony_ci				   &frev, &crev, &data_offset))
552462306a36Sopenharmony_ci		return -EINVAL;
552562306a36Sopenharmony_ci	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
552662306a36Sopenharmony_ci
552762306a36Sopenharmony_ci	state_array = (struct _StateArray *)
552862306a36Sopenharmony_ci		(mode_info->atom_context->bios + data_offset +
552962306a36Sopenharmony_ci		 le16_to_cpu(power_info->pplib.usStateArrayOffset));
553062306a36Sopenharmony_ci	clock_info_array = (struct _ClockInfoArray *)
553162306a36Sopenharmony_ci		(mode_info->atom_context->bios + data_offset +
553262306a36Sopenharmony_ci		 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset));
553362306a36Sopenharmony_ci	non_clock_info_array = (struct _NonClockInfoArray *)
553462306a36Sopenharmony_ci		(mode_info->atom_context->bios + data_offset +
553562306a36Sopenharmony_ci		 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
553662306a36Sopenharmony_ci
553762306a36Sopenharmony_ci	rdev->pm.dpm.ps = kcalloc(state_array->ucNumEntries,
553862306a36Sopenharmony_ci				  sizeof(struct radeon_ps),
553962306a36Sopenharmony_ci				  GFP_KERNEL);
554062306a36Sopenharmony_ci	if (!rdev->pm.dpm.ps)
554162306a36Sopenharmony_ci		return -ENOMEM;
554262306a36Sopenharmony_ci	power_state_offset = (u8 *)state_array->states;
554362306a36Sopenharmony_ci	rdev->pm.dpm.num_ps = 0;
554462306a36Sopenharmony_ci	for (i = 0; i < state_array->ucNumEntries; i++) {
554562306a36Sopenharmony_ci		u8 *idx;
554662306a36Sopenharmony_ci		power_state = (union pplib_power_state *)power_state_offset;
554762306a36Sopenharmony_ci		non_clock_array_index = power_state->v2.nonClockInfoIndex;
554862306a36Sopenharmony_ci		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
554962306a36Sopenharmony_ci			&non_clock_info_array->nonClockInfo[non_clock_array_index];
555062306a36Sopenharmony_ci		if (!rdev->pm.power_state[i].clock_info) {
555162306a36Sopenharmony_ci			ret = -EINVAL;
555262306a36Sopenharmony_ci			goto err_free_ps;
555362306a36Sopenharmony_ci		}
555462306a36Sopenharmony_ci		ps = kzalloc(sizeof(struct ci_ps), GFP_KERNEL);
555562306a36Sopenharmony_ci		if (ps == NULL) {
555662306a36Sopenharmony_ci			ret = -ENOMEM;
555762306a36Sopenharmony_ci			goto err_free_ps;
555862306a36Sopenharmony_ci		}
555962306a36Sopenharmony_ci		rdev->pm.dpm.ps[i].ps_priv = ps;
556062306a36Sopenharmony_ci		ci_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
556162306a36Sopenharmony_ci					      non_clock_info,
556262306a36Sopenharmony_ci					      non_clock_info_array->ucEntrySize);
556362306a36Sopenharmony_ci		k = 0;
556462306a36Sopenharmony_ci		idx = (u8 *)&power_state->v2.clockInfoIndex[0];
556562306a36Sopenharmony_ci		for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) {
556662306a36Sopenharmony_ci			clock_array_index = idx[j];
556762306a36Sopenharmony_ci			if (clock_array_index >= clock_info_array->ucNumEntries)
556862306a36Sopenharmony_ci				continue;
556962306a36Sopenharmony_ci			if (k >= CISLANDS_MAX_HARDWARE_POWERLEVELS)
557062306a36Sopenharmony_ci				break;
557162306a36Sopenharmony_ci			clock_info = (union pplib_clock_info *)
557262306a36Sopenharmony_ci				((u8 *)&clock_info_array->clockInfo[0] +
557362306a36Sopenharmony_ci				 (clock_array_index * clock_info_array->ucEntrySize));
557462306a36Sopenharmony_ci			ci_parse_pplib_clock_info(rdev,
557562306a36Sopenharmony_ci						  &rdev->pm.dpm.ps[i], k,
557662306a36Sopenharmony_ci						  clock_info);
557762306a36Sopenharmony_ci			k++;
557862306a36Sopenharmony_ci		}
557962306a36Sopenharmony_ci		power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
558062306a36Sopenharmony_ci		rdev->pm.dpm.num_ps = i + 1;
558162306a36Sopenharmony_ci	}
558262306a36Sopenharmony_ci
558362306a36Sopenharmony_ci	/* fill in the vce power states */
558462306a36Sopenharmony_ci	for (i = 0; i < RADEON_MAX_VCE_LEVELS; i++) {
558562306a36Sopenharmony_ci		u32 sclk, mclk;
558662306a36Sopenharmony_ci		clock_array_index = rdev->pm.dpm.vce_states[i].clk_idx;
558762306a36Sopenharmony_ci		clock_info = (union pplib_clock_info *)
558862306a36Sopenharmony_ci			&clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
558962306a36Sopenharmony_ci		sclk = le16_to_cpu(clock_info->ci.usEngineClockLow);
559062306a36Sopenharmony_ci		sclk |= clock_info->ci.ucEngineClockHigh << 16;
559162306a36Sopenharmony_ci		mclk = le16_to_cpu(clock_info->ci.usMemoryClockLow);
559262306a36Sopenharmony_ci		mclk |= clock_info->ci.ucMemoryClockHigh << 16;
559362306a36Sopenharmony_ci		rdev->pm.dpm.vce_states[i].sclk = sclk;
559462306a36Sopenharmony_ci		rdev->pm.dpm.vce_states[i].mclk = mclk;
559562306a36Sopenharmony_ci	}
559662306a36Sopenharmony_ci
559762306a36Sopenharmony_ci	return 0;
559862306a36Sopenharmony_ci
559962306a36Sopenharmony_cierr_free_ps:
560062306a36Sopenharmony_ci	for (i = 0; i < rdev->pm.dpm.num_ps; i++)
560162306a36Sopenharmony_ci		kfree(rdev->pm.dpm.ps[i].ps_priv);
560262306a36Sopenharmony_ci	kfree(rdev->pm.dpm.ps);
560362306a36Sopenharmony_ci	return ret;
560462306a36Sopenharmony_ci}
560562306a36Sopenharmony_ci
560662306a36Sopenharmony_cistatic int ci_get_vbios_boot_values(struct radeon_device *rdev,
560762306a36Sopenharmony_ci				    struct ci_vbios_boot_state *boot_state)
560862306a36Sopenharmony_ci{
560962306a36Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
561062306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
561162306a36Sopenharmony_ci	ATOM_FIRMWARE_INFO_V2_2 *firmware_info;
561262306a36Sopenharmony_ci	u8 frev, crev;
561362306a36Sopenharmony_ci	u16 data_offset;
561462306a36Sopenharmony_ci
561562306a36Sopenharmony_ci	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
561662306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
561762306a36Sopenharmony_ci		firmware_info =
561862306a36Sopenharmony_ci			(ATOM_FIRMWARE_INFO_V2_2 *)(mode_info->atom_context->bios +
561962306a36Sopenharmony_ci						    data_offset);
562062306a36Sopenharmony_ci		boot_state->mvdd_bootup_value = le16_to_cpu(firmware_info->usBootUpMVDDCVoltage);
562162306a36Sopenharmony_ci		boot_state->vddc_bootup_value = le16_to_cpu(firmware_info->usBootUpVDDCVoltage);
562262306a36Sopenharmony_ci		boot_state->vddci_bootup_value = le16_to_cpu(firmware_info->usBootUpVDDCIVoltage);
562362306a36Sopenharmony_ci		boot_state->pcie_gen_bootup_value = ci_get_current_pcie_speed(rdev);
562462306a36Sopenharmony_ci		boot_state->pcie_lane_bootup_value = ci_get_current_pcie_lane_number(rdev);
562562306a36Sopenharmony_ci		boot_state->sclk_bootup_value = le32_to_cpu(firmware_info->ulDefaultEngineClock);
562662306a36Sopenharmony_ci		boot_state->mclk_bootup_value = le32_to_cpu(firmware_info->ulDefaultMemoryClock);
562762306a36Sopenharmony_ci
562862306a36Sopenharmony_ci		return 0;
562962306a36Sopenharmony_ci	}
563062306a36Sopenharmony_ci	return -EINVAL;
563162306a36Sopenharmony_ci}
563262306a36Sopenharmony_ci
563362306a36Sopenharmony_civoid ci_dpm_fini(struct radeon_device *rdev)
563462306a36Sopenharmony_ci{
563562306a36Sopenharmony_ci	int i;
563662306a36Sopenharmony_ci
563762306a36Sopenharmony_ci	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
563862306a36Sopenharmony_ci		kfree(rdev->pm.dpm.ps[i].ps_priv);
563962306a36Sopenharmony_ci	}
564062306a36Sopenharmony_ci	kfree(rdev->pm.dpm.ps);
564162306a36Sopenharmony_ci	kfree(rdev->pm.dpm.priv);
564262306a36Sopenharmony_ci	kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries);
564362306a36Sopenharmony_ci	r600_free_extended_power_table(rdev);
564462306a36Sopenharmony_ci}
564562306a36Sopenharmony_ci
564662306a36Sopenharmony_ciint ci_dpm_init(struct radeon_device *rdev)
564762306a36Sopenharmony_ci{
564862306a36Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
564962306a36Sopenharmony_ci	SMU7_Discrete_DpmTable  *dpm_table;
565062306a36Sopenharmony_ci	struct radeon_gpio_rec gpio;
565162306a36Sopenharmony_ci	u16 data_offset, size;
565262306a36Sopenharmony_ci	u8 frev, crev;
565362306a36Sopenharmony_ci	struct ci_power_info *pi;
565462306a36Sopenharmony_ci	enum pci_bus_speed speed_cap = PCI_SPEED_UNKNOWN;
565562306a36Sopenharmony_ci	struct pci_dev *root = rdev->pdev->bus->self;
565662306a36Sopenharmony_ci	int ret;
565762306a36Sopenharmony_ci
565862306a36Sopenharmony_ci	pi = kzalloc(sizeof(struct ci_power_info), GFP_KERNEL);
565962306a36Sopenharmony_ci	if (pi == NULL)
566062306a36Sopenharmony_ci		return -ENOMEM;
566162306a36Sopenharmony_ci	rdev->pm.dpm.priv = pi;
566262306a36Sopenharmony_ci
566362306a36Sopenharmony_ci	if (!pci_is_root_bus(rdev->pdev->bus))
566462306a36Sopenharmony_ci		speed_cap = pcie_get_speed_cap(root);
566562306a36Sopenharmony_ci	if (speed_cap == PCI_SPEED_UNKNOWN) {
566662306a36Sopenharmony_ci		pi->sys_pcie_mask = 0;
566762306a36Sopenharmony_ci	} else {
566862306a36Sopenharmony_ci		if (speed_cap == PCIE_SPEED_8_0GT)
566962306a36Sopenharmony_ci			pi->sys_pcie_mask = RADEON_PCIE_SPEED_25 |
567062306a36Sopenharmony_ci				RADEON_PCIE_SPEED_50 |
567162306a36Sopenharmony_ci				RADEON_PCIE_SPEED_80;
567262306a36Sopenharmony_ci		else if (speed_cap == PCIE_SPEED_5_0GT)
567362306a36Sopenharmony_ci			pi->sys_pcie_mask = RADEON_PCIE_SPEED_25 |
567462306a36Sopenharmony_ci				RADEON_PCIE_SPEED_50;
567562306a36Sopenharmony_ci		else
567662306a36Sopenharmony_ci			pi->sys_pcie_mask = RADEON_PCIE_SPEED_25;
567762306a36Sopenharmony_ci	}
567862306a36Sopenharmony_ci	pi->force_pcie_gen = RADEON_PCIE_GEN_INVALID;
567962306a36Sopenharmony_ci
568062306a36Sopenharmony_ci	pi->pcie_gen_performance.max = RADEON_PCIE_GEN1;
568162306a36Sopenharmony_ci	pi->pcie_gen_performance.min = RADEON_PCIE_GEN3;
568262306a36Sopenharmony_ci	pi->pcie_gen_powersaving.max = RADEON_PCIE_GEN1;
568362306a36Sopenharmony_ci	pi->pcie_gen_powersaving.min = RADEON_PCIE_GEN3;
568462306a36Sopenharmony_ci
568562306a36Sopenharmony_ci	pi->pcie_lane_performance.max = 0;
568662306a36Sopenharmony_ci	pi->pcie_lane_performance.min = 16;
568762306a36Sopenharmony_ci	pi->pcie_lane_powersaving.max = 0;
568862306a36Sopenharmony_ci	pi->pcie_lane_powersaving.min = 16;
568962306a36Sopenharmony_ci
569062306a36Sopenharmony_ci	ret = ci_get_vbios_boot_values(rdev, &pi->vbios_boot_state);
569162306a36Sopenharmony_ci	if (ret) {
569262306a36Sopenharmony_ci		kfree(rdev->pm.dpm.priv);
569362306a36Sopenharmony_ci		return ret;
569462306a36Sopenharmony_ci	}
569562306a36Sopenharmony_ci
569662306a36Sopenharmony_ci	ret = r600_get_platform_caps(rdev);
569762306a36Sopenharmony_ci	if (ret) {
569862306a36Sopenharmony_ci		kfree(rdev->pm.dpm.priv);
569962306a36Sopenharmony_ci		return ret;
570062306a36Sopenharmony_ci	}
570162306a36Sopenharmony_ci
570262306a36Sopenharmony_ci	ret = r600_parse_extended_power_table(rdev);
570362306a36Sopenharmony_ci	if (ret) {
570462306a36Sopenharmony_ci		kfree(rdev->pm.dpm.priv);
570562306a36Sopenharmony_ci		return ret;
570662306a36Sopenharmony_ci	}
570762306a36Sopenharmony_ci
570862306a36Sopenharmony_ci	ret = ci_parse_power_table(rdev);
570962306a36Sopenharmony_ci	if (ret) {
571062306a36Sopenharmony_ci		kfree(rdev->pm.dpm.priv);
571162306a36Sopenharmony_ci		r600_free_extended_power_table(rdev);
571262306a36Sopenharmony_ci		return ret;
571362306a36Sopenharmony_ci	}
571462306a36Sopenharmony_ci
571562306a36Sopenharmony_ci	pi->dll_default_on = false;
571662306a36Sopenharmony_ci	pi->sram_end = SMC_RAM_END;
571762306a36Sopenharmony_ci
571862306a36Sopenharmony_ci	pi->activity_target[0] = CISLAND_TARGETACTIVITY_DFLT;
571962306a36Sopenharmony_ci	pi->activity_target[1] = CISLAND_TARGETACTIVITY_DFLT;
572062306a36Sopenharmony_ci	pi->activity_target[2] = CISLAND_TARGETACTIVITY_DFLT;
572162306a36Sopenharmony_ci	pi->activity_target[3] = CISLAND_TARGETACTIVITY_DFLT;
572262306a36Sopenharmony_ci	pi->activity_target[4] = CISLAND_TARGETACTIVITY_DFLT;
572362306a36Sopenharmony_ci	pi->activity_target[5] = CISLAND_TARGETACTIVITY_DFLT;
572462306a36Sopenharmony_ci	pi->activity_target[6] = CISLAND_TARGETACTIVITY_DFLT;
572562306a36Sopenharmony_ci	pi->activity_target[7] = CISLAND_TARGETACTIVITY_DFLT;
572662306a36Sopenharmony_ci
572762306a36Sopenharmony_ci	pi->mclk_activity_target = CISLAND_MCLK_TARGETACTIVITY_DFLT;
572862306a36Sopenharmony_ci
572962306a36Sopenharmony_ci	pi->sclk_dpm_key_disabled = 0;
573062306a36Sopenharmony_ci	pi->mclk_dpm_key_disabled = 0;
573162306a36Sopenharmony_ci	pi->pcie_dpm_key_disabled = 0;
573262306a36Sopenharmony_ci	pi->thermal_sclk_dpm_enabled = 0;
573362306a36Sopenharmony_ci
573462306a36Sopenharmony_ci	/* mclk dpm is unstable on some R7 260X cards with the old mc ucode */
573562306a36Sopenharmony_ci	if ((rdev->pdev->device == 0x6658) &&
573662306a36Sopenharmony_ci	    (rdev->mc_fw->size == (BONAIRE_MC_UCODE_SIZE * 4))) {
573762306a36Sopenharmony_ci		pi->mclk_dpm_key_disabled = 1;
573862306a36Sopenharmony_ci	}
573962306a36Sopenharmony_ci
574062306a36Sopenharmony_ci	pi->caps_sclk_ds = true;
574162306a36Sopenharmony_ci
574262306a36Sopenharmony_ci	pi->mclk_strobe_mode_threshold = 40000;
574362306a36Sopenharmony_ci	pi->mclk_stutter_mode_threshold = 40000;
574462306a36Sopenharmony_ci	pi->mclk_edc_enable_threshold = 40000;
574562306a36Sopenharmony_ci	pi->mclk_edc_wr_enable_threshold = 40000;
574662306a36Sopenharmony_ci
574762306a36Sopenharmony_ci	ci_initialize_powertune_defaults(rdev);
574862306a36Sopenharmony_ci
574962306a36Sopenharmony_ci	pi->caps_fps = false;
575062306a36Sopenharmony_ci
575162306a36Sopenharmony_ci	pi->caps_sclk_throttle_low_notification = false;
575262306a36Sopenharmony_ci
575362306a36Sopenharmony_ci	pi->caps_uvd_dpm = true;
575462306a36Sopenharmony_ci	pi->caps_vce_dpm = true;
575562306a36Sopenharmony_ci
575662306a36Sopenharmony_ci	ci_get_leakage_voltages(rdev);
575762306a36Sopenharmony_ci	ci_patch_dependency_tables_with_leakage(rdev);
575862306a36Sopenharmony_ci	ci_set_private_data_variables_based_on_pptable(rdev);
575962306a36Sopenharmony_ci
576062306a36Sopenharmony_ci	rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries =
576162306a36Sopenharmony_ci		kcalloc(4,
576262306a36Sopenharmony_ci			sizeof(struct radeon_clock_voltage_dependency_entry),
576362306a36Sopenharmony_ci			GFP_KERNEL);
576462306a36Sopenharmony_ci	if (!rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries) {
576562306a36Sopenharmony_ci		ci_dpm_fini(rdev);
576662306a36Sopenharmony_ci		return -ENOMEM;
576762306a36Sopenharmony_ci	}
576862306a36Sopenharmony_ci	rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.count = 4;
576962306a36Sopenharmony_ci	rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].clk = 0;
577062306a36Sopenharmony_ci	rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].v = 0;
577162306a36Sopenharmony_ci	rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[1].clk = 36000;
577262306a36Sopenharmony_ci	rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[1].v = 720;
577362306a36Sopenharmony_ci	rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[2].clk = 54000;
577462306a36Sopenharmony_ci	rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[2].v = 810;
577562306a36Sopenharmony_ci	rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[3].clk = 72000;
577662306a36Sopenharmony_ci	rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[3].v = 900;
577762306a36Sopenharmony_ci
577862306a36Sopenharmony_ci	rdev->pm.dpm.dyn_state.mclk_sclk_ratio = 4;
577962306a36Sopenharmony_ci	rdev->pm.dpm.dyn_state.sclk_mclk_delta = 15000;
578062306a36Sopenharmony_ci	rdev->pm.dpm.dyn_state.vddc_vddci_delta = 200;
578162306a36Sopenharmony_ci
578262306a36Sopenharmony_ci	rdev->pm.dpm.dyn_state.valid_sclk_values.count = 0;
578362306a36Sopenharmony_ci	rdev->pm.dpm.dyn_state.valid_sclk_values.values = NULL;
578462306a36Sopenharmony_ci	rdev->pm.dpm.dyn_state.valid_mclk_values.count = 0;
578562306a36Sopenharmony_ci	rdev->pm.dpm.dyn_state.valid_mclk_values.values = NULL;
578662306a36Sopenharmony_ci
578762306a36Sopenharmony_ci	if (rdev->family == CHIP_HAWAII) {
578862306a36Sopenharmony_ci		pi->thermal_temp_setting.temperature_low = 94500;
578962306a36Sopenharmony_ci		pi->thermal_temp_setting.temperature_high = 95000;
579062306a36Sopenharmony_ci		pi->thermal_temp_setting.temperature_shutdown = 104000;
579162306a36Sopenharmony_ci	} else {
579262306a36Sopenharmony_ci		pi->thermal_temp_setting.temperature_low = 99500;
579362306a36Sopenharmony_ci		pi->thermal_temp_setting.temperature_high = 100000;
579462306a36Sopenharmony_ci		pi->thermal_temp_setting.temperature_shutdown = 104000;
579562306a36Sopenharmony_ci	}
579662306a36Sopenharmony_ci
579762306a36Sopenharmony_ci	pi->uvd_enabled = false;
579862306a36Sopenharmony_ci
579962306a36Sopenharmony_ci	dpm_table = &pi->smc_state_table;
580062306a36Sopenharmony_ci
580162306a36Sopenharmony_ci	gpio = radeon_atombios_lookup_gpio(rdev, VDDC_VRHOT_GPIO_PINID);
580262306a36Sopenharmony_ci	if (gpio.valid) {
580362306a36Sopenharmony_ci		dpm_table->VRHotGpio = gpio.shift;
580462306a36Sopenharmony_ci		rdev->pm.dpm.platform_caps |= ATOM_PP_PLATFORM_CAP_REGULATOR_HOT;
580562306a36Sopenharmony_ci	} else {
580662306a36Sopenharmony_ci		dpm_table->VRHotGpio = CISLANDS_UNUSED_GPIO_PIN;
580762306a36Sopenharmony_ci		rdev->pm.dpm.platform_caps &= ~ATOM_PP_PLATFORM_CAP_REGULATOR_HOT;
580862306a36Sopenharmony_ci	}
580962306a36Sopenharmony_ci
581062306a36Sopenharmony_ci	gpio = radeon_atombios_lookup_gpio(rdev, PP_AC_DC_SWITCH_GPIO_PINID);
581162306a36Sopenharmony_ci	if (gpio.valid) {
581262306a36Sopenharmony_ci		dpm_table->AcDcGpio = gpio.shift;
581362306a36Sopenharmony_ci		rdev->pm.dpm.platform_caps |= ATOM_PP_PLATFORM_CAP_HARDWAREDC;
581462306a36Sopenharmony_ci	} else {
581562306a36Sopenharmony_ci		dpm_table->AcDcGpio = CISLANDS_UNUSED_GPIO_PIN;
581662306a36Sopenharmony_ci		rdev->pm.dpm.platform_caps &= ~ATOM_PP_PLATFORM_CAP_HARDWAREDC;
581762306a36Sopenharmony_ci	}
581862306a36Sopenharmony_ci
581962306a36Sopenharmony_ci	gpio = radeon_atombios_lookup_gpio(rdev, VDDC_PCC_GPIO_PINID);
582062306a36Sopenharmony_ci	if (gpio.valid) {
582162306a36Sopenharmony_ci		u32 tmp = RREG32_SMC(CNB_PWRMGT_CNTL);
582262306a36Sopenharmony_ci
582362306a36Sopenharmony_ci		switch (gpio.shift) {
582462306a36Sopenharmony_ci		case 0:
582562306a36Sopenharmony_ci			tmp &= ~GNB_SLOW_MODE_MASK;
582662306a36Sopenharmony_ci			tmp |= GNB_SLOW_MODE(1);
582762306a36Sopenharmony_ci			break;
582862306a36Sopenharmony_ci		case 1:
582962306a36Sopenharmony_ci			tmp &= ~GNB_SLOW_MODE_MASK;
583062306a36Sopenharmony_ci			tmp |= GNB_SLOW_MODE(2);
583162306a36Sopenharmony_ci			break;
583262306a36Sopenharmony_ci		case 2:
583362306a36Sopenharmony_ci			tmp |= GNB_SLOW;
583462306a36Sopenharmony_ci			break;
583562306a36Sopenharmony_ci		case 3:
583662306a36Sopenharmony_ci			tmp |= FORCE_NB_PS1;
583762306a36Sopenharmony_ci			break;
583862306a36Sopenharmony_ci		case 4:
583962306a36Sopenharmony_ci			tmp |= DPM_ENABLED;
584062306a36Sopenharmony_ci			break;
584162306a36Sopenharmony_ci		default:
584262306a36Sopenharmony_ci			DRM_DEBUG("Invalid PCC GPIO: %u!\n", gpio.shift);
584362306a36Sopenharmony_ci			break;
584462306a36Sopenharmony_ci		}
584562306a36Sopenharmony_ci		WREG32_SMC(CNB_PWRMGT_CNTL, tmp);
584662306a36Sopenharmony_ci	}
584762306a36Sopenharmony_ci
584862306a36Sopenharmony_ci	pi->voltage_control = CISLANDS_VOLTAGE_CONTROL_NONE;
584962306a36Sopenharmony_ci	pi->vddci_control = CISLANDS_VOLTAGE_CONTROL_NONE;
585062306a36Sopenharmony_ci	pi->mvdd_control = CISLANDS_VOLTAGE_CONTROL_NONE;
585162306a36Sopenharmony_ci	if (radeon_atom_is_voltage_gpio(rdev, VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_GPIO_LUT))
585262306a36Sopenharmony_ci		pi->voltage_control = CISLANDS_VOLTAGE_CONTROL_BY_GPIO;
585362306a36Sopenharmony_ci	else if (radeon_atom_is_voltage_gpio(rdev, VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_SVID2))
585462306a36Sopenharmony_ci		pi->voltage_control = CISLANDS_VOLTAGE_CONTROL_BY_SVID2;
585562306a36Sopenharmony_ci
585662306a36Sopenharmony_ci	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_VDDCI_CONTROL) {
585762306a36Sopenharmony_ci		if (radeon_atom_is_voltage_gpio(rdev, VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT))
585862306a36Sopenharmony_ci			pi->vddci_control = CISLANDS_VOLTAGE_CONTROL_BY_GPIO;
585962306a36Sopenharmony_ci		else if (radeon_atom_is_voltage_gpio(rdev, VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_SVID2))
586062306a36Sopenharmony_ci			pi->vddci_control = CISLANDS_VOLTAGE_CONTROL_BY_SVID2;
586162306a36Sopenharmony_ci		else
586262306a36Sopenharmony_ci			rdev->pm.dpm.platform_caps &= ~ATOM_PP_PLATFORM_CAP_VDDCI_CONTROL;
586362306a36Sopenharmony_ci	}
586462306a36Sopenharmony_ci
586562306a36Sopenharmony_ci	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_MVDDCONTROL) {
586662306a36Sopenharmony_ci		if (radeon_atom_is_voltage_gpio(rdev, VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT))
586762306a36Sopenharmony_ci			pi->mvdd_control = CISLANDS_VOLTAGE_CONTROL_BY_GPIO;
586862306a36Sopenharmony_ci		else if (radeon_atom_is_voltage_gpio(rdev, VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_SVID2))
586962306a36Sopenharmony_ci			pi->mvdd_control = CISLANDS_VOLTAGE_CONTROL_BY_SVID2;
587062306a36Sopenharmony_ci		else
587162306a36Sopenharmony_ci			rdev->pm.dpm.platform_caps &= ~ATOM_PP_PLATFORM_CAP_MVDDCONTROL;
587262306a36Sopenharmony_ci	}
587362306a36Sopenharmony_ci
587462306a36Sopenharmony_ci	pi->vddc_phase_shed_control = true;
587562306a36Sopenharmony_ci
587662306a36Sopenharmony_ci#if defined(CONFIG_ACPI)
587762306a36Sopenharmony_ci	pi->pcie_performance_request =
587862306a36Sopenharmony_ci		radeon_acpi_is_pcie_performance_request_supported(rdev);
587962306a36Sopenharmony_ci#else
588062306a36Sopenharmony_ci	pi->pcie_performance_request = false;
588162306a36Sopenharmony_ci#endif
588262306a36Sopenharmony_ci
588362306a36Sopenharmony_ci	if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
588462306a36Sopenharmony_ci				   &frev, &crev, &data_offset)) {
588562306a36Sopenharmony_ci		pi->caps_sclk_ss_support = true;
588662306a36Sopenharmony_ci		pi->caps_mclk_ss_support = true;
588762306a36Sopenharmony_ci		pi->dynamic_ss = true;
588862306a36Sopenharmony_ci	} else {
588962306a36Sopenharmony_ci		pi->caps_sclk_ss_support = false;
589062306a36Sopenharmony_ci		pi->caps_mclk_ss_support = false;
589162306a36Sopenharmony_ci		pi->dynamic_ss = true;
589262306a36Sopenharmony_ci	}
589362306a36Sopenharmony_ci
589462306a36Sopenharmony_ci	if (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE)
589562306a36Sopenharmony_ci		pi->thermal_protection = true;
589662306a36Sopenharmony_ci	else
589762306a36Sopenharmony_ci		pi->thermal_protection = false;
589862306a36Sopenharmony_ci
589962306a36Sopenharmony_ci	pi->caps_dynamic_ac_timing = true;
590062306a36Sopenharmony_ci
590162306a36Sopenharmony_ci	pi->uvd_power_gated = false;
590262306a36Sopenharmony_ci
590362306a36Sopenharmony_ci	/* make sure dc limits are valid */
590462306a36Sopenharmony_ci	if ((rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.sclk == 0) ||
590562306a36Sopenharmony_ci	    (rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.mclk == 0))
590662306a36Sopenharmony_ci		rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc =
590762306a36Sopenharmony_ci			rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
590862306a36Sopenharmony_ci
590962306a36Sopenharmony_ci	pi->fan_ctrl_is_in_default_mode = true;
591062306a36Sopenharmony_ci
591162306a36Sopenharmony_ci	return 0;
591262306a36Sopenharmony_ci}
591362306a36Sopenharmony_ci
591462306a36Sopenharmony_civoid ci_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
591562306a36Sopenharmony_ci						    struct seq_file *m)
591662306a36Sopenharmony_ci{
591762306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
591862306a36Sopenharmony_ci	struct radeon_ps *rps = &pi->current_rps;
591962306a36Sopenharmony_ci	u32 sclk = ci_get_average_sclk_freq(rdev);
592062306a36Sopenharmony_ci	u32 mclk = ci_get_average_mclk_freq(rdev);
592162306a36Sopenharmony_ci
592262306a36Sopenharmony_ci	seq_printf(m, "uvd    %sabled\n", pi->uvd_enabled ? "en" : "dis");
592362306a36Sopenharmony_ci	seq_printf(m, "vce    %sabled\n", rps->vce_active ? "en" : "dis");
592462306a36Sopenharmony_ci	seq_printf(m, "power level avg    sclk: %u mclk: %u\n",
592562306a36Sopenharmony_ci		   sclk, mclk);
592662306a36Sopenharmony_ci}
592762306a36Sopenharmony_ci
592862306a36Sopenharmony_civoid ci_dpm_print_power_state(struct radeon_device *rdev,
592962306a36Sopenharmony_ci			      struct radeon_ps *rps)
593062306a36Sopenharmony_ci{
593162306a36Sopenharmony_ci	struct ci_ps *ps = ci_get_ps(rps);
593262306a36Sopenharmony_ci	struct ci_pl *pl;
593362306a36Sopenharmony_ci	int i;
593462306a36Sopenharmony_ci
593562306a36Sopenharmony_ci	r600_dpm_print_class_info(rps->class, rps->class2);
593662306a36Sopenharmony_ci	r600_dpm_print_cap_info(rps->caps);
593762306a36Sopenharmony_ci	printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
593862306a36Sopenharmony_ci	for (i = 0; i < ps->performance_level_count; i++) {
593962306a36Sopenharmony_ci		pl = &ps->performance_levels[i];
594062306a36Sopenharmony_ci		printk("\t\tpower level %d    sclk: %u mclk: %u pcie gen: %u pcie lanes: %u\n",
594162306a36Sopenharmony_ci		       i, pl->sclk, pl->mclk, pl->pcie_gen + 1, pl->pcie_lane);
594262306a36Sopenharmony_ci	}
594362306a36Sopenharmony_ci	r600_dpm_print_ps_status(rdev, rps);
594462306a36Sopenharmony_ci}
594562306a36Sopenharmony_ci
594662306a36Sopenharmony_ciu32 ci_dpm_get_current_sclk(struct radeon_device *rdev)
594762306a36Sopenharmony_ci{
594862306a36Sopenharmony_ci	u32 sclk = ci_get_average_sclk_freq(rdev);
594962306a36Sopenharmony_ci
595062306a36Sopenharmony_ci	return sclk;
595162306a36Sopenharmony_ci}
595262306a36Sopenharmony_ci
595362306a36Sopenharmony_ciu32 ci_dpm_get_current_mclk(struct radeon_device *rdev)
595462306a36Sopenharmony_ci{
595562306a36Sopenharmony_ci	u32 mclk = ci_get_average_mclk_freq(rdev);
595662306a36Sopenharmony_ci
595762306a36Sopenharmony_ci	return mclk;
595862306a36Sopenharmony_ci}
595962306a36Sopenharmony_ci
596062306a36Sopenharmony_ciu32 ci_dpm_get_sclk(struct radeon_device *rdev, bool low)
596162306a36Sopenharmony_ci{
596262306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
596362306a36Sopenharmony_ci	struct ci_ps *requested_state = ci_get_ps(&pi->requested_rps);
596462306a36Sopenharmony_ci
596562306a36Sopenharmony_ci	if (low)
596662306a36Sopenharmony_ci		return requested_state->performance_levels[0].sclk;
596762306a36Sopenharmony_ci	else
596862306a36Sopenharmony_ci		return requested_state->performance_levels[requested_state->performance_level_count - 1].sclk;
596962306a36Sopenharmony_ci}
597062306a36Sopenharmony_ci
597162306a36Sopenharmony_ciu32 ci_dpm_get_mclk(struct radeon_device *rdev, bool low)
597262306a36Sopenharmony_ci{
597362306a36Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
597462306a36Sopenharmony_ci	struct ci_ps *requested_state = ci_get_ps(&pi->requested_rps);
597562306a36Sopenharmony_ci
597662306a36Sopenharmony_ci	if (low)
597762306a36Sopenharmony_ci		return requested_state->performance_levels[0].mclk;
597862306a36Sopenharmony_ci	else
597962306a36Sopenharmony_ci		return requested_state->performance_levels[requested_state->performance_level_count - 1].mclk;
598062306a36Sopenharmony_ci}
5981