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