18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright 2013 Advanced Micro Devices, Inc.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation
78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
128c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
158c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
168c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
178c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
188c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
198c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
208c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci */
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include <linux/firmware.h>
258c2ecf20Sopenharmony_ci#include <linux/pci.h>
268c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#include "atom.h"
298c2ecf20Sopenharmony_ci#include "ci_dpm.h"
308c2ecf20Sopenharmony_ci#include "cikd.h"
318c2ecf20Sopenharmony_ci#include "r600_dpm.h"
328c2ecf20Sopenharmony_ci#include "radeon.h"
338c2ecf20Sopenharmony_ci#include "radeon_asic.h"
348c2ecf20Sopenharmony_ci#include "radeon_ucode.h"
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#define MC_CG_ARB_FREQ_F0           0x0a
378c2ecf20Sopenharmony_ci#define MC_CG_ARB_FREQ_F1           0x0b
388c2ecf20Sopenharmony_ci#define MC_CG_ARB_FREQ_F2           0x0c
398c2ecf20Sopenharmony_ci#define MC_CG_ARB_FREQ_F3           0x0d
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#define SMC_RAM_END 0x40000
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#define VOLTAGE_SCALE               4
448c2ecf20Sopenharmony_ci#define VOLTAGE_VID_OFFSET_SCALE1    625
458c2ecf20Sopenharmony_ci#define VOLTAGE_VID_OFFSET_SCALE2    100
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic const struct ci_pt_defaults defaults_hawaii_xt =
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	1, 0xF, 0xFD, 0x19, 5, 0x14, 0, 0xB0000,
508c2ecf20Sopenharmony_ci	{ 0x2E,  0x00,  0x00,  0x88,  0x00,  0x00,  0x72,  0x60,  0x51,  0xA7,  0x79,  0x6B,  0x90,  0xBD,  0x79  },
518c2ecf20Sopenharmony_ci	{ 0x217, 0x217, 0x217, 0x242, 0x242, 0x242, 0x269, 0x269, 0x269, 0x2A1, 0x2A1, 0x2A1, 0x2C9, 0x2C9, 0x2C9 }
528c2ecf20Sopenharmony_ci};
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic const struct ci_pt_defaults defaults_hawaii_pro =
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	1, 0xF, 0xFD, 0x19, 5, 0x14, 0, 0x65062,
578c2ecf20Sopenharmony_ci	{ 0x2E,  0x00,  0x00,  0x88,  0x00,  0x00,  0x72,  0x60,  0x51,  0xA7,  0x79,  0x6B,  0x90,  0xBD,  0x79  },
588c2ecf20Sopenharmony_ci	{ 0x217, 0x217, 0x217, 0x242, 0x242, 0x242, 0x269, 0x269, 0x269, 0x2A1, 0x2A1, 0x2A1, 0x2C9, 0x2C9, 0x2C9 }
598c2ecf20Sopenharmony_ci};
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic const struct ci_pt_defaults defaults_bonaire_xt =
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	1, 0xF, 0xFD, 0x19, 5, 45, 0, 0xB0000,
648c2ecf20Sopenharmony_ci	{ 0x79,  0x253, 0x25D, 0xAE,  0x72,  0x80,  0x83,  0x86,  0x6F,  0xC8,  0xC9,  0xC9,  0x2F,  0x4D,  0x61  },
658c2ecf20Sopenharmony_ci	{ 0x17C, 0x172, 0x180, 0x1BC, 0x1B3, 0x1BD, 0x206, 0x200, 0x203, 0x25D, 0x25A, 0x255, 0x2C3, 0x2C5, 0x2B4 }
668c2ecf20Sopenharmony_ci};
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistatic const struct ci_pt_defaults defaults_saturn_xt =
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	1, 0xF, 0xFD, 0x19, 5, 55, 0, 0x70000,
718c2ecf20Sopenharmony_ci	{ 0x8C,  0x247, 0x249, 0xA6,  0x80,  0x81,  0x8B,  0x89,  0x86,  0xC9,  0xCA,  0xC9,  0x4D,  0x4D,  0x4D  },
728c2ecf20Sopenharmony_ci	{ 0x187, 0x187, 0x187, 0x1C7, 0x1C7, 0x1C7, 0x210, 0x210, 0x210, 0x266, 0x266, 0x266, 0x2C9, 0x2C9, 0x2C9 }
738c2ecf20Sopenharmony_ci};
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic const struct ci_pt_config_reg didt_config_ci[] =
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	{ 0x10, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
788c2ecf20Sopenharmony_ci	{ 0x10, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
798c2ecf20Sopenharmony_ci	{ 0x10, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
808c2ecf20Sopenharmony_ci	{ 0x10, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
818c2ecf20Sopenharmony_ci	{ 0x11, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
828c2ecf20Sopenharmony_ci	{ 0x11, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
838c2ecf20Sopenharmony_ci	{ 0x11, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
848c2ecf20Sopenharmony_ci	{ 0x11, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
858c2ecf20Sopenharmony_ci	{ 0x12, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
868c2ecf20Sopenharmony_ci	{ 0x12, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
878c2ecf20Sopenharmony_ci	{ 0x12, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
888c2ecf20Sopenharmony_ci	{ 0x12, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
898c2ecf20Sopenharmony_ci	{ 0x2, 0x00003fff, 0, 0x4, CISLANDS_CONFIGREG_DIDT_IND },
908c2ecf20Sopenharmony_ci	{ 0x2, 0x03ff0000, 16, 0x80, CISLANDS_CONFIGREG_DIDT_IND },
918c2ecf20Sopenharmony_ci	{ 0x2, 0x78000000, 27, 0x3, CISLANDS_CONFIGREG_DIDT_IND },
928c2ecf20Sopenharmony_ci	{ 0x1, 0x0000ffff, 0, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
938c2ecf20Sopenharmony_ci	{ 0x1, 0xffff0000, 16, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
948c2ecf20Sopenharmony_ci	{ 0x0, 0x00000001, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
958c2ecf20Sopenharmony_ci	{ 0x30, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
968c2ecf20Sopenharmony_ci	{ 0x30, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
978c2ecf20Sopenharmony_ci	{ 0x30, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
988c2ecf20Sopenharmony_ci	{ 0x30, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
998c2ecf20Sopenharmony_ci	{ 0x31, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1008c2ecf20Sopenharmony_ci	{ 0x31, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1018c2ecf20Sopenharmony_ci	{ 0x31, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1028c2ecf20Sopenharmony_ci	{ 0x31, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1038c2ecf20Sopenharmony_ci	{ 0x32, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1048c2ecf20Sopenharmony_ci	{ 0x32, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1058c2ecf20Sopenharmony_ci	{ 0x32, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1068c2ecf20Sopenharmony_ci	{ 0x32, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1078c2ecf20Sopenharmony_ci	{ 0x22, 0x00003fff, 0, 0x4, CISLANDS_CONFIGREG_DIDT_IND },
1088c2ecf20Sopenharmony_ci	{ 0x22, 0x03ff0000, 16, 0x80, CISLANDS_CONFIGREG_DIDT_IND },
1098c2ecf20Sopenharmony_ci	{ 0x22, 0x78000000, 27, 0x3, CISLANDS_CONFIGREG_DIDT_IND },
1108c2ecf20Sopenharmony_ci	{ 0x21, 0x0000ffff, 0, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
1118c2ecf20Sopenharmony_ci	{ 0x21, 0xffff0000, 16, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
1128c2ecf20Sopenharmony_ci	{ 0x20, 0x00000001, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1138c2ecf20Sopenharmony_ci	{ 0x50, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1148c2ecf20Sopenharmony_ci	{ 0x50, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1158c2ecf20Sopenharmony_ci	{ 0x50, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1168c2ecf20Sopenharmony_ci	{ 0x50, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1178c2ecf20Sopenharmony_ci	{ 0x51, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1188c2ecf20Sopenharmony_ci	{ 0x51, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1198c2ecf20Sopenharmony_ci	{ 0x51, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1208c2ecf20Sopenharmony_ci	{ 0x51, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1218c2ecf20Sopenharmony_ci	{ 0x52, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1228c2ecf20Sopenharmony_ci	{ 0x52, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1238c2ecf20Sopenharmony_ci	{ 0x52, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1248c2ecf20Sopenharmony_ci	{ 0x52, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1258c2ecf20Sopenharmony_ci	{ 0x42, 0x00003fff, 0, 0x4, CISLANDS_CONFIGREG_DIDT_IND },
1268c2ecf20Sopenharmony_ci	{ 0x42, 0x03ff0000, 16, 0x80, CISLANDS_CONFIGREG_DIDT_IND },
1278c2ecf20Sopenharmony_ci	{ 0x42, 0x78000000, 27, 0x3, CISLANDS_CONFIGREG_DIDT_IND },
1288c2ecf20Sopenharmony_ci	{ 0x41, 0x0000ffff, 0, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
1298c2ecf20Sopenharmony_ci	{ 0x41, 0xffff0000, 16, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
1308c2ecf20Sopenharmony_ci	{ 0x40, 0x00000001, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1318c2ecf20Sopenharmony_ci	{ 0x70, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1328c2ecf20Sopenharmony_ci	{ 0x70, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1338c2ecf20Sopenharmony_ci	{ 0x70, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1348c2ecf20Sopenharmony_ci	{ 0x70, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1358c2ecf20Sopenharmony_ci	{ 0x71, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1368c2ecf20Sopenharmony_ci	{ 0x71, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1378c2ecf20Sopenharmony_ci	{ 0x71, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1388c2ecf20Sopenharmony_ci	{ 0x71, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1398c2ecf20Sopenharmony_ci	{ 0x72, 0x000000ff, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1408c2ecf20Sopenharmony_ci	{ 0x72, 0x0000ff00, 8, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1418c2ecf20Sopenharmony_ci	{ 0x72, 0x00ff0000, 16, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1428c2ecf20Sopenharmony_ci	{ 0x72, 0xff000000, 24, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1438c2ecf20Sopenharmony_ci	{ 0x62, 0x00003fff, 0, 0x4, CISLANDS_CONFIGREG_DIDT_IND },
1448c2ecf20Sopenharmony_ci	{ 0x62, 0x03ff0000, 16, 0x80, CISLANDS_CONFIGREG_DIDT_IND },
1458c2ecf20Sopenharmony_ci	{ 0x62, 0x78000000, 27, 0x3, CISLANDS_CONFIGREG_DIDT_IND },
1468c2ecf20Sopenharmony_ci	{ 0x61, 0x0000ffff, 0, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
1478c2ecf20Sopenharmony_ci	{ 0x61, 0xffff0000, 16, 0x3FFF, CISLANDS_CONFIGREG_DIDT_IND },
1488c2ecf20Sopenharmony_ci	{ 0x60, 0x00000001, 0, 0x0, CISLANDS_CONFIGREG_DIDT_IND },
1498c2ecf20Sopenharmony_ci	{ 0xFFFFFFFF }
1508c2ecf20Sopenharmony_ci};
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ciextern u8 rv770_get_memory_module_index(struct radeon_device *rdev);
1538c2ecf20Sopenharmony_ciextern int ni_copy_and_switch_arb_sets(struct radeon_device *rdev,
1548c2ecf20Sopenharmony_ci				       u32 arb_freq_src, u32 arb_freq_dest);
1558c2ecf20Sopenharmony_ciextern u8 si_get_ddr3_mclk_frequency_ratio(u32 memory_clock);
1568c2ecf20Sopenharmony_ciextern u8 si_get_mclk_frequency_ratio(u32 memory_clock, bool strobe_mode);
1578c2ecf20Sopenharmony_ciextern void si_trim_voltage_table_to_fit_state_table(struct radeon_device *rdev,
1588c2ecf20Sopenharmony_ci						     u32 max_voltage_steps,
1598c2ecf20Sopenharmony_ci						     struct atom_voltage_table *voltage_table);
1608c2ecf20Sopenharmony_ciextern void cik_enter_rlc_safe_mode(struct radeon_device *rdev);
1618c2ecf20Sopenharmony_ciextern void cik_exit_rlc_safe_mode(struct radeon_device *rdev);
1628c2ecf20Sopenharmony_ciextern int ci_mc_load_microcode(struct radeon_device *rdev);
1638c2ecf20Sopenharmony_ciextern void cik_update_cg(struct radeon_device *rdev,
1648c2ecf20Sopenharmony_ci			  u32 block, bool enable);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic int ci_get_std_voltage_value_sidd(struct radeon_device *rdev,
1678c2ecf20Sopenharmony_ci					 struct atom_voltage_table_entry *voltage_table,
1688c2ecf20Sopenharmony_ci					 u16 *std_voltage_hi_sidd, u16 *std_voltage_lo_sidd);
1698c2ecf20Sopenharmony_cistatic int ci_set_power_limit(struct radeon_device *rdev, u32 n);
1708c2ecf20Sopenharmony_cistatic int ci_set_overdrive_target_tdp(struct radeon_device *rdev,
1718c2ecf20Sopenharmony_ci				       u32 target_tdp);
1728c2ecf20Sopenharmony_cistatic int ci_update_uvd_dpm(struct radeon_device *rdev, bool gate);
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic PPSMC_Result ci_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg);
1758c2ecf20Sopenharmony_cistatic PPSMC_Result ci_send_msg_to_smc_with_parameter(struct radeon_device *rdev,
1768c2ecf20Sopenharmony_ci						      PPSMC_Msg msg, u32 parameter);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic void ci_thermal_start_smc_fan_control(struct radeon_device *rdev);
1798c2ecf20Sopenharmony_cistatic void ci_fan_ctrl_set_default_mode(struct radeon_device *rdev);
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic struct ci_power_info *ci_get_pi(struct radeon_device *rdev)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	struct ci_power_info *pi = rdev->pm.dpm.priv;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	return pi;
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistatic struct ci_ps *ci_get_ps(struct radeon_ps *rps)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	struct ci_ps *ps = rps->ps_priv;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	return ps;
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic void ci_initialize_powertune_defaults(struct radeon_device *rdev)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	switch (rdev->pdev->device) {
2008c2ecf20Sopenharmony_ci	case 0x6649:
2018c2ecf20Sopenharmony_ci	case 0x6650:
2028c2ecf20Sopenharmony_ci	case 0x6651:
2038c2ecf20Sopenharmony_ci	case 0x6658:
2048c2ecf20Sopenharmony_ci	case 0x665C:
2058c2ecf20Sopenharmony_ci	case 0x665D:
2068c2ecf20Sopenharmony_ci	default:
2078c2ecf20Sopenharmony_ci		pi->powertune_defaults = &defaults_bonaire_xt;
2088c2ecf20Sopenharmony_ci		break;
2098c2ecf20Sopenharmony_ci	case 0x6640:
2108c2ecf20Sopenharmony_ci	case 0x6641:
2118c2ecf20Sopenharmony_ci	case 0x6646:
2128c2ecf20Sopenharmony_ci	case 0x6647:
2138c2ecf20Sopenharmony_ci		pi->powertune_defaults = &defaults_saturn_xt;
2148c2ecf20Sopenharmony_ci		break;
2158c2ecf20Sopenharmony_ci	case 0x67B8:
2168c2ecf20Sopenharmony_ci	case 0x67B0:
2178c2ecf20Sopenharmony_ci		pi->powertune_defaults = &defaults_hawaii_xt;
2188c2ecf20Sopenharmony_ci		break;
2198c2ecf20Sopenharmony_ci	case 0x67BA:
2208c2ecf20Sopenharmony_ci	case 0x67B1:
2218c2ecf20Sopenharmony_ci		pi->powertune_defaults = &defaults_hawaii_pro;
2228c2ecf20Sopenharmony_ci		break;
2238c2ecf20Sopenharmony_ci	case 0x67A0:
2248c2ecf20Sopenharmony_ci	case 0x67A1:
2258c2ecf20Sopenharmony_ci	case 0x67A2:
2268c2ecf20Sopenharmony_ci	case 0x67A8:
2278c2ecf20Sopenharmony_ci	case 0x67A9:
2288c2ecf20Sopenharmony_ci	case 0x67AA:
2298c2ecf20Sopenharmony_ci	case 0x67B9:
2308c2ecf20Sopenharmony_ci	case 0x67BE:
2318c2ecf20Sopenharmony_ci		pi->powertune_defaults = &defaults_bonaire_xt;
2328c2ecf20Sopenharmony_ci		break;
2338c2ecf20Sopenharmony_ci	}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	pi->dte_tj_offset = 0;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	pi->caps_power_containment = true;
2388c2ecf20Sopenharmony_ci	pi->caps_cac = false;
2398c2ecf20Sopenharmony_ci	pi->caps_sq_ramping = false;
2408c2ecf20Sopenharmony_ci	pi->caps_db_ramping = false;
2418c2ecf20Sopenharmony_ci	pi->caps_td_ramping = false;
2428c2ecf20Sopenharmony_ci	pi->caps_tcp_ramping = false;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	if (pi->caps_power_containment) {
2458c2ecf20Sopenharmony_ci		pi->caps_cac = true;
2468c2ecf20Sopenharmony_ci		if (rdev->family == CHIP_HAWAII)
2478c2ecf20Sopenharmony_ci			pi->enable_bapm_feature = false;
2488c2ecf20Sopenharmony_ci		else
2498c2ecf20Sopenharmony_ci			pi->enable_bapm_feature = true;
2508c2ecf20Sopenharmony_ci		pi->enable_tdc_limit_feature = true;
2518c2ecf20Sopenharmony_ci		pi->enable_pkg_pwr_tracking_feature = true;
2528c2ecf20Sopenharmony_ci	}
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_cistatic u8 ci_convert_to_vid(u16 vddc)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	return (6200 - (vddc * VOLTAGE_SCALE)) / 25;
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_cistatic int ci_populate_bapm_vddc_vid_sidd(struct radeon_device *rdev)
2618c2ecf20Sopenharmony_ci{
2628c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
2638c2ecf20Sopenharmony_ci	u8 *hi_vid = pi->smc_powertune_table.BapmVddCVidHiSidd;
2648c2ecf20Sopenharmony_ci	u8 *lo_vid = pi->smc_powertune_table.BapmVddCVidLoSidd;
2658c2ecf20Sopenharmony_ci	u8 *hi2_vid = pi->smc_powertune_table.BapmVddCVidHiSidd2;
2668c2ecf20Sopenharmony_ci	u32 i;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	if (rdev->pm.dpm.dyn_state.cac_leakage_table.entries == NULL)
2698c2ecf20Sopenharmony_ci		return -EINVAL;
2708c2ecf20Sopenharmony_ci	if (rdev->pm.dpm.dyn_state.cac_leakage_table.count > 8)
2718c2ecf20Sopenharmony_ci		return -EINVAL;
2728c2ecf20Sopenharmony_ci	if (rdev->pm.dpm.dyn_state.cac_leakage_table.count !=
2738c2ecf20Sopenharmony_ci	    rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count)
2748c2ecf20Sopenharmony_ci		return -EINVAL;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	for (i = 0; i < rdev->pm.dpm.dyn_state.cac_leakage_table.count; i++) {
2778c2ecf20Sopenharmony_ci		if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_EVV) {
2788c2ecf20Sopenharmony_ci			lo_vid[i] = ci_convert_to_vid(rdev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc1);
2798c2ecf20Sopenharmony_ci			hi_vid[i] = ci_convert_to_vid(rdev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc2);
2808c2ecf20Sopenharmony_ci			hi2_vid[i] = ci_convert_to_vid(rdev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc3);
2818c2ecf20Sopenharmony_ci		} else {
2828c2ecf20Sopenharmony_ci			lo_vid[i] = ci_convert_to_vid(rdev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc);
2838c2ecf20Sopenharmony_ci			hi_vid[i] = ci_convert_to_vid((u16)rdev->pm.dpm.dyn_state.cac_leakage_table.entries[i].leakage);
2848c2ecf20Sopenharmony_ci		}
2858c2ecf20Sopenharmony_ci	}
2868c2ecf20Sopenharmony_ci	return 0;
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_cistatic int ci_populate_vddc_vid(struct radeon_device *rdev)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
2928c2ecf20Sopenharmony_ci	u8 *vid = pi->smc_powertune_table.VddCVid;
2938c2ecf20Sopenharmony_ci	u32 i;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	if (pi->vddc_voltage_table.count > 8)
2968c2ecf20Sopenharmony_ci		return -EINVAL;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	for (i = 0; i < pi->vddc_voltage_table.count; i++)
2998c2ecf20Sopenharmony_ci		vid[i] = ci_convert_to_vid(pi->vddc_voltage_table.entries[i].value);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	return 0;
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cistatic int ci_populate_svi_load_line(struct radeon_device *rdev)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
3078c2ecf20Sopenharmony_ci	const struct ci_pt_defaults *pt_defaults = pi->powertune_defaults;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	pi->smc_powertune_table.SviLoadLineEn = pt_defaults->svi_load_line_en;
3108c2ecf20Sopenharmony_ci	pi->smc_powertune_table.SviLoadLineVddC = pt_defaults->svi_load_line_vddc;
3118c2ecf20Sopenharmony_ci	pi->smc_powertune_table.SviLoadLineTrimVddC = 3;
3128c2ecf20Sopenharmony_ci	pi->smc_powertune_table.SviLoadLineOffsetVddC = 0;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	return 0;
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_cistatic int ci_populate_tdc_limit(struct radeon_device *rdev)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
3208c2ecf20Sopenharmony_ci	const struct ci_pt_defaults *pt_defaults = pi->powertune_defaults;
3218c2ecf20Sopenharmony_ci	u16 tdc_limit;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	tdc_limit = rdev->pm.dpm.dyn_state.cac_tdp_table->tdc * 256;
3248c2ecf20Sopenharmony_ci	pi->smc_powertune_table.TDC_VDDC_PkgLimit = cpu_to_be16(tdc_limit);
3258c2ecf20Sopenharmony_ci	pi->smc_powertune_table.TDC_VDDC_ThrottleReleaseLimitPerc =
3268c2ecf20Sopenharmony_ci		pt_defaults->tdc_vddc_throttle_release_limit_perc;
3278c2ecf20Sopenharmony_ci	pi->smc_powertune_table.TDC_MAWt = pt_defaults->tdc_mawt;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	return 0;
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_cistatic int ci_populate_dw8(struct radeon_device *rdev)
3338c2ecf20Sopenharmony_ci{
3348c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
3358c2ecf20Sopenharmony_ci	const struct ci_pt_defaults *pt_defaults = pi->powertune_defaults;
3368c2ecf20Sopenharmony_ci	int ret;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	ret = ci_read_smc_sram_dword(rdev,
3398c2ecf20Sopenharmony_ci				     SMU7_FIRMWARE_HEADER_LOCATION +
3408c2ecf20Sopenharmony_ci				     offsetof(SMU7_Firmware_Header, PmFuseTable) +
3418c2ecf20Sopenharmony_ci				     offsetof(SMU7_Discrete_PmFuses, TdcWaterfallCtl),
3428c2ecf20Sopenharmony_ci				     (u32 *)&pi->smc_powertune_table.TdcWaterfallCtl,
3438c2ecf20Sopenharmony_ci				     pi->sram_end);
3448c2ecf20Sopenharmony_ci	if (ret)
3458c2ecf20Sopenharmony_ci		return -EINVAL;
3468c2ecf20Sopenharmony_ci	else
3478c2ecf20Sopenharmony_ci		pi->smc_powertune_table.TdcWaterfallCtl = pt_defaults->tdc_waterfall_ctl;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	return 0;
3508c2ecf20Sopenharmony_ci}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_cistatic int ci_populate_fuzzy_fan(struct radeon_device *rdev)
3538c2ecf20Sopenharmony_ci{
3548c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	if ((rdev->pm.dpm.fan.fan_output_sensitivity & (1 << 15)) ||
3578c2ecf20Sopenharmony_ci	    (rdev->pm.dpm.fan.fan_output_sensitivity == 0))
3588c2ecf20Sopenharmony_ci		rdev->pm.dpm.fan.fan_output_sensitivity =
3598c2ecf20Sopenharmony_ci			rdev->pm.dpm.fan.default_fan_output_sensitivity;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	pi->smc_powertune_table.FuzzyFan_PwmSetDelta =
3628c2ecf20Sopenharmony_ci		cpu_to_be16(rdev->pm.dpm.fan.fan_output_sensitivity);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	return 0;
3658c2ecf20Sopenharmony_ci}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_cistatic int ci_min_max_v_gnbl_pm_lid_from_bapm_vddc(struct radeon_device *rdev)
3688c2ecf20Sopenharmony_ci{
3698c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
3708c2ecf20Sopenharmony_ci	u8 *hi_vid = pi->smc_powertune_table.BapmVddCVidHiSidd;
3718c2ecf20Sopenharmony_ci	u8 *lo_vid = pi->smc_powertune_table.BapmVddCVidLoSidd;
3728c2ecf20Sopenharmony_ci	int i, min, max;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	min = max = hi_vid[0];
3758c2ecf20Sopenharmony_ci	for (i = 0; i < 8; i++) {
3768c2ecf20Sopenharmony_ci		if (0 != hi_vid[i]) {
3778c2ecf20Sopenharmony_ci			if (min > hi_vid[i])
3788c2ecf20Sopenharmony_ci				min = hi_vid[i];
3798c2ecf20Sopenharmony_ci			if (max < hi_vid[i])
3808c2ecf20Sopenharmony_ci				max = hi_vid[i];
3818c2ecf20Sopenharmony_ci		}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci		if (0 != lo_vid[i]) {
3848c2ecf20Sopenharmony_ci			if (min > lo_vid[i])
3858c2ecf20Sopenharmony_ci				min = lo_vid[i];
3868c2ecf20Sopenharmony_ci			if (max < lo_vid[i])
3878c2ecf20Sopenharmony_ci				max = lo_vid[i];
3888c2ecf20Sopenharmony_ci		}
3898c2ecf20Sopenharmony_ci	}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	if ((min == 0) || (max == 0))
3928c2ecf20Sopenharmony_ci		return -EINVAL;
3938c2ecf20Sopenharmony_ci	pi->smc_powertune_table.GnbLPMLMaxVid = (u8)max;
3948c2ecf20Sopenharmony_ci	pi->smc_powertune_table.GnbLPMLMinVid = (u8)min;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	return 0;
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic int ci_populate_bapm_vddc_base_leakage_sidd(struct radeon_device *rdev)
4008c2ecf20Sopenharmony_ci{
4018c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
4028c2ecf20Sopenharmony_ci	u16 hi_sidd = pi->smc_powertune_table.BapmVddCBaseLeakageHiSidd;
4038c2ecf20Sopenharmony_ci	u16 lo_sidd = pi->smc_powertune_table.BapmVddCBaseLeakageLoSidd;
4048c2ecf20Sopenharmony_ci	struct radeon_cac_tdp_table *cac_tdp_table =
4058c2ecf20Sopenharmony_ci		rdev->pm.dpm.dyn_state.cac_tdp_table;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	hi_sidd = cac_tdp_table->high_cac_leakage / 100 * 256;
4088c2ecf20Sopenharmony_ci	lo_sidd = cac_tdp_table->low_cac_leakage / 100 * 256;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	pi->smc_powertune_table.BapmVddCBaseLeakageHiSidd = cpu_to_be16(hi_sidd);
4118c2ecf20Sopenharmony_ci	pi->smc_powertune_table.BapmVddCBaseLeakageLoSidd = cpu_to_be16(lo_sidd);
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	return 0;
4148c2ecf20Sopenharmony_ci}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_cistatic int ci_populate_bapm_parameters_in_dpm_table(struct radeon_device *rdev)
4178c2ecf20Sopenharmony_ci{
4188c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
4198c2ecf20Sopenharmony_ci	const struct ci_pt_defaults *pt_defaults = pi->powertune_defaults;
4208c2ecf20Sopenharmony_ci	SMU7_Discrete_DpmTable  *dpm_table = &pi->smc_state_table;
4218c2ecf20Sopenharmony_ci	struct radeon_cac_tdp_table *cac_tdp_table =
4228c2ecf20Sopenharmony_ci		rdev->pm.dpm.dyn_state.cac_tdp_table;
4238c2ecf20Sopenharmony_ci	struct radeon_ppm_table *ppm = rdev->pm.dpm.dyn_state.ppm_table;
4248c2ecf20Sopenharmony_ci	int i, j, k;
4258c2ecf20Sopenharmony_ci	const u16 *def1;
4268c2ecf20Sopenharmony_ci	const u16 *def2;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	dpm_table->DefaultTdp = cac_tdp_table->tdp * 256;
4298c2ecf20Sopenharmony_ci	dpm_table->TargetTdp = cac_tdp_table->configurable_tdp * 256;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	dpm_table->DTETjOffset = (u8)pi->dte_tj_offset;
4328c2ecf20Sopenharmony_ci	dpm_table->GpuTjMax =
4338c2ecf20Sopenharmony_ci		(u8)(pi->thermal_temp_setting.temperature_high / 1000);
4348c2ecf20Sopenharmony_ci	dpm_table->GpuTjHyst = 8;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	dpm_table->DTEAmbientTempBase = pt_defaults->dte_ambient_temp_base;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	if (ppm) {
4398c2ecf20Sopenharmony_ci		dpm_table->PPM_PkgPwrLimit = cpu_to_be16((u16)ppm->dgpu_tdp * 256 / 1000);
4408c2ecf20Sopenharmony_ci		dpm_table->PPM_TemperatureLimit = cpu_to_be16((u16)ppm->tj_max * 256);
4418c2ecf20Sopenharmony_ci	} else {
4428c2ecf20Sopenharmony_ci		dpm_table->PPM_PkgPwrLimit = cpu_to_be16(0);
4438c2ecf20Sopenharmony_ci		dpm_table->PPM_TemperatureLimit = cpu_to_be16(0);
4448c2ecf20Sopenharmony_ci	}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	dpm_table->BAPM_TEMP_GRADIENT = cpu_to_be32(pt_defaults->bapm_temp_gradient);
4478c2ecf20Sopenharmony_ci	def1 = pt_defaults->bapmti_r;
4488c2ecf20Sopenharmony_ci	def2 = pt_defaults->bapmti_rc;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	for (i = 0; i < SMU7_DTE_ITERATIONS; i++) {
4518c2ecf20Sopenharmony_ci		for (j = 0; j < SMU7_DTE_SOURCES; j++) {
4528c2ecf20Sopenharmony_ci			for (k = 0; k < SMU7_DTE_SINKS; k++) {
4538c2ecf20Sopenharmony_ci				dpm_table->BAPMTI_R[i][j][k] = cpu_to_be16(*def1);
4548c2ecf20Sopenharmony_ci				dpm_table->BAPMTI_RC[i][j][k] = cpu_to_be16(*def2);
4558c2ecf20Sopenharmony_ci				def1++;
4568c2ecf20Sopenharmony_ci				def2++;
4578c2ecf20Sopenharmony_ci			}
4588c2ecf20Sopenharmony_ci		}
4598c2ecf20Sopenharmony_ci	}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	return 0;
4628c2ecf20Sopenharmony_ci}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_cistatic int ci_populate_pm_base(struct radeon_device *rdev)
4658c2ecf20Sopenharmony_ci{
4668c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
4678c2ecf20Sopenharmony_ci	u32 pm_fuse_table_offset;
4688c2ecf20Sopenharmony_ci	int ret;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	if (pi->caps_power_containment) {
4718c2ecf20Sopenharmony_ci		ret = ci_read_smc_sram_dword(rdev,
4728c2ecf20Sopenharmony_ci					     SMU7_FIRMWARE_HEADER_LOCATION +
4738c2ecf20Sopenharmony_ci					     offsetof(SMU7_Firmware_Header, PmFuseTable),
4748c2ecf20Sopenharmony_ci					     &pm_fuse_table_offset, pi->sram_end);
4758c2ecf20Sopenharmony_ci		if (ret)
4768c2ecf20Sopenharmony_ci			return ret;
4778c2ecf20Sopenharmony_ci		ret = ci_populate_bapm_vddc_vid_sidd(rdev);
4788c2ecf20Sopenharmony_ci		if (ret)
4798c2ecf20Sopenharmony_ci			return ret;
4808c2ecf20Sopenharmony_ci		ret = ci_populate_vddc_vid(rdev);
4818c2ecf20Sopenharmony_ci		if (ret)
4828c2ecf20Sopenharmony_ci			return ret;
4838c2ecf20Sopenharmony_ci		ret = ci_populate_svi_load_line(rdev);
4848c2ecf20Sopenharmony_ci		if (ret)
4858c2ecf20Sopenharmony_ci			return ret;
4868c2ecf20Sopenharmony_ci		ret = ci_populate_tdc_limit(rdev);
4878c2ecf20Sopenharmony_ci		if (ret)
4888c2ecf20Sopenharmony_ci			return ret;
4898c2ecf20Sopenharmony_ci		ret = ci_populate_dw8(rdev);
4908c2ecf20Sopenharmony_ci		if (ret)
4918c2ecf20Sopenharmony_ci			return ret;
4928c2ecf20Sopenharmony_ci		ret = ci_populate_fuzzy_fan(rdev);
4938c2ecf20Sopenharmony_ci		if (ret)
4948c2ecf20Sopenharmony_ci			return ret;
4958c2ecf20Sopenharmony_ci		ret = ci_min_max_v_gnbl_pm_lid_from_bapm_vddc(rdev);
4968c2ecf20Sopenharmony_ci		if (ret)
4978c2ecf20Sopenharmony_ci			return ret;
4988c2ecf20Sopenharmony_ci		ret = ci_populate_bapm_vddc_base_leakage_sidd(rdev);
4998c2ecf20Sopenharmony_ci		if (ret)
5008c2ecf20Sopenharmony_ci			return ret;
5018c2ecf20Sopenharmony_ci		ret = ci_copy_bytes_to_smc(rdev, pm_fuse_table_offset,
5028c2ecf20Sopenharmony_ci					   (u8 *)&pi->smc_powertune_table,
5038c2ecf20Sopenharmony_ci					   sizeof(SMU7_Discrete_PmFuses), pi->sram_end);
5048c2ecf20Sopenharmony_ci		if (ret)
5058c2ecf20Sopenharmony_ci			return ret;
5068c2ecf20Sopenharmony_ci	}
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	return 0;
5098c2ecf20Sopenharmony_ci}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_cistatic void ci_do_enable_didt(struct radeon_device *rdev, const bool enable)
5128c2ecf20Sopenharmony_ci{
5138c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
5148c2ecf20Sopenharmony_ci	u32 data;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	if (pi->caps_sq_ramping) {
5178c2ecf20Sopenharmony_ci		data = RREG32_DIDT(DIDT_SQ_CTRL0);
5188c2ecf20Sopenharmony_ci		if (enable)
5198c2ecf20Sopenharmony_ci			data |= DIDT_CTRL_EN;
5208c2ecf20Sopenharmony_ci		else
5218c2ecf20Sopenharmony_ci			data &= ~DIDT_CTRL_EN;
5228c2ecf20Sopenharmony_ci		WREG32_DIDT(DIDT_SQ_CTRL0, data);
5238c2ecf20Sopenharmony_ci	}
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	if (pi->caps_db_ramping) {
5268c2ecf20Sopenharmony_ci		data = RREG32_DIDT(DIDT_DB_CTRL0);
5278c2ecf20Sopenharmony_ci		if (enable)
5288c2ecf20Sopenharmony_ci			data |= DIDT_CTRL_EN;
5298c2ecf20Sopenharmony_ci		else
5308c2ecf20Sopenharmony_ci			data &= ~DIDT_CTRL_EN;
5318c2ecf20Sopenharmony_ci		WREG32_DIDT(DIDT_DB_CTRL0, data);
5328c2ecf20Sopenharmony_ci	}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	if (pi->caps_td_ramping) {
5358c2ecf20Sopenharmony_ci		data = RREG32_DIDT(DIDT_TD_CTRL0);
5368c2ecf20Sopenharmony_ci		if (enable)
5378c2ecf20Sopenharmony_ci			data |= DIDT_CTRL_EN;
5388c2ecf20Sopenharmony_ci		else
5398c2ecf20Sopenharmony_ci			data &= ~DIDT_CTRL_EN;
5408c2ecf20Sopenharmony_ci		WREG32_DIDT(DIDT_TD_CTRL0, data);
5418c2ecf20Sopenharmony_ci	}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	if (pi->caps_tcp_ramping) {
5448c2ecf20Sopenharmony_ci		data = RREG32_DIDT(DIDT_TCP_CTRL0);
5458c2ecf20Sopenharmony_ci		if (enable)
5468c2ecf20Sopenharmony_ci			data |= DIDT_CTRL_EN;
5478c2ecf20Sopenharmony_ci		else
5488c2ecf20Sopenharmony_ci			data &= ~DIDT_CTRL_EN;
5498c2ecf20Sopenharmony_ci		WREG32_DIDT(DIDT_TCP_CTRL0, data);
5508c2ecf20Sopenharmony_ci	}
5518c2ecf20Sopenharmony_ci}
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_cistatic int ci_program_pt_config_registers(struct radeon_device *rdev,
5548c2ecf20Sopenharmony_ci					  const struct ci_pt_config_reg *cac_config_regs)
5558c2ecf20Sopenharmony_ci{
5568c2ecf20Sopenharmony_ci	const struct ci_pt_config_reg *config_regs = cac_config_regs;
5578c2ecf20Sopenharmony_ci	u32 data;
5588c2ecf20Sopenharmony_ci	u32 cache = 0;
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	if (config_regs == NULL)
5618c2ecf20Sopenharmony_ci		return -EINVAL;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	while (config_regs->offset != 0xFFFFFFFF) {
5648c2ecf20Sopenharmony_ci		if (config_regs->type == CISLANDS_CONFIGREG_CACHE) {
5658c2ecf20Sopenharmony_ci			cache |= ((config_regs->value << config_regs->shift) & config_regs->mask);
5668c2ecf20Sopenharmony_ci		} else {
5678c2ecf20Sopenharmony_ci			switch (config_regs->type) {
5688c2ecf20Sopenharmony_ci			case CISLANDS_CONFIGREG_SMC_IND:
5698c2ecf20Sopenharmony_ci				data = RREG32_SMC(config_regs->offset);
5708c2ecf20Sopenharmony_ci				break;
5718c2ecf20Sopenharmony_ci			case CISLANDS_CONFIGREG_DIDT_IND:
5728c2ecf20Sopenharmony_ci				data = RREG32_DIDT(config_regs->offset);
5738c2ecf20Sopenharmony_ci				break;
5748c2ecf20Sopenharmony_ci			default:
5758c2ecf20Sopenharmony_ci				data = RREG32(config_regs->offset << 2);
5768c2ecf20Sopenharmony_ci				break;
5778c2ecf20Sopenharmony_ci			}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci			data &= ~config_regs->mask;
5808c2ecf20Sopenharmony_ci			data |= ((config_regs->value << config_regs->shift) & config_regs->mask);
5818c2ecf20Sopenharmony_ci			data |= cache;
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci			switch (config_regs->type) {
5848c2ecf20Sopenharmony_ci			case CISLANDS_CONFIGREG_SMC_IND:
5858c2ecf20Sopenharmony_ci				WREG32_SMC(config_regs->offset, data);
5868c2ecf20Sopenharmony_ci				break;
5878c2ecf20Sopenharmony_ci			case CISLANDS_CONFIGREG_DIDT_IND:
5888c2ecf20Sopenharmony_ci				WREG32_DIDT(config_regs->offset, data);
5898c2ecf20Sopenharmony_ci				break;
5908c2ecf20Sopenharmony_ci			default:
5918c2ecf20Sopenharmony_ci				WREG32(config_regs->offset << 2, data);
5928c2ecf20Sopenharmony_ci				break;
5938c2ecf20Sopenharmony_ci			}
5948c2ecf20Sopenharmony_ci			cache = 0;
5958c2ecf20Sopenharmony_ci		}
5968c2ecf20Sopenharmony_ci		config_regs++;
5978c2ecf20Sopenharmony_ci	}
5988c2ecf20Sopenharmony_ci	return 0;
5998c2ecf20Sopenharmony_ci}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_cistatic int ci_enable_didt(struct radeon_device *rdev, bool enable)
6028c2ecf20Sopenharmony_ci{
6038c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
6048c2ecf20Sopenharmony_ci	int ret;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	if (pi->caps_sq_ramping || pi->caps_db_ramping ||
6078c2ecf20Sopenharmony_ci	    pi->caps_td_ramping || pi->caps_tcp_ramping) {
6088c2ecf20Sopenharmony_ci		cik_enter_rlc_safe_mode(rdev);
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci		if (enable) {
6118c2ecf20Sopenharmony_ci			ret = ci_program_pt_config_registers(rdev, didt_config_ci);
6128c2ecf20Sopenharmony_ci			if (ret) {
6138c2ecf20Sopenharmony_ci				cik_exit_rlc_safe_mode(rdev);
6148c2ecf20Sopenharmony_ci				return ret;
6158c2ecf20Sopenharmony_ci			}
6168c2ecf20Sopenharmony_ci		}
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci		ci_do_enable_didt(rdev, enable);
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci		cik_exit_rlc_safe_mode(rdev);
6218c2ecf20Sopenharmony_ci	}
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	return 0;
6248c2ecf20Sopenharmony_ci}
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_cistatic int ci_enable_power_containment(struct radeon_device *rdev, bool enable)
6278c2ecf20Sopenharmony_ci{
6288c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
6298c2ecf20Sopenharmony_ci	PPSMC_Result smc_result;
6308c2ecf20Sopenharmony_ci	int ret = 0;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	if (enable) {
6338c2ecf20Sopenharmony_ci		pi->power_containment_features = 0;
6348c2ecf20Sopenharmony_ci		if (pi->caps_power_containment) {
6358c2ecf20Sopenharmony_ci			if (pi->enable_bapm_feature) {
6368c2ecf20Sopenharmony_ci				smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_EnableDTE);
6378c2ecf20Sopenharmony_ci				if (smc_result != PPSMC_Result_OK)
6388c2ecf20Sopenharmony_ci					ret = -EINVAL;
6398c2ecf20Sopenharmony_ci				else
6408c2ecf20Sopenharmony_ci					pi->power_containment_features |= POWERCONTAINMENT_FEATURE_BAPM;
6418c2ecf20Sopenharmony_ci			}
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci			if (pi->enable_tdc_limit_feature) {
6448c2ecf20Sopenharmony_ci				smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_TDCLimitEnable);
6458c2ecf20Sopenharmony_ci				if (smc_result != PPSMC_Result_OK)
6468c2ecf20Sopenharmony_ci					ret = -EINVAL;
6478c2ecf20Sopenharmony_ci				else
6488c2ecf20Sopenharmony_ci					pi->power_containment_features |= POWERCONTAINMENT_FEATURE_TDCLimit;
6498c2ecf20Sopenharmony_ci			}
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci			if (pi->enable_pkg_pwr_tracking_feature) {
6528c2ecf20Sopenharmony_ci				smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_PkgPwrLimitEnable);
6538c2ecf20Sopenharmony_ci				if (smc_result != PPSMC_Result_OK) {
6548c2ecf20Sopenharmony_ci					ret = -EINVAL;
6558c2ecf20Sopenharmony_ci				} else {
6568c2ecf20Sopenharmony_ci					struct radeon_cac_tdp_table *cac_tdp_table =
6578c2ecf20Sopenharmony_ci						rdev->pm.dpm.dyn_state.cac_tdp_table;
6588c2ecf20Sopenharmony_ci					u32 default_pwr_limit =
6598c2ecf20Sopenharmony_ci						(u32)(cac_tdp_table->maximum_power_delivery_limit * 256);
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci					pi->power_containment_features |= POWERCONTAINMENT_FEATURE_PkgPwrLimit;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci					ci_set_power_limit(rdev, default_pwr_limit);
6648c2ecf20Sopenharmony_ci				}
6658c2ecf20Sopenharmony_ci			}
6668c2ecf20Sopenharmony_ci		}
6678c2ecf20Sopenharmony_ci	} else {
6688c2ecf20Sopenharmony_ci		if (pi->caps_power_containment && pi->power_containment_features) {
6698c2ecf20Sopenharmony_ci			if (pi->power_containment_features & POWERCONTAINMENT_FEATURE_TDCLimit)
6708c2ecf20Sopenharmony_ci				ci_send_msg_to_smc(rdev, PPSMC_MSG_TDCLimitDisable);
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci			if (pi->power_containment_features & POWERCONTAINMENT_FEATURE_BAPM)
6738c2ecf20Sopenharmony_ci				ci_send_msg_to_smc(rdev, PPSMC_MSG_DisableDTE);
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci			if (pi->power_containment_features & POWERCONTAINMENT_FEATURE_PkgPwrLimit)
6768c2ecf20Sopenharmony_ci				ci_send_msg_to_smc(rdev, PPSMC_MSG_PkgPwrLimitDisable);
6778c2ecf20Sopenharmony_ci			pi->power_containment_features = 0;
6788c2ecf20Sopenharmony_ci		}
6798c2ecf20Sopenharmony_ci	}
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	return ret;
6828c2ecf20Sopenharmony_ci}
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_cistatic int ci_enable_smc_cac(struct radeon_device *rdev, bool enable)
6858c2ecf20Sopenharmony_ci{
6868c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
6878c2ecf20Sopenharmony_ci	PPSMC_Result smc_result;
6888c2ecf20Sopenharmony_ci	int ret = 0;
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	if (pi->caps_cac) {
6918c2ecf20Sopenharmony_ci		if (enable) {
6928c2ecf20Sopenharmony_ci			smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_EnableCac);
6938c2ecf20Sopenharmony_ci			if (smc_result != PPSMC_Result_OK) {
6948c2ecf20Sopenharmony_ci				ret = -EINVAL;
6958c2ecf20Sopenharmony_ci				pi->cac_enabled = false;
6968c2ecf20Sopenharmony_ci			} else {
6978c2ecf20Sopenharmony_ci				pi->cac_enabled = true;
6988c2ecf20Sopenharmony_ci			}
6998c2ecf20Sopenharmony_ci		} else if (pi->cac_enabled) {
7008c2ecf20Sopenharmony_ci			ci_send_msg_to_smc(rdev, PPSMC_MSG_DisableCac);
7018c2ecf20Sopenharmony_ci			pi->cac_enabled = false;
7028c2ecf20Sopenharmony_ci		}
7038c2ecf20Sopenharmony_ci	}
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	return ret;
7068c2ecf20Sopenharmony_ci}
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_cistatic int ci_enable_thermal_based_sclk_dpm(struct radeon_device *rdev,
7098c2ecf20Sopenharmony_ci					    bool enable)
7108c2ecf20Sopenharmony_ci{
7118c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
7128c2ecf20Sopenharmony_ci	PPSMC_Result smc_result = PPSMC_Result_OK;
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	if (pi->thermal_sclk_dpm_enabled) {
7158c2ecf20Sopenharmony_ci		if (enable)
7168c2ecf20Sopenharmony_ci			smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_ENABLE_THERMAL_DPM);
7178c2ecf20Sopenharmony_ci		else
7188c2ecf20Sopenharmony_ci			smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_DISABLE_THERMAL_DPM);
7198c2ecf20Sopenharmony_ci	}
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	if (smc_result == PPSMC_Result_OK)
7228c2ecf20Sopenharmony_ci		return 0;
7238c2ecf20Sopenharmony_ci	else
7248c2ecf20Sopenharmony_ci		return -EINVAL;
7258c2ecf20Sopenharmony_ci}
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_cistatic int ci_power_control_set_level(struct radeon_device *rdev)
7288c2ecf20Sopenharmony_ci{
7298c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
7308c2ecf20Sopenharmony_ci	struct radeon_cac_tdp_table *cac_tdp_table =
7318c2ecf20Sopenharmony_ci		rdev->pm.dpm.dyn_state.cac_tdp_table;
7328c2ecf20Sopenharmony_ci	s32 adjust_percent;
7338c2ecf20Sopenharmony_ci	s32 target_tdp;
7348c2ecf20Sopenharmony_ci	int ret = 0;
7358c2ecf20Sopenharmony_ci	bool adjust_polarity = false; /* ??? */
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	if (pi->caps_power_containment) {
7388c2ecf20Sopenharmony_ci		adjust_percent = adjust_polarity ?
7398c2ecf20Sopenharmony_ci			rdev->pm.dpm.tdp_adjustment : (-1 * rdev->pm.dpm.tdp_adjustment);
7408c2ecf20Sopenharmony_ci		target_tdp = ((100 + adjust_percent) *
7418c2ecf20Sopenharmony_ci			      (s32)cac_tdp_table->configurable_tdp) / 100;
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci		ret = ci_set_overdrive_target_tdp(rdev, (u32)target_tdp);
7448c2ecf20Sopenharmony_ci	}
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	return ret;
7478c2ecf20Sopenharmony_ci}
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_civoid ci_dpm_powergate_uvd(struct radeon_device *rdev, bool gate)
7508c2ecf20Sopenharmony_ci{
7518c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	if (pi->uvd_power_gated == gate)
7548c2ecf20Sopenharmony_ci		return;
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	pi->uvd_power_gated = gate;
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	ci_update_uvd_dpm(rdev, gate);
7598c2ecf20Sopenharmony_ci}
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_cibool ci_dpm_vblank_too_short(struct radeon_device *rdev)
7628c2ecf20Sopenharmony_ci{
7638c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
7648c2ecf20Sopenharmony_ci	u32 vblank_time = r600_dpm_get_vblank_time(rdev);
7658c2ecf20Sopenharmony_ci	u32 switch_limit = pi->mem_gddr5 ? 450 : 300;
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	/* disable mclk switching if the refresh is >120Hz, even if the
7688c2ecf20Sopenharmony_ci        * blanking period would allow it
7698c2ecf20Sopenharmony_ci        */
7708c2ecf20Sopenharmony_ci	if (r600_dpm_get_vrefresh(rdev) > 120)
7718c2ecf20Sopenharmony_ci		return true;
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	if (vblank_time < switch_limit)
7748c2ecf20Sopenharmony_ci		return true;
7758c2ecf20Sopenharmony_ci	else
7768c2ecf20Sopenharmony_ci		return false;
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci}
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_cistatic void ci_apply_state_adjust_rules(struct radeon_device *rdev,
7818c2ecf20Sopenharmony_ci					struct radeon_ps *rps)
7828c2ecf20Sopenharmony_ci{
7838c2ecf20Sopenharmony_ci	struct ci_ps *ps = ci_get_ps(rps);
7848c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
7858c2ecf20Sopenharmony_ci	struct radeon_clock_and_voltage_limits *max_limits;
7868c2ecf20Sopenharmony_ci	bool disable_mclk_switching;
7878c2ecf20Sopenharmony_ci	u32 sclk, mclk;
7888c2ecf20Sopenharmony_ci	int i;
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	if (rps->vce_active) {
7918c2ecf20Sopenharmony_ci		rps->evclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].evclk;
7928c2ecf20Sopenharmony_ci		rps->ecclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].ecclk;
7938c2ecf20Sopenharmony_ci	} else {
7948c2ecf20Sopenharmony_ci		rps->evclk = 0;
7958c2ecf20Sopenharmony_ci		rps->ecclk = 0;
7968c2ecf20Sopenharmony_ci	}
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	if ((rdev->pm.dpm.new_active_crtc_count > 1) ||
7998c2ecf20Sopenharmony_ci	    ci_dpm_vblank_too_short(rdev))
8008c2ecf20Sopenharmony_ci		disable_mclk_switching = true;
8018c2ecf20Sopenharmony_ci	else
8028c2ecf20Sopenharmony_ci		disable_mclk_switching = false;
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY)
8058c2ecf20Sopenharmony_ci		pi->battery_state = true;
8068c2ecf20Sopenharmony_ci	else
8078c2ecf20Sopenharmony_ci		pi->battery_state = false;
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	if (rdev->pm.dpm.ac_power)
8108c2ecf20Sopenharmony_ci		max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
8118c2ecf20Sopenharmony_ci	else
8128c2ecf20Sopenharmony_ci		max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	if (rdev->pm.dpm.ac_power == false) {
8158c2ecf20Sopenharmony_ci		for (i = 0; i < ps->performance_level_count; i++) {
8168c2ecf20Sopenharmony_ci			if (ps->performance_levels[i].mclk > max_limits->mclk)
8178c2ecf20Sopenharmony_ci				ps->performance_levels[i].mclk = max_limits->mclk;
8188c2ecf20Sopenharmony_ci			if (ps->performance_levels[i].sclk > max_limits->sclk)
8198c2ecf20Sopenharmony_ci				ps->performance_levels[i].sclk = max_limits->sclk;
8208c2ecf20Sopenharmony_ci		}
8218c2ecf20Sopenharmony_ci	}
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	/* XXX validate the min clocks required for display */
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	if (disable_mclk_switching) {
8268c2ecf20Sopenharmony_ci		mclk  = ps->performance_levels[ps->performance_level_count - 1].mclk;
8278c2ecf20Sopenharmony_ci		sclk = ps->performance_levels[0].sclk;
8288c2ecf20Sopenharmony_ci	} else {
8298c2ecf20Sopenharmony_ci		mclk = ps->performance_levels[0].mclk;
8308c2ecf20Sopenharmony_ci		sclk = ps->performance_levels[0].sclk;
8318c2ecf20Sopenharmony_ci	}
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	if (rps->vce_active) {
8348c2ecf20Sopenharmony_ci		if (sclk < rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk)
8358c2ecf20Sopenharmony_ci			sclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk;
8368c2ecf20Sopenharmony_ci		if (mclk < rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].mclk)
8378c2ecf20Sopenharmony_ci			mclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].mclk;
8388c2ecf20Sopenharmony_ci	}
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	ps->performance_levels[0].sclk = sclk;
8418c2ecf20Sopenharmony_ci	ps->performance_levels[0].mclk = mclk;
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	if (ps->performance_levels[1].sclk < ps->performance_levels[0].sclk)
8448c2ecf20Sopenharmony_ci		ps->performance_levels[1].sclk = ps->performance_levels[0].sclk;
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	if (disable_mclk_switching) {
8478c2ecf20Sopenharmony_ci		if (ps->performance_levels[0].mclk < ps->performance_levels[1].mclk)
8488c2ecf20Sopenharmony_ci			ps->performance_levels[0].mclk = ps->performance_levels[1].mclk;
8498c2ecf20Sopenharmony_ci	} else {
8508c2ecf20Sopenharmony_ci		if (ps->performance_levels[1].mclk < ps->performance_levels[0].mclk)
8518c2ecf20Sopenharmony_ci			ps->performance_levels[1].mclk = ps->performance_levels[0].mclk;
8528c2ecf20Sopenharmony_ci	}
8538c2ecf20Sopenharmony_ci}
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_cistatic int ci_thermal_set_temperature_range(struct radeon_device *rdev,
8568c2ecf20Sopenharmony_ci					    int min_temp, int max_temp)
8578c2ecf20Sopenharmony_ci{
8588c2ecf20Sopenharmony_ci	int low_temp = 0 * 1000;
8598c2ecf20Sopenharmony_ci	int high_temp = 255 * 1000;
8608c2ecf20Sopenharmony_ci	u32 tmp;
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	if (low_temp < min_temp)
8638c2ecf20Sopenharmony_ci		low_temp = min_temp;
8648c2ecf20Sopenharmony_ci	if (high_temp > max_temp)
8658c2ecf20Sopenharmony_ci		high_temp = max_temp;
8668c2ecf20Sopenharmony_ci	if (high_temp < low_temp) {
8678c2ecf20Sopenharmony_ci		DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp);
8688c2ecf20Sopenharmony_ci		return -EINVAL;
8698c2ecf20Sopenharmony_ci	}
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	tmp = RREG32_SMC(CG_THERMAL_INT);
8728c2ecf20Sopenharmony_ci	tmp &= ~(CI_DIG_THERM_INTH_MASK | CI_DIG_THERM_INTL_MASK);
8738c2ecf20Sopenharmony_ci	tmp |= CI_DIG_THERM_INTH(high_temp / 1000) |
8748c2ecf20Sopenharmony_ci		CI_DIG_THERM_INTL(low_temp / 1000);
8758c2ecf20Sopenharmony_ci	WREG32_SMC(CG_THERMAL_INT, tmp);
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci#if 0
8788c2ecf20Sopenharmony_ci	/* XXX: need to figure out how to handle this properly */
8798c2ecf20Sopenharmony_ci	tmp = RREG32_SMC(CG_THERMAL_CTRL);
8808c2ecf20Sopenharmony_ci	tmp &= DIG_THERM_DPM_MASK;
8818c2ecf20Sopenharmony_ci	tmp |= DIG_THERM_DPM(high_temp / 1000);
8828c2ecf20Sopenharmony_ci	WREG32_SMC(CG_THERMAL_CTRL, tmp);
8838c2ecf20Sopenharmony_ci#endif
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	rdev->pm.dpm.thermal.min_temp = low_temp;
8868c2ecf20Sopenharmony_ci	rdev->pm.dpm.thermal.max_temp = high_temp;
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	return 0;
8898c2ecf20Sopenharmony_ci}
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_cistatic int ci_thermal_enable_alert(struct radeon_device *rdev,
8928c2ecf20Sopenharmony_ci				   bool enable)
8938c2ecf20Sopenharmony_ci{
8948c2ecf20Sopenharmony_ci	u32 thermal_int = RREG32_SMC(CG_THERMAL_INT);
8958c2ecf20Sopenharmony_ci	PPSMC_Result result;
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	if (enable) {
8988c2ecf20Sopenharmony_ci		thermal_int &= ~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
8998c2ecf20Sopenharmony_ci		WREG32_SMC(CG_THERMAL_INT, thermal_int);
9008c2ecf20Sopenharmony_ci		rdev->irq.dpm_thermal = false;
9018c2ecf20Sopenharmony_ci		result = ci_send_msg_to_smc(rdev, PPSMC_MSG_Thermal_Cntl_Enable);
9028c2ecf20Sopenharmony_ci		if (result != PPSMC_Result_OK) {
9038c2ecf20Sopenharmony_ci			DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");
9048c2ecf20Sopenharmony_ci			return -EINVAL;
9058c2ecf20Sopenharmony_ci		}
9068c2ecf20Sopenharmony_ci	} else {
9078c2ecf20Sopenharmony_ci		thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW;
9088c2ecf20Sopenharmony_ci		WREG32_SMC(CG_THERMAL_INT, thermal_int);
9098c2ecf20Sopenharmony_ci		rdev->irq.dpm_thermal = true;
9108c2ecf20Sopenharmony_ci		result = ci_send_msg_to_smc(rdev, PPSMC_MSG_Thermal_Cntl_Disable);
9118c2ecf20Sopenharmony_ci		if (result != PPSMC_Result_OK) {
9128c2ecf20Sopenharmony_ci			DRM_DEBUG_KMS("Could not disable thermal interrupts.\n");
9138c2ecf20Sopenharmony_ci			return -EINVAL;
9148c2ecf20Sopenharmony_ci		}
9158c2ecf20Sopenharmony_ci	}
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci	return 0;
9188c2ecf20Sopenharmony_ci}
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_cistatic void ci_fan_ctrl_set_static_mode(struct radeon_device *rdev, u32 mode)
9218c2ecf20Sopenharmony_ci{
9228c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
9238c2ecf20Sopenharmony_ci	u32 tmp;
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci	if (pi->fan_ctrl_is_in_default_mode) {
9268c2ecf20Sopenharmony_ci		tmp = (RREG32_SMC(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK) >> FDO_PWM_MODE_SHIFT;
9278c2ecf20Sopenharmony_ci		pi->fan_ctrl_default_mode = tmp;
9288c2ecf20Sopenharmony_ci		tmp = (RREG32_SMC(CG_FDO_CTRL2) & TMIN_MASK) >> TMIN_SHIFT;
9298c2ecf20Sopenharmony_ci		pi->t_min = tmp;
9308c2ecf20Sopenharmony_ci		pi->fan_ctrl_is_in_default_mode = false;
9318c2ecf20Sopenharmony_ci	}
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	tmp = RREG32_SMC(CG_FDO_CTRL2) & ~TMIN_MASK;
9348c2ecf20Sopenharmony_ci	tmp |= TMIN(0);
9358c2ecf20Sopenharmony_ci	WREG32_SMC(CG_FDO_CTRL2, tmp);
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	tmp = RREG32_SMC(CG_FDO_CTRL2) & ~FDO_PWM_MODE_MASK;
9388c2ecf20Sopenharmony_ci	tmp |= FDO_PWM_MODE(mode);
9398c2ecf20Sopenharmony_ci	WREG32_SMC(CG_FDO_CTRL2, tmp);
9408c2ecf20Sopenharmony_ci}
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_cistatic int ci_thermal_setup_fan_table(struct radeon_device *rdev)
9438c2ecf20Sopenharmony_ci{
9448c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
9458c2ecf20Sopenharmony_ci	SMU7_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
9468c2ecf20Sopenharmony_ci	u32 duty100;
9478c2ecf20Sopenharmony_ci	u32 t_diff1, t_diff2, pwm_diff1, pwm_diff2;
9488c2ecf20Sopenharmony_ci	u16 fdo_min, slope1, slope2;
9498c2ecf20Sopenharmony_ci	u32 reference_clock, tmp;
9508c2ecf20Sopenharmony_ci	int ret;
9518c2ecf20Sopenharmony_ci	u64 tmp64;
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	if (!pi->fan_table_start) {
9548c2ecf20Sopenharmony_ci		rdev->pm.dpm.fan.ucode_fan_control = false;
9558c2ecf20Sopenharmony_ci		return 0;
9568c2ecf20Sopenharmony_ci	}
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	duty100 = (RREG32_SMC(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	if (duty100 == 0) {
9618c2ecf20Sopenharmony_ci		rdev->pm.dpm.fan.ucode_fan_control = false;
9628c2ecf20Sopenharmony_ci		return 0;
9638c2ecf20Sopenharmony_ci	}
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	tmp64 = (u64)rdev->pm.dpm.fan.pwm_min * duty100;
9668c2ecf20Sopenharmony_ci	do_div(tmp64, 10000);
9678c2ecf20Sopenharmony_ci	fdo_min = (u16)tmp64;
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	t_diff1 = rdev->pm.dpm.fan.t_med - rdev->pm.dpm.fan.t_min;
9708c2ecf20Sopenharmony_ci	t_diff2 = rdev->pm.dpm.fan.t_high - rdev->pm.dpm.fan.t_med;
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	pwm_diff1 = rdev->pm.dpm.fan.pwm_med - rdev->pm.dpm.fan.pwm_min;
9738c2ecf20Sopenharmony_ci	pwm_diff2 = rdev->pm.dpm.fan.pwm_high - rdev->pm.dpm.fan.pwm_med;
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	slope1 = (u16)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
9768c2ecf20Sopenharmony_ci	slope2 = (u16)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	fan_table.TempMin = cpu_to_be16((50 + rdev->pm.dpm.fan.t_min) / 100);
9798c2ecf20Sopenharmony_ci	fan_table.TempMed = cpu_to_be16((50 + rdev->pm.dpm.fan.t_med) / 100);
9808c2ecf20Sopenharmony_ci	fan_table.TempMax = cpu_to_be16((50 + rdev->pm.dpm.fan.t_max) / 100);
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci	fan_table.Slope1 = cpu_to_be16(slope1);
9838c2ecf20Sopenharmony_ci	fan_table.Slope2 = cpu_to_be16(slope2);
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	fan_table.FdoMin = cpu_to_be16(fdo_min);
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci	fan_table.HystDown = cpu_to_be16(rdev->pm.dpm.fan.t_hyst);
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	fan_table.HystUp = cpu_to_be16(1);
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	fan_table.HystSlope = cpu_to_be16(1);
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	fan_table.TempRespLim = cpu_to_be16(5);
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	reference_clock = radeon_get_xclk(rdev);
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	fan_table.RefreshPeriod = cpu_to_be32((rdev->pm.dpm.fan.cycle_delay *
9988c2ecf20Sopenharmony_ci					       reference_clock) / 1600);
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	fan_table.FdoMax = cpu_to_be16((u16)duty100);
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci	tmp = (RREG32_SMC(CG_MULT_THERMAL_CTRL) & TEMP_SEL_MASK) >> TEMP_SEL_SHIFT;
10038c2ecf20Sopenharmony_ci	fan_table.TempSrc = (uint8_t)tmp;
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	ret = ci_copy_bytes_to_smc(rdev,
10068c2ecf20Sopenharmony_ci				   pi->fan_table_start,
10078c2ecf20Sopenharmony_ci				   (u8 *)(&fan_table),
10088c2ecf20Sopenharmony_ci				   sizeof(fan_table),
10098c2ecf20Sopenharmony_ci				   pi->sram_end);
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci	if (ret) {
10128c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to load fan table to the SMC.");
10138c2ecf20Sopenharmony_ci		rdev->pm.dpm.fan.ucode_fan_control = false;
10148c2ecf20Sopenharmony_ci	}
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	return 0;
10178c2ecf20Sopenharmony_ci}
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_cistatic int ci_fan_ctrl_start_smc_fan_control(struct radeon_device *rdev)
10208c2ecf20Sopenharmony_ci{
10218c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
10228c2ecf20Sopenharmony_ci	PPSMC_Result ret;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	if (pi->caps_od_fuzzy_fan_control_support) {
10258c2ecf20Sopenharmony_ci		ret = ci_send_msg_to_smc_with_parameter(rdev,
10268c2ecf20Sopenharmony_ci							PPSMC_StartFanControl,
10278c2ecf20Sopenharmony_ci							FAN_CONTROL_FUZZY);
10288c2ecf20Sopenharmony_ci		if (ret != PPSMC_Result_OK)
10298c2ecf20Sopenharmony_ci			return -EINVAL;
10308c2ecf20Sopenharmony_ci		ret = ci_send_msg_to_smc_with_parameter(rdev,
10318c2ecf20Sopenharmony_ci							PPSMC_MSG_SetFanPwmMax,
10328c2ecf20Sopenharmony_ci							rdev->pm.dpm.fan.default_max_fan_pwm);
10338c2ecf20Sopenharmony_ci		if (ret != PPSMC_Result_OK)
10348c2ecf20Sopenharmony_ci			return -EINVAL;
10358c2ecf20Sopenharmony_ci	} else {
10368c2ecf20Sopenharmony_ci		ret = ci_send_msg_to_smc_with_parameter(rdev,
10378c2ecf20Sopenharmony_ci							PPSMC_StartFanControl,
10388c2ecf20Sopenharmony_ci							FAN_CONTROL_TABLE);
10398c2ecf20Sopenharmony_ci		if (ret != PPSMC_Result_OK)
10408c2ecf20Sopenharmony_ci			return -EINVAL;
10418c2ecf20Sopenharmony_ci	}
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	pi->fan_is_controlled_by_smc = true;
10448c2ecf20Sopenharmony_ci	return 0;
10458c2ecf20Sopenharmony_ci}
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_cistatic int ci_fan_ctrl_stop_smc_fan_control(struct radeon_device *rdev)
10488c2ecf20Sopenharmony_ci{
10498c2ecf20Sopenharmony_ci	PPSMC_Result ret;
10508c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	ret = ci_send_msg_to_smc(rdev, PPSMC_StopFanControl);
10538c2ecf20Sopenharmony_ci	if (ret == PPSMC_Result_OK) {
10548c2ecf20Sopenharmony_ci		pi->fan_is_controlled_by_smc = false;
10558c2ecf20Sopenharmony_ci		return 0;
10568c2ecf20Sopenharmony_ci	} else
10578c2ecf20Sopenharmony_ci		return -EINVAL;
10588c2ecf20Sopenharmony_ci}
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ciint ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
10618c2ecf20Sopenharmony_ci					     u32 *speed)
10628c2ecf20Sopenharmony_ci{
10638c2ecf20Sopenharmony_ci	u32 duty, duty100;
10648c2ecf20Sopenharmony_ci	u64 tmp64;
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	if (rdev->pm.no_fan)
10678c2ecf20Sopenharmony_ci		return -ENOENT;
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	duty100 = (RREG32_SMC(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
10708c2ecf20Sopenharmony_ci	duty = (RREG32_SMC(CG_THERMAL_STATUS) & FDO_PWM_DUTY_MASK) >> FDO_PWM_DUTY_SHIFT;
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci	if (duty100 == 0)
10738c2ecf20Sopenharmony_ci		return -EINVAL;
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	tmp64 = (u64)duty * 100;
10768c2ecf20Sopenharmony_ci	do_div(tmp64, duty100);
10778c2ecf20Sopenharmony_ci	*speed = (u32)tmp64;
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	if (*speed > 100)
10808c2ecf20Sopenharmony_ci		*speed = 100;
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci	return 0;
10838c2ecf20Sopenharmony_ci}
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ciint ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
10868c2ecf20Sopenharmony_ci					     u32 speed)
10878c2ecf20Sopenharmony_ci{
10888c2ecf20Sopenharmony_ci	u32 tmp;
10898c2ecf20Sopenharmony_ci	u32 duty, duty100;
10908c2ecf20Sopenharmony_ci	u64 tmp64;
10918c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	if (rdev->pm.no_fan)
10948c2ecf20Sopenharmony_ci		return -ENOENT;
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	if (pi->fan_is_controlled_by_smc)
10978c2ecf20Sopenharmony_ci		return -EINVAL;
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci	if (speed > 100)
11008c2ecf20Sopenharmony_ci		return -EINVAL;
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci	duty100 = (RREG32_SMC(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	if (duty100 == 0)
11058c2ecf20Sopenharmony_ci		return -EINVAL;
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci	tmp64 = (u64)speed * duty100;
11088c2ecf20Sopenharmony_ci	do_div(tmp64, 100);
11098c2ecf20Sopenharmony_ci	duty = (u32)tmp64;
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci	tmp = RREG32_SMC(CG_FDO_CTRL0) & ~FDO_STATIC_DUTY_MASK;
11128c2ecf20Sopenharmony_ci	tmp |= FDO_STATIC_DUTY(duty);
11138c2ecf20Sopenharmony_ci	WREG32_SMC(CG_FDO_CTRL0, tmp);
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci	return 0;
11168c2ecf20Sopenharmony_ci}
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_civoid ci_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode)
11198c2ecf20Sopenharmony_ci{
11208c2ecf20Sopenharmony_ci	if (mode) {
11218c2ecf20Sopenharmony_ci		/* stop auto-manage */
11228c2ecf20Sopenharmony_ci		if (rdev->pm.dpm.fan.ucode_fan_control)
11238c2ecf20Sopenharmony_ci			ci_fan_ctrl_stop_smc_fan_control(rdev);
11248c2ecf20Sopenharmony_ci		ci_fan_ctrl_set_static_mode(rdev, mode);
11258c2ecf20Sopenharmony_ci	} else {
11268c2ecf20Sopenharmony_ci		/* restart auto-manage */
11278c2ecf20Sopenharmony_ci		if (rdev->pm.dpm.fan.ucode_fan_control)
11288c2ecf20Sopenharmony_ci			ci_thermal_start_smc_fan_control(rdev);
11298c2ecf20Sopenharmony_ci		else
11308c2ecf20Sopenharmony_ci			ci_fan_ctrl_set_default_mode(rdev);
11318c2ecf20Sopenharmony_ci	}
11328c2ecf20Sopenharmony_ci}
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ciu32 ci_fan_ctrl_get_mode(struct radeon_device *rdev)
11358c2ecf20Sopenharmony_ci{
11368c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
11378c2ecf20Sopenharmony_ci	u32 tmp;
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	if (pi->fan_is_controlled_by_smc)
11408c2ecf20Sopenharmony_ci		return 0;
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci	tmp = RREG32_SMC(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK;
11438c2ecf20Sopenharmony_ci	return (tmp >> FDO_PWM_MODE_SHIFT);
11448c2ecf20Sopenharmony_ci}
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci#if 0
11478c2ecf20Sopenharmony_cistatic int ci_fan_ctrl_get_fan_speed_rpm(struct radeon_device *rdev,
11488c2ecf20Sopenharmony_ci					 u32 *speed)
11498c2ecf20Sopenharmony_ci{
11508c2ecf20Sopenharmony_ci	u32 tach_period;
11518c2ecf20Sopenharmony_ci	u32 xclk = radeon_get_xclk(rdev);
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci	if (rdev->pm.no_fan)
11548c2ecf20Sopenharmony_ci		return -ENOENT;
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci	if (rdev->pm.fan_pulses_per_revolution == 0)
11578c2ecf20Sopenharmony_ci		return -ENOENT;
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci	tach_period = (RREG32_SMC(CG_TACH_STATUS) & TACH_PERIOD_MASK) >> TACH_PERIOD_SHIFT;
11608c2ecf20Sopenharmony_ci	if (tach_period == 0)
11618c2ecf20Sopenharmony_ci		return -ENOENT;
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci	*speed = 60 * xclk * 10000 / tach_period;
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	return 0;
11668c2ecf20Sopenharmony_ci}
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_cistatic int ci_fan_ctrl_set_fan_speed_rpm(struct radeon_device *rdev,
11698c2ecf20Sopenharmony_ci					 u32 speed)
11708c2ecf20Sopenharmony_ci{
11718c2ecf20Sopenharmony_ci	u32 tach_period, tmp;
11728c2ecf20Sopenharmony_ci	u32 xclk = radeon_get_xclk(rdev);
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci	if (rdev->pm.no_fan)
11758c2ecf20Sopenharmony_ci		return -ENOENT;
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	if (rdev->pm.fan_pulses_per_revolution == 0)
11788c2ecf20Sopenharmony_ci		return -ENOENT;
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	if ((speed < rdev->pm.fan_min_rpm) ||
11818c2ecf20Sopenharmony_ci	    (speed > rdev->pm.fan_max_rpm))
11828c2ecf20Sopenharmony_ci		return -EINVAL;
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci	if (rdev->pm.dpm.fan.ucode_fan_control)
11858c2ecf20Sopenharmony_ci		ci_fan_ctrl_stop_smc_fan_control(rdev);
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci	tach_period = 60 * xclk * 10000 / (8 * speed);
11888c2ecf20Sopenharmony_ci	tmp = RREG32_SMC(CG_TACH_CTRL) & ~TARGET_PERIOD_MASK;
11898c2ecf20Sopenharmony_ci	tmp |= TARGET_PERIOD(tach_period);
11908c2ecf20Sopenharmony_ci	WREG32_SMC(CG_TACH_CTRL, tmp);
11918c2ecf20Sopenharmony_ci
11928c2ecf20Sopenharmony_ci	ci_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC_RPM);
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci	return 0;
11958c2ecf20Sopenharmony_ci}
11968c2ecf20Sopenharmony_ci#endif
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_cistatic void ci_fan_ctrl_set_default_mode(struct radeon_device *rdev)
11998c2ecf20Sopenharmony_ci{
12008c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
12018c2ecf20Sopenharmony_ci	u32 tmp;
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	if (!pi->fan_ctrl_is_in_default_mode) {
12048c2ecf20Sopenharmony_ci		tmp = RREG32_SMC(CG_FDO_CTRL2) & ~FDO_PWM_MODE_MASK;
12058c2ecf20Sopenharmony_ci		tmp |= FDO_PWM_MODE(pi->fan_ctrl_default_mode);
12068c2ecf20Sopenharmony_ci		WREG32_SMC(CG_FDO_CTRL2, tmp);
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci		tmp = RREG32_SMC(CG_FDO_CTRL2) & ~TMIN_MASK;
12098c2ecf20Sopenharmony_ci		tmp |= TMIN(pi->t_min);
12108c2ecf20Sopenharmony_ci		WREG32_SMC(CG_FDO_CTRL2, tmp);
12118c2ecf20Sopenharmony_ci		pi->fan_ctrl_is_in_default_mode = true;
12128c2ecf20Sopenharmony_ci	}
12138c2ecf20Sopenharmony_ci}
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_cistatic void ci_thermal_start_smc_fan_control(struct radeon_device *rdev)
12168c2ecf20Sopenharmony_ci{
12178c2ecf20Sopenharmony_ci	if (rdev->pm.dpm.fan.ucode_fan_control) {
12188c2ecf20Sopenharmony_ci		ci_fan_ctrl_start_smc_fan_control(rdev);
12198c2ecf20Sopenharmony_ci		ci_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC);
12208c2ecf20Sopenharmony_ci	}
12218c2ecf20Sopenharmony_ci}
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_cistatic void ci_thermal_initialize(struct radeon_device *rdev)
12248c2ecf20Sopenharmony_ci{
12258c2ecf20Sopenharmony_ci	u32 tmp;
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	if (rdev->pm.fan_pulses_per_revolution) {
12288c2ecf20Sopenharmony_ci		tmp = RREG32_SMC(CG_TACH_CTRL) & ~EDGE_PER_REV_MASK;
12298c2ecf20Sopenharmony_ci		tmp |= EDGE_PER_REV(rdev->pm.fan_pulses_per_revolution -1);
12308c2ecf20Sopenharmony_ci		WREG32_SMC(CG_TACH_CTRL, tmp);
12318c2ecf20Sopenharmony_ci	}
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci	tmp = RREG32_SMC(CG_FDO_CTRL2) & ~TACH_PWM_RESP_RATE_MASK;
12348c2ecf20Sopenharmony_ci	tmp |= TACH_PWM_RESP_RATE(0x28);
12358c2ecf20Sopenharmony_ci	WREG32_SMC(CG_FDO_CTRL2, tmp);
12368c2ecf20Sopenharmony_ci}
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_cistatic int ci_thermal_start_thermal_controller(struct radeon_device *rdev)
12398c2ecf20Sopenharmony_ci{
12408c2ecf20Sopenharmony_ci	int ret;
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	ci_thermal_initialize(rdev);
12438c2ecf20Sopenharmony_ci	ret = ci_thermal_set_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
12448c2ecf20Sopenharmony_ci	if (ret)
12458c2ecf20Sopenharmony_ci		return ret;
12468c2ecf20Sopenharmony_ci	ret = ci_thermal_enable_alert(rdev, true);
12478c2ecf20Sopenharmony_ci	if (ret)
12488c2ecf20Sopenharmony_ci		return ret;
12498c2ecf20Sopenharmony_ci	if (rdev->pm.dpm.fan.ucode_fan_control) {
12508c2ecf20Sopenharmony_ci		ret = ci_thermal_setup_fan_table(rdev);
12518c2ecf20Sopenharmony_ci		if (ret)
12528c2ecf20Sopenharmony_ci			return ret;
12538c2ecf20Sopenharmony_ci		ci_thermal_start_smc_fan_control(rdev);
12548c2ecf20Sopenharmony_ci	}
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	return 0;
12578c2ecf20Sopenharmony_ci}
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_cistatic void ci_thermal_stop_thermal_controller(struct radeon_device *rdev)
12608c2ecf20Sopenharmony_ci{
12618c2ecf20Sopenharmony_ci	if (!rdev->pm.no_fan)
12628c2ecf20Sopenharmony_ci		ci_fan_ctrl_set_default_mode(rdev);
12638c2ecf20Sopenharmony_ci}
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci#if 0
12668c2ecf20Sopenharmony_cistatic int ci_read_smc_soft_register(struct radeon_device *rdev,
12678c2ecf20Sopenharmony_ci				     u16 reg_offset, u32 *value)
12688c2ecf20Sopenharmony_ci{
12698c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci	return ci_read_smc_sram_dword(rdev,
12728c2ecf20Sopenharmony_ci				      pi->soft_regs_start + reg_offset,
12738c2ecf20Sopenharmony_ci				      value, pi->sram_end);
12748c2ecf20Sopenharmony_ci}
12758c2ecf20Sopenharmony_ci#endif
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_cistatic int ci_write_smc_soft_register(struct radeon_device *rdev,
12788c2ecf20Sopenharmony_ci				      u16 reg_offset, u32 value)
12798c2ecf20Sopenharmony_ci{
12808c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci	return ci_write_smc_sram_dword(rdev,
12838c2ecf20Sopenharmony_ci				       pi->soft_regs_start + reg_offset,
12848c2ecf20Sopenharmony_ci				       value, pi->sram_end);
12858c2ecf20Sopenharmony_ci}
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_cistatic void ci_init_fps_limits(struct radeon_device *rdev)
12888c2ecf20Sopenharmony_ci{
12898c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
12908c2ecf20Sopenharmony_ci	SMU7_Discrete_DpmTable *table = &pi->smc_state_table;
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_ci	if (pi->caps_fps) {
12938c2ecf20Sopenharmony_ci		u16 tmp;
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_ci		tmp = 45;
12968c2ecf20Sopenharmony_ci		table->FpsHighT = cpu_to_be16(tmp);
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci		tmp = 30;
12998c2ecf20Sopenharmony_ci		table->FpsLowT = cpu_to_be16(tmp);
13008c2ecf20Sopenharmony_ci	}
13018c2ecf20Sopenharmony_ci}
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_cistatic int ci_update_sclk_t(struct radeon_device *rdev)
13048c2ecf20Sopenharmony_ci{
13058c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
13068c2ecf20Sopenharmony_ci	int ret = 0;
13078c2ecf20Sopenharmony_ci	u32 low_sclk_interrupt_t = 0;
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci	if (pi->caps_sclk_throttle_low_notification) {
13108c2ecf20Sopenharmony_ci		low_sclk_interrupt_t = cpu_to_be32(pi->low_sclk_interrupt_t);
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci		ret = ci_copy_bytes_to_smc(rdev,
13138c2ecf20Sopenharmony_ci					   pi->dpm_table_start +
13148c2ecf20Sopenharmony_ci					   offsetof(SMU7_Discrete_DpmTable, LowSclkInterruptT),
13158c2ecf20Sopenharmony_ci					   (u8 *)&low_sclk_interrupt_t,
13168c2ecf20Sopenharmony_ci					   sizeof(u32), pi->sram_end);
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_ci	}
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci	return ret;
13218c2ecf20Sopenharmony_ci}
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_cistatic void ci_get_leakage_voltages(struct radeon_device *rdev)
13248c2ecf20Sopenharmony_ci{
13258c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
13268c2ecf20Sopenharmony_ci	u16 leakage_id, virtual_voltage_id;
13278c2ecf20Sopenharmony_ci	u16 vddc, vddci;
13288c2ecf20Sopenharmony_ci	int i;
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci	pi->vddc_leakage.count = 0;
13318c2ecf20Sopenharmony_ci	pi->vddci_leakage.count = 0;
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ci	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_EVV) {
13348c2ecf20Sopenharmony_ci		for (i = 0; i < CISLANDS_MAX_LEAKAGE_COUNT; i++) {
13358c2ecf20Sopenharmony_ci			virtual_voltage_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i;
13368c2ecf20Sopenharmony_ci			if (radeon_atom_get_voltage_evv(rdev, virtual_voltage_id, &vddc) != 0)
13378c2ecf20Sopenharmony_ci				continue;
13388c2ecf20Sopenharmony_ci			if (vddc != 0 && vddc != virtual_voltage_id) {
13398c2ecf20Sopenharmony_ci				pi->vddc_leakage.actual_voltage[pi->vddc_leakage.count] = vddc;
13408c2ecf20Sopenharmony_ci				pi->vddc_leakage.leakage_id[pi->vddc_leakage.count] = virtual_voltage_id;
13418c2ecf20Sopenharmony_ci				pi->vddc_leakage.count++;
13428c2ecf20Sopenharmony_ci			}
13438c2ecf20Sopenharmony_ci		}
13448c2ecf20Sopenharmony_ci	} else if (radeon_atom_get_leakage_id_from_vbios(rdev, &leakage_id) == 0) {
13458c2ecf20Sopenharmony_ci		for (i = 0; i < CISLANDS_MAX_LEAKAGE_COUNT; i++) {
13468c2ecf20Sopenharmony_ci			virtual_voltage_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i;
13478c2ecf20Sopenharmony_ci			if (radeon_atom_get_leakage_vddc_based_on_leakage_params(rdev, &vddc, &vddci,
13488c2ecf20Sopenharmony_ci										 virtual_voltage_id,
13498c2ecf20Sopenharmony_ci										 leakage_id) == 0) {
13508c2ecf20Sopenharmony_ci				if (vddc != 0 && vddc != virtual_voltage_id) {
13518c2ecf20Sopenharmony_ci					pi->vddc_leakage.actual_voltage[pi->vddc_leakage.count] = vddc;
13528c2ecf20Sopenharmony_ci					pi->vddc_leakage.leakage_id[pi->vddc_leakage.count] = virtual_voltage_id;
13538c2ecf20Sopenharmony_ci					pi->vddc_leakage.count++;
13548c2ecf20Sopenharmony_ci				}
13558c2ecf20Sopenharmony_ci				if (vddci != 0 && vddci != virtual_voltage_id) {
13568c2ecf20Sopenharmony_ci					pi->vddci_leakage.actual_voltage[pi->vddci_leakage.count] = vddci;
13578c2ecf20Sopenharmony_ci					pi->vddci_leakage.leakage_id[pi->vddci_leakage.count] = virtual_voltage_id;
13588c2ecf20Sopenharmony_ci					pi->vddci_leakage.count++;
13598c2ecf20Sopenharmony_ci				}
13608c2ecf20Sopenharmony_ci			}
13618c2ecf20Sopenharmony_ci		}
13628c2ecf20Sopenharmony_ci	}
13638c2ecf20Sopenharmony_ci}
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_cistatic void ci_set_dpm_event_sources(struct radeon_device *rdev, u32 sources)
13668c2ecf20Sopenharmony_ci{
13678c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
13688c2ecf20Sopenharmony_ci	bool want_thermal_protection;
13698c2ecf20Sopenharmony_ci	enum radeon_dpm_event_src dpm_event_src;
13708c2ecf20Sopenharmony_ci	u32 tmp;
13718c2ecf20Sopenharmony_ci
13728c2ecf20Sopenharmony_ci	switch (sources) {
13738c2ecf20Sopenharmony_ci	case 0:
13748c2ecf20Sopenharmony_ci	default:
13758c2ecf20Sopenharmony_ci		want_thermal_protection = false;
13768c2ecf20Sopenharmony_ci		break;
13778c2ecf20Sopenharmony_ci	case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL):
13788c2ecf20Sopenharmony_ci		want_thermal_protection = true;
13798c2ecf20Sopenharmony_ci		dpm_event_src = RADEON_DPM_EVENT_SRC_DIGITAL;
13808c2ecf20Sopenharmony_ci		break;
13818c2ecf20Sopenharmony_ci	case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL):
13828c2ecf20Sopenharmony_ci		want_thermal_protection = true;
13838c2ecf20Sopenharmony_ci		dpm_event_src = RADEON_DPM_EVENT_SRC_EXTERNAL;
13848c2ecf20Sopenharmony_ci		break;
13858c2ecf20Sopenharmony_ci	case ((1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL) |
13868c2ecf20Sopenharmony_ci	      (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL)):
13878c2ecf20Sopenharmony_ci		want_thermal_protection = true;
13888c2ecf20Sopenharmony_ci		dpm_event_src = RADEON_DPM_EVENT_SRC_DIGIAL_OR_EXTERNAL;
13898c2ecf20Sopenharmony_ci		break;
13908c2ecf20Sopenharmony_ci	}
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci	if (want_thermal_protection) {
13938c2ecf20Sopenharmony_ci#if 0
13948c2ecf20Sopenharmony_ci		/* XXX: need to figure out how to handle this properly */
13958c2ecf20Sopenharmony_ci		tmp = RREG32_SMC(CG_THERMAL_CTRL);
13968c2ecf20Sopenharmony_ci		tmp &= DPM_EVENT_SRC_MASK;
13978c2ecf20Sopenharmony_ci		tmp |= DPM_EVENT_SRC(dpm_event_src);
13988c2ecf20Sopenharmony_ci		WREG32_SMC(CG_THERMAL_CTRL, tmp);
13998c2ecf20Sopenharmony_ci#endif
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci		tmp = RREG32_SMC(GENERAL_PWRMGT);
14028c2ecf20Sopenharmony_ci		if (pi->thermal_protection)
14038c2ecf20Sopenharmony_ci			tmp &= ~THERMAL_PROTECTION_DIS;
14048c2ecf20Sopenharmony_ci		else
14058c2ecf20Sopenharmony_ci			tmp |= THERMAL_PROTECTION_DIS;
14068c2ecf20Sopenharmony_ci		WREG32_SMC(GENERAL_PWRMGT, tmp);
14078c2ecf20Sopenharmony_ci	} else {
14088c2ecf20Sopenharmony_ci		tmp = RREG32_SMC(GENERAL_PWRMGT);
14098c2ecf20Sopenharmony_ci		tmp |= THERMAL_PROTECTION_DIS;
14108c2ecf20Sopenharmony_ci		WREG32_SMC(GENERAL_PWRMGT, tmp);
14118c2ecf20Sopenharmony_ci	}
14128c2ecf20Sopenharmony_ci}
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_cistatic void ci_enable_auto_throttle_source(struct radeon_device *rdev,
14158c2ecf20Sopenharmony_ci					   enum radeon_dpm_auto_throttle_src source,
14168c2ecf20Sopenharmony_ci					   bool enable)
14178c2ecf20Sopenharmony_ci{
14188c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci	if (enable) {
14218c2ecf20Sopenharmony_ci		if (!(pi->active_auto_throttle_sources & (1 << source))) {
14228c2ecf20Sopenharmony_ci			pi->active_auto_throttle_sources |= 1 << source;
14238c2ecf20Sopenharmony_ci			ci_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources);
14248c2ecf20Sopenharmony_ci		}
14258c2ecf20Sopenharmony_ci	} else {
14268c2ecf20Sopenharmony_ci		if (pi->active_auto_throttle_sources & (1 << source)) {
14278c2ecf20Sopenharmony_ci			pi->active_auto_throttle_sources &= ~(1 << source);
14288c2ecf20Sopenharmony_ci			ci_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources);
14298c2ecf20Sopenharmony_ci		}
14308c2ecf20Sopenharmony_ci	}
14318c2ecf20Sopenharmony_ci}
14328c2ecf20Sopenharmony_ci
14338c2ecf20Sopenharmony_cistatic void ci_enable_vr_hot_gpio_interrupt(struct radeon_device *rdev)
14348c2ecf20Sopenharmony_ci{
14358c2ecf20Sopenharmony_ci	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_REGULATOR_HOT)
14368c2ecf20Sopenharmony_ci		ci_send_msg_to_smc(rdev, PPSMC_MSG_EnableVRHotGPIOInterrupt);
14378c2ecf20Sopenharmony_ci}
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_cistatic int ci_unfreeze_sclk_mclk_dpm(struct radeon_device *rdev)
14408c2ecf20Sopenharmony_ci{
14418c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
14428c2ecf20Sopenharmony_ci	PPSMC_Result smc_result;
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci	if (!pi->need_update_smu7_dpm_table)
14458c2ecf20Sopenharmony_ci		return 0;
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci	if ((!pi->sclk_dpm_key_disabled) &&
14488c2ecf20Sopenharmony_ci	    (pi->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_UPDATE_SCLK))) {
14498c2ecf20Sopenharmony_ci		smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_SCLKDPM_UnfreezeLevel);
14508c2ecf20Sopenharmony_ci		if (smc_result != PPSMC_Result_OK)
14518c2ecf20Sopenharmony_ci			return -EINVAL;
14528c2ecf20Sopenharmony_ci	}
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci	if ((!pi->mclk_dpm_key_disabled) &&
14558c2ecf20Sopenharmony_ci	    (pi->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)) {
14568c2ecf20Sopenharmony_ci		smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_MCLKDPM_UnfreezeLevel);
14578c2ecf20Sopenharmony_ci		if (smc_result != PPSMC_Result_OK)
14588c2ecf20Sopenharmony_ci			return -EINVAL;
14598c2ecf20Sopenharmony_ci	}
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci	pi->need_update_smu7_dpm_table = 0;
14628c2ecf20Sopenharmony_ci	return 0;
14638c2ecf20Sopenharmony_ci}
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_cistatic int ci_enable_sclk_mclk_dpm(struct radeon_device *rdev, bool enable)
14668c2ecf20Sopenharmony_ci{
14678c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
14688c2ecf20Sopenharmony_ci	PPSMC_Result smc_result;
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci	if (enable) {
14718c2ecf20Sopenharmony_ci		if (!pi->sclk_dpm_key_disabled) {
14728c2ecf20Sopenharmony_ci			smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_DPM_Enable);
14738c2ecf20Sopenharmony_ci			if (smc_result != PPSMC_Result_OK)
14748c2ecf20Sopenharmony_ci				return -EINVAL;
14758c2ecf20Sopenharmony_ci		}
14768c2ecf20Sopenharmony_ci
14778c2ecf20Sopenharmony_ci		if (!pi->mclk_dpm_key_disabled) {
14788c2ecf20Sopenharmony_ci			smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_MCLKDPM_Enable);
14798c2ecf20Sopenharmony_ci			if (smc_result != PPSMC_Result_OK)
14808c2ecf20Sopenharmony_ci				return -EINVAL;
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci			WREG32_P(MC_SEQ_CNTL_3, CAC_EN, ~CAC_EN);
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci			WREG32_SMC(LCAC_MC0_CNTL, 0x05);
14858c2ecf20Sopenharmony_ci			WREG32_SMC(LCAC_MC1_CNTL, 0x05);
14868c2ecf20Sopenharmony_ci			WREG32_SMC(LCAC_CPL_CNTL, 0x100005);
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci			udelay(10);
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci			WREG32_SMC(LCAC_MC0_CNTL, 0x400005);
14918c2ecf20Sopenharmony_ci			WREG32_SMC(LCAC_MC1_CNTL, 0x400005);
14928c2ecf20Sopenharmony_ci			WREG32_SMC(LCAC_CPL_CNTL, 0x500005);
14938c2ecf20Sopenharmony_ci		}
14948c2ecf20Sopenharmony_ci	} else {
14958c2ecf20Sopenharmony_ci		if (!pi->sclk_dpm_key_disabled) {
14968c2ecf20Sopenharmony_ci			smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_DPM_Disable);
14978c2ecf20Sopenharmony_ci			if (smc_result != PPSMC_Result_OK)
14988c2ecf20Sopenharmony_ci				return -EINVAL;
14998c2ecf20Sopenharmony_ci		}
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_ci		if (!pi->mclk_dpm_key_disabled) {
15028c2ecf20Sopenharmony_ci			smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_MCLKDPM_Disable);
15038c2ecf20Sopenharmony_ci			if (smc_result != PPSMC_Result_OK)
15048c2ecf20Sopenharmony_ci				return -EINVAL;
15058c2ecf20Sopenharmony_ci		}
15068c2ecf20Sopenharmony_ci	}
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci	return 0;
15098c2ecf20Sopenharmony_ci}
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_cistatic int ci_start_dpm(struct radeon_device *rdev)
15128c2ecf20Sopenharmony_ci{
15138c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
15148c2ecf20Sopenharmony_ci	PPSMC_Result smc_result;
15158c2ecf20Sopenharmony_ci	int ret;
15168c2ecf20Sopenharmony_ci	u32 tmp;
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci	tmp = RREG32_SMC(GENERAL_PWRMGT);
15198c2ecf20Sopenharmony_ci	tmp |= GLOBAL_PWRMGT_EN;
15208c2ecf20Sopenharmony_ci	WREG32_SMC(GENERAL_PWRMGT, tmp);
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci	tmp = RREG32_SMC(SCLK_PWRMGT_CNTL);
15238c2ecf20Sopenharmony_ci	tmp |= DYNAMIC_PM_EN;
15248c2ecf20Sopenharmony_ci	WREG32_SMC(SCLK_PWRMGT_CNTL, tmp);
15258c2ecf20Sopenharmony_ci
15268c2ecf20Sopenharmony_ci	ci_write_smc_soft_register(rdev, offsetof(SMU7_SoftRegisters, VoltageChangeTimeout), 0x1000);
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci	WREG32_P(BIF_LNCNT_RESET, 0, ~RESET_LNCNT_EN);
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_ci	smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_Voltage_Cntl_Enable);
15318c2ecf20Sopenharmony_ci	if (smc_result != PPSMC_Result_OK)
15328c2ecf20Sopenharmony_ci		return -EINVAL;
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci	ret = ci_enable_sclk_mclk_dpm(rdev, true);
15358c2ecf20Sopenharmony_ci	if (ret)
15368c2ecf20Sopenharmony_ci		return ret;
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci	if (!pi->pcie_dpm_key_disabled) {
15398c2ecf20Sopenharmony_ci		smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_PCIeDPM_Enable);
15408c2ecf20Sopenharmony_ci		if (smc_result != PPSMC_Result_OK)
15418c2ecf20Sopenharmony_ci			return -EINVAL;
15428c2ecf20Sopenharmony_ci	}
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_ci	return 0;
15458c2ecf20Sopenharmony_ci}
15468c2ecf20Sopenharmony_ci
15478c2ecf20Sopenharmony_cistatic int ci_freeze_sclk_mclk_dpm(struct radeon_device *rdev)
15488c2ecf20Sopenharmony_ci{
15498c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
15508c2ecf20Sopenharmony_ci	PPSMC_Result smc_result;
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci	if (!pi->need_update_smu7_dpm_table)
15538c2ecf20Sopenharmony_ci		return 0;
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci	if ((!pi->sclk_dpm_key_disabled) &&
15568c2ecf20Sopenharmony_ci	    (pi->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_UPDATE_SCLK))) {
15578c2ecf20Sopenharmony_ci		smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_SCLKDPM_FreezeLevel);
15588c2ecf20Sopenharmony_ci		if (smc_result != PPSMC_Result_OK)
15598c2ecf20Sopenharmony_ci			return -EINVAL;
15608c2ecf20Sopenharmony_ci	}
15618c2ecf20Sopenharmony_ci
15628c2ecf20Sopenharmony_ci	if ((!pi->mclk_dpm_key_disabled) &&
15638c2ecf20Sopenharmony_ci	    (pi->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)) {
15648c2ecf20Sopenharmony_ci		smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_MCLKDPM_FreezeLevel);
15658c2ecf20Sopenharmony_ci		if (smc_result != PPSMC_Result_OK)
15668c2ecf20Sopenharmony_ci			return -EINVAL;
15678c2ecf20Sopenharmony_ci	}
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci	return 0;
15708c2ecf20Sopenharmony_ci}
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_cistatic int ci_stop_dpm(struct radeon_device *rdev)
15738c2ecf20Sopenharmony_ci{
15748c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
15758c2ecf20Sopenharmony_ci	PPSMC_Result smc_result;
15768c2ecf20Sopenharmony_ci	int ret;
15778c2ecf20Sopenharmony_ci	u32 tmp;
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_ci	tmp = RREG32_SMC(GENERAL_PWRMGT);
15808c2ecf20Sopenharmony_ci	tmp &= ~GLOBAL_PWRMGT_EN;
15818c2ecf20Sopenharmony_ci	WREG32_SMC(GENERAL_PWRMGT, tmp);
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci	tmp = RREG32_SMC(SCLK_PWRMGT_CNTL);
15848c2ecf20Sopenharmony_ci	tmp &= ~DYNAMIC_PM_EN;
15858c2ecf20Sopenharmony_ci	WREG32_SMC(SCLK_PWRMGT_CNTL, tmp);
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_ci	if (!pi->pcie_dpm_key_disabled) {
15888c2ecf20Sopenharmony_ci		smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_PCIeDPM_Disable);
15898c2ecf20Sopenharmony_ci		if (smc_result != PPSMC_Result_OK)
15908c2ecf20Sopenharmony_ci			return -EINVAL;
15918c2ecf20Sopenharmony_ci	}
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ci	ret = ci_enable_sclk_mclk_dpm(rdev, false);
15948c2ecf20Sopenharmony_ci	if (ret)
15958c2ecf20Sopenharmony_ci		return ret;
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci	smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_Voltage_Cntl_Disable);
15988c2ecf20Sopenharmony_ci	if (smc_result != PPSMC_Result_OK)
15998c2ecf20Sopenharmony_ci		return -EINVAL;
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci	return 0;
16028c2ecf20Sopenharmony_ci}
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_cistatic void ci_enable_sclk_control(struct radeon_device *rdev, bool enable)
16058c2ecf20Sopenharmony_ci{
16068c2ecf20Sopenharmony_ci	u32 tmp = RREG32_SMC(SCLK_PWRMGT_CNTL);
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_ci	if (enable)
16098c2ecf20Sopenharmony_ci		tmp &= ~SCLK_PWRMGT_OFF;
16108c2ecf20Sopenharmony_ci	else
16118c2ecf20Sopenharmony_ci		tmp |= SCLK_PWRMGT_OFF;
16128c2ecf20Sopenharmony_ci	WREG32_SMC(SCLK_PWRMGT_CNTL, tmp);
16138c2ecf20Sopenharmony_ci}
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci#if 0
16168c2ecf20Sopenharmony_cistatic int ci_notify_hw_of_power_source(struct radeon_device *rdev,
16178c2ecf20Sopenharmony_ci					bool ac_power)
16188c2ecf20Sopenharmony_ci{
16198c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
16208c2ecf20Sopenharmony_ci	struct radeon_cac_tdp_table *cac_tdp_table =
16218c2ecf20Sopenharmony_ci		rdev->pm.dpm.dyn_state.cac_tdp_table;
16228c2ecf20Sopenharmony_ci	u32 power_limit;
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_ci	if (ac_power)
16258c2ecf20Sopenharmony_ci		power_limit = (u32)(cac_tdp_table->maximum_power_delivery_limit * 256);
16268c2ecf20Sopenharmony_ci	else
16278c2ecf20Sopenharmony_ci		power_limit = (u32)(cac_tdp_table->battery_power_limit * 256);
16288c2ecf20Sopenharmony_ci
16298c2ecf20Sopenharmony_ci	ci_set_power_limit(rdev, power_limit);
16308c2ecf20Sopenharmony_ci
16318c2ecf20Sopenharmony_ci	if (pi->caps_automatic_dc_transition) {
16328c2ecf20Sopenharmony_ci		if (ac_power)
16338c2ecf20Sopenharmony_ci			ci_send_msg_to_smc(rdev, PPSMC_MSG_RunningOnAC);
16348c2ecf20Sopenharmony_ci		else
16358c2ecf20Sopenharmony_ci			ci_send_msg_to_smc(rdev, PPSMC_MSG_Remove_DC_Clamp);
16368c2ecf20Sopenharmony_ci	}
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci	return 0;
16398c2ecf20Sopenharmony_ci}
16408c2ecf20Sopenharmony_ci#endif
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_cistatic PPSMC_Result ci_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg)
16438c2ecf20Sopenharmony_ci{
16448c2ecf20Sopenharmony_ci	u32 tmp;
16458c2ecf20Sopenharmony_ci	int i;
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci	if (!ci_is_smc_running(rdev))
16488c2ecf20Sopenharmony_ci		return PPSMC_Result_Failed;
16498c2ecf20Sopenharmony_ci
16508c2ecf20Sopenharmony_ci	WREG32(SMC_MESSAGE_0, msg);
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_ci	for (i = 0; i < rdev->usec_timeout; i++) {
16538c2ecf20Sopenharmony_ci		tmp = RREG32(SMC_RESP_0);
16548c2ecf20Sopenharmony_ci		if (tmp != 0)
16558c2ecf20Sopenharmony_ci			break;
16568c2ecf20Sopenharmony_ci		udelay(1);
16578c2ecf20Sopenharmony_ci	}
16588c2ecf20Sopenharmony_ci	tmp = RREG32(SMC_RESP_0);
16598c2ecf20Sopenharmony_ci
16608c2ecf20Sopenharmony_ci	return (PPSMC_Result)tmp;
16618c2ecf20Sopenharmony_ci}
16628c2ecf20Sopenharmony_ci
16638c2ecf20Sopenharmony_cistatic PPSMC_Result ci_send_msg_to_smc_with_parameter(struct radeon_device *rdev,
16648c2ecf20Sopenharmony_ci						      PPSMC_Msg msg, u32 parameter)
16658c2ecf20Sopenharmony_ci{
16668c2ecf20Sopenharmony_ci	WREG32(SMC_MSG_ARG_0, parameter);
16678c2ecf20Sopenharmony_ci	return ci_send_msg_to_smc(rdev, msg);
16688c2ecf20Sopenharmony_ci}
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_cistatic PPSMC_Result ci_send_msg_to_smc_return_parameter(struct radeon_device *rdev,
16718c2ecf20Sopenharmony_ci							PPSMC_Msg msg, u32 *parameter)
16728c2ecf20Sopenharmony_ci{
16738c2ecf20Sopenharmony_ci	PPSMC_Result smc_result;
16748c2ecf20Sopenharmony_ci
16758c2ecf20Sopenharmony_ci	smc_result = ci_send_msg_to_smc(rdev, msg);
16768c2ecf20Sopenharmony_ci
16778c2ecf20Sopenharmony_ci	if ((smc_result == PPSMC_Result_OK) && parameter)
16788c2ecf20Sopenharmony_ci		*parameter = RREG32(SMC_MSG_ARG_0);
16798c2ecf20Sopenharmony_ci
16808c2ecf20Sopenharmony_ci	return smc_result;
16818c2ecf20Sopenharmony_ci}
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_cistatic int ci_dpm_force_state_sclk(struct radeon_device *rdev, u32 n)
16848c2ecf20Sopenharmony_ci{
16858c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci	if (!pi->sclk_dpm_key_disabled) {
16888c2ecf20Sopenharmony_ci		PPSMC_Result smc_result =
16898c2ecf20Sopenharmony_ci			ci_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SCLKDPM_SetEnabledMask, 1 << n);
16908c2ecf20Sopenharmony_ci		if (smc_result != PPSMC_Result_OK)
16918c2ecf20Sopenharmony_ci			return -EINVAL;
16928c2ecf20Sopenharmony_ci	}
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_ci	return 0;
16958c2ecf20Sopenharmony_ci}
16968c2ecf20Sopenharmony_ci
16978c2ecf20Sopenharmony_cistatic int ci_dpm_force_state_mclk(struct radeon_device *rdev, u32 n)
16988c2ecf20Sopenharmony_ci{
16998c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ci	if (!pi->mclk_dpm_key_disabled) {
17028c2ecf20Sopenharmony_ci		PPSMC_Result smc_result =
17038c2ecf20Sopenharmony_ci			ci_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_MCLKDPM_SetEnabledMask, 1 << n);
17048c2ecf20Sopenharmony_ci		if (smc_result != PPSMC_Result_OK)
17058c2ecf20Sopenharmony_ci			return -EINVAL;
17068c2ecf20Sopenharmony_ci	}
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci	return 0;
17098c2ecf20Sopenharmony_ci}
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_cistatic int ci_dpm_force_state_pcie(struct radeon_device *rdev, u32 n)
17128c2ecf20Sopenharmony_ci{
17138c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_ci	if (!pi->pcie_dpm_key_disabled) {
17168c2ecf20Sopenharmony_ci		PPSMC_Result smc_result =
17178c2ecf20Sopenharmony_ci			ci_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_PCIeDPM_ForceLevel, n);
17188c2ecf20Sopenharmony_ci		if (smc_result != PPSMC_Result_OK)
17198c2ecf20Sopenharmony_ci			return -EINVAL;
17208c2ecf20Sopenharmony_ci	}
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_ci	return 0;
17238c2ecf20Sopenharmony_ci}
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_cistatic int ci_set_power_limit(struct radeon_device *rdev, u32 n)
17268c2ecf20Sopenharmony_ci{
17278c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
17288c2ecf20Sopenharmony_ci
17298c2ecf20Sopenharmony_ci	if (pi->power_containment_features & POWERCONTAINMENT_FEATURE_PkgPwrLimit) {
17308c2ecf20Sopenharmony_ci		PPSMC_Result smc_result =
17318c2ecf20Sopenharmony_ci			ci_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_PkgPwrSetLimit, n);
17328c2ecf20Sopenharmony_ci		if (smc_result != PPSMC_Result_OK)
17338c2ecf20Sopenharmony_ci			return -EINVAL;
17348c2ecf20Sopenharmony_ci	}
17358c2ecf20Sopenharmony_ci
17368c2ecf20Sopenharmony_ci	return 0;
17378c2ecf20Sopenharmony_ci}
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_cistatic int ci_set_overdrive_target_tdp(struct radeon_device *rdev,
17408c2ecf20Sopenharmony_ci				       u32 target_tdp)
17418c2ecf20Sopenharmony_ci{
17428c2ecf20Sopenharmony_ci	PPSMC_Result smc_result =
17438c2ecf20Sopenharmony_ci		ci_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_OverDriveSetTargetTdp, target_tdp);
17448c2ecf20Sopenharmony_ci	if (smc_result != PPSMC_Result_OK)
17458c2ecf20Sopenharmony_ci		return -EINVAL;
17468c2ecf20Sopenharmony_ci	return 0;
17478c2ecf20Sopenharmony_ci}
17488c2ecf20Sopenharmony_ci
17498c2ecf20Sopenharmony_ci#if 0
17508c2ecf20Sopenharmony_cistatic int ci_set_boot_state(struct radeon_device *rdev)
17518c2ecf20Sopenharmony_ci{
17528c2ecf20Sopenharmony_ci	return ci_enable_sclk_mclk_dpm(rdev, false);
17538c2ecf20Sopenharmony_ci}
17548c2ecf20Sopenharmony_ci#endif
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_cistatic u32 ci_get_average_sclk_freq(struct radeon_device *rdev)
17578c2ecf20Sopenharmony_ci{
17588c2ecf20Sopenharmony_ci	u32 sclk_freq;
17598c2ecf20Sopenharmony_ci	PPSMC_Result smc_result =
17608c2ecf20Sopenharmony_ci		ci_send_msg_to_smc_return_parameter(rdev,
17618c2ecf20Sopenharmony_ci						    PPSMC_MSG_API_GetSclkFrequency,
17628c2ecf20Sopenharmony_ci						    &sclk_freq);
17638c2ecf20Sopenharmony_ci	if (smc_result != PPSMC_Result_OK)
17648c2ecf20Sopenharmony_ci		sclk_freq = 0;
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_ci	return sclk_freq;
17678c2ecf20Sopenharmony_ci}
17688c2ecf20Sopenharmony_ci
17698c2ecf20Sopenharmony_cistatic u32 ci_get_average_mclk_freq(struct radeon_device *rdev)
17708c2ecf20Sopenharmony_ci{
17718c2ecf20Sopenharmony_ci	u32 mclk_freq;
17728c2ecf20Sopenharmony_ci	PPSMC_Result smc_result =
17738c2ecf20Sopenharmony_ci		ci_send_msg_to_smc_return_parameter(rdev,
17748c2ecf20Sopenharmony_ci						    PPSMC_MSG_API_GetMclkFrequency,
17758c2ecf20Sopenharmony_ci						    &mclk_freq);
17768c2ecf20Sopenharmony_ci	if (smc_result != PPSMC_Result_OK)
17778c2ecf20Sopenharmony_ci		mclk_freq = 0;
17788c2ecf20Sopenharmony_ci
17798c2ecf20Sopenharmony_ci	return mclk_freq;
17808c2ecf20Sopenharmony_ci}
17818c2ecf20Sopenharmony_ci
17828c2ecf20Sopenharmony_cistatic void ci_dpm_start_smc(struct radeon_device *rdev)
17838c2ecf20Sopenharmony_ci{
17848c2ecf20Sopenharmony_ci	int i;
17858c2ecf20Sopenharmony_ci
17868c2ecf20Sopenharmony_ci	ci_program_jump_on_start(rdev);
17878c2ecf20Sopenharmony_ci	ci_start_smc_clock(rdev);
17888c2ecf20Sopenharmony_ci	ci_start_smc(rdev);
17898c2ecf20Sopenharmony_ci	for (i = 0; i < rdev->usec_timeout; i++) {
17908c2ecf20Sopenharmony_ci		if (RREG32_SMC(FIRMWARE_FLAGS) & INTERRUPTS_ENABLED)
17918c2ecf20Sopenharmony_ci			break;
17928c2ecf20Sopenharmony_ci	}
17938c2ecf20Sopenharmony_ci}
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_cistatic void ci_dpm_stop_smc(struct radeon_device *rdev)
17968c2ecf20Sopenharmony_ci{
17978c2ecf20Sopenharmony_ci	ci_reset_smc(rdev);
17988c2ecf20Sopenharmony_ci	ci_stop_smc_clock(rdev);
17998c2ecf20Sopenharmony_ci}
18008c2ecf20Sopenharmony_ci
18018c2ecf20Sopenharmony_cistatic int ci_process_firmware_header(struct radeon_device *rdev)
18028c2ecf20Sopenharmony_ci{
18038c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
18048c2ecf20Sopenharmony_ci	u32 tmp;
18058c2ecf20Sopenharmony_ci	int ret;
18068c2ecf20Sopenharmony_ci
18078c2ecf20Sopenharmony_ci	ret = ci_read_smc_sram_dword(rdev,
18088c2ecf20Sopenharmony_ci				     SMU7_FIRMWARE_HEADER_LOCATION +
18098c2ecf20Sopenharmony_ci				     offsetof(SMU7_Firmware_Header, DpmTable),
18108c2ecf20Sopenharmony_ci				     &tmp, pi->sram_end);
18118c2ecf20Sopenharmony_ci	if (ret)
18128c2ecf20Sopenharmony_ci		return ret;
18138c2ecf20Sopenharmony_ci
18148c2ecf20Sopenharmony_ci	pi->dpm_table_start = tmp;
18158c2ecf20Sopenharmony_ci
18168c2ecf20Sopenharmony_ci	ret = ci_read_smc_sram_dword(rdev,
18178c2ecf20Sopenharmony_ci				     SMU7_FIRMWARE_HEADER_LOCATION +
18188c2ecf20Sopenharmony_ci				     offsetof(SMU7_Firmware_Header, SoftRegisters),
18198c2ecf20Sopenharmony_ci				     &tmp, pi->sram_end);
18208c2ecf20Sopenharmony_ci	if (ret)
18218c2ecf20Sopenharmony_ci		return ret;
18228c2ecf20Sopenharmony_ci
18238c2ecf20Sopenharmony_ci	pi->soft_regs_start = tmp;
18248c2ecf20Sopenharmony_ci
18258c2ecf20Sopenharmony_ci	ret = ci_read_smc_sram_dword(rdev,
18268c2ecf20Sopenharmony_ci				     SMU7_FIRMWARE_HEADER_LOCATION +
18278c2ecf20Sopenharmony_ci				     offsetof(SMU7_Firmware_Header, mcRegisterTable),
18288c2ecf20Sopenharmony_ci				     &tmp, pi->sram_end);
18298c2ecf20Sopenharmony_ci	if (ret)
18308c2ecf20Sopenharmony_ci		return ret;
18318c2ecf20Sopenharmony_ci
18328c2ecf20Sopenharmony_ci	pi->mc_reg_table_start = tmp;
18338c2ecf20Sopenharmony_ci
18348c2ecf20Sopenharmony_ci	ret = ci_read_smc_sram_dword(rdev,
18358c2ecf20Sopenharmony_ci				     SMU7_FIRMWARE_HEADER_LOCATION +
18368c2ecf20Sopenharmony_ci				     offsetof(SMU7_Firmware_Header, FanTable),
18378c2ecf20Sopenharmony_ci				     &tmp, pi->sram_end);
18388c2ecf20Sopenharmony_ci	if (ret)
18398c2ecf20Sopenharmony_ci		return ret;
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_ci	pi->fan_table_start = tmp;
18428c2ecf20Sopenharmony_ci
18438c2ecf20Sopenharmony_ci	ret = ci_read_smc_sram_dword(rdev,
18448c2ecf20Sopenharmony_ci				     SMU7_FIRMWARE_HEADER_LOCATION +
18458c2ecf20Sopenharmony_ci				     offsetof(SMU7_Firmware_Header, mcArbDramTimingTable),
18468c2ecf20Sopenharmony_ci				     &tmp, pi->sram_end);
18478c2ecf20Sopenharmony_ci	if (ret)
18488c2ecf20Sopenharmony_ci		return ret;
18498c2ecf20Sopenharmony_ci
18508c2ecf20Sopenharmony_ci	pi->arb_table_start = tmp;
18518c2ecf20Sopenharmony_ci
18528c2ecf20Sopenharmony_ci	return 0;
18538c2ecf20Sopenharmony_ci}
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_cistatic void ci_read_clock_registers(struct radeon_device *rdev)
18568c2ecf20Sopenharmony_ci{
18578c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
18588c2ecf20Sopenharmony_ci
18598c2ecf20Sopenharmony_ci	pi->clock_registers.cg_spll_func_cntl =
18608c2ecf20Sopenharmony_ci		RREG32_SMC(CG_SPLL_FUNC_CNTL);
18618c2ecf20Sopenharmony_ci	pi->clock_registers.cg_spll_func_cntl_2 =
18628c2ecf20Sopenharmony_ci		RREG32_SMC(CG_SPLL_FUNC_CNTL_2);
18638c2ecf20Sopenharmony_ci	pi->clock_registers.cg_spll_func_cntl_3 =
18648c2ecf20Sopenharmony_ci		RREG32_SMC(CG_SPLL_FUNC_CNTL_3);
18658c2ecf20Sopenharmony_ci	pi->clock_registers.cg_spll_func_cntl_4 =
18668c2ecf20Sopenharmony_ci		RREG32_SMC(CG_SPLL_FUNC_CNTL_4);
18678c2ecf20Sopenharmony_ci	pi->clock_registers.cg_spll_spread_spectrum =
18688c2ecf20Sopenharmony_ci		RREG32_SMC(CG_SPLL_SPREAD_SPECTRUM);
18698c2ecf20Sopenharmony_ci	pi->clock_registers.cg_spll_spread_spectrum_2 =
18708c2ecf20Sopenharmony_ci		RREG32_SMC(CG_SPLL_SPREAD_SPECTRUM_2);
18718c2ecf20Sopenharmony_ci	pi->clock_registers.dll_cntl = RREG32(DLL_CNTL);
18728c2ecf20Sopenharmony_ci	pi->clock_registers.mclk_pwrmgt_cntl = RREG32(MCLK_PWRMGT_CNTL);
18738c2ecf20Sopenharmony_ci	pi->clock_registers.mpll_ad_func_cntl = RREG32(MPLL_AD_FUNC_CNTL);
18748c2ecf20Sopenharmony_ci	pi->clock_registers.mpll_dq_func_cntl = RREG32(MPLL_DQ_FUNC_CNTL);
18758c2ecf20Sopenharmony_ci	pi->clock_registers.mpll_func_cntl = RREG32(MPLL_FUNC_CNTL);
18768c2ecf20Sopenharmony_ci	pi->clock_registers.mpll_func_cntl_1 = RREG32(MPLL_FUNC_CNTL_1);
18778c2ecf20Sopenharmony_ci	pi->clock_registers.mpll_func_cntl_2 = RREG32(MPLL_FUNC_CNTL_2);
18788c2ecf20Sopenharmony_ci	pi->clock_registers.mpll_ss1 = RREG32(MPLL_SS1);
18798c2ecf20Sopenharmony_ci	pi->clock_registers.mpll_ss2 = RREG32(MPLL_SS2);
18808c2ecf20Sopenharmony_ci}
18818c2ecf20Sopenharmony_ci
18828c2ecf20Sopenharmony_cistatic void ci_init_sclk_t(struct radeon_device *rdev)
18838c2ecf20Sopenharmony_ci{
18848c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
18858c2ecf20Sopenharmony_ci
18868c2ecf20Sopenharmony_ci	pi->low_sclk_interrupt_t = 0;
18878c2ecf20Sopenharmony_ci}
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_cistatic void ci_enable_thermal_protection(struct radeon_device *rdev,
18908c2ecf20Sopenharmony_ci					 bool enable)
18918c2ecf20Sopenharmony_ci{
18928c2ecf20Sopenharmony_ci	u32 tmp = RREG32_SMC(GENERAL_PWRMGT);
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_ci	if (enable)
18958c2ecf20Sopenharmony_ci		tmp &= ~THERMAL_PROTECTION_DIS;
18968c2ecf20Sopenharmony_ci	else
18978c2ecf20Sopenharmony_ci		tmp |= THERMAL_PROTECTION_DIS;
18988c2ecf20Sopenharmony_ci	WREG32_SMC(GENERAL_PWRMGT, tmp);
18998c2ecf20Sopenharmony_ci}
19008c2ecf20Sopenharmony_ci
19018c2ecf20Sopenharmony_cistatic void ci_enable_acpi_power_management(struct radeon_device *rdev)
19028c2ecf20Sopenharmony_ci{
19038c2ecf20Sopenharmony_ci	u32 tmp = RREG32_SMC(GENERAL_PWRMGT);
19048c2ecf20Sopenharmony_ci
19058c2ecf20Sopenharmony_ci	tmp |= STATIC_PM_EN;
19068c2ecf20Sopenharmony_ci
19078c2ecf20Sopenharmony_ci	WREG32_SMC(GENERAL_PWRMGT, tmp);
19088c2ecf20Sopenharmony_ci}
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_ci#if 0
19118c2ecf20Sopenharmony_cistatic int ci_enter_ulp_state(struct radeon_device *rdev)
19128c2ecf20Sopenharmony_ci{
19138c2ecf20Sopenharmony_ci
19148c2ecf20Sopenharmony_ci	WREG32(SMC_MESSAGE_0, PPSMC_MSG_SwitchToMinimumPower);
19158c2ecf20Sopenharmony_ci
19168c2ecf20Sopenharmony_ci	udelay(25000);
19178c2ecf20Sopenharmony_ci
19188c2ecf20Sopenharmony_ci	return 0;
19198c2ecf20Sopenharmony_ci}
19208c2ecf20Sopenharmony_ci
19218c2ecf20Sopenharmony_cistatic int ci_exit_ulp_state(struct radeon_device *rdev)
19228c2ecf20Sopenharmony_ci{
19238c2ecf20Sopenharmony_ci	int i;
19248c2ecf20Sopenharmony_ci
19258c2ecf20Sopenharmony_ci	WREG32(SMC_MESSAGE_0, PPSMC_MSG_ResumeFromMinimumPower);
19268c2ecf20Sopenharmony_ci
19278c2ecf20Sopenharmony_ci	udelay(7000);
19288c2ecf20Sopenharmony_ci
19298c2ecf20Sopenharmony_ci	for (i = 0; i < rdev->usec_timeout; i++) {
19308c2ecf20Sopenharmony_ci		if (RREG32(SMC_RESP_0) == 1)
19318c2ecf20Sopenharmony_ci			break;
19328c2ecf20Sopenharmony_ci		udelay(1000);
19338c2ecf20Sopenharmony_ci	}
19348c2ecf20Sopenharmony_ci
19358c2ecf20Sopenharmony_ci	return 0;
19368c2ecf20Sopenharmony_ci}
19378c2ecf20Sopenharmony_ci#endif
19388c2ecf20Sopenharmony_ci
19398c2ecf20Sopenharmony_cistatic int ci_notify_smc_display_change(struct radeon_device *rdev,
19408c2ecf20Sopenharmony_ci					bool has_display)
19418c2ecf20Sopenharmony_ci{
19428c2ecf20Sopenharmony_ci	PPSMC_Msg msg = has_display ? PPSMC_MSG_HasDisplay : PPSMC_MSG_NoDisplay;
19438c2ecf20Sopenharmony_ci
19448c2ecf20Sopenharmony_ci	return (ci_send_msg_to_smc(rdev, msg) == PPSMC_Result_OK) ?  0 : -EINVAL;
19458c2ecf20Sopenharmony_ci}
19468c2ecf20Sopenharmony_ci
19478c2ecf20Sopenharmony_cistatic int ci_enable_ds_master_switch(struct radeon_device *rdev,
19488c2ecf20Sopenharmony_ci				      bool enable)
19498c2ecf20Sopenharmony_ci{
19508c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
19518c2ecf20Sopenharmony_ci
19528c2ecf20Sopenharmony_ci	if (enable) {
19538c2ecf20Sopenharmony_ci		if (pi->caps_sclk_ds) {
19548c2ecf20Sopenharmony_ci			if (ci_send_msg_to_smc(rdev, PPSMC_MSG_MASTER_DeepSleep_ON) != PPSMC_Result_OK)
19558c2ecf20Sopenharmony_ci				return -EINVAL;
19568c2ecf20Sopenharmony_ci		} else {
19578c2ecf20Sopenharmony_ci			if (ci_send_msg_to_smc(rdev, PPSMC_MSG_MASTER_DeepSleep_OFF) != PPSMC_Result_OK)
19588c2ecf20Sopenharmony_ci				return -EINVAL;
19598c2ecf20Sopenharmony_ci		}
19608c2ecf20Sopenharmony_ci	} else {
19618c2ecf20Sopenharmony_ci		if (pi->caps_sclk_ds) {
19628c2ecf20Sopenharmony_ci			if (ci_send_msg_to_smc(rdev, PPSMC_MSG_MASTER_DeepSleep_OFF) != PPSMC_Result_OK)
19638c2ecf20Sopenharmony_ci				return -EINVAL;
19648c2ecf20Sopenharmony_ci		}
19658c2ecf20Sopenharmony_ci	}
19668c2ecf20Sopenharmony_ci
19678c2ecf20Sopenharmony_ci	return 0;
19688c2ecf20Sopenharmony_ci}
19698c2ecf20Sopenharmony_ci
19708c2ecf20Sopenharmony_cistatic void ci_program_display_gap(struct radeon_device *rdev)
19718c2ecf20Sopenharmony_ci{
19728c2ecf20Sopenharmony_ci	u32 tmp = RREG32_SMC(CG_DISPLAY_GAP_CNTL);
19738c2ecf20Sopenharmony_ci	u32 pre_vbi_time_in_us;
19748c2ecf20Sopenharmony_ci	u32 frame_time_in_us;
19758c2ecf20Sopenharmony_ci	u32 ref_clock = rdev->clock.spll.reference_freq;
19768c2ecf20Sopenharmony_ci	u32 refresh_rate = r600_dpm_get_vrefresh(rdev);
19778c2ecf20Sopenharmony_ci	u32 vblank_time = r600_dpm_get_vblank_time(rdev);
19788c2ecf20Sopenharmony_ci
19798c2ecf20Sopenharmony_ci	tmp &= ~DISP_GAP_MASK;
19808c2ecf20Sopenharmony_ci	if (rdev->pm.dpm.new_active_crtc_count > 0)
19818c2ecf20Sopenharmony_ci		tmp |= DISP_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM);
19828c2ecf20Sopenharmony_ci	else
19838c2ecf20Sopenharmony_ci		tmp |= DISP_GAP(R600_PM_DISPLAY_GAP_IGNORE);
19848c2ecf20Sopenharmony_ci	WREG32_SMC(CG_DISPLAY_GAP_CNTL, tmp);
19858c2ecf20Sopenharmony_ci
19868c2ecf20Sopenharmony_ci	if (refresh_rate == 0)
19878c2ecf20Sopenharmony_ci		refresh_rate = 60;
19888c2ecf20Sopenharmony_ci	if (vblank_time == 0xffffffff)
19898c2ecf20Sopenharmony_ci		vblank_time = 500;
19908c2ecf20Sopenharmony_ci	frame_time_in_us = 1000000 / refresh_rate;
19918c2ecf20Sopenharmony_ci	pre_vbi_time_in_us =
19928c2ecf20Sopenharmony_ci		frame_time_in_us - 200 - vblank_time;
19938c2ecf20Sopenharmony_ci	tmp = pre_vbi_time_in_us * (ref_clock / 100);
19948c2ecf20Sopenharmony_ci
19958c2ecf20Sopenharmony_ci	WREG32_SMC(CG_DISPLAY_GAP_CNTL2, tmp);
19968c2ecf20Sopenharmony_ci	ci_write_smc_soft_register(rdev, offsetof(SMU7_SoftRegisters, PreVBlankGap), 0x64);
19978c2ecf20Sopenharmony_ci	ci_write_smc_soft_register(rdev, offsetof(SMU7_SoftRegisters, VBlankTimeout), (frame_time_in_us - pre_vbi_time_in_us));
19988c2ecf20Sopenharmony_ci
19998c2ecf20Sopenharmony_ci
20008c2ecf20Sopenharmony_ci	ci_notify_smc_display_change(rdev, (rdev->pm.dpm.new_active_crtc_count == 1));
20018c2ecf20Sopenharmony_ci
20028c2ecf20Sopenharmony_ci}
20038c2ecf20Sopenharmony_ci
20048c2ecf20Sopenharmony_cistatic void ci_enable_spread_spectrum(struct radeon_device *rdev, bool enable)
20058c2ecf20Sopenharmony_ci{
20068c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
20078c2ecf20Sopenharmony_ci	u32 tmp;
20088c2ecf20Sopenharmony_ci
20098c2ecf20Sopenharmony_ci	if (enable) {
20108c2ecf20Sopenharmony_ci		if (pi->caps_sclk_ss_support) {
20118c2ecf20Sopenharmony_ci			tmp = RREG32_SMC(GENERAL_PWRMGT);
20128c2ecf20Sopenharmony_ci			tmp |= DYN_SPREAD_SPECTRUM_EN;
20138c2ecf20Sopenharmony_ci			WREG32_SMC(GENERAL_PWRMGT, tmp);
20148c2ecf20Sopenharmony_ci		}
20158c2ecf20Sopenharmony_ci	} else {
20168c2ecf20Sopenharmony_ci		tmp = RREG32_SMC(CG_SPLL_SPREAD_SPECTRUM);
20178c2ecf20Sopenharmony_ci		tmp &= ~SSEN;
20188c2ecf20Sopenharmony_ci		WREG32_SMC(CG_SPLL_SPREAD_SPECTRUM, tmp);
20198c2ecf20Sopenharmony_ci
20208c2ecf20Sopenharmony_ci		tmp = RREG32_SMC(GENERAL_PWRMGT);
20218c2ecf20Sopenharmony_ci		tmp &= ~DYN_SPREAD_SPECTRUM_EN;
20228c2ecf20Sopenharmony_ci		WREG32_SMC(GENERAL_PWRMGT, tmp);
20238c2ecf20Sopenharmony_ci	}
20248c2ecf20Sopenharmony_ci}
20258c2ecf20Sopenharmony_ci
20268c2ecf20Sopenharmony_cistatic void ci_program_sstp(struct radeon_device *rdev)
20278c2ecf20Sopenharmony_ci{
20288c2ecf20Sopenharmony_ci	WREG32_SMC(CG_SSP, (SSTU(R600_SSTU_DFLT) | SST(R600_SST_DFLT)));
20298c2ecf20Sopenharmony_ci}
20308c2ecf20Sopenharmony_ci
20318c2ecf20Sopenharmony_cistatic void ci_enable_display_gap(struct radeon_device *rdev)
20328c2ecf20Sopenharmony_ci{
20338c2ecf20Sopenharmony_ci	u32 tmp = RREG32_SMC(CG_DISPLAY_GAP_CNTL);
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_ci	tmp &= ~(DISP_GAP_MASK | DISP_GAP_MCHG_MASK);
20368c2ecf20Sopenharmony_ci	tmp |= (DISP_GAP(R600_PM_DISPLAY_GAP_IGNORE) |
20378c2ecf20Sopenharmony_ci		DISP_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK));
20388c2ecf20Sopenharmony_ci
20398c2ecf20Sopenharmony_ci	WREG32_SMC(CG_DISPLAY_GAP_CNTL, tmp);
20408c2ecf20Sopenharmony_ci}
20418c2ecf20Sopenharmony_ci
20428c2ecf20Sopenharmony_cistatic void ci_program_vc(struct radeon_device *rdev)
20438c2ecf20Sopenharmony_ci{
20448c2ecf20Sopenharmony_ci	u32 tmp;
20458c2ecf20Sopenharmony_ci
20468c2ecf20Sopenharmony_ci	tmp = RREG32_SMC(SCLK_PWRMGT_CNTL);
20478c2ecf20Sopenharmony_ci	tmp &= ~(RESET_SCLK_CNT | RESET_BUSY_CNT);
20488c2ecf20Sopenharmony_ci	WREG32_SMC(SCLK_PWRMGT_CNTL, tmp);
20498c2ecf20Sopenharmony_ci
20508c2ecf20Sopenharmony_ci	WREG32_SMC(CG_FTV_0, CISLANDS_VRC_DFLT0);
20518c2ecf20Sopenharmony_ci	WREG32_SMC(CG_FTV_1, CISLANDS_VRC_DFLT1);
20528c2ecf20Sopenharmony_ci	WREG32_SMC(CG_FTV_2, CISLANDS_VRC_DFLT2);
20538c2ecf20Sopenharmony_ci	WREG32_SMC(CG_FTV_3, CISLANDS_VRC_DFLT3);
20548c2ecf20Sopenharmony_ci	WREG32_SMC(CG_FTV_4, CISLANDS_VRC_DFLT4);
20558c2ecf20Sopenharmony_ci	WREG32_SMC(CG_FTV_5, CISLANDS_VRC_DFLT5);
20568c2ecf20Sopenharmony_ci	WREG32_SMC(CG_FTV_6, CISLANDS_VRC_DFLT6);
20578c2ecf20Sopenharmony_ci	WREG32_SMC(CG_FTV_7, CISLANDS_VRC_DFLT7);
20588c2ecf20Sopenharmony_ci}
20598c2ecf20Sopenharmony_ci
20608c2ecf20Sopenharmony_cistatic void ci_clear_vc(struct radeon_device *rdev)
20618c2ecf20Sopenharmony_ci{
20628c2ecf20Sopenharmony_ci	u32 tmp;
20638c2ecf20Sopenharmony_ci
20648c2ecf20Sopenharmony_ci	tmp = RREG32_SMC(SCLK_PWRMGT_CNTL);
20658c2ecf20Sopenharmony_ci	tmp |= (RESET_SCLK_CNT | RESET_BUSY_CNT);
20668c2ecf20Sopenharmony_ci	WREG32_SMC(SCLK_PWRMGT_CNTL, tmp);
20678c2ecf20Sopenharmony_ci
20688c2ecf20Sopenharmony_ci	WREG32_SMC(CG_FTV_0, 0);
20698c2ecf20Sopenharmony_ci	WREG32_SMC(CG_FTV_1, 0);
20708c2ecf20Sopenharmony_ci	WREG32_SMC(CG_FTV_2, 0);
20718c2ecf20Sopenharmony_ci	WREG32_SMC(CG_FTV_3, 0);
20728c2ecf20Sopenharmony_ci	WREG32_SMC(CG_FTV_4, 0);
20738c2ecf20Sopenharmony_ci	WREG32_SMC(CG_FTV_5, 0);
20748c2ecf20Sopenharmony_ci	WREG32_SMC(CG_FTV_6, 0);
20758c2ecf20Sopenharmony_ci	WREG32_SMC(CG_FTV_7, 0);
20768c2ecf20Sopenharmony_ci}
20778c2ecf20Sopenharmony_ci
20788c2ecf20Sopenharmony_cistatic int ci_upload_firmware(struct radeon_device *rdev)
20798c2ecf20Sopenharmony_ci{
20808c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
20818c2ecf20Sopenharmony_ci	int i, ret;
20828c2ecf20Sopenharmony_ci
20838c2ecf20Sopenharmony_ci	for (i = 0; i < rdev->usec_timeout; i++) {
20848c2ecf20Sopenharmony_ci		if (RREG32_SMC(RCU_UC_EVENTS) & BOOT_SEQ_DONE)
20858c2ecf20Sopenharmony_ci			break;
20868c2ecf20Sopenharmony_ci	}
20878c2ecf20Sopenharmony_ci	WREG32_SMC(SMC_SYSCON_MISC_CNTL, 1);
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_ci	ci_stop_smc_clock(rdev);
20908c2ecf20Sopenharmony_ci	ci_reset_smc(rdev);
20918c2ecf20Sopenharmony_ci
20928c2ecf20Sopenharmony_ci	ret = ci_load_smc_ucode(rdev, pi->sram_end);
20938c2ecf20Sopenharmony_ci
20948c2ecf20Sopenharmony_ci	return ret;
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_ci}
20978c2ecf20Sopenharmony_ci
20988c2ecf20Sopenharmony_cistatic int ci_get_svi2_voltage_table(struct radeon_device *rdev,
20998c2ecf20Sopenharmony_ci				     struct radeon_clock_voltage_dependency_table *voltage_dependency_table,
21008c2ecf20Sopenharmony_ci				     struct atom_voltage_table *voltage_table)
21018c2ecf20Sopenharmony_ci{
21028c2ecf20Sopenharmony_ci	u32 i;
21038c2ecf20Sopenharmony_ci
21048c2ecf20Sopenharmony_ci	if (voltage_dependency_table == NULL)
21058c2ecf20Sopenharmony_ci		return -EINVAL;
21068c2ecf20Sopenharmony_ci
21078c2ecf20Sopenharmony_ci	voltage_table->mask_low = 0;
21088c2ecf20Sopenharmony_ci	voltage_table->phase_delay = 0;
21098c2ecf20Sopenharmony_ci
21108c2ecf20Sopenharmony_ci	voltage_table->count = voltage_dependency_table->count;
21118c2ecf20Sopenharmony_ci	for (i = 0; i < voltage_table->count; i++) {
21128c2ecf20Sopenharmony_ci		voltage_table->entries[i].value = voltage_dependency_table->entries[i].v;
21138c2ecf20Sopenharmony_ci		voltage_table->entries[i].smio_low = 0;
21148c2ecf20Sopenharmony_ci	}
21158c2ecf20Sopenharmony_ci
21168c2ecf20Sopenharmony_ci	return 0;
21178c2ecf20Sopenharmony_ci}
21188c2ecf20Sopenharmony_ci
21198c2ecf20Sopenharmony_cistatic int ci_construct_voltage_tables(struct radeon_device *rdev)
21208c2ecf20Sopenharmony_ci{
21218c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
21228c2ecf20Sopenharmony_ci	int ret;
21238c2ecf20Sopenharmony_ci
21248c2ecf20Sopenharmony_ci	if (pi->voltage_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO) {
21258c2ecf20Sopenharmony_ci		ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_VDDC,
21268c2ecf20Sopenharmony_ci						    VOLTAGE_OBJ_GPIO_LUT,
21278c2ecf20Sopenharmony_ci						    &pi->vddc_voltage_table);
21288c2ecf20Sopenharmony_ci		if (ret)
21298c2ecf20Sopenharmony_ci			return ret;
21308c2ecf20Sopenharmony_ci	} else if (pi->voltage_control == CISLANDS_VOLTAGE_CONTROL_BY_SVID2) {
21318c2ecf20Sopenharmony_ci		ret = ci_get_svi2_voltage_table(rdev,
21328c2ecf20Sopenharmony_ci						&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
21338c2ecf20Sopenharmony_ci						&pi->vddc_voltage_table);
21348c2ecf20Sopenharmony_ci		if (ret)
21358c2ecf20Sopenharmony_ci			return ret;
21368c2ecf20Sopenharmony_ci	}
21378c2ecf20Sopenharmony_ci
21388c2ecf20Sopenharmony_ci	if (pi->vddc_voltage_table.count > SMU7_MAX_LEVELS_VDDC)
21398c2ecf20Sopenharmony_ci		si_trim_voltage_table_to_fit_state_table(rdev, SMU7_MAX_LEVELS_VDDC,
21408c2ecf20Sopenharmony_ci							 &pi->vddc_voltage_table);
21418c2ecf20Sopenharmony_ci
21428c2ecf20Sopenharmony_ci	if (pi->vddci_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO) {
21438c2ecf20Sopenharmony_ci		ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_VDDCI,
21448c2ecf20Sopenharmony_ci						    VOLTAGE_OBJ_GPIO_LUT,
21458c2ecf20Sopenharmony_ci						    &pi->vddci_voltage_table);
21468c2ecf20Sopenharmony_ci		if (ret)
21478c2ecf20Sopenharmony_ci			return ret;
21488c2ecf20Sopenharmony_ci	} else if (pi->vddci_control == CISLANDS_VOLTAGE_CONTROL_BY_SVID2) {
21498c2ecf20Sopenharmony_ci		ret = ci_get_svi2_voltage_table(rdev,
21508c2ecf20Sopenharmony_ci						&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
21518c2ecf20Sopenharmony_ci						&pi->vddci_voltage_table);
21528c2ecf20Sopenharmony_ci		if (ret)
21538c2ecf20Sopenharmony_ci			return ret;
21548c2ecf20Sopenharmony_ci	}
21558c2ecf20Sopenharmony_ci
21568c2ecf20Sopenharmony_ci	if (pi->vddci_voltage_table.count > SMU7_MAX_LEVELS_VDDCI)
21578c2ecf20Sopenharmony_ci		si_trim_voltage_table_to_fit_state_table(rdev, SMU7_MAX_LEVELS_VDDCI,
21588c2ecf20Sopenharmony_ci							 &pi->vddci_voltage_table);
21598c2ecf20Sopenharmony_ci
21608c2ecf20Sopenharmony_ci	if (pi->mvdd_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO) {
21618c2ecf20Sopenharmony_ci		ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_MVDDC,
21628c2ecf20Sopenharmony_ci						    VOLTAGE_OBJ_GPIO_LUT,
21638c2ecf20Sopenharmony_ci						    &pi->mvdd_voltage_table);
21648c2ecf20Sopenharmony_ci		if (ret)
21658c2ecf20Sopenharmony_ci			return ret;
21668c2ecf20Sopenharmony_ci	} else if (pi->mvdd_control == CISLANDS_VOLTAGE_CONTROL_BY_SVID2) {
21678c2ecf20Sopenharmony_ci		ret = ci_get_svi2_voltage_table(rdev,
21688c2ecf20Sopenharmony_ci						&rdev->pm.dpm.dyn_state.mvdd_dependency_on_mclk,
21698c2ecf20Sopenharmony_ci						&pi->mvdd_voltage_table);
21708c2ecf20Sopenharmony_ci		if (ret)
21718c2ecf20Sopenharmony_ci			return ret;
21728c2ecf20Sopenharmony_ci	}
21738c2ecf20Sopenharmony_ci
21748c2ecf20Sopenharmony_ci	if (pi->mvdd_voltage_table.count > SMU7_MAX_LEVELS_MVDD)
21758c2ecf20Sopenharmony_ci		si_trim_voltage_table_to_fit_state_table(rdev, SMU7_MAX_LEVELS_MVDD,
21768c2ecf20Sopenharmony_ci							 &pi->mvdd_voltage_table);
21778c2ecf20Sopenharmony_ci
21788c2ecf20Sopenharmony_ci	return 0;
21798c2ecf20Sopenharmony_ci}
21808c2ecf20Sopenharmony_ci
21818c2ecf20Sopenharmony_cistatic void ci_populate_smc_voltage_table(struct radeon_device *rdev,
21828c2ecf20Sopenharmony_ci					  struct atom_voltage_table_entry *voltage_table,
21838c2ecf20Sopenharmony_ci					  SMU7_Discrete_VoltageLevel *smc_voltage_table)
21848c2ecf20Sopenharmony_ci{
21858c2ecf20Sopenharmony_ci	int ret;
21868c2ecf20Sopenharmony_ci
21878c2ecf20Sopenharmony_ci	ret = ci_get_std_voltage_value_sidd(rdev, voltage_table,
21888c2ecf20Sopenharmony_ci					    &smc_voltage_table->StdVoltageHiSidd,
21898c2ecf20Sopenharmony_ci					    &smc_voltage_table->StdVoltageLoSidd);
21908c2ecf20Sopenharmony_ci
21918c2ecf20Sopenharmony_ci	if (ret) {
21928c2ecf20Sopenharmony_ci		smc_voltage_table->StdVoltageHiSidd = voltage_table->value * VOLTAGE_SCALE;
21938c2ecf20Sopenharmony_ci		smc_voltage_table->StdVoltageLoSidd = voltage_table->value * VOLTAGE_SCALE;
21948c2ecf20Sopenharmony_ci	}
21958c2ecf20Sopenharmony_ci
21968c2ecf20Sopenharmony_ci	smc_voltage_table->Voltage = cpu_to_be16(voltage_table->value * VOLTAGE_SCALE);
21978c2ecf20Sopenharmony_ci	smc_voltage_table->StdVoltageHiSidd =
21988c2ecf20Sopenharmony_ci		cpu_to_be16(smc_voltage_table->StdVoltageHiSidd);
21998c2ecf20Sopenharmony_ci	smc_voltage_table->StdVoltageLoSidd =
22008c2ecf20Sopenharmony_ci		cpu_to_be16(smc_voltage_table->StdVoltageLoSidd);
22018c2ecf20Sopenharmony_ci}
22028c2ecf20Sopenharmony_ci
22038c2ecf20Sopenharmony_cistatic int ci_populate_smc_vddc_table(struct radeon_device *rdev,
22048c2ecf20Sopenharmony_ci				      SMU7_Discrete_DpmTable *table)
22058c2ecf20Sopenharmony_ci{
22068c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
22078c2ecf20Sopenharmony_ci	unsigned int count;
22088c2ecf20Sopenharmony_ci
22098c2ecf20Sopenharmony_ci	table->VddcLevelCount = pi->vddc_voltage_table.count;
22108c2ecf20Sopenharmony_ci	for (count = 0; count < table->VddcLevelCount; count++) {
22118c2ecf20Sopenharmony_ci		ci_populate_smc_voltage_table(rdev,
22128c2ecf20Sopenharmony_ci					      &pi->vddc_voltage_table.entries[count],
22138c2ecf20Sopenharmony_ci					      &table->VddcLevel[count]);
22148c2ecf20Sopenharmony_ci
22158c2ecf20Sopenharmony_ci		if (pi->voltage_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO)
22168c2ecf20Sopenharmony_ci			table->VddcLevel[count].Smio |=
22178c2ecf20Sopenharmony_ci				pi->vddc_voltage_table.entries[count].smio_low;
22188c2ecf20Sopenharmony_ci		else
22198c2ecf20Sopenharmony_ci			table->VddcLevel[count].Smio = 0;
22208c2ecf20Sopenharmony_ci	}
22218c2ecf20Sopenharmony_ci	table->VddcLevelCount = cpu_to_be32(table->VddcLevelCount);
22228c2ecf20Sopenharmony_ci
22238c2ecf20Sopenharmony_ci	return 0;
22248c2ecf20Sopenharmony_ci}
22258c2ecf20Sopenharmony_ci
22268c2ecf20Sopenharmony_cistatic int ci_populate_smc_vddci_table(struct radeon_device *rdev,
22278c2ecf20Sopenharmony_ci				       SMU7_Discrete_DpmTable *table)
22288c2ecf20Sopenharmony_ci{
22298c2ecf20Sopenharmony_ci	unsigned int count;
22308c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
22318c2ecf20Sopenharmony_ci
22328c2ecf20Sopenharmony_ci	table->VddciLevelCount = pi->vddci_voltage_table.count;
22338c2ecf20Sopenharmony_ci	for (count = 0; count < table->VddciLevelCount; count++) {
22348c2ecf20Sopenharmony_ci		ci_populate_smc_voltage_table(rdev,
22358c2ecf20Sopenharmony_ci					      &pi->vddci_voltage_table.entries[count],
22368c2ecf20Sopenharmony_ci					      &table->VddciLevel[count]);
22378c2ecf20Sopenharmony_ci
22388c2ecf20Sopenharmony_ci		if (pi->vddci_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO)
22398c2ecf20Sopenharmony_ci			table->VddciLevel[count].Smio |=
22408c2ecf20Sopenharmony_ci				pi->vddci_voltage_table.entries[count].smio_low;
22418c2ecf20Sopenharmony_ci		else
22428c2ecf20Sopenharmony_ci			table->VddciLevel[count].Smio = 0;
22438c2ecf20Sopenharmony_ci	}
22448c2ecf20Sopenharmony_ci	table->VddciLevelCount = cpu_to_be32(table->VddciLevelCount);
22458c2ecf20Sopenharmony_ci
22468c2ecf20Sopenharmony_ci	return 0;
22478c2ecf20Sopenharmony_ci}
22488c2ecf20Sopenharmony_ci
22498c2ecf20Sopenharmony_cistatic int ci_populate_smc_mvdd_table(struct radeon_device *rdev,
22508c2ecf20Sopenharmony_ci				      SMU7_Discrete_DpmTable *table)
22518c2ecf20Sopenharmony_ci{
22528c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
22538c2ecf20Sopenharmony_ci	unsigned int count;
22548c2ecf20Sopenharmony_ci
22558c2ecf20Sopenharmony_ci	table->MvddLevelCount = pi->mvdd_voltage_table.count;
22568c2ecf20Sopenharmony_ci	for (count = 0; count < table->MvddLevelCount; count++) {
22578c2ecf20Sopenharmony_ci		ci_populate_smc_voltage_table(rdev,
22588c2ecf20Sopenharmony_ci					      &pi->mvdd_voltage_table.entries[count],
22598c2ecf20Sopenharmony_ci					      &table->MvddLevel[count]);
22608c2ecf20Sopenharmony_ci
22618c2ecf20Sopenharmony_ci		if (pi->mvdd_control == CISLANDS_VOLTAGE_CONTROL_BY_GPIO)
22628c2ecf20Sopenharmony_ci			table->MvddLevel[count].Smio |=
22638c2ecf20Sopenharmony_ci				pi->mvdd_voltage_table.entries[count].smio_low;
22648c2ecf20Sopenharmony_ci		else
22658c2ecf20Sopenharmony_ci			table->MvddLevel[count].Smio = 0;
22668c2ecf20Sopenharmony_ci	}
22678c2ecf20Sopenharmony_ci	table->MvddLevelCount = cpu_to_be32(table->MvddLevelCount);
22688c2ecf20Sopenharmony_ci
22698c2ecf20Sopenharmony_ci	return 0;
22708c2ecf20Sopenharmony_ci}
22718c2ecf20Sopenharmony_ci
22728c2ecf20Sopenharmony_cistatic int ci_populate_smc_voltage_tables(struct radeon_device *rdev,
22738c2ecf20Sopenharmony_ci					  SMU7_Discrete_DpmTable *table)
22748c2ecf20Sopenharmony_ci{
22758c2ecf20Sopenharmony_ci	int ret;
22768c2ecf20Sopenharmony_ci
22778c2ecf20Sopenharmony_ci	ret = ci_populate_smc_vddc_table(rdev, table);
22788c2ecf20Sopenharmony_ci	if (ret)
22798c2ecf20Sopenharmony_ci		return ret;
22808c2ecf20Sopenharmony_ci
22818c2ecf20Sopenharmony_ci	ret = ci_populate_smc_vddci_table(rdev, table);
22828c2ecf20Sopenharmony_ci	if (ret)
22838c2ecf20Sopenharmony_ci		return ret;
22848c2ecf20Sopenharmony_ci
22858c2ecf20Sopenharmony_ci	ret = ci_populate_smc_mvdd_table(rdev, table);
22868c2ecf20Sopenharmony_ci	if (ret)
22878c2ecf20Sopenharmony_ci		return ret;
22888c2ecf20Sopenharmony_ci
22898c2ecf20Sopenharmony_ci	return 0;
22908c2ecf20Sopenharmony_ci}
22918c2ecf20Sopenharmony_ci
22928c2ecf20Sopenharmony_cistatic int ci_populate_mvdd_value(struct radeon_device *rdev, u32 mclk,
22938c2ecf20Sopenharmony_ci				  SMU7_Discrete_VoltageLevel *voltage)
22948c2ecf20Sopenharmony_ci{
22958c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
22968c2ecf20Sopenharmony_ci	u32 i = 0;
22978c2ecf20Sopenharmony_ci
22988c2ecf20Sopenharmony_ci	if (pi->mvdd_control != CISLANDS_VOLTAGE_CONTROL_NONE) {
22998c2ecf20Sopenharmony_ci		for (i = 0; i < rdev->pm.dpm.dyn_state.mvdd_dependency_on_mclk.count; i++) {
23008c2ecf20Sopenharmony_ci			if (mclk <= rdev->pm.dpm.dyn_state.mvdd_dependency_on_mclk.entries[i].clk) {
23018c2ecf20Sopenharmony_ci				voltage->Voltage = pi->mvdd_voltage_table.entries[i].value;
23028c2ecf20Sopenharmony_ci				break;
23038c2ecf20Sopenharmony_ci			}
23048c2ecf20Sopenharmony_ci		}
23058c2ecf20Sopenharmony_ci
23068c2ecf20Sopenharmony_ci		if (i >= rdev->pm.dpm.dyn_state.mvdd_dependency_on_mclk.count)
23078c2ecf20Sopenharmony_ci			return -EINVAL;
23088c2ecf20Sopenharmony_ci	}
23098c2ecf20Sopenharmony_ci
23108c2ecf20Sopenharmony_ci	return -EINVAL;
23118c2ecf20Sopenharmony_ci}
23128c2ecf20Sopenharmony_ci
23138c2ecf20Sopenharmony_cistatic int ci_get_std_voltage_value_sidd(struct radeon_device *rdev,
23148c2ecf20Sopenharmony_ci					 struct atom_voltage_table_entry *voltage_table,
23158c2ecf20Sopenharmony_ci					 u16 *std_voltage_hi_sidd, u16 *std_voltage_lo_sidd)
23168c2ecf20Sopenharmony_ci{
23178c2ecf20Sopenharmony_ci	u16 v_index, idx;
23188c2ecf20Sopenharmony_ci	bool voltage_found = false;
23198c2ecf20Sopenharmony_ci	*std_voltage_hi_sidd = voltage_table->value * VOLTAGE_SCALE;
23208c2ecf20Sopenharmony_ci	*std_voltage_lo_sidd = voltage_table->value * VOLTAGE_SCALE;
23218c2ecf20Sopenharmony_ci
23228c2ecf20Sopenharmony_ci	if (rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries == NULL)
23238c2ecf20Sopenharmony_ci		return -EINVAL;
23248c2ecf20Sopenharmony_ci
23258c2ecf20Sopenharmony_ci	if (rdev->pm.dpm.dyn_state.cac_leakage_table.entries) {
23268c2ecf20Sopenharmony_ci		for (v_index = 0; (u32)v_index < rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count; v_index++) {
23278c2ecf20Sopenharmony_ci			if (voltage_table->value ==
23288c2ecf20Sopenharmony_ci			    rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[v_index].v) {
23298c2ecf20Sopenharmony_ci				voltage_found = true;
23308c2ecf20Sopenharmony_ci				if ((u32)v_index < rdev->pm.dpm.dyn_state.cac_leakage_table.count)
23318c2ecf20Sopenharmony_ci					idx = v_index;
23328c2ecf20Sopenharmony_ci				else
23338c2ecf20Sopenharmony_ci					idx = rdev->pm.dpm.dyn_state.cac_leakage_table.count - 1;
23348c2ecf20Sopenharmony_ci				*std_voltage_lo_sidd =
23358c2ecf20Sopenharmony_ci					rdev->pm.dpm.dyn_state.cac_leakage_table.entries[idx].vddc * VOLTAGE_SCALE;
23368c2ecf20Sopenharmony_ci				*std_voltage_hi_sidd =
23378c2ecf20Sopenharmony_ci					rdev->pm.dpm.dyn_state.cac_leakage_table.entries[idx].leakage * VOLTAGE_SCALE;
23388c2ecf20Sopenharmony_ci				break;
23398c2ecf20Sopenharmony_ci			}
23408c2ecf20Sopenharmony_ci		}
23418c2ecf20Sopenharmony_ci
23428c2ecf20Sopenharmony_ci		if (!voltage_found) {
23438c2ecf20Sopenharmony_ci			for (v_index = 0; (u32)v_index < rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count; v_index++) {
23448c2ecf20Sopenharmony_ci				if (voltage_table->value <=
23458c2ecf20Sopenharmony_ci				    rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[v_index].v) {
23468c2ecf20Sopenharmony_ci					voltage_found = true;
23478c2ecf20Sopenharmony_ci					if ((u32)v_index < rdev->pm.dpm.dyn_state.cac_leakage_table.count)
23488c2ecf20Sopenharmony_ci						idx = v_index;
23498c2ecf20Sopenharmony_ci					else
23508c2ecf20Sopenharmony_ci						idx = rdev->pm.dpm.dyn_state.cac_leakage_table.count - 1;
23518c2ecf20Sopenharmony_ci					*std_voltage_lo_sidd =
23528c2ecf20Sopenharmony_ci						rdev->pm.dpm.dyn_state.cac_leakage_table.entries[idx].vddc * VOLTAGE_SCALE;
23538c2ecf20Sopenharmony_ci					*std_voltage_hi_sidd =
23548c2ecf20Sopenharmony_ci						rdev->pm.dpm.dyn_state.cac_leakage_table.entries[idx].leakage * VOLTAGE_SCALE;
23558c2ecf20Sopenharmony_ci					break;
23568c2ecf20Sopenharmony_ci				}
23578c2ecf20Sopenharmony_ci			}
23588c2ecf20Sopenharmony_ci		}
23598c2ecf20Sopenharmony_ci	}
23608c2ecf20Sopenharmony_ci
23618c2ecf20Sopenharmony_ci	return 0;
23628c2ecf20Sopenharmony_ci}
23638c2ecf20Sopenharmony_ci
23648c2ecf20Sopenharmony_cistatic void ci_populate_phase_value_based_on_sclk(struct radeon_device *rdev,
23658c2ecf20Sopenharmony_ci						  const struct radeon_phase_shedding_limits_table *limits,
23668c2ecf20Sopenharmony_ci						  u32 sclk,
23678c2ecf20Sopenharmony_ci						  u32 *phase_shedding)
23688c2ecf20Sopenharmony_ci{
23698c2ecf20Sopenharmony_ci	unsigned int i;
23708c2ecf20Sopenharmony_ci
23718c2ecf20Sopenharmony_ci	*phase_shedding = 1;
23728c2ecf20Sopenharmony_ci
23738c2ecf20Sopenharmony_ci	for (i = 0; i < limits->count; i++) {
23748c2ecf20Sopenharmony_ci		if (sclk < limits->entries[i].sclk) {
23758c2ecf20Sopenharmony_ci			*phase_shedding = i;
23768c2ecf20Sopenharmony_ci			break;
23778c2ecf20Sopenharmony_ci		}
23788c2ecf20Sopenharmony_ci	}
23798c2ecf20Sopenharmony_ci}
23808c2ecf20Sopenharmony_ci
23818c2ecf20Sopenharmony_cistatic void ci_populate_phase_value_based_on_mclk(struct radeon_device *rdev,
23828c2ecf20Sopenharmony_ci						  const struct radeon_phase_shedding_limits_table *limits,
23838c2ecf20Sopenharmony_ci						  u32 mclk,
23848c2ecf20Sopenharmony_ci						  u32 *phase_shedding)
23858c2ecf20Sopenharmony_ci{
23868c2ecf20Sopenharmony_ci	unsigned int i;
23878c2ecf20Sopenharmony_ci
23888c2ecf20Sopenharmony_ci	*phase_shedding = 1;
23898c2ecf20Sopenharmony_ci
23908c2ecf20Sopenharmony_ci	for (i = 0; i < limits->count; i++) {
23918c2ecf20Sopenharmony_ci		if (mclk < limits->entries[i].mclk) {
23928c2ecf20Sopenharmony_ci			*phase_shedding = i;
23938c2ecf20Sopenharmony_ci			break;
23948c2ecf20Sopenharmony_ci		}
23958c2ecf20Sopenharmony_ci	}
23968c2ecf20Sopenharmony_ci}
23978c2ecf20Sopenharmony_ci
23988c2ecf20Sopenharmony_cistatic int ci_init_arb_table_index(struct radeon_device *rdev)
23998c2ecf20Sopenharmony_ci{
24008c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
24018c2ecf20Sopenharmony_ci	u32 tmp;
24028c2ecf20Sopenharmony_ci	int ret;
24038c2ecf20Sopenharmony_ci
24048c2ecf20Sopenharmony_ci	ret = ci_read_smc_sram_dword(rdev, pi->arb_table_start,
24058c2ecf20Sopenharmony_ci				     &tmp, pi->sram_end);
24068c2ecf20Sopenharmony_ci	if (ret)
24078c2ecf20Sopenharmony_ci		return ret;
24088c2ecf20Sopenharmony_ci
24098c2ecf20Sopenharmony_ci	tmp &= 0x00FFFFFF;
24108c2ecf20Sopenharmony_ci	tmp |= MC_CG_ARB_FREQ_F1 << 24;
24118c2ecf20Sopenharmony_ci
24128c2ecf20Sopenharmony_ci	return ci_write_smc_sram_dword(rdev, pi->arb_table_start,
24138c2ecf20Sopenharmony_ci				       tmp, pi->sram_end);
24148c2ecf20Sopenharmony_ci}
24158c2ecf20Sopenharmony_ci
24168c2ecf20Sopenharmony_cistatic int ci_get_dependency_volt_by_clk(struct radeon_device *rdev,
24178c2ecf20Sopenharmony_ci					 struct radeon_clock_voltage_dependency_table *allowed_clock_voltage_table,
24188c2ecf20Sopenharmony_ci					 u32 clock, u32 *voltage)
24198c2ecf20Sopenharmony_ci{
24208c2ecf20Sopenharmony_ci	u32 i = 0;
24218c2ecf20Sopenharmony_ci
24228c2ecf20Sopenharmony_ci	if (allowed_clock_voltage_table->count == 0)
24238c2ecf20Sopenharmony_ci		return -EINVAL;
24248c2ecf20Sopenharmony_ci
24258c2ecf20Sopenharmony_ci	for (i = 0; i < allowed_clock_voltage_table->count; i++) {
24268c2ecf20Sopenharmony_ci		if (allowed_clock_voltage_table->entries[i].clk >= clock) {
24278c2ecf20Sopenharmony_ci			*voltage = allowed_clock_voltage_table->entries[i].v;
24288c2ecf20Sopenharmony_ci			return 0;
24298c2ecf20Sopenharmony_ci		}
24308c2ecf20Sopenharmony_ci	}
24318c2ecf20Sopenharmony_ci
24328c2ecf20Sopenharmony_ci	*voltage = allowed_clock_voltage_table->entries[i-1].v;
24338c2ecf20Sopenharmony_ci
24348c2ecf20Sopenharmony_ci	return 0;
24358c2ecf20Sopenharmony_ci}
24368c2ecf20Sopenharmony_ci
24378c2ecf20Sopenharmony_cistatic u8 ci_get_sleep_divider_id_from_clock(struct radeon_device *rdev,
24388c2ecf20Sopenharmony_ci					     u32 sclk, u32 min_sclk_in_sr)
24398c2ecf20Sopenharmony_ci{
24408c2ecf20Sopenharmony_ci	u32 i;
24418c2ecf20Sopenharmony_ci	u32 tmp;
24428c2ecf20Sopenharmony_ci	u32 min = (min_sclk_in_sr > CISLAND_MINIMUM_ENGINE_CLOCK) ?
24438c2ecf20Sopenharmony_ci		min_sclk_in_sr : CISLAND_MINIMUM_ENGINE_CLOCK;
24448c2ecf20Sopenharmony_ci
24458c2ecf20Sopenharmony_ci	if (sclk < min)
24468c2ecf20Sopenharmony_ci		return 0;
24478c2ecf20Sopenharmony_ci
24488c2ecf20Sopenharmony_ci	for (i = CISLAND_MAX_DEEPSLEEP_DIVIDER_ID;  ; i--) {
24498c2ecf20Sopenharmony_ci		tmp = sclk / (1 << i);
24508c2ecf20Sopenharmony_ci		if (tmp >= min || i == 0)
24518c2ecf20Sopenharmony_ci			break;
24528c2ecf20Sopenharmony_ci	}
24538c2ecf20Sopenharmony_ci
24548c2ecf20Sopenharmony_ci	return (u8)i;
24558c2ecf20Sopenharmony_ci}
24568c2ecf20Sopenharmony_ci
24578c2ecf20Sopenharmony_cistatic int ci_initial_switch_from_arb_f0_to_f1(struct radeon_device *rdev)
24588c2ecf20Sopenharmony_ci{
24598c2ecf20Sopenharmony_ci	return ni_copy_and_switch_arb_sets(rdev, MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1);
24608c2ecf20Sopenharmony_ci}
24618c2ecf20Sopenharmony_ci
24628c2ecf20Sopenharmony_cistatic int ci_reset_to_default(struct radeon_device *rdev)
24638c2ecf20Sopenharmony_ci{
24648c2ecf20Sopenharmony_ci	return (ci_send_msg_to_smc(rdev, PPSMC_MSG_ResetToDefaults) == PPSMC_Result_OK) ?
24658c2ecf20Sopenharmony_ci		0 : -EINVAL;
24668c2ecf20Sopenharmony_ci}
24678c2ecf20Sopenharmony_ci
24688c2ecf20Sopenharmony_cistatic int ci_force_switch_to_arb_f0(struct radeon_device *rdev)
24698c2ecf20Sopenharmony_ci{
24708c2ecf20Sopenharmony_ci	u32 tmp;
24718c2ecf20Sopenharmony_ci
24728c2ecf20Sopenharmony_ci	tmp = (RREG32_SMC(SMC_SCRATCH9) & 0x0000ff00) >> 8;
24738c2ecf20Sopenharmony_ci
24748c2ecf20Sopenharmony_ci	if (tmp == MC_CG_ARB_FREQ_F0)
24758c2ecf20Sopenharmony_ci		return 0;
24768c2ecf20Sopenharmony_ci
24778c2ecf20Sopenharmony_ci	return ni_copy_and_switch_arb_sets(rdev, tmp, MC_CG_ARB_FREQ_F0);
24788c2ecf20Sopenharmony_ci}
24798c2ecf20Sopenharmony_ci
24808c2ecf20Sopenharmony_cistatic void ci_register_patching_mc_arb(struct radeon_device *rdev,
24818c2ecf20Sopenharmony_ci					const u32 engine_clock,
24828c2ecf20Sopenharmony_ci					const u32 memory_clock,
24838c2ecf20Sopenharmony_ci					u32 *dram_timimg2)
24848c2ecf20Sopenharmony_ci{
24858c2ecf20Sopenharmony_ci	bool patch;
24868c2ecf20Sopenharmony_ci	u32 tmp, tmp2;
24878c2ecf20Sopenharmony_ci
24888c2ecf20Sopenharmony_ci	tmp = RREG32(MC_SEQ_MISC0);
24898c2ecf20Sopenharmony_ci	patch = ((tmp & 0x0000f00) == 0x300) ? true : false;
24908c2ecf20Sopenharmony_ci
24918c2ecf20Sopenharmony_ci	if (patch &&
24928c2ecf20Sopenharmony_ci	    ((rdev->pdev->device == 0x67B0) ||
24938c2ecf20Sopenharmony_ci	     (rdev->pdev->device == 0x67B1))) {
24948c2ecf20Sopenharmony_ci		if ((memory_clock > 100000) && (memory_clock <= 125000)) {
24958c2ecf20Sopenharmony_ci			tmp2 = (((0x31 * engine_clock) / 125000) - 1) & 0xff;
24968c2ecf20Sopenharmony_ci			*dram_timimg2 &= ~0x00ff0000;
24978c2ecf20Sopenharmony_ci			*dram_timimg2 |= tmp2 << 16;
24988c2ecf20Sopenharmony_ci		} else if ((memory_clock > 125000) && (memory_clock <= 137500)) {
24998c2ecf20Sopenharmony_ci			tmp2 = (((0x36 * engine_clock) / 137500) - 1) & 0xff;
25008c2ecf20Sopenharmony_ci			*dram_timimg2 &= ~0x00ff0000;
25018c2ecf20Sopenharmony_ci			*dram_timimg2 |= tmp2 << 16;
25028c2ecf20Sopenharmony_ci		}
25038c2ecf20Sopenharmony_ci	}
25048c2ecf20Sopenharmony_ci}
25058c2ecf20Sopenharmony_ci
25068c2ecf20Sopenharmony_ci
25078c2ecf20Sopenharmony_cistatic int ci_populate_memory_timing_parameters(struct radeon_device *rdev,
25088c2ecf20Sopenharmony_ci						u32 sclk,
25098c2ecf20Sopenharmony_ci						u32 mclk,
25108c2ecf20Sopenharmony_ci						SMU7_Discrete_MCArbDramTimingTableEntry *arb_regs)
25118c2ecf20Sopenharmony_ci{
25128c2ecf20Sopenharmony_ci	u32 dram_timing;
25138c2ecf20Sopenharmony_ci	u32 dram_timing2;
25148c2ecf20Sopenharmony_ci	u32 burst_time;
25158c2ecf20Sopenharmony_ci
25168c2ecf20Sopenharmony_ci	radeon_atom_set_engine_dram_timings(rdev, sclk, mclk);
25178c2ecf20Sopenharmony_ci
25188c2ecf20Sopenharmony_ci	dram_timing  = RREG32(MC_ARB_DRAM_TIMING);
25198c2ecf20Sopenharmony_ci	dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2);
25208c2ecf20Sopenharmony_ci	burst_time = RREG32(MC_ARB_BURST_TIME) & STATE0_MASK;
25218c2ecf20Sopenharmony_ci
25228c2ecf20Sopenharmony_ci	ci_register_patching_mc_arb(rdev, sclk, mclk, &dram_timing2);
25238c2ecf20Sopenharmony_ci
25248c2ecf20Sopenharmony_ci	arb_regs->McArbDramTiming  = cpu_to_be32(dram_timing);
25258c2ecf20Sopenharmony_ci	arb_regs->McArbDramTiming2 = cpu_to_be32(dram_timing2);
25268c2ecf20Sopenharmony_ci	arb_regs->McArbBurstTime = (u8)burst_time;
25278c2ecf20Sopenharmony_ci
25288c2ecf20Sopenharmony_ci	return 0;
25298c2ecf20Sopenharmony_ci}
25308c2ecf20Sopenharmony_ci
25318c2ecf20Sopenharmony_cistatic int ci_do_program_memory_timing_parameters(struct radeon_device *rdev)
25328c2ecf20Sopenharmony_ci{
25338c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
25348c2ecf20Sopenharmony_ci	SMU7_Discrete_MCArbDramTimingTable arb_regs;
25358c2ecf20Sopenharmony_ci	u32 i, j;
25368c2ecf20Sopenharmony_ci	int ret =  0;
25378c2ecf20Sopenharmony_ci
25388c2ecf20Sopenharmony_ci	memset(&arb_regs, 0, sizeof(SMU7_Discrete_MCArbDramTimingTable));
25398c2ecf20Sopenharmony_ci
25408c2ecf20Sopenharmony_ci	for (i = 0; i < pi->dpm_table.sclk_table.count; i++) {
25418c2ecf20Sopenharmony_ci		for (j = 0; j < pi->dpm_table.mclk_table.count; j++) {
25428c2ecf20Sopenharmony_ci			ret = ci_populate_memory_timing_parameters(rdev,
25438c2ecf20Sopenharmony_ci								   pi->dpm_table.sclk_table.dpm_levels[i].value,
25448c2ecf20Sopenharmony_ci								   pi->dpm_table.mclk_table.dpm_levels[j].value,
25458c2ecf20Sopenharmony_ci								   &arb_regs.entries[i][j]);
25468c2ecf20Sopenharmony_ci			if (ret)
25478c2ecf20Sopenharmony_ci				break;
25488c2ecf20Sopenharmony_ci		}
25498c2ecf20Sopenharmony_ci	}
25508c2ecf20Sopenharmony_ci
25518c2ecf20Sopenharmony_ci	if (ret == 0)
25528c2ecf20Sopenharmony_ci		ret = ci_copy_bytes_to_smc(rdev,
25538c2ecf20Sopenharmony_ci					   pi->arb_table_start,
25548c2ecf20Sopenharmony_ci					   (u8 *)&arb_regs,
25558c2ecf20Sopenharmony_ci					   sizeof(SMU7_Discrete_MCArbDramTimingTable),
25568c2ecf20Sopenharmony_ci					   pi->sram_end);
25578c2ecf20Sopenharmony_ci
25588c2ecf20Sopenharmony_ci	return ret;
25598c2ecf20Sopenharmony_ci}
25608c2ecf20Sopenharmony_ci
25618c2ecf20Sopenharmony_cistatic int ci_program_memory_timing_parameters(struct radeon_device *rdev)
25628c2ecf20Sopenharmony_ci{
25638c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
25648c2ecf20Sopenharmony_ci
25658c2ecf20Sopenharmony_ci	if (pi->need_update_smu7_dpm_table == 0)
25668c2ecf20Sopenharmony_ci		return 0;
25678c2ecf20Sopenharmony_ci
25688c2ecf20Sopenharmony_ci	return ci_do_program_memory_timing_parameters(rdev);
25698c2ecf20Sopenharmony_ci}
25708c2ecf20Sopenharmony_ci
25718c2ecf20Sopenharmony_cistatic void ci_populate_smc_initial_state(struct radeon_device *rdev,
25728c2ecf20Sopenharmony_ci					  struct radeon_ps *radeon_boot_state)
25738c2ecf20Sopenharmony_ci{
25748c2ecf20Sopenharmony_ci	struct ci_ps *boot_state = ci_get_ps(radeon_boot_state);
25758c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
25768c2ecf20Sopenharmony_ci	u32 level = 0;
25778c2ecf20Sopenharmony_ci
25788c2ecf20Sopenharmony_ci	for (level = 0; level < rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count; level++) {
25798c2ecf20Sopenharmony_ci		if (rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[level].clk >=
25808c2ecf20Sopenharmony_ci		    boot_state->performance_levels[0].sclk) {
25818c2ecf20Sopenharmony_ci			pi->smc_state_table.GraphicsBootLevel = level;
25828c2ecf20Sopenharmony_ci			break;
25838c2ecf20Sopenharmony_ci		}
25848c2ecf20Sopenharmony_ci	}
25858c2ecf20Sopenharmony_ci
25868c2ecf20Sopenharmony_ci	for (level = 0; level < rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk.count; level++) {
25878c2ecf20Sopenharmony_ci		if (rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries[level].clk >=
25888c2ecf20Sopenharmony_ci		    boot_state->performance_levels[0].mclk) {
25898c2ecf20Sopenharmony_ci			pi->smc_state_table.MemoryBootLevel = level;
25908c2ecf20Sopenharmony_ci			break;
25918c2ecf20Sopenharmony_ci		}
25928c2ecf20Sopenharmony_ci	}
25938c2ecf20Sopenharmony_ci}
25948c2ecf20Sopenharmony_ci
25958c2ecf20Sopenharmony_cistatic u32 ci_get_dpm_level_enable_mask_value(struct ci_single_dpm_table *dpm_table)
25968c2ecf20Sopenharmony_ci{
25978c2ecf20Sopenharmony_ci	u32 i;
25988c2ecf20Sopenharmony_ci	u32 mask_value = 0;
25998c2ecf20Sopenharmony_ci
26008c2ecf20Sopenharmony_ci	for (i = dpm_table->count; i > 0; i--) {
26018c2ecf20Sopenharmony_ci		mask_value = mask_value << 1;
26028c2ecf20Sopenharmony_ci		if (dpm_table->dpm_levels[i-1].enabled)
26038c2ecf20Sopenharmony_ci			mask_value |= 0x1;
26048c2ecf20Sopenharmony_ci		else
26058c2ecf20Sopenharmony_ci			mask_value &= 0xFFFFFFFE;
26068c2ecf20Sopenharmony_ci	}
26078c2ecf20Sopenharmony_ci
26088c2ecf20Sopenharmony_ci	return mask_value;
26098c2ecf20Sopenharmony_ci}
26108c2ecf20Sopenharmony_ci
26118c2ecf20Sopenharmony_cistatic void ci_populate_smc_link_level(struct radeon_device *rdev,
26128c2ecf20Sopenharmony_ci				       SMU7_Discrete_DpmTable *table)
26138c2ecf20Sopenharmony_ci{
26148c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
26158c2ecf20Sopenharmony_ci	struct ci_dpm_table *dpm_table = &pi->dpm_table;
26168c2ecf20Sopenharmony_ci	u32 i;
26178c2ecf20Sopenharmony_ci
26188c2ecf20Sopenharmony_ci	for (i = 0; i < dpm_table->pcie_speed_table.count; i++) {
26198c2ecf20Sopenharmony_ci		table->LinkLevel[i].PcieGenSpeed =
26208c2ecf20Sopenharmony_ci			(u8)dpm_table->pcie_speed_table.dpm_levels[i].value;
26218c2ecf20Sopenharmony_ci		table->LinkLevel[i].PcieLaneCount =
26228c2ecf20Sopenharmony_ci			r600_encode_pci_lane_width(dpm_table->pcie_speed_table.dpm_levels[i].param1);
26238c2ecf20Sopenharmony_ci		table->LinkLevel[i].EnabledForActivity = 1;
26248c2ecf20Sopenharmony_ci		table->LinkLevel[i].DownT = cpu_to_be32(5);
26258c2ecf20Sopenharmony_ci		table->LinkLevel[i].UpT = cpu_to_be32(30);
26268c2ecf20Sopenharmony_ci	}
26278c2ecf20Sopenharmony_ci
26288c2ecf20Sopenharmony_ci	pi->smc_state_table.LinkLevelCount = (u8)dpm_table->pcie_speed_table.count;
26298c2ecf20Sopenharmony_ci	pi->dpm_level_enable_mask.pcie_dpm_enable_mask =
26308c2ecf20Sopenharmony_ci		ci_get_dpm_level_enable_mask_value(&dpm_table->pcie_speed_table);
26318c2ecf20Sopenharmony_ci}
26328c2ecf20Sopenharmony_ci
26338c2ecf20Sopenharmony_cistatic int ci_populate_smc_uvd_level(struct radeon_device *rdev,
26348c2ecf20Sopenharmony_ci				     SMU7_Discrete_DpmTable *table)
26358c2ecf20Sopenharmony_ci{
26368c2ecf20Sopenharmony_ci	u32 count;
26378c2ecf20Sopenharmony_ci	struct atom_clock_dividers dividers;
26388c2ecf20Sopenharmony_ci	int ret = -EINVAL;
26398c2ecf20Sopenharmony_ci
26408c2ecf20Sopenharmony_ci	table->UvdLevelCount =
26418c2ecf20Sopenharmony_ci		rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count;
26428c2ecf20Sopenharmony_ci
26438c2ecf20Sopenharmony_ci	for (count = 0; count < table->UvdLevelCount; count++) {
26448c2ecf20Sopenharmony_ci		table->UvdLevel[count].VclkFrequency =
26458c2ecf20Sopenharmony_ci			rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[count].vclk;
26468c2ecf20Sopenharmony_ci		table->UvdLevel[count].DclkFrequency =
26478c2ecf20Sopenharmony_ci			rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[count].dclk;
26488c2ecf20Sopenharmony_ci		table->UvdLevel[count].MinVddc =
26498c2ecf20Sopenharmony_ci			rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[count].v * VOLTAGE_SCALE;
26508c2ecf20Sopenharmony_ci		table->UvdLevel[count].MinVddcPhases = 1;
26518c2ecf20Sopenharmony_ci
26528c2ecf20Sopenharmony_ci		ret = radeon_atom_get_clock_dividers(rdev,
26538c2ecf20Sopenharmony_ci						     COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
26548c2ecf20Sopenharmony_ci						     table->UvdLevel[count].VclkFrequency, false, &dividers);
26558c2ecf20Sopenharmony_ci		if (ret)
26568c2ecf20Sopenharmony_ci			return ret;
26578c2ecf20Sopenharmony_ci
26588c2ecf20Sopenharmony_ci		table->UvdLevel[count].VclkDivider = (u8)dividers.post_divider;
26598c2ecf20Sopenharmony_ci
26608c2ecf20Sopenharmony_ci		ret = radeon_atom_get_clock_dividers(rdev,
26618c2ecf20Sopenharmony_ci						     COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
26628c2ecf20Sopenharmony_ci						     table->UvdLevel[count].DclkFrequency, false, &dividers);
26638c2ecf20Sopenharmony_ci		if (ret)
26648c2ecf20Sopenharmony_ci			return ret;
26658c2ecf20Sopenharmony_ci
26668c2ecf20Sopenharmony_ci		table->UvdLevel[count].DclkDivider = (u8)dividers.post_divider;
26678c2ecf20Sopenharmony_ci
26688c2ecf20Sopenharmony_ci		table->UvdLevel[count].VclkFrequency = cpu_to_be32(table->UvdLevel[count].VclkFrequency);
26698c2ecf20Sopenharmony_ci		table->UvdLevel[count].DclkFrequency = cpu_to_be32(table->UvdLevel[count].DclkFrequency);
26708c2ecf20Sopenharmony_ci		table->UvdLevel[count].MinVddc = cpu_to_be16(table->UvdLevel[count].MinVddc);
26718c2ecf20Sopenharmony_ci	}
26728c2ecf20Sopenharmony_ci
26738c2ecf20Sopenharmony_ci	return ret;
26748c2ecf20Sopenharmony_ci}
26758c2ecf20Sopenharmony_ci
26768c2ecf20Sopenharmony_cistatic int ci_populate_smc_vce_level(struct radeon_device *rdev,
26778c2ecf20Sopenharmony_ci				     SMU7_Discrete_DpmTable *table)
26788c2ecf20Sopenharmony_ci{
26798c2ecf20Sopenharmony_ci	u32 count;
26808c2ecf20Sopenharmony_ci	struct atom_clock_dividers dividers;
26818c2ecf20Sopenharmony_ci	int ret = -EINVAL;
26828c2ecf20Sopenharmony_ci
26838c2ecf20Sopenharmony_ci	table->VceLevelCount =
26848c2ecf20Sopenharmony_ci		rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.count;
26858c2ecf20Sopenharmony_ci
26868c2ecf20Sopenharmony_ci	for (count = 0; count < table->VceLevelCount; count++) {
26878c2ecf20Sopenharmony_ci		table->VceLevel[count].Frequency =
26888c2ecf20Sopenharmony_ci			rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[count].evclk;
26898c2ecf20Sopenharmony_ci		table->VceLevel[count].MinVoltage =
26908c2ecf20Sopenharmony_ci			(u16)rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[count].v * VOLTAGE_SCALE;
26918c2ecf20Sopenharmony_ci		table->VceLevel[count].MinPhases = 1;
26928c2ecf20Sopenharmony_ci
26938c2ecf20Sopenharmony_ci		ret = radeon_atom_get_clock_dividers(rdev,
26948c2ecf20Sopenharmony_ci						     COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
26958c2ecf20Sopenharmony_ci						     table->VceLevel[count].Frequency, false, &dividers);
26968c2ecf20Sopenharmony_ci		if (ret)
26978c2ecf20Sopenharmony_ci			return ret;
26988c2ecf20Sopenharmony_ci
26998c2ecf20Sopenharmony_ci		table->VceLevel[count].Divider = (u8)dividers.post_divider;
27008c2ecf20Sopenharmony_ci
27018c2ecf20Sopenharmony_ci		table->VceLevel[count].Frequency = cpu_to_be32(table->VceLevel[count].Frequency);
27028c2ecf20Sopenharmony_ci		table->VceLevel[count].MinVoltage = cpu_to_be16(table->VceLevel[count].MinVoltage);
27038c2ecf20Sopenharmony_ci	}
27048c2ecf20Sopenharmony_ci
27058c2ecf20Sopenharmony_ci	return ret;
27068c2ecf20Sopenharmony_ci
27078c2ecf20Sopenharmony_ci}
27088c2ecf20Sopenharmony_ci
27098c2ecf20Sopenharmony_cistatic int ci_populate_smc_acp_level(struct radeon_device *rdev,
27108c2ecf20Sopenharmony_ci				     SMU7_Discrete_DpmTable *table)
27118c2ecf20Sopenharmony_ci{
27128c2ecf20Sopenharmony_ci	u32 count;
27138c2ecf20Sopenharmony_ci	struct atom_clock_dividers dividers;
27148c2ecf20Sopenharmony_ci	int ret = -EINVAL;
27158c2ecf20Sopenharmony_ci
27168c2ecf20Sopenharmony_ci	table->AcpLevelCount = (u8)
27178c2ecf20Sopenharmony_ci		(rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.count);
27188c2ecf20Sopenharmony_ci
27198c2ecf20Sopenharmony_ci	for (count = 0; count < table->AcpLevelCount; count++) {
27208c2ecf20Sopenharmony_ci		table->AcpLevel[count].Frequency =
27218c2ecf20Sopenharmony_ci			rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries[count].clk;
27228c2ecf20Sopenharmony_ci		table->AcpLevel[count].MinVoltage =
27238c2ecf20Sopenharmony_ci			rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries[count].v;
27248c2ecf20Sopenharmony_ci		table->AcpLevel[count].MinPhases = 1;
27258c2ecf20Sopenharmony_ci
27268c2ecf20Sopenharmony_ci		ret = radeon_atom_get_clock_dividers(rdev,
27278c2ecf20Sopenharmony_ci						     COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
27288c2ecf20Sopenharmony_ci						     table->AcpLevel[count].Frequency, false, &dividers);
27298c2ecf20Sopenharmony_ci		if (ret)
27308c2ecf20Sopenharmony_ci			return ret;
27318c2ecf20Sopenharmony_ci
27328c2ecf20Sopenharmony_ci		table->AcpLevel[count].Divider = (u8)dividers.post_divider;
27338c2ecf20Sopenharmony_ci
27348c2ecf20Sopenharmony_ci		table->AcpLevel[count].Frequency = cpu_to_be32(table->AcpLevel[count].Frequency);
27358c2ecf20Sopenharmony_ci		table->AcpLevel[count].MinVoltage = cpu_to_be16(table->AcpLevel[count].MinVoltage);
27368c2ecf20Sopenharmony_ci	}
27378c2ecf20Sopenharmony_ci
27388c2ecf20Sopenharmony_ci	return ret;
27398c2ecf20Sopenharmony_ci}
27408c2ecf20Sopenharmony_ci
27418c2ecf20Sopenharmony_cistatic int ci_populate_smc_samu_level(struct radeon_device *rdev,
27428c2ecf20Sopenharmony_ci				      SMU7_Discrete_DpmTable *table)
27438c2ecf20Sopenharmony_ci{
27448c2ecf20Sopenharmony_ci	u32 count;
27458c2ecf20Sopenharmony_ci	struct atom_clock_dividers dividers;
27468c2ecf20Sopenharmony_ci	int ret = -EINVAL;
27478c2ecf20Sopenharmony_ci
27488c2ecf20Sopenharmony_ci	table->SamuLevelCount =
27498c2ecf20Sopenharmony_ci		rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.count;
27508c2ecf20Sopenharmony_ci
27518c2ecf20Sopenharmony_ci	for (count = 0; count < table->SamuLevelCount; count++) {
27528c2ecf20Sopenharmony_ci		table->SamuLevel[count].Frequency =
27538c2ecf20Sopenharmony_ci			rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries[count].clk;
27548c2ecf20Sopenharmony_ci		table->SamuLevel[count].MinVoltage =
27558c2ecf20Sopenharmony_ci			rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries[count].v * VOLTAGE_SCALE;
27568c2ecf20Sopenharmony_ci		table->SamuLevel[count].MinPhases = 1;
27578c2ecf20Sopenharmony_ci
27588c2ecf20Sopenharmony_ci		ret = radeon_atom_get_clock_dividers(rdev,
27598c2ecf20Sopenharmony_ci						     COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
27608c2ecf20Sopenharmony_ci						     table->SamuLevel[count].Frequency, false, &dividers);
27618c2ecf20Sopenharmony_ci		if (ret)
27628c2ecf20Sopenharmony_ci			return ret;
27638c2ecf20Sopenharmony_ci
27648c2ecf20Sopenharmony_ci		table->SamuLevel[count].Divider = (u8)dividers.post_divider;
27658c2ecf20Sopenharmony_ci
27668c2ecf20Sopenharmony_ci		table->SamuLevel[count].Frequency = cpu_to_be32(table->SamuLevel[count].Frequency);
27678c2ecf20Sopenharmony_ci		table->SamuLevel[count].MinVoltage = cpu_to_be16(table->SamuLevel[count].MinVoltage);
27688c2ecf20Sopenharmony_ci	}
27698c2ecf20Sopenharmony_ci
27708c2ecf20Sopenharmony_ci	return ret;
27718c2ecf20Sopenharmony_ci}
27728c2ecf20Sopenharmony_ci
27738c2ecf20Sopenharmony_cistatic int ci_calculate_mclk_params(struct radeon_device *rdev,
27748c2ecf20Sopenharmony_ci				    u32 memory_clock,
27758c2ecf20Sopenharmony_ci				    SMU7_Discrete_MemoryLevel *mclk,
27768c2ecf20Sopenharmony_ci				    bool strobe_mode,
27778c2ecf20Sopenharmony_ci				    bool dll_state_on)
27788c2ecf20Sopenharmony_ci{
27798c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
27808c2ecf20Sopenharmony_ci	u32  dll_cntl = pi->clock_registers.dll_cntl;
27818c2ecf20Sopenharmony_ci	u32  mclk_pwrmgt_cntl = pi->clock_registers.mclk_pwrmgt_cntl;
27828c2ecf20Sopenharmony_ci	u32  mpll_ad_func_cntl = pi->clock_registers.mpll_ad_func_cntl;
27838c2ecf20Sopenharmony_ci	u32  mpll_dq_func_cntl = pi->clock_registers.mpll_dq_func_cntl;
27848c2ecf20Sopenharmony_ci	u32  mpll_func_cntl = pi->clock_registers.mpll_func_cntl;
27858c2ecf20Sopenharmony_ci	u32  mpll_func_cntl_1 = pi->clock_registers.mpll_func_cntl_1;
27868c2ecf20Sopenharmony_ci	u32  mpll_func_cntl_2 = pi->clock_registers.mpll_func_cntl_2;
27878c2ecf20Sopenharmony_ci	u32  mpll_ss1 = pi->clock_registers.mpll_ss1;
27888c2ecf20Sopenharmony_ci	u32  mpll_ss2 = pi->clock_registers.mpll_ss2;
27898c2ecf20Sopenharmony_ci	struct atom_mpll_param mpll_param;
27908c2ecf20Sopenharmony_ci	int ret;
27918c2ecf20Sopenharmony_ci
27928c2ecf20Sopenharmony_ci	ret = radeon_atom_get_memory_pll_dividers(rdev, memory_clock, strobe_mode, &mpll_param);
27938c2ecf20Sopenharmony_ci	if (ret)
27948c2ecf20Sopenharmony_ci		return ret;
27958c2ecf20Sopenharmony_ci
27968c2ecf20Sopenharmony_ci	mpll_func_cntl &= ~BWCTRL_MASK;
27978c2ecf20Sopenharmony_ci	mpll_func_cntl |= BWCTRL(mpll_param.bwcntl);
27988c2ecf20Sopenharmony_ci
27998c2ecf20Sopenharmony_ci	mpll_func_cntl_1 &= ~(CLKF_MASK | CLKFRAC_MASK | VCO_MODE_MASK);
28008c2ecf20Sopenharmony_ci	mpll_func_cntl_1 |= CLKF(mpll_param.clkf) |
28018c2ecf20Sopenharmony_ci		CLKFRAC(mpll_param.clkfrac) | VCO_MODE(mpll_param.vco_mode);
28028c2ecf20Sopenharmony_ci
28038c2ecf20Sopenharmony_ci	mpll_ad_func_cntl &= ~YCLK_POST_DIV_MASK;
28048c2ecf20Sopenharmony_ci	mpll_ad_func_cntl |= YCLK_POST_DIV(mpll_param.post_div);
28058c2ecf20Sopenharmony_ci
28068c2ecf20Sopenharmony_ci	if (pi->mem_gddr5) {
28078c2ecf20Sopenharmony_ci		mpll_dq_func_cntl &= ~(YCLK_SEL_MASK | YCLK_POST_DIV_MASK);
28088c2ecf20Sopenharmony_ci		mpll_dq_func_cntl |= YCLK_SEL(mpll_param.yclk_sel) |
28098c2ecf20Sopenharmony_ci			YCLK_POST_DIV(mpll_param.post_div);
28108c2ecf20Sopenharmony_ci	}
28118c2ecf20Sopenharmony_ci
28128c2ecf20Sopenharmony_ci	if (pi->caps_mclk_ss_support) {
28138c2ecf20Sopenharmony_ci		struct radeon_atom_ss ss;
28148c2ecf20Sopenharmony_ci		u32 freq_nom;
28158c2ecf20Sopenharmony_ci		u32 tmp;
28168c2ecf20Sopenharmony_ci		u32 reference_clock = rdev->clock.mpll.reference_freq;
28178c2ecf20Sopenharmony_ci
28188c2ecf20Sopenharmony_ci		if (mpll_param.qdr == 1)
28198c2ecf20Sopenharmony_ci			freq_nom = memory_clock * 4 * (1 << mpll_param.post_div);
28208c2ecf20Sopenharmony_ci		else
28218c2ecf20Sopenharmony_ci			freq_nom = memory_clock * 2 * (1 << mpll_param.post_div);
28228c2ecf20Sopenharmony_ci
28238c2ecf20Sopenharmony_ci		tmp = (freq_nom / reference_clock);
28248c2ecf20Sopenharmony_ci		tmp = tmp * tmp;
28258c2ecf20Sopenharmony_ci		if (radeon_atombios_get_asic_ss_info(rdev, &ss,
28268c2ecf20Sopenharmony_ci						     ASIC_INTERNAL_MEMORY_SS, freq_nom)) {
28278c2ecf20Sopenharmony_ci			u32 clks = reference_clock * 5 / ss.rate;
28288c2ecf20Sopenharmony_ci			u32 clkv = (u32)((((131 * ss.percentage * ss.rate) / 100) * tmp) / freq_nom);
28298c2ecf20Sopenharmony_ci
28308c2ecf20Sopenharmony_ci			mpll_ss1 &= ~CLKV_MASK;
28318c2ecf20Sopenharmony_ci			mpll_ss1 |= CLKV(clkv);
28328c2ecf20Sopenharmony_ci
28338c2ecf20Sopenharmony_ci			mpll_ss2 &= ~CLKS_MASK;
28348c2ecf20Sopenharmony_ci			mpll_ss2 |= CLKS(clks);
28358c2ecf20Sopenharmony_ci		}
28368c2ecf20Sopenharmony_ci	}
28378c2ecf20Sopenharmony_ci
28388c2ecf20Sopenharmony_ci	mclk_pwrmgt_cntl &= ~DLL_SPEED_MASK;
28398c2ecf20Sopenharmony_ci	mclk_pwrmgt_cntl |= DLL_SPEED(mpll_param.dll_speed);
28408c2ecf20Sopenharmony_ci
28418c2ecf20Sopenharmony_ci	if (dll_state_on)
28428c2ecf20Sopenharmony_ci		mclk_pwrmgt_cntl |= MRDCK0_PDNB | MRDCK1_PDNB;
28438c2ecf20Sopenharmony_ci	else
28448c2ecf20Sopenharmony_ci		mclk_pwrmgt_cntl &= ~(MRDCK0_PDNB | MRDCK1_PDNB);
28458c2ecf20Sopenharmony_ci
28468c2ecf20Sopenharmony_ci	mclk->MclkFrequency = memory_clock;
28478c2ecf20Sopenharmony_ci	mclk->MpllFuncCntl = mpll_func_cntl;
28488c2ecf20Sopenharmony_ci	mclk->MpllFuncCntl_1 = mpll_func_cntl_1;
28498c2ecf20Sopenharmony_ci	mclk->MpllFuncCntl_2 = mpll_func_cntl_2;
28508c2ecf20Sopenharmony_ci	mclk->MpllAdFuncCntl = mpll_ad_func_cntl;
28518c2ecf20Sopenharmony_ci	mclk->MpllDqFuncCntl = mpll_dq_func_cntl;
28528c2ecf20Sopenharmony_ci	mclk->MclkPwrmgtCntl = mclk_pwrmgt_cntl;
28538c2ecf20Sopenharmony_ci	mclk->DllCntl = dll_cntl;
28548c2ecf20Sopenharmony_ci	mclk->MpllSs1 = mpll_ss1;
28558c2ecf20Sopenharmony_ci	mclk->MpllSs2 = mpll_ss2;
28568c2ecf20Sopenharmony_ci
28578c2ecf20Sopenharmony_ci	return 0;
28588c2ecf20Sopenharmony_ci}
28598c2ecf20Sopenharmony_ci
28608c2ecf20Sopenharmony_cistatic int ci_populate_single_memory_level(struct radeon_device *rdev,
28618c2ecf20Sopenharmony_ci					   u32 memory_clock,
28628c2ecf20Sopenharmony_ci					   SMU7_Discrete_MemoryLevel *memory_level)
28638c2ecf20Sopenharmony_ci{
28648c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
28658c2ecf20Sopenharmony_ci	int ret;
28668c2ecf20Sopenharmony_ci	bool dll_state_on;
28678c2ecf20Sopenharmony_ci
28688c2ecf20Sopenharmony_ci	if (rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries) {
28698c2ecf20Sopenharmony_ci		ret = ci_get_dependency_volt_by_clk(rdev,
28708c2ecf20Sopenharmony_ci						    &rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
28718c2ecf20Sopenharmony_ci						    memory_clock, &memory_level->MinVddc);
28728c2ecf20Sopenharmony_ci		if (ret)
28738c2ecf20Sopenharmony_ci			return ret;
28748c2ecf20Sopenharmony_ci	}
28758c2ecf20Sopenharmony_ci
28768c2ecf20Sopenharmony_ci	if (rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries) {
28778c2ecf20Sopenharmony_ci		ret = ci_get_dependency_volt_by_clk(rdev,
28788c2ecf20Sopenharmony_ci						    &rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
28798c2ecf20Sopenharmony_ci						    memory_clock, &memory_level->MinVddci);
28808c2ecf20Sopenharmony_ci		if (ret)
28818c2ecf20Sopenharmony_ci			return ret;
28828c2ecf20Sopenharmony_ci	}
28838c2ecf20Sopenharmony_ci
28848c2ecf20Sopenharmony_ci	if (rdev->pm.dpm.dyn_state.mvdd_dependency_on_mclk.entries) {
28858c2ecf20Sopenharmony_ci		ret = ci_get_dependency_volt_by_clk(rdev,
28868c2ecf20Sopenharmony_ci						    &rdev->pm.dpm.dyn_state.mvdd_dependency_on_mclk,
28878c2ecf20Sopenharmony_ci						    memory_clock, &memory_level->MinMvdd);
28888c2ecf20Sopenharmony_ci		if (ret)
28898c2ecf20Sopenharmony_ci			return ret;
28908c2ecf20Sopenharmony_ci	}
28918c2ecf20Sopenharmony_ci
28928c2ecf20Sopenharmony_ci	memory_level->MinVddcPhases = 1;
28938c2ecf20Sopenharmony_ci
28948c2ecf20Sopenharmony_ci	if (pi->vddc_phase_shed_control)
28958c2ecf20Sopenharmony_ci		ci_populate_phase_value_based_on_mclk(rdev,
28968c2ecf20Sopenharmony_ci						      &rdev->pm.dpm.dyn_state.phase_shedding_limits_table,
28978c2ecf20Sopenharmony_ci						      memory_clock,
28988c2ecf20Sopenharmony_ci						      &memory_level->MinVddcPhases);
28998c2ecf20Sopenharmony_ci
29008c2ecf20Sopenharmony_ci	memory_level->EnabledForThrottle = 1;
29018c2ecf20Sopenharmony_ci	memory_level->UpH = 0;
29028c2ecf20Sopenharmony_ci	memory_level->DownH = 100;
29038c2ecf20Sopenharmony_ci	memory_level->VoltageDownH = 0;
29048c2ecf20Sopenharmony_ci	memory_level->ActivityLevel = (u16)pi->mclk_activity_target;
29058c2ecf20Sopenharmony_ci
29068c2ecf20Sopenharmony_ci	memory_level->StutterEnable = false;
29078c2ecf20Sopenharmony_ci	memory_level->StrobeEnable = false;
29088c2ecf20Sopenharmony_ci	memory_level->EdcReadEnable = false;
29098c2ecf20Sopenharmony_ci	memory_level->EdcWriteEnable = false;
29108c2ecf20Sopenharmony_ci	memory_level->RttEnable = false;
29118c2ecf20Sopenharmony_ci
29128c2ecf20Sopenharmony_ci	memory_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
29138c2ecf20Sopenharmony_ci
29148c2ecf20Sopenharmony_ci	if (pi->mclk_stutter_mode_threshold &&
29158c2ecf20Sopenharmony_ci	    (memory_clock <= pi->mclk_stutter_mode_threshold) &&
29168c2ecf20Sopenharmony_ci	    (pi->uvd_enabled == false) &&
29178c2ecf20Sopenharmony_ci	    (RREG32(DPG_PIPE_STUTTER_CONTROL) & STUTTER_ENABLE) &&
29188c2ecf20Sopenharmony_ci	    (rdev->pm.dpm.new_active_crtc_count <= 2))
29198c2ecf20Sopenharmony_ci		memory_level->StutterEnable = true;
29208c2ecf20Sopenharmony_ci
29218c2ecf20Sopenharmony_ci	if (pi->mclk_strobe_mode_threshold &&
29228c2ecf20Sopenharmony_ci	    (memory_clock <= pi->mclk_strobe_mode_threshold))
29238c2ecf20Sopenharmony_ci		memory_level->StrobeEnable = 1;
29248c2ecf20Sopenharmony_ci
29258c2ecf20Sopenharmony_ci	if (pi->mem_gddr5) {
29268c2ecf20Sopenharmony_ci		memory_level->StrobeRatio =
29278c2ecf20Sopenharmony_ci			si_get_mclk_frequency_ratio(memory_clock, memory_level->StrobeEnable);
29288c2ecf20Sopenharmony_ci		if (pi->mclk_edc_enable_threshold &&
29298c2ecf20Sopenharmony_ci		    (memory_clock > pi->mclk_edc_enable_threshold))
29308c2ecf20Sopenharmony_ci			memory_level->EdcReadEnable = true;
29318c2ecf20Sopenharmony_ci
29328c2ecf20Sopenharmony_ci		if (pi->mclk_edc_wr_enable_threshold &&
29338c2ecf20Sopenharmony_ci		    (memory_clock > pi->mclk_edc_wr_enable_threshold))
29348c2ecf20Sopenharmony_ci			memory_level->EdcWriteEnable = true;
29358c2ecf20Sopenharmony_ci
29368c2ecf20Sopenharmony_ci		if (memory_level->StrobeEnable) {
29378c2ecf20Sopenharmony_ci			if (si_get_mclk_frequency_ratio(memory_clock, true) >=
29388c2ecf20Sopenharmony_ci			    ((RREG32(MC_SEQ_MISC7) >> 16) & 0xf))
29398c2ecf20Sopenharmony_ci				dll_state_on = ((RREG32(MC_SEQ_MISC5) >> 1) & 0x1) ? true : false;
29408c2ecf20Sopenharmony_ci			else
29418c2ecf20Sopenharmony_ci				dll_state_on = ((RREG32(MC_SEQ_MISC6) >> 1) & 0x1) ? true : false;
29428c2ecf20Sopenharmony_ci		} else {
29438c2ecf20Sopenharmony_ci			dll_state_on = pi->dll_default_on;
29448c2ecf20Sopenharmony_ci		}
29458c2ecf20Sopenharmony_ci	} else {
29468c2ecf20Sopenharmony_ci		memory_level->StrobeRatio = si_get_ddr3_mclk_frequency_ratio(memory_clock);
29478c2ecf20Sopenharmony_ci		dll_state_on = ((RREG32(MC_SEQ_MISC5) >> 1) & 0x1) ? true : false;
29488c2ecf20Sopenharmony_ci	}
29498c2ecf20Sopenharmony_ci
29508c2ecf20Sopenharmony_ci	ret = ci_calculate_mclk_params(rdev, memory_clock, memory_level, memory_level->StrobeEnable, dll_state_on);
29518c2ecf20Sopenharmony_ci	if (ret)
29528c2ecf20Sopenharmony_ci		return ret;
29538c2ecf20Sopenharmony_ci
29548c2ecf20Sopenharmony_ci	memory_level->MinVddc = cpu_to_be32(memory_level->MinVddc * VOLTAGE_SCALE);
29558c2ecf20Sopenharmony_ci	memory_level->MinVddcPhases = cpu_to_be32(memory_level->MinVddcPhases);
29568c2ecf20Sopenharmony_ci	memory_level->MinVddci = cpu_to_be32(memory_level->MinVddci * VOLTAGE_SCALE);
29578c2ecf20Sopenharmony_ci	memory_level->MinMvdd = cpu_to_be32(memory_level->MinMvdd * VOLTAGE_SCALE);
29588c2ecf20Sopenharmony_ci
29598c2ecf20Sopenharmony_ci	memory_level->MclkFrequency = cpu_to_be32(memory_level->MclkFrequency);
29608c2ecf20Sopenharmony_ci	memory_level->ActivityLevel = cpu_to_be16(memory_level->ActivityLevel);
29618c2ecf20Sopenharmony_ci	memory_level->MpllFuncCntl = cpu_to_be32(memory_level->MpllFuncCntl);
29628c2ecf20Sopenharmony_ci	memory_level->MpllFuncCntl_1 = cpu_to_be32(memory_level->MpllFuncCntl_1);
29638c2ecf20Sopenharmony_ci	memory_level->MpllFuncCntl_2 = cpu_to_be32(memory_level->MpllFuncCntl_2);
29648c2ecf20Sopenharmony_ci	memory_level->MpllAdFuncCntl = cpu_to_be32(memory_level->MpllAdFuncCntl);
29658c2ecf20Sopenharmony_ci	memory_level->MpllDqFuncCntl = cpu_to_be32(memory_level->MpllDqFuncCntl);
29668c2ecf20Sopenharmony_ci	memory_level->MclkPwrmgtCntl = cpu_to_be32(memory_level->MclkPwrmgtCntl);
29678c2ecf20Sopenharmony_ci	memory_level->DllCntl = cpu_to_be32(memory_level->DllCntl);
29688c2ecf20Sopenharmony_ci	memory_level->MpllSs1 = cpu_to_be32(memory_level->MpllSs1);
29698c2ecf20Sopenharmony_ci	memory_level->MpllSs2 = cpu_to_be32(memory_level->MpllSs2);
29708c2ecf20Sopenharmony_ci
29718c2ecf20Sopenharmony_ci	return 0;
29728c2ecf20Sopenharmony_ci}
29738c2ecf20Sopenharmony_ci
29748c2ecf20Sopenharmony_cistatic int ci_populate_smc_acpi_level(struct radeon_device *rdev,
29758c2ecf20Sopenharmony_ci				      SMU7_Discrete_DpmTable *table)
29768c2ecf20Sopenharmony_ci{
29778c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
29788c2ecf20Sopenharmony_ci	struct atom_clock_dividers dividers;
29798c2ecf20Sopenharmony_ci	SMU7_Discrete_VoltageLevel voltage_level;
29808c2ecf20Sopenharmony_ci	u32 spll_func_cntl = pi->clock_registers.cg_spll_func_cntl;
29818c2ecf20Sopenharmony_ci	u32 spll_func_cntl_2 = pi->clock_registers.cg_spll_func_cntl_2;
29828c2ecf20Sopenharmony_ci	u32 dll_cntl = pi->clock_registers.dll_cntl;
29838c2ecf20Sopenharmony_ci	u32 mclk_pwrmgt_cntl = pi->clock_registers.mclk_pwrmgt_cntl;
29848c2ecf20Sopenharmony_ci	int ret;
29858c2ecf20Sopenharmony_ci
29868c2ecf20Sopenharmony_ci	table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC;
29878c2ecf20Sopenharmony_ci
29888c2ecf20Sopenharmony_ci	if (pi->acpi_vddc)
29898c2ecf20Sopenharmony_ci		table->ACPILevel.MinVddc = cpu_to_be32(pi->acpi_vddc * VOLTAGE_SCALE);
29908c2ecf20Sopenharmony_ci	else
29918c2ecf20Sopenharmony_ci		table->ACPILevel.MinVddc = cpu_to_be32(pi->min_vddc_in_pp_table * VOLTAGE_SCALE);
29928c2ecf20Sopenharmony_ci
29938c2ecf20Sopenharmony_ci	table->ACPILevel.MinVddcPhases = pi->vddc_phase_shed_control ? 0 : 1;
29948c2ecf20Sopenharmony_ci
29958c2ecf20Sopenharmony_ci	table->ACPILevel.SclkFrequency = rdev->clock.spll.reference_freq;
29968c2ecf20Sopenharmony_ci
29978c2ecf20Sopenharmony_ci	ret = radeon_atom_get_clock_dividers(rdev,
29988c2ecf20Sopenharmony_ci					     COMPUTE_GPUCLK_INPUT_FLAG_SCLK,
29998c2ecf20Sopenharmony_ci					     table->ACPILevel.SclkFrequency, false, &dividers);
30008c2ecf20Sopenharmony_ci	if (ret)
30018c2ecf20Sopenharmony_ci		return ret;
30028c2ecf20Sopenharmony_ci
30038c2ecf20Sopenharmony_ci	table->ACPILevel.SclkDid = (u8)dividers.post_divider;
30048c2ecf20Sopenharmony_ci	table->ACPILevel.DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
30058c2ecf20Sopenharmony_ci	table->ACPILevel.DeepSleepDivId = 0;
30068c2ecf20Sopenharmony_ci
30078c2ecf20Sopenharmony_ci	spll_func_cntl &= ~SPLL_PWRON;
30088c2ecf20Sopenharmony_ci	spll_func_cntl |= SPLL_RESET;
30098c2ecf20Sopenharmony_ci
30108c2ecf20Sopenharmony_ci	spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
30118c2ecf20Sopenharmony_ci	spll_func_cntl_2 |= SCLK_MUX_SEL(4);
30128c2ecf20Sopenharmony_ci
30138c2ecf20Sopenharmony_ci	table->ACPILevel.CgSpllFuncCntl = spll_func_cntl;
30148c2ecf20Sopenharmony_ci	table->ACPILevel.CgSpllFuncCntl2 = spll_func_cntl_2;
30158c2ecf20Sopenharmony_ci	table->ACPILevel.CgSpllFuncCntl3 = pi->clock_registers.cg_spll_func_cntl_3;
30168c2ecf20Sopenharmony_ci	table->ACPILevel.CgSpllFuncCntl4 = pi->clock_registers.cg_spll_func_cntl_4;
30178c2ecf20Sopenharmony_ci	table->ACPILevel.SpllSpreadSpectrum = pi->clock_registers.cg_spll_spread_spectrum;
30188c2ecf20Sopenharmony_ci	table->ACPILevel.SpllSpreadSpectrum2 = pi->clock_registers.cg_spll_spread_spectrum_2;
30198c2ecf20Sopenharmony_ci	table->ACPILevel.CcPwrDynRm = 0;
30208c2ecf20Sopenharmony_ci	table->ACPILevel.CcPwrDynRm1 = 0;
30218c2ecf20Sopenharmony_ci
30228c2ecf20Sopenharmony_ci	table->ACPILevel.Flags = cpu_to_be32(table->ACPILevel.Flags);
30238c2ecf20Sopenharmony_ci	table->ACPILevel.MinVddcPhases = cpu_to_be32(table->ACPILevel.MinVddcPhases);
30248c2ecf20Sopenharmony_ci	table->ACPILevel.SclkFrequency = cpu_to_be32(table->ACPILevel.SclkFrequency);
30258c2ecf20Sopenharmony_ci	table->ACPILevel.CgSpllFuncCntl = cpu_to_be32(table->ACPILevel.CgSpllFuncCntl);
30268c2ecf20Sopenharmony_ci	table->ACPILevel.CgSpllFuncCntl2 = cpu_to_be32(table->ACPILevel.CgSpllFuncCntl2);
30278c2ecf20Sopenharmony_ci	table->ACPILevel.CgSpllFuncCntl3 = cpu_to_be32(table->ACPILevel.CgSpllFuncCntl3);
30288c2ecf20Sopenharmony_ci	table->ACPILevel.CgSpllFuncCntl4 = cpu_to_be32(table->ACPILevel.CgSpllFuncCntl4);
30298c2ecf20Sopenharmony_ci	table->ACPILevel.SpllSpreadSpectrum = cpu_to_be32(table->ACPILevel.SpllSpreadSpectrum);
30308c2ecf20Sopenharmony_ci	table->ACPILevel.SpllSpreadSpectrum2 = cpu_to_be32(table->ACPILevel.SpllSpreadSpectrum2);
30318c2ecf20Sopenharmony_ci	table->ACPILevel.CcPwrDynRm = cpu_to_be32(table->ACPILevel.CcPwrDynRm);
30328c2ecf20Sopenharmony_ci	table->ACPILevel.CcPwrDynRm1 = cpu_to_be32(table->ACPILevel.CcPwrDynRm1);
30338c2ecf20Sopenharmony_ci
30348c2ecf20Sopenharmony_ci	table->MemoryACPILevel.MinVddc = table->ACPILevel.MinVddc;
30358c2ecf20Sopenharmony_ci	table->MemoryACPILevel.MinVddcPhases = table->ACPILevel.MinVddcPhases;
30368c2ecf20Sopenharmony_ci
30378c2ecf20Sopenharmony_ci	if (pi->vddci_control != CISLANDS_VOLTAGE_CONTROL_NONE) {
30388c2ecf20Sopenharmony_ci		if (pi->acpi_vddci)
30398c2ecf20Sopenharmony_ci			table->MemoryACPILevel.MinVddci =
30408c2ecf20Sopenharmony_ci				cpu_to_be32(pi->acpi_vddci * VOLTAGE_SCALE);
30418c2ecf20Sopenharmony_ci		else
30428c2ecf20Sopenharmony_ci			table->MemoryACPILevel.MinVddci =
30438c2ecf20Sopenharmony_ci				cpu_to_be32(pi->min_vddci_in_pp_table * VOLTAGE_SCALE);
30448c2ecf20Sopenharmony_ci	}
30458c2ecf20Sopenharmony_ci
30468c2ecf20Sopenharmony_ci	if (ci_populate_mvdd_value(rdev, 0, &voltage_level))
30478c2ecf20Sopenharmony_ci		table->MemoryACPILevel.MinMvdd = 0;
30488c2ecf20Sopenharmony_ci	else
30498c2ecf20Sopenharmony_ci		table->MemoryACPILevel.MinMvdd =
30508c2ecf20Sopenharmony_ci			cpu_to_be32(voltage_level.Voltage * VOLTAGE_SCALE);
30518c2ecf20Sopenharmony_ci
30528c2ecf20Sopenharmony_ci	mclk_pwrmgt_cntl |= MRDCK0_RESET | MRDCK1_RESET;
30538c2ecf20Sopenharmony_ci	mclk_pwrmgt_cntl &= ~(MRDCK0_PDNB | MRDCK1_PDNB);
30548c2ecf20Sopenharmony_ci
30558c2ecf20Sopenharmony_ci	dll_cntl &= ~(MRDCK0_BYPASS | MRDCK1_BYPASS);
30568c2ecf20Sopenharmony_ci
30578c2ecf20Sopenharmony_ci	table->MemoryACPILevel.DllCntl = cpu_to_be32(dll_cntl);
30588c2ecf20Sopenharmony_ci	table->MemoryACPILevel.MclkPwrmgtCntl = cpu_to_be32(mclk_pwrmgt_cntl);
30598c2ecf20Sopenharmony_ci	table->MemoryACPILevel.MpllAdFuncCntl =
30608c2ecf20Sopenharmony_ci		cpu_to_be32(pi->clock_registers.mpll_ad_func_cntl);
30618c2ecf20Sopenharmony_ci	table->MemoryACPILevel.MpllDqFuncCntl =
30628c2ecf20Sopenharmony_ci		cpu_to_be32(pi->clock_registers.mpll_dq_func_cntl);
30638c2ecf20Sopenharmony_ci	table->MemoryACPILevel.MpllFuncCntl =
30648c2ecf20Sopenharmony_ci		cpu_to_be32(pi->clock_registers.mpll_func_cntl);
30658c2ecf20Sopenharmony_ci	table->MemoryACPILevel.MpllFuncCntl_1 =
30668c2ecf20Sopenharmony_ci		cpu_to_be32(pi->clock_registers.mpll_func_cntl_1);
30678c2ecf20Sopenharmony_ci	table->MemoryACPILevel.MpllFuncCntl_2 =
30688c2ecf20Sopenharmony_ci		cpu_to_be32(pi->clock_registers.mpll_func_cntl_2);
30698c2ecf20Sopenharmony_ci	table->MemoryACPILevel.MpllSs1 = cpu_to_be32(pi->clock_registers.mpll_ss1);
30708c2ecf20Sopenharmony_ci	table->MemoryACPILevel.MpllSs2 = cpu_to_be32(pi->clock_registers.mpll_ss2);
30718c2ecf20Sopenharmony_ci
30728c2ecf20Sopenharmony_ci	table->MemoryACPILevel.EnabledForThrottle = 0;
30738c2ecf20Sopenharmony_ci	table->MemoryACPILevel.EnabledForActivity = 0;
30748c2ecf20Sopenharmony_ci	table->MemoryACPILevel.UpH = 0;
30758c2ecf20Sopenharmony_ci	table->MemoryACPILevel.DownH = 100;
30768c2ecf20Sopenharmony_ci	table->MemoryACPILevel.VoltageDownH = 0;
30778c2ecf20Sopenharmony_ci	table->MemoryACPILevel.ActivityLevel =
30788c2ecf20Sopenharmony_ci		cpu_to_be16((u16)pi->mclk_activity_target);
30798c2ecf20Sopenharmony_ci
30808c2ecf20Sopenharmony_ci	table->MemoryACPILevel.StutterEnable = false;
30818c2ecf20Sopenharmony_ci	table->MemoryACPILevel.StrobeEnable = false;
30828c2ecf20Sopenharmony_ci	table->MemoryACPILevel.EdcReadEnable = false;
30838c2ecf20Sopenharmony_ci	table->MemoryACPILevel.EdcWriteEnable = false;
30848c2ecf20Sopenharmony_ci	table->MemoryACPILevel.RttEnable = false;
30858c2ecf20Sopenharmony_ci
30868c2ecf20Sopenharmony_ci	return 0;
30878c2ecf20Sopenharmony_ci}
30888c2ecf20Sopenharmony_ci
30898c2ecf20Sopenharmony_ci
30908c2ecf20Sopenharmony_cistatic int ci_enable_ulv(struct radeon_device *rdev, bool enable)
30918c2ecf20Sopenharmony_ci{
30928c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
30938c2ecf20Sopenharmony_ci	struct ci_ulv_parm *ulv = &pi->ulv;
30948c2ecf20Sopenharmony_ci
30958c2ecf20Sopenharmony_ci	if (ulv->supported) {
30968c2ecf20Sopenharmony_ci		if (enable)
30978c2ecf20Sopenharmony_ci			return (ci_send_msg_to_smc(rdev, PPSMC_MSG_EnableULV) == PPSMC_Result_OK) ?
30988c2ecf20Sopenharmony_ci				0 : -EINVAL;
30998c2ecf20Sopenharmony_ci		else
31008c2ecf20Sopenharmony_ci			return (ci_send_msg_to_smc(rdev, PPSMC_MSG_DisableULV) == PPSMC_Result_OK) ?
31018c2ecf20Sopenharmony_ci				0 : -EINVAL;
31028c2ecf20Sopenharmony_ci	}
31038c2ecf20Sopenharmony_ci
31048c2ecf20Sopenharmony_ci	return 0;
31058c2ecf20Sopenharmony_ci}
31068c2ecf20Sopenharmony_ci
31078c2ecf20Sopenharmony_cistatic int ci_populate_ulv_level(struct radeon_device *rdev,
31088c2ecf20Sopenharmony_ci				 SMU7_Discrete_Ulv *state)
31098c2ecf20Sopenharmony_ci{
31108c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
31118c2ecf20Sopenharmony_ci	u16 ulv_voltage = rdev->pm.dpm.backbias_response_time;
31128c2ecf20Sopenharmony_ci
31138c2ecf20Sopenharmony_ci	state->CcPwrDynRm = 0;
31148c2ecf20Sopenharmony_ci	state->CcPwrDynRm1 = 0;
31158c2ecf20Sopenharmony_ci
31168c2ecf20Sopenharmony_ci	if (ulv_voltage == 0) {
31178c2ecf20Sopenharmony_ci		pi->ulv.supported = false;
31188c2ecf20Sopenharmony_ci		return 0;
31198c2ecf20Sopenharmony_ci	}
31208c2ecf20Sopenharmony_ci
31218c2ecf20Sopenharmony_ci	if (pi->voltage_control != CISLANDS_VOLTAGE_CONTROL_BY_SVID2) {
31228c2ecf20Sopenharmony_ci		if (ulv_voltage > rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[0].v)
31238c2ecf20Sopenharmony_ci			state->VddcOffset = 0;
31248c2ecf20Sopenharmony_ci		else
31258c2ecf20Sopenharmony_ci			state->VddcOffset =
31268c2ecf20Sopenharmony_ci				rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[0].v - ulv_voltage;
31278c2ecf20Sopenharmony_ci	} else {
31288c2ecf20Sopenharmony_ci		if (ulv_voltage > rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[0].v)
31298c2ecf20Sopenharmony_ci			state->VddcOffsetVid = 0;
31308c2ecf20Sopenharmony_ci		else
31318c2ecf20Sopenharmony_ci			state->VddcOffsetVid = (u8)
31328c2ecf20Sopenharmony_ci				((rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[0].v - ulv_voltage) *
31338c2ecf20Sopenharmony_ci				 VOLTAGE_VID_OFFSET_SCALE2 / VOLTAGE_VID_OFFSET_SCALE1);
31348c2ecf20Sopenharmony_ci	}
31358c2ecf20Sopenharmony_ci	state->VddcPhase = pi->vddc_phase_shed_control ? 0 : 1;
31368c2ecf20Sopenharmony_ci
31378c2ecf20Sopenharmony_ci	state->CcPwrDynRm = cpu_to_be32(state->CcPwrDynRm);
31388c2ecf20Sopenharmony_ci	state->CcPwrDynRm1 = cpu_to_be32(state->CcPwrDynRm1);
31398c2ecf20Sopenharmony_ci	state->VddcOffset = cpu_to_be16(state->VddcOffset);
31408c2ecf20Sopenharmony_ci
31418c2ecf20Sopenharmony_ci	return 0;
31428c2ecf20Sopenharmony_ci}
31438c2ecf20Sopenharmony_ci
31448c2ecf20Sopenharmony_cistatic int ci_calculate_sclk_params(struct radeon_device *rdev,
31458c2ecf20Sopenharmony_ci				    u32 engine_clock,
31468c2ecf20Sopenharmony_ci				    SMU7_Discrete_GraphicsLevel *sclk)
31478c2ecf20Sopenharmony_ci{
31488c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
31498c2ecf20Sopenharmony_ci	struct atom_clock_dividers dividers;
31508c2ecf20Sopenharmony_ci	u32 spll_func_cntl_3 = pi->clock_registers.cg_spll_func_cntl_3;
31518c2ecf20Sopenharmony_ci	u32 spll_func_cntl_4 = pi->clock_registers.cg_spll_func_cntl_4;
31528c2ecf20Sopenharmony_ci	u32 cg_spll_spread_spectrum = pi->clock_registers.cg_spll_spread_spectrum;
31538c2ecf20Sopenharmony_ci	u32 cg_spll_spread_spectrum_2 = pi->clock_registers.cg_spll_spread_spectrum_2;
31548c2ecf20Sopenharmony_ci	u32 reference_clock = rdev->clock.spll.reference_freq;
31558c2ecf20Sopenharmony_ci	u32 reference_divider;
31568c2ecf20Sopenharmony_ci	u32 fbdiv;
31578c2ecf20Sopenharmony_ci	int ret;
31588c2ecf20Sopenharmony_ci
31598c2ecf20Sopenharmony_ci	ret = radeon_atom_get_clock_dividers(rdev,
31608c2ecf20Sopenharmony_ci					     COMPUTE_GPUCLK_INPUT_FLAG_SCLK,
31618c2ecf20Sopenharmony_ci					     engine_clock, false, &dividers);
31628c2ecf20Sopenharmony_ci	if (ret)
31638c2ecf20Sopenharmony_ci		return ret;
31648c2ecf20Sopenharmony_ci
31658c2ecf20Sopenharmony_ci	reference_divider = 1 + dividers.ref_div;
31668c2ecf20Sopenharmony_ci	fbdiv = dividers.fb_div & 0x3FFFFFF;
31678c2ecf20Sopenharmony_ci
31688c2ecf20Sopenharmony_ci	spll_func_cntl_3 &= ~SPLL_FB_DIV_MASK;
31698c2ecf20Sopenharmony_ci	spll_func_cntl_3 |= SPLL_FB_DIV(fbdiv);
31708c2ecf20Sopenharmony_ci	spll_func_cntl_3 |= SPLL_DITHEN;
31718c2ecf20Sopenharmony_ci
31728c2ecf20Sopenharmony_ci	if (pi->caps_sclk_ss_support) {
31738c2ecf20Sopenharmony_ci		struct radeon_atom_ss ss;
31748c2ecf20Sopenharmony_ci		u32 vco_freq = engine_clock * dividers.post_div;
31758c2ecf20Sopenharmony_ci
31768c2ecf20Sopenharmony_ci		if (radeon_atombios_get_asic_ss_info(rdev, &ss,
31778c2ecf20Sopenharmony_ci						     ASIC_INTERNAL_ENGINE_SS, vco_freq)) {
31788c2ecf20Sopenharmony_ci			u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate);
31798c2ecf20Sopenharmony_ci			u32 clk_v = 4 * ss.percentage * fbdiv / (clk_s * 10000);
31808c2ecf20Sopenharmony_ci
31818c2ecf20Sopenharmony_ci			cg_spll_spread_spectrum &= ~CLK_S_MASK;
31828c2ecf20Sopenharmony_ci			cg_spll_spread_spectrum |= CLK_S(clk_s);
31838c2ecf20Sopenharmony_ci			cg_spll_spread_spectrum |= SSEN;
31848c2ecf20Sopenharmony_ci
31858c2ecf20Sopenharmony_ci			cg_spll_spread_spectrum_2 &= ~CLK_V_MASK;
31868c2ecf20Sopenharmony_ci			cg_spll_spread_spectrum_2 |= CLK_V(clk_v);
31878c2ecf20Sopenharmony_ci		}
31888c2ecf20Sopenharmony_ci	}
31898c2ecf20Sopenharmony_ci
31908c2ecf20Sopenharmony_ci	sclk->SclkFrequency = engine_clock;
31918c2ecf20Sopenharmony_ci	sclk->CgSpllFuncCntl3 = spll_func_cntl_3;
31928c2ecf20Sopenharmony_ci	sclk->CgSpllFuncCntl4 = spll_func_cntl_4;
31938c2ecf20Sopenharmony_ci	sclk->SpllSpreadSpectrum = cg_spll_spread_spectrum;
31948c2ecf20Sopenharmony_ci	sclk->SpllSpreadSpectrum2  = cg_spll_spread_spectrum_2;
31958c2ecf20Sopenharmony_ci	sclk->SclkDid = (u8)dividers.post_divider;
31968c2ecf20Sopenharmony_ci
31978c2ecf20Sopenharmony_ci	return 0;
31988c2ecf20Sopenharmony_ci}
31998c2ecf20Sopenharmony_ci
32008c2ecf20Sopenharmony_cistatic int ci_populate_single_graphic_level(struct radeon_device *rdev,
32018c2ecf20Sopenharmony_ci					    u32 engine_clock,
32028c2ecf20Sopenharmony_ci					    u16 sclk_activity_level_t,
32038c2ecf20Sopenharmony_ci					    SMU7_Discrete_GraphicsLevel *graphic_level)
32048c2ecf20Sopenharmony_ci{
32058c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
32068c2ecf20Sopenharmony_ci	int ret;
32078c2ecf20Sopenharmony_ci
32088c2ecf20Sopenharmony_ci	ret = ci_calculate_sclk_params(rdev, engine_clock, graphic_level);
32098c2ecf20Sopenharmony_ci	if (ret)
32108c2ecf20Sopenharmony_ci		return ret;
32118c2ecf20Sopenharmony_ci
32128c2ecf20Sopenharmony_ci	ret = ci_get_dependency_volt_by_clk(rdev,
32138c2ecf20Sopenharmony_ci					    &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
32148c2ecf20Sopenharmony_ci					    engine_clock, &graphic_level->MinVddc);
32158c2ecf20Sopenharmony_ci	if (ret)
32168c2ecf20Sopenharmony_ci		return ret;
32178c2ecf20Sopenharmony_ci
32188c2ecf20Sopenharmony_ci	graphic_level->SclkFrequency = engine_clock;
32198c2ecf20Sopenharmony_ci
32208c2ecf20Sopenharmony_ci	graphic_level->Flags =  0;
32218c2ecf20Sopenharmony_ci	graphic_level->MinVddcPhases = 1;
32228c2ecf20Sopenharmony_ci
32238c2ecf20Sopenharmony_ci	if (pi->vddc_phase_shed_control)
32248c2ecf20Sopenharmony_ci		ci_populate_phase_value_based_on_sclk(rdev,
32258c2ecf20Sopenharmony_ci						      &rdev->pm.dpm.dyn_state.phase_shedding_limits_table,
32268c2ecf20Sopenharmony_ci						      engine_clock,
32278c2ecf20Sopenharmony_ci						      &graphic_level->MinVddcPhases);
32288c2ecf20Sopenharmony_ci
32298c2ecf20Sopenharmony_ci	graphic_level->ActivityLevel = sclk_activity_level_t;
32308c2ecf20Sopenharmony_ci
32318c2ecf20Sopenharmony_ci	graphic_level->CcPwrDynRm = 0;
32328c2ecf20Sopenharmony_ci	graphic_level->CcPwrDynRm1 = 0;
32338c2ecf20Sopenharmony_ci	graphic_level->EnabledForThrottle = 1;
32348c2ecf20Sopenharmony_ci	graphic_level->UpH = 0;
32358c2ecf20Sopenharmony_ci	graphic_level->DownH = 0;
32368c2ecf20Sopenharmony_ci	graphic_level->VoltageDownH = 0;
32378c2ecf20Sopenharmony_ci	graphic_level->PowerThrottle = 0;
32388c2ecf20Sopenharmony_ci
32398c2ecf20Sopenharmony_ci	if (pi->caps_sclk_ds)
32408c2ecf20Sopenharmony_ci		graphic_level->DeepSleepDivId = ci_get_sleep_divider_id_from_clock(rdev,
32418c2ecf20Sopenharmony_ci										   engine_clock,
32428c2ecf20Sopenharmony_ci										   CISLAND_MINIMUM_ENGINE_CLOCK);
32438c2ecf20Sopenharmony_ci
32448c2ecf20Sopenharmony_ci	graphic_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW;
32458c2ecf20Sopenharmony_ci
32468c2ecf20Sopenharmony_ci	graphic_level->Flags = cpu_to_be32(graphic_level->Flags);
32478c2ecf20Sopenharmony_ci	graphic_level->MinVddc = cpu_to_be32(graphic_level->MinVddc * VOLTAGE_SCALE);
32488c2ecf20Sopenharmony_ci	graphic_level->MinVddcPhases = cpu_to_be32(graphic_level->MinVddcPhases);
32498c2ecf20Sopenharmony_ci	graphic_level->SclkFrequency = cpu_to_be32(graphic_level->SclkFrequency);
32508c2ecf20Sopenharmony_ci	graphic_level->ActivityLevel = cpu_to_be16(graphic_level->ActivityLevel);
32518c2ecf20Sopenharmony_ci	graphic_level->CgSpllFuncCntl3 = cpu_to_be32(graphic_level->CgSpllFuncCntl3);
32528c2ecf20Sopenharmony_ci	graphic_level->CgSpllFuncCntl4 = cpu_to_be32(graphic_level->CgSpllFuncCntl4);
32538c2ecf20Sopenharmony_ci	graphic_level->SpllSpreadSpectrum = cpu_to_be32(graphic_level->SpllSpreadSpectrum);
32548c2ecf20Sopenharmony_ci	graphic_level->SpllSpreadSpectrum2 = cpu_to_be32(graphic_level->SpllSpreadSpectrum2);
32558c2ecf20Sopenharmony_ci	graphic_level->CcPwrDynRm = cpu_to_be32(graphic_level->CcPwrDynRm);
32568c2ecf20Sopenharmony_ci	graphic_level->CcPwrDynRm1 = cpu_to_be32(graphic_level->CcPwrDynRm1);
32578c2ecf20Sopenharmony_ci
32588c2ecf20Sopenharmony_ci	return 0;
32598c2ecf20Sopenharmony_ci}
32608c2ecf20Sopenharmony_ci
32618c2ecf20Sopenharmony_cistatic int ci_populate_all_graphic_levels(struct radeon_device *rdev)
32628c2ecf20Sopenharmony_ci{
32638c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
32648c2ecf20Sopenharmony_ci	struct ci_dpm_table *dpm_table = &pi->dpm_table;
32658c2ecf20Sopenharmony_ci	u32 level_array_address = pi->dpm_table_start +
32668c2ecf20Sopenharmony_ci		offsetof(SMU7_Discrete_DpmTable, GraphicsLevel);
32678c2ecf20Sopenharmony_ci	u32 level_array_size = sizeof(SMU7_Discrete_GraphicsLevel) *
32688c2ecf20Sopenharmony_ci		SMU7_MAX_LEVELS_GRAPHICS;
32698c2ecf20Sopenharmony_ci	SMU7_Discrete_GraphicsLevel *levels = pi->smc_state_table.GraphicsLevel;
32708c2ecf20Sopenharmony_ci	u32 i, ret;
32718c2ecf20Sopenharmony_ci
32728c2ecf20Sopenharmony_ci	memset(levels, 0, level_array_size);
32738c2ecf20Sopenharmony_ci
32748c2ecf20Sopenharmony_ci	for (i = 0; i < dpm_table->sclk_table.count; i++) {
32758c2ecf20Sopenharmony_ci		ret = ci_populate_single_graphic_level(rdev,
32768c2ecf20Sopenharmony_ci						       dpm_table->sclk_table.dpm_levels[i].value,
32778c2ecf20Sopenharmony_ci						       (u16)pi->activity_target[i],
32788c2ecf20Sopenharmony_ci						       &pi->smc_state_table.GraphicsLevel[i]);
32798c2ecf20Sopenharmony_ci		if (ret)
32808c2ecf20Sopenharmony_ci			return ret;
32818c2ecf20Sopenharmony_ci		if (i > 1)
32828c2ecf20Sopenharmony_ci			pi->smc_state_table.GraphicsLevel[i].DeepSleepDivId = 0;
32838c2ecf20Sopenharmony_ci		if (i == (dpm_table->sclk_table.count - 1))
32848c2ecf20Sopenharmony_ci			pi->smc_state_table.GraphicsLevel[i].DisplayWatermark =
32858c2ecf20Sopenharmony_ci				PPSMC_DISPLAY_WATERMARK_HIGH;
32868c2ecf20Sopenharmony_ci	}
32878c2ecf20Sopenharmony_ci	pi->smc_state_table.GraphicsLevel[0].EnabledForActivity = 1;
32888c2ecf20Sopenharmony_ci
32898c2ecf20Sopenharmony_ci	pi->smc_state_table.GraphicsDpmLevelCount = (u8)dpm_table->sclk_table.count;
32908c2ecf20Sopenharmony_ci	pi->dpm_level_enable_mask.sclk_dpm_enable_mask =
32918c2ecf20Sopenharmony_ci		ci_get_dpm_level_enable_mask_value(&dpm_table->sclk_table);
32928c2ecf20Sopenharmony_ci
32938c2ecf20Sopenharmony_ci	ret = ci_copy_bytes_to_smc(rdev, level_array_address,
32948c2ecf20Sopenharmony_ci				   (u8 *)levels, level_array_size,
32958c2ecf20Sopenharmony_ci				   pi->sram_end);
32968c2ecf20Sopenharmony_ci	if (ret)
32978c2ecf20Sopenharmony_ci		return ret;
32988c2ecf20Sopenharmony_ci
32998c2ecf20Sopenharmony_ci	return 0;
33008c2ecf20Sopenharmony_ci}
33018c2ecf20Sopenharmony_ci
33028c2ecf20Sopenharmony_cistatic int ci_populate_ulv_state(struct radeon_device *rdev,
33038c2ecf20Sopenharmony_ci				 SMU7_Discrete_Ulv *ulv_level)
33048c2ecf20Sopenharmony_ci{
33058c2ecf20Sopenharmony_ci	return ci_populate_ulv_level(rdev, ulv_level);
33068c2ecf20Sopenharmony_ci}
33078c2ecf20Sopenharmony_ci
33088c2ecf20Sopenharmony_cistatic int ci_populate_all_memory_levels(struct radeon_device *rdev)
33098c2ecf20Sopenharmony_ci{
33108c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
33118c2ecf20Sopenharmony_ci	struct ci_dpm_table *dpm_table = &pi->dpm_table;
33128c2ecf20Sopenharmony_ci	u32 level_array_address = pi->dpm_table_start +
33138c2ecf20Sopenharmony_ci		offsetof(SMU7_Discrete_DpmTable, MemoryLevel);
33148c2ecf20Sopenharmony_ci	u32 level_array_size = sizeof(SMU7_Discrete_MemoryLevel) *
33158c2ecf20Sopenharmony_ci		SMU7_MAX_LEVELS_MEMORY;
33168c2ecf20Sopenharmony_ci	SMU7_Discrete_MemoryLevel *levels = pi->smc_state_table.MemoryLevel;
33178c2ecf20Sopenharmony_ci	u32 i, ret;
33188c2ecf20Sopenharmony_ci
33198c2ecf20Sopenharmony_ci	memset(levels, 0, level_array_size);
33208c2ecf20Sopenharmony_ci
33218c2ecf20Sopenharmony_ci	for (i = 0; i < dpm_table->mclk_table.count; i++) {
33228c2ecf20Sopenharmony_ci		if (dpm_table->mclk_table.dpm_levels[i].value == 0)
33238c2ecf20Sopenharmony_ci			return -EINVAL;
33248c2ecf20Sopenharmony_ci		ret = ci_populate_single_memory_level(rdev,
33258c2ecf20Sopenharmony_ci						      dpm_table->mclk_table.dpm_levels[i].value,
33268c2ecf20Sopenharmony_ci						      &pi->smc_state_table.MemoryLevel[i]);
33278c2ecf20Sopenharmony_ci		if (ret)
33288c2ecf20Sopenharmony_ci			return ret;
33298c2ecf20Sopenharmony_ci	}
33308c2ecf20Sopenharmony_ci
33318c2ecf20Sopenharmony_ci	pi->smc_state_table.MemoryLevel[0].EnabledForActivity = 1;
33328c2ecf20Sopenharmony_ci
33338c2ecf20Sopenharmony_ci	if ((dpm_table->mclk_table.count >= 2) &&
33348c2ecf20Sopenharmony_ci	    ((rdev->pdev->device == 0x67B0) || (rdev->pdev->device == 0x67B1))) {
33358c2ecf20Sopenharmony_ci		pi->smc_state_table.MemoryLevel[1].MinVddc =
33368c2ecf20Sopenharmony_ci			pi->smc_state_table.MemoryLevel[0].MinVddc;
33378c2ecf20Sopenharmony_ci		pi->smc_state_table.MemoryLevel[1].MinVddcPhases =
33388c2ecf20Sopenharmony_ci			pi->smc_state_table.MemoryLevel[0].MinVddcPhases;
33398c2ecf20Sopenharmony_ci	}
33408c2ecf20Sopenharmony_ci
33418c2ecf20Sopenharmony_ci	pi->smc_state_table.MemoryLevel[0].ActivityLevel = cpu_to_be16(0x1F);
33428c2ecf20Sopenharmony_ci
33438c2ecf20Sopenharmony_ci	pi->smc_state_table.MemoryDpmLevelCount = (u8)dpm_table->mclk_table.count;
33448c2ecf20Sopenharmony_ci	pi->dpm_level_enable_mask.mclk_dpm_enable_mask =
33458c2ecf20Sopenharmony_ci		ci_get_dpm_level_enable_mask_value(&dpm_table->mclk_table);
33468c2ecf20Sopenharmony_ci
33478c2ecf20Sopenharmony_ci	pi->smc_state_table.MemoryLevel[dpm_table->mclk_table.count - 1].DisplayWatermark =
33488c2ecf20Sopenharmony_ci		PPSMC_DISPLAY_WATERMARK_HIGH;
33498c2ecf20Sopenharmony_ci
33508c2ecf20Sopenharmony_ci	ret = ci_copy_bytes_to_smc(rdev, level_array_address,
33518c2ecf20Sopenharmony_ci				   (u8 *)levels, level_array_size,
33528c2ecf20Sopenharmony_ci				   pi->sram_end);
33538c2ecf20Sopenharmony_ci	if (ret)
33548c2ecf20Sopenharmony_ci		return ret;
33558c2ecf20Sopenharmony_ci
33568c2ecf20Sopenharmony_ci	return 0;
33578c2ecf20Sopenharmony_ci}
33588c2ecf20Sopenharmony_ci
33598c2ecf20Sopenharmony_cistatic void ci_reset_single_dpm_table(struct radeon_device *rdev,
33608c2ecf20Sopenharmony_ci				      struct ci_single_dpm_table* dpm_table,
33618c2ecf20Sopenharmony_ci				      u32 count)
33628c2ecf20Sopenharmony_ci{
33638c2ecf20Sopenharmony_ci	u32 i;
33648c2ecf20Sopenharmony_ci
33658c2ecf20Sopenharmony_ci	dpm_table->count = count;
33668c2ecf20Sopenharmony_ci	for (i = 0; i < MAX_REGULAR_DPM_NUMBER; i++)
33678c2ecf20Sopenharmony_ci		dpm_table->dpm_levels[i].enabled = false;
33688c2ecf20Sopenharmony_ci}
33698c2ecf20Sopenharmony_ci
33708c2ecf20Sopenharmony_cistatic void ci_setup_pcie_table_entry(struct ci_single_dpm_table* dpm_table,
33718c2ecf20Sopenharmony_ci				      u32 index, u32 pcie_gen, u32 pcie_lanes)
33728c2ecf20Sopenharmony_ci{
33738c2ecf20Sopenharmony_ci	dpm_table->dpm_levels[index].value = pcie_gen;
33748c2ecf20Sopenharmony_ci	dpm_table->dpm_levels[index].param1 = pcie_lanes;
33758c2ecf20Sopenharmony_ci	dpm_table->dpm_levels[index].enabled = true;
33768c2ecf20Sopenharmony_ci}
33778c2ecf20Sopenharmony_ci
33788c2ecf20Sopenharmony_cistatic int ci_setup_default_pcie_tables(struct radeon_device *rdev)
33798c2ecf20Sopenharmony_ci{
33808c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
33818c2ecf20Sopenharmony_ci
33828c2ecf20Sopenharmony_ci	if (!pi->use_pcie_performance_levels && !pi->use_pcie_powersaving_levels)
33838c2ecf20Sopenharmony_ci		return -EINVAL;
33848c2ecf20Sopenharmony_ci
33858c2ecf20Sopenharmony_ci	if (pi->use_pcie_performance_levels && !pi->use_pcie_powersaving_levels) {
33868c2ecf20Sopenharmony_ci		pi->pcie_gen_powersaving = pi->pcie_gen_performance;
33878c2ecf20Sopenharmony_ci		pi->pcie_lane_powersaving = pi->pcie_lane_performance;
33888c2ecf20Sopenharmony_ci	} else if (!pi->use_pcie_performance_levels && pi->use_pcie_powersaving_levels) {
33898c2ecf20Sopenharmony_ci		pi->pcie_gen_performance = pi->pcie_gen_powersaving;
33908c2ecf20Sopenharmony_ci		pi->pcie_lane_performance = pi->pcie_lane_powersaving;
33918c2ecf20Sopenharmony_ci	}
33928c2ecf20Sopenharmony_ci
33938c2ecf20Sopenharmony_ci	ci_reset_single_dpm_table(rdev,
33948c2ecf20Sopenharmony_ci				  &pi->dpm_table.pcie_speed_table,
33958c2ecf20Sopenharmony_ci				  SMU7_MAX_LEVELS_LINK);
33968c2ecf20Sopenharmony_ci
33978c2ecf20Sopenharmony_ci	if (rdev->family == CHIP_BONAIRE)
33988c2ecf20Sopenharmony_ci		ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 0,
33998c2ecf20Sopenharmony_ci					  pi->pcie_gen_powersaving.min,
34008c2ecf20Sopenharmony_ci					  pi->pcie_lane_powersaving.max);
34018c2ecf20Sopenharmony_ci	else
34028c2ecf20Sopenharmony_ci		ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 0,
34038c2ecf20Sopenharmony_ci					  pi->pcie_gen_powersaving.min,
34048c2ecf20Sopenharmony_ci					  pi->pcie_lane_powersaving.min);
34058c2ecf20Sopenharmony_ci	ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 1,
34068c2ecf20Sopenharmony_ci				  pi->pcie_gen_performance.min,
34078c2ecf20Sopenharmony_ci				  pi->pcie_lane_performance.min);
34088c2ecf20Sopenharmony_ci	ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 2,
34098c2ecf20Sopenharmony_ci				  pi->pcie_gen_powersaving.min,
34108c2ecf20Sopenharmony_ci				  pi->pcie_lane_powersaving.max);
34118c2ecf20Sopenharmony_ci	ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 3,
34128c2ecf20Sopenharmony_ci				  pi->pcie_gen_performance.min,
34138c2ecf20Sopenharmony_ci				  pi->pcie_lane_performance.max);
34148c2ecf20Sopenharmony_ci	ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 4,
34158c2ecf20Sopenharmony_ci				  pi->pcie_gen_powersaving.max,
34168c2ecf20Sopenharmony_ci				  pi->pcie_lane_powersaving.max);
34178c2ecf20Sopenharmony_ci	ci_setup_pcie_table_entry(&pi->dpm_table.pcie_speed_table, 5,
34188c2ecf20Sopenharmony_ci				  pi->pcie_gen_performance.max,
34198c2ecf20Sopenharmony_ci				  pi->pcie_lane_performance.max);
34208c2ecf20Sopenharmony_ci
34218c2ecf20Sopenharmony_ci	pi->dpm_table.pcie_speed_table.count = 6;
34228c2ecf20Sopenharmony_ci
34238c2ecf20Sopenharmony_ci	return 0;
34248c2ecf20Sopenharmony_ci}
34258c2ecf20Sopenharmony_ci
34268c2ecf20Sopenharmony_cistatic int ci_setup_default_dpm_tables(struct radeon_device *rdev)
34278c2ecf20Sopenharmony_ci{
34288c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
34298c2ecf20Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *allowed_sclk_vddc_table =
34308c2ecf20Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
34318c2ecf20Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *allowed_mclk_table =
34328c2ecf20Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk;
34338c2ecf20Sopenharmony_ci	struct radeon_cac_leakage_table *std_voltage_table =
34348c2ecf20Sopenharmony_ci		&rdev->pm.dpm.dyn_state.cac_leakage_table;
34358c2ecf20Sopenharmony_ci	u32 i;
34368c2ecf20Sopenharmony_ci
34378c2ecf20Sopenharmony_ci	if (allowed_sclk_vddc_table == NULL)
34388c2ecf20Sopenharmony_ci		return -EINVAL;
34398c2ecf20Sopenharmony_ci	if (allowed_sclk_vddc_table->count < 1)
34408c2ecf20Sopenharmony_ci		return -EINVAL;
34418c2ecf20Sopenharmony_ci	if (allowed_mclk_table == NULL)
34428c2ecf20Sopenharmony_ci		return -EINVAL;
34438c2ecf20Sopenharmony_ci	if (allowed_mclk_table->count < 1)
34448c2ecf20Sopenharmony_ci		return -EINVAL;
34458c2ecf20Sopenharmony_ci
34468c2ecf20Sopenharmony_ci	memset(&pi->dpm_table, 0, sizeof(struct ci_dpm_table));
34478c2ecf20Sopenharmony_ci
34488c2ecf20Sopenharmony_ci	ci_reset_single_dpm_table(rdev,
34498c2ecf20Sopenharmony_ci				  &pi->dpm_table.sclk_table,
34508c2ecf20Sopenharmony_ci				  SMU7_MAX_LEVELS_GRAPHICS);
34518c2ecf20Sopenharmony_ci	ci_reset_single_dpm_table(rdev,
34528c2ecf20Sopenharmony_ci				  &pi->dpm_table.mclk_table,
34538c2ecf20Sopenharmony_ci				  SMU7_MAX_LEVELS_MEMORY);
34548c2ecf20Sopenharmony_ci	ci_reset_single_dpm_table(rdev,
34558c2ecf20Sopenharmony_ci				  &pi->dpm_table.vddc_table,
34568c2ecf20Sopenharmony_ci				  SMU7_MAX_LEVELS_VDDC);
34578c2ecf20Sopenharmony_ci	ci_reset_single_dpm_table(rdev,
34588c2ecf20Sopenharmony_ci				  &pi->dpm_table.vddci_table,
34598c2ecf20Sopenharmony_ci				  SMU7_MAX_LEVELS_VDDCI);
34608c2ecf20Sopenharmony_ci	ci_reset_single_dpm_table(rdev,
34618c2ecf20Sopenharmony_ci				  &pi->dpm_table.mvdd_table,
34628c2ecf20Sopenharmony_ci				  SMU7_MAX_LEVELS_MVDD);
34638c2ecf20Sopenharmony_ci
34648c2ecf20Sopenharmony_ci	pi->dpm_table.sclk_table.count = 0;
34658c2ecf20Sopenharmony_ci	for (i = 0; i < allowed_sclk_vddc_table->count; i++) {
34668c2ecf20Sopenharmony_ci		if ((i == 0) ||
34678c2ecf20Sopenharmony_ci		    (pi->dpm_table.sclk_table.dpm_levels[pi->dpm_table.sclk_table.count-1].value !=
34688c2ecf20Sopenharmony_ci		     allowed_sclk_vddc_table->entries[i].clk)) {
34698c2ecf20Sopenharmony_ci			pi->dpm_table.sclk_table.dpm_levels[pi->dpm_table.sclk_table.count].value =
34708c2ecf20Sopenharmony_ci				allowed_sclk_vddc_table->entries[i].clk;
34718c2ecf20Sopenharmony_ci			pi->dpm_table.sclk_table.dpm_levels[pi->dpm_table.sclk_table.count].enabled =
34728c2ecf20Sopenharmony_ci				(i == 0) ? true : false;
34738c2ecf20Sopenharmony_ci			pi->dpm_table.sclk_table.count++;
34748c2ecf20Sopenharmony_ci		}
34758c2ecf20Sopenharmony_ci	}
34768c2ecf20Sopenharmony_ci
34778c2ecf20Sopenharmony_ci	pi->dpm_table.mclk_table.count = 0;
34788c2ecf20Sopenharmony_ci	for (i = 0; i < allowed_mclk_table->count; i++) {
34798c2ecf20Sopenharmony_ci		if ((i == 0) ||
34808c2ecf20Sopenharmony_ci		    (pi->dpm_table.mclk_table.dpm_levels[pi->dpm_table.mclk_table.count-1].value !=
34818c2ecf20Sopenharmony_ci		     allowed_mclk_table->entries[i].clk)) {
34828c2ecf20Sopenharmony_ci			pi->dpm_table.mclk_table.dpm_levels[pi->dpm_table.mclk_table.count].value =
34838c2ecf20Sopenharmony_ci				allowed_mclk_table->entries[i].clk;
34848c2ecf20Sopenharmony_ci			pi->dpm_table.mclk_table.dpm_levels[pi->dpm_table.mclk_table.count].enabled =
34858c2ecf20Sopenharmony_ci				(i == 0) ? true : false;
34868c2ecf20Sopenharmony_ci			pi->dpm_table.mclk_table.count++;
34878c2ecf20Sopenharmony_ci		}
34888c2ecf20Sopenharmony_ci	}
34898c2ecf20Sopenharmony_ci
34908c2ecf20Sopenharmony_ci	for (i = 0; i < allowed_sclk_vddc_table->count; i++) {
34918c2ecf20Sopenharmony_ci		pi->dpm_table.vddc_table.dpm_levels[i].value =
34928c2ecf20Sopenharmony_ci			allowed_sclk_vddc_table->entries[i].v;
34938c2ecf20Sopenharmony_ci		pi->dpm_table.vddc_table.dpm_levels[i].param1 =
34948c2ecf20Sopenharmony_ci			std_voltage_table->entries[i].leakage;
34958c2ecf20Sopenharmony_ci		pi->dpm_table.vddc_table.dpm_levels[i].enabled = true;
34968c2ecf20Sopenharmony_ci	}
34978c2ecf20Sopenharmony_ci	pi->dpm_table.vddc_table.count = allowed_sclk_vddc_table->count;
34988c2ecf20Sopenharmony_ci
34998c2ecf20Sopenharmony_ci	allowed_mclk_table = &rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk;
35008c2ecf20Sopenharmony_ci	if (allowed_mclk_table) {
35018c2ecf20Sopenharmony_ci		for (i = 0; i < allowed_mclk_table->count; i++) {
35028c2ecf20Sopenharmony_ci			pi->dpm_table.vddci_table.dpm_levels[i].value =
35038c2ecf20Sopenharmony_ci				allowed_mclk_table->entries[i].v;
35048c2ecf20Sopenharmony_ci			pi->dpm_table.vddci_table.dpm_levels[i].enabled = true;
35058c2ecf20Sopenharmony_ci		}
35068c2ecf20Sopenharmony_ci		pi->dpm_table.vddci_table.count = allowed_mclk_table->count;
35078c2ecf20Sopenharmony_ci	}
35088c2ecf20Sopenharmony_ci
35098c2ecf20Sopenharmony_ci	allowed_mclk_table = &rdev->pm.dpm.dyn_state.mvdd_dependency_on_mclk;
35108c2ecf20Sopenharmony_ci	if (allowed_mclk_table) {
35118c2ecf20Sopenharmony_ci		for (i = 0; i < allowed_mclk_table->count; i++) {
35128c2ecf20Sopenharmony_ci			pi->dpm_table.mvdd_table.dpm_levels[i].value =
35138c2ecf20Sopenharmony_ci				allowed_mclk_table->entries[i].v;
35148c2ecf20Sopenharmony_ci			pi->dpm_table.mvdd_table.dpm_levels[i].enabled = true;
35158c2ecf20Sopenharmony_ci		}
35168c2ecf20Sopenharmony_ci		pi->dpm_table.mvdd_table.count = allowed_mclk_table->count;
35178c2ecf20Sopenharmony_ci	}
35188c2ecf20Sopenharmony_ci
35198c2ecf20Sopenharmony_ci	ci_setup_default_pcie_tables(rdev);
35208c2ecf20Sopenharmony_ci
35218c2ecf20Sopenharmony_ci	return 0;
35228c2ecf20Sopenharmony_ci}
35238c2ecf20Sopenharmony_ci
35248c2ecf20Sopenharmony_cistatic int ci_find_boot_level(struct ci_single_dpm_table *table,
35258c2ecf20Sopenharmony_ci			      u32 value, u32 *boot_level)
35268c2ecf20Sopenharmony_ci{
35278c2ecf20Sopenharmony_ci	u32 i;
35288c2ecf20Sopenharmony_ci	int ret = -EINVAL;
35298c2ecf20Sopenharmony_ci
35308c2ecf20Sopenharmony_ci	for(i = 0; i < table->count; i++) {
35318c2ecf20Sopenharmony_ci		if (value == table->dpm_levels[i].value) {
35328c2ecf20Sopenharmony_ci			*boot_level = i;
35338c2ecf20Sopenharmony_ci			ret = 0;
35348c2ecf20Sopenharmony_ci		}
35358c2ecf20Sopenharmony_ci	}
35368c2ecf20Sopenharmony_ci
35378c2ecf20Sopenharmony_ci	return ret;
35388c2ecf20Sopenharmony_ci}
35398c2ecf20Sopenharmony_ci
35408c2ecf20Sopenharmony_cistatic int ci_init_smc_table(struct radeon_device *rdev)
35418c2ecf20Sopenharmony_ci{
35428c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
35438c2ecf20Sopenharmony_ci	struct ci_ulv_parm *ulv = &pi->ulv;
35448c2ecf20Sopenharmony_ci	struct radeon_ps *radeon_boot_state = rdev->pm.dpm.boot_ps;
35458c2ecf20Sopenharmony_ci	SMU7_Discrete_DpmTable *table = &pi->smc_state_table;
35468c2ecf20Sopenharmony_ci	int ret;
35478c2ecf20Sopenharmony_ci
35488c2ecf20Sopenharmony_ci	ret = ci_setup_default_dpm_tables(rdev);
35498c2ecf20Sopenharmony_ci	if (ret)
35508c2ecf20Sopenharmony_ci		return ret;
35518c2ecf20Sopenharmony_ci
35528c2ecf20Sopenharmony_ci	if (pi->voltage_control != CISLANDS_VOLTAGE_CONTROL_NONE)
35538c2ecf20Sopenharmony_ci		ci_populate_smc_voltage_tables(rdev, table);
35548c2ecf20Sopenharmony_ci
35558c2ecf20Sopenharmony_ci	ci_init_fps_limits(rdev);
35568c2ecf20Sopenharmony_ci
35578c2ecf20Sopenharmony_ci	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC)
35588c2ecf20Sopenharmony_ci		table->SystemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
35598c2ecf20Sopenharmony_ci
35608c2ecf20Sopenharmony_ci	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC)
35618c2ecf20Sopenharmony_ci		table->SystemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
35628c2ecf20Sopenharmony_ci
35638c2ecf20Sopenharmony_ci	if (pi->mem_gddr5)
35648c2ecf20Sopenharmony_ci		table->SystemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
35658c2ecf20Sopenharmony_ci
35668c2ecf20Sopenharmony_ci	if (ulv->supported) {
35678c2ecf20Sopenharmony_ci		ret = ci_populate_ulv_state(rdev, &pi->smc_state_table.Ulv);
35688c2ecf20Sopenharmony_ci		if (ret)
35698c2ecf20Sopenharmony_ci			return ret;
35708c2ecf20Sopenharmony_ci		WREG32_SMC(CG_ULV_PARAMETER, ulv->cg_ulv_parameter);
35718c2ecf20Sopenharmony_ci	}
35728c2ecf20Sopenharmony_ci
35738c2ecf20Sopenharmony_ci	ret = ci_populate_all_graphic_levels(rdev);
35748c2ecf20Sopenharmony_ci	if (ret)
35758c2ecf20Sopenharmony_ci		return ret;
35768c2ecf20Sopenharmony_ci
35778c2ecf20Sopenharmony_ci	ret = ci_populate_all_memory_levels(rdev);
35788c2ecf20Sopenharmony_ci	if (ret)
35798c2ecf20Sopenharmony_ci		return ret;
35808c2ecf20Sopenharmony_ci
35818c2ecf20Sopenharmony_ci	ci_populate_smc_link_level(rdev, table);
35828c2ecf20Sopenharmony_ci
35838c2ecf20Sopenharmony_ci	ret = ci_populate_smc_acpi_level(rdev, table);
35848c2ecf20Sopenharmony_ci	if (ret)
35858c2ecf20Sopenharmony_ci		return ret;
35868c2ecf20Sopenharmony_ci
35878c2ecf20Sopenharmony_ci	ret = ci_populate_smc_vce_level(rdev, table);
35888c2ecf20Sopenharmony_ci	if (ret)
35898c2ecf20Sopenharmony_ci		return ret;
35908c2ecf20Sopenharmony_ci
35918c2ecf20Sopenharmony_ci	ret = ci_populate_smc_acp_level(rdev, table);
35928c2ecf20Sopenharmony_ci	if (ret)
35938c2ecf20Sopenharmony_ci		return ret;
35948c2ecf20Sopenharmony_ci
35958c2ecf20Sopenharmony_ci	ret = ci_populate_smc_samu_level(rdev, table);
35968c2ecf20Sopenharmony_ci	if (ret)
35978c2ecf20Sopenharmony_ci		return ret;
35988c2ecf20Sopenharmony_ci
35998c2ecf20Sopenharmony_ci	ret = ci_do_program_memory_timing_parameters(rdev);
36008c2ecf20Sopenharmony_ci	if (ret)
36018c2ecf20Sopenharmony_ci		return ret;
36028c2ecf20Sopenharmony_ci
36038c2ecf20Sopenharmony_ci	ret = ci_populate_smc_uvd_level(rdev, table);
36048c2ecf20Sopenharmony_ci	if (ret)
36058c2ecf20Sopenharmony_ci		return ret;
36068c2ecf20Sopenharmony_ci
36078c2ecf20Sopenharmony_ci	table->UvdBootLevel  = 0;
36088c2ecf20Sopenharmony_ci	table->VceBootLevel  = 0;
36098c2ecf20Sopenharmony_ci	table->AcpBootLevel  = 0;
36108c2ecf20Sopenharmony_ci	table->SamuBootLevel  = 0;
36118c2ecf20Sopenharmony_ci	table->GraphicsBootLevel  = 0;
36128c2ecf20Sopenharmony_ci	table->MemoryBootLevel  = 0;
36138c2ecf20Sopenharmony_ci
36148c2ecf20Sopenharmony_ci	ret = ci_find_boot_level(&pi->dpm_table.sclk_table,
36158c2ecf20Sopenharmony_ci				 pi->vbios_boot_state.sclk_bootup_value,
36168c2ecf20Sopenharmony_ci				 (u32 *)&pi->smc_state_table.GraphicsBootLevel);
36178c2ecf20Sopenharmony_ci
36188c2ecf20Sopenharmony_ci	ret = ci_find_boot_level(&pi->dpm_table.mclk_table,
36198c2ecf20Sopenharmony_ci				 pi->vbios_boot_state.mclk_bootup_value,
36208c2ecf20Sopenharmony_ci				 (u32 *)&pi->smc_state_table.MemoryBootLevel);
36218c2ecf20Sopenharmony_ci
36228c2ecf20Sopenharmony_ci	table->BootVddc = pi->vbios_boot_state.vddc_bootup_value;
36238c2ecf20Sopenharmony_ci	table->BootVddci = pi->vbios_boot_state.vddci_bootup_value;
36248c2ecf20Sopenharmony_ci	table->BootMVdd = pi->vbios_boot_state.mvdd_bootup_value;
36258c2ecf20Sopenharmony_ci
36268c2ecf20Sopenharmony_ci	ci_populate_smc_initial_state(rdev, radeon_boot_state);
36278c2ecf20Sopenharmony_ci
36288c2ecf20Sopenharmony_ci	ret = ci_populate_bapm_parameters_in_dpm_table(rdev);
36298c2ecf20Sopenharmony_ci	if (ret)
36308c2ecf20Sopenharmony_ci		return ret;
36318c2ecf20Sopenharmony_ci
36328c2ecf20Sopenharmony_ci	table->UVDInterval = 1;
36338c2ecf20Sopenharmony_ci	table->VCEInterval = 1;
36348c2ecf20Sopenharmony_ci	table->ACPInterval = 1;
36358c2ecf20Sopenharmony_ci	table->SAMUInterval = 1;
36368c2ecf20Sopenharmony_ci	table->GraphicsVoltageChangeEnable = 1;
36378c2ecf20Sopenharmony_ci	table->GraphicsThermThrottleEnable = 1;
36388c2ecf20Sopenharmony_ci	table->GraphicsInterval = 1;
36398c2ecf20Sopenharmony_ci	table->VoltageInterval = 1;
36408c2ecf20Sopenharmony_ci	table->ThermalInterval = 1;
36418c2ecf20Sopenharmony_ci	table->TemperatureLimitHigh = (u16)((pi->thermal_temp_setting.temperature_high *
36428c2ecf20Sopenharmony_ci					     CISLANDS_Q88_FORMAT_CONVERSION_UNIT) / 1000);
36438c2ecf20Sopenharmony_ci	table->TemperatureLimitLow = (u16)((pi->thermal_temp_setting.temperature_low *
36448c2ecf20Sopenharmony_ci					    CISLANDS_Q88_FORMAT_CONVERSION_UNIT) / 1000);
36458c2ecf20Sopenharmony_ci	table->MemoryVoltageChangeEnable = 1;
36468c2ecf20Sopenharmony_ci	table->MemoryInterval = 1;
36478c2ecf20Sopenharmony_ci	table->VoltageResponseTime = 0;
36488c2ecf20Sopenharmony_ci	table->VddcVddciDelta = 4000;
36498c2ecf20Sopenharmony_ci	table->PhaseResponseTime = 0;
36508c2ecf20Sopenharmony_ci	table->MemoryThermThrottleEnable = 1;
36518c2ecf20Sopenharmony_ci	table->PCIeBootLinkLevel = pi->dpm_table.pcie_speed_table.count - 1;
36528c2ecf20Sopenharmony_ci	table->PCIeGenInterval = 1;
36538c2ecf20Sopenharmony_ci	if (pi->voltage_control == CISLANDS_VOLTAGE_CONTROL_BY_SVID2)
36548c2ecf20Sopenharmony_ci		table->SVI2Enable  = 1;
36558c2ecf20Sopenharmony_ci	else
36568c2ecf20Sopenharmony_ci		table->SVI2Enable  = 0;
36578c2ecf20Sopenharmony_ci
36588c2ecf20Sopenharmony_ci	table->ThermGpio = 17;
36598c2ecf20Sopenharmony_ci	table->SclkStepSize = 0x4000;
36608c2ecf20Sopenharmony_ci
36618c2ecf20Sopenharmony_ci	table->SystemFlags = cpu_to_be32(table->SystemFlags);
36628c2ecf20Sopenharmony_ci	table->SmioMaskVddcVid = cpu_to_be32(table->SmioMaskVddcVid);
36638c2ecf20Sopenharmony_ci	table->SmioMaskVddcPhase = cpu_to_be32(table->SmioMaskVddcPhase);
36648c2ecf20Sopenharmony_ci	table->SmioMaskVddciVid = cpu_to_be32(table->SmioMaskVddciVid);
36658c2ecf20Sopenharmony_ci	table->SmioMaskMvddVid = cpu_to_be32(table->SmioMaskMvddVid);
36668c2ecf20Sopenharmony_ci	table->SclkStepSize = cpu_to_be32(table->SclkStepSize);
36678c2ecf20Sopenharmony_ci	table->TemperatureLimitHigh = cpu_to_be16(table->TemperatureLimitHigh);
36688c2ecf20Sopenharmony_ci	table->TemperatureLimitLow = cpu_to_be16(table->TemperatureLimitLow);
36698c2ecf20Sopenharmony_ci	table->VddcVddciDelta = cpu_to_be16(table->VddcVddciDelta);
36708c2ecf20Sopenharmony_ci	table->VoltageResponseTime = cpu_to_be16(table->VoltageResponseTime);
36718c2ecf20Sopenharmony_ci	table->PhaseResponseTime = cpu_to_be16(table->PhaseResponseTime);
36728c2ecf20Sopenharmony_ci	table->BootVddc = cpu_to_be16(table->BootVddc * VOLTAGE_SCALE);
36738c2ecf20Sopenharmony_ci	table->BootVddci = cpu_to_be16(table->BootVddci * VOLTAGE_SCALE);
36748c2ecf20Sopenharmony_ci	table->BootMVdd = cpu_to_be16(table->BootMVdd * VOLTAGE_SCALE);
36758c2ecf20Sopenharmony_ci
36768c2ecf20Sopenharmony_ci	ret = ci_copy_bytes_to_smc(rdev,
36778c2ecf20Sopenharmony_ci				   pi->dpm_table_start +
36788c2ecf20Sopenharmony_ci				   offsetof(SMU7_Discrete_DpmTable, SystemFlags),
36798c2ecf20Sopenharmony_ci				   (u8 *)&table->SystemFlags,
36808c2ecf20Sopenharmony_ci				   sizeof(SMU7_Discrete_DpmTable) - 3 * sizeof(SMU7_PIDController),
36818c2ecf20Sopenharmony_ci				   pi->sram_end);
36828c2ecf20Sopenharmony_ci	if (ret)
36838c2ecf20Sopenharmony_ci		return ret;
36848c2ecf20Sopenharmony_ci
36858c2ecf20Sopenharmony_ci	return 0;
36868c2ecf20Sopenharmony_ci}
36878c2ecf20Sopenharmony_ci
36888c2ecf20Sopenharmony_cistatic void ci_trim_single_dpm_states(struct radeon_device *rdev,
36898c2ecf20Sopenharmony_ci				      struct ci_single_dpm_table *dpm_table,
36908c2ecf20Sopenharmony_ci				      u32 low_limit, u32 high_limit)
36918c2ecf20Sopenharmony_ci{
36928c2ecf20Sopenharmony_ci	u32 i;
36938c2ecf20Sopenharmony_ci
36948c2ecf20Sopenharmony_ci	for (i = 0; i < dpm_table->count; i++) {
36958c2ecf20Sopenharmony_ci		if ((dpm_table->dpm_levels[i].value < low_limit) ||
36968c2ecf20Sopenharmony_ci		    (dpm_table->dpm_levels[i].value > high_limit))
36978c2ecf20Sopenharmony_ci			dpm_table->dpm_levels[i].enabled = false;
36988c2ecf20Sopenharmony_ci		else
36998c2ecf20Sopenharmony_ci			dpm_table->dpm_levels[i].enabled = true;
37008c2ecf20Sopenharmony_ci	}
37018c2ecf20Sopenharmony_ci}
37028c2ecf20Sopenharmony_ci
37038c2ecf20Sopenharmony_cistatic void ci_trim_pcie_dpm_states(struct radeon_device *rdev,
37048c2ecf20Sopenharmony_ci				    u32 speed_low, u32 lanes_low,
37058c2ecf20Sopenharmony_ci				    u32 speed_high, u32 lanes_high)
37068c2ecf20Sopenharmony_ci{
37078c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
37088c2ecf20Sopenharmony_ci	struct ci_single_dpm_table *pcie_table = &pi->dpm_table.pcie_speed_table;
37098c2ecf20Sopenharmony_ci	u32 i, j;
37108c2ecf20Sopenharmony_ci
37118c2ecf20Sopenharmony_ci	for (i = 0; i < pcie_table->count; i++) {
37128c2ecf20Sopenharmony_ci		if ((pcie_table->dpm_levels[i].value < speed_low) ||
37138c2ecf20Sopenharmony_ci		    (pcie_table->dpm_levels[i].param1 < lanes_low) ||
37148c2ecf20Sopenharmony_ci		    (pcie_table->dpm_levels[i].value > speed_high) ||
37158c2ecf20Sopenharmony_ci		    (pcie_table->dpm_levels[i].param1 > lanes_high))
37168c2ecf20Sopenharmony_ci			pcie_table->dpm_levels[i].enabled = false;
37178c2ecf20Sopenharmony_ci		else
37188c2ecf20Sopenharmony_ci			pcie_table->dpm_levels[i].enabled = true;
37198c2ecf20Sopenharmony_ci	}
37208c2ecf20Sopenharmony_ci
37218c2ecf20Sopenharmony_ci	for (i = 0; i < pcie_table->count; i++) {
37228c2ecf20Sopenharmony_ci		if (pcie_table->dpm_levels[i].enabled) {
37238c2ecf20Sopenharmony_ci			for (j = i + 1; j < pcie_table->count; j++) {
37248c2ecf20Sopenharmony_ci				if (pcie_table->dpm_levels[j].enabled) {
37258c2ecf20Sopenharmony_ci					if ((pcie_table->dpm_levels[i].value == pcie_table->dpm_levels[j].value) &&
37268c2ecf20Sopenharmony_ci					    (pcie_table->dpm_levels[i].param1 == pcie_table->dpm_levels[j].param1))
37278c2ecf20Sopenharmony_ci						pcie_table->dpm_levels[j].enabled = false;
37288c2ecf20Sopenharmony_ci				}
37298c2ecf20Sopenharmony_ci			}
37308c2ecf20Sopenharmony_ci		}
37318c2ecf20Sopenharmony_ci	}
37328c2ecf20Sopenharmony_ci}
37338c2ecf20Sopenharmony_ci
37348c2ecf20Sopenharmony_cistatic int ci_trim_dpm_states(struct radeon_device *rdev,
37358c2ecf20Sopenharmony_ci			      struct radeon_ps *radeon_state)
37368c2ecf20Sopenharmony_ci{
37378c2ecf20Sopenharmony_ci	struct ci_ps *state = ci_get_ps(radeon_state);
37388c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
37398c2ecf20Sopenharmony_ci	u32 high_limit_count;
37408c2ecf20Sopenharmony_ci
37418c2ecf20Sopenharmony_ci	if (state->performance_level_count < 1)
37428c2ecf20Sopenharmony_ci		return -EINVAL;
37438c2ecf20Sopenharmony_ci
37448c2ecf20Sopenharmony_ci	if (state->performance_level_count == 1)
37458c2ecf20Sopenharmony_ci		high_limit_count = 0;
37468c2ecf20Sopenharmony_ci	else
37478c2ecf20Sopenharmony_ci		high_limit_count = 1;
37488c2ecf20Sopenharmony_ci
37498c2ecf20Sopenharmony_ci	ci_trim_single_dpm_states(rdev,
37508c2ecf20Sopenharmony_ci				  &pi->dpm_table.sclk_table,
37518c2ecf20Sopenharmony_ci				  state->performance_levels[0].sclk,
37528c2ecf20Sopenharmony_ci				  state->performance_levels[high_limit_count].sclk);
37538c2ecf20Sopenharmony_ci
37548c2ecf20Sopenharmony_ci	ci_trim_single_dpm_states(rdev,
37558c2ecf20Sopenharmony_ci				  &pi->dpm_table.mclk_table,
37568c2ecf20Sopenharmony_ci				  state->performance_levels[0].mclk,
37578c2ecf20Sopenharmony_ci				  state->performance_levels[high_limit_count].mclk);
37588c2ecf20Sopenharmony_ci
37598c2ecf20Sopenharmony_ci	ci_trim_pcie_dpm_states(rdev,
37608c2ecf20Sopenharmony_ci				state->performance_levels[0].pcie_gen,
37618c2ecf20Sopenharmony_ci				state->performance_levels[0].pcie_lane,
37628c2ecf20Sopenharmony_ci				state->performance_levels[high_limit_count].pcie_gen,
37638c2ecf20Sopenharmony_ci				state->performance_levels[high_limit_count].pcie_lane);
37648c2ecf20Sopenharmony_ci
37658c2ecf20Sopenharmony_ci	return 0;
37668c2ecf20Sopenharmony_ci}
37678c2ecf20Sopenharmony_ci
37688c2ecf20Sopenharmony_cistatic int ci_apply_disp_minimum_voltage_request(struct radeon_device *rdev)
37698c2ecf20Sopenharmony_ci{
37708c2ecf20Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *disp_voltage_table =
37718c2ecf20Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk;
37728c2ecf20Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *vddc_table =
37738c2ecf20Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
37748c2ecf20Sopenharmony_ci	u32 requested_voltage = 0;
37758c2ecf20Sopenharmony_ci	u32 i;
37768c2ecf20Sopenharmony_ci
37778c2ecf20Sopenharmony_ci	if (disp_voltage_table == NULL)
37788c2ecf20Sopenharmony_ci		return -EINVAL;
37798c2ecf20Sopenharmony_ci	if (!disp_voltage_table->count)
37808c2ecf20Sopenharmony_ci		return -EINVAL;
37818c2ecf20Sopenharmony_ci
37828c2ecf20Sopenharmony_ci	for (i = 0; i < disp_voltage_table->count; i++) {
37838c2ecf20Sopenharmony_ci		if (rdev->clock.current_dispclk == disp_voltage_table->entries[i].clk)
37848c2ecf20Sopenharmony_ci			requested_voltage = disp_voltage_table->entries[i].v;
37858c2ecf20Sopenharmony_ci	}
37868c2ecf20Sopenharmony_ci
37878c2ecf20Sopenharmony_ci	for (i = 0; i < vddc_table->count; i++) {
37888c2ecf20Sopenharmony_ci		if (requested_voltage <= vddc_table->entries[i].v) {
37898c2ecf20Sopenharmony_ci			requested_voltage = vddc_table->entries[i].v;
37908c2ecf20Sopenharmony_ci			return (ci_send_msg_to_smc_with_parameter(rdev,
37918c2ecf20Sopenharmony_ci								  PPSMC_MSG_VddC_Request,
37928c2ecf20Sopenharmony_ci								  requested_voltage * VOLTAGE_SCALE) == PPSMC_Result_OK) ?
37938c2ecf20Sopenharmony_ci				0 : -EINVAL;
37948c2ecf20Sopenharmony_ci		}
37958c2ecf20Sopenharmony_ci	}
37968c2ecf20Sopenharmony_ci
37978c2ecf20Sopenharmony_ci	return -EINVAL;
37988c2ecf20Sopenharmony_ci}
37998c2ecf20Sopenharmony_ci
38008c2ecf20Sopenharmony_cistatic int ci_upload_dpm_level_enable_mask(struct radeon_device *rdev)
38018c2ecf20Sopenharmony_ci{
38028c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
38038c2ecf20Sopenharmony_ci	PPSMC_Result result;
38048c2ecf20Sopenharmony_ci
38058c2ecf20Sopenharmony_ci	ci_apply_disp_minimum_voltage_request(rdev);
38068c2ecf20Sopenharmony_ci
38078c2ecf20Sopenharmony_ci	if (!pi->sclk_dpm_key_disabled) {
38088c2ecf20Sopenharmony_ci		if (pi->dpm_level_enable_mask.sclk_dpm_enable_mask) {
38098c2ecf20Sopenharmony_ci			result = ci_send_msg_to_smc_with_parameter(rdev,
38108c2ecf20Sopenharmony_ci								   PPSMC_MSG_SCLKDPM_SetEnabledMask,
38118c2ecf20Sopenharmony_ci								   pi->dpm_level_enable_mask.sclk_dpm_enable_mask);
38128c2ecf20Sopenharmony_ci			if (result != PPSMC_Result_OK)
38138c2ecf20Sopenharmony_ci				return -EINVAL;
38148c2ecf20Sopenharmony_ci		}
38158c2ecf20Sopenharmony_ci	}
38168c2ecf20Sopenharmony_ci
38178c2ecf20Sopenharmony_ci	if (!pi->mclk_dpm_key_disabled) {
38188c2ecf20Sopenharmony_ci		if (pi->dpm_level_enable_mask.mclk_dpm_enable_mask) {
38198c2ecf20Sopenharmony_ci			result = ci_send_msg_to_smc_with_parameter(rdev,
38208c2ecf20Sopenharmony_ci								   PPSMC_MSG_MCLKDPM_SetEnabledMask,
38218c2ecf20Sopenharmony_ci								   pi->dpm_level_enable_mask.mclk_dpm_enable_mask);
38228c2ecf20Sopenharmony_ci			if (result != PPSMC_Result_OK)
38238c2ecf20Sopenharmony_ci				return -EINVAL;
38248c2ecf20Sopenharmony_ci		}
38258c2ecf20Sopenharmony_ci	}
38268c2ecf20Sopenharmony_ci#if 0
38278c2ecf20Sopenharmony_ci	if (!pi->pcie_dpm_key_disabled) {
38288c2ecf20Sopenharmony_ci		if (pi->dpm_level_enable_mask.pcie_dpm_enable_mask) {
38298c2ecf20Sopenharmony_ci			result = ci_send_msg_to_smc_with_parameter(rdev,
38308c2ecf20Sopenharmony_ci								   PPSMC_MSG_PCIeDPM_SetEnabledMask,
38318c2ecf20Sopenharmony_ci								   pi->dpm_level_enable_mask.pcie_dpm_enable_mask);
38328c2ecf20Sopenharmony_ci			if (result != PPSMC_Result_OK)
38338c2ecf20Sopenharmony_ci				return -EINVAL;
38348c2ecf20Sopenharmony_ci		}
38358c2ecf20Sopenharmony_ci	}
38368c2ecf20Sopenharmony_ci#endif
38378c2ecf20Sopenharmony_ci	return 0;
38388c2ecf20Sopenharmony_ci}
38398c2ecf20Sopenharmony_ci
38408c2ecf20Sopenharmony_cistatic void ci_find_dpm_states_clocks_in_dpm_table(struct radeon_device *rdev,
38418c2ecf20Sopenharmony_ci						   struct radeon_ps *radeon_state)
38428c2ecf20Sopenharmony_ci{
38438c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
38448c2ecf20Sopenharmony_ci	struct ci_ps *state = ci_get_ps(radeon_state);
38458c2ecf20Sopenharmony_ci	struct ci_single_dpm_table *sclk_table = &pi->dpm_table.sclk_table;
38468c2ecf20Sopenharmony_ci	u32 sclk = state->performance_levels[state->performance_level_count-1].sclk;
38478c2ecf20Sopenharmony_ci	struct ci_single_dpm_table *mclk_table = &pi->dpm_table.mclk_table;
38488c2ecf20Sopenharmony_ci	u32 mclk = state->performance_levels[state->performance_level_count-1].mclk;
38498c2ecf20Sopenharmony_ci	u32 i;
38508c2ecf20Sopenharmony_ci
38518c2ecf20Sopenharmony_ci	pi->need_update_smu7_dpm_table = 0;
38528c2ecf20Sopenharmony_ci
38538c2ecf20Sopenharmony_ci	for (i = 0; i < sclk_table->count; i++) {
38548c2ecf20Sopenharmony_ci		if (sclk == sclk_table->dpm_levels[i].value)
38558c2ecf20Sopenharmony_ci			break;
38568c2ecf20Sopenharmony_ci	}
38578c2ecf20Sopenharmony_ci
38588c2ecf20Sopenharmony_ci	if (i >= sclk_table->count) {
38598c2ecf20Sopenharmony_ci		pi->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK;
38608c2ecf20Sopenharmony_ci	} else {
38618c2ecf20Sopenharmony_ci		/* XXX The current code always reprogrammed the sclk levels,
38628c2ecf20Sopenharmony_ci		 * but we don't currently handle disp sclk requirements
38638c2ecf20Sopenharmony_ci		 * so just skip it.
38648c2ecf20Sopenharmony_ci		 */
38658c2ecf20Sopenharmony_ci		if (CISLAND_MINIMUM_ENGINE_CLOCK != CISLAND_MINIMUM_ENGINE_CLOCK)
38668c2ecf20Sopenharmony_ci			pi->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_SCLK;
38678c2ecf20Sopenharmony_ci	}
38688c2ecf20Sopenharmony_ci
38698c2ecf20Sopenharmony_ci	for (i = 0; i < mclk_table->count; i++) {
38708c2ecf20Sopenharmony_ci		if (mclk == mclk_table->dpm_levels[i].value)
38718c2ecf20Sopenharmony_ci			break;
38728c2ecf20Sopenharmony_ci	}
38738c2ecf20Sopenharmony_ci
38748c2ecf20Sopenharmony_ci	if (i >= mclk_table->count)
38758c2ecf20Sopenharmony_ci		pi->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_MCLK;
38768c2ecf20Sopenharmony_ci
38778c2ecf20Sopenharmony_ci	if (rdev->pm.dpm.current_active_crtc_count !=
38788c2ecf20Sopenharmony_ci	    rdev->pm.dpm.new_active_crtc_count)
38798c2ecf20Sopenharmony_ci		pi->need_update_smu7_dpm_table |= DPMTABLE_UPDATE_MCLK;
38808c2ecf20Sopenharmony_ci}
38818c2ecf20Sopenharmony_ci
38828c2ecf20Sopenharmony_cistatic int ci_populate_and_upload_sclk_mclk_dpm_levels(struct radeon_device *rdev,
38838c2ecf20Sopenharmony_ci						       struct radeon_ps *radeon_state)
38848c2ecf20Sopenharmony_ci{
38858c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
38868c2ecf20Sopenharmony_ci	struct ci_ps *state = ci_get_ps(radeon_state);
38878c2ecf20Sopenharmony_ci	u32 sclk = state->performance_levels[state->performance_level_count-1].sclk;
38888c2ecf20Sopenharmony_ci	u32 mclk = state->performance_levels[state->performance_level_count-1].mclk;
38898c2ecf20Sopenharmony_ci	struct ci_dpm_table *dpm_table = &pi->dpm_table;
38908c2ecf20Sopenharmony_ci	int ret;
38918c2ecf20Sopenharmony_ci
38928c2ecf20Sopenharmony_ci	if (!pi->need_update_smu7_dpm_table)
38938c2ecf20Sopenharmony_ci		return 0;
38948c2ecf20Sopenharmony_ci
38958c2ecf20Sopenharmony_ci	if (pi->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_SCLK)
38968c2ecf20Sopenharmony_ci		dpm_table->sclk_table.dpm_levels[dpm_table->sclk_table.count-1].value = sclk;
38978c2ecf20Sopenharmony_ci
38988c2ecf20Sopenharmony_ci	if (pi->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK)
38998c2ecf20Sopenharmony_ci		dpm_table->mclk_table.dpm_levels[dpm_table->mclk_table.count-1].value = mclk;
39008c2ecf20Sopenharmony_ci
39018c2ecf20Sopenharmony_ci	if (pi->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_UPDATE_SCLK)) {
39028c2ecf20Sopenharmony_ci		ret = ci_populate_all_graphic_levels(rdev);
39038c2ecf20Sopenharmony_ci		if (ret)
39048c2ecf20Sopenharmony_ci			return ret;
39058c2ecf20Sopenharmony_ci	}
39068c2ecf20Sopenharmony_ci
39078c2ecf20Sopenharmony_ci	if (pi->need_update_smu7_dpm_table & (DPMTABLE_OD_UPDATE_MCLK | DPMTABLE_UPDATE_MCLK)) {
39088c2ecf20Sopenharmony_ci		ret = ci_populate_all_memory_levels(rdev);
39098c2ecf20Sopenharmony_ci		if (ret)
39108c2ecf20Sopenharmony_ci			return ret;
39118c2ecf20Sopenharmony_ci	}
39128c2ecf20Sopenharmony_ci
39138c2ecf20Sopenharmony_ci	return 0;
39148c2ecf20Sopenharmony_ci}
39158c2ecf20Sopenharmony_ci
39168c2ecf20Sopenharmony_cistatic int ci_enable_uvd_dpm(struct radeon_device *rdev, bool enable)
39178c2ecf20Sopenharmony_ci{
39188c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
39198c2ecf20Sopenharmony_ci	const struct radeon_clock_and_voltage_limits *max_limits;
39208c2ecf20Sopenharmony_ci	int i;
39218c2ecf20Sopenharmony_ci
39228c2ecf20Sopenharmony_ci	if (rdev->pm.dpm.ac_power)
39238c2ecf20Sopenharmony_ci		max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
39248c2ecf20Sopenharmony_ci	else
39258c2ecf20Sopenharmony_ci		max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
39268c2ecf20Sopenharmony_ci
39278c2ecf20Sopenharmony_ci	if (enable) {
39288c2ecf20Sopenharmony_ci		pi->dpm_level_enable_mask.uvd_dpm_enable_mask = 0;
39298c2ecf20Sopenharmony_ci
39308c2ecf20Sopenharmony_ci		for (i = rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count - 1; i >= 0; i--) {
39318c2ecf20Sopenharmony_ci			if (rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[i].v <= max_limits->vddc) {
39328c2ecf20Sopenharmony_ci				pi->dpm_level_enable_mask.uvd_dpm_enable_mask |= 1 << i;
39338c2ecf20Sopenharmony_ci
39348c2ecf20Sopenharmony_ci				if (!pi->caps_uvd_dpm)
39358c2ecf20Sopenharmony_ci					break;
39368c2ecf20Sopenharmony_ci			}
39378c2ecf20Sopenharmony_ci		}
39388c2ecf20Sopenharmony_ci
39398c2ecf20Sopenharmony_ci		ci_send_msg_to_smc_with_parameter(rdev,
39408c2ecf20Sopenharmony_ci						  PPSMC_MSG_UVDDPM_SetEnabledMask,
39418c2ecf20Sopenharmony_ci						  pi->dpm_level_enable_mask.uvd_dpm_enable_mask);
39428c2ecf20Sopenharmony_ci
39438c2ecf20Sopenharmony_ci		if (pi->last_mclk_dpm_enable_mask & 0x1) {
39448c2ecf20Sopenharmony_ci			pi->uvd_enabled = true;
39458c2ecf20Sopenharmony_ci			pi->dpm_level_enable_mask.mclk_dpm_enable_mask &= 0xFFFFFFFE;
39468c2ecf20Sopenharmony_ci			ci_send_msg_to_smc_with_parameter(rdev,
39478c2ecf20Sopenharmony_ci							  PPSMC_MSG_MCLKDPM_SetEnabledMask,
39488c2ecf20Sopenharmony_ci							  pi->dpm_level_enable_mask.mclk_dpm_enable_mask);
39498c2ecf20Sopenharmony_ci		}
39508c2ecf20Sopenharmony_ci	} else {
39518c2ecf20Sopenharmony_ci		if (pi->last_mclk_dpm_enable_mask & 0x1) {
39528c2ecf20Sopenharmony_ci			pi->uvd_enabled = false;
39538c2ecf20Sopenharmony_ci			pi->dpm_level_enable_mask.mclk_dpm_enable_mask |= 1;
39548c2ecf20Sopenharmony_ci			ci_send_msg_to_smc_with_parameter(rdev,
39558c2ecf20Sopenharmony_ci							  PPSMC_MSG_MCLKDPM_SetEnabledMask,
39568c2ecf20Sopenharmony_ci							  pi->dpm_level_enable_mask.mclk_dpm_enable_mask);
39578c2ecf20Sopenharmony_ci		}
39588c2ecf20Sopenharmony_ci	}
39598c2ecf20Sopenharmony_ci
39608c2ecf20Sopenharmony_ci	return (ci_send_msg_to_smc(rdev, enable ?
39618c2ecf20Sopenharmony_ci				   PPSMC_MSG_UVDDPM_Enable : PPSMC_MSG_UVDDPM_Disable) == PPSMC_Result_OK) ?
39628c2ecf20Sopenharmony_ci		0 : -EINVAL;
39638c2ecf20Sopenharmony_ci}
39648c2ecf20Sopenharmony_ci
39658c2ecf20Sopenharmony_cistatic int ci_enable_vce_dpm(struct radeon_device *rdev, bool enable)
39668c2ecf20Sopenharmony_ci{
39678c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
39688c2ecf20Sopenharmony_ci	const struct radeon_clock_and_voltage_limits *max_limits;
39698c2ecf20Sopenharmony_ci	int i;
39708c2ecf20Sopenharmony_ci
39718c2ecf20Sopenharmony_ci	if (rdev->pm.dpm.ac_power)
39728c2ecf20Sopenharmony_ci		max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
39738c2ecf20Sopenharmony_ci	else
39748c2ecf20Sopenharmony_ci		max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
39758c2ecf20Sopenharmony_ci
39768c2ecf20Sopenharmony_ci	if (enable) {
39778c2ecf20Sopenharmony_ci		pi->dpm_level_enable_mask.vce_dpm_enable_mask = 0;
39788c2ecf20Sopenharmony_ci		for (i = rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.count - 1; i >= 0; i--) {
39798c2ecf20Sopenharmony_ci			if (rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[i].v <= max_limits->vddc) {
39808c2ecf20Sopenharmony_ci				pi->dpm_level_enable_mask.vce_dpm_enable_mask |= 1 << i;
39818c2ecf20Sopenharmony_ci
39828c2ecf20Sopenharmony_ci				if (!pi->caps_vce_dpm)
39838c2ecf20Sopenharmony_ci					break;
39848c2ecf20Sopenharmony_ci			}
39858c2ecf20Sopenharmony_ci		}
39868c2ecf20Sopenharmony_ci
39878c2ecf20Sopenharmony_ci		ci_send_msg_to_smc_with_parameter(rdev,
39888c2ecf20Sopenharmony_ci						  PPSMC_MSG_VCEDPM_SetEnabledMask,
39898c2ecf20Sopenharmony_ci						  pi->dpm_level_enable_mask.vce_dpm_enable_mask);
39908c2ecf20Sopenharmony_ci	}
39918c2ecf20Sopenharmony_ci
39928c2ecf20Sopenharmony_ci	return (ci_send_msg_to_smc(rdev, enable ?
39938c2ecf20Sopenharmony_ci				   PPSMC_MSG_VCEDPM_Enable : PPSMC_MSG_VCEDPM_Disable) == PPSMC_Result_OK) ?
39948c2ecf20Sopenharmony_ci		0 : -EINVAL;
39958c2ecf20Sopenharmony_ci}
39968c2ecf20Sopenharmony_ci
39978c2ecf20Sopenharmony_ci#if 0
39988c2ecf20Sopenharmony_cistatic int ci_enable_samu_dpm(struct radeon_device *rdev, bool enable)
39998c2ecf20Sopenharmony_ci{
40008c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
40018c2ecf20Sopenharmony_ci	const struct radeon_clock_and_voltage_limits *max_limits;
40028c2ecf20Sopenharmony_ci	int i;
40038c2ecf20Sopenharmony_ci
40048c2ecf20Sopenharmony_ci	if (rdev->pm.dpm.ac_power)
40058c2ecf20Sopenharmony_ci		max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
40068c2ecf20Sopenharmony_ci	else
40078c2ecf20Sopenharmony_ci		max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
40088c2ecf20Sopenharmony_ci
40098c2ecf20Sopenharmony_ci	if (enable) {
40108c2ecf20Sopenharmony_ci		pi->dpm_level_enable_mask.samu_dpm_enable_mask = 0;
40118c2ecf20Sopenharmony_ci		for (i = rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.count - 1; i >= 0; i--) {
40128c2ecf20Sopenharmony_ci			if (rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries[i].v <= max_limits->vddc) {
40138c2ecf20Sopenharmony_ci				pi->dpm_level_enable_mask.samu_dpm_enable_mask |= 1 << i;
40148c2ecf20Sopenharmony_ci
40158c2ecf20Sopenharmony_ci				if (!pi->caps_samu_dpm)
40168c2ecf20Sopenharmony_ci					break;
40178c2ecf20Sopenharmony_ci			}
40188c2ecf20Sopenharmony_ci		}
40198c2ecf20Sopenharmony_ci
40208c2ecf20Sopenharmony_ci		ci_send_msg_to_smc_with_parameter(rdev,
40218c2ecf20Sopenharmony_ci						  PPSMC_MSG_SAMUDPM_SetEnabledMask,
40228c2ecf20Sopenharmony_ci						  pi->dpm_level_enable_mask.samu_dpm_enable_mask);
40238c2ecf20Sopenharmony_ci	}
40248c2ecf20Sopenharmony_ci	return (ci_send_msg_to_smc(rdev, enable ?
40258c2ecf20Sopenharmony_ci				   PPSMC_MSG_SAMUDPM_Enable : PPSMC_MSG_SAMUDPM_Disable) == PPSMC_Result_OK) ?
40268c2ecf20Sopenharmony_ci		0 : -EINVAL;
40278c2ecf20Sopenharmony_ci}
40288c2ecf20Sopenharmony_ci
40298c2ecf20Sopenharmony_cistatic int ci_enable_acp_dpm(struct radeon_device *rdev, bool enable)
40308c2ecf20Sopenharmony_ci{
40318c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
40328c2ecf20Sopenharmony_ci	const struct radeon_clock_and_voltage_limits *max_limits;
40338c2ecf20Sopenharmony_ci	int i;
40348c2ecf20Sopenharmony_ci
40358c2ecf20Sopenharmony_ci	if (rdev->pm.dpm.ac_power)
40368c2ecf20Sopenharmony_ci		max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
40378c2ecf20Sopenharmony_ci	else
40388c2ecf20Sopenharmony_ci		max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
40398c2ecf20Sopenharmony_ci
40408c2ecf20Sopenharmony_ci	if (enable) {
40418c2ecf20Sopenharmony_ci		pi->dpm_level_enable_mask.acp_dpm_enable_mask = 0;
40428c2ecf20Sopenharmony_ci		for (i = rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.count - 1; i >= 0; i--) {
40438c2ecf20Sopenharmony_ci			if (rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries[i].v <= max_limits->vddc) {
40448c2ecf20Sopenharmony_ci				pi->dpm_level_enable_mask.acp_dpm_enable_mask |= 1 << i;
40458c2ecf20Sopenharmony_ci
40468c2ecf20Sopenharmony_ci				if (!pi->caps_acp_dpm)
40478c2ecf20Sopenharmony_ci					break;
40488c2ecf20Sopenharmony_ci			}
40498c2ecf20Sopenharmony_ci		}
40508c2ecf20Sopenharmony_ci
40518c2ecf20Sopenharmony_ci		ci_send_msg_to_smc_with_parameter(rdev,
40528c2ecf20Sopenharmony_ci						  PPSMC_MSG_ACPDPM_SetEnabledMask,
40538c2ecf20Sopenharmony_ci						  pi->dpm_level_enable_mask.acp_dpm_enable_mask);
40548c2ecf20Sopenharmony_ci	}
40558c2ecf20Sopenharmony_ci
40568c2ecf20Sopenharmony_ci	return (ci_send_msg_to_smc(rdev, enable ?
40578c2ecf20Sopenharmony_ci				   PPSMC_MSG_ACPDPM_Enable : PPSMC_MSG_ACPDPM_Disable) == PPSMC_Result_OK) ?
40588c2ecf20Sopenharmony_ci		0 : -EINVAL;
40598c2ecf20Sopenharmony_ci}
40608c2ecf20Sopenharmony_ci#endif
40618c2ecf20Sopenharmony_ci
40628c2ecf20Sopenharmony_cistatic int ci_update_uvd_dpm(struct radeon_device *rdev, bool gate)
40638c2ecf20Sopenharmony_ci{
40648c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
40658c2ecf20Sopenharmony_ci	u32 tmp;
40668c2ecf20Sopenharmony_ci
40678c2ecf20Sopenharmony_ci	if (!gate) {
40688c2ecf20Sopenharmony_ci		if (pi->caps_uvd_dpm ||
40698c2ecf20Sopenharmony_ci		    (rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count <= 0))
40708c2ecf20Sopenharmony_ci			pi->smc_state_table.UvdBootLevel = 0;
40718c2ecf20Sopenharmony_ci		else
40728c2ecf20Sopenharmony_ci			pi->smc_state_table.UvdBootLevel =
40738c2ecf20Sopenharmony_ci				rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count - 1;
40748c2ecf20Sopenharmony_ci
40758c2ecf20Sopenharmony_ci		tmp = RREG32_SMC(DPM_TABLE_475);
40768c2ecf20Sopenharmony_ci		tmp &= ~UvdBootLevel_MASK;
40778c2ecf20Sopenharmony_ci		tmp |= UvdBootLevel(pi->smc_state_table.UvdBootLevel);
40788c2ecf20Sopenharmony_ci		WREG32_SMC(DPM_TABLE_475, tmp);
40798c2ecf20Sopenharmony_ci	}
40808c2ecf20Sopenharmony_ci
40818c2ecf20Sopenharmony_ci	return ci_enable_uvd_dpm(rdev, !gate);
40828c2ecf20Sopenharmony_ci}
40838c2ecf20Sopenharmony_ci
40848c2ecf20Sopenharmony_cistatic u8 ci_get_vce_boot_level(struct radeon_device *rdev)
40858c2ecf20Sopenharmony_ci{
40868c2ecf20Sopenharmony_ci	u8 i;
40878c2ecf20Sopenharmony_ci	u32 min_evclk = 30000; /* ??? */
40888c2ecf20Sopenharmony_ci	struct radeon_vce_clock_voltage_dependency_table *table =
40898c2ecf20Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
40908c2ecf20Sopenharmony_ci
40918c2ecf20Sopenharmony_ci	for (i = 0; i < table->count; i++) {
40928c2ecf20Sopenharmony_ci		if (table->entries[i].evclk >= min_evclk)
40938c2ecf20Sopenharmony_ci			return i;
40948c2ecf20Sopenharmony_ci	}
40958c2ecf20Sopenharmony_ci
40968c2ecf20Sopenharmony_ci	return table->count - 1;
40978c2ecf20Sopenharmony_ci}
40988c2ecf20Sopenharmony_ci
40998c2ecf20Sopenharmony_cistatic int ci_update_vce_dpm(struct radeon_device *rdev,
41008c2ecf20Sopenharmony_ci			     struct radeon_ps *radeon_new_state,
41018c2ecf20Sopenharmony_ci			     struct radeon_ps *radeon_current_state)
41028c2ecf20Sopenharmony_ci{
41038c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
41048c2ecf20Sopenharmony_ci	int ret = 0;
41058c2ecf20Sopenharmony_ci	u32 tmp;
41068c2ecf20Sopenharmony_ci
41078c2ecf20Sopenharmony_ci	if (radeon_current_state->evclk != radeon_new_state->evclk) {
41088c2ecf20Sopenharmony_ci		if (radeon_new_state->evclk) {
41098c2ecf20Sopenharmony_ci			/* turn the clocks on when encoding */
41108c2ecf20Sopenharmony_ci			cik_update_cg(rdev, RADEON_CG_BLOCK_VCE, false);
41118c2ecf20Sopenharmony_ci
41128c2ecf20Sopenharmony_ci			pi->smc_state_table.VceBootLevel = ci_get_vce_boot_level(rdev);
41138c2ecf20Sopenharmony_ci			tmp = RREG32_SMC(DPM_TABLE_475);
41148c2ecf20Sopenharmony_ci			tmp &= ~VceBootLevel_MASK;
41158c2ecf20Sopenharmony_ci			tmp |= VceBootLevel(pi->smc_state_table.VceBootLevel);
41168c2ecf20Sopenharmony_ci			WREG32_SMC(DPM_TABLE_475, tmp);
41178c2ecf20Sopenharmony_ci
41188c2ecf20Sopenharmony_ci			ret = ci_enable_vce_dpm(rdev, true);
41198c2ecf20Sopenharmony_ci		} else {
41208c2ecf20Sopenharmony_ci			/* turn the clocks off when not encoding */
41218c2ecf20Sopenharmony_ci			cik_update_cg(rdev, RADEON_CG_BLOCK_VCE, true);
41228c2ecf20Sopenharmony_ci
41238c2ecf20Sopenharmony_ci			ret = ci_enable_vce_dpm(rdev, false);
41248c2ecf20Sopenharmony_ci		}
41258c2ecf20Sopenharmony_ci	}
41268c2ecf20Sopenharmony_ci	return ret;
41278c2ecf20Sopenharmony_ci}
41288c2ecf20Sopenharmony_ci
41298c2ecf20Sopenharmony_ci#if 0
41308c2ecf20Sopenharmony_cistatic int ci_update_samu_dpm(struct radeon_device *rdev, bool gate)
41318c2ecf20Sopenharmony_ci{
41328c2ecf20Sopenharmony_ci	return ci_enable_samu_dpm(rdev, gate);
41338c2ecf20Sopenharmony_ci}
41348c2ecf20Sopenharmony_ci
41358c2ecf20Sopenharmony_cistatic int ci_update_acp_dpm(struct radeon_device *rdev, bool gate)
41368c2ecf20Sopenharmony_ci{
41378c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
41388c2ecf20Sopenharmony_ci	u32 tmp;
41398c2ecf20Sopenharmony_ci
41408c2ecf20Sopenharmony_ci	if (!gate) {
41418c2ecf20Sopenharmony_ci		pi->smc_state_table.AcpBootLevel = 0;
41428c2ecf20Sopenharmony_ci
41438c2ecf20Sopenharmony_ci		tmp = RREG32_SMC(DPM_TABLE_475);
41448c2ecf20Sopenharmony_ci		tmp &= ~AcpBootLevel_MASK;
41458c2ecf20Sopenharmony_ci		tmp |= AcpBootLevel(pi->smc_state_table.AcpBootLevel);
41468c2ecf20Sopenharmony_ci		WREG32_SMC(DPM_TABLE_475, tmp);
41478c2ecf20Sopenharmony_ci	}
41488c2ecf20Sopenharmony_ci
41498c2ecf20Sopenharmony_ci	return ci_enable_acp_dpm(rdev, !gate);
41508c2ecf20Sopenharmony_ci}
41518c2ecf20Sopenharmony_ci#endif
41528c2ecf20Sopenharmony_ci
41538c2ecf20Sopenharmony_cistatic int ci_generate_dpm_level_enable_mask(struct radeon_device *rdev,
41548c2ecf20Sopenharmony_ci					     struct radeon_ps *radeon_state)
41558c2ecf20Sopenharmony_ci{
41568c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
41578c2ecf20Sopenharmony_ci	int ret;
41588c2ecf20Sopenharmony_ci
41598c2ecf20Sopenharmony_ci	ret = ci_trim_dpm_states(rdev, radeon_state);
41608c2ecf20Sopenharmony_ci	if (ret)
41618c2ecf20Sopenharmony_ci		return ret;
41628c2ecf20Sopenharmony_ci
41638c2ecf20Sopenharmony_ci	pi->dpm_level_enable_mask.sclk_dpm_enable_mask =
41648c2ecf20Sopenharmony_ci		ci_get_dpm_level_enable_mask_value(&pi->dpm_table.sclk_table);
41658c2ecf20Sopenharmony_ci	pi->dpm_level_enable_mask.mclk_dpm_enable_mask =
41668c2ecf20Sopenharmony_ci		ci_get_dpm_level_enable_mask_value(&pi->dpm_table.mclk_table);
41678c2ecf20Sopenharmony_ci	pi->last_mclk_dpm_enable_mask =
41688c2ecf20Sopenharmony_ci		pi->dpm_level_enable_mask.mclk_dpm_enable_mask;
41698c2ecf20Sopenharmony_ci	if (pi->uvd_enabled) {
41708c2ecf20Sopenharmony_ci		if (pi->dpm_level_enable_mask.mclk_dpm_enable_mask & 1)
41718c2ecf20Sopenharmony_ci			pi->dpm_level_enable_mask.mclk_dpm_enable_mask &= 0xFFFFFFFE;
41728c2ecf20Sopenharmony_ci	}
41738c2ecf20Sopenharmony_ci	pi->dpm_level_enable_mask.pcie_dpm_enable_mask =
41748c2ecf20Sopenharmony_ci		ci_get_dpm_level_enable_mask_value(&pi->dpm_table.pcie_speed_table);
41758c2ecf20Sopenharmony_ci
41768c2ecf20Sopenharmony_ci	return 0;
41778c2ecf20Sopenharmony_ci}
41788c2ecf20Sopenharmony_ci
41798c2ecf20Sopenharmony_cistatic u32 ci_get_lowest_enabled_level(struct radeon_device *rdev,
41808c2ecf20Sopenharmony_ci				       u32 level_mask)
41818c2ecf20Sopenharmony_ci{
41828c2ecf20Sopenharmony_ci	u32 level = 0;
41838c2ecf20Sopenharmony_ci
41848c2ecf20Sopenharmony_ci	while ((level_mask & (1 << level)) == 0)
41858c2ecf20Sopenharmony_ci		level++;
41868c2ecf20Sopenharmony_ci
41878c2ecf20Sopenharmony_ci	return level;
41888c2ecf20Sopenharmony_ci}
41898c2ecf20Sopenharmony_ci
41908c2ecf20Sopenharmony_ci
41918c2ecf20Sopenharmony_ciint ci_dpm_force_performance_level(struct radeon_device *rdev,
41928c2ecf20Sopenharmony_ci				   enum radeon_dpm_forced_level level)
41938c2ecf20Sopenharmony_ci{
41948c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
41958c2ecf20Sopenharmony_ci	u32 tmp, levels, i;
41968c2ecf20Sopenharmony_ci	int ret;
41978c2ecf20Sopenharmony_ci
41988c2ecf20Sopenharmony_ci	if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
41998c2ecf20Sopenharmony_ci		if ((!pi->pcie_dpm_key_disabled) &&
42008c2ecf20Sopenharmony_ci		    pi->dpm_level_enable_mask.pcie_dpm_enable_mask) {
42018c2ecf20Sopenharmony_ci			levels = 0;
42028c2ecf20Sopenharmony_ci			tmp = pi->dpm_level_enable_mask.pcie_dpm_enable_mask;
42038c2ecf20Sopenharmony_ci			while (tmp >>= 1)
42048c2ecf20Sopenharmony_ci				levels++;
42058c2ecf20Sopenharmony_ci			if (levels) {
42068c2ecf20Sopenharmony_ci				ret = ci_dpm_force_state_pcie(rdev, level);
42078c2ecf20Sopenharmony_ci				if (ret)
42088c2ecf20Sopenharmony_ci					return ret;
42098c2ecf20Sopenharmony_ci				for (i = 0; i < rdev->usec_timeout; i++) {
42108c2ecf20Sopenharmony_ci					tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX_1) &
42118c2ecf20Sopenharmony_ci					       CURR_PCIE_INDEX_MASK) >> CURR_PCIE_INDEX_SHIFT;
42128c2ecf20Sopenharmony_ci					if (tmp == levels)
42138c2ecf20Sopenharmony_ci						break;
42148c2ecf20Sopenharmony_ci					udelay(1);
42158c2ecf20Sopenharmony_ci				}
42168c2ecf20Sopenharmony_ci			}
42178c2ecf20Sopenharmony_ci		}
42188c2ecf20Sopenharmony_ci		if ((!pi->sclk_dpm_key_disabled) &&
42198c2ecf20Sopenharmony_ci		    pi->dpm_level_enable_mask.sclk_dpm_enable_mask) {
42208c2ecf20Sopenharmony_ci			levels = 0;
42218c2ecf20Sopenharmony_ci			tmp = pi->dpm_level_enable_mask.sclk_dpm_enable_mask;
42228c2ecf20Sopenharmony_ci			while (tmp >>= 1)
42238c2ecf20Sopenharmony_ci				levels++;
42248c2ecf20Sopenharmony_ci			if (levels) {
42258c2ecf20Sopenharmony_ci				ret = ci_dpm_force_state_sclk(rdev, levels);
42268c2ecf20Sopenharmony_ci				if (ret)
42278c2ecf20Sopenharmony_ci					return ret;
42288c2ecf20Sopenharmony_ci				for (i = 0; i < rdev->usec_timeout; i++) {
42298c2ecf20Sopenharmony_ci					tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) &
42308c2ecf20Sopenharmony_ci					       CURR_SCLK_INDEX_MASK) >> CURR_SCLK_INDEX_SHIFT;
42318c2ecf20Sopenharmony_ci					if (tmp == levels)
42328c2ecf20Sopenharmony_ci						break;
42338c2ecf20Sopenharmony_ci					udelay(1);
42348c2ecf20Sopenharmony_ci				}
42358c2ecf20Sopenharmony_ci			}
42368c2ecf20Sopenharmony_ci		}
42378c2ecf20Sopenharmony_ci		if ((!pi->mclk_dpm_key_disabled) &&
42388c2ecf20Sopenharmony_ci		    pi->dpm_level_enable_mask.mclk_dpm_enable_mask) {
42398c2ecf20Sopenharmony_ci			levels = 0;
42408c2ecf20Sopenharmony_ci			tmp = pi->dpm_level_enable_mask.mclk_dpm_enable_mask;
42418c2ecf20Sopenharmony_ci			while (tmp >>= 1)
42428c2ecf20Sopenharmony_ci				levels++;
42438c2ecf20Sopenharmony_ci			if (levels) {
42448c2ecf20Sopenharmony_ci				ret = ci_dpm_force_state_mclk(rdev, levels);
42458c2ecf20Sopenharmony_ci				if (ret)
42468c2ecf20Sopenharmony_ci					return ret;
42478c2ecf20Sopenharmony_ci				for (i = 0; i < rdev->usec_timeout; i++) {
42488c2ecf20Sopenharmony_ci					tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) &
42498c2ecf20Sopenharmony_ci					       CURR_MCLK_INDEX_MASK) >> CURR_MCLK_INDEX_SHIFT;
42508c2ecf20Sopenharmony_ci					if (tmp == levels)
42518c2ecf20Sopenharmony_ci						break;
42528c2ecf20Sopenharmony_ci					udelay(1);
42538c2ecf20Sopenharmony_ci				}
42548c2ecf20Sopenharmony_ci			}
42558c2ecf20Sopenharmony_ci		}
42568c2ecf20Sopenharmony_ci	} else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
42578c2ecf20Sopenharmony_ci		if ((!pi->sclk_dpm_key_disabled) &&
42588c2ecf20Sopenharmony_ci		    pi->dpm_level_enable_mask.sclk_dpm_enable_mask) {
42598c2ecf20Sopenharmony_ci			levels = ci_get_lowest_enabled_level(rdev,
42608c2ecf20Sopenharmony_ci							     pi->dpm_level_enable_mask.sclk_dpm_enable_mask);
42618c2ecf20Sopenharmony_ci			ret = ci_dpm_force_state_sclk(rdev, levels);
42628c2ecf20Sopenharmony_ci			if (ret)
42638c2ecf20Sopenharmony_ci				return ret;
42648c2ecf20Sopenharmony_ci			for (i = 0; i < rdev->usec_timeout; i++) {
42658c2ecf20Sopenharmony_ci				tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) &
42668c2ecf20Sopenharmony_ci				       CURR_SCLK_INDEX_MASK) >> CURR_SCLK_INDEX_SHIFT;
42678c2ecf20Sopenharmony_ci				if (tmp == levels)
42688c2ecf20Sopenharmony_ci					break;
42698c2ecf20Sopenharmony_ci				udelay(1);
42708c2ecf20Sopenharmony_ci			}
42718c2ecf20Sopenharmony_ci		}
42728c2ecf20Sopenharmony_ci		if ((!pi->mclk_dpm_key_disabled) &&
42738c2ecf20Sopenharmony_ci		    pi->dpm_level_enable_mask.mclk_dpm_enable_mask) {
42748c2ecf20Sopenharmony_ci			levels = ci_get_lowest_enabled_level(rdev,
42758c2ecf20Sopenharmony_ci							     pi->dpm_level_enable_mask.mclk_dpm_enable_mask);
42768c2ecf20Sopenharmony_ci			ret = ci_dpm_force_state_mclk(rdev, levels);
42778c2ecf20Sopenharmony_ci			if (ret)
42788c2ecf20Sopenharmony_ci				return ret;
42798c2ecf20Sopenharmony_ci			for (i = 0; i < rdev->usec_timeout; i++) {
42808c2ecf20Sopenharmony_ci				tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) &
42818c2ecf20Sopenharmony_ci				       CURR_MCLK_INDEX_MASK) >> CURR_MCLK_INDEX_SHIFT;
42828c2ecf20Sopenharmony_ci				if (tmp == levels)
42838c2ecf20Sopenharmony_ci					break;
42848c2ecf20Sopenharmony_ci				udelay(1);
42858c2ecf20Sopenharmony_ci			}
42868c2ecf20Sopenharmony_ci		}
42878c2ecf20Sopenharmony_ci		if ((!pi->pcie_dpm_key_disabled) &&
42888c2ecf20Sopenharmony_ci		    pi->dpm_level_enable_mask.pcie_dpm_enable_mask) {
42898c2ecf20Sopenharmony_ci			levels = ci_get_lowest_enabled_level(rdev,
42908c2ecf20Sopenharmony_ci							     pi->dpm_level_enable_mask.pcie_dpm_enable_mask);
42918c2ecf20Sopenharmony_ci			ret = ci_dpm_force_state_pcie(rdev, levels);
42928c2ecf20Sopenharmony_ci			if (ret)
42938c2ecf20Sopenharmony_ci				return ret;
42948c2ecf20Sopenharmony_ci			for (i = 0; i < rdev->usec_timeout; i++) {
42958c2ecf20Sopenharmony_ci				tmp = (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX_1) &
42968c2ecf20Sopenharmony_ci				       CURR_PCIE_INDEX_MASK) >> CURR_PCIE_INDEX_SHIFT;
42978c2ecf20Sopenharmony_ci				if (tmp == levels)
42988c2ecf20Sopenharmony_ci					break;
42998c2ecf20Sopenharmony_ci				udelay(1);
43008c2ecf20Sopenharmony_ci			}
43018c2ecf20Sopenharmony_ci		}
43028c2ecf20Sopenharmony_ci	} else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) {
43038c2ecf20Sopenharmony_ci		if (!pi->pcie_dpm_key_disabled) {
43048c2ecf20Sopenharmony_ci			PPSMC_Result smc_result;
43058c2ecf20Sopenharmony_ci
43068c2ecf20Sopenharmony_ci			smc_result = ci_send_msg_to_smc(rdev,
43078c2ecf20Sopenharmony_ci							PPSMC_MSG_PCIeDPM_UnForceLevel);
43088c2ecf20Sopenharmony_ci			if (smc_result != PPSMC_Result_OK)
43098c2ecf20Sopenharmony_ci				return -EINVAL;
43108c2ecf20Sopenharmony_ci		}
43118c2ecf20Sopenharmony_ci		ret = ci_upload_dpm_level_enable_mask(rdev);
43128c2ecf20Sopenharmony_ci		if (ret)
43138c2ecf20Sopenharmony_ci			return ret;
43148c2ecf20Sopenharmony_ci	}
43158c2ecf20Sopenharmony_ci
43168c2ecf20Sopenharmony_ci	rdev->pm.dpm.forced_level = level;
43178c2ecf20Sopenharmony_ci
43188c2ecf20Sopenharmony_ci	return 0;
43198c2ecf20Sopenharmony_ci}
43208c2ecf20Sopenharmony_ci
43218c2ecf20Sopenharmony_cistatic int ci_set_mc_special_registers(struct radeon_device *rdev,
43228c2ecf20Sopenharmony_ci				       struct ci_mc_reg_table *table)
43238c2ecf20Sopenharmony_ci{
43248c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
43258c2ecf20Sopenharmony_ci	u8 i, j, k;
43268c2ecf20Sopenharmony_ci	u32 temp_reg;
43278c2ecf20Sopenharmony_ci
43288c2ecf20Sopenharmony_ci	for (i = 0, j = table->last; i < table->last; i++) {
43298c2ecf20Sopenharmony_ci		if (j >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
43308c2ecf20Sopenharmony_ci			return -EINVAL;
43318c2ecf20Sopenharmony_ci		switch(table->mc_reg_address[i].s1 << 2) {
43328c2ecf20Sopenharmony_ci		case MC_SEQ_MISC1:
43338c2ecf20Sopenharmony_ci			temp_reg = RREG32(MC_PMG_CMD_EMRS);
43348c2ecf20Sopenharmony_ci			table->mc_reg_address[j].s1 = MC_PMG_CMD_EMRS >> 2;
43358c2ecf20Sopenharmony_ci			table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_EMRS_LP >> 2;
43368c2ecf20Sopenharmony_ci			for (k = 0; k < table->num_entries; k++) {
43378c2ecf20Sopenharmony_ci				table->mc_reg_table_entry[k].mc_data[j] =
43388c2ecf20Sopenharmony_ci					((temp_reg & 0xffff0000)) | ((table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16);
43398c2ecf20Sopenharmony_ci			}
43408c2ecf20Sopenharmony_ci			j++;
43418c2ecf20Sopenharmony_ci			if (j >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
43428c2ecf20Sopenharmony_ci				return -EINVAL;
43438c2ecf20Sopenharmony_ci
43448c2ecf20Sopenharmony_ci			temp_reg = RREG32(MC_PMG_CMD_MRS);
43458c2ecf20Sopenharmony_ci			table->mc_reg_address[j].s1 = MC_PMG_CMD_MRS >> 2;
43468c2ecf20Sopenharmony_ci			table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_MRS_LP >> 2;
43478c2ecf20Sopenharmony_ci			for (k = 0; k < table->num_entries; k++) {
43488c2ecf20Sopenharmony_ci				table->mc_reg_table_entry[k].mc_data[j] =
43498c2ecf20Sopenharmony_ci					(temp_reg & 0xffff0000) | (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
43508c2ecf20Sopenharmony_ci				if (!pi->mem_gddr5)
43518c2ecf20Sopenharmony_ci					table->mc_reg_table_entry[k].mc_data[j] |= 0x100;
43528c2ecf20Sopenharmony_ci			}
43538c2ecf20Sopenharmony_ci			j++;
43548c2ecf20Sopenharmony_ci			if (j >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
43558c2ecf20Sopenharmony_ci				return -EINVAL;
43568c2ecf20Sopenharmony_ci
43578c2ecf20Sopenharmony_ci			if (!pi->mem_gddr5) {
43588c2ecf20Sopenharmony_ci				table->mc_reg_address[j].s1 = MC_PMG_AUTO_CMD >> 2;
43598c2ecf20Sopenharmony_ci				table->mc_reg_address[j].s0 = MC_PMG_AUTO_CMD >> 2;
43608c2ecf20Sopenharmony_ci				for (k = 0; k < table->num_entries; k++) {
43618c2ecf20Sopenharmony_ci					table->mc_reg_table_entry[k].mc_data[j] =
43628c2ecf20Sopenharmony_ci						(table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16;
43638c2ecf20Sopenharmony_ci				}
43648c2ecf20Sopenharmony_ci				j++;
43658c2ecf20Sopenharmony_ci				if (j > SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
43668c2ecf20Sopenharmony_ci					return -EINVAL;
43678c2ecf20Sopenharmony_ci			}
43688c2ecf20Sopenharmony_ci			break;
43698c2ecf20Sopenharmony_ci		case MC_SEQ_RESERVE_M:
43708c2ecf20Sopenharmony_ci			temp_reg = RREG32(MC_PMG_CMD_MRS1);
43718c2ecf20Sopenharmony_ci			table->mc_reg_address[j].s1 = MC_PMG_CMD_MRS1 >> 2;
43728c2ecf20Sopenharmony_ci			table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_MRS1_LP >> 2;
43738c2ecf20Sopenharmony_ci			for (k = 0; k < table->num_entries; k++) {
43748c2ecf20Sopenharmony_ci				table->mc_reg_table_entry[k].mc_data[j] =
43758c2ecf20Sopenharmony_ci					(temp_reg & 0xffff0000) | (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
43768c2ecf20Sopenharmony_ci			}
43778c2ecf20Sopenharmony_ci			j++;
43788c2ecf20Sopenharmony_ci			if (j > SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
43798c2ecf20Sopenharmony_ci				return -EINVAL;
43808c2ecf20Sopenharmony_ci			break;
43818c2ecf20Sopenharmony_ci		default:
43828c2ecf20Sopenharmony_ci			break;
43838c2ecf20Sopenharmony_ci		}
43848c2ecf20Sopenharmony_ci
43858c2ecf20Sopenharmony_ci	}
43868c2ecf20Sopenharmony_ci
43878c2ecf20Sopenharmony_ci	table->last = j;
43888c2ecf20Sopenharmony_ci
43898c2ecf20Sopenharmony_ci	return 0;
43908c2ecf20Sopenharmony_ci}
43918c2ecf20Sopenharmony_ci
43928c2ecf20Sopenharmony_cistatic bool ci_check_s0_mc_reg_index(u16 in_reg, u16 *out_reg)
43938c2ecf20Sopenharmony_ci{
43948c2ecf20Sopenharmony_ci	bool result = true;
43958c2ecf20Sopenharmony_ci
43968c2ecf20Sopenharmony_ci	switch(in_reg) {
43978c2ecf20Sopenharmony_ci	case MC_SEQ_RAS_TIMING >> 2:
43988c2ecf20Sopenharmony_ci		*out_reg = MC_SEQ_RAS_TIMING_LP >> 2;
43998c2ecf20Sopenharmony_ci		break;
44008c2ecf20Sopenharmony_ci	case MC_SEQ_DLL_STBY >> 2:
44018c2ecf20Sopenharmony_ci		*out_reg = MC_SEQ_DLL_STBY_LP >> 2;
44028c2ecf20Sopenharmony_ci		break;
44038c2ecf20Sopenharmony_ci	case MC_SEQ_G5PDX_CMD0 >> 2:
44048c2ecf20Sopenharmony_ci		*out_reg = MC_SEQ_G5PDX_CMD0_LP >> 2;
44058c2ecf20Sopenharmony_ci		break;
44068c2ecf20Sopenharmony_ci	case MC_SEQ_G5PDX_CMD1 >> 2:
44078c2ecf20Sopenharmony_ci		*out_reg = MC_SEQ_G5PDX_CMD1_LP >> 2;
44088c2ecf20Sopenharmony_ci		break;
44098c2ecf20Sopenharmony_ci	case MC_SEQ_G5PDX_CTRL >> 2:
44108c2ecf20Sopenharmony_ci		*out_reg = MC_SEQ_G5PDX_CTRL_LP >> 2;
44118c2ecf20Sopenharmony_ci		break;
44128c2ecf20Sopenharmony_ci	case MC_SEQ_CAS_TIMING >> 2:
44138c2ecf20Sopenharmony_ci		*out_reg = MC_SEQ_CAS_TIMING_LP >> 2;
44148c2ecf20Sopenharmony_ci		break;
44158c2ecf20Sopenharmony_ci	case MC_SEQ_MISC_TIMING >> 2:
44168c2ecf20Sopenharmony_ci		*out_reg = MC_SEQ_MISC_TIMING_LP >> 2;
44178c2ecf20Sopenharmony_ci		break;
44188c2ecf20Sopenharmony_ci	case MC_SEQ_MISC_TIMING2 >> 2:
44198c2ecf20Sopenharmony_ci		*out_reg = MC_SEQ_MISC_TIMING2_LP >> 2;
44208c2ecf20Sopenharmony_ci		break;
44218c2ecf20Sopenharmony_ci	case MC_SEQ_PMG_DVS_CMD >> 2:
44228c2ecf20Sopenharmony_ci		*out_reg = MC_SEQ_PMG_DVS_CMD_LP >> 2;
44238c2ecf20Sopenharmony_ci		break;
44248c2ecf20Sopenharmony_ci	case MC_SEQ_PMG_DVS_CTL >> 2:
44258c2ecf20Sopenharmony_ci		*out_reg = MC_SEQ_PMG_DVS_CTL_LP >> 2;
44268c2ecf20Sopenharmony_ci		break;
44278c2ecf20Sopenharmony_ci	case MC_SEQ_RD_CTL_D0 >> 2:
44288c2ecf20Sopenharmony_ci		*out_reg = MC_SEQ_RD_CTL_D0_LP >> 2;
44298c2ecf20Sopenharmony_ci		break;
44308c2ecf20Sopenharmony_ci	case MC_SEQ_RD_CTL_D1 >> 2:
44318c2ecf20Sopenharmony_ci		*out_reg = MC_SEQ_RD_CTL_D1_LP >> 2;
44328c2ecf20Sopenharmony_ci		break;
44338c2ecf20Sopenharmony_ci	case MC_SEQ_WR_CTL_D0 >> 2:
44348c2ecf20Sopenharmony_ci		*out_reg = MC_SEQ_WR_CTL_D0_LP >> 2;
44358c2ecf20Sopenharmony_ci		break;
44368c2ecf20Sopenharmony_ci	case MC_SEQ_WR_CTL_D1 >> 2:
44378c2ecf20Sopenharmony_ci		*out_reg = MC_SEQ_WR_CTL_D1_LP >> 2;
44388c2ecf20Sopenharmony_ci		break;
44398c2ecf20Sopenharmony_ci	case MC_PMG_CMD_EMRS >> 2:
44408c2ecf20Sopenharmony_ci		*out_reg = MC_SEQ_PMG_CMD_EMRS_LP >> 2;
44418c2ecf20Sopenharmony_ci		break;
44428c2ecf20Sopenharmony_ci	case MC_PMG_CMD_MRS >> 2:
44438c2ecf20Sopenharmony_ci		*out_reg = MC_SEQ_PMG_CMD_MRS_LP >> 2;
44448c2ecf20Sopenharmony_ci		break;
44458c2ecf20Sopenharmony_ci	case MC_PMG_CMD_MRS1 >> 2:
44468c2ecf20Sopenharmony_ci		*out_reg = MC_SEQ_PMG_CMD_MRS1_LP >> 2;
44478c2ecf20Sopenharmony_ci		break;
44488c2ecf20Sopenharmony_ci	case MC_SEQ_PMG_TIMING >> 2:
44498c2ecf20Sopenharmony_ci		*out_reg = MC_SEQ_PMG_TIMING_LP >> 2;
44508c2ecf20Sopenharmony_ci		break;
44518c2ecf20Sopenharmony_ci	case MC_PMG_CMD_MRS2 >> 2:
44528c2ecf20Sopenharmony_ci		*out_reg = MC_SEQ_PMG_CMD_MRS2_LP >> 2;
44538c2ecf20Sopenharmony_ci		break;
44548c2ecf20Sopenharmony_ci	case MC_SEQ_WR_CTL_2 >> 2:
44558c2ecf20Sopenharmony_ci		*out_reg = MC_SEQ_WR_CTL_2_LP >> 2;
44568c2ecf20Sopenharmony_ci		break;
44578c2ecf20Sopenharmony_ci	default:
44588c2ecf20Sopenharmony_ci		result = false;
44598c2ecf20Sopenharmony_ci		break;
44608c2ecf20Sopenharmony_ci	}
44618c2ecf20Sopenharmony_ci
44628c2ecf20Sopenharmony_ci	return result;
44638c2ecf20Sopenharmony_ci}
44648c2ecf20Sopenharmony_ci
44658c2ecf20Sopenharmony_cistatic void ci_set_valid_flag(struct ci_mc_reg_table *table)
44668c2ecf20Sopenharmony_ci{
44678c2ecf20Sopenharmony_ci	u8 i, j;
44688c2ecf20Sopenharmony_ci
44698c2ecf20Sopenharmony_ci	for (i = 0; i < table->last; i++) {
44708c2ecf20Sopenharmony_ci		for (j = 1; j < table->num_entries; j++) {
44718c2ecf20Sopenharmony_ci			if (table->mc_reg_table_entry[j-1].mc_data[i] !=
44728c2ecf20Sopenharmony_ci			    table->mc_reg_table_entry[j].mc_data[i]) {
44738c2ecf20Sopenharmony_ci				table->valid_flag |= 1 << i;
44748c2ecf20Sopenharmony_ci				break;
44758c2ecf20Sopenharmony_ci			}
44768c2ecf20Sopenharmony_ci		}
44778c2ecf20Sopenharmony_ci	}
44788c2ecf20Sopenharmony_ci}
44798c2ecf20Sopenharmony_ci
44808c2ecf20Sopenharmony_cistatic void ci_set_s0_mc_reg_index(struct ci_mc_reg_table *table)
44818c2ecf20Sopenharmony_ci{
44828c2ecf20Sopenharmony_ci	u32 i;
44838c2ecf20Sopenharmony_ci	u16 address;
44848c2ecf20Sopenharmony_ci
44858c2ecf20Sopenharmony_ci	for (i = 0; i < table->last; i++) {
44868c2ecf20Sopenharmony_ci		table->mc_reg_address[i].s0 =
44878c2ecf20Sopenharmony_ci			ci_check_s0_mc_reg_index(table->mc_reg_address[i].s1, &address) ?
44888c2ecf20Sopenharmony_ci			address : table->mc_reg_address[i].s1;
44898c2ecf20Sopenharmony_ci	}
44908c2ecf20Sopenharmony_ci}
44918c2ecf20Sopenharmony_ci
44928c2ecf20Sopenharmony_cistatic int ci_copy_vbios_mc_reg_table(const struct atom_mc_reg_table *table,
44938c2ecf20Sopenharmony_ci				      struct ci_mc_reg_table *ci_table)
44948c2ecf20Sopenharmony_ci{
44958c2ecf20Sopenharmony_ci	u8 i, j;
44968c2ecf20Sopenharmony_ci
44978c2ecf20Sopenharmony_ci	if (table->last > SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
44988c2ecf20Sopenharmony_ci		return -EINVAL;
44998c2ecf20Sopenharmony_ci	if (table->num_entries > MAX_AC_TIMING_ENTRIES)
45008c2ecf20Sopenharmony_ci		return -EINVAL;
45018c2ecf20Sopenharmony_ci
45028c2ecf20Sopenharmony_ci	for (i = 0; i < table->last; i++)
45038c2ecf20Sopenharmony_ci		ci_table->mc_reg_address[i].s1 = table->mc_reg_address[i].s1;
45048c2ecf20Sopenharmony_ci
45058c2ecf20Sopenharmony_ci	ci_table->last = table->last;
45068c2ecf20Sopenharmony_ci
45078c2ecf20Sopenharmony_ci	for (i = 0; i < table->num_entries; i++) {
45088c2ecf20Sopenharmony_ci		ci_table->mc_reg_table_entry[i].mclk_max =
45098c2ecf20Sopenharmony_ci			table->mc_reg_table_entry[i].mclk_max;
45108c2ecf20Sopenharmony_ci		for (j = 0; j < table->last; j++)
45118c2ecf20Sopenharmony_ci			ci_table->mc_reg_table_entry[i].mc_data[j] =
45128c2ecf20Sopenharmony_ci				table->mc_reg_table_entry[i].mc_data[j];
45138c2ecf20Sopenharmony_ci	}
45148c2ecf20Sopenharmony_ci	ci_table->num_entries = table->num_entries;
45158c2ecf20Sopenharmony_ci
45168c2ecf20Sopenharmony_ci	return 0;
45178c2ecf20Sopenharmony_ci}
45188c2ecf20Sopenharmony_ci
45198c2ecf20Sopenharmony_cistatic int ci_register_patching_mc_seq(struct radeon_device *rdev,
45208c2ecf20Sopenharmony_ci				       struct ci_mc_reg_table *table)
45218c2ecf20Sopenharmony_ci{
45228c2ecf20Sopenharmony_ci	u8 i, k;
45238c2ecf20Sopenharmony_ci	u32 tmp;
45248c2ecf20Sopenharmony_ci	bool patch;
45258c2ecf20Sopenharmony_ci
45268c2ecf20Sopenharmony_ci	tmp = RREG32(MC_SEQ_MISC0);
45278c2ecf20Sopenharmony_ci	patch = ((tmp & 0x0000f00) == 0x300) ? true : false;
45288c2ecf20Sopenharmony_ci
45298c2ecf20Sopenharmony_ci	if (patch &&
45308c2ecf20Sopenharmony_ci	    ((rdev->pdev->device == 0x67B0) ||
45318c2ecf20Sopenharmony_ci	     (rdev->pdev->device == 0x67B1))) {
45328c2ecf20Sopenharmony_ci		for (i = 0; i < table->last; i++) {
45338c2ecf20Sopenharmony_ci			if (table->last >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
45348c2ecf20Sopenharmony_ci				return -EINVAL;
45358c2ecf20Sopenharmony_ci			switch(table->mc_reg_address[i].s1 >> 2) {
45368c2ecf20Sopenharmony_ci			case MC_SEQ_MISC1:
45378c2ecf20Sopenharmony_ci				for (k = 0; k < table->num_entries; k++) {
45388c2ecf20Sopenharmony_ci					if ((table->mc_reg_table_entry[k].mclk_max == 125000) ||
45398c2ecf20Sopenharmony_ci					    (table->mc_reg_table_entry[k].mclk_max == 137500))
45408c2ecf20Sopenharmony_ci						table->mc_reg_table_entry[k].mc_data[i] =
45418c2ecf20Sopenharmony_ci							(table->mc_reg_table_entry[k].mc_data[i] & 0xFFFFFFF8) |
45428c2ecf20Sopenharmony_ci							0x00000007;
45438c2ecf20Sopenharmony_ci				}
45448c2ecf20Sopenharmony_ci				break;
45458c2ecf20Sopenharmony_ci			case MC_SEQ_WR_CTL_D0:
45468c2ecf20Sopenharmony_ci				for (k = 0; k < table->num_entries; k++) {
45478c2ecf20Sopenharmony_ci					if ((table->mc_reg_table_entry[k].mclk_max == 125000) ||
45488c2ecf20Sopenharmony_ci					    (table->mc_reg_table_entry[k].mclk_max == 137500))
45498c2ecf20Sopenharmony_ci						table->mc_reg_table_entry[k].mc_data[i] =
45508c2ecf20Sopenharmony_ci							(table->mc_reg_table_entry[k].mc_data[i] & 0xFFFF0F00) |
45518c2ecf20Sopenharmony_ci							0x0000D0DD;
45528c2ecf20Sopenharmony_ci				}
45538c2ecf20Sopenharmony_ci				break;
45548c2ecf20Sopenharmony_ci			case MC_SEQ_WR_CTL_D1:
45558c2ecf20Sopenharmony_ci				for (k = 0; k < table->num_entries; k++) {
45568c2ecf20Sopenharmony_ci					if ((table->mc_reg_table_entry[k].mclk_max == 125000) ||
45578c2ecf20Sopenharmony_ci					    (table->mc_reg_table_entry[k].mclk_max == 137500))
45588c2ecf20Sopenharmony_ci						table->mc_reg_table_entry[k].mc_data[i] =
45598c2ecf20Sopenharmony_ci							(table->mc_reg_table_entry[k].mc_data[i] & 0xFFFF0F00) |
45608c2ecf20Sopenharmony_ci							0x0000D0DD;
45618c2ecf20Sopenharmony_ci				}
45628c2ecf20Sopenharmony_ci				break;
45638c2ecf20Sopenharmony_ci			case MC_SEQ_WR_CTL_2:
45648c2ecf20Sopenharmony_ci				for (k = 0; k < table->num_entries; k++) {
45658c2ecf20Sopenharmony_ci					if ((table->mc_reg_table_entry[k].mclk_max == 125000) ||
45668c2ecf20Sopenharmony_ci					    (table->mc_reg_table_entry[k].mclk_max == 137500))
45678c2ecf20Sopenharmony_ci						table->mc_reg_table_entry[k].mc_data[i] = 0;
45688c2ecf20Sopenharmony_ci				}
45698c2ecf20Sopenharmony_ci				break;
45708c2ecf20Sopenharmony_ci			case MC_SEQ_CAS_TIMING:
45718c2ecf20Sopenharmony_ci				for (k = 0; k < table->num_entries; k++) {
45728c2ecf20Sopenharmony_ci					if (table->mc_reg_table_entry[k].mclk_max == 125000)
45738c2ecf20Sopenharmony_ci						table->mc_reg_table_entry[k].mc_data[i] =
45748c2ecf20Sopenharmony_ci							(table->mc_reg_table_entry[k].mc_data[i] & 0xFFE0FE0F) |
45758c2ecf20Sopenharmony_ci							0x000C0140;
45768c2ecf20Sopenharmony_ci					else if (table->mc_reg_table_entry[k].mclk_max == 137500)
45778c2ecf20Sopenharmony_ci						table->mc_reg_table_entry[k].mc_data[i] =
45788c2ecf20Sopenharmony_ci							(table->mc_reg_table_entry[k].mc_data[i] & 0xFFE0FE0F) |
45798c2ecf20Sopenharmony_ci							0x000C0150;
45808c2ecf20Sopenharmony_ci				}
45818c2ecf20Sopenharmony_ci				break;
45828c2ecf20Sopenharmony_ci			case MC_SEQ_MISC_TIMING:
45838c2ecf20Sopenharmony_ci				for (k = 0; k < table->num_entries; k++) {
45848c2ecf20Sopenharmony_ci					if (table->mc_reg_table_entry[k].mclk_max == 125000)
45858c2ecf20Sopenharmony_ci						table->mc_reg_table_entry[k].mc_data[i] =
45868c2ecf20Sopenharmony_ci							(table->mc_reg_table_entry[k].mc_data[i] & 0xFFFFFFE0) |
45878c2ecf20Sopenharmony_ci							0x00000030;
45888c2ecf20Sopenharmony_ci					else if (table->mc_reg_table_entry[k].mclk_max == 137500)
45898c2ecf20Sopenharmony_ci						table->mc_reg_table_entry[k].mc_data[i] =
45908c2ecf20Sopenharmony_ci							(table->mc_reg_table_entry[k].mc_data[i] & 0xFFFFFFE0) |
45918c2ecf20Sopenharmony_ci							0x00000035;
45928c2ecf20Sopenharmony_ci				}
45938c2ecf20Sopenharmony_ci				break;
45948c2ecf20Sopenharmony_ci			default:
45958c2ecf20Sopenharmony_ci				break;
45968c2ecf20Sopenharmony_ci			}
45978c2ecf20Sopenharmony_ci		}
45988c2ecf20Sopenharmony_ci
45998c2ecf20Sopenharmony_ci		WREG32(MC_SEQ_IO_DEBUG_INDEX, 3);
46008c2ecf20Sopenharmony_ci		tmp = RREG32(MC_SEQ_IO_DEBUG_DATA);
46018c2ecf20Sopenharmony_ci		tmp = (tmp & 0xFFF8FFFF) | (1 << 16);
46028c2ecf20Sopenharmony_ci		WREG32(MC_SEQ_IO_DEBUG_INDEX, 3);
46038c2ecf20Sopenharmony_ci		WREG32(MC_SEQ_IO_DEBUG_DATA, tmp);
46048c2ecf20Sopenharmony_ci	}
46058c2ecf20Sopenharmony_ci
46068c2ecf20Sopenharmony_ci	return 0;
46078c2ecf20Sopenharmony_ci}
46088c2ecf20Sopenharmony_ci
46098c2ecf20Sopenharmony_cistatic int ci_initialize_mc_reg_table(struct radeon_device *rdev)
46108c2ecf20Sopenharmony_ci{
46118c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
46128c2ecf20Sopenharmony_ci	struct atom_mc_reg_table *table;
46138c2ecf20Sopenharmony_ci	struct ci_mc_reg_table *ci_table = &pi->mc_reg_table;
46148c2ecf20Sopenharmony_ci	u8 module_index = rv770_get_memory_module_index(rdev);
46158c2ecf20Sopenharmony_ci	int ret;
46168c2ecf20Sopenharmony_ci
46178c2ecf20Sopenharmony_ci	table = kzalloc(sizeof(struct atom_mc_reg_table), GFP_KERNEL);
46188c2ecf20Sopenharmony_ci	if (!table)
46198c2ecf20Sopenharmony_ci		return -ENOMEM;
46208c2ecf20Sopenharmony_ci
46218c2ecf20Sopenharmony_ci	WREG32(MC_SEQ_RAS_TIMING_LP, RREG32(MC_SEQ_RAS_TIMING));
46228c2ecf20Sopenharmony_ci	WREG32(MC_SEQ_CAS_TIMING_LP, RREG32(MC_SEQ_CAS_TIMING));
46238c2ecf20Sopenharmony_ci	WREG32(MC_SEQ_DLL_STBY_LP, RREG32(MC_SEQ_DLL_STBY));
46248c2ecf20Sopenharmony_ci	WREG32(MC_SEQ_G5PDX_CMD0_LP, RREG32(MC_SEQ_G5PDX_CMD0));
46258c2ecf20Sopenharmony_ci	WREG32(MC_SEQ_G5PDX_CMD1_LP, RREG32(MC_SEQ_G5PDX_CMD1));
46268c2ecf20Sopenharmony_ci	WREG32(MC_SEQ_G5PDX_CTRL_LP, RREG32(MC_SEQ_G5PDX_CTRL));
46278c2ecf20Sopenharmony_ci	WREG32(MC_SEQ_PMG_DVS_CMD_LP, RREG32(MC_SEQ_PMG_DVS_CMD));
46288c2ecf20Sopenharmony_ci	WREG32(MC_SEQ_PMG_DVS_CTL_LP, RREG32(MC_SEQ_PMG_DVS_CTL));
46298c2ecf20Sopenharmony_ci	WREG32(MC_SEQ_MISC_TIMING_LP, RREG32(MC_SEQ_MISC_TIMING));
46308c2ecf20Sopenharmony_ci	WREG32(MC_SEQ_MISC_TIMING2_LP, RREG32(MC_SEQ_MISC_TIMING2));
46318c2ecf20Sopenharmony_ci	WREG32(MC_SEQ_PMG_CMD_EMRS_LP, RREG32(MC_PMG_CMD_EMRS));
46328c2ecf20Sopenharmony_ci	WREG32(MC_SEQ_PMG_CMD_MRS_LP, RREG32(MC_PMG_CMD_MRS));
46338c2ecf20Sopenharmony_ci	WREG32(MC_SEQ_PMG_CMD_MRS1_LP, RREG32(MC_PMG_CMD_MRS1));
46348c2ecf20Sopenharmony_ci	WREG32(MC_SEQ_WR_CTL_D0_LP, RREG32(MC_SEQ_WR_CTL_D0));
46358c2ecf20Sopenharmony_ci	WREG32(MC_SEQ_WR_CTL_D1_LP, RREG32(MC_SEQ_WR_CTL_D1));
46368c2ecf20Sopenharmony_ci	WREG32(MC_SEQ_RD_CTL_D0_LP, RREG32(MC_SEQ_RD_CTL_D0));
46378c2ecf20Sopenharmony_ci	WREG32(MC_SEQ_RD_CTL_D1_LP, RREG32(MC_SEQ_RD_CTL_D1));
46388c2ecf20Sopenharmony_ci	WREG32(MC_SEQ_PMG_TIMING_LP, RREG32(MC_SEQ_PMG_TIMING));
46398c2ecf20Sopenharmony_ci	WREG32(MC_SEQ_PMG_CMD_MRS2_LP, RREG32(MC_PMG_CMD_MRS2));
46408c2ecf20Sopenharmony_ci	WREG32(MC_SEQ_WR_CTL_2_LP, RREG32(MC_SEQ_WR_CTL_2));
46418c2ecf20Sopenharmony_ci
46428c2ecf20Sopenharmony_ci	ret = radeon_atom_init_mc_reg_table(rdev, module_index, table);
46438c2ecf20Sopenharmony_ci	if (ret)
46448c2ecf20Sopenharmony_ci		goto init_mc_done;
46458c2ecf20Sopenharmony_ci
46468c2ecf20Sopenharmony_ci	ret = ci_copy_vbios_mc_reg_table(table, ci_table);
46478c2ecf20Sopenharmony_ci	if (ret)
46488c2ecf20Sopenharmony_ci		goto init_mc_done;
46498c2ecf20Sopenharmony_ci
46508c2ecf20Sopenharmony_ci	ci_set_s0_mc_reg_index(ci_table);
46518c2ecf20Sopenharmony_ci
46528c2ecf20Sopenharmony_ci	ret = ci_register_patching_mc_seq(rdev, ci_table);
46538c2ecf20Sopenharmony_ci	if (ret)
46548c2ecf20Sopenharmony_ci		goto init_mc_done;
46558c2ecf20Sopenharmony_ci
46568c2ecf20Sopenharmony_ci	ret = ci_set_mc_special_registers(rdev, ci_table);
46578c2ecf20Sopenharmony_ci	if (ret)
46588c2ecf20Sopenharmony_ci		goto init_mc_done;
46598c2ecf20Sopenharmony_ci
46608c2ecf20Sopenharmony_ci	ci_set_valid_flag(ci_table);
46618c2ecf20Sopenharmony_ci
46628c2ecf20Sopenharmony_ciinit_mc_done:
46638c2ecf20Sopenharmony_ci	kfree(table);
46648c2ecf20Sopenharmony_ci
46658c2ecf20Sopenharmony_ci	return ret;
46668c2ecf20Sopenharmony_ci}
46678c2ecf20Sopenharmony_ci
46688c2ecf20Sopenharmony_cistatic int ci_populate_mc_reg_addresses(struct radeon_device *rdev,
46698c2ecf20Sopenharmony_ci					SMU7_Discrete_MCRegisters *mc_reg_table)
46708c2ecf20Sopenharmony_ci{
46718c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
46728c2ecf20Sopenharmony_ci	u32 i, j;
46738c2ecf20Sopenharmony_ci
46748c2ecf20Sopenharmony_ci	for (i = 0, j = 0; j < pi->mc_reg_table.last; j++) {
46758c2ecf20Sopenharmony_ci		if (pi->mc_reg_table.valid_flag & (1 << j)) {
46768c2ecf20Sopenharmony_ci			if (i >= SMU7_DISCRETE_MC_REGISTER_ARRAY_SIZE)
46778c2ecf20Sopenharmony_ci				return -EINVAL;
46788c2ecf20Sopenharmony_ci			mc_reg_table->address[i].s0 = cpu_to_be16(pi->mc_reg_table.mc_reg_address[j].s0);
46798c2ecf20Sopenharmony_ci			mc_reg_table->address[i].s1 = cpu_to_be16(pi->mc_reg_table.mc_reg_address[j].s1);
46808c2ecf20Sopenharmony_ci			i++;
46818c2ecf20Sopenharmony_ci		}
46828c2ecf20Sopenharmony_ci	}
46838c2ecf20Sopenharmony_ci
46848c2ecf20Sopenharmony_ci	mc_reg_table->last = (u8)i;
46858c2ecf20Sopenharmony_ci
46868c2ecf20Sopenharmony_ci	return 0;
46878c2ecf20Sopenharmony_ci}
46888c2ecf20Sopenharmony_ci
46898c2ecf20Sopenharmony_cistatic void ci_convert_mc_registers(const struct ci_mc_reg_entry *entry,
46908c2ecf20Sopenharmony_ci				    SMU7_Discrete_MCRegisterSet *data,
46918c2ecf20Sopenharmony_ci				    u32 num_entries, u32 valid_flag)
46928c2ecf20Sopenharmony_ci{
46938c2ecf20Sopenharmony_ci	u32 i, j;
46948c2ecf20Sopenharmony_ci
46958c2ecf20Sopenharmony_ci	for (i = 0, j = 0; j < num_entries; j++) {
46968c2ecf20Sopenharmony_ci		if (valid_flag & (1 << j)) {
46978c2ecf20Sopenharmony_ci			data->value[i] = cpu_to_be32(entry->mc_data[j]);
46988c2ecf20Sopenharmony_ci			i++;
46998c2ecf20Sopenharmony_ci		}
47008c2ecf20Sopenharmony_ci	}
47018c2ecf20Sopenharmony_ci}
47028c2ecf20Sopenharmony_ci
47038c2ecf20Sopenharmony_cistatic void ci_convert_mc_reg_table_entry_to_smc(struct radeon_device *rdev,
47048c2ecf20Sopenharmony_ci						 const u32 memory_clock,
47058c2ecf20Sopenharmony_ci						 SMU7_Discrete_MCRegisterSet *mc_reg_table_data)
47068c2ecf20Sopenharmony_ci{
47078c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
47088c2ecf20Sopenharmony_ci	u32 i = 0;
47098c2ecf20Sopenharmony_ci
47108c2ecf20Sopenharmony_ci	for(i = 0; i < pi->mc_reg_table.num_entries; i++) {
47118c2ecf20Sopenharmony_ci		if (memory_clock <= pi->mc_reg_table.mc_reg_table_entry[i].mclk_max)
47128c2ecf20Sopenharmony_ci			break;
47138c2ecf20Sopenharmony_ci	}
47148c2ecf20Sopenharmony_ci
47158c2ecf20Sopenharmony_ci	if ((i == pi->mc_reg_table.num_entries) && (i > 0))
47168c2ecf20Sopenharmony_ci		--i;
47178c2ecf20Sopenharmony_ci
47188c2ecf20Sopenharmony_ci	ci_convert_mc_registers(&pi->mc_reg_table.mc_reg_table_entry[i],
47198c2ecf20Sopenharmony_ci				mc_reg_table_data, pi->mc_reg_table.last,
47208c2ecf20Sopenharmony_ci				pi->mc_reg_table.valid_flag);
47218c2ecf20Sopenharmony_ci}
47228c2ecf20Sopenharmony_ci
47238c2ecf20Sopenharmony_cistatic void ci_convert_mc_reg_table_to_smc(struct radeon_device *rdev,
47248c2ecf20Sopenharmony_ci					   SMU7_Discrete_MCRegisters *mc_reg_table)
47258c2ecf20Sopenharmony_ci{
47268c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
47278c2ecf20Sopenharmony_ci	u32 i;
47288c2ecf20Sopenharmony_ci
47298c2ecf20Sopenharmony_ci	for (i = 0; i < pi->dpm_table.mclk_table.count; i++)
47308c2ecf20Sopenharmony_ci		ci_convert_mc_reg_table_entry_to_smc(rdev,
47318c2ecf20Sopenharmony_ci						     pi->dpm_table.mclk_table.dpm_levels[i].value,
47328c2ecf20Sopenharmony_ci						     &mc_reg_table->data[i]);
47338c2ecf20Sopenharmony_ci}
47348c2ecf20Sopenharmony_ci
47358c2ecf20Sopenharmony_cistatic int ci_populate_initial_mc_reg_table(struct radeon_device *rdev)
47368c2ecf20Sopenharmony_ci{
47378c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
47388c2ecf20Sopenharmony_ci	int ret;
47398c2ecf20Sopenharmony_ci
47408c2ecf20Sopenharmony_ci	memset(&pi->smc_mc_reg_table, 0, sizeof(SMU7_Discrete_MCRegisters));
47418c2ecf20Sopenharmony_ci
47428c2ecf20Sopenharmony_ci	ret = ci_populate_mc_reg_addresses(rdev, &pi->smc_mc_reg_table);
47438c2ecf20Sopenharmony_ci	if (ret)
47448c2ecf20Sopenharmony_ci		return ret;
47458c2ecf20Sopenharmony_ci	ci_convert_mc_reg_table_to_smc(rdev, &pi->smc_mc_reg_table);
47468c2ecf20Sopenharmony_ci
47478c2ecf20Sopenharmony_ci	return ci_copy_bytes_to_smc(rdev,
47488c2ecf20Sopenharmony_ci				    pi->mc_reg_table_start,
47498c2ecf20Sopenharmony_ci				    (u8 *)&pi->smc_mc_reg_table,
47508c2ecf20Sopenharmony_ci				    sizeof(SMU7_Discrete_MCRegisters),
47518c2ecf20Sopenharmony_ci				    pi->sram_end);
47528c2ecf20Sopenharmony_ci}
47538c2ecf20Sopenharmony_ci
47548c2ecf20Sopenharmony_cistatic int ci_update_and_upload_mc_reg_table(struct radeon_device *rdev)
47558c2ecf20Sopenharmony_ci{
47568c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
47578c2ecf20Sopenharmony_ci
47588c2ecf20Sopenharmony_ci	if (!(pi->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK))
47598c2ecf20Sopenharmony_ci		return 0;
47608c2ecf20Sopenharmony_ci
47618c2ecf20Sopenharmony_ci	memset(&pi->smc_mc_reg_table, 0, sizeof(SMU7_Discrete_MCRegisters));
47628c2ecf20Sopenharmony_ci
47638c2ecf20Sopenharmony_ci	ci_convert_mc_reg_table_to_smc(rdev, &pi->smc_mc_reg_table);
47648c2ecf20Sopenharmony_ci
47658c2ecf20Sopenharmony_ci	return ci_copy_bytes_to_smc(rdev,
47668c2ecf20Sopenharmony_ci				    pi->mc_reg_table_start +
47678c2ecf20Sopenharmony_ci				    offsetof(SMU7_Discrete_MCRegisters, data[0]),
47688c2ecf20Sopenharmony_ci				    (u8 *)&pi->smc_mc_reg_table.data[0],
47698c2ecf20Sopenharmony_ci				    sizeof(SMU7_Discrete_MCRegisterSet) *
47708c2ecf20Sopenharmony_ci				    pi->dpm_table.mclk_table.count,
47718c2ecf20Sopenharmony_ci				    pi->sram_end);
47728c2ecf20Sopenharmony_ci}
47738c2ecf20Sopenharmony_ci
47748c2ecf20Sopenharmony_cistatic void ci_enable_voltage_control(struct radeon_device *rdev)
47758c2ecf20Sopenharmony_ci{
47768c2ecf20Sopenharmony_ci	u32 tmp = RREG32_SMC(GENERAL_PWRMGT);
47778c2ecf20Sopenharmony_ci
47788c2ecf20Sopenharmony_ci	tmp |= VOLT_PWRMGT_EN;
47798c2ecf20Sopenharmony_ci	WREG32_SMC(GENERAL_PWRMGT, tmp);
47808c2ecf20Sopenharmony_ci}
47818c2ecf20Sopenharmony_ci
47828c2ecf20Sopenharmony_cistatic enum radeon_pcie_gen ci_get_maximum_link_speed(struct radeon_device *rdev,
47838c2ecf20Sopenharmony_ci						      struct radeon_ps *radeon_state)
47848c2ecf20Sopenharmony_ci{
47858c2ecf20Sopenharmony_ci	struct ci_ps *state = ci_get_ps(radeon_state);
47868c2ecf20Sopenharmony_ci	int i;
47878c2ecf20Sopenharmony_ci	u16 pcie_speed, max_speed = 0;
47888c2ecf20Sopenharmony_ci
47898c2ecf20Sopenharmony_ci	for (i = 0; i < state->performance_level_count; i++) {
47908c2ecf20Sopenharmony_ci		pcie_speed = state->performance_levels[i].pcie_gen;
47918c2ecf20Sopenharmony_ci		if (max_speed < pcie_speed)
47928c2ecf20Sopenharmony_ci			max_speed = pcie_speed;
47938c2ecf20Sopenharmony_ci	}
47948c2ecf20Sopenharmony_ci
47958c2ecf20Sopenharmony_ci	return max_speed;
47968c2ecf20Sopenharmony_ci}
47978c2ecf20Sopenharmony_ci
47988c2ecf20Sopenharmony_cistatic u16 ci_get_current_pcie_speed(struct radeon_device *rdev)
47998c2ecf20Sopenharmony_ci{
48008c2ecf20Sopenharmony_ci	u32 speed_cntl = 0;
48018c2ecf20Sopenharmony_ci
48028c2ecf20Sopenharmony_ci	speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL) & LC_CURRENT_DATA_RATE_MASK;
48038c2ecf20Sopenharmony_ci	speed_cntl >>= LC_CURRENT_DATA_RATE_SHIFT;
48048c2ecf20Sopenharmony_ci
48058c2ecf20Sopenharmony_ci	return (u16)speed_cntl;
48068c2ecf20Sopenharmony_ci}
48078c2ecf20Sopenharmony_ci
48088c2ecf20Sopenharmony_cistatic int ci_get_current_pcie_lane_number(struct radeon_device *rdev)
48098c2ecf20Sopenharmony_ci{
48108c2ecf20Sopenharmony_ci	u32 link_width = 0;
48118c2ecf20Sopenharmony_ci
48128c2ecf20Sopenharmony_ci	link_width = RREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL) & LC_LINK_WIDTH_RD_MASK;
48138c2ecf20Sopenharmony_ci	link_width >>= LC_LINK_WIDTH_RD_SHIFT;
48148c2ecf20Sopenharmony_ci
48158c2ecf20Sopenharmony_ci	switch (link_width) {
48168c2ecf20Sopenharmony_ci	case RADEON_PCIE_LC_LINK_WIDTH_X1:
48178c2ecf20Sopenharmony_ci		return 1;
48188c2ecf20Sopenharmony_ci	case RADEON_PCIE_LC_LINK_WIDTH_X2:
48198c2ecf20Sopenharmony_ci		return 2;
48208c2ecf20Sopenharmony_ci	case RADEON_PCIE_LC_LINK_WIDTH_X4:
48218c2ecf20Sopenharmony_ci		return 4;
48228c2ecf20Sopenharmony_ci	case RADEON_PCIE_LC_LINK_WIDTH_X8:
48238c2ecf20Sopenharmony_ci		return 8;
48248c2ecf20Sopenharmony_ci	case RADEON_PCIE_LC_LINK_WIDTH_X12:
48258c2ecf20Sopenharmony_ci		/* not actually supported */
48268c2ecf20Sopenharmony_ci		return 12;
48278c2ecf20Sopenharmony_ci	case RADEON_PCIE_LC_LINK_WIDTH_X0:
48288c2ecf20Sopenharmony_ci	case RADEON_PCIE_LC_LINK_WIDTH_X16:
48298c2ecf20Sopenharmony_ci	default:
48308c2ecf20Sopenharmony_ci		return 16;
48318c2ecf20Sopenharmony_ci	}
48328c2ecf20Sopenharmony_ci}
48338c2ecf20Sopenharmony_ci
48348c2ecf20Sopenharmony_cistatic void ci_request_link_speed_change_before_state_change(struct radeon_device *rdev,
48358c2ecf20Sopenharmony_ci							     struct radeon_ps *radeon_new_state,
48368c2ecf20Sopenharmony_ci							     struct radeon_ps *radeon_current_state)
48378c2ecf20Sopenharmony_ci{
48388c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
48398c2ecf20Sopenharmony_ci	enum radeon_pcie_gen target_link_speed =
48408c2ecf20Sopenharmony_ci		ci_get_maximum_link_speed(rdev, radeon_new_state);
48418c2ecf20Sopenharmony_ci	enum radeon_pcie_gen current_link_speed;
48428c2ecf20Sopenharmony_ci
48438c2ecf20Sopenharmony_ci	if (pi->force_pcie_gen == RADEON_PCIE_GEN_INVALID)
48448c2ecf20Sopenharmony_ci		current_link_speed = ci_get_maximum_link_speed(rdev, radeon_current_state);
48458c2ecf20Sopenharmony_ci	else
48468c2ecf20Sopenharmony_ci		current_link_speed = pi->force_pcie_gen;
48478c2ecf20Sopenharmony_ci
48488c2ecf20Sopenharmony_ci	pi->force_pcie_gen = RADEON_PCIE_GEN_INVALID;
48498c2ecf20Sopenharmony_ci	pi->pspp_notify_required = false;
48508c2ecf20Sopenharmony_ci	if (target_link_speed > current_link_speed) {
48518c2ecf20Sopenharmony_ci		switch (target_link_speed) {
48528c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI
48538c2ecf20Sopenharmony_ci		case RADEON_PCIE_GEN3:
48548c2ecf20Sopenharmony_ci			if (radeon_acpi_pcie_performance_request(rdev, PCIE_PERF_REQ_PECI_GEN3, false) == 0)
48558c2ecf20Sopenharmony_ci				break;
48568c2ecf20Sopenharmony_ci			pi->force_pcie_gen = RADEON_PCIE_GEN2;
48578c2ecf20Sopenharmony_ci			if (current_link_speed == RADEON_PCIE_GEN2)
48588c2ecf20Sopenharmony_ci				break;
48598c2ecf20Sopenharmony_ci			fallthrough;
48608c2ecf20Sopenharmony_ci		case RADEON_PCIE_GEN2:
48618c2ecf20Sopenharmony_ci			if (radeon_acpi_pcie_performance_request(rdev, PCIE_PERF_REQ_PECI_GEN2, false) == 0)
48628c2ecf20Sopenharmony_ci				break;
48638c2ecf20Sopenharmony_ci#endif
48648c2ecf20Sopenharmony_ci			/* fall through */
48658c2ecf20Sopenharmony_ci		default:
48668c2ecf20Sopenharmony_ci			pi->force_pcie_gen = ci_get_current_pcie_speed(rdev);
48678c2ecf20Sopenharmony_ci			break;
48688c2ecf20Sopenharmony_ci		}
48698c2ecf20Sopenharmony_ci	} else {
48708c2ecf20Sopenharmony_ci		if (target_link_speed < current_link_speed)
48718c2ecf20Sopenharmony_ci			pi->pspp_notify_required = true;
48728c2ecf20Sopenharmony_ci	}
48738c2ecf20Sopenharmony_ci}
48748c2ecf20Sopenharmony_ci
48758c2ecf20Sopenharmony_cistatic void ci_notify_link_speed_change_after_state_change(struct radeon_device *rdev,
48768c2ecf20Sopenharmony_ci							   struct radeon_ps *radeon_new_state,
48778c2ecf20Sopenharmony_ci							   struct radeon_ps *radeon_current_state)
48788c2ecf20Sopenharmony_ci{
48798c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
48808c2ecf20Sopenharmony_ci	enum radeon_pcie_gen target_link_speed =
48818c2ecf20Sopenharmony_ci		ci_get_maximum_link_speed(rdev, radeon_new_state);
48828c2ecf20Sopenharmony_ci	u8 request;
48838c2ecf20Sopenharmony_ci
48848c2ecf20Sopenharmony_ci	if (pi->pspp_notify_required) {
48858c2ecf20Sopenharmony_ci		if (target_link_speed == RADEON_PCIE_GEN3)
48868c2ecf20Sopenharmony_ci			request = PCIE_PERF_REQ_PECI_GEN3;
48878c2ecf20Sopenharmony_ci		else if (target_link_speed == RADEON_PCIE_GEN2)
48888c2ecf20Sopenharmony_ci			request = PCIE_PERF_REQ_PECI_GEN2;
48898c2ecf20Sopenharmony_ci		else
48908c2ecf20Sopenharmony_ci			request = PCIE_PERF_REQ_PECI_GEN1;
48918c2ecf20Sopenharmony_ci
48928c2ecf20Sopenharmony_ci		if ((request == PCIE_PERF_REQ_PECI_GEN1) &&
48938c2ecf20Sopenharmony_ci		    (ci_get_current_pcie_speed(rdev) > 0))
48948c2ecf20Sopenharmony_ci			return;
48958c2ecf20Sopenharmony_ci
48968c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI
48978c2ecf20Sopenharmony_ci		radeon_acpi_pcie_performance_request(rdev, request, false);
48988c2ecf20Sopenharmony_ci#endif
48998c2ecf20Sopenharmony_ci	}
49008c2ecf20Sopenharmony_ci}
49018c2ecf20Sopenharmony_ci
49028c2ecf20Sopenharmony_cistatic int ci_set_private_data_variables_based_on_pptable(struct radeon_device *rdev)
49038c2ecf20Sopenharmony_ci{
49048c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
49058c2ecf20Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *allowed_sclk_vddc_table =
49068c2ecf20Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
49078c2ecf20Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *allowed_mclk_vddc_table =
49088c2ecf20Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk;
49098c2ecf20Sopenharmony_ci	struct radeon_clock_voltage_dependency_table *allowed_mclk_vddci_table =
49108c2ecf20Sopenharmony_ci		&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk;
49118c2ecf20Sopenharmony_ci
49128c2ecf20Sopenharmony_ci	if (allowed_sclk_vddc_table == NULL)
49138c2ecf20Sopenharmony_ci		return -EINVAL;
49148c2ecf20Sopenharmony_ci	if (allowed_sclk_vddc_table->count < 1)
49158c2ecf20Sopenharmony_ci		return -EINVAL;
49168c2ecf20Sopenharmony_ci	if (allowed_mclk_vddc_table == NULL)
49178c2ecf20Sopenharmony_ci		return -EINVAL;
49188c2ecf20Sopenharmony_ci	if (allowed_mclk_vddc_table->count < 1)
49198c2ecf20Sopenharmony_ci		return -EINVAL;
49208c2ecf20Sopenharmony_ci	if (allowed_mclk_vddci_table == NULL)
49218c2ecf20Sopenharmony_ci		return -EINVAL;
49228c2ecf20Sopenharmony_ci	if (allowed_mclk_vddci_table->count < 1)
49238c2ecf20Sopenharmony_ci		return -EINVAL;
49248c2ecf20Sopenharmony_ci
49258c2ecf20Sopenharmony_ci	pi->min_vddc_in_pp_table = allowed_sclk_vddc_table->entries[0].v;
49268c2ecf20Sopenharmony_ci	pi->max_vddc_in_pp_table =
49278c2ecf20Sopenharmony_ci		allowed_sclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].v;
49288c2ecf20Sopenharmony_ci
49298c2ecf20Sopenharmony_ci	pi->min_vddci_in_pp_table = allowed_mclk_vddci_table->entries[0].v;
49308c2ecf20Sopenharmony_ci	pi->max_vddci_in_pp_table =
49318c2ecf20Sopenharmony_ci		allowed_mclk_vddci_table->entries[allowed_mclk_vddci_table->count - 1].v;
49328c2ecf20Sopenharmony_ci
49338c2ecf20Sopenharmony_ci	rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk =
49348c2ecf20Sopenharmony_ci		allowed_sclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].clk;
49358c2ecf20Sopenharmony_ci	rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.mclk =
49368c2ecf20Sopenharmony_ci		allowed_mclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].clk;
49378c2ecf20Sopenharmony_ci	rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddc =
49388c2ecf20Sopenharmony_ci		allowed_sclk_vddc_table->entries[allowed_sclk_vddc_table->count - 1].v;
49398c2ecf20Sopenharmony_ci	rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddci =
49408c2ecf20Sopenharmony_ci		allowed_mclk_vddci_table->entries[allowed_mclk_vddci_table->count - 1].v;
49418c2ecf20Sopenharmony_ci
49428c2ecf20Sopenharmony_ci	return 0;
49438c2ecf20Sopenharmony_ci}
49448c2ecf20Sopenharmony_ci
49458c2ecf20Sopenharmony_cistatic void ci_patch_with_vddc_leakage(struct radeon_device *rdev, u16 *vddc)
49468c2ecf20Sopenharmony_ci{
49478c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
49488c2ecf20Sopenharmony_ci	struct ci_leakage_voltage *leakage_table = &pi->vddc_leakage;
49498c2ecf20Sopenharmony_ci	u32 leakage_index;
49508c2ecf20Sopenharmony_ci
49518c2ecf20Sopenharmony_ci	for (leakage_index = 0; leakage_index < leakage_table->count; leakage_index++) {
49528c2ecf20Sopenharmony_ci		if (leakage_table->leakage_id[leakage_index] == *vddc) {
49538c2ecf20Sopenharmony_ci			*vddc = leakage_table->actual_voltage[leakage_index];
49548c2ecf20Sopenharmony_ci			break;
49558c2ecf20Sopenharmony_ci		}
49568c2ecf20Sopenharmony_ci	}
49578c2ecf20Sopenharmony_ci}
49588c2ecf20Sopenharmony_ci
49598c2ecf20Sopenharmony_cistatic void ci_patch_with_vddci_leakage(struct radeon_device *rdev, u16 *vddci)
49608c2ecf20Sopenharmony_ci{
49618c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
49628c2ecf20Sopenharmony_ci	struct ci_leakage_voltage *leakage_table = &pi->vddci_leakage;
49638c2ecf20Sopenharmony_ci	u32 leakage_index;
49648c2ecf20Sopenharmony_ci
49658c2ecf20Sopenharmony_ci	for (leakage_index = 0; leakage_index < leakage_table->count; leakage_index++) {
49668c2ecf20Sopenharmony_ci		if (leakage_table->leakage_id[leakage_index] == *vddci) {
49678c2ecf20Sopenharmony_ci			*vddci = leakage_table->actual_voltage[leakage_index];
49688c2ecf20Sopenharmony_ci			break;
49698c2ecf20Sopenharmony_ci		}
49708c2ecf20Sopenharmony_ci	}
49718c2ecf20Sopenharmony_ci}
49728c2ecf20Sopenharmony_ci
49738c2ecf20Sopenharmony_cistatic void ci_patch_clock_voltage_dependency_table_with_vddc_leakage(struct radeon_device *rdev,
49748c2ecf20Sopenharmony_ci								      struct radeon_clock_voltage_dependency_table *table)
49758c2ecf20Sopenharmony_ci{
49768c2ecf20Sopenharmony_ci	u32 i;
49778c2ecf20Sopenharmony_ci
49788c2ecf20Sopenharmony_ci	if (table) {
49798c2ecf20Sopenharmony_ci		for (i = 0; i < table->count; i++)
49808c2ecf20Sopenharmony_ci			ci_patch_with_vddc_leakage(rdev, &table->entries[i].v);
49818c2ecf20Sopenharmony_ci	}
49828c2ecf20Sopenharmony_ci}
49838c2ecf20Sopenharmony_ci
49848c2ecf20Sopenharmony_cistatic void ci_patch_clock_voltage_dependency_table_with_vddci_leakage(struct radeon_device *rdev,
49858c2ecf20Sopenharmony_ci								       struct radeon_clock_voltage_dependency_table *table)
49868c2ecf20Sopenharmony_ci{
49878c2ecf20Sopenharmony_ci	u32 i;
49888c2ecf20Sopenharmony_ci
49898c2ecf20Sopenharmony_ci	if (table) {
49908c2ecf20Sopenharmony_ci		for (i = 0; i < table->count; i++)
49918c2ecf20Sopenharmony_ci			ci_patch_with_vddci_leakage(rdev, &table->entries[i].v);
49928c2ecf20Sopenharmony_ci	}
49938c2ecf20Sopenharmony_ci}
49948c2ecf20Sopenharmony_ci
49958c2ecf20Sopenharmony_cistatic void ci_patch_vce_clock_voltage_dependency_table_with_vddc_leakage(struct radeon_device *rdev,
49968c2ecf20Sopenharmony_ci									  struct radeon_vce_clock_voltage_dependency_table *table)
49978c2ecf20Sopenharmony_ci{
49988c2ecf20Sopenharmony_ci	u32 i;
49998c2ecf20Sopenharmony_ci
50008c2ecf20Sopenharmony_ci	if (table) {
50018c2ecf20Sopenharmony_ci		for (i = 0; i < table->count; i++)
50028c2ecf20Sopenharmony_ci			ci_patch_with_vddc_leakage(rdev, &table->entries[i].v);
50038c2ecf20Sopenharmony_ci	}
50048c2ecf20Sopenharmony_ci}
50058c2ecf20Sopenharmony_ci
50068c2ecf20Sopenharmony_cistatic void ci_patch_uvd_clock_voltage_dependency_table_with_vddc_leakage(struct radeon_device *rdev,
50078c2ecf20Sopenharmony_ci									  struct radeon_uvd_clock_voltage_dependency_table *table)
50088c2ecf20Sopenharmony_ci{
50098c2ecf20Sopenharmony_ci	u32 i;
50108c2ecf20Sopenharmony_ci
50118c2ecf20Sopenharmony_ci	if (table) {
50128c2ecf20Sopenharmony_ci		for (i = 0; i < table->count; i++)
50138c2ecf20Sopenharmony_ci			ci_patch_with_vddc_leakage(rdev, &table->entries[i].v);
50148c2ecf20Sopenharmony_ci	}
50158c2ecf20Sopenharmony_ci}
50168c2ecf20Sopenharmony_ci
50178c2ecf20Sopenharmony_cistatic void ci_patch_vddc_phase_shed_limit_table_with_vddc_leakage(struct radeon_device *rdev,
50188c2ecf20Sopenharmony_ci								   struct radeon_phase_shedding_limits_table *table)
50198c2ecf20Sopenharmony_ci{
50208c2ecf20Sopenharmony_ci	u32 i;
50218c2ecf20Sopenharmony_ci
50228c2ecf20Sopenharmony_ci	if (table) {
50238c2ecf20Sopenharmony_ci		for (i = 0; i < table->count; i++)
50248c2ecf20Sopenharmony_ci			ci_patch_with_vddc_leakage(rdev, &table->entries[i].voltage);
50258c2ecf20Sopenharmony_ci	}
50268c2ecf20Sopenharmony_ci}
50278c2ecf20Sopenharmony_ci
50288c2ecf20Sopenharmony_cistatic void ci_patch_clock_voltage_limits_with_vddc_leakage(struct radeon_device *rdev,
50298c2ecf20Sopenharmony_ci							    struct radeon_clock_and_voltage_limits *table)
50308c2ecf20Sopenharmony_ci{
50318c2ecf20Sopenharmony_ci	if (table) {
50328c2ecf20Sopenharmony_ci		ci_patch_with_vddc_leakage(rdev, (u16 *)&table->vddc);
50338c2ecf20Sopenharmony_ci		ci_patch_with_vddci_leakage(rdev, (u16 *)&table->vddci);
50348c2ecf20Sopenharmony_ci	}
50358c2ecf20Sopenharmony_ci}
50368c2ecf20Sopenharmony_ci
50378c2ecf20Sopenharmony_cistatic void ci_patch_cac_leakage_table_with_vddc_leakage(struct radeon_device *rdev,
50388c2ecf20Sopenharmony_ci							 struct radeon_cac_leakage_table *table)
50398c2ecf20Sopenharmony_ci{
50408c2ecf20Sopenharmony_ci	u32 i;
50418c2ecf20Sopenharmony_ci
50428c2ecf20Sopenharmony_ci	if (table) {
50438c2ecf20Sopenharmony_ci		for (i = 0; i < table->count; i++)
50448c2ecf20Sopenharmony_ci			ci_patch_with_vddc_leakage(rdev, &table->entries[i].vddc);
50458c2ecf20Sopenharmony_ci	}
50468c2ecf20Sopenharmony_ci}
50478c2ecf20Sopenharmony_ci
50488c2ecf20Sopenharmony_cistatic void ci_patch_dependency_tables_with_leakage(struct radeon_device *rdev)
50498c2ecf20Sopenharmony_ci{
50508c2ecf20Sopenharmony_ci
50518c2ecf20Sopenharmony_ci	ci_patch_clock_voltage_dependency_table_with_vddc_leakage(rdev,
50528c2ecf20Sopenharmony_ci								  &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk);
50538c2ecf20Sopenharmony_ci	ci_patch_clock_voltage_dependency_table_with_vddc_leakage(rdev,
50548c2ecf20Sopenharmony_ci								  &rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk);
50558c2ecf20Sopenharmony_ci	ci_patch_clock_voltage_dependency_table_with_vddc_leakage(rdev,
50568c2ecf20Sopenharmony_ci								  &rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk);
50578c2ecf20Sopenharmony_ci	ci_patch_clock_voltage_dependency_table_with_vddci_leakage(rdev,
50588c2ecf20Sopenharmony_ci								   &rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk);
50598c2ecf20Sopenharmony_ci	ci_patch_vce_clock_voltage_dependency_table_with_vddc_leakage(rdev,
50608c2ecf20Sopenharmony_ci								      &rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table);
50618c2ecf20Sopenharmony_ci	ci_patch_uvd_clock_voltage_dependency_table_with_vddc_leakage(rdev,
50628c2ecf20Sopenharmony_ci								      &rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table);
50638c2ecf20Sopenharmony_ci	ci_patch_clock_voltage_dependency_table_with_vddc_leakage(rdev,
50648c2ecf20Sopenharmony_ci								  &rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table);
50658c2ecf20Sopenharmony_ci	ci_patch_clock_voltage_dependency_table_with_vddc_leakage(rdev,
50668c2ecf20Sopenharmony_ci								  &rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table);
50678c2ecf20Sopenharmony_ci	ci_patch_vddc_phase_shed_limit_table_with_vddc_leakage(rdev,
50688c2ecf20Sopenharmony_ci							       &rdev->pm.dpm.dyn_state.phase_shedding_limits_table);
50698c2ecf20Sopenharmony_ci	ci_patch_clock_voltage_limits_with_vddc_leakage(rdev,
50708c2ecf20Sopenharmony_ci							&rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac);
50718c2ecf20Sopenharmony_ci	ci_patch_clock_voltage_limits_with_vddc_leakage(rdev,
50728c2ecf20Sopenharmony_ci							&rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc);
50738c2ecf20Sopenharmony_ci	ci_patch_cac_leakage_table_with_vddc_leakage(rdev,
50748c2ecf20Sopenharmony_ci						     &rdev->pm.dpm.dyn_state.cac_leakage_table);
50758c2ecf20Sopenharmony_ci
50768c2ecf20Sopenharmony_ci}
50778c2ecf20Sopenharmony_ci
50788c2ecf20Sopenharmony_cistatic void ci_get_memory_type(struct radeon_device *rdev)
50798c2ecf20Sopenharmony_ci{
50808c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
50818c2ecf20Sopenharmony_ci	u32 tmp;
50828c2ecf20Sopenharmony_ci
50838c2ecf20Sopenharmony_ci	tmp = RREG32(MC_SEQ_MISC0);
50848c2ecf20Sopenharmony_ci
50858c2ecf20Sopenharmony_ci	if (((tmp & MC_SEQ_MISC0_GDDR5_MASK) >> MC_SEQ_MISC0_GDDR5_SHIFT) ==
50868c2ecf20Sopenharmony_ci	    MC_SEQ_MISC0_GDDR5_VALUE)
50878c2ecf20Sopenharmony_ci		pi->mem_gddr5 = true;
50888c2ecf20Sopenharmony_ci	else
50898c2ecf20Sopenharmony_ci		pi->mem_gddr5 = false;
50908c2ecf20Sopenharmony_ci
50918c2ecf20Sopenharmony_ci}
50928c2ecf20Sopenharmony_ci
50938c2ecf20Sopenharmony_cistatic void ci_update_current_ps(struct radeon_device *rdev,
50948c2ecf20Sopenharmony_ci				 struct radeon_ps *rps)
50958c2ecf20Sopenharmony_ci{
50968c2ecf20Sopenharmony_ci	struct ci_ps *new_ps = ci_get_ps(rps);
50978c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
50988c2ecf20Sopenharmony_ci
50998c2ecf20Sopenharmony_ci	pi->current_rps = *rps;
51008c2ecf20Sopenharmony_ci	pi->current_ps = *new_ps;
51018c2ecf20Sopenharmony_ci	pi->current_rps.ps_priv = &pi->current_ps;
51028c2ecf20Sopenharmony_ci}
51038c2ecf20Sopenharmony_ci
51048c2ecf20Sopenharmony_cistatic void ci_update_requested_ps(struct radeon_device *rdev,
51058c2ecf20Sopenharmony_ci				   struct radeon_ps *rps)
51068c2ecf20Sopenharmony_ci{
51078c2ecf20Sopenharmony_ci	struct ci_ps *new_ps = ci_get_ps(rps);
51088c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
51098c2ecf20Sopenharmony_ci
51108c2ecf20Sopenharmony_ci	pi->requested_rps = *rps;
51118c2ecf20Sopenharmony_ci	pi->requested_ps = *new_ps;
51128c2ecf20Sopenharmony_ci	pi->requested_rps.ps_priv = &pi->requested_ps;
51138c2ecf20Sopenharmony_ci}
51148c2ecf20Sopenharmony_ci
51158c2ecf20Sopenharmony_ciint ci_dpm_pre_set_power_state(struct radeon_device *rdev)
51168c2ecf20Sopenharmony_ci{
51178c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
51188c2ecf20Sopenharmony_ci	struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps;
51198c2ecf20Sopenharmony_ci	struct radeon_ps *new_ps = &requested_ps;
51208c2ecf20Sopenharmony_ci
51218c2ecf20Sopenharmony_ci	ci_update_requested_ps(rdev, new_ps);
51228c2ecf20Sopenharmony_ci
51238c2ecf20Sopenharmony_ci	ci_apply_state_adjust_rules(rdev, &pi->requested_rps);
51248c2ecf20Sopenharmony_ci
51258c2ecf20Sopenharmony_ci	return 0;
51268c2ecf20Sopenharmony_ci}
51278c2ecf20Sopenharmony_ci
51288c2ecf20Sopenharmony_civoid ci_dpm_post_set_power_state(struct radeon_device *rdev)
51298c2ecf20Sopenharmony_ci{
51308c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
51318c2ecf20Sopenharmony_ci	struct radeon_ps *new_ps = &pi->requested_rps;
51328c2ecf20Sopenharmony_ci
51338c2ecf20Sopenharmony_ci	ci_update_current_ps(rdev, new_ps);
51348c2ecf20Sopenharmony_ci}
51358c2ecf20Sopenharmony_ci
51368c2ecf20Sopenharmony_ci
51378c2ecf20Sopenharmony_civoid ci_dpm_setup_asic(struct radeon_device *rdev)
51388c2ecf20Sopenharmony_ci{
51398c2ecf20Sopenharmony_ci	int r;
51408c2ecf20Sopenharmony_ci
51418c2ecf20Sopenharmony_ci	r = ci_mc_load_microcode(rdev);
51428c2ecf20Sopenharmony_ci	if (r)
51438c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to load MC firmware!\n");
51448c2ecf20Sopenharmony_ci	ci_read_clock_registers(rdev);
51458c2ecf20Sopenharmony_ci	ci_get_memory_type(rdev);
51468c2ecf20Sopenharmony_ci	ci_enable_acpi_power_management(rdev);
51478c2ecf20Sopenharmony_ci	ci_init_sclk_t(rdev);
51488c2ecf20Sopenharmony_ci}
51498c2ecf20Sopenharmony_ci
51508c2ecf20Sopenharmony_ciint ci_dpm_enable(struct radeon_device *rdev)
51518c2ecf20Sopenharmony_ci{
51528c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
51538c2ecf20Sopenharmony_ci	struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
51548c2ecf20Sopenharmony_ci	int ret;
51558c2ecf20Sopenharmony_ci
51568c2ecf20Sopenharmony_ci	if (ci_is_smc_running(rdev))
51578c2ecf20Sopenharmony_ci		return -EINVAL;
51588c2ecf20Sopenharmony_ci	if (pi->voltage_control != CISLANDS_VOLTAGE_CONTROL_NONE) {
51598c2ecf20Sopenharmony_ci		ci_enable_voltage_control(rdev);
51608c2ecf20Sopenharmony_ci		ret = ci_construct_voltage_tables(rdev);
51618c2ecf20Sopenharmony_ci		if (ret) {
51628c2ecf20Sopenharmony_ci			DRM_ERROR("ci_construct_voltage_tables failed\n");
51638c2ecf20Sopenharmony_ci			return ret;
51648c2ecf20Sopenharmony_ci		}
51658c2ecf20Sopenharmony_ci	}
51668c2ecf20Sopenharmony_ci	if (pi->caps_dynamic_ac_timing) {
51678c2ecf20Sopenharmony_ci		ret = ci_initialize_mc_reg_table(rdev);
51688c2ecf20Sopenharmony_ci		if (ret)
51698c2ecf20Sopenharmony_ci			pi->caps_dynamic_ac_timing = false;
51708c2ecf20Sopenharmony_ci	}
51718c2ecf20Sopenharmony_ci	if (pi->dynamic_ss)
51728c2ecf20Sopenharmony_ci		ci_enable_spread_spectrum(rdev, true);
51738c2ecf20Sopenharmony_ci	if (pi->thermal_protection)
51748c2ecf20Sopenharmony_ci		ci_enable_thermal_protection(rdev, true);
51758c2ecf20Sopenharmony_ci	ci_program_sstp(rdev);
51768c2ecf20Sopenharmony_ci	ci_enable_display_gap(rdev);
51778c2ecf20Sopenharmony_ci	ci_program_vc(rdev);
51788c2ecf20Sopenharmony_ci	ret = ci_upload_firmware(rdev);
51798c2ecf20Sopenharmony_ci	if (ret) {
51808c2ecf20Sopenharmony_ci		DRM_ERROR("ci_upload_firmware failed\n");
51818c2ecf20Sopenharmony_ci		return ret;
51828c2ecf20Sopenharmony_ci	}
51838c2ecf20Sopenharmony_ci	ret = ci_process_firmware_header(rdev);
51848c2ecf20Sopenharmony_ci	if (ret) {
51858c2ecf20Sopenharmony_ci		DRM_ERROR("ci_process_firmware_header failed\n");
51868c2ecf20Sopenharmony_ci		return ret;
51878c2ecf20Sopenharmony_ci	}
51888c2ecf20Sopenharmony_ci	ret = ci_initial_switch_from_arb_f0_to_f1(rdev);
51898c2ecf20Sopenharmony_ci	if (ret) {
51908c2ecf20Sopenharmony_ci		DRM_ERROR("ci_initial_switch_from_arb_f0_to_f1 failed\n");
51918c2ecf20Sopenharmony_ci		return ret;
51928c2ecf20Sopenharmony_ci	}
51938c2ecf20Sopenharmony_ci	ret = ci_init_smc_table(rdev);
51948c2ecf20Sopenharmony_ci	if (ret) {
51958c2ecf20Sopenharmony_ci		DRM_ERROR("ci_init_smc_table failed\n");
51968c2ecf20Sopenharmony_ci		return ret;
51978c2ecf20Sopenharmony_ci	}
51988c2ecf20Sopenharmony_ci	ret = ci_init_arb_table_index(rdev);
51998c2ecf20Sopenharmony_ci	if (ret) {
52008c2ecf20Sopenharmony_ci		DRM_ERROR("ci_init_arb_table_index failed\n");
52018c2ecf20Sopenharmony_ci		return ret;
52028c2ecf20Sopenharmony_ci	}
52038c2ecf20Sopenharmony_ci	if (pi->caps_dynamic_ac_timing) {
52048c2ecf20Sopenharmony_ci		ret = ci_populate_initial_mc_reg_table(rdev);
52058c2ecf20Sopenharmony_ci		if (ret) {
52068c2ecf20Sopenharmony_ci			DRM_ERROR("ci_populate_initial_mc_reg_table failed\n");
52078c2ecf20Sopenharmony_ci			return ret;
52088c2ecf20Sopenharmony_ci		}
52098c2ecf20Sopenharmony_ci	}
52108c2ecf20Sopenharmony_ci	ret = ci_populate_pm_base(rdev);
52118c2ecf20Sopenharmony_ci	if (ret) {
52128c2ecf20Sopenharmony_ci		DRM_ERROR("ci_populate_pm_base failed\n");
52138c2ecf20Sopenharmony_ci		return ret;
52148c2ecf20Sopenharmony_ci	}
52158c2ecf20Sopenharmony_ci	ci_dpm_start_smc(rdev);
52168c2ecf20Sopenharmony_ci	ci_enable_vr_hot_gpio_interrupt(rdev);
52178c2ecf20Sopenharmony_ci	ret = ci_notify_smc_display_change(rdev, false);
52188c2ecf20Sopenharmony_ci	if (ret) {
52198c2ecf20Sopenharmony_ci		DRM_ERROR("ci_notify_smc_display_change failed\n");
52208c2ecf20Sopenharmony_ci		return ret;
52218c2ecf20Sopenharmony_ci	}
52228c2ecf20Sopenharmony_ci	ci_enable_sclk_control(rdev, true);
52238c2ecf20Sopenharmony_ci	ret = ci_enable_ulv(rdev, true);
52248c2ecf20Sopenharmony_ci	if (ret) {
52258c2ecf20Sopenharmony_ci		DRM_ERROR("ci_enable_ulv failed\n");
52268c2ecf20Sopenharmony_ci		return ret;
52278c2ecf20Sopenharmony_ci	}
52288c2ecf20Sopenharmony_ci	ret = ci_enable_ds_master_switch(rdev, true);
52298c2ecf20Sopenharmony_ci	if (ret) {
52308c2ecf20Sopenharmony_ci		DRM_ERROR("ci_enable_ds_master_switch failed\n");
52318c2ecf20Sopenharmony_ci		return ret;
52328c2ecf20Sopenharmony_ci	}
52338c2ecf20Sopenharmony_ci	ret = ci_start_dpm(rdev);
52348c2ecf20Sopenharmony_ci	if (ret) {
52358c2ecf20Sopenharmony_ci		DRM_ERROR("ci_start_dpm failed\n");
52368c2ecf20Sopenharmony_ci		return ret;
52378c2ecf20Sopenharmony_ci	}
52388c2ecf20Sopenharmony_ci	ret = ci_enable_didt(rdev, true);
52398c2ecf20Sopenharmony_ci	if (ret) {
52408c2ecf20Sopenharmony_ci		DRM_ERROR("ci_enable_didt failed\n");
52418c2ecf20Sopenharmony_ci		return ret;
52428c2ecf20Sopenharmony_ci	}
52438c2ecf20Sopenharmony_ci	ret = ci_enable_smc_cac(rdev, true);
52448c2ecf20Sopenharmony_ci	if (ret) {
52458c2ecf20Sopenharmony_ci		DRM_ERROR("ci_enable_smc_cac failed\n");
52468c2ecf20Sopenharmony_ci		return ret;
52478c2ecf20Sopenharmony_ci	}
52488c2ecf20Sopenharmony_ci	ret = ci_enable_power_containment(rdev, true);
52498c2ecf20Sopenharmony_ci	if (ret) {
52508c2ecf20Sopenharmony_ci		DRM_ERROR("ci_enable_power_containment failed\n");
52518c2ecf20Sopenharmony_ci		return ret;
52528c2ecf20Sopenharmony_ci	}
52538c2ecf20Sopenharmony_ci
52548c2ecf20Sopenharmony_ci	ret = ci_power_control_set_level(rdev);
52558c2ecf20Sopenharmony_ci	if (ret) {
52568c2ecf20Sopenharmony_ci		DRM_ERROR("ci_power_control_set_level failed\n");
52578c2ecf20Sopenharmony_ci		return ret;
52588c2ecf20Sopenharmony_ci	}
52598c2ecf20Sopenharmony_ci
52608c2ecf20Sopenharmony_ci	ci_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
52618c2ecf20Sopenharmony_ci
52628c2ecf20Sopenharmony_ci	ret = ci_enable_thermal_based_sclk_dpm(rdev, true);
52638c2ecf20Sopenharmony_ci	if (ret) {
52648c2ecf20Sopenharmony_ci		DRM_ERROR("ci_enable_thermal_based_sclk_dpm failed\n");
52658c2ecf20Sopenharmony_ci		return ret;
52668c2ecf20Sopenharmony_ci	}
52678c2ecf20Sopenharmony_ci
52688c2ecf20Sopenharmony_ci	ci_thermal_start_thermal_controller(rdev);
52698c2ecf20Sopenharmony_ci
52708c2ecf20Sopenharmony_ci	ci_update_current_ps(rdev, boot_ps);
52718c2ecf20Sopenharmony_ci
52728c2ecf20Sopenharmony_ci	return 0;
52738c2ecf20Sopenharmony_ci}
52748c2ecf20Sopenharmony_ci
52758c2ecf20Sopenharmony_cistatic int ci_set_temperature_range(struct radeon_device *rdev)
52768c2ecf20Sopenharmony_ci{
52778c2ecf20Sopenharmony_ci	int ret;
52788c2ecf20Sopenharmony_ci
52798c2ecf20Sopenharmony_ci	ret = ci_thermal_enable_alert(rdev, false);
52808c2ecf20Sopenharmony_ci	if (ret)
52818c2ecf20Sopenharmony_ci		return ret;
52828c2ecf20Sopenharmony_ci	ret = ci_thermal_set_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
52838c2ecf20Sopenharmony_ci	if (ret)
52848c2ecf20Sopenharmony_ci		return ret;
52858c2ecf20Sopenharmony_ci	ret = ci_thermal_enable_alert(rdev, true);
52868c2ecf20Sopenharmony_ci	if (ret)
52878c2ecf20Sopenharmony_ci		return ret;
52888c2ecf20Sopenharmony_ci
52898c2ecf20Sopenharmony_ci	return ret;
52908c2ecf20Sopenharmony_ci}
52918c2ecf20Sopenharmony_ci
52928c2ecf20Sopenharmony_ciint ci_dpm_late_enable(struct radeon_device *rdev)
52938c2ecf20Sopenharmony_ci{
52948c2ecf20Sopenharmony_ci	int ret;
52958c2ecf20Sopenharmony_ci
52968c2ecf20Sopenharmony_ci	ret = ci_set_temperature_range(rdev);
52978c2ecf20Sopenharmony_ci	if (ret)
52988c2ecf20Sopenharmony_ci		return ret;
52998c2ecf20Sopenharmony_ci
53008c2ecf20Sopenharmony_ci	ci_dpm_powergate_uvd(rdev, true);
53018c2ecf20Sopenharmony_ci
53028c2ecf20Sopenharmony_ci	return 0;
53038c2ecf20Sopenharmony_ci}
53048c2ecf20Sopenharmony_ci
53058c2ecf20Sopenharmony_civoid ci_dpm_disable(struct radeon_device *rdev)
53068c2ecf20Sopenharmony_ci{
53078c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
53088c2ecf20Sopenharmony_ci	struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
53098c2ecf20Sopenharmony_ci
53108c2ecf20Sopenharmony_ci	ci_dpm_powergate_uvd(rdev, false);
53118c2ecf20Sopenharmony_ci
53128c2ecf20Sopenharmony_ci	if (!ci_is_smc_running(rdev))
53138c2ecf20Sopenharmony_ci		return;
53148c2ecf20Sopenharmony_ci
53158c2ecf20Sopenharmony_ci	ci_thermal_stop_thermal_controller(rdev);
53168c2ecf20Sopenharmony_ci
53178c2ecf20Sopenharmony_ci	if (pi->thermal_protection)
53188c2ecf20Sopenharmony_ci		ci_enable_thermal_protection(rdev, false);
53198c2ecf20Sopenharmony_ci	ci_enable_power_containment(rdev, false);
53208c2ecf20Sopenharmony_ci	ci_enable_smc_cac(rdev, false);
53218c2ecf20Sopenharmony_ci	ci_enable_didt(rdev, false);
53228c2ecf20Sopenharmony_ci	ci_enable_spread_spectrum(rdev, false);
53238c2ecf20Sopenharmony_ci	ci_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, false);
53248c2ecf20Sopenharmony_ci	ci_stop_dpm(rdev);
53258c2ecf20Sopenharmony_ci	ci_enable_ds_master_switch(rdev, false);
53268c2ecf20Sopenharmony_ci	ci_enable_ulv(rdev, false);
53278c2ecf20Sopenharmony_ci	ci_clear_vc(rdev);
53288c2ecf20Sopenharmony_ci	ci_reset_to_default(rdev);
53298c2ecf20Sopenharmony_ci	ci_dpm_stop_smc(rdev);
53308c2ecf20Sopenharmony_ci	ci_force_switch_to_arb_f0(rdev);
53318c2ecf20Sopenharmony_ci	ci_enable_thermal_based_sclk_dpm(rdev, false);
53328c2ecf20Sopenharmony_ci
53338c2ecf20Sopenharmony_ci	ci_update_current_ps(rdev, boot_ps);
53348c2ecf20Sopenharmony_ci}
53358c2ecf20Sopenharmony_ci
53368c2ecf20Sopenharmony_ciint ci_dpm_set_power_state(struct radeon_device *rdev)
53378c2ecf20Sopenharmony_ci{
53388c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
53398c2ecf20Sopenharmony_ci	struct radeon_ps *new_ps = &pi->requested_rps;
53408c2ecf20Sopenharmony_ci	struct radeon_ps *old_ps = &pi->current_rps;
53418c2ecf20Sopenharmony_ci	int ret;
53428c2ecf20Sopenharmony_ci
53438c2ecf20Sopenharmony_ci	ci_find_dpm_states_clocks_in_dpm_table(rdev, new_ps);
53448c2ecf20Sopenharmony_ci	if (pi->pcie_performance_request)
53458c2ecf20Sopenharmony_ci		ci_request_link_speed_change_before_state_change(rdev, new_ps, old_ps);
53468c2ecf20Sopenharmony_ci	ret = ci_freeze_sclk_mclk_dpm(rdev);
53478c2ecf20Sopenharmony_ci	if (ret) {
53488c2ecf20Sopenharmony_ci		DRM_ERROR("ci_freeze_sclk_mclk_dpm failed\n");
53498c2ecf20Sopenharmony_ci		return ret;
53508c2ecf20Sopenharmony_ci	}
53518c2ecf20Sopenharmony_ci	ret = ci_populate_and_upload_sclk_mclk_dpm_levels(rdev, new_ps);
53528c2ecf20Sopenharmony_ci	if (ret) {
53538c2ecf20Sopenharmony_ci		DRM_ERROR("ci_populate_and_upload_sclk_mclk_dpm_levels failed\n");
53548c2ecf20Sopenharmony_ci		return ret;
53558c2ecf20Sopenharmony_ci	}
53568c2ecf20Sopenharmony_ci	ret = ci_generate_dpm_level_enable_mask(rdev, new_ps);
53578c2ecf20Sopenharmony_ci	if (ret) {
53588c2ecf20Sopenharmony_ci		DRM_ERROR("ci_generate_dpm_level_enable_mask failed\n");
53598c2ecf20Sopenharmony_ci		return ret;
53608c2ecf20Sopenharmony_ci	}
53618c2ecf20Sopenharmony_ci
53628c2ecf20Sopenharmony_ci	ret = ci_update_vce_dpm(rdev, new_ps, old_ps);
53638c2ecf20Sopenharmony_ci	if (ret) {
53648c2ecf20Sopenharmony_ci		DRM_ERROR("ci_update_vce_dpm failed\n");
53658c2ecf20Sopenharmony_ci		return ret;
53668c2ecf20Sopenharmony_ci	}
53678c2ecf20Sopenharmony_ci
53688c2ecf20Sopenharmony_ci	ret = ci_update_sclk_t(rdev);
53698c2ecf20Sopenharmony_ci	if (ret) {
53708c2ecf20Sopenharmony_ci		DRM_ERROR("ci_update_sclk_t failed\n");
53718c2ecf20Sopenharmony_ci		return ret;
53728c2ecf20Sopenharmony_ci	}
53738c2ecf20Sopenharmony_ci	if (pi->caps_dynamic_ac_timing) {
53748c2ecf20Sopenharmony_ci		ret = ci_update_and_upload_mc_reg_table(rdev);
53758c2ecf20Sopenharmony_ci		if (ret) {
53768c2ecf20Sopenharmony_ci			DRM_ERROR("ci_update_and_upload_mc_reg_table failed\n");
53778c2ecf20Sopenharmony_ci			return ret;
53788c2ecf20Sopenharmony_ci		}
53798c2ecf20Sopenharmony_ci	}
53808c2ecf20Sopenharmony_ci	ret = ci_program_memory_timing_parameters(rdev);
53818c2ecf20Sopenharmony_ci	if (ret) {
53828c2ecf20Sopenharmony_ci		DRM_ERROR("ci_program_memory_timing_parameters failed\n");
53838c2ecf20Sopenharmony_ci		return ret;
53848c2ecf20Sopenharmony_ci	}
53858c2ecf20Sopenharmony_ci	ret = ci_unfreeze_sclk_mclk_dpm(rdev);
53868c2ecf20Sopenharmony_ci	if (ret) {
53878c2ecf20Sopenharmony_ci		DRM_ERROR("ci_unfreeze_sclk_mclk_dpm failed\n");
53888c2ecf20Sopenharmony_ci		return ret;
53898c2ecf20Sopenharmony_ci	}
53908c2ecf20Sopenharmony_ci	ret = ci_upload_dpm_level_enable_mask(rdev);
53918c2ecf20Sopenharmony_ci	if (ret) {
53928c2ecf20Sopenharmony_ci		DRM_ERROR("ci_upload_dpm_level_enable_mask failed\n");
53938c2ecf20Sopenharmony_ci		return ret;
53948c2ecf20Sopenharmony_ci	}
53958c2ecf20Sopenharmony_ci	if (pi->pcie_performance_request)
53968c2ecf20Sopenharmony_ci		ci_notify_link_speed_change_after_state_change(rdev, new_ps, old_ps);
53978c2ecf20Sopenharmony_ci
53988c2ecf20Sopenharmony_ci	return 0;
53998c2ecf20Sopenharmony_ci}
54008c2ecf20Sopenharmony_ci
54018c2ecf20Sopenharmony_ci#if 0
54028c2ecf20Sopenharmony_civoid ci_dpm_reset_asic(struct radeon_device *rdev)
54038c2ecf20Sopenharmony_ci{
54048c2ecf20Sopenharmony_ci	ci_set_boot_state(rdev);
54058c2ecf20Sopenharmony_ci}
54068c2ecf20Sopenharmony_ci#endif
54078c2ecf20Sopenharmony_ci
54088c2ecf20Sopenharmony_civoid ci_dpm_display_configuration_changed(struct radeon_device *rdev)
54098c2ecf20Sopenharmony_ci{
54108c2ecf20Sopenharmony_ci	ci_program_display_gap(rdev);
54118c2ecf20Sopenharmony_ci}
54128c2ecf20Sopenharmony_ci
54138c2ecf20Sopenharmony_ciunion power_info {
54148c2ecf20Sopenharmony_ci	struct _ATOM_POWERPLAY_INFO info;
54158c2ecf20Sopenharmony_ci	struct _ATOM_POWERPLAY_INFO_V2 info_2;
54168c2ecf20Sopenharmony_ci	struct _ATOM_POWERPLAY_INFO_V3 info_3;
54178c2ecf20Sopenharmony_ci	struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
54188c2ecf20Sopenharmony_ci	struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
54198c2ecf20Sopenharmony_ci	struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
54208c2ecf20Sopenharmony_ci};
54218c2ecf20Sopenharmony_ci
54228c2ecf20Sopenharmony_ciunion pplib_clock_info {
54238c2ecf20Sopenharmony_ci	struct _ATOM_PPLIB_R600_CLOCK_INFO r600;
54248c2ecf20Sopenharmony_ci	struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780;
54258c2ecf20Sopenharmony_ci	struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen;
54268c2ecf20Sopenharmony_ci	struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo;
54278c2ecf20Sopenharmony_ci	struct _ATOM_PPLIB_SI_CLOCK_INFO si;
54288c2ecf20Sopenharmony_ci	struct _ATOM_PPLIB_CI_CLOCK_INFO ci;
54298c2ecf20Sopenharmony_ci};
54308c2ecf20Sopenharmony_ci
54318c2ecf20Sopenharmony_ciunion pplib_power_state {
54328c2ecf20Sopenharmony_ci	struct _ATOM_PPLIB_STATE v1;
54338c2ecf20Sopenharmony_ci	struct _ATOM_PPLIB_STATE_V2 v2;
54348c2ecf20Sopenharmony_ci};
54358c2ecf20Sopenharmony_ci
54368c2ecf20Sopenharmony_cistatic void ci_parse_pplib_non_clock_info(struct radeon_device *rdev,
54378c2ecf20Sopenharmony_ci					  struct radeon_ps *rps,
54388c2ecf20Sopenharmony_ci					  struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
54398c2ecf20Sopenharmony_ci					  u8 table_rev)
54408c2ecf20Sopenharmony_ci{
54418c2ecf20Sopenharmony_ci	rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings);
54428c2ecf20Sopenharmony_ci	rps->class = le16_to_cpu(non_clock_info->usClassification);
54438c2ecf20Sopenharmony_ci	rps->class2 = le16_to_cpu(non_clock_info->usClassification2);
54448c2ecf20Sopenharmony_ci
54458c2ecf20Sopenharmony_ci	if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
54468c2ecf20Sopenharmony_ci		rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
54478c2ecf20Sopenharmony_ci		rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
54488c2ecf20Sopenharmony_ci	} else {
54498c2ecf20Sopenharmony_ci		rps->vclk = 0;
54508c2ecf20Sopenharmony_ci		rps->dclk = 0;
54518c2ecf20Sopenharmony_ci	}
54528c2ecf20Sopenharmony_ci
54538c2ecf20Sopenharmony_ci	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
54548c2ecf20Sopenharmony_ci		rdev->pm.dpm.boot_ps = rps;
54558c2ecf20Sopenharmony_ci	if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
54568c2ecf20Sopenharmony_ci		rdev->pm.dpm.uvd_ps = rps;
54578c2ecf20Sopenharmony_ci}
54588c2ecf20Sopenharmony_ci
54598c2ecf20Sopenharmony_cistatic void ci_parse_pplib_clock_info(struct radeon_device *rdev,
54608c2ecf20Sopenharmony_ci				      struct radeon_ps *rps, int index,
54618c2ecf20Sopenharmony_ci				      union pplib_clock_info *clock_info)
54628c2ecf20Sopenharmony_ci{
54638c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
54648c2ecf20Sopenharmony_ci	struct ci_ps *ps = ci_get_ps(rps);
54658c2ecf20Sopenharmony_ci	struct ci_pl *pl = &ps->performance_levels[index];
54668c2ecf20Sopenharmony_ci
54678c2ecf20Sopenharmony_ci	ps->performance_level_count = index + 1;
54688c2ecf20Sopenharmony_ci
54698c2ecf20Sopenharmony_ci	pl->sclk = le16_to_cpu(clock_info->ci.usEngineClockLow);
54708c2ecf20Sopenharmony_ci	pl->sclk |= clock_info->ci.ucEngineClockHigh << 16;
54718c2ecf20Sopenharmony_ci	pl->mclk = le16_to_cpu(clock_info->ci.usMemoryClockLow);
54728c2ecf20Sopenharmony_ci	pl->mclk |= clock_info->ci.ucMemoryClockHigh << 16;
54738c2ecf20Sopenharmony_ci
54748c2ecf20Sopenharmony_ci	pl->pcie_gen = r600_get_pcie_gen_support(rdev,
54758c2ecf20Sopenharmony_ci						 pi->sys_pcie_mask,
54768c2ecf20Sopenharmony_ci						 pi->vbios_boot_state.pcie_gen_bootup_value,
54778c2ecf20Sopenharmony_ci						 clock_info->ci.ucPCIEGen);
54788c2ecf20Sopenharmony_ci	pl->pcie_lane = r600_get_pcie_lane_support(rdev,
54798c2ecf20Sopenharmony_ci						   pi->vbios_boot_state.pcie_lane_bootup_value,
54808c2ecf20Sopenharmony_ci						   le16_to_cpu(clock_info->ci.usPCIELane));
54818c2ecf20Sopenharmony_ci
54828c2ecf20Sopenharmony_ci	if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) {
54838c2ecf20Sopenharmony_ci		pi->acpi_pcie_gen = pl->pcie_gen;
54848c2ecf20Sopenharmony_ci	}
54858c2ecf20Sopenharmony_ci
54868c2ecf20Sopenharmony_ci	if (rps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) {
54878c2ecf20Sopenharmony_ci		pi->ulv.supported = true;
54888c2ecf20Sopenharmony_ci		pi->ulv.pl = *pl;
54898c2ecf20Sopenharmony_ci		pi->ulv.cg_ulv_parameter = CISLANDS_CGULVPARAMETER_DFLT;
54908c2ecf20Sopenharmony_ci	}
54918c2ecf20Sopenharmony_ci
54928c2ecf20Sopenharmony_ci	/* patch up boot state */
54938c2ecf20Sopenharmony_ci	if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
54948c2ecf20Sopenharmony_ci		pl->mclk = pi->vbios_boot_state.mclk_bootup_value;
54958c2ecf20Sopenharmony_ci		pl->sclk = pi->vbios_boot_state.sclk_bootup_value;
54968c2ecf20Sopenharmony_ci		pl->pcie_gen = pi->vbios_boot_state.pcie_gen_bootup_value;
54978c2ecf20Sopenharmony_ci		pl->pcie_lane = pi->vbios_boot_state.pcie_lane_bootup_value;
54988c2ecf20Sopenharmony_ci	}
54998c2ecf20Sopenharmony_ci
55008c2ecf20Sopenharmony_ci	switch (rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) {
55018c2ecf20Sopenharmony_ci	case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY:
55028c2ecf20Sopenharmony_ci		pi->use_pcie_powersaving_levels = true;
55038c2ecf20Sopenharmony_ci		if (pi->pcie_gen_powersaving.max < pl->pcie_gen)
55048c2ecf20Sopenharmony_ci			pi->pcie_gen_powersaving.max = pl->pcie_gen;
55058c2ecf20Sopenharmony_ci		if (pi->pcie_gen_powersaving.min > pl->pcie_gen)
55068c2ecf20Sopenharmony_ci			pi->pcie_gen_powersaving.min = pl->pcie_gen;
55078c2ecf20Sopenharmony_ci		if (pi->pcie_lane_powersaving.max < pl->pcie_lane)
55088c2ecf20Sopenharmony_ci			pi->pcie_lane_powersaving.max = pl->pcie_lane;
55098c2ecf20Sopenharmony_ci		if (pi->pcie_lane_powersaving.min > pl->pcie_lane)
55108c2ecf20Sopenharmony_ci			pi->pcie_lane_powersaving.min = pl->pcie_lane;
55118c2ecf20Sopenharmony_ci		break;
55128c2ecf20Sopenharmony_ci	case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE:
55138c2ecf20Sopenharmony_ci		pi->use_pcie_performance_levels = true;
55148c2ecf20Sopenharmony_ci		if (pi->pcie_gen_performance.max < pl->pcie_gen)
55158c2ecf20Sopenharmony_ci			pi->pcie_gen_performance.max = pl->pcie_gen;
55168c2ecf20Sopenharmony_ci		if (pi->pcie_gen_performance.min > pl->pcie_gen)
55178c2ecf20Sopenharmony_ci			pi->pcie_gen_performance.min = pl->pcie_gen;
55188c2ecf20Sopenharmony_ci		if (pi->pcie_lane_performance.max < pl->pcie_lane)
55198c2ecf20Sopenharmony_ci			pi->pcie_lane_performance.max = pl->pcie_lane;
55208c2ecf20Sopenharmony_ci		if (pi->pcie_lane_performance.min > pl->pcie_lane)
55218c2ecf20Sopenharmony_ci			pi->pcie_lane_performance.min = pl->pcie_lane;
55228c2ecf20Sopenharmony_ci		break;
55238c2ecf20Sopenharmony_ci	default:
55248c2ecf20Sopenharmony_ci		break;
55258c2ecf20Sopenharmony_ci	}
55268c2ecf20Sopenharmony_ci}
55278c2ecf20Sopenharmony_ci
55288c2ecf20Sopenharmony_cistatic int ci_parse_power_table(struct radeon_device *rdev)
55298c2ecf20Sopenharmony_ci{
55308c2ecf20Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
55318c2ecf20Sopenharmony_ci	struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
55328c2ecf20Sopenharmony_ci	union pplib_power_state *power_state;
55338c2ecf20Sopenharmony_ci	int i, j, k, non_clock_array_index, clock_array_index;
55348c2ecf20Sopenharmony_ci	union pplib_clock_info *clock_info;
55358c2ecf20Sopenharmony_ci	struct _StateArray *state_array;
55368c2ecf20Sopenharmony_ci	struct _ClockInfoArray *clock_info_array;
55378c2ecf20Sopenharmony_ci	struct _NonClockInfoArray *non_clock_info_array;
55388c2ecf20Sopenharmony_ci	union power_info *power_info;
55398c2ecf20Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
55408c2ecf20Sopenharmony_ci	u16 data_offset;
55418c2ecf20Sopenharmony_ci	u8 frev, crev;
55428c2ecf20Sopenharmony_ci	u8 *power_state_offset;
55438c2ecf20Sopenharmony_ci	struct ci_ps *ps;
55448c2ecf20Sopenharmony_ci	int ret;
55458c2ecf20Sopenharmony_ci
55468c2ecf20Sopenharmony_ci	if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
55478c2ecf20Sopenharmony_ci				   &frev, &crev, &data_offset))
55488c2ecf20Sopenharmony_ci		return -EINVAL;
55498c2ecf20Sopenharmony_ci	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
55508c2ecf20Sopenharmony_ci
55518c2ecf20Sopenharmony_ci	state_array = (struct _StateArray *)
55528c2ecf20Sopenharmony_ci		(mode_info->atom_context->bios + data_offset +
55538c2ecf20Sopenharmony_ci		 le16_to_cpu(power_info->pplib.usStateArrayOffset));
55548c2ecf20Sopenharmony_ci	clock_info_array = (struct _ClockInfoArray *)
55558c2ecf20Sopenharmony_ci		(mode_info->atom_context->bios + data_offset +
55568c2ecf20Sopenharmony_ci		 le16_to_cpu(power_info->pplib.usClockInfoArrayOffset));
55578c2ecf20Sopenharmony_ci	non_clock_info_array = (struct _NonClockInfoArray *)
55588c2ecf20Sopenharmony_ci		(mode_info->atom_context->bios + data_offset +
55598c2ecf20Sopenharmony_ci		 le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
55608c2ecf20Sopenharmony_ci
55618c2ecf20Sopenharmony_ci	rdev->pm.dpm.ps = kcalloc(state_array->ucNumEntries,
55628c2ecf20Sopenharmony_ci				  sizeof(struct radeon_ps),
55638c2ecf20Sopenharmony_ci				  GFP_KERNEL);
55648c2ecf20Sopenharmony_ci	if (!rdev->pm.dpm.ps)
55658c2ecf20Sopenharmony_ci		return -ENOMEM;
55668c2ecf20Sopenharmony_ci	power_state_offset = (u8 *)state_array->states;
55678c2ecf20Sopenharmony_ci	rdev->pm.dpm.num_ps = 0;
55688c2ecf20Sopenharmony_ci	for (i = 0; i < state_array->ucNumEntries; i++) {
55698c2ecf20Sopenharmony_ci		u8 *idx;
55708c2ecf20Sopenharmony_ci		power_state = (union pplib_power_state *)power_state_offset;
55718c2ecf20Sopenharmony_ci		non_clock_array_index = power_state->v2.nonClockInfoIndex;
55728c2ecf20Sopenharmony_ci		non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
55738c2ecf20Sopenharmony_ci			&non_clock_info_array->nonClockInfo[non_clock_array_index];
55748c2ecf20Sopenharmony_ci		if (!rdev->pm.power_state[i].clock_info) {
55758c2ecf20Sopenharmony_ci			ret = -EINVAL;
55768c2ecf20Sopenharmony_ci			goto err_free_ps;
55778c2ecf20Sopenharmony_ci		}
55788c2ecf20Sopenharmony_ci		ps = kzalloc(sizeof(struct ci_ps), GFP_KERNEL);
55798c2ecf20Sopenharmony_ci		if (ps == NULL) {
55808c2ecf20Sopenharmony_ci			ret = -ENOMEM;
55818c2ecf20Sopenharmony_ci			goto err_free_ps;
55828c2ecf20Sopenharmony_ci		}
55838c2ecf20Sopenharmony_ci		rdev->pm.dpm.ps[i].ps_priv = ps;
55848c2ecf20Sopenharmony_ci		ci_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
55858c2ecf20Sopenharmony_ci					      non_clock_info,
55868c2ecf20Sopenharmony_ci					      non_clock_info_array->ucEntrySize);
55878c2ecf20Sopenharmony_ci		k = 0;
55888c2ecf20Sopenharmony_ci		idx = (u8 *)&power_state->v2.clockInfoIndex[0];
55898c2ecf20Sopenharmony_ci		for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) {
55908c2ecf20Sopenharmony_ci			clock_array_index = idx[j];
55918c2ecf20Sopenharmony_ci			if (clock_array_index >= clock_info_array->ucNumEntries)
55928c2ecf20Sopenharmony_ci				continue;
55938c2ecf20Sopenharmony_ci			if (k >= CISLANDS_MAX_HARDWARE_POWERLEVELS)
55948c2ecf20Sopenharmony_ci				break;
55958c2ecf20Sopenharmony_ci			clock_info = (union pplib_clock_info *)
55968c2ecf20Sopenharmony_ci				((u8 *)&clock_info_array->clockInfo[0] +
55978c2ecf20Sopenharmony_ci				 (clock_array_index * clock_info_array->ucEntrySize));
55988c2ecf20Sopenharmony_ci			ci_parse_pplib_clock_info(rdev,
55998c2ecf20Sopenharmony_ci						  &rdev->pm.dpm.ps[i], k,
56008c2ecf20Sopenharmony_ci						  clock_info);
56018c2ecf20Sopenharmony_ci			k++;
56028c2ecf20Sopenharmony_ci		}
56038c2ecf20Sopenharmony_ci		power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
56048c2ecf20Sopenharmony_ci		rdev->pm.dpm.num_ps = i + 1;
56058c2ecf20Sopenharmony_ci	}
56068c2ecf20Sopenharmony_ci
56078c2ecf20Sopenharmony_ci	/* fill in the vce power states */
56088c2ecf20Sopenharmony_ci	for (i = 0; i < RADEON_MAX_VCE_LEVELS; i++) {
56098c2ecf20Sopenharmony_ci		u32 sclk, mclk;
56108c2ecf20Sopenharmony_ci		clock_array_index = rdev->pm.dpm.vce_states[i].clk_idx;
56118c2ecf20Sopenharmony_ci		clock_info = (union pplib_clock_info *)
56128c2ecf20Sopenharmony_ci			&clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
56138c2ecf20Sopenharmony_ci		sclk = le16_to_cpu(clock_info->ci.usEngineClockLow);
56148c2ecf20Sopenharmony_ci		sclk |= clock_info->ci.ucEngineClockHigh << 16;
56158c2ecf20Sopenharmony_ci		mclk = le16_to_cpu(clock_info->ci.usMemoryClockLow);
56168c2ecf20Sopenharmony_ci		mclk |= clock_info->ci.ucMemoryClockHigh << 16;
56178c2ecf20Sopenharmony_ci		rdev->pm.dpm.vce_states[i].sclk = sclk;
56188c2ecf20Sopenharmony_ci		rdev->pm.dpm.vce_states[i].mclk = mclk;
56198c2ecf20Sopenharmony_ci	}
56208c2ecf20Sopenharmony_ci
56218c2ecf20Sopenharmony_ci	return 0;
56228c2ecf20Sopenharmony_ci
56238c2ecf20Sopenharmony_cierr_free_ps:
56248c2ecf20Sopenharmony_ci	for (i = 0; i < rdev->pm.dpm.num_ps; i++)
56258c2ecf20Sopenharmony_ci		kfree(rdev->pm.dpm.ps[i].ps_priv);
56268c2ecf20Sopenharmony_ci	kfree(rdev->pm.dpm.ps);
56278c2ecf20Sopenharmony_ci	return ret;
56288c2ecf20Sopenharmony_ci}
56298c2ecf20Sopenharmony_ci
56308c2ecf20Sopenharmony_cistatic int ci_get_vbios_boot_values(struct radeon_device *rdev,
56318c2ecf20Sopenharmony_ci				    struct ci_vbios_boot_state *boot_state)
56328c2ecf20Sopenharmony_ci{
56338c2ecf20Sopenharmony_ci	struct radeon_mode_info *mode_info = &rdev->mode_info;
56348c2ecf20Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
56358c2ecf20Sopenharmony_ci	ATOM_FIRMWARE_INFO_V2_2 *firmware_info;
56368c2ecf20Sopenharmony_ci	u8 frev, crev;
56378c2ecf20Sopenharmony_ci	u16 data_offset;
56388c2ecf20Sopenharmony_ci
56398c2ecf20Sopenharmony_ci	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
56408c2ecf20Sopenharmony_ci				   &frev, &crev, &data_offset)) {
56418c2ecf20Sopenharmony_ci		firmware_info =
56428c2ecf20Sopenharmony_ci			(ATOM_FIRMWARE_INFO_V2_2 *)(mode_info->atom_context->bios +
56438c2ecf20Sopenharmony_ci						    data_offset);
56448c2ecf20Sopenharmony_ci		boot_state->mvdd_bootup_value = le16_to_cpu(firmware_info->usBootUpMVDDCVoltage);
56458c2ecf20Sopenharmony_ci		boot_state->vddc_bootup_value = le16_to_cpu(firmware_info->usBootUpVDDCVoltage);
56468c2ecf20Sopenharmony_ci		boot_state->vddci_bootup_value = le16_to_cpu(firmware_info->usBootUpVDDCIVoltage);
56478c2ecf20Sopenharmony_ci		boot_state->pcie_gen_bootup_value = ci_get_current_pcie_speed(rdev);
56488c2ecf20Sopenharmony_ci		boot_state->pcie_lane_bootup_value = ci_get_current_pcie_lane_number(rdev);
56498c2ecf20Sopenharmony_ci		boot_state->sclk_bootup_value = le32_to_cpu(firmware_info->ulDefaultEngineClock);
56508c2ecf20Sopenharmony_ci		boot_state->mclk_bootup_value = le32_to_cpu(firmware_info->ulDefaultMemoryClock);
56518c2ecf20Sopenharmony_ci
56528c2ecf20Sopenharmony_ci		return 0;
56538c2ecf20Sopenharmony_ci	}
56548c2ecf20Sopenharmony_ci	return -EINVAL;
56558c2ecf20Sopenharmony_ci}
56568c2ecf20Sopenharmony_ci
56578c2ecf20Sopenharmony_civoid ci_dpm_fini(struct radeon_device *rdev)
56588c2ecf20Sopenharmony_ci{
56598c2ecf20Sopenharmony_ci	int i;
56608c2ecf20Sopenharmony_ci
56618c2ecf20Sopenharmony_ci	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
56628c2ecf20Sopenharmony_ci		kfree(rdev->pm.dpm.ps[i].ps_priv);
56638c2ecf20Sopenharmony_ci	}
56648c2ecf20Sopenharmony_ci	kfree(rdev->pm.dpm.ps);
56658c2ecf20Sopenharmony_ci	kfree(rdev->pm.dpm.priv);
56668c2ecf20Sopenharmony_ci	kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries);
56678c2ecf20Sopenharmony_ci	r600_free_extended_power_table(rdev);
56688c2ecf20Sopenharmony_ci}
56698c2ecf20Sopenharmony_ci
56708c2ecf20Sopenharmony_ciint ci_dpm_init(struct radeon_device *rdev)
56718c2ecf20Sopenharmony_ci{
56728c2ecf20Sopenharmony_ci	int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
56738c2ecf20Sopenharmony_ci	SMU7_Discrete_DpmTable  *dpm_table;
56748c2ecf20Sopenharmony_ci	struct radeon_gpio_rec gpio;
56758c2ecf20Sopenharmony_ci	u16 data_offset, size;
56768c2ecf20Sopenharmony_ci	u8 frev, crev;
56778c2ecf20Sopenharmony_ci	struct ci_power_info *pi;
56788c2ecf20Sopenharmony_ci	enum pci_bus_speed speed_cap = PCI_SPEED_UNKNOWN;
56798c2ecf20Sopenharmony_ci	struct pci_dev *root = rdev->pdev->bus->self;
56808c2ecf20Sopenharmony_ci	int ret;
56818c2ecf20Sopenharmony_ci
56828c2ecf20Sopenharmony_ci	pi = kzalloc(sizeof(struct ci_power_info), GFP_KERNEL);
56838c2ecf20Sopenharmony_ci	if (pi == NULL)
56848c2ecf20Sopenharmony_ci		return -ENOMEM;
56858c2ecf20Sopenharmony_ci	rdev->pm.dpm.priv = pi;
56868c2ecf20Sopenharmony_ci
56878c2ecf20Sopenharmony_ci	if (!pci_is_root_bus(rdev->pdev->bus))
56888c2ecf20Sopenharmony_ci		speed_cap = pcie_get_speed_cap(root);
56898c2ecf20Sopenharmony_ci	if (speed_cap == PCI_SPEED_UNKNOWN) {
56908c2ecf20Sopenharmony_ci		pi->sys_pcie_mask = 0;
56918c2ecf20Sopenharmony_ci	} else {
56928c2ecf20Sopenharmony_ci		if (speed_cap == PCIE_SPEED_8_0GT)
56938c2ecf20Sopenharmony_ci			pi->sys_pcie_mask = RADEON_PCIE_SPEED_25 |
56948c2ecf20Sopenharmony_ci				RADEON_PCIE_SPEED_50 |
56958c2ecf20Sopenharmony_ci				RADEON_PCIE_SPEED_80;
56968c2ecf20Sopenharmony_ci		else if (speed_cap == PCIE_SPEED_5_0GT)
56978c2ecf20Sopenharmony_ci			pi->sys_pcie_mask = RADEON_PCIE_SPEED_25 |
56988c2ecf20Sopenharmony_ci				RADEON_PCIE_SPEED_50;
56998c2ecf20Sopenharmony_ci		else
57008c2ecf20Sopenharmony_ci			pi->sys_pcie_mask = RADEON_PCIE_SPEED_25;
57018c2ecf20Sopenharmony_ci	}
57028c2ecf20Sopenharmony_ci	pi->force_pcie_gen = RADEON_PCIE_GEN_INVALID;
57038c2ecf20Sopenharmony_ci
57048c2ecf20Sopenharmony_ci	pi->pcie_gen_performance.max = RADEON_PCIE_GEN1;
57058c2ecf20Sopenharmony_ci	pi->pcie_gen_performance.min = RADEON_PCIE_GEN3;
57068c2ecf20Sopenharmony_ci	pi->pcie_gen_powersaving.max = RADEON_PCIE_GEN1;
57078c2ecf20Sopenharmony_ci	pi->pcie_gen_powersaving.min = RADEON_PCIE_GEN3;
57088c2ecf20Sopenharmony_ci
57098c2ecf20Sopenharmony_ci	pi->pcie_lane_performance.max = 0;
57108c2ecf20Sopenharmony_ci	pi->pcie_lane_performance.min = 16;
57118c2ecf20Sopenharmony_ci	pi->pcie_lane_powersaving.max = 0;
57128c2ecf20Sopenharmony_ci	pi->pcie_lane_powersaving.min = 16;
57138c2ecf20Sopenharmony_ci
57148c2ecf20Sopenharmony_ci	ret = ci_get_vbios_boot_values(rdev, &pi->vbios_boot_state);
57158c2ecf20Sopenharmony_ci	if (ret) {
57168c2ecf20Sopenharmony_ci		kfree(rdev->pm.dpm.priv);
57178c2ecf20Sopenharmony_ci		return ret;
57188c2ecf20Sopenharmony_ci	}
57198c2ecf20Sopenharmony_ci
57208c2ecf20Sopenharmony_ci	ret = r600_get_platform_caps(rdev);
57218c2ecf20Sopenharmony_ci	if (ret) {
57228c2ecf20Sopenharmony_ci		kfree(rdev->pm.dpm.priv);
57238c2ecf20Sopenharmony_ci		return ret;
57248c2ecf20Sopenharmony_ci	}
57258c2ecf20Sopenharmony_ci
57268c2ecf20Sopenharmony_ci	ret = r600_parse_extended_power_table(rdev);
57278c2ecf20Sopenharmony_ci	if (ret) {
57288c2ecf20Sopenharmony_ci		kfree(rdev->pm.dpm.priv);
57298c2ecf20Sopenharmony_ci		return ret;
57308c2ecf20Sopenharmony_ci	}
57318c2ecf20Sopenharmony_ci
57328c2ecf20Sopenharmony_ci	ret = ci_parse_power_table(rdev);
57338c2ecf20Sopenharmony_ci	if (ret) {
57348c2ecf20Sopenharmony_ci		kfree(rdev->pm.dpm.priv);
57358c2ecf20Sopenharmony_ci		r600_free_extended_power_table(rdev);
57368c2ecf20Sopenharmony_ci		return ret;
57378c2ecf20Sopenharmony_ci	}
57388c2ecf20Sopenharmony_ci
57398c2ecf20Sopenharmony_ci	pi->dll_default_on = false;
57408c2ecf20Sopenharmony_ci	pi->sram_end = SMC_RAM_END;
57418c2ecf20Sopenharmony_ci
57428c2ecf20Sopenharmony_ci	pi->activity_target[0] = CISLAND_TARGETACTIVITY_DFLT;
57438c2ecf20Sopenharmony_ci	pi->activity_target[1] = CISLAND_TARGETACTIVITY_DFLT;
57448c2ecf20Sopenharmony_ci	pi->activity_target[2] = CISLAND_TARGETACTIVITY_DFLT;
57458c2ecf20Sopenharmony_ci	pi->activity_target[3] = CISLAND_TARGETACTIVITY_DFLT;
57468c2ecf20Sopenharmony_ci	pi->activity_target[4] = CISLAND_TARGETACTIVITY_DFLT;
57478c2ecf20Sopenharmony_ci	pi->activity_target[5] = CISLAND_TARGETACTIVITY_DFLT;
57488c2ecf20Sopenharmony_ci	pi->activity_target[6] = CISLAND_TARGETACTIVITY_DFLT;
57498c2ecf20Sopenharmony_ci	pi->activity_target[7] = CISLAND_TARGETACTIVITY_DFLT;
57508c2ecf20Sopenharmony_ci
57518c2ecf20Sopenharmony_ci	pi->mclk_activity_target = CISLAND_MCLK_TARGETACTIVITY_DFLT;
57528c2ecf20Sopenharmony_ci
57538c2ecf20Sopenharmony_ci	pi->sclk_dpm_key_disabled = 0;
57548c2ecf20Sopenharmony_ci	pi->mclk_dpm_key_disabled = 0;
57558c2ecf20Sopenharmony_ci	pi->pcie_dpm_key_disabled = 0;
57568c2ecf20Sopenharmony_ci	pi->thermal_sclk_dpm_enabled = 0;
57578c2ecf20Sopenharmony_ci
57588c2ecf20Sopenharmony_ci	/* mclk dpm is unstable on some R7 260X cards with the old mc ucode */
57598c2ecf20Sopenharmony_ci	if ((rdev->pdev->device == 0x6658) &&
57608c2ecf20Sopenharmony_ci	    (rdev->mc_fw->size == (BONAIRE_MC_UCODE_SIZE * 4))) {
57618c2ecf20Sopenharmony_ci		pi->mclk_dpm_key_disabled = 1;
57628c2ecf20Sopenharmony_ci	}
57638c2ecf20Sopenharmony_ci
57648c2ecf20Sopenharmony_ci	pi->caps_sclk_ds = true;
57658c2ecf20Sopenharmony_ci
57668c2ecf20Sopenharmony_ci	pi->mclk_strobe_mode_threshold = 40000;
57678c2ecf20Sopenharmony_ci	pi->mclk_stutter_mode_threshold = 40000;
57688c2ecf20Sopenharmony_ci	pi->mclk_edc_enable_threshold = 40000;
57698c2ecf20Sopenharmony_ci	pi->mclk_edc_wr_enable_threshold = 40000;
57708c2ecf20Sopenharmony_ci
57718c2ecf20Sopenharmony_ci	ci_initialize_powertune_defaults(rdev);
57728c2ecf20Sopenharmony_ci
57738c2ecf20Sopenharmony_ci	pi->caps_fps = false;
57748c2ecf20Sopenharmony_ci
57758c2ecf20Sopenharmony_ci	pi->caps_sclk_throttle_low_notification = false;
57768c2ecf20Sopenharmony_ci
57778c2ecf20Sopenharmony_ci	pi->caps_uvd_dpm = true;
57788c2ecf20Sopenharmony_ci	pi->caps_vce_dpm = true;
57798c2ecf20Sopenharmony_ci
57808c2ecf20Sopenharmony_ci	ci_get_leakage_voltages(rdev);
57818c2ecf20Sopenharmony_ci	ci_patch_dependency_tables_with_leakage(rdev);
57828c2ecf20Sopenharmony_ci	ci_set_private_data_variables_based_on_pptable(rdev);
57838c2ecf20Sopenharmony_ci
57848c2ecf20Sopenharmony_ci	rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries =
57858c2ecf20Sopenharmony_ci		kcalloc(4,
57868c2ecf20Sopenharmony_ci			sizeof(struct radeon_clock_voltage_dependency_entry),
57878c2ecf20Sopenharmony_ci			GFP_KERNEL);
57888c2ecf20Sopenharmony_ci	if (!rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries) {
57898c2ecf20Sopenharmony_ci		ci_dpm_fini(rdev);
57908c2ecf20Sopenharmony_ci		return -ENOMEM;
57918c2ecf20Sopenharmony_ci	}
57928c2ecf20Sopenharmony_ci	rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.count = 4;
57938c2ecf20Sopenharmony_ci	rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].clk = 0;
57948c2ecf20Sopenharmony_ci	rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].v = 0;
57958c2ecf20Sopenharmony_ci	rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[1].clk = 36000;
57968c2ecf20Sopenharmony_ci	rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[1].v = 720;
57978c2ecf20Sopenharmony_ci	rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[2].clk = 54000;
57988c2ecf20Sopenharmony_ci	rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[2].v = 810;
57998c2ecf20Sopenharmony_ci	rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[3].clk = 72000;
58008c2ecf20Sopenharmony_ci	rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[3].v = 900;
58018c2ecf20Sopenharmony_ci
58028c2ecf20Sopenharmony_ci	rdev->pm.dpm.dyn_state.mclk_sclk_ratio = 4;
58038c2ecf20Sopenharmony_ci	rdev->pm.dpm.dyn_state.sclk_mclk_delta = 15000;
58048c2ecf20Sopenharmony_ci	rdev->pm.dpm.dyn_state.vddc_vddci_delta = 200;
58058c2ecf20Sopenharmony_ci
58068c2ecf20Sopenharmony_ci	rdev->pm.dpm.dyn_state.valid_sclk_values.count = 0;
58078c2ecf20Sopenharmony_ci	rdev->pm.dpm.dyn_state.valid_sclk_values.values = NULL;
58088c2ecf20Sopenharmony_ci	rdev->pm.dpm.dyn_state.valid_mclk_values.count = 0;
58098c2ecf20Sopenharmony_ci	rdev->pm.dpm.dyn_state.valid_mclk_values.values = NULL;
58108c2ecf20Sopenharmony_ci
58118c2ecf20Sopenharmony_ci	if (rdev->family == CHIP_HAWAII) {
58128c2ecf20Sopenharmony_ci		pi->thermal_temp_setting.temperature_low = 94500;
58138c2ecf20Sopenharmony_ci		pi->thermal_temp_setting.temperature_high = 95000;
58148c2ecf20Sopenharmony_ci		pi->thermal_temp_setting.temperature_shutdown = 104000;
58158c2ecf20Sopenharmony_ci	} else {
58168c2ecf20Sopenharmony_ci		pi->thermal_temp_setting.temperature_low = 99500;
58178c2ecf20Sopenharmony_ci		pi->thermal_temp_setting.temperature_high = 100000;
58188c2ecf20Sopenharmony_ci		pi->thermal_temp_setting.temperature_shutdown = 104000;
58198c2ecf20Sopenharmony_ci	}
58208c2ecf20Sopenharmony_ci
58218c2ecf20Sopenharmony_ci	pi->uvd_enabled = false;
58228c2ecf20Sopenharmony_ci
58238c2ecf20Sopenharmony_ci	dpm_table = &pi->smc_state_table;
58248c2ecf20Sopenharmony_ci
58258c2ecf20Sopenharmony_ci	gpio = radeon_atombios_lookup_gpio(rdev, VDDC_VRHOT_GPIO_PINID);
58268c2ecf20Sopenharmony_ci	if (gpio.valid) {
58278c2ecf20Sopenharmony_ci		dpm_table->VRHotGpio = gpio.shift;
58288c2ecf20Sopenharmony_ci		rdev->pm.dpm.platform_caps |= ATOM_PP_PLATFORM_CAP_REGULATOR_HOT;
58298c2ecf20Sopenharmony_ci	} else {
58308c2ecf20Sopenharmony_ci		dpm_table->VRHotGpio = CISLANDS_UNUSED_GPIO_PIN;
58318c2ecf20Sopenharmony_ci		rdev->pm.dpm.platform_caps &= ~ATOM_PP_PLATFORM_CAP_REGULATOR_HOT;
58328c2ecf20Sopenharmony_ci	}
58338c2ecf20Sopenharmony_ci
58348c2ecf20Sopenharmony_ci	gpio = radeon_atombios_lookup_gpio(rdev, PP_AC_DC_SWITCH_GPIO_PINID);
58358c2ecf20Sopenharmony_ci	if (gpio.valid) {
58368c2ecf20Sopenharmony_ci		dpm_table->AcDcGpio = gpio.shift;
58378c2ecf20Sopenharmony_ci		rdev->pm.dpm.platform_caps |= ATOM_PP_PLATFORM_CAP_HARDWAREDC;
58388c2ecf20Sopenharmony_ci	} else {
58398c2ecf20Sopenharmony_ci		dpm_table->AcDcGpio = CISLANDS_UNUSED_GPIO_PIN;
58408c2ecf20Sopenharmony_ci		rdev->pm.dpm.platform_caps &= ~ATOM_PP_PLATFORM_CAP_HARDWAREDC;
58418c2ecf20Sopenharmony_ci	}
58428c2ecf20Sopenharmony_ci
58438c2ecf20Sopenharmony_ci	gpio = radeon_atombios_lookup_gpio(rdev, VDDC_PCC_GPIO_PINID);
58448c2ecf20Sopenharmony_ci	if (gpio.valid) {
58458c2ecf20Sopenharmony_ci		u32 tmp = RREG32_SMC(CNB_PWRMGT_CNTL);
58468c2ecf20Sopenharmony_ci
58478c2ecf20Sopenharmony_ci		switch (gpio.shift) {
58488c2ecf20Sopenharmony_ci		case 0:
58498c2ecf20Sopenharmony_ci			tmp &= ~GNB_SLOW_MODE_MASK;
58508c2ecf20Sopenharmony_ci			tmp |= GNB_SLOW_MODE(1);
58518c2ecf20Sopenharmony_ci			break;
58528c2ecf20Sopenharmony_ci		case 1:
58538c2ecf20Sopenharmony_ci			tmp &= ~GNB_SLOW_MODE_MASK;
58548c2ecf20Sopenharmony_ci			tmp |= GNB_SLOW_MODE(2);
58558c2ecf20Sopenharmony_ci			break;
58568c2ecf20Sopenharmony_ci		case 2:
58578c2ecf20Sopenharmony_ci			tmp |= GNB_SLOW;
58588c2ecf20Sopenharmony_ci			break;
58598c2ecf20Sopenharmony_ci		case 3:
58608c2ecf20Sopenharmony_ci			tmp |= FORCE_NB_PS1;
58618c2ecf20Sopenharmony_ci			break;
58628c2ecf20Sopenharmony_ci		case 4:
58638c2ecf20Sopenharmony_ci			tmp |= DPM_ENABLED;
58648c2ecf20Sopenharmony_ci			break;
58658c2ecf20Sopenharmony_ci		default:
58668c2ecf20Sopenharmony_ci			DRM_DEBUG("Invalid PCC GPIO: %u!\n", gpio.shift);
58678c2ecf20Sopenharmony_ci			break;
58688c2ecf20Sopenharmony_ci		}
58698c2ecf20Sopenharmony_ci		WREG32_SMC(CNB_PWRMGT_CNTL, tmp);
58708c2ecf20Sopenharmony_ci	}
58718c2ecf20Sopenharmony_ci
58728c2ecf20Sopenharmony_ci	pi->voltage_control = CISLANDS_VOLTAGE_CONTROL_NONE;
58738c2ecf20Sopenharmony_ci	pi->vddci_control = CISLANDS_VOLTAGE_CONTROL_NONE;
58748c2ecf20Sopenharmony_ci	pi->mvdd_control = CISLANDS_VOLTAGE_CONTROL_NONE;
58758c2ecf20Sopenharmony_ci	if (radeon_atom_is_voltage_gpio(rdev, VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_GPIO_LUT))
58768c2ecf20Sopenharmony_ci		pi->voltage_control = CISLANDS_VOLTAGE_CONTROL_BY_GPIO;
58778c2ecf20Sopenharmony_ci	else if (radeon_atom_is_voltage_gpio(rdev, VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_SVID2))
58788c2ecf20Sopenharmony_ci		pi->voltage_control = CISLANDS_VOLTAGE_CONTROL_BY_SVID2;
58798c2ecf20Sopenharmony_ci
58808c2ecf20Sopenharmony_ci	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_VDDCI_CONTROL) {
58818c2ecf20Sopenharmony_ci		if (radeon_atom_is_voltage_gpio(rdev, VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT))
58828c2ecf20Sopenharmony_ci			pi->vddci_control = CISLANDS_VOLTAGE_CONTROL_BY_GPIO;
58838c2ecf20Sopenharmony_ci		else if (radeon_atom_is_voltage_gpio(rdev, VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_SVID2))
58848c2ecf20Sopenharmony_ci			pi->vddci_control = CISLANDS_VOLTAGE_CONTROL_BY_SVID2;
58858c2ecf20Sopenharmony_ci		else
58868c2ecf20Sopenharmony_ci			rdev->pm.dpm.platform_caps &= ~ATOM_PP_PLATFORM_CAP_VDDCI_CONTROL;
58878c2ecf20Sopenharmony_ci	}
58888c2ecf20Sopenharmony_ci
58898c2ecf20Sopenharmony_ci	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_MVDDCONTROL) {
58908c2ecf20Sopenharmony_ci		if (radeon_atom_is_voltage_gpio(rdev, VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT))
58918c2ecf20Sopenharmony_ci			pi->mvdd_control = CISLANDS_VOLTAGE_CONTROL_BY_GPIO;
58928c2ecf20Sopenharmony_ci		else if (radeon_atom_is_voltage_gpio(rdev, VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_SVID2))
58938c2ecf20Sopenharmony_ci			pi->mvdd_control = CISLANDS_VOLTAGE_CONTROL_BY_SVID2;
58948c2ecf20Sopenharmony_ci		else
58958c2ecf20Sopenharmony_ci			rdev->pm.dpm.platform_caps &= ~ATOM_PP_PLATFORM_CAP_MVDDCONTROL;
58968c2ecf20Sopenharmony_ci	}
58978c2ecf20Sopenharmony_ci
58988c2ecf20Sopenharmony_ci	pi->vddc_phase_shed_control = true;
58998c2ecf20Sopenharmony_ci
59008c2ecf20Sopenharmony_ci#if defined(CONFIG_ACPI)
59018c2ecf20Sopenharmony_ci	pi->pcie_performance_request =
59028c2ecf20Sopenharmony_ci		radeon_acpi_is_pcie_performance_request_supported(rdev);
59038c2ecf20Sopenharmony_ci#else
59048c2ecf20Sopenharmony_ci	pi->pcie_performance_request = false;
59058c2ecf20Sopenharmony_ci#endif
59068c2ecf20Sopenharmony_ci
59078c2ecf20Sopenharmony_ci	if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
59088c2ecf20Sopenharmony_ci				   &frev, &crev, &data_offset)) {
59098c2ecf20Sopenharmony_ci		pi->caps_sclk_ss_support = true;
59108c2ecf20Sopenharmony_ci		pi->caps_mclk_ss_support = true;
59118c2ecf20Sopenharmony_ci		pi->dynamic_ss = true;
59128c2ecf20Sopenharmony_ci	} else {
59138c2ecf20Sopenharmony_ci		pi->caps_sclk_ss_support = false;
59148c2ecf20Sopenharmony_ci		pi->caps_mclk_ss_support = false;
59158c2ecf20Sopenharmony_ci		pi->dynamic_ss = true;
59168c2ecf20Sopenharmony_ci	}
59178c2ecf20Sopenharmony_ci
59188c2ecf20Sopenharmony_ci	if (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE)
59198c2ecf20Sopenharmony_ci		pi->thermal_protection = true;
59208c2ecf20Sopenharmony_ci	else
59218c2ecf20Sopenharmony_ci		pi->thermal_protection = false;
59228c2ecf20Sopenharmony_ci
59238c2ecf20Sopenharmony_ci	pi->caps_dynamic_ac_timing = true;
59248c2ecf20Sopenharmony_ci
59258c2ecf20Sopenharmony_ci	pi->uvd_power_gated = false;
59268c2ecf20Sopenharmony_ci
59278c2ecf20Sopenharmony_ci	/* make sure dc limits are valid */
59288c2ecf20Sopenharmony_ci	if ((rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.sclk == 0) ||
59298c2ecf20Sopenharmony_ci	    (rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.mclk == 0))
59308c2ecf20Sopenharmony_ci		rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc =
59318c2ecf20Sopenharmony_ci			rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
59328c2ecf20Sopenharmony_ci
59338c2ecf20Sopenharmony_ci	pi->fan_ctrl_is_in_default_mode = true;
59348c2ecf20Sopenharmony_ci
59358c2ecf20Sopenharmony_ci	return 0;
59368c2ecf20Sopenharmony_ci}
59378c2ecf20Sopenharmony_ci
59388c2ecf20Sopenharmony_civoid ci_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
59398c2ecf20Sopenharmony_ci						    struct seq_file *m)
59408c2ecf20Sopenharmony_ci{
59418c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
59428c2ecf20Sopenharmony_ci	struct radeon_ps *rps = &pi->current_rps;
59438c2ecf20Sopenharmony_ci	u32 sclk = ci_get_average_sclk_freq(rdev);
59448c2ecf20Sopenharmony_ci	u32 mclk = ci_get_average_mclk_freq(rdev);
59458c2ecf20Sopenharmony_ci
59468c2ecf20Sopenharmony_ci	seq_printf(m, "uvd    %sabled\n", pi->uvd_enabled ? "en" : "dis");
59478c2ecf20Sopenharmony_ci	seq_printf(m, "vce    %sabled\n", rps->vce_active ? "en" : "dis");
59488c2ecf20Sopenharmony_ci	seq_printf(m, "power level avg    sclk: %u mclk: %u\n",
59498c2ecf20Sopenharmony_ci		   sclk, mclk);
59508c2ecf20Sopenharmony_ci}
59518c2ecf20Sopenharmony_ci
59528c2ecf20Sopenharmony_civoid ci_dpm_print_power_state(struct radeon_device *rdev,
59538c2ecf20Sopenharmony_ci			      struct radeon_ps *rps)
59548c2ecf20Sopenharmony_ci{
59558c2ecf20Sopenharmony_ci	struct ci_ps *ps = ci_get_ps(rps);
59568c2ecf20Sopenharmony_ci	struct ci_pl *pl;
59578c2ecf20Sopenharmony_ci	int i;
59588c2ecf20Sopenharmony_ci
59598c2ecf20Sopenharmony_ci	r600_dpm_print_class_info(rps->class, rps->class2);
59608c2ecf20Sopenharmony_ci	r600_dpm_print_cap_info(rps->caps);
59618c2ecf20Sopenharmony_ci	printk("\tuvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
59628c2ecf20Sopenharmony_ci	for (i = 0; i < ps->performance_level_count; i++) {
59638c2ecf20Sopenharmony_ci		pl = &ps->performance_levels[i];
59648c2ecf20Sopenharmony_ci		printk("\t\tpower level %d    sclk: %u mclk: %u pcie gen: %u pcie lanes: %u\n",
59658c2ecf20Sopenharmony_ci		       i, pl->sclk, pl->mclk, pl->pcie_gen + 1, pl->pcie_lane);
59668c2ecf20Sopenharmony_ci	}
59678c2ecf20Sopenharmony_ci	r600_dpm_print_ps_status(rdev, rps);
59688c2ecf20Sopenharmony_ci}
59698c2ecf20Sopenharmony_ci
59708c2ecf20Sopenharmony_ciu32 ci_dpm_get_current_sclk(struct radeon_device *rdev)
59718c2ecf20Sopenharmony_ci{
59728c2ecf20Sopenharmony_ci	u32 sclk = ci_get_average_sclk_freq(rdev);
59738c2ecf20Sopenharmony_ci
59748c2ecf20Sopenharmony_ci	return sclk;
59758c2ecf20Sopenharmony_ci}
59768c2ecf20Sopenharmony_ci
59778c2ecf20Sopenharmony_ciu32 ci_dpm_get_current_mclk(struct radeon_device *rdev)
59788c2ecf20Sopenharmony_ci{
59798c2ecf20Sopenharmony_ci	u32 mclk = ci_get_average_mclk_freq(rdev);
59808c2ecf20Sopenharmony_ci
59818c2ecf20Sopenharmony_ci	return mclk;
59828c2ecf20Sopenharmony_ci}
59838c2ecf20Sopenharmony_ci
59848c2ecf20Sopenharmony_ciu32 ci_dpm_get_sclk(struct radeon_device *rdev, bool low)
59858c2ecf20Sopenharmony_ci{
59868c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
59878c2ecf20Sopenharmony_ci	struct ci_ps *requested_state = ci_get_ps(&pi->requested_rps);
59888c2ecf20Sopenharmony_ci
59898c2ecf20Sopenharmony_ci	if (low)
59908c2ecf20Sopenharmony_ci		return requested_state->performance_levels[0].sclk;
59918c2ecf20Sopenharmony_ci	else
59928c2ecf20Sopenharmony_ci		return requested_state->performance_levels[requested_state->performance_level_count - 1].sclk;
59938c2ecf20Sopenharmony_ci}
59948c2ecf20Sopenharmony_ci
59958c2ecf20Sopenharmony_ciu32 ci_dpm_get_mclk(struct radeon_device *rdev, bool low)
59968c2ecf20Sopenharmony_ci{
59978c2ecf20Sopenharmony_ci	struct ci_power_info *pi = ci_get_pi(rdev);
59988c2ecf20Sopenharmony_ci	struct ci_ps *requested_state = ci_get_ps(&pi->requested_rps);
59998c2ecf20Sopenharmony_ci
60008c2ecf20Sopenharmony_ci	if (low)
60018c2ecf20Sopenharmony_ci		return requested_state->performance_levels[0].mclk;
60028c2ecf20Sopenharmony_ci	else
60038c2ecf20Sopenharmony_ci		return requested_state->performance_levels[requested_state->performance_level_count - 1].mclk;
60048c2ecf20Sopenharmony_ci}
6005