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