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, ÷rs); 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, ÷rs); 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, ÷rs); 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, ÷rs); 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, ÷rs); 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, ÷rs); 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, ÷rs); 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