141a524abSAlex Deucher /* 241a524abSAlex Deucher * Copyright 2013 Advanced Micro Devices, Inc. 341a524abSAlex Deucher * 441a524abSAlex Deucher * Permission is hereby granted, free of charge, to any person obtaining a 541a524abSAlex Deucher * copy of this software and associated documentation files (the "Software"), 641a524abSAlex Deucher * to deal in the Software without restriction, including without limitation 741a524abSAlex Deucher * the rights to use, copy, modify, merge, publish, distribute, sublicense, 841a524abSAlex Deucher * and/or sell copies of the Software, and to permit persons to whom the 941a524abSAlex Deucher * Software is furnished to do so, subject to the following conditions: 1041a524abSAlex Deucher * 1141a524abSAlex Deucher * The above copyright notice and this permission notice shall be included in 1241a524abSAlex Deucher * all copies or substantial portions of the Software. 1341a524abSAlex Deucher * 1441a524abSAlex Deucher * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1541a524abSAlex Deucher * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1641a524abSAlex Deucher * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1741a524abSAlex Deucher * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 1841a524abSAlex Deucher * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 1941a524abSAlex Deucher * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2041a524abSAlex Deucher * OTHER DEALINGS IN THE SOFTWARE. 2141a524abSAlex Deucher * 2241a524abSAlex Deucher */ 2341a524abSAlex Deucher 2441a524abSAlex Deucher #include "drmP.h" 2541a524abSAlex Deucher #include "radeon.h" 2641a524abSAlex Deucher #include "cikd.h" 2741a524abSAlex Deucher #include "r600_dpm.h" 2841a524abSAlex Deucher #include "kv_dpm.h" 29e409b128SChristian König #include "radeon_asic.h" 30ae3e40e8SAlex Deucher #include <linux/seq_file.h> 3141a524abSAlex Deucher 3241a524abSAlex Deucher #define KV_MAX_DEEPSLEEP_DIVIDER_ID 5 3341a524abSAlex Deucher #define KV_MINIMUM_ENGINE_CLOCK 800 3441a524abSAlex Deucher #define SMC_RAM_END 0x40000 3541a524abSAlex Deucher 3639da0384SAlex Deucher static int kv_enable_nb_dpm(struct radeon_device *rdev, 3739da0384SAlex Deucher bool enable); 3841a524abSAlex Deucher static void kv_init_graphics_levels(struct radeon_device *rdev); 3941a524abSAlex Deucher static int kv_calculate_ds_divider(struct radeon_device *rdev); 4041a524abSAlex Deucher static int kv_calculate_nbps_level_settings(struct radeon_device *rdev); 4141a524abSAlex Deucher static int kv_calculate_dpm_settings(struct radeon_device *rdev); 4241a524abSAlex Deucher static void kv_enable_new_levels(struct radeon_device *rdev); 4341a524abSAlex Deucher static void kv_program_nbps_index_settings(struct radeon_device *rdev, 4441a524abSAlex Deucher struct radeon_ps *new_rps); 45136de91eSAlex Deucher static int kv_set_enabled_level(struct radeon_device *rdev, u32 level); 4641a524abSAlex Deucher static int kv_set_enabled_levels(struct radeon_device *rdev); 472b4c8022SAlex Deucher static int kv_force_dpm_highest(struct radeon_device *rdev); 4841a524abSAlex Deucher static int kv_force_dpm_lowest(struct radeon_device *rdev); 4941a524abSAlex Deucher static void kv_apply_state_adjust_rules(struct radeon_device *rdev, 5041a524abSAlex Deucher struct radeon_ps *new_rps, 5141a524abSAlex Deucher struct radeon_ps *old_rps); 5241a524abSAlex Deucher static int kv_set_thermal_temperature_range(struct radeon_device *rdev, 5341a524abSAlex Deucher int min_temp, int max_temp); 5441a524abSAlex Deucher static int kv_init_fps_limits(struct radeon_device *rdev); 5541a524abSAlex Deucher 5677df508aSAlex Deucher void kv_dpm_powergate_uvd(struct radeon_device *rdev, bool gate); 5741a524abSAlex Deucher static void kv_dpm_powergate_vce(struct radeon_device *rdev, bool gate); 5841a524abSAlex Deucher static void kv_dpm_powergate_samu(struct radeon_device *rdev, bool gate); 5941a524abSAlex Deucher static void kv_dpm_powergate_acp(struct radeon_device *rdev, bool gate); 6041a524abSAlex Deucher 6141a524abSAlex Deucher extern void cik_enter_rlc_safe_mode(struct radeon_device *rdev); 6241a524abSAlex Deucher extern void cik_exit_rlc_safe_mode(struct radeon_device *rdev); 6341a524abSAlex Deucher extern void cik_update_cg(struct radeon_device *rdev, 6441a524abSAlex Deucher u32 block, bool enable); 6541a524abSAlex Deucher 6641a524abSAlex Deucher static const struct kv_lcac_config_values sx_local_cac_cfg_kv[] = 6741a524abSAlex Deucher { 6841a524abSAlex Deucher { 0, 4, 1 }, 6941a524abSAlex Deucher { 1, 4, 1 }, 7041a524abSAlex Deucher { 2, 5, 1 }, 7141a524abSAlex Deucher { 3, 4, 2 }, 7241a524abSAlex Deucher { 4, 1, 1 }, 7341a524abSAlex Deucher { 5, 5, 2 }, 7441a524abSAlex Deucher { 6, 6, 1 }, 7541a524abSAlex Deucher { 7, 9, 2 }, 7641a524abSAlex Deucher { 0xffffffff } 7741a524abSAlex Deucher }; 7841a524abSAlex Deucher 7941a524abSAlex Deucher static const struct kv_lcac_config_values mc0_local_cac_cfg_kv[] = 8041a524abSAlex Deucher { 8141a524abSAlex Deucher { 0, 4, 1 }, 8241a524abSAlex Deucher { 0xffffffff } 8341a524abSAlex Deucher }; 8441a524abSAlex Deucher 8541a524abSAlex Deucher static const struct kv_lcac_config_values mc1_local_cac_cfg_kv[] = 8641a524abSAlex Deucher { 8741a524abSAlex Deucher { 0, 4, 1 }, 8841a524abSAlex Deucher { 0xffffffff } 8941a524abSAlex Deucher }; 9041a524abSAlex Deucher 9141a524abSAlex Deucher static const struct kv_lcac_config_values mc2_local_cac_cfg_kv[] = 9241a524abSAlex Deucher { 9341a524abSAlex Deucher { 0, 4, 1 }, 9441a524abSAlex Deucher { 0xffffffff } 9541a524abSAlex Deucher }; 9641a524abSAlex Deucher 9741a524abSAlex Deucher static const struct kv_lcac_config_values mc3_local_cac_cfg_kv[] = 9841a524abSAlex Deucher { 9941a524abSAlex Deucher { 0, 4, 1 }, 10041a524abSAlex Deucher { 0xffffffff } 10141a524abSAlex Deucher }; 10241a524abSAlex Deucher 10341a524abSAlex Deucher static const struct kv_lcac_config_values cpl_local_cac_cfg_kv[] = 10441a524abSAlex Deucher { 10541a524abSAlex Deucher { 0, 4, 1 }, 10641a524abSAlex Deucher { 1, 4, 1 }, 10741a524abSAlex Deucher { 2, 5, 1 }, 10841a524abSAlex Deucher { 3, 4, 1 }, 10941a524abSAlex Deucher { 4, 1, 1 }, 11041a524abSAlex Deucher { 5, 5, 1 }, 11141a524abSAlex Deucher { 6, 6, 1 }, 11241a524abSAlex Deucher { 7, 9, 1 }, 11341a524abSAlex Deucher { 8, 4, 1 }, 11441a524abSAlex Deucher { 9, 2, 1 }, 11541a524abSAlex Deucher { 10, 3, 1 }, 11641a524abSAlex Deucher { 11, 6, 1 }, 11741a524abSAlex Deucher { 12, 8, 2 }, 11841a524abSAlex Deucher { 13, 1, 1 }, 11941a524abSAlex Deucher { 14, 2, 1 }, 12041a524abSAlex Deucher { 15, 3, 1 }, 12141a524abSAlex Deucher { 16, 1, 1 }, 12241a524abSAlex Deucher { 17, 4, 1 }, 12341a524abSAlex Deucher { 18, 3, 1 }, 12441a524abSAlex Deucher { 19, 1, 1 }, 12541a524abSAlex Deucher { 20, 8, 1 }, 12641a524abSAlex Deucher { 21, 5, 1 }, 12741a524abSAlex Deucher { 22, 1, 1 }, 12841a524abSAlex Deucher { 23, 1, 1 }, 12941a524abSAlex Deucher { 24, 4, 1 }, 13041a524abSAlex Deucher { 27, 6, 1 }, 13141a524abSAlex Deucher { 28, 1, 1 }, 13241a524abSAlex Deucher { 0xffffffff } 13341a524abSAlex Deucher }; 13441a524abSAlex Deucher 13541a524abSAlex Deucher static const struct kv_lcac_config_reg sx0_cac_config_reg[] = 13641a524abSAlex Deucher { 13741a524abSAlex Deucher { 0xc0400d00, 0x003e0000, 17, 0x3fc00000, 22, 0x0001fffe, 1, 0x00000001, 0 } 13841a524abSAlex Deucher }; 13941a524abSAlex Deucher 14041a524abSAlex Deucher static const struct kv_lcac_config_reg mc0_cac_config_reg[] = 14141a524abSAlex Deucher { 14241a524abSAlex Deucher { 0xc0400d30, 0x003e0000, 17, 0x3fc00000, 22, 0x0001fffe, 1, 0x00000001, 0 } 14341a524abSAlex Deucher }; 14441a524abSAlex Deucher 14541a524abSAlex Deucher static const struct kv_lcac_config_reg mc1_cac_config_reg[] = 14641a524abSAlex Deucher { 14741a524abSAlex Deucher { 0xc0400d3c, 0x003e0000, 17, 0x3fc00000, 22, 0x0001fffe, 1, 0x00000001, 0 } 14841a524abSAlex Deucher }; 14941a524abSAlex Deucher 15041a524abSAlex Deucher static const struct kv_lcac_config_reg mc2_cac_config_reg[] = 15141a524abSAlex Deucher { 15241a524abSAlex Deucher { 0xc0400d48, 0x003e0000, 17, 0x3fc00000, 22, 0x0001fffe, 1, 0x00000001, 0 } 15341a524abSAlex Deucher }; 15441a524abSAlex Deucher 15541a524abSAlex Deucher static const struct kv_lcac_config_reg mc3_cac_config_reg[] = 15641a524abSAlex Deucher { 15741a524abSAlex Deucher { 0xc0400d54, 0x003e0000, 17, 0x3fc00000, 22, 0x0001fffe, 1, 0x00000001, 0 } 15841a524abSAlex Deucher }; 15941a524abSAlex Deucher 16041a524abSAlex Deucher static const struct kv_lcac_config_reg cpl_cac_config_reg[] = 16141a524abSAlex Deucher { 16241a524abSAlex Deucher { 0xc0400d80, 0x003e0000, 17, 0x3fc00000, 22, 0x0001fffe, 1, 0x00000001, 0 } 16341a524abSAlex Deucher }; 16441a524abSAlex Deucher 16541a524abSAlex Deucher static const struct kv_pt_config_reg didt_config_kv[] = 16641a524abSAlex Deucher { 16741a524abSAlex Deucher { 0x10, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 16841a524abSAlex Deucher { 0x10, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, 16941a524abSAlex Deucher { 0x10, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, 17041a524abSAlex Deucher { 0x10, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, 17141a524abSAlex Deucher { 0x11, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 17241a524abSAlex Deucher { 0x11, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, 17341a524abSAlex Deucher { 0x11, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, 17441a524abSAlex Deucher { 0x11, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, 17541a524abSAlex Deucher { 0x12, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 17641a524abSAlex Deucher { 0x12, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, 17741a524abSAlex Deucher { 0x12, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, 17841a524abSAlex Deucher { 0x12, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, 17941a524abSAlex Deucher { 0x2, 0x00003fff, 0, 0x4, KV_CONFIGREG_DIDT_IND }, 18041a524abSAlex Deucher { 0x2, 0x03ff0000, 16, 0x80, KV_CONFIGREG_DIDT_IND }, 18141a524abSAlex Deucher { 0x2, 0x78000000, 27, 0x3, KV_CONFIGREG_DIDT_IND }, 18241a524abSAlex Deucher { 0x1, 0x0000ffff, 0, 0x3FFF, KV_CONFIGREG_DIDT_IND }, 18341a524abSAlex Deucher { 0x1, 0xffff0000, 16, 0x3FFF, KV_CONFIGREG_DIDT_IND }, 18441a524abSAlex Deucher { 0x0, 0x00000001, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 18541a524abSAlex Deucher { 0x30, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 18641a524abSAlex Deucher { 0x30, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, 18741a524abSAlex Deucher { 0x30, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, 18841a524abSAlex Deucher { 0x30, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, 18941a524abSAlex Deucher { 0x31, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 19041a524abSAlex Deucher { 0x31, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, 19141a524abSAlex Deucher { 0x31, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, 19241a524abSAlex Deucher { 0x31, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, 19341a524abSAlex Deucher { 0x32, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 19441a524abSAlex Deucher { 0x32, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, 19541a524abSAlex Deucher { 0x32, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, 19641a524abSAlex Deucher { 0x32, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, 19741a524abSAlex Deucher { 0x22, 0x00003fff, 0, 0x4, KV_CONFIGREG_DIDT_IND }, 19841a524abSAlex Deucher { 0x22, 0x03ff0000, 16, 0x80, KV_CONFIGREG_DIDT_IND }, 19941a524abSAlex Deucher { 0x22, 0x78000000, 27, 0x3, KV_CONFIGREG_DIDT_IND }, 20041a524abSAlex Deucher { 0x21, 0x0000ffff, 0, 0x3FFF, KV_CONFIGREG_DIDT_IND }, 20141a524abSAlex Deucher { 0x21, 0xffff0000, 16, 0x3FFF, KV_CONFIGREG_DIDT_IND }, 20241a524abSAlex Deucher { 0x20, 0x00000001, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 20341a524abSAlex Deucher { 0x50, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 20441a524abSAlex Deucher { 0x50, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, 20541a524abSAlex Deucher { 0x50, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, 20641a524abSAlex Deucher { 0x50, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, 20741a524abSAlex Deucher { 0x51, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 20841a524abSAlex Deucher { 0x51, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, 20941a524abSAlex Deucher { 0x51, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, 21041a524abSAlex Deucher { 0x51, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, 21141a524abSAlex Deucher { 0x52, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 21241a524abSAlex Deucher { 0x52, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, 21341a524abSAlex Deucher { 0x52, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, 21441a524abSAlex Deucher { 0x52, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, 21541a524abSAlex Deucher { 0x42, 0x00003fff, 0, 0x4, KV_CONFIGREG_DIDT_IND }, 21641a524abSAlex Deucher { 0x42, 0x03ff0000, 16, 0x80, KV_CONFIGREG_DIDT_IND }, 21741a524abSAlex Deucher { 0x42, 0x78000000, 27, 0x3, KV_CONFIGREG_DIDT_IND }, 21841a524abSAlex Deucher { 0x41, 0x0000ffff, 0, 0x3FFF, KV_CONFIGREG_DIDT_IND }, 21941a524abSAlex Deucher { 0x41, 0xffff0000, 16, 0x3FFF, KV_CONFIGREG_DIDT_IND }, 22041a524abSAlex Deucher { 0x40, 0x00000001, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 22141a524abSAlex Deucher { 0x70, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 22241a524abSAlex Deucher { 0x70, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, 22341a524abSAlex Deucher { 0x70, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, 22441a524abSAlex Deucher { 0x70, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, 22541a524abSAlex Deucher { 0x71, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 22641a524abSAlex Deucher { 0x71, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, 22741a524abSAlex Deucher { 0x71, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, 22841a524abSAlex Deucher { 0x71, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, 22941a524abSAlex Deucher { 0x72, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 23041a524abSAlex Deucher { 0x72, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, 23141a524abSAlex Deucher { 0x72, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, 23241a524abSAlex Deucher { 0x72, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, 23341a524abSAlex Deucher { 0x62, 0x00003fff, 0, 0x4, KV_CONFIGREG_DIDT_IND }, 23441a524abSAlex Deucher { 0x62, 0x03ff0000, 16, 0x80, KV_CONFIGREG_DIDT_IND }, 23541a524abSAlex Deucher { 0x62, 0x78000000, 27, 0x3, KV_CONFIGREG_DIDT_IND }, 23641a524abSAlex Deucher { 0x61, 0x0000ffff, 0, 0x3FFF, KV_CONFIGREG_DIDT_IND }, 23741a524abSAlex Deucher { 0x61, 0xffff0000, 16, 0x3FFF, KV_CONFIGREG_DIDT_IND }, 23841a524abSAlex Deucher { 0x60, 0x00000001, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 23941a524abSAlex Deucher { 0xFFFFFFFF } 24041a524abSAlex Deucher }; 24141a524abSAlex Deucher 24241a524abSAlex Deucher static struct kv_ps *kv_get_ps(struct radeon_ps *rps) 24341a524abSAlex Deucher { 24441a524abSAlex Deucher struct kv_ps *ps = rps->ps_priv; 24541a524abSAlex Deucher 24641a524abSAlex Deucher return ps; 24741a524abSAlex Deucher } 24841a524abSAlex Deucher 24941a524abSAlex Deucher static struct kv_power_info *kv_get_pi(struct radeon_device *rdev) 25041a524abSAlex Deucher { 25141a524abSAlex Deucher struct kv_power_info *pi = rdev->pm.dpm.priv; 25241a524abSAlex Deucher 25341a524abSAlex Deucher return pi; 25441a524abSAlex Deucher } 25541a524abSAlex Deucher 25641a524abSAlex Deucher #if 0 25741a524abSAlex Deucher static void kv_program_local_cac_table(struct radeon_device *rdev, 25841a524abSAlex Deucher const struct kv_lcac_config_values *local_cac_table, 25941a524abSAlex Deucher const struct kv_lcac_config_reg *local_cac_reg) 26041a524abSAlex Deucher { 26141a524abSAlex Deucher u32 i, count, data; 26241a524abSAlex Deucher const struct kv_lcac_config_values *values = local_cac_table; 26341a524abSAlex Deucher 26441a524abSAlex Deucher while (values->block_id != 0xffffffff) { 26541a524abSAlex Deucher count = values->signal_id; 26641a524abSAlex Deucher for (i = 0; i < count; i++) { 26741a524abSAlex Deucher data = ((values->block_id << local_cac_reg->block_shift) & 26841a524abSAlex Deucher local_cac_reg->block_mask); 26941a524abSAlex Deucher data |= ((i << local_cac_reg->signal_shift) & 27041a524abSAlex Deucher local_cac_reg->signal_mask); 27141a524abSAlex Deucher data |= ((values->t << local_cac_reg->t_shift) & 27241a524abSAlex Deucher local_cac_reg->t_mask); 27341a524abSAlex Deucher data |= ((1 << local_cac_reg->enable_shift) & 27441a524abSAlex Deucher local_cac_reg->enable_mask); 27541a524abSAlex Deucher WREG32_SMC(local_cac_reg->cntl, data); 27641a524abSAlex Deucher } 27741a524abSAlex Deucher values++; 27841a524abSAlex Deucher } 27941a524abSAlex Deucher } 28041a524abSAlex Deucher #endif 28141a524abSAlex Deucher 28241a524abSAlex Deucher static int kv_program_pt_config_registers(struct radeon_device *rdev, 28341a524abSAlex Deucher const struct kv_pt_config_reg *cac_config_regs) 28441a524abSAlex Deucher { 28541a524abSAlex Deucher const struct kv_pt_config_reg *config_regs = cac_config_regs; 28641a524abSAlex Deucher u32 data; 28741a524abSAlex Deucher u32 cache = 0; 28841a524abSAlex Deucher 28941a524abSAlex Deucher if (config_regs == NULL) 29041a524abSAlex Deucher return -EINVAL; 29141a524abSAlex Deucher 29241a524abSAlex Deucher while (config_regs->offset != 0xFFFFFFFF) { 29341a524abSAlex Deucher if (config_regs->type == KV_CONFIGREG_CACHE) { 29441a524abSAlex Deucher cache |= ((config_regs->value << config_regs->shift) & config_regs->mask); 29541a524abSAlex Deucher } else { 29641a524abSAlex Deucher switch (config_regs->type) { 29741a524abSAlex Deucher case KV_CONFIGREG_SMC_IND: 29841a524abSAlex Deucher data = RREG32_SMC(config_regs->offset); 29941a524abSAlex Deucher break; 30041a524abSAlex Deucher case KV_CONFIGREG_DIDT_IND: 30141a524abSAlex Deucher data = RREG32_DIDT(config_regs->offset); 30241a524abSAlex Deucher break; 30341a524abSAlex Deucher default: 30441a524abSAlex Deucher data = RREG32(config_regs->offset << 2); 30541a524abSAlex Deucher break; 30641a524abSAlex Deucher } 30741a524abSAlex Deucher 30841a524abSAlex Deucher data &= ~config_regs->mask; 30941a524abSAlex Deucher data |= ((config_regs->value << config_regs->shift) & config_regs->mask); 31041a524abSAlex Deucher data |= cache; 31141a524abSAlex Deucher cache = 0; 31241a524abSAlex Deucher 31341a524abSAlex Deucher switch (config_regs->type) { 31441a524abSAlex Deucher case KV_CONFIGREG_SMC_IND: 31541a524abSAlex Deucher WREG32_SMC(config_regs->offset, data); 31641a524abSAlex Deucher break; 31741a524abSAlex Deucher case KV_CONFIGREG_DIDT_IND: 31841a524abSAlex Deucher WREG32_DIDT(config_regs->offset, data); 31941a524abSAlex Deucher break; 32041a524abSAlex Deucher default: 32141a524abSAlex Deucher WREG32(config_regs->offset << 2, data); 32241a524abSAlex Deucher break; 32341a524abSAlex Deucher } 32441a524abSAlex Deucher } 32541a524abSAlex Deucher config_regs++; 32641a524abSAlex Deucher } 32741a524abSAlex Deucher 32841a524abSAlex Deucher return 0; 32941a524abSAlex Deucher } 33041a524abSAlex Deucher 33141a524abSAlex Deucher static void kv_do_enable_didt(struct radeon_device *rdev, bool enable) 33241a524abSAlex Deucher { 33341a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 33441a524abSAlex Deucher u32 data; 33541a524abSAlex Deucher 33641a524abSAlex Deucher if (pi->caps_sq_ramping) { 33741a524abSAlex Deucher data = RREG32_DIDT(DIDT_SQ_CTRL0); 33841a524abSAlex Deucher if (enable) 33941a524abSAlex Deucher data |= DIDT_CTRL_EN; 34041a524abSAlex Deucher else 34141a524abSAlex Deucher data &= ~DIDT_CTRL_EN; 34241a524abSAlex Deucher WREG32_DIDT(DIDT_SQ_CTRL0, data); 34341a524abSAlex Deucher } 34441a524abSAlex Deucher 34541a524abSAlex Deucher if (pi->caps_db_ramping) { 34641a524abSAlex Deucher data = RREG32_DIDT(DIDT_DB_CTRL0); 34741a524abSAlex Deucher if (enable) 34841a524abSAlex Deucher data |= DIDT_CTRL_EN; 34941a524abSAlex Deucher else 35041a524abSAlex Deucher data &= ~DIDT_CTRL_EN; 35141a524abSAlex Deucher WREG32_DIDT(DIDT_DB_CTRL0, data); 35241a524abSAlex Deucher } 35341a524abSAlex Deucher 35441a524abSAlex Deucher if (pi->caps_td_ramping) { 35541a524abSAlex Deucher data = RREG32_DIDT(DIDT_TD_CTRL0); 35641a524abSAlex Deucher if (enable) 35741a524abSAlex Deucher data |= DIDT_CTRL_EN; 35841a524abSAlex Deucher else 35941a524abSAlex Deucher data &= ~DIDT_CTRL_EN; 36041a524abSAlex Deucher WREG32_DIDT(DIDT_TD_CTRL0, data); 36141a524abSAlex Deucher } 36241a524abSAlex Deucher 36341a524abSAlex Deucher if (pi->caps_tcp_ramping) { 36441a524abSAlex Deucher data = RREG32_DIDT(DIDT_TCP_CTRL0); 36541a524abSAlex Deucher if (enable) 36641a524abSAlex Deucher data |= DIDT_CTRL_EN; 36741a524abSAlex Deucher else 36841a524abSAlex Deucher data &= ~DIDT_CTRL_EN; 36941a524abSAlex Deucher WREG32_DIDT(DIDT_TCP_CTRL0, data); 37041a524abSAlex Deucher } 37141a524abSAlex Deucher } 37241a524abSAlex Deucher 37341a524abSAlex Deucher static int kv_enable_didt(struct radeon_device *rdev, bool enable) 37441a524abSAlex Deucher { 37541a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 37641a524abSAlex Deucher int ret; 37741a524abSAlex Deucher 37841a524abSAlex Deucher if (pi->caps_sq_ramping || 37941a524abSAlex Deucher pi->caps_db_ramping || 38041a524abSAlex Deucher pi->caps_td_ramping || 38141a524abSAlex Deucher pi->caps_tcp_ramping) { 38241a524abSAlex Deucher cik_enter_rlc_safe_mode(rdev); 38341a524abSAlex Deucher 38441a524abSAlex Deucher if (enable) { 38541a524abSAlex Deucher ret = kv_program_pt_config_registers(rdev, didt_config_kv); 38641a524abSAlex Deucher if (ret) { 38741a524abSAlex Deucher cik_exit_rlc_safe_mode(rdev); 38841a524abSAlex Deucher return ret; 38941a524abSAlex Deucher } 39041a524abSAlex Deucher } 39141a524abSAlex Deucher 39241a524abSAlex Deucher kv_do_enable_didt(rdev, enable); 39341a524abSAlex Deucher 39441a524abSAlex Deucher cik_exit_rlc_safe_mode(rdev); 39541a524abSAlex Deucher } 39641a524abSAlex Deucher 39741a524abSAlex Deucher return 0; 39841a524abSAlex Deucher } 39941a524abSAlex Deucher 40041a524abSAlex Deucher #if 0 40141a524abSAlex Deucher static void kv_initialize_hardware_cac_manager(struct radeon_device *rdev) 40241a524abSAlex Deucher { 40341a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 40441a524abSAlex Deucher 40541a524abSAlex Deucher if (pi->caps_cac) { 40641a524abSAlex Deucher WREG32_SMC(LCAC_SX0_OVR_SEL, 0); 40741a524abSAlex Deucher WREG32_SMC(LCAC_SX0_OVR_VAL, 0); 40841a524abSAlex Deucher kv_program_local_cac_table(rdev, sx_local_cac_cfg_kv, sx0_cac_config_reg); 40941a524abSAlex Deucher 41041a524abSAlex Deucher WREG32_SMC(LCAC_MC0_OVR_SEL, 0); 41141a524abSAlex Deucher WREG32_SMC(LCAC_MC0_OVR_VAL, 0); 41241a524abSAlex Deucher kv_program_local_cac_table(rdev, mc0_local_cac_cfg_kv, mc0_cac_config_reg); 41341a524abSAlex Deucher 41441a524abSAlex Deucher WREG32_SMC(LCAC_MC1_OVR_SEL, 0); 41541a524abSAlex Deucher WREG32_SMC(LCAC_MC1_OVR_VAL, 0); 41641a524abSAlex Deucher kv_program_local_cac_table(rdev, mc1_local_cac_cfg_kv, mc1_cac_config_reg); 41741a524abSAlex Deucher 41841a524abSAlex Deucher WREG32_SMC(LCAC_MC2_OVR_SEL, 0); 41941a524abSAlex Deucher WREG32_SMC(LCAC_MC2_OVR_VAL, 0); 42041a524abSAlex Deucher kv_program_local_cac_table(rdev, mc2_local_cac_cfg_kv, mc2_cac_config_reg); 42141a524abSAlex Deucher 42241a524abSAlex Deucher WREG32_SMC(LCAC_MC3_OVR_SEL, 0); 42341a524abSAlex Deucher WREG32_SMC(LCAC_MC3_OVR_VAL, 0); 42441a524abSAlex Deucher kv_program_local_cac_table(rdev, mc3_local_cac_cfg_kv, mc3_cac_config_reg); 42541a524abSAlex Deucher 42641a524abSAlex Deucher WREG32_SMC(LCAC_CPL_OVR_SEL, 0); 42741a524abSAlex Deucher WREG32_SMC(LCAC_CPL_OVR_VAL, 0); 42841a524abSAlex Deucher kv_program_local_cac_table(rdev, cpl_local_cac_cfg_kv, cpl_cac_config_reg); 42941a524abSAlex Deucher } 43041a524abSAlex Deucher } 43141a524abSAlex Deucher #endif 43241a524abSAlex Deucher 43341a524abSAlex Deucher static int kv_enable_smc_cac(struct radeon_device *rdev, bool enable) 43441a524abSAlex Deucher { 43541a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 43641a524abSAlex Deucher int ret = 0; 43741a524abSAlex Deucher 43841a524abSAlex Deucher if (pi->caps_cac) { 43941a524abSAlex Deucher if (enable) { 44041a524abSAlex Deucher ret = kv_notify_message_to_smu(rdev, PPSMC_MSG_EnableCac); 44141a524abSAlex Deucher if (ret) 44241a524abSAlex Deucher pi->cac_enabled = false; 44341a524abSAlex Deucher else 44441a524abSAlex Deucher pi->cac_enabled = true; 44541a524abSAlex Deucher } else if (pi->cac_enabled) { 44641a524abSAlex Deucher kv_notify_message_to_smu(rdev, PPSMC_MSG_DisableCac); 44741a524abSAlex Deucher pi->cac_enabled = false; 44841a524abSAlex Deucher } 44941a524abSAlex Deucher } 45041a524abSAlex Deucher 45141a524abSAlex Deucher return ret; 45241a524abSAlex Deucher } 45341a524abSAlex Deucher 45441a524abSAlex Deucher static int kv_process_firmware_header(struct radeon_device *rdev) 45541a524abSAlex Deucher { 45641a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 45741a524abSAlex Deucher u32 tmp; 45841a524abSAlex Deucher int ret; 45941a524abSAlex Deucher 46041a524abSAlex Deucher ret = kv_read_smc_sram_dword(rdev, SMU7_FIRMWARE_HEADER_LOCATION + 46141a524abSAlex Deucher offsetof(SMU7_Firmware_Header, DpmTable), 46241a524abSAlex Deucher &tmp, pi->sram_end); 46341a524abSAlex Deucher 46441a524abSAlex Deucher if (ret == 0) 46541a524abSAlex Deucher pi->dpm_table_start = tmp; 46641a524abSAlex Deucher 46741a524abSAlex Deucher ret = kv_read_smc_sram_dword(rdev, SMU7_FIRMWARE_HEADER_LOCATION + 46841a524abSAlex Deucher offsetof(SMU7_Firmware_Header, SoftRegisters), 46941a524abSAlex Deucher &tmp, pi->sram_end); 47041a524abSAlex Deucher 47141a524abSAlex Deucher if (ret == 0) 47241a524abSAlex Deucher pi->soft_regs_start = tmp; 47341a524abSAlex Deucher 47441a524abSAlex Deucher return ret; 47541a524abSAlex Deucher } 47641a524abSAlex Deucher 47741a524abSAlex Deucher static int kv_enable_dpm_voltage_scaling(struct radeon_device *rdev) 47841a524abSAlex Deucher { 47941a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 48041a524abSAlex Deucher int ret; 48141a524abSAlex Deucher 48241a524abSAlex Deucher pi->graphics_voltage_change_enable = 1; 48341a524abSAlex Deucher 48441a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 48541a524abSAlex Deucher pi->dpm_table_start + 48641a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, GraphicsVoltageChangeEnable), 48741a524abSAlex Deucher &pi->graphics_voltage_change_enable, 48841a524abSAlex Deucher sizeof(u8), pi->sram_end); 48941a524abSAlex Deucher 49041a524abSAlex Deucher return ret; 49141a524abSAlex Deucher } 49241a524abSAlex Deucher 49341a524abSAlex Deucher static int kv_set_dpm_interval(struct radeon_device *rdev) 49441a524abSAlex Deucher { 49541a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 49641a524abSAlex Deucher int ret; 49741a524abSAlex Deucher 49841a524abSAlex Deucher pi->graphics_interval = 1; 49941a524abSAlex Deucher 50041a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 50141a524abSAlex Deucher pi->dpm_table_start + 50241a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, GraphicsInterval), 50341a524abSAlex Deucher &pi->graphics_interval, 50441a524abSAlex Deucher sizeof(u8), pi->sram_end); 50541a524abSAlex Deucher 50641a524abSAlex Deucher return ret; 50741a524abSAlex Deucher } 50841a524abSAlex Deucher 50941a524abSAlex Deucher static int kv_set_dpm_boot_state(struct radeon_device *rdev) 51041a524abSAlex Deucher { 51141a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 51241a524abSAlex Deucher int ret; 51341a524abSAlex Deucher 51441a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 51541a524abSAlex Deucher pi->dpm_table_start + 51641a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, GraphicsBootLevel), 51741a524abSAlex Deucher &pi->graphics_boot_level, 51841a524abSAlex Deucher sizeof(u8), pi->sram_end); 51941a524abSAlex Deucher 52041a524abSAlex Deucher return ret; 52141a524abSAlex Deucher } 52241a524abSAlex Deucher 52341a524abSAlex Deucher static void kv_program_vc(struct radeon_device *rdev) 52441a524abSAlex Deucher { 525136de91eSAlex Deucher WREG32_SMC(CG_FTV_0, 0x3FFFC100); 52641a524abSAlex Deucher } 52741a524abSAlex Deucher 52841a524abSAlex Deucher static void kv_clear_vc(struct radeon_device *rdev) 52941a524abSAlex Deucher { 53041a524abSAlex Deucher WREG32_SMC(CG_FTV_0, 0); 53141a524abSAlex Deucher } 53241a524abSAlex Deucher 53341a524abSAlex Deucher static int kv_set_divider_value(struct radeon_device *rdev, 53441a524abSAlex Deucher u32 index, u32 sclk) 53541a524abSAlex Deucher { 53641a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 53741a524abSAlex Deucher struct atom_clock_dividers dividers; 53841a524abSAlex Deucher int ret; 53941a524abSAlex Deucher 54041a524abSAlex Deucher ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, 54141a524abSAlex Deucher sclk, false, ÷rs); 54241a524abSAlex Deucher if (ret) 54341a524abSAlex Deucher return ret; 54441a524abSAlex Deucher 54541a524abSAlex Deucher pi->graphics_level[index].SclkDid = (u8)dividers.post_div; 54641a524abSAlex Deucher pi->graphics_level[index].SclkFrequency = cpu_to_be32(sclk); 54741a524abSAlex Deucher 54841a524abSAlex Deucher return 0; 54941a524abSAlex Deucher } 55041a524abSAlex Deucher 55147f5c746SAlex Deucher static u32 kv_convert_vid2_to_vid7(struct radeon_device *rdev, 55247f5c746SAlex Deucher struct sumo_vid_mapping_table *vid_mapping_table, 55347f5c746SAlex Deucher u32 vid_2bit) 55447f5c746SAlex Deucher { 55547f5c746SAlex Deucher struct radeon_clock_voltage_dependency_table *vddc_sclk_table = 55647f5c746SAlex Deucher &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; 55747f5c746SAlex Deucher u32 i; 55847f5c746SAlex Deucher 55947f5c746SAlex Deucher if (vddc_sclk_table && vddc_sclk_table->count) { 56047f5c746SAlex Deucher if (vid_2bit < vddc_sclk_table->count) 56147f5c746SAlex Deucher return vddc_sclk_table->entries[vid_2bit].v; 56247f5c746SAlex Deucher else 56347f5c746SAlex Deucher return vddc_sclk_table->entries[vddc_sclk_table->count - 1].v; 56447f5c746SAlex Deucher } else { 56547f5c746SAlex Deucher for (i = 0; i < vid_mapping_table->num_entries; i++) { 56647f5c746SAlex Deucher if (vid_mapping_table->entries[i].vid_2bit == vid_2bit) 56747f5c746SAlex Deucher return vid_mapping_table->entries[i].vid_7bit; 56847f5c746SAlex Deucher } 56947f5c746SAlex Deucher return vid_mapping_table->entries[vid_mapping_table->num_entries - 1].vid_7bit; 57047f5c746SAlex Deucher } 57147f5c746SAlex Deucher } 57247f5c746SAlex Deucher 57347f5c746SAlex Deucher static u32 kv_convert_vid7_to_vid2(struct radeon_device *rdev, 57447f5c746SAlex Deucher struct sumo_vid_mapping_table *vid_mapping_table, 57547f5c746SAlex Deucher u32 vid_7bit) 57647f5c746SAlex Deucher { 57747f5c746SAlex Deucher struct radeon_clock_voltage_dependency_table *vddc_sclk_table = 57847f5c746SAlex Deucher &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; 57947f5c746SAlex Deucher u32 i; 58047f5c746SAlex Deucher 58147f5c746SAlex Deucher if (vddc_sclk_table && vddc_sclk_table->count) { 58247f5c746SAlex Deucher for (i = 0; i < vddc_sclk_table->count; i++) { 58347f5c746SAlex Deucher if (vddc_sclk_table->entries[i].v == vid_7bit) 58447f5c746SAlex Deucher return i; 58547f5c746SAlex Deucher } 58647f5c746SAlex Deucher return vddc_sclk_table->count - 1; 58747f5c746SAlex Deucher } else { 58847f5c746SAlex Deucher for (i = 0; i < vid_mapping_table->num_entries; i++) { 58947f5c746SAlex Deucher if (vid_mapping_table->entries[i].vid_7bit == vid_7bit) 59047f5c746SAlex Deucher return vid_mapping_table->entries[i].vid_2bit; 59147f5c746SAlex Deucher } 59247f5c746SAlex Deucher 59347f5c746SAlex Deucher return vid_mapping_table->entries[vid_mapping_table->num_entries - 1].vid_2bit; 59447f5c746SAlex Deucher } 59547f5c746SAlex Deucher } 59647f5c746SAlex Deucher 59741a524abSAlex Deucher static u16 kv_convert_8bit_index_to_voltage(struct radeon_device *rdev, 59841a524abSAlex Deucher u16 voltage) 59941a524abSAlex Deucher { 60041a524abSAlex Deucher return 6200 - (voltage * 25); 60141a524abSAlex Deucher } 60241a524abSAlex Deucher 60341a524abSAlex Deucher static u16 kv_convert_2bit_index_to_voltage(struct radeon_device *rdev, 60441a524abSAlex Deucher u32 vid_2bit) 60541a524abSAlex Deucher { 60641a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 60747f5c746SAlex Deucher u32 vid_8bit = kv_convert_vid2_to_vid7(rdev, 60841a524abSAlex Deucher &pi->sys_info.vid_mapping_table, 60941a524abSAlex Deucher vid_2bit); 61041a524abSAlex Deucher 61141a524abSAlex Deucher return kv_convert_8bit_index_to_voltage(rdev, (u16)vid_8bit); 61241a524abSAlex Deucher } 61341a524abSAlex Deucher 61441a524abSAlex Deucher 61541a524abSAlex Deucher static int kv_set_vid(struct radeon_device *rdev, u32 index, u32 vid) 61641a524abSAlex Deucher { 61741a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 61841a524abSAlex Deucher 61941a524abSAlex Deucher pi->graphics_level[index].VoltageDownH = (u8)pi->voltage_drop_t; 62041a524abSAlex Deucher pi->graphics_level[index].MinVddNb = 62141a524abSAlex Deucher cpu_to_be32(kv_convert_2bit_index_to_voltage(rdev, vid)); 62241a524abSAlex Deucher 62341a524abSAlex Deucher return 0; 62441a524abSAlex Deucher } 62541a524abSAlex Deucher 62641a524abSAlex Deucher static int kv_set_at(struct radeon_device *rdev, u32 index, u32 at) 62741a524abSAlex Deucher { 62841a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 62941a524abSAlex Deucher 63041a524abSAlex Deucher pi->graphics_level[index].AT = cpu_to_be16((u16)at); 63141a524abSAlex Deucher 63241a524abSAlex Deucher return 0; 63341a524abSAlex Deucher } 63441a524abSAlex Deucher 63541a524abSAlex Deucher static void kv_dpm_power_level_enable(struct radeon_device *rdev, 63641a524abSAlex Deucher u32 index, bool enable) 63741a524abSAlex Deucher { 63841a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 63941a524abSAlex Deucher 64041a524abSAlex Deucher pi->graphics_level[index].EnabledForActivity = enable ? 1 : 0; 64141a524abSAlex Deucher } 64241a524abSAlex Deucher 64341a524abSAlex Deucher static void kv_start_dpm(struct radeon_device *rdev) 64441a524abSAlex Deucher { 64541a524abSAlex Deucher u32 tmp = RREG32_SMC(GENERAL_PWRMGT); 64641a524abSAlex Deucher 64741a524abSAlex Deucher tmp |= GLOBAL_PWRMGT_EN; 64841a524abSAlex Deucher WREG32_SMC(GENERAL_PWRMGT, tmp); 64941a524abSAlex Deucher 65041a524abSAlex Deucher kv_smc_dpm_enable(rdev, true); 65141a524abSAlex Deucher } 65241a524abSAlex Deucher 65341a524abSAlex Deucher static void kv_stop_dpm(struct radeon_device *rdev) 65441a524abSAlex Deucher { 65541a524abSAlex Deucher kv_smc_dpm_enable(rdev, false); 65641a524abSAlex Deucher } 65741a524abSAlex Deucher 65841a524abSAlex Deucher static void kv_start_am(struct radeon_device *rdev) 65941a524abSAlex Deucher { 66041a524abSAlex Deucher u32 sclk_pwrmgt_cntl = RREG32_SMC(SCLK_PWRMGT_CNTL); 66141a524abSAlex Deucher 66241a524abSAlex Deucher sclk_pwrmgt_cntl &= ~(RESET_SCLK_CNT | RESET_BUSY_CNT); 66341a524abSAlex Deucher sclk_pwrmgt_cntl |= DYNAMIC_PM_EN; 66441a524abSAlex Deucher 66541a524abSAlex Deucher WREG32_SMC(SCLK_PWRMGT_CNTL, sclk_pwrmgt_cntl); 66641a524abSAlex Deucher } 66741a524abSAlex Deucher 66841a524abSAlex Deucher static void kv_reset_am(struct radeon_device *rdev) 66941a524abSAlex Deucher { 67041a524abSAlex Deucher u32 sclk_pwrmgt_cntl = RREG32_SMC(SCLK_PWRMGT_CNTL); 67141a524abSAlex Deucher 67241a524abSAlex Deucher sclk_pwrmgt_cntl |= (RESET_SCLK_CNT | RESET_BUSY_CNT); 67341a524abSAlex Deucher 67441a524abSAlex Deucher WREG32_SMC(SCLK_PWRMGT_CNTL, sclk_pwrmgt_cntl); 67541a524abSAlex Deucher } 67641a524abSAlex Deucher 67741a524abSAlex Deucher static int kv_freeze_sclk_dpm(struct radeon_device *rdev, bool freeze) 67841a524abSAlex Deucher { 67941a524abSAlex Deucher return kv_notify_message_to_smu(rdev, freeze ? 68041a524abSAlex Deucher PPSMC_MSG_SCLKDPM_FreezeLevel : PPSMC_MSG_SCLKDPM_UnfreezeLevel); 68141a524abSAlex Deucher } 68241a524abSAlex Deucher 68341a524abSAlex Deucher static int kv_force_lowest_valid(struct radeon_device *rdev) 68441a524abSAlex Deucher { 68541a524abSAlex Deucher return kv_force_dpm_lowest(rdev); 68641a524abSAlex Deucher } 68741a524abSAlex Deucher 68841a524abSAlex Deucher static int kv_unforce_levels(struct radeon_device *rdev) 68941a524abSAlex Deucher { 6907d032a4bSSamuel Li if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) 69141a524abSAlex Deucher return kv_notify_message_to_smu(rdev, PPSMC_MSG_NoForcedLevel); 692136de91eSAlex Deucher else 693136de91eSAlex Deucher return kv_set_enabled_levels(rdev); 69441a524abSAlex Deucher } 69541a524abSAlex Deucher 69641a524abSAlex Deucher static int kv_update_sclk_t(struct radeon_device *rdev) 69741a524abSAlex Deucher { 69841a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 69941a524abSAlex Deucher u32 low_sclk_interrupt_t = 0; 70041a524abSAlex Deucher int ret = 0; 70141a524abSAlex Deucher 70241a524abSAlex Deucher if (pi->caps_sclk_throttle_low_notification) { 70341a524abSAlex Deucher low_sclk_interrupt_t = cpu_to_be32(pi->low_sclk_interrupt_t); 70441a524abSAlex Deucher 70541a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 70641a524abSAlex Deucher pi->dpm_table_start + 70741a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, LowSclkInterruptT), 70841a524abSAlex Deucher (u8 *)&low_sclk_interrupt_t, 70941a524abSAlex Deucher sizeof(u32), pi->sram_end); 71041a524abSAlex Deucher } 71141a524abSAlex Deucher return ret; 71241a524abSAlex Deucher } 71341a524abSAlex Deucher 71441a524abSAlex Deucher static int kv_program_bootup_state(struct radeon_device *rdev) 71541a524abSAlex Deucher { 71641a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 71741a524abSAlex Deucher u32 i; 71841a524abSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 71941a524abSAlex Deucher &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; 72041a524abSAlex Deucher 72141a524abSAlex Deucher if (table && table->count) { 7228c5c6fadSDan Carpenter for (i = pi->graphics_dpm_level_count - 1; i > 0; i--) { 7238c5c6fadSDan Carpenter if (table->entries[i].clk == pi->boot_pl.sclk) 72441a524abSAlex Deucher break; 72541a524abSAlex Deucher } 72641a524abSAlex Deucher 72741a524abSAlex Deucher pi->graphics_boot_level = (u8)i; 72841a524abSAlex Deucher kv_dpm_power_level_enable(rdev, i, true); 72941a524abSAlex Deucher } else { 73041a524abSAlex Deucher struct sumo_sclk_voltage_mapping_table *table = 73141a524abSAlex Deucher &pi->sys_info.sclk_voltage_mapping_table; 73241a524abSAlex Deucher 73341a524abSAlex Deucher if (table->num_max_dpm_entries == 0) 73441a524abSAlex Deucher return -EINVAL; 73541a524abSAlex Deucher 7368c5c6fadSDan Carpenter for (i = pi->graphics_dpm_level_count - 1; i > 0; i--) { 7378c5c6fadSDan Carpenter if (table->entries[i].sclk_frequency == pi->boot_pl.sclk) 73841a524abSAlex Deucher break; 73941a524abSAlex Deucher } 74041a524abSAlex Deucher 74141a524abSAlex Deucher pi->graphics_boot_level = (u8)i; 74241a524abSAlex Deucher kv_dpm_power_level_enable(rdev, i, true); 74341a524abSAlex Deucher } 74441a524abSAlex Deucher return 0; 74541a524abSAlex Deucher } 74641a524abSAlex Deucher 74741a524abSAlex Deucher static int kv_enable_auto_thermal_throttling(struct radeon_device *rdev) 74841a524abSAlex Deucher { 74941a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 75041a524abSAlex Deucher int ret; 75141a524abSAlex Deucher 75241a524abSAlex Deucher pi->graphics_therm_throttle_enable = 1; 75341a524abSAlex Deucher 75441a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 75541a524abSAlex Deucher pi->dpm_table_start + 75641a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, GraphicsThermThrottleEnable), 75741a524abSAlex Deucher &pi->graphics_therm_throttle_enable, 75841a524abSAlex Deucher sizeof(u8), pi->sram_end); 75941a524abSAlex Deucher 76041a524abSAlex Deucher return ret; 76141a524abSAlex Deucher } 76241a524abSAlex Deucher 76341a524abSAlex Deucher static int kv_upload_dpm_settings(struct radeon_device *rdev) 76441a524abSAlex Deucher { 76541a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 76641a524abSAlex Deucher int ret; 76741a524abSAlex Deucher 76841a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 76941a524abSAlex Deucher pi->dpm_table_start + 77041a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, GraphicsLevel), 77141a524abSAlex Deucher (u8 *)&pi->graphics_level, 77241a524abSAlex Deucher sizeof(SMU7_Fusion_GraphicsLevel) * SMU7_MAX_LEVELS_GRAPHICS, 77341a524abSAlex Deucher pi->sram_end); 77441a524abSAlex Deucher 77541a524abSAlex Deucher if (ret) 77641a524abSAlex Deucher return ret; 77741a524abSAlex Deucher 77841a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 77941a524abSAlex Deucher pi->dpm_table_start + 78041a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, GraphicsDpmLevelCount), 78141a524abSAlex Deucher &pi->graphics_dpm_level_count, 78241a524abSAlex Deucher sizeof(u8), pi->sram_end); 78341a524abSAlex Deucher 78441a524abSAlex Deucher return ret; 78541a524abSAlex Deucher } 78641a524abSAlex Deucher 78741a524abSAlex Deucher static u32 kv_get_clock_difference(u32 a, u32 b) 78841a524abSAlex Deucher { 78941a524abSAlex Deucher return (a >= b) ? a - b : b - a; 79041a524abSAlex Deucher } 79141a524abSAlex Deucher 79241a524abSAlex Deucher static u32 kv_get_clk_bypass(struct radeon_device *rdev, u32 clk) 79341a524abSAlex Deucher { 79441a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 79541a524abSAlex Deucher u32 value; 79641a524abSAlex Deucher 79741a524abSAlex Deucher if (pi->caps_enable_dfs_bypass) { 79841a524abSAlex Deucher if (kv_get_clock_difference(clk, 40000) < 200) 79941a524abSAlex Deucher value = 3; 80041a524abSAlex Deucher else if (kv_get_clock_difference(clk, 30000) < 200) 80141a524abSAlex Deucher value = 2; 80241a524abSAlex Deucher else if (kv_get_clock_difference(clk, 20000) < 200) 80341a524abSAlex Deucher value = 7; 80441a524abSAlex Deucher else if (kv_get_clock_difference(clk, 15000) < 200) 80541a524abSAlex Deucher value = 6; 80641a524abSAlex Deucher else if (kv_get_clock_difference(clk, 10000) < 200) 80741a524abSAlex Deucher value = 8; 80841a524abSAlex Deucher else 80941a524abSAlex Deucher value = 0; 81041a524abSAlex Deucher } else { 81141a524abSAlex Deucher value = 0; 81241a524abSAlex Deucher } 81341a524abSAlex Deucher 81441a524abSAlex Deucher return value; 81541a524abSAlex Deucher } 81641a524abSAlex Deucher 81741a524abSAlex Deucher static int kv_populate_uvd_table(struct radeon_device *rdev) 81841a524abSAlex Deucher { 81941a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 82041a524abSAlex Deucher struct radeon_uvd_clock_voltage_dependency_table *table = 82141a524abSAlex Deucher &rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table; 82241a524abSAlex Deucher struct atom_clock_dividers dividers; 82341a524abSAlex Deucher int ret; 82441a524abSAlex Deucher u32 i; 82541a524abSAlex Deucher 82641a524abSAlex Deucher if (table == NULL || table->count == 0) 82741a524abSAlex Deucher return 0; 82841a524abSAlex Deucher 82941a524abSAlex Deucher pi->uvd_level_count = 0; 83041a524abSAlex Deucher for (i = 0; i < table->count; i++) { 83141a524abSAlex Deucher if (pi->high_voltage_t && 83241a524abSAlex Deucher (pi->high_voltage_t < table->entries[i].v)) 83341a524abSAlex Deucher break; 83441a524abSAlex Deucher 83541a524abSAlex Deucher pi->uvd_level[i].VclkFrequency = cpu_to_be32(table->entries[i].vclk); 83641a524abSAlex Deucher pi->uvd_level[i].DclkFrequency = cpu_to_be32(table->entries[i].dclk); 83741a524abSAlex Deucher pi->uvd_level[i].MinVddNb = cpu_to_be16(table->entries[i].v); 83841a524abSAlex Deucher 83941a524abSAlex Deucher pi->uvd_level[i].VClkBypassCntl = 84041a524abSAlex Deucher (u8)kv_get_clk_bypass(rdev, table->entries[i].vclk); 84141a524abSAlex Deucher pi->uvd_level[i].DClkBypassCntl = 84241a524abSAlex Deucher (u8)kv_get_clk_bypass(rdev, table->entries[i].dclk); 84341a524abSAlex Deucher 84441a524abSAlex Deucher ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, 84541a524abSAlex Deucher table->entries[i].vclk, false, ÷rs); 84641a524abSAlex Deucher if (ret) 84741a524abSAlex Deucher return ret; 84841a524abSAlex Deucher pi->uvd_level[i].VclkDivider = (u8)dividers.post_div; 84941a524abSAlex Deucher 85041a524abSAlex Deucher ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, 85141a524abSAlex Deucher table->entries[i].dclk, false, ÷rs); 85241a524abSAlex Deucher if (ret) 85341a524abSAlex Deucher return ret; 85441a524abSAlex Deucher pi->uvd_level[i].DclkDivider = (u8)dividers.post_div; 85541a524abSAlex Deucher 85641a524abSAlex Deucher pi->uvd_level_count++; 85741a524abSAlex Deucher } 85841a524abSAlex Deucher 85941a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 86041a524abSAlex Deucher pi->dpm_table_start + 86141a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, UvdLevelCount), 86241a524abSAlex Deucher (u8 *)&pi->uvd_level_count, 86341a524abSAlex Deucher sizeof(u8), pi->sram_end); 86441a524abSAlex Deucher if (ret) 86541a524abSAlex Deucher return ret; 86641a524abSAlex Deucher 86741a524abSAlex Deucher pi->uvd_interval = 1; 86841a524abSAlex Deucher 86941a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 87041a524abSAlex Deucher pi->dpm_table_start + 87141a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, UVDInterval), 87241a524abSAlex Deucher &pi->uvd_interval, 87341a524abSAlex Deucher sizeof(u8), pi->sram_end); 87441a524abSAlex Deucher if (ret) 87541a524abSAlex Deucher return ret; 87641a524abSAlex Deucher 87741a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 87841a524abSAlex Deucher pi->dpm_table_start + 87941a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, UvdLevel), 88041a524abSAlex Deucher (u8 *)&pi->uvd_level, 88141a524abSAlex Deucher sizeof(SMU7_Fusion_UvdLevel) * SMU7_MAX_LEVELS_UVD, 88241a524abSAlex Deucher pi->sram_end); 88341a524abSAlex Deucher 88441a524abSAlex Deucher return ret; 88541a524abSAlex Deucher 88641a524abSAlex Deucher } 88741a524abSAlex Deucher 88841a524abSAlex Deucher static int kv_populate_vce_table(struct radeon_device *rdev) 88941a524abSAlex Deucher { 89041a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 89141a524abSAlex Deucher int ret; 89241a524abSAlex Deucher u32 i; 89341a524abSAlex Deucher struct radeon_vce_clock_voltage_dependency_table *table = 89441a524abSAlex Deucher &rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table; 89541a524abSAlex Deucher struct atom_clock_dividers dividers; 89641a524abSAlex Deucher 89741a524abSAlex Deucher if (table == NULL || table->count == 0) 89841a524abSAlex Deucher return 0; 89941a524abSAlex Deucher 90041a524abSAlex Deucher pi->vce_level_count = 0; 90141a524abSAlex Deucher for (i = 0; i < table->count; i++) { 90241a524abSAlex Deucher if (pi->high_voltage_t && 90341a524abSAlex Deucher pi->high_voltage_t < table->entries[i].v) 90441a524abSAlex Deucher break; 90541a524abSAlex Deucher 90641a524abSAlex Deucher pi->vce_level[i].Frequency = cpu_to_be32(table->entries[i].evclk); 90741a524abSAlex Deucher pi->vce_level[i].MinVoltage = cpu_to_be16(table->entries[i].v); 90841a524abSAlex Deucher 90941a524abSAlex Deucher pi->vce_level[i].ClkBypassCntl = 91041a524abSAlex Deucher (u8)kv_get_clk_bypass(rdev, table->entries[i].evclk); 91141a524abSAlex Deucher 91241a524abSAlex Deucher ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, 91341a524abSAlex Deucher table->entries[i].evclk, false, ÷rs); 91441a524abSAlex Deucher if (ret) 91541a524abSAlex Deucher return ret; 91641a524abSAlex Deucher pi->vce_level[i].Divider = (u8)dividers.post_div; 91741a524abSAlex Deucher 91841a524abSAlex Deucher pi->vce_level_count++; 91941a524abSAlex Deucher } 92041a524abSAlex Deucher 92141a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 92241a524abSAlex Deucher pi->dpm_table_start + 92341a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, VceLevelCount), 92441a524abSAlex Deucher (u8 *)&pi->vce_level_count, 92541a524abSAlex Deucher sizeof(u8), 92641a524abSAlex Deucher pi->sram_end); 92741a524abSAlex Deucher if (ret) 92841a524abSAlex Deucher return ret; 92941a524abSAlex Deucher 93041a524abSAlex Deucher pi->vce_interval = 1; 93141a524abSAlex Deucher 93241a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 93341a524abSAlex Deucher pi->dpm_table_start + 93441a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, VCEInterval), 93541a524abSAlex Deucher (u8 *)&pi->vce_interval, 93641a524abSAlex Deucher sizeof(u8), 93741a524abSAlex Deucher pi->sram_end); 93841a524abSAlex Deucher if (ret) 93941a524abSAlex Deucher return ret; 94041a524abSAlex Deucher 94141a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 94241a524abSAlex Deucher pi->dpm_table_start + 94341a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, VceLevel), 94441a524abSAlex Deucher (u8 *)&pi->vce_level, 94541a524abSAlex Deucher sizeof(SMU7_Fusion_ExtClkLevel) * SMU7_MAX_LEVELS_VCE, 94641a524abSAlex Deucher pi->sram_end); 94741a524abSAlex Deucher 94841a524abSAlex Deucher return ret; 94941a524abSAlex Deucher } 95041a524abSAlex Deucher 95141a524abSAlex Deucher static int kv_populate_samu_table(struct radeon_device *rdev) 95241a524abSAlex Deucher { 95341a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 95441a524abSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 95541a524abSAlex Deucher &rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table; 95641a524abSAlex Deucher struct atom_clock_dividers dividers; 95741a524abSAlex Deucher int ret; 95841a524abSAlex Deucher u32 i; 95941a524abSAlex Deucher 96041a524abSAlex Deucher if (table == NULL || table->count == 0) 96141a524abSAlex Deucher return 0; 96241a524abSAlex Deucher 96341a524abSAlex Deucher pi->samu_level_count = 0; 96441a524abSAlex Deucher for (i = 0; i < table->count; i++) { 96541a524abSAlex Deucher if (pi->high_voltage_t && 96641a524abSAlex Deucher pi->high_voltage_t < table->entries[i].v) 96741a524abSAlex Deucher break; 96841a524abSAlex Deucher 96941a524abSAlex Deucher pi->samu_level[i].Frequency = cpu_to_be32(table->entries[i].clk); 97041a524abSAlex Deucher pi->samu_level[i].MinVoltage = cpu_to_be16(table->entries[i].v); 97141a524abSAlex Deucher 97241a524abSAlex Deucher pi->samu_level[i].ClkBypassCntl = 97341a524abSAlex Deucher (u8)kv_get_clk_bypass(rdev, table->entries[i].clk); 97441a524abSAlex Deucher 97541a524abSAlex Deucher ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, 97641a524abSAlex Deucher table->entries[i].clk, false, ÷rs); 97741a524abSAlex Deucher if (ret) 97841a524abSAlex Deucher return ret; 97941a524abSAlex Deucher pi->samu_level[i].Divider = (u8)dividers.post_div; 98041a524abSAlex Deucher 98141a524abSAlex Deucher pi->samu_level_count++; 98241a524abSAlex Deucher } 98341a524abSAlex Deucher 98441a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 98541a524abSAlex Deucher pi->dpm_table_start + 98641a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, SamuLevelCount), 98741a524abSAlex Deucher (u8 *)&pi->samu_level_count, 98841a524abSAlex Deucher sizeof(u8), 98941a524abSAlex Deucher pi->sram_end); 99041a524abSAlex Deucher if (ret) 99141a524abSAlex Deucher return ret; 99241a524abSAlex Deucher 99341a524abSAlex Deucher pi->samu_interval = 1; 99441a524abSAlex Deucher 99541a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 99641a524abSAlex Deucher pi->dpm_table_start + 99741a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, SAMUInterval), 99841a524abSAlex Deucher (u8 *)&pi->samu_interval, 99941a524abSAlex Deucher sizeof(u8), 100041a524abSAlex Deucher pi->sram_end); 100141a524abSAlex Deucher if (ret) 100241a524abSAlex Deucher return ret; 100341a524abSAlex Deucher 100441a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 100541a524abSAlex Deucher pi->dpm_table_start + 100641a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, SamuLevel), 100741a524abSAlex Deucher (u8 *)&pi->samu_level, 100841a524abSAlex Deucher sizeof(SMU7_Fusion_ExtClkLevel) * SMU7_MAX_LEVELS_SAMU, 100941a524abSAlex Deucher pi->sram_end); 101041a524abSAlex Deucher if (ret) 101141a524abSAlex Deucher return ret; 101241a524abSAlex Deucher 101341a524abSAlex Deucher return ret; 101441a524abSAlex Deucher } 101541a524abSAlex Deucher 101641a524abSAlex Deucher 101741a524abSAlex Deucher static int kv_populate_acp_table(struct radeon_device *rdev) 101841a524abSAlex Deucher { 101941a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 102041a524abSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 102141a524abSAlex Deucher &rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table; 102241a524abSAlex Deucher struct atom_clock_dividers dividers; 102341a524abSAlex Deucher int ret; 102441a524abSAlex Deucher u32 i; 102541a524abSAlex Deucher 102641a524abSAlex Deucher if (table == NULL || table->count == 0) 102741a524abSAlex Deucher return 0; 102841a524abSAlex Deucher 102941a524abSAlex Deucher pi->acp_level_count = 0; 103041a524abSAlex Deucher for (i = 0; i < table->count; i++) { 103141a524abSAlex Deucher pi->acp_level[i].Frequency = cpu_to_be32(table->entries[i].clk); 103241a524abSAlex Deucher pi->acp_level[i].MinVoltage = cpu_to_be16(table->entries[i].v); 103341a524abSAlex Deucher 103441a524abSAlex Deucher ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, 103541a524abSAlex Deucher table->entries[i].clk, false, ÷rs); 103641a524abSAlex Deucher if (ret) 103741a524abSAlex Deucher return ret; 103841a524abSAlex Deucher pi->acp_level[i].Divider = (u8)dividers.post_div; 103941a524abSAlex Deucher 104041a524abSAlex Deucher pi->acp_level_count++; 104141a524abSAlex Deucher } 104241a524abSAlex Deucher 104341a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 104441a524abSAlex Deucher pi->dpm_table_start + 104541a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, AcpLevelCount), 104641a524abSAlex Deucher (u8 *)&pi->acp_level_count, 104741a524abSAlex Deucher sizeof(u8), 104841a524abSAlex Deucher pi->sram_end); 104941a524abSAlex Deucher if (ret) 105041a524abSAlex Deucher return ret; 105141a524abSAlex Deucher 105241a524abSAlex Deucher pi->acp_interval = 1; 105341a524abSAlex Deucher 105441a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 105541a524abSAlex Deucher pi->dpm_table_start + 105641a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, ACPInterval), 105741a524abSAlex Deucher (u8 *)&pi->acp_interval, 105841a524abSAlex Deucher sizeof(u8), 105941a524abSAlex Deucher pi->sram_end); 106041a524abSAlex Deucher if (ret) 106141a524abSAlex Deucher return ret; 106241a524abSAlex Deucher 106341a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 106441a524abSAlex Deucher pi->dpm_table_start + 106541a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, AcpLevel), 106641a524abSAlex Deucher (u8 *)&pi->acp_level, 106741a524abSAlex Deucher sizeof(SMU7_Fusion_ExtClkLevel) * SMU7_MAX_LEVELS_ACP, 106841a524abSAlex Deucher pi->sram_end); 106941a524abSAlex Deucher if (ret) 107041a524abSAlex Deucher return ret; 107141a524abSAlex Deucher 107241a524abSAlex Deucher return ret; 107341a524abSAlex Deucher } 107441a524abSAlex Deucher 107541a524abSAlex Deucher static void kv_calculate_dfs_bypass_settings(struct radeon_device *rdev) 107641a524abSAlex Deucher { 107741a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 107841a524abSAlex Deucher u32 i; 107941a524abSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 108041a524abSAlex Deucher &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; 108141a524abSAlex Deucher 108241a524abSAlex Deucher if (table && table->count) { 108341a524abSAlex Deucher for (i = 0; i < pi->graphics_dpm_level_count; i++) { 108441a524abSAlex Deucher if (pi->caps_enable_dfs_bypass) { 108541a524abSAlex Deucher if (kv_get_clock_difference(table->entries[i].clk, 40000) < 200) 108641a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 3; 108741a524abSAlex Deucher else if (kv_get_clock_difference(table->entries[i].clk, 30000) < 200) 108841a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 2; 108941a524abSAlex Deucher else if (kv_get_clock_difference(table->entries[i].clk, 26600) < 200) 109041a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 7; 109141a524abSAlex Deucher else if (kv_get_clock_difference(table->entries[i].clk , 20000) < 200) 109241a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 6; 109341a524abSAlex Deucher else if (kv_get_clock_difference(table->entries[i].clk , 10000) < 200) 109441a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 8; 109541a524abSAlex Deucher else 109641a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 0; 109741a524abSAlex Deucher } else { 109841a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 0; 109941a524abSAlex Deucher } 110041a524abSAlex Deucher } 110141a524abSAlex Deucher } else { 110241a524abSAlex Deucher struct sumo_sclk_voltage_mapping_table *table = 110341a524abSAlex Deucher &pi->sys_info.sclk_voltage_mapping_table; 110441a524abSAlex Deucher for (i = 0; i < pi->graphics_dpm_level_count; i++) { 110541a524abSAlex Deucher if (pi->caps_enable_dfs_bypass) { 110641a524abSAlex Deucher if (kv_get_clock_difference(table->entries[i].sclk_frequency, 40000) < 200) 110741a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 3; 110841a524abSAlex Deucher else if (kv_get_clock_difference(table->entries[i].sclk_frequency, 30000) < 200) 110941a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 2; 111041a524abSAlex Deucher else if (kv_get_clock_difference(table->entries[i].sclk_frequency, 26600) < 200) 111141a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 7; 111241a524abSAlex Deucher else if (kv_get_clock_difference(table->entries[i].sclk_frequency, 20000) < 200) 111341a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 6; 111441a524abSAlex Deucher else if (kv_get_clock_difference(table->entries[i].sclk_frequency, 10000) < 200) 111541a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 8; 111641a524abSAlex Deucher else 111741a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 0; 111841a524abSAlex Deucher } else { 111941a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 0; 112041a524abSAlex Deucher } 112141a524abSAlex Deucher } 112241a524abSAlex Deucher } 112341a524abSAlex Deucher } 112441a524abSAlex Deucher 112541a524abSAlex Deucher static int kv_enable_ulv(struct radeon_device *rdev, bool enable) 112641a524abSAlex Deucher { 112741a524abSAlex Deucher return kv_notify_message_to_smu(rdev, enable ? 112841a524abSAlex Deucher PPSMC_MSG_EnableULV : PPSMC_MSG_DisableULV); 112941a524abSAlex Deucher } 113041a524abSAlex Deucher 1131136de91eSAlex Deucher static void kv_reset_acp_boot_level(struct radeon_device *rdev) 1132136de91eSAlex Deucher { 1133136de91eSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 1134136de91eSAlex Deucher 1135136de91eSAlex Deucher pi->acp_boot_level = 0xff; 1136136de91eSAlex Deucher } 1137136de91eSAlex Deucher 113841a524abSAlex Deucher static void kv_update_current_ps(struct radeon_device *rdev, 113941a524abSAlex Deucher struct radeon_ps *rps) 114041a524abSAlex Deucher { 114141a524abSAlex Deucher struct kv_ps *new_ps = kv_get_ps(rps); 114241a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 114341a524abSAlex Deucher 114441a524abSAlex Deucher pi->current_rps = *rps; 114541a524abSAlex Deucher pi->current_ps = *new_ps; 114641a524abSAlex Deucher pi->current_rps.ps_priv = &pi->current_ps; 114741a524abSAlex Deucher } 114841a524abSAlex Deucher 114941a524abSAlex Deucher static void kv_update_requested_ps(struct radeon_device *rdev, 115041a524abSAlex Deucher struct radeon_ps *rps) 115141a524abSAlex Deucher { 115241a524abSAlex Deucher struct kv_ps *new_ps = kv_get_ps(rps); 115341a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 115441a524abSAlex Deucher 115541a524abSAlex Deucher pi->requested_rps = *rps; 115641a524abSAlex Deucher pi->requested_ps = *new_ps; 115741a524abSAlex Deucher pi->requested_rps.ps_priv = &pi->requested_ps; 115841a524abSAlex Deucher } 115941a524abSAlex Deucher 1160b7a5ae97SAlex Deucher void kv_dpm_enable_bapm(struct radeon_device *rdev, bool enable) 1161b7a5ae97SAlex Deucher { 1162b7a5ae97SAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 1163b7a5ae97SAlex Deucher int ret; 1164b7a5ae97SAlex Deucher 1165b7a5ae97SAlex Deucher if (pi->bapm_enable) { 1166b7a5ae97SAlex Deucher ret = kv_smc_bapm_enable(rdev, enable); 1167b7a5ae97SAlex Deucher if (ret) 1168b7a5ae97SAlex Deucher DRM_ERROR("kv_smc_bapm_enable failed\n"); 1169b7a5ae97SAlex Deucher } 1170b7a5ae97SAlex Deucher } 1171b7a5ae97SAlex Deucher 117241a524abSAlex Deucher int kv_dpm_enable(struct radeon_device *rdev) 117341a524abSAlex Deucher { 117441a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 117541a524abSAlex Deucher int ret; 117641a524abSAlex Deucher 117741a524abSAlex Deucher ret = kv_process_firmware_header(rdev); 117841a524abSAlex Deucher if (ret) { 117941a524abSAlex Deucher DRM_ERROR("kv_process_firmware_header failed\n"); 118041a524abSAlex Deucher return ret; 118141a524abSAlex Deucher } 118241a524abSAlex Deucher kv_init_fps_limits(rdev); 118341a524abSAlex Deucher kv_init_graphics_levels(rdev); 118441a524abSAlex Deucher ret = kv_program_bootup_state(rdev); 118541a524abSAlex Deucher if (ret) { 118641a524abSAlex Deucher DRM_ERROR("kv_program_bootup_state failed\n"); 118741a524abSAlex Deucher return ret; 118841a524abSAlex Deucher } 118941a524abSAlex Deucher kv_calculate_dfs_bypass_settings(rdev); 119041a524abSAlex Deucher ret = kv_upload_dpm_settings(rdev); 119141a524abSAlex Deucher if (ret) { 119241a524abSAlex Deucher DRM_ERROR("kv_upload_dpm_settings failed\n"); 119341a524abSAlex Deucher return ret; 119441a524abSAlex Deucher } 119541a524abSAlex Deucher ret = kv_populate_uvd_table(rdev); 119641a524abSAlex Deucher if (ret) { 119741a524abSAlex Deucher DRM_ERROR("kv_populate_uvd_table failed\n"); 119841a524abSAlex Deucher return ret; 119941a524abSAlex Deucher } 120041a524abSAlex Deucher ret = kv_populate_vce_table(rdev); 120141a524abSAlex Deucher if (ret) { 120241a524abSAlex Deucher DRM_ERROR("kv_populate_vce_table failed\n"); 120341a524abSAlex Deucher return ret; 120441a524abSAlex Deucher } 120541a524abSAlex Deucher ret = kv_populate_samu_table(rdev); 120641a524abSAlex Deucher if (ret) { 120741a524abSAlex Deucher DRM_ERROR("kv_populate_samu_table failed\n"); 120841a524abSAlex Deucher return ret; 120941a524abSAlex Deucher } 121041a524abSAlex Deucher ret = kv_populate_acp_table(rdev); 121141a524abSAlex Deucher if (ret) { 121241a524abSAlex Deucher DRM_ERROR("kv_populate_acp_table failed\n"); 121341a524abSAlex Deucher return ret; 121441a524abSAlex Deucher } 121541a524abSAlex Deucher kv_program_vc(rdev); 121641a524abSAlex Deucher #if 0 121741a524abSAlex Deucher kv_initialize_hardware_cac_manager(rdev); 121841a524abSAlex Deucher #endif 121941a524abSAlex Deucher kv_start_am(rdev); 122041a524abSAlex Deucher if (pi->enable_auto_thermal_throttling) { 122141a524abSAlex Deucher ret = kv_enable_auto_thermal_throttling(rdev); 122241a524abSAlex Deucher if (ret) { 122341a524abSAlex Deucher DRM_ERROR("kv_enable_auto_thermal_throttling failed\n"); 122441a524abSAlex Deucher return ret; 122541a524abSAlex Deucher } 122641a524abSAlex Deucher } 122741a524abSAlex Deucher ret = kv_enable_dpm_voltage_scaling(rdev); 122841a524abSAlex Deucher if (ret) { 122941a524abSAlex Deucher DRM_ERROR("kv_enable_dpm_voltage_scaling failed\n"); 123041a524abSAlex Deucher return ret; 123141a524abSAlex Deucher } 123241a524abSAlex Deucher ret = kv_set_dpm_interval(rdev); 123341a524abSAlex Deucher if (ret) { 123441a524abSAlex Deucher DRM_ERROR("kv_set_dpm_interval failed\n"); 123541a524abSAlex Deucher return ret; 123641a524abSAlex Deucher } 123741a524abSAlex Deucher ret = kv_set_dpm_boot_state(rdev); 123841a524abSAlex Deucher if (ret) { 123941a524abSAlex Deucher DRM_ERROR("kv_set_dpm_boot_state failed\n"); 124041a524abSAlex Deucher return ret; 124141a524abSAlex Deucher } 124241a524abSAlex Deucher ret = kv_enable_ulv(rdev, true); 124341a524abSAlex Deucher if (ret) { 124441a524abSAlex Deucher DRM_ERROR("kv_enable_ulv failed\n"); 124541a524abSAlex Deucher return ret; 124641a524abSAlex Deucher } 124741a524abSAlex Deucher kv_start_dpm(rdev); 124841a524abSAlex Deucher ret = kv_enable_didt(rdev, true); 124941a524abSAlex Deucher if (ret) { 125041a524abSAlex Deucher DRM_ERROR("kv_enable_didt failed\n"); 125141a524abSAlex Deucher return ret; 125241a524abSAlex Deucher } 125341a524abSAlex Deucher ret = kv_enable_smc_cac(rdev, true); 125441a524abSAlex Deucher if (ret) { 125541a524abSAlex Deucher DRM_ERROR("kv_enable_smc_cac failed\n"); 125641a524abSAlex Deucher return ret; 125741a524abSAlex Deucher } 125841a524abSAlex Deucher 1259136de91eSAlex Deucher kv_reset_acp_boot_level(rdev); 1260136de91eSAlex Deucher 126164d03221SAlex Deucher ret = kv_smc_bapm_enable(rdev, false); 126264d03221SAlex Deucher if (ret) { 126364d03221SAlex Deucher DRM_ERROR("kv_smc_bapm_enable failed\n"); 126464d03221SAlex Deucher return ret; 126564d03221SAlex Deucher } 126664d03221SAlex Deucher 126741a524abSAlex Deucher kv_update_current_ps(rdev, rdev->pm.dpm.boot_ps); 126841a524abSAlex Deucher 126941a524abSAlex Deucher return ret; 127041a524abSAlex Deucher } 127141a524abSAlex Deucher 1272d8852c34SAlex Deucher int kv_dpm_late_enable(struct radeon_device *rdev) 1273d8852c34SAlex Deucher { 12747c7e867cSDave Jones int ret = 0; 1275d8852c34SAlex Deucher 1276d8852c34SAlex Deucher if (rdev->irq.installed && 1277d8852c34SAlex Deucher r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { 1278d8852c34SAlex Deucher ret = kv_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); 1279d8852c34SAlex Deucher if (ret) { 1280d8852c34SAlex Deucher DRM_ERROR("kv_set_thermal_temperature_range failed\n"); 1281d8852c34SAlex Deucher return ret; 1282d8852c34SAlex Deucher } 1283d8852c34SAlex Deucher rdev->irq.dpm_thermal = true; 1284d8852c34SAlex Deucher radeon_irq_set(rdev); 1285d8852c34SAlex Deucher } 1286d8852c34SAlex Deucher 1287d8852c34SAlex Deucher /* powerdown unused blocks for now */ 1288d8852c34SAlex Deucher kv_dpm_powergate_acp(rdev, true); 1289d8852c34SAlex Deucher kv_dpm_powergate_samu(rdev, true); 1290d8852c34SAlex Deucher kv_dpm_powergate_vce(rdev, true); 1291d8852c34SAlex Deucher kv_dpm_powergate_uvd(rdev, true); 1292d8852c34SAlex Deucher 1293d8852c34SAlex Deucher return ret; 1294d8852c34SAlex Deucher } 1295d8852c34SAlex Deucher 129641a524abSAlex Deucher void kv_dpm_disable(struct radeon_device *rdev) 129741a524abSAlex Deucher { 129864d03221SAlex Deucher kv_smc_bapm_enable(rdev, false); 129964d03221SAlex Deucher 130039da0384SAlex Deucher if (rdev->family == CHIP_MULLINS) 130139da0384SAlex Deucher kv_enable_nb_dpm(rdev, false); 130239da0384SAlex Deucher 130339c88ae3SAlex Deucher /* powerup blocks */ 130439c88ae3SAlex Deucher kv_dpm_powergate_acp(rdev, false); 130539c88ae3SAlex Deucher kv_dpm_powergate_samu(rdev, false); 130639c88ae3SAlex Deucher kv_dpm_powergate_vce(rdev, false); 130739c88ae3SAlex Deucher kv_dpm_powergate_uvd(rdev, false); 130839c88ae3SAlex Deucher 130941a524abSAlex Deucher kv_enable_smc_cac(rdev, false); 131041a524abSAlex Deucher kv_enable_didt(rdev, false); 131141a524abSAlex Deucher kv_clear_vc(rdev); 131241a524abSAlex Deucher kv_stop_dpm(rdev); 131341a524abSAlex Deucher kv_enable_ulv(rdev, false); 131441a524abSAlex Deucher kv_reset_am(rdev); 131541a524abSAlex Deucher 131641a524abSAlex Deucher kv_update_current_ps(rdev, rdev->pm.dpm.boot_ps); 131741a524abSAlex Deucher } 131841a524abSAlex Deucher 131941a524abSAlex Deucher #if 0 132041a524abSAlex Deucher static int kv_write_smc_soft_register(struct radeon_device *rdev, 132141a524abSAlex Deucher u16 reg_offset, u32 value) 132241a524abSAlex Deucher { 132341a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 132441a524abSAlex Deucher 132541a524abSAlex Deucher return kv_copy_bytes_to_smc(rdev, pi->soft_regs_start + reg_offset, 132641a524abSAlex Deucher (u8 *)&value, sizeof(u16), pi->sram_end); 132741a524abSAlex Deucher } 132841a524abSAlex Deucher 132941a524abSAlex Deucher static int kv_read_smc_soft_register(struct radeon_device *rdev, 133041a524abSAlex Deucher u16 reg_offset, u32 *value) 133141a524abSAlex Deucher { 133241a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 133341a524abSAlex Deucher 133441a524abSAlex Deucher return kv_read_smc_sram_dword(rdev, pi->soft_regs_start + reg_offset, 133541a524abSAlex Deucher value, pi->sram_end); 133641a524abSAlex Deucher } 133741a524abSAlex Deucher #endif 133841a524abSAlex Deucher 133941a524abSAlex Deucher static void kv_init_sclk_t(struct radeon_device *rdev) 134041a524abSAlex Deucher { 134141a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 134241a524abSAlex Deucher 134341a524abSAlex Deucher pi->low_sclk_interrupt_t = 0; 134441a524abSAlex Deucher } 134541a524abSAlex Deucher 134641a524abSAlex Deucher static int kv_init_fps_limits(struct radeon_device *rdev) 134741a524abSAlex Deucher { 134841a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 134941a524abSAlex Deucher int ret = 0; 135041a524abSAlex Deucher 135141a524abSAlex Deucher if (pi->caps_fps) { 135241a524abSAlex Deucher u16 tmp; 135341a524abSAlex Deucher 135441a524abSAlex Deucher tmp = 45; 135541a524abSAlex Deucher pi->fps_high_t = cpu_to_be16(tmp); 135641a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 135741a524abSAlex Deucher pi->dpm_table_start + 135841a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, FpsHighT), 135941a524abSAlex Deucher (u8 *)&pi->fps_high_t, 136041a524abSAlex Deucher sizeof(u16), pi->sram_end); 136141a524abSAlex Deucher 136241a524abSAlex Deucher tmp = 30; 136341a524abSAlex Deucher pi->fps_low_t = cpu_to_be16(tmp); 136441a524abSAlex Deucher 136541a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 136641a524abSAlex Deucher pi->dpm_table_start + 136741a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, FpsLowT), 136841a524abSAlex Deucher (u8 *)&pi->fps_low_t, 136941a524abSAlex Deucher sizeof(u16), pi->sram_end); 137041a524abSAlex Deucher 137141a524abSAlex Deucher } 137241a524abSAlex Deucher return ret; 137341a524abSAlex Deucher } 137441a524abSAlex Deucher 137541a524abSAlex Deucher static void kv_init_powergate_state(struct radeon_device *rdev) 137641a524abSAlex Deucher { 137741a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 137841a524abSAlex Deucher 137941a524abSAlex Deucher pi->uvd_power_gated = false; 138041a524abSAlex Deucher pi->vce_power_gated = false; 138141a524abSAlex Deucher pi->samu_power_gated = false; 138241a524abSAlex Deucher pi->acp_power_gated = false; 138341a524abSAlex Deucher 138441a524abSAlex Deucher } 138541a524abSAlex Deucher 138641a524abSAlex Deucher static int kv_enable_uvd_dpm(struct radeon_device *rdev, bool enable) 138741a524abSAlex Deucher { 138841a524abSAlex Deucher return kv_notify_message_to_smu(rdev, enable ? 138941a524abSAlex Deucher PPSMC_MSG_UVDDPM_Enable : PPSMC_MSG_UVDDPM_Disable); 139041a524abSAlex Deucher } 139141a524abSAlex Deucher 139241a524abSAlex Deucher static int kv_enable_vce_dpm(struct radeon_device *rdev, bool enable) 139341a524abSAlex Deucher { 139441a524abSAlex Deucher return kv_notify_message_to_smu(rdev, enable ? 139541a524abSAlex Deucher PPSMC_MSG_VCEDPM_Enable : PPSMC_MSG_VCEDPM_Disable); 139641a524abSAlex Deucher } 139741a524abSAlex Deucher 139841a524abSAlex Deucher static int kv_enable_samu_dpm(struct radeon_device *rdev, bool enable) 139941a524abSAlex Deucher { 140041a524abSAlex Deucher return kv_notify_message_to_smu(rdev, enable ? 140141a524abSAlex Deucher PPSMC_MSG_SAMUDPM_Enable : PPSMC_MSG_SAMUDPM_Disable); 140241a524abSAlex Deucher } 140341a524abSAlex Deucher 140441a524abSAlex Deucher static int kv_enable_acp_dpm(struct radeon_device *rdev, bool enable) 140541a524abSAlex Deucher { 140641a524abSAlex Deucher return kv_notify_message_to_smu(rdev, enable ? 140741a524abSAlex Deucher PPSMC_MSG_ACPDPM_Enable : PPSMC_MSG_ACPDPM_Disable); 140841a524abSAlex Deucher } 140941a524abSAlex Deucher 141041a524abSAlex Deucher static int kv_update_uvd_dpm(struct radeon_device *rdev, bool gate) 141141a524abSAlex Deucher { 141241a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 141341a524abSAlex Deucher struct radeon_uvd_clock_voltage_dependency_table *table = 141441a524abSAlex Deucher &rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table; 141541a524abSAlex Deucher int ret; 141647f5c746SAlex Deucher u32 mask; 141741a524abSAlex Deucher 141841a524abSAlex Deucher if (!gate) { 141947f5c746SAlex Deucher if (table->count) 142041a524abSAlex Deucher pi->uvd_boot_level = table->count - 1; 142141a524abSAlex Deucher else 142241a524abSAlex Deucher pi->uvd_boot_level = 0; 142341a524abSAlex Deucher 142447f5c746SAlex Deucher if (!pi->caps_uvd_dpm || pi->caps_stable_p_state) { 142547f5c746SAlex Deucher mask = 1 << pi->uvd_boot_level; 142647f5c746SAlex Deucher } else { 142747f5c746SAlex Deucher mask = 0x1f; 142847f5c746SAlex Deucher } 142947f5c746SAlex Deucher 143041a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 143141a524abSAlex Deucher pi->dpm_table_start + 143241a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, UvdBootLevel), 143341a524abSAlex Deucher (uint8_t *)&pi->uvd_boot_level, 143441a524abSAlex Deucher sizeof(u8), pi->sram_end); 143541a524abSAlex Deucher if (ret) 143641a524abSAlex Deucher return ret; 143741a524abSAlex Deucher 143841a524abSAlex Deucher kv_send_msg_to_smc_with_parameter(rdev, 143941a524abSAlex Deucher PPSMC_MSG_UVDDPM_SetEnabledMask, 144047f5c746SAlex Deucher mask); 144141a524abSAlex Deucher } 144241a524abSAlex Deucher 144341a524abSAlex Deucher return kv_enable_uvd_dpm(rdev, !gate); 144441a524abSAlex Deucher } 144541a524abSAlex Deucher 1446c83dec3bSAlex Deucher static u8 kv_get_vce_boot_level(struct radeon_device *rdev, u32 evclk) 144741a524abSAlex Deucher { 144841a524abSAlex Deucher u8 i; 144941a524abSAlex Deucher struct radeon_vce_clock_voltage_dependency_table *table = 145041a524abSAlex Deucher &rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table; 145141a524abSAlex Deucher 145241a524abSAlex Deucher for (i = 0; i < table->count; i++) { 1453c83dec3bSAlex Deucher if (table->entries[i].evclk >= evclk) 145441a524abSAlex Deucher break; 145541a524abSAlex Deucher } 145641a524abSAlex Deucher 145741a524abSAlex Deucher return i; 145841a524abSAlex Deucher } 145941a524abSAlex Deucher 146041a524abSAlex Deucher static int kv_update_vce_dpm(struct radeon_device *rdev, 146141a524abSAlex Deucher struct radeon_ps *radeon_new_state, 146241a524abSAlex Deucher struct radeon_ps *radeon_current_state) 146341a524abSAlex Deucher { 146441a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 146541a524abSAlex Deucher struct radeon_vce_clock_voltage_dependency_table *table = 146641a524abSAlex Deucher &rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table; 146741a524abSAlex Deucher int ret; 146841a524abSAlex Deucher 146941a524abSAlex Deucher if (radeon_new_state->evclk > 0 && radeon_current_state->evclk == 0) { 147042332905SAlex Deucher kv_dpm_powergate_vce(rdev, false); 1471a1d6f97cSAlex Deucher /* turn the clocks on when encoding */ 1472a1d6f97cSAlex Deucher cik_update_cg(rdev, RADEON_CG_BLOCK_VCE, false); 147341a524abSAlex Deucher if (pi->caps_stable_p_state) 147441a524abSAlex Deucher pi->vce_boot_level = table->count - 1; 147541a524abSAlex Deucher else 1476c83dec3bSAlex Deucher pi->vce_boot_level = kv_get_vce_boot_level(rdev, radeon_new_state->evclk); 147741a524abSAlex Deucher 147841a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 147941a524abSAlex Deucher pi->dpm_table_start + 148041a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, VceBootLevel), 148141a524abSAlex Deucher (u8 *)&pi->vce_boot_level, 148241a524abSAlex Deucher sizeof(u8), 148341a524abSAlex Deucher pi->sram_end); 148441a524abSAlex Deucher if (ret) 148541a524abSAlex Deucher return ret; 148641a524abSAlex Deucher 148741a524abSAlex Deucher if (pi->caps_stable_p_state) 148841a524abSAlex Deucher kv_send_msg_to_smc_with_parameter(rdev, 148941a524abSAlex Deucher PPSMC_MSG_VCEDPM_SetEnabledMask, 149041a524abSAlex Deucher (1 << pi->vce_boot_level)); 149141a524abSAlex Deucher 149241a524abSAlex Deucher kv_enable_vce_dpm(rdev, true); 149341a524abSAlex Deucher } else if (radeon_new_state->evclk == 0 && radeon_current_state->evclk > 0) { 149441a524abSAlex Deucher kv_enable_vce_dpm(rdev, false); 1495a1d6f97cSAlex Deucher /* turn the clocks off when not encoding */ 1496a1d6f97cSAlex Deucher cik_update_cg(rdev, RADEON_CG_BLOCK_VCE, true); 149742332905SAlex Deucher kv_dpm_powergate_vce(rdev, true); 149841a524abSAlex Deucher } 149941a524abSAlex Deucher 150041a524abSAlex Deucher return 0; 150141a524abSAlex Deucher } 150241a524abSAlex Deucher 150341a524abSAlex Deucher static int kv_update_samu_dpm(struct radeon_device *rdev, bool gate) 150441a524abSAlex Deucher { 150541a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 150641a524abSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 150741a524abSAlex Deucher &rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table; 150841a524abSAlex Deucher int ret; 150941a524abSAlex Deucher 151041a524abSAlex Deucher if (!gate) { 151141a524abSAlex Deucher if (pi->caps_stable_p_state) 151241a524abSAlex Deucher pi->samu_boot_level = table->count - 1; 151341a524abSAlex Deucher else 151441a524abSAlex Deucher pi->samu_boot_level = 0; 151541a524abSAlex Deucher 151641a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 151741a524abSAlex Deucher pi->dpm_table_start + 151841a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, SamuBootLevel), 151941a524abSAlex Deucher (u8 *)&pi->samu_boot_level, 152041a524abSAlex Deucher sizeof(u8), 152141a524abSAlex Deucher pi->sram_end); 152241a524abSAlex Deucher if (ret) 152341a524abSAlex Deucher return ret; 152441a524abSAlex Deucher 152541a524abSAlex Deucher if (pi->caps_stable_p_state) 152641a524abSAlex Deucher kv_send_msg_to_smc_with_parameter(rdev, 152741a524abSAlex Deucher PPSMC_MSG_SAMUDPM_SetEnabledMask, 152841a524abSAlex Deucher (1 << pi->samu_boot_level)); 152941a524abSAlex Deucher } 153041a524abSAlex Deucher 153141a524abSAlex Deucher return kv_enable_samu_dpm(rdev, !gate); 153241a524abSAlex Deucher } 153341a524abSAlex Deucher 1534136de91eSAlex Deucher static u8 kv_get_acp_boot_level(struct radeon_device *rdev) 1535136de91eSAlex Deucher { 1536136de91eSAlex Deucher u8 i; 1537136de91eSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 1538136de91eSAlex Deucher &rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table; 1539136de91eSAlex Deucher 1540136de91eSAlex Deucher for (i = 0; i < table->count; i++) { 1541136de91eSAlex Deucher if (table->entries[i].clk >= 0) /* XXX */ 1542136de91eSAlex Deucher break; 1543136de91eSAlex Deucher } 1544136de91eSAlex Deucher 1545136de91eSAlex Deucher if (i >= table->count) 1546136de91eSAlex Deucher i = table->count - 1; 1547136de91eSAlex Deucher 1548136de91eSAlex Deucher return i; 1549136de91eSAlex Deucher } 1550136de91eSAlex Deucher 1551136de91eSAlex Deucher static void kv_update_acp_boot_level(struct radeon_device *rdev) 1552136de91eSAlex Deucher { 1553136de91eSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 1554136de91eSAlex Deucher u8 acp_boot_level; 1555136de91eSAlex Deucher 1556136de91eSAlex Deucher if (!pi->caps_stable_p_state) { 1557136de91eSAlex Deucher acp_boot_level = kv_get_acp_boot_level(rdev); 1558136de91eSAlex Deucher if (acp_boot_level != pi->acp_boot_level) { 1559136de91eSAlex Deucher pi->acp_boot_level = acp_boot_level; 1560136de91eSAlex Deucher kv_send_msg_to_smc_with_parameter(rdev, 1561136de91eSAlex Deucher PPSMC_MSG_ACPDPM_SetEnabledMask, 1562136de91eSAlex Deucher (1 << pi->acp_boot_level)); 1563136de91eSAlex Deucher } 1564136de91eSAlex Deucher } 1565136de91eSAlex Deucher } 1566136de91eSAlex Deucher 156741a524abSAlex Deucher static int kv_update_acp_dpm(struct radeon_device *rdev, bool gate) 156841a524abSAlex Deucher { 156941a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 157041a524abSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 157141a524abSAlex Deucher &rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table; 157241a524abSAlex Deucher int ret; 157341a524abSAlex Deucher 157441a524abSAlex Deucher if (!gate) { 157541a524abSAlex Deucher if (pi->caps_stable_p_state) 157641a524abSAlex Deucher pi->acp_boot_level = table->count - 1; 157741a524abSAlex Deucher else 1578136de91eSAlex Deucher pi->acp_boot_level = kv_get_acp_boot_level(rdev); 157941a524abSAlex Deucher 158041a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 158141a524abSAlex Deucher pi->dpm_table_start + 158241a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, AcpBootLevel), 158341a524abSAlex Deucher (u8 *)&pi->acp_boot_level, 158441a524abSAlex Deucher sizeof(u8), 158541a524abSAlex Deucher pi->sram_end); 158641a524abSAlex Deucher if (ret) 158741a524abSAlex Deucher return ret; 158841a524abSAlex Deucher 158941a524abSAlex Deucher if (pi->caps_stable_p_state) 159041a524abSAlex Deucher kv_send_msg_to_smc_with_parameter(rdev, 159141a524abSAlex Deucher PPSMC_MSG_ACPDPM_SetEnabledMask, 159241a524abSAlex Deucher (1 << pi->acp_boot_level)); 159341a524abSAlex Deucher } 159441a524abSAlex Deucher 159541a524abSAlex Deucher return kv_enable_acp_dpm(rdev, !gate); 159641a524abSAlex Deucher } 159741a524abSAlex Deucher 159877df508aSAlex Deucher void kv_dpm_powergate_uvd(struct radeon_device *rdev, bool gate) 159941a524abSAlex Deucher { 160041a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 160141a524abSAlex Deucher 160241a524abSAlex Deucher if (pi->uvd_power_gated == gate) 160341a524abSAlex Deucher return; 160441a524abSAlex Deucher 160541a524abSAlex Deucher pi->uvd_power_gated = gate; 160641a524abSAlex Deucher 160741a524abSAlex Deucher if (gate) { 1608f30df435SAlex Deucher if (pi->caps_uvd_pg) { 1609e409b128SChristian König uvd_v1_0_stop(rdev); 161077df508aSAlex Deucher cik_update_cg(rdev, RADEON_CG_BLOCK_UVD, false); 1611f30df435SAlex Deucher } 161277df508aSAlex Deucher kv_update_uvd_dpm(rdev, gate); 161341a524abSAlex Deucher if (pi->caps_uvd_pg) 161441a524abSAlex Deucher kv_notify_message_to_smu(rdev, PPSMC_MSG_UVDPowerOFF); 161541a524abSAlex Deucher } else { 1616f30df435SAlex Deucher if (pi->caps_uvd_pg) { 161741a524abSAlex Deucher kv_notify_message_to_smu(rdev, PPSMC_MSG_UVDPowerON); 1618e409b128SChristian König uvd_v4_2_resume(rdev); 1619e409b128SChristian König uvd_v1_0_start(rdev); 162077df508aSAlex Deucher cik_update_cg(rdev, RADEON_CG_BLOCK_UVD, true); 1621f30df435SAlex Deucher } 162277df508aSAlex Deucher kv_update_uvd_dpm(rdev, gate); 162341a524abSAlex Deucher } 162441a524abSAlex Deucher } 162541a524abSAlex Deucher 162641a524abSAlex Deucher static void kv_dpm_powergate_vce(struct radeon_device *rdev, bool gate) 162741a524abSAlex Deucher { 162841a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 162941a524abSAlex Deucher 163041a524abSAlex Deucher if (pi->vce_power_gated == gate) 163141a524abSAlex Deucher return; 163241a524abSAlex Deucher 163341a524abSAlex Deucher pi->vce_power_gated = gate; 163441a524abSAlex Deucher 163541a524abSAlex Deucher if (gate) { 163644493ba9SAlex Deucher if (pi->caps_vce_pg) { 163744493ba9SAlex Deucher /* XXX do we need a vce_v1_0_stop() ? */ 163841a524abSAlex Deucher kv_notify_message_to_smu(rdev, PPSMC_MSG_VCEPowerOFF); 163944493ba9SAlex Deucher } 164041a524abSAlex Deucher } else { 164144493ba9SAlex Deucher if (pi->caps_vce_pg) { 164241a524abSAlex Deucher kv_notify_message_to_smu(rdev, PPSMC_MSG_VCEPowerON); 164344493ba9SAlex Deucher vce_v2_0_resume(rdev); 164444493ba9SAlex Deucher vce_v1_0_start(rdev); 164544493ba9SAlex Deucher } 164641a524abSAlex Deucher } 164741a524abSAlex Deucher } 164841a524abSAlex Deucher 164941a524abSAlex Deucher static void kv_dpm_powergate_samu(struct radeon_device *rdev, bool gate) 165041a524abSAlex Deucher { 165141a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 165241a524abSAlex Deucher 165341a524abSAlex Deucher if (pi->samu_power_gated == gate) 165441a524abSAlex Deucher return; 165541a524abSAlex Deucher 165641a524abSAlex Deucher pi->samu_power_gated = gate; 165741a524abSAlex Deucher 165841a524abSAlex Deucher if (gate) { 165941a524abSAlex Deucher kv_update_samu_dpm(rdev, true); 166041a524abSAlex Deucher if (pi->caps_samu_pg) 166141a524abSAlex Deucher kv_notify_message_to_smu(rdev, PPSMC_MSG_SAMPowerOFF); 166241a524abSAlex Deucher } else { 166341a524abSAlex Deucher if (pi->caps_samu_pg) 166441a524abSAlex Deucher kv_notify_message_to_smu(rdev, PPSMC_MSG_SAMPowerON); 166541a524abSAlex Deucher kv_update_samu_dpm(rdev, false); 166641a524abSAlex Deucher } 166741a524abSAlex Deucher } 166841a524abSAlex Deucher 166941a524abSAlex Deucher static void kv_dpm_powergate_acp(struct radeon_device *rdev, bool gate) 167041a524abSAlex Deucher { 167141a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 167241a524abSAlex Deucher 167341a524abSAlex Deucher if (pi->acp_power_gated == gate) 167441a524abSAlex Deucher return; 167541a524abSAlex Deucher 16767d032a4bSSamuel Li if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) 167741a524abSAlex Deucher return; 167841a524abSAlex Deucher 167941a524abSAlex Deucher pi->acp_power_gated = gate; 168041a524abSAlex Deucher 168141a524abSAlex Deucher if (gate) { 168241a524abSAlex Deucher kv_update_acp_dpm(rdev, true); 168341a524abSAlex Deucher if (pi->caps_acp_pg) 168441a524abSAlex Deucher kv_notify_message_to_smu(rdev, PPSMC_MSG_ACPPowerOFF); 168541a524abSAlex Deucher } else { 168641a524abSAlex Deucher if (pi->caps_acp_pg) 168741a524abSAlex Deucher kv_notify_message_to_smu(rdev, PPSMC_MSG_ACPPowerON); 168841a524abSAlex Deucher kv_update_acp_dpm(rdev, false); 168941a524abSAlex Deucher } 169041a524abSAlex Deucher } 169141a524abSAlex Deucher 169241a524abSAlex Deucher static void kv_set_valid_clock_range(struct radeon_device *rdev, 169341a524abSAlex Deucher struct radeon_ps *new_rps) 169441a524abSAlex Deucher { 169541a524abSAlex Deucher struct kv_ps *new_ps = kv_get_ps(new_rps); 169641a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 169741a524abSAlex Deucher u32 i; 169841a524abSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 169941a524abSAlex Deucher &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; 170041a524abSAlex Deucher 170141a524abSAlex Deucher if (table && table->count) { 170241a524abSAlex Deucher for (i = 0; i < pi->graphics_dpm_level_count; i++) { 170341a524abSAlex Deucher if ((table->entries[i].clk >= new_ps->levels[0].sclk) || 170441a524abSAlex Deucher (i == (pi->graphics_dpm_level_count - 1))) { 170541a524abSAlex Deucher pi->lowest_valid = i; 170641a524abSAlex Deucher break; 170741a524abSAlex Deucher } 170841a524abSAlex Deucher } 170941a524abSAlex Deucher 17108c5c6fadSDan Carpenter for (i = pi->graphics_dpm_level_count - 1; i > 0; i--) { 17118c5c6fadSDan Carpenter if (table->entries[i].clk <= new_ps->levels[new_ps->num_levels - 1].sclk) 171241a524abSAlex Deucher break; 171341a524abSAlex Deucher } 17148c5c6fadSDan Carpenter pi->highest_valid = i; 171541a524abSAlex Deucher 171641a524abSAlex Deucher if (pi->lowest_valid > pi->highest_valid) { 171741a524abSAlex Deucher if ((new_ps->levels[0].sclk - table->entries[pi->highest_valid].clk) > 171841a524abSAlex Deucher (table->entries[pi->lowest_valid].clk - new_ps->levels[new_ps->num_levels - 1].sclk)) 171941a524abSAlex Deucher pi->highest_valid = pi->lowest_valid; 172041a524abSAlex Deucher else 172141a524abSAlex Deucher pi->lowest_valid = pi->highest_valid; 172241a524abSAlex Deucher } 172341a524abSAlex Deucher } else { 172441a524abSAlex Deucher struct sumo_sclk_voltage_mapping_table *table = 172541a524abSAlex Deucher &pi->sys_info.sclk_voltage_mapping_table; 172641a524abSAlex Deucher 172741a524abSAlex Deucher for (i = 0; i < (int)pi->graphics_dpm_level_count; i++) { 172841a524abSAlex Deucher if (table->entries[i].sclk_frequency >= new_ps->levels[0].sclk || 172941a524abSAlex Deucher i == (int)(pi->graphics_dpm_level_count - 1)) { 173041a524abSAlex Deucher pi->lowest_valid = i; 173141a524abSAlex Deucher break; 173241a524abSAlex Deucher } 173341a524abSAlex Deucher } 173441a524abSAlex Deucher 17358c5c6fadSDan Carpenter for (i = pi->graphics_dpm_level_count - 1; i > 0; i--) { 173641a524abSAlex Deucher if (table->entries[i].sclk_frequency <= 17378c5c6fadSDan Carpenter new_ps->levels[new_ps->num_levels - 1].sclk) 173841a524abSAlex Deucher break; 173941a524abSAlex Deucher } 17408c5c6fadSDan Carpenter pi->highest_valid = i; 174141a524abSAlex Deucher 174241a524abSAlex Deucher if (pi->lowest_valid > pi->highest_valid) { 174341a524abSAlex Deucher if ((new_ps->levels[0].sclk - 174441a524abSAlex Deucher table->entries[pi->highest_valid].sclk_frequency) > 174541a524abSAlex Deucher (table->entries[pi->lowest_valid].sclk_frequency - 174641a524abSAlex Deucher new_ps->levels[new_ps->num_levels -1].sclk)) 174741a524abSAlex Deucher pi->highest_valid = pi->lowest_valid; 174841a524abSAlex Deucher else 174941a524abSAlex Deucher pi->lowest_valid = pi->highest_valid; 175041a524abSAlex Deucher } 175141a524abSAlex Deucher } 175241a524abSAlex Deucher } 175341a524abSAlex Deucher 175441a524abSAlex Deucher static int kv_update_dfs_bypass_settings(struct radeon_device *rdev, 175541a524abSAlex Deucher struct radeon_ps *new_rps) 175641a524abSAlex Deucher { 175741a524abSAlex Deucher struct kv_ps *new_ps = kv_get_ps(new_rps); 175841a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 175941a524abSAlex Deucher int ret = 0; 176041a524abSAlex Deucher u8 clk_bypass_cntl; 176141a524abSAlex Deucher 176241a524abSAlex Deucher if (pi->caps_enable_dfs_bypass) { 176341a524abSAlex Deucher clk_bypass_cntl = new_ps->need_dfs_bypass ? 176441a524abSAlex Deucher pi->graphics_level[pi->graphics_boot_level].ClkBypassCntl : 0; 176541a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 176641a524abSAlex Deucher (pi->dpm_table_start + 176741a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, GraphicsLevel) + 176841a524abSAlex Deucher (pi->graphics_boot_level * sizeof(SMU7_Fusion_GraphicsLevel)) + 176941a524abSAlex Deucher offsetof(SMU7_Fusion_GraphicsLevel, ClkBypassCntl)), 177041a524abSAlex Deucher &clk_bypass_cntl, 177141a524abSAlex Deucher sizeof(u8), pi->sram_end); 177241a524abSAlex Deucher } 177341a524abSAlex Deucher 177441a524abSAlex Deucher return ret; 177541a524abSAlex Deucher } 177641a524abSAlex Deucher 177739da0384SAlex Deucher static int kv_enable_nb_dpm(struct radeon_device *rdev, 177839da0384SAlex Deucher bool enable) 177941a524abSAlex Deucher { 178041a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 178141a524abSAlex Deucher int ret = 0; 178241a524abSAlex Deucher 178339da0384SAlex Deucher if (enable) { 178441a524abSAlex Deucher if (pi->enable_nb_dpm && !pi->nb_dpm_enabled) { 178541a524abSAlex Deucher ret = kv_notify_message_to_smu(rdev, PPSMC_MSG_NBDPM_Enable); 178641a524abSAlex Deucher if (ret == 0) 178741a524abSAlex Deucher pi->nb_dpm_enabled = true; 178841a524abSAlex Deucher } 178939da0384SAlex Deucher } else { 179039da0384SAlex Deucher if (pi->enable_nb_dpm && pi->nb_dpm_enabled) { 179139da0384SAlex Deucher ret = kv_notify_message_to_smu(rdev, PPSMC_MSG_NBDPM_Disable); 179239da0384SAlex Deucher if (ret == 0) 179339da0384SAlex Deucher pi->nb_dpm_enabled = false; 179439da0384SAlex Deucher } 179539da0384SAlex Deucher } 179641a524abSAlex Deucher 179741a524abSAlex Deucher return ret; 179841a524abSAlex Deucher } 179941a524abSAlex Deucher 18002b4c8022SAlex Deucher int kv_dpm_force_performance_level(struct radeon_device *rdev, 18012b4c8022SAlex Deucher enum radeon_dpm_forced_level level) 18022b4c8022SAlex Deucher { 18032b4c8022SAlex Deucher int ret; 18042b4c8022SAlex Deucher 18052b4c8022SAlex Deucher if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { 18062b4c8022SAlex Deucher ret = kv_force_dpm_highest(rdev); 18072b4c8022SAlex Deucher if (ret) 18082b4c8022SAlex Deucher return ret; 18092b4c8022SAlex Deucher } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) { 18102b4c8022SAlex Deucher ret = kv_force_dpm_lowest(rdev); 18112b4c8022SAlex Deucher if (ret) 18122b4c8022SAlex Deucher return ret; 18132b4c8022SAlex Deucher } else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) { 18142b4c8022SAlex Deucher ret = kv_unforce_levels(rdev); 18152b4c8022SAlex Deucher if (ret) 18162b4c8022SAlex Deucher return ret; 18172b4c8022SAlex Deucher } 18182b4c8022SAlex Deucher 18192b4c8022SAlex Deucher rdev->pm.dpm.forced_level = level; 18202b4c8022SAlex Deucher 18212b4c8022SAlex Deucher return 0; 18222b4c8022SAlex Deucher } 18232b4c8022SAlex Deucher 182441a524abSAlex Deucher int kv_dpm_pre_set_power_state(struct radeon_device *rdev) 182541a524abSAlex Deucher { 182641a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 182741a524abSAlex Deucher struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps; 182841a524abSAlex Deucher struct radeon_ps *new_ps = &requested_ps; 182941a524abSAlex Deucher 183041a524abSAlex Deucher kv_update_requested_ps(rdev, new_ps); 183141a524abSAlex Deucher 183241a524abSAlex Deucher kv_apply_state_adjust_rules(rdev, 183341a524abSAlex Deucher &pi->requested_rps, 183441a524abSAlex Deucher &pi->current_rps); 183541a524abSAlex Deucher 183641a524abSAlex Deucher return 0; 183741a524abSAlex Deucher } 183841a524abSAlex Deucher 183941a524abSAlex Deucher int kv_dpm_set_power_state(struct radeon_device *rdev) 184041a524abSAlex Deucher { 184141a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 184241a524abSAlex Deucher struct radeon_ps *new_ps = &pi->requested_rps; 184342332905SAlex Deucher struct radeon_ps *old_ps = &pi->current_rps; 184441a524abSAlex Deucher int ret; 184541a524abSAlex Deucher 1846b7a5ae97SAlex Deucher if (pi->bapm_enable) { 1847b7a5ae97SAlex Deucher ret = kv_smc_bapm_enable(rdev, rdev->pm.dpm.ac_power); 1848b7a5ae97SAlex Deucher if (ret) { 1849b7a5ae97SAlex Deucher DRM_ERROR("kv_smc_bapm_enable failed\n"); 1850b7a5ae97SAlex Deucher return ret; 1851b7a5ae97SAlex Deucher } 1852b7a5ae97SAlex Deucher } 1853b7a5ae97SAlex Deucher 18547d032a4bSSamuel Li if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) { 185541a524abSAlex Deucher if (pi->enable_dpm) { 185641a524abSAlex Deucher kv_set_valid_clock_range(rdev, new_ps); 185741a524abSAlex Deucher kv_update_dfs_bypass_settings(rdev, new_ps); 185841a524abSAlex Deucher ret = kv_calculate_ds_divider(rdev); 185941a524abSAlex Deucher if (ret) { 186041a524abSAlex Deucher DRM_ERROR("kv_calculate_ds_divider failed\n"); 186141a524abSAlex Deucher return ret; 186241a524abSAlex Deucher } 186341a524abSAlex Deucher kv_calculate_nbps_level_settings(rdev); 186441a524abSAlex Deucher kv_calculate_dpm_settings(rdev); 186541a524abSAlex Deucher kv_force_lowest_valid(rdev); 186641a524abSAlex Deucher kv_enable_new_levels(rdev); 186741a524abSAlex Deucher kv_upload_dpm_settings(rdev); 186841a524abSAlex Deucher kv_program_nbps_index_settings(rdev, new_ps); 186941a524abSAlex Deucher kv_unforce_levels(rdev); 187041a524abSAlex Deucher kv_set_enabled_levels(rdev); 187141a524abSAlex Deucher kv_force_lowest_valid(rdev); 187241a524abSAlex Deucher kv_unforce_levels(rdev); 187342332905SAlex Deucher 187441a524abSAlex Deucher ret = kv_update_vce_dpm(rdev, new_ps, old_ps); 187541a524abSAlex Deucher if (ret) { 187641a524abSAlex Deucher DRM_ERROR("kv_update_vce_dpm failed\n"); 187741a524abSAlex Deucher return ret; 187841a524abSAlex Deucher } 187941a524abSAlex Deucher kv_update_sclk_t(rdev); 188047f5c746SAlex Deucher if (rdev->family == CHIP_MULLINS) 188139da0384SAlex Deucher kv_enable_nb_dpm(rdev, true); 188241a524abSAlex Deucher } 188341a524abSAlex Deucher } else { 188441a524abSAlex Deucher if (pi->enable_dpm) { 188541a524abSAlex Deucher kv_set_valid_clock_range(rdev, new_ps); 188641a524abSAlex Deucher kv_update_dfs_bypass_settings(rdev, new_ps); 188741a524abSAlex Deucher ret = kv_calculate_ds_divider(rdev); 188841a524abSAlex Deucher if (ret) { 188941a524abSAlex Deucher DRM_ERROR("kv_calculate_ds_divider failed\n"); 189041a524abSAlex Deucher return ret; 189141a524abSAlex Deucher } 189241a524abSAlex Deucher kv_calculate_nbps_level_settings(rdev); 189341a524abSAlex Deucher kv_calculate_dpm_settings(rdev); 189441a524abSAlex Deucher kv_freeze_sclk_dpm(rdev, true); 189541a524abSAlex Deucher kv_upload_dpm_settings(rdev); 189641a524abSAlex Deucher kv_program_nbps_index_settings(rdev, new_ps); 189741a524abSAlex Deucher kv_freeze_sclk_dpm(rdev, false); 189841a524abSAlex Deucher kv_set_enabled_levels(rdev); 189941a524abSAlex Deucher ret = kv_update_vce_dpm(rdev, new_ps, old_ps); 190041a524abSAlex Deucher if (ret) { 190141a524abSAlex Deucher DRM_ERROR("kv_update_vce_dpm failed\n"); 190241a524abSAlex Deucher return ret; 190341a524abSAlex Deucher } 1904136de91eSAlex Deucher kv_update_acp_boot_level(rdev); 190541a524abSAlex Deucher kv_update_sclk_t(rdev); 190639da0384SAlex Deucher kv_enable_nb_dpm(rdev, true); 190741a524abSAlex Deucher } 190841a524abSAlex Deucher } 19096500fc0cSAlex Deucher 191041a524abSAlex Deucher return 0; 191141a524abSAlex Deucher } 191241a524abSAlex Deucher 191341a524abSAlex Deucher void kv_dpm_post_set_power_state(struct radeon_device *rdev) 191441a524abSAlex Deucher { 191541a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 191641a524abSAlex Deucher struct radeon_ps *new_ps = &pi->requested_rps; 191741a524abSAlex Deucher 191841a524abSAlex Deucher kv_update_current_ps(rdev, new_ps); 191941a524abSAlex Deucher } 192041a524abSAlex Deucher 192141a524abSAlex Deucher void kv_dpm_setup_asic(struct radeon_device *rdev) 192241a524abSAlex Deucher { 192341a524abSAlex Deucher sumo_take_smu_control(rdev, true); 192441a524abSAlex Deucher kv_init_powergate_state(rdev); 192541a524abSAlex Deucher kv_init_sclk_t(rdev); 192641a524abSAlex Deucher } 192741a524abSAlex Deucher 1928dafc519dSAlex Deucher #if 0 192941a524abSAlex Deucher void kv_dpm_reset_asic(struct radeon_device *rdev) 193041a524abSAlex Deucher { 1931136de91eSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 1932136de91eSAlex Deucher 19337d032a4bSSamuel Li if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) { 193441a524abSAlex Deucher kv_force_lowest_valid(rdev); 193541a524abSAlex Deucher kv_init_graphics_levels(rdev); 193641a524abSAlex Deucher kv_program_bootup_state(rdev); 193741a524abSAlex Deucher kv_upload_dpm_settings(rdev); 193841a524abSAlex Deucher kv_force_lowest_valid(rdev); 193941a524abSAlex Deucher kv_unforce_levels(rdev); 1940136de91eSAlex Deucher } else { 1941136de91eSAlex Deucher kv_init_graphics_levels(rdev); 1942136de91eSAlex Deucher kv_program_bootup_state(rdev); 1943136de91eSAlex Deucher kv_freeze_sclk_dpm(rdev, true); 1944136de91eSAlex Deucher kv_upload_dpm_settings(rdev); 1945136de91eSAlex Deucher kv_freeze_sclk_dpm(rdev, false); 1946136de91eSAlex Deucher kv_set_enabled_level(rdev, pi->graphics_boot_level); 1947136de91eSAlex Deucher } 194841a524abSAlex Deucher } 1949dafc519dSAlex Deucher #endif 195041a524abSAlex Deucher 195141a524abSAlex Deucher //XXX use sumo_dpm_display_configuration_changed 195241a524abSAlex Deucher 195341a524abSAlex Deucher static void kv_construct_max_power_limits_table(struct radeon_device *rdev, 195441a524abSAlex Deucher struct radeon_clock_and_voltage_limits *table) 195541a524abSAlex Deucher { 195641a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 195741a524abSAlex Deucher 195841a524abSAlex Deucher if (pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries > 0) { 195941a524abSAlex Deucher int idx = pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries - 1; 196041a524abSAlex Deucher table->sclk = 196141a524abSAlex Deucher pi->sys_info.sclk_voltage_mapping_table.entries[idx].sclk_frequency; 196241a524abSAlex Deucher table->vddc = 196341a524abSAlex Deucher kv_convert_2bit_index_to_voltage(rdev, 196441a524abSAlex Deucher pi->sys_info.sclk_voltage_mapping_table.entries[idx].vid_2bit); 196541a524abSAlex Deucher } 196641a524abSAlex Deucher 196741a524abSAlex Deucher table->mclk = pi->sys_info.nbp_memory_clock[0]; 196841a524abSAlex Deucher } 196941a524abSAlex Deucher 197041a524abSAlex Deucher static void kv_patch_voltage_values(struct radeon_device *rdev) 197141a524abSAlex Deucher { 197241a524abSAlex Deucher int i; 197347f5c746SAlex Deucher struct radeon_uvd_clock_voltage_dependency_table *uvd_table = 197441a524abSAlex Deucher &rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table; 197547f5c746SAlex Deucher struct radeon_vce_clock_voltage_dependency_table *vce_table = 197647f5c746SAlex Deucher &rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table; 197747f5c746SAlex Deucher struct radeon_clock_voltage_dependency_table *samu_table = 197847f5c746SAlex Deucher &rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table; 197947f5c746SAlex Deucher struct radeon_clock_voltage_dependency_table *acp_table = 198047f5c746SAlex Deucher &rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table; 198141a524abSAlex Deucher 198247f5c746SAlex Deucher if (uvd_table->count) { 198347f5c746SAlex Deucher for (i = 0; i < uvd_table->count; i++) 198447f5c746SAlex Deucher uvd_table->entries[i].v = 198541a524abSAlex Deucher kv_convert_8bit_index_to_voltage(rdev, 198647f5c746SAlex Deucher uvd_table->entries[i].v); 198747f5c746SAlex Deucher } 198847f5c746SAlex Deucher 198947f5c746SAlex Deucher if (vce_table->count) { 199047f5c746SAlex Deucher for (i = 0; i < vce_table->count; i++) 199147f5c746SAlex Deucher vce_table->entries[i].v = 199247f5c746SAlex Deucher kv_convert_8bit_index_to_voltage(rdev, 199347f5c746SAlex Deucher vce_table->entries[i].v); 199447f5c746SAlex Deucher } 199547f5c746SAlex Deucher 199647f5c746SAlex Deucher if (samu_table->count) { 199747f5c746SAlex Deucher for (i = 0; i < samu_table->count; i++) 199847f5c746SAlex Deucher samu_table->entries[i].v = 199947f5c746SAlex Deucher kv_convert_8bit_index_to_voltage(rdev, 200047f5c746SAlex Deucher samu_table->entries[i].v); 200147f5c746SAlex Deucher } 200247f5c746SAlex Deucher 200347f5c746SAlex Deucher if (acp_table->count) { 200447f5c746SAlex Deucher for (i = 0; i < acp_table->count; i++) 200547f5c746SAlex Deucher acp_table->entries[i].v = 200647f5c746SAlex Deucher kv_convert_8bit_index_to_voltage(rdev, 200747f5c746SAlex Deucher acp_table->entries[i].v); 200841a524abSAlex Deucher } 200941a524abSAlex Deucher 201041a524abSAlex Deucher } 201141a524abSAlex Deucher 201241a524abSAlex Deucher static void kv_construct_boot_state(struct radeon_device *rdev) 201341a524abSAlex Deucher { 201441a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 201541a524abSAlex Deucher 201641a524abSAlex Deucher pi->boot_pl.sclk = pi->sys_info.bootup_sclk; 201741a524abSAlex Deucher pi->boot_pl.vddc_index = pi->sys_info.bootup_nb_voltage_index; 201841a524abSAlex Deucher pi->boot_pl.ds_divider_index = 0; 201941a524abSAlex Deucher pi->boot_pl.ss_divider_index = 0; 202041a524abSAlex Deucher pi->boot_pl.allow_gnb_slow = 1; 202141a524abSAlex Deucher pi->boot_pl.force_nbp_state = 0; 202241a524abSAlex Deucher pi->boot_pl.display_wm = 0; 202341a524abSAlex Deucher pi->boot_pl.vce_wm = 0; 202441a524abSAlex Deucher } 202541a524abSAlex Deucher 20262b4c8022SAlex Deucher static int kv_force_dpm_highest(struct radeon_device *rdev) 20272b4c8022SAlex Deucher { 20282b4c8022SAlex Deucher int ret; 20292b4c8022SAlex Deucher u32 enable_mask, i; 20302b4c8022SAlex Deucher 20312b4c8022SAlex Deucher ret = kv_dpm_get_enable_mask(rdev, &enable_mask); 20322b4c8022SAlex Deucher if (ret) 20332b4c8022SAlex Deucher return ret; 20342b4c8022SAlex Deucher 20358c5c6fadSDan Carpenter for (i = SMU7_MAX_LEVELS_GRAPHICS - 1; i > 0; i--) { 20362b4c8022SAlex Deucher if (enable_mask & (1 << i)) 20372b4c8022SAlex Deucher break; 20382b4c8022SAlex Deucher } 20392b4c8022SAlex Deucher 20407d032a4bSSamuel Li if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) 20412b4c8022SAlex Deucher return kv_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_DPM_ForceState, i); 2042136de91eSAlex Deucher else 2043136de91eSAlex Deucher return kv_set_enabled_level(rdev, i); 20442b4c8022SAlex Deucher } 20452b4c8022SAlex Deucher 204641a524abSAlex Deucher static int kv_force_dpm_lowest(struct radeon_device *rdev) 204741a524abSAlex Deucher { 204841a524abSAlex Deucher int ret; 204941a524abSAlex Deucher u32 enable_mask, i; 205041a524abSAlex Deucher 205141a524abSAlex Deucher ret = kv_dpm_get_enable_mask(rdev, &enable_mask); 205241a524abSAlex Deucher if (ret) 205341a524abSAlex Deucher return ret; 205441a524abSAlex Deucher 205541a524abSAlex Deucher for (i = 0; i < SMU7_MAX_LEVELS_GRAPHICS; i++) { 205641a524abSAlex Deucher if (enable_mask & (1 << i)) 205741a524abSAlex Deucher break; 205841a524abSAlex Deucher } 205941a524abSAlex Deucher 20607d032a4bSSamuel Li if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) 206141a524abSAlex Deucher return kv_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_DPM_ForceState, i); 2062136de91eSAlex Deucher else 2063136de91eSAlex Deucher return kv_set_enabled_level(rdev, i); 206441a524abSAlex Deucher } 206541a524abSAlex Deucher 206641a524abSAlex Deucher static u8 kv_get_sleep_divider_id_from_clock(struct radeon_device *rdev, 206741a524abSAlex Deucher u32 sclk, u32 min_sclk_in_sr) 206841a524abSAlex Deucher { 206941a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 207041a524abSAlex Deucher u32 i; 207141a524abSAlex Deucher u32 temp; 207241a524abSAlex Deucher u32 min = (min_sclk_in_sr > KV_MINIMUM_ENGINE_CLOCK) ? 207341a524abSAlex Deucher min_sclk_in_sr : KV_MINIMUM_ENGINE_CLOCK; 207441a524abSAlex Deucher 207541a524abSAlex Deucher if (sclk < min) 207641a524abSAlex Deucher return 0; 207741a524abSAlex Deucher 207841a524abSAlex Deucher if (!pi->caps_sclk_ds) 207941a524abSAlex Deucher return 0; 208041a524abSAlex Deucher 20818c5c6fadSDan Carpenter for (i = KV_MAX_DEEPSLEEP_DIVIDER_ID; i > 0; i--) { 208241a524abSAlex Deucher temp = sclk / sumo_get_sleep_divider_from_id(i); 20838c5c6fadSDan Carpenter if (temp >= min) 208441a524abSAlex Deucher break; 208541a524abSAlex Deucher } 208641a524abSAlex Deucher 208741a524abSAlex Deucher return (u8)i; 208841a524abSAlex Deucher } 208941a524abSAlex Deucher 209041a524abSAlex Deucher static int kv_get_high_voltage_limit(struct radeon_device *rdev, int *limit) 209141a524abSAlex Deucher { 209241a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 209341a524abSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 209441a524abSAlex Deucher &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; 209541a524abSAlex Deucher int i; 209641a524abSAlex Deucher 209741a524abSAlex Deucher if (table && table->count) { 209841a524abSAlex Deucher for (i = table->count - 1; i >= 0; i--) { 209941a524abSAlex Deucher if (pi->high_voltage_t && 210041a524abSAlex Deucher (kv_convert_8bit_index_to_voltage(rdev, table->entries[i].v) <= 210141a524abSAlex Deucher pi->high_voltage_t)) { 210241a524abSAlex Deucher *limit = i; 210341a524abSAlex Deucher return 0; 210441a524abSAlex Deucher } 210541a524abSAlex Deucher } 210641a524abSAlex Deucher } else { 210741a524abSAlex Deucher struct sumo_sclk_voltage_mapping_table *table = 210841a524abSAlex Deucher &pi->sys_info.sclk_voltage_mapping_table; 210941a524abSAlex Deucher 211041a524abSAlex Deucher for (i = table->num_max_dpm_entries - 1; i >= 0; i--) { 211141a524abSAlex Deucher if (pi->high_voltage_t && 211241a524abSAlex Deucher (kv_convert_2bit_index_to_voltage(rdev, table->entries[i].vid_2bit) <= 211341a524abSAlex Deucher pi->high_voltage_t)) { 211441a524abSAlex Deucher *limit = i; 211541a524abSAlex Deucher return 0; 211641a524abSAlex Deucher } 211741a524abSAlex Deucher } 211841a524abSAlex Deucher } 211941a524abSAlex Deucher 212041a524abSAlex Deucher *limit = 0; 212141a524abSAlex Deucher return 0; 212241a524abSAlex Deucher } 212341a524abSAlex Deucher 212441a524abSAlex Deucher static void kv_apply_state_adjust_rules(struct radeon_device *rdev, 212541a524abSAlex Deucher struct radeon_ps *new_rps, 212641a524abSAlex Deucher struct radeon_ps *old_rps) 212741a524abSAlex Deucher { 212841a524abSAlex Deucher struct kv_ps *ps = kv_get_ps(new_rps); 212941a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 213041a524abSAlex Deucher u32 min_sclk = 10000; /* ??? */ 213141a524abSAlex Deucher u32 sclk, mclk = 0; 213241a524abSAlex Deucher int i, limit; 213341a524abSAlex Deucher bool force_high; 213441a524abSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 213541a524abSAlex Deucher &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; 213641a524abSAlex Deucher u32 stable_p_state_sclk = 0; 213741a524abSAlex Deucher struct radeon_clock_and_voltage_limits *max_limits = 213841a524abSAlex Deucher &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; 213941a524abSAlex Deucher 214042332905SAlex Deucher if (new_rps->vce_active) { 214142332905SAlex Deucher new_rps->evclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].evclk; 214242332905SAlex Deucher new_rps->ecclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].ecclk; 214342332905SAlex Deucher } else { 214442332905SAlex Deucher new_rps->evclk = 0; 214542332905SAlex Deucher new_rps->ecclk = 0; 214642332905SAlex Deucher } 214742332905SAlex Deucher 214841a524abSAlex Deucher mclk = max_limits->mclk; 214941a524abSAlex Deucher sclk = min_sclk; 215041a524abSAlex Deucher 215141a524abSAlex Deucher if (pi->caps_stable_p_state) { 215241a524abSAlex Deucher stable_p_state_sclk = (max_limits->sclk * 75) / 100; 215341a524abSAlex Deucher 215441a524abSAlex Deucher for (i = table->count - 1; i >= 0; i++) { 215541a524abSAlex Deucher if (stable_p_state_sclk >= table->entries[i].clk) { 215641a524abSAlex Deucher stable_p_state_sclk = table->entries[i].clk; 215741a524abSAlex Deucher break; 215841a524abSAlex Deucher } 215941a524abSAlex Deucher } 216041a524abSAlex Deucher 216141a524abSAlex Deucher if (i > 0) 216241a524abSAlex Deucher stable_p_state_sclk = table->entries[0].clk; 216341a524abSAlex Deucher 216441a524abSAlex Deucher sclk = stable_p_state_sclk; 216541a524abSAlex Deucher } 216641a524abSAlex Deucher 216742332905SAlex Deucher if (new_rps->vce_active) { 216842332905SAlex Deucher if (sclk < rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk) 216942332905SAlex Deucher sclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk; 217042332905SAlex Deucher } 217142332905SAlex Deucher 217241a524abSAlex Deucher ps->need_dfs_bypass = true; 217341a524abSAlex Deucher 217441a524abSAlex Deucher for (i = 0; i < ps->num_levels; i++) { 217541a524abSAlex Deucher if (ps->levels[i].sclk < sclk) 217641a524abSAlex Deucher ps->levels[i].sclk = sclk; 217741a524abSAlex Deucher } 217841a524abSAlex Deucher 217941a524abSAlex Deucher if (table && table->count) { 218041a524abSAlex Deucher for (i = 0; i < ps->num_levels; i++) { 218141a524abSAlex Deucher if (pi->high_voltage_t && 218241a524abSAlex Deucher (pi->high_voltage_t < 218341a524abSAlex Deucher kv_convert_8bit_index_to_voltage(rdev, ps->levels[i].vddc_index))) { 218441a524abSAlex Deucher kv_get_high_voltage_limit(rdev, &limit); 218541a524abSAlex Deucher ps->levels[i].sclk = table->entries[limit].clk; 218641a524abSAlex Deucher } 218741a524abSAlex Deucher } 218841a524abSAlex Deucher } else { 218941a524abSAlex Deucher struct sumo_sclk_voltage_mapping_table *table = 219041a524abSAlex Deucher &pi->sys_info.sclk_voltage_mapping_table; 219141a524abSAlex Deucher 219241a524abSAlex Deucher for (i = 0; i < ps->num_levels; i++) { 219341a524abSAlex Deucher if (pi->high_voltage_t && 219441a524abSAlex Deucher (pi->high_voltage_t < 219541a524abSAlex Deucher kv_convert_8bit_index_to_voltage(rdev, ps->levels[i].vddc_index))) { 219641a524abSAlex Deucher kv_get_high_voltage_limit(rdev, &limit); 219741a524abSAlex Deucher ps->levels[i].sclk = table->entries[limit].sclk_frequency; 219841a524abSAlex Deucher } 219941a524abSAlex Deucher } 220041a524abSAlex Deucher } 220141a524abSAlex Deucher 220241a524abSAlex Deucher if (pi->caps_stable_p_state) { 220341a524abSAlex Deucher for (i = 0; i < ps->num_levels; i++) { 220441a524abSAlex Deucher ps->levels[i].sclk = stable_p_state_sclk; 220541a524abSAlex Deucher } 220641a524abSAlex Deucher } 220741a524abSAlex Deucher 220842332905SAlex Deucher pi->video_start = new_rps->dclk || new_rps->vclk || 220942332905SAlex Deucher new_rps->evclk || new_rps->ecclk; 221041a524abSAlex Deucher 221141a524abSAlex Deucher if ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == 221241a524abSAlex Deucher ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) 221341a524abSAlex Deucher pi->battery_state = true; 221441a524abSAlex Deucher else 221541a524abSAlex Deucher pi->battery_state = false; 221641a524abSAlex Deucher 22177d032a4bSSamuel Li if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) { 221841a524abSAlex Deucher ps->dpm0_pg_nb_ps_lo = 0x1; 221941a524abSAlex Deucher ps->dpm0_pg_nb_ps_hi = 0x0; 222041a524abSAlex Deucher ps->dpmx_nb_ps_lo = 0x1; 222141a524abSAlex Deucher ps->dpmx_nb_ps_hi = 0x0; 222241a524abSAlex Deucher } else { 2223136de91eSAlex Deucher ps->dpm0_pg_nb_ps_lo = 0x3; 222441a524abSAlex Deucher ps->dpm0_pg_nb_ps_hi = 0x0; 2225136de91eSAlex Deucher ps->dpmx_nb_ps_lo = 0x3; 2226136de91eSAlex Deucher ps->dpmx_nb_ps_hi = 0x0; 222741a524abSAlex Deucher 2228136de91eSAlex Deucher if (pi->sys_info.nb_dpm_enable) { 222941a524abSAlex Deucher force_high = (mclk >= pi->sys_info.nbp_memory_clock[3]) || 223041a524abSAlex Deucher pi->video_start || (rdev->pm.dpm.new_active_crtc_count >= 3) || 223141a524abSAlex Deucher pi->disable_nb_ps3_in_battery; 223241a524abSAlex Deucher ps->dpm0_pg_nb_ps_lo = force_high ? 0x2 : 0x3; 223341a524abSAlex Deucher ps->dpm0_pg_nb_ps_hi = 0x2; 223441a524abSAlex Deucher ps->dpmx_nb_ps_lo = force_high ? 0x2 : 0x3; 223541a524abSAlex Deucher ps->dpmx_nb_ps_hi = 0x2; 223641a524abSAlex Deucher } 223741a524abSAlex Deucher } 223841a524abSAlex Deucher } 223941a524abSAlex Deucher 224041a524abSAlex Deucher static void kv_dpm_power_level_enabled_for_throttle(struct radeon_device *rdev, 224141a524abSAlex Deucher u32 index, bool enable) 224241a524abSAlex Deucher { 224341a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 224441a524abSAlex Deucher 224541a524abSAlex Deucher pi->graphics_level[index].EnabledForThrottle = enable ? 1 : 0; 224641a524abSAlex Deucher } 224741a524abSAlex Deucher 224841a524abSAlex Deucher static int kv_calculate_ds_divider(struct radeon_device *rdev) 224941a524abSAlex Deucher { 225041a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 225141a524abSAlex Deucher u32 sclk_in_sr = 10000; /* ??? */ 225241a524abSAlex Deucher u32 i; 225341a524abSAlex Deucher 225441a524abSAlex Deucher if (pi->lowest_valid > pi->highest_valid) 225541a524abSAlex Deucher return -EINVAL; 225641a524abSAlex Deucher 225741a524abSAlex Deucher for (i = pi->lowest_valid; i <= pi->highest_valid; i++) { 225841a524abSAlex Deucher pi->graphics_level[i].DeepSleepDivId = 225941a524abSAlex Deucher kv_get_sleep_divider_id_from_clock(rdev, 226041a524abSAlex Deucher be32_to_cpu(pi->graphics_level[i].SclkFrequency), 226141a524abSAlex Deucher sclk_in_sr); 226241a524abSAlex Deucher } 226341a524abSAlex Deucher return 0; 226441a524abSAlex Deucher } 226541a524abSAlex Deucher 226641a524abSAlex Deucher static int kv_calculate_nbps_level_settings(struct radeon_device *rdev) 226741a524abSAlex Deucher { 226841a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 226941a524abSAlex Deucher u32 i; 227041a524abSAlex Deucher bool force_high; 227141a524abSAlex Deucher struct radeon_clock_and_voltage_limits *max_limits = 227241a524abSAlex Deucher &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; 227341a524abSAlex Deucher u32 mclk = max_limits->mclk; 227441a524abSAlex Deucher 227541a524abSAlex Deucher if (pi->lowest_valid > pi->highest_valid) 227641a524abSAlex Deucher return -EINVAL; 227741a524abSAlex Deucher 22787d032a4bSSamuel Li if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) { 227941a524abSAlex Deucher for (i = pi->lowest_valid; i <= pi->highest_valid; i++) { 228041a524abSAlex Deucher pi->graphics_level[i].GnbSlow = 1; 228141a524abSAlex Deucher pi->graphics_level[i].ForceNbPs1 = 0; 228241a524abSAlex Deucher pi->graphics_level[i].UpH = 0; 228341a524abSAlex Deucher } 228441a524abSAlex Deucher 228541a524abSAlex Deucher if (!pi->sys_info.nb_dpm_enable) 228641a524abSAlex Deucher return 0; 228741a524abSAlex Deucher 228841a524abSAlex Deucher force_high = ((mclk >= pi->sys_info.nbp_memory_clock[3]) || 228941a524abSAlex Deucher (rdev->pm.dpm.new_active_crtc_count >= 3) || pi->video_start); 229041a524abSAlex Deucher 229141a524abSAlex Deucher if (force_high) { 229241a524abSAlex Deucher for (i = pi->lowest_valid; i <= pi->highest_valid; i++) 229341a524abSAlex Deucher pi->graphics_level[i].GnbSlow = 0; 229441a524abSAlex Deucher } else { 229541a524abSAlex Deucher if (pi->battery_state) 229641a524abSAlex Deucher pi->graphics_level[0].ForceNbPs1 = 1; 229741a524abSAlex Deucher 229841a524abSAlex Deucher pi->graphics_level[1].GnbSlow = 0; 229941a524abSAlex Deucher pi->graphics_level[2].GnbSlow = 0; 230041a524abSAlex Deucher pi->graphics_level[3].GnbSlow = 0; 230141a524abSAlex Deucher pi->graphics_level[4].GnbSlow = 0; 230241a524abSAlex Deucher } 230341a524abSAlex Deucher } else { 230441a524abSAlex Deucher for (i = pi->lowest_valid; i <= pi->highest_valid; i++) { 230541a524abSAlex Deucher pi->graphics_level[i].GnbSlow = 1; 230641a524abSAlex Deucher pi->graphics_level[i].ForceNbPs1 = 0; 230741a524abSAlex Deucher pi->graphics_level[i].UpH = 0; 230841a524abSAlex Deucher } 230941a524abSAlex Deucher 231041a524abSAlex Deucher if (pi->sys_info.nb_dpm_enable && pi->battery_state) { 231141a524abSAlex Deucher pi->graphics_level[pi->lowest_valid].UpH = 0x28; 231241a524abSAlex Deucher pi->graphics_level[pi->lowest_valid].GnbSlow = 0; 231341a524abSAlex Deucher if (pi->lowest_valid != pi->highest_valid) 231441a524abSAlex Deucher pi->graphics_level[pi->lowest_valid].ForceNbPs1 = 1; 231541a524abSAlex Deucher } 231641a524abSAlex Deucher } 231741a524abSAlex Deucher return 0; 231841a524abSAlex Deucher } 231941a524abSAlex Deucher 232041a524abSAlex Deucher static int kv_calculate_dpm_settings(struct radeon_device *rdev) 232141a524abSAlex Deucher { 232241a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 232341a524abSAlex Deucher u32 i; 232441a524abSAlex Deucher 232541a524abSAlex Deucher if (pi->lowest_valid > pi->highest_valid) 232641a524abSAlex Deucher return -EINVAL; 232741a524abSAlex Deucher 232841a524abSAlex Deucher for (i = pi->lowest_valid; i <= pi->highest_valid; i++) 232941a524abSAlex Deucher pi->graphics_level[i].DisplayWatermark = (i == pi->highest_valid) ? 1 : 0; 233041a524abSAlex Deucher 233141a524abSAlex Deucher return 0; 233241a524abSAlex Deucher } 233341a524abSAlex Deucher 233441a524abSAlex Deucher static void kv_init_graphics_levels(struct radeon_device *rdev) 233541a524abSAlex Deucher { 233641a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 233741a524abSAlex Deucher u32 i; 233841a524abSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 233941a524abSAlex Deucher &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; 234041a524abSAlex Deucher 234141a524abSAlex Deucher if (table && table->count) { 234241a524abSAlex Deucher u32 vid_2bit; 234341a524abSAlex Deucher 234441a524abSAlex Deucher pi->graphics_dpm_level_count = 0; 234541a524abSAlex Deucher for (i = 0; i < table->count; i++) { 234641a524abSAlex Deucher if (pi->high_voltage_t && 234741a524abSAlex Deucher (pi->high_voltage_t < 234841a524abSAlex Deucher kv_convert_8bit_index_to_voltage(rdev, table->entries[i].v))) 234941a524abSAlex Deucher break; 235041a524abSAlex Deucher 235141a524abSAlex Deucher kv_set_divider_value(rdev, i, table->entries[i].clk); 235247f5c746SAlex Deucher vid_2bit = kv_convert_vid7_to_vid2(rdev, 235341a524abSAlex Deucher &pi->sys_info.vid_mapping_table, 235441a524abSAlex Deucher table->entries[i].v); 235541a524abSAlex Deucher kv_set_vid(rdev, i, vid_2bit); 235641a524abSAlex Deucher kv_set_at(rdev, i, pi->at[i]); 235741a524abSAlex Deucher kv_dpm_power_level_enabled_for_throttle(rdev, i, true); 235841a524abSAlex Deucher pi->graphics_dpm_level_count++; 235941a524abSAlex Deucher } 236041a524abSAlex Deucher } else { 236141a524abSAlex Deucher struct sumo_sclk_voltage_mapping_table *table = 236241a524abSAlex Deucher &pi->sys_info.sclk_voltage_mapping_table; 236341a524abSAlex Deucher 236441a524abSAlex Deucher pi->graphics_dpm_level_count = 0; 236541a524abSAlex Deucher for (i = 0; i < table->num_max_dpm_entries; i++) { 236641a524abSAlex Deucher if (pi->high_voltage_t && 236741a524abSAlex Deucher pi->high_voltage_t < 236841a524abSAlex Deucher kv_convert_2bit_index_to_voltage(rdev, table->entries[i].vid_2bit)) 236941a524abSAlex Deucher break; 237041a524abSAlex Deucher 237141a524abSAlex Deucher kv_set_divider_value(rdev, i, table->entries[i].sclk_frequency); 237241a524abSAlex Deucher kv_set_vid(rdev, i, table->entries[i].vid_2bit); 237341a524abSAlex Deucher kv_set_at(rdev, i, pi->at[i]); 237441a524abSAlex Deucher kv_dpm_power_level_enabled_for_throttle(rdev, i, true); 237541a524abSAlex Deucher pi->graphics_dpm_level_count++; 237641a524abSAlex Deucher } 237741a524abSAlex Deucher } 237841a524abSAlex Deucher 237941a524abSAlex Deucher for (i = 0; i < SMU7_MAX_LEVELS_GRAPHICS; i++) 238041a524abSAlex Deucher kv_dpm_power_level_enable(rdev, i, false); 238141a524abSAlex Deucher } 238241a524abSAlex Deucher 238341a524abSAlex Deucher static void kv_enable_new_levels(struct radeon_device *rdev) 238441a524abSAlex Deucher { 238541a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 238641a524abSAlex Deucher u32 i; 238741a524abSAlex Deucher 238841a524abSAlex Deucher for (i = 0; i < SMU7_MAX_LEVELS_GRAPHICS; i++) { 238941a524abSAlex Deucher if (i >= pi->lowest_valid && i <= pi->highest_valid) 239041a524abSAlex Deucher kv_dpm_power_level_enable(rdev, i, true); 239141a524abSAlex Deucher } 239241a524abSAlex Deucher } 239341a524abSAlex Deucher 2394136de91eSAlex Deucher static int kv_set_enabled_level(struct radeon_device *rdev, u32 level) 2395136de91eSAlex Deucher { 2396136de91eSAlex Deucher u32 new_mask = (1 << level); 2397136de91eSAlex Deucher 2398136de91eSAlex Deucher return kv_send_msg_to_smc_with_parameter(rdev, 2399136de91eSAlex Deucher PPSMC_MSG_SCLKDPM_SetEnabledMask, 2400136de91eSAlex Deucher new_mask); 2401136de91eSAlex Deucher } 2402136de91eSAlex Deucher 240341a524abSAlex Deucher static int kv_set_enabled_levels(struct radeon_device *rdev) 240441a524abSAlex Deucher { 240541a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 240641a524abSAlex Deucher u32 i, new_mask = 0; 240741a524abSAlex Deucher 240841a524abSAlex Deucher for (i = pi->lowest_valid; i <= pi->highest_valid; i++) 240941a524abSAlex Deucher new_mask |= (1 << i); 241041a524abSAlex Deucher 241141a524abSAlex Deucher return kv_send_msg_to_smc_with_parameter(rdev, 241241a524abSAlex Deucher PPSMC_MSG_SCLKDPM_SetEnabledMask, 241341a524abSAlex Deucher new_mask); 241441a524abSAlex Deucher } 241541a524abSAlex Deucher 241641a524abSAlex Deucher static void kv_program_nbps_index_settings(struct radeon_device *rdev, 241741a524abSAlex Deucher struct radeon_ps *new_rps) 241841a524abSAlex Deucher { 241941a524abSAlex Deucher struct kv_ps *new_ps = kv_get_ps(new_rps); 242041a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 242141a524abSAlex Deucher u32 nbdpmconfig1; 242241a524abSAlex Deucher 24237d032a4bSSamuel Li if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) 242441a524abSAlex Deucher return; 242541a524abSAlex Deucher 242641a524abSAlex Deucher if (pi->sys_info.nb_dpm_enable) { 242741a524abSAlex Deucher nbdpmconfig1 = RREG32_SMC(NB_DPM_CONFIG_1); 242841a524abSAlex Deucher nbdpmconfig1 &= ~(Dpm0PgNbPsLo_MASK | Dpm0PgNbPsHi_MASK | 242941a524abSAlex Deucher DpmXNbPsLo_MASK | DpmXNbPsHi_MASK); 243041a524abSAlex Deucher nbdpmconfig1 |= (Dpm0PgNbPsLo(new_ps->dpm0_pg_nb_ps_lo) | 243141a524abSAlex Deucher Dpm0PgNbPsHi(new_ps->dpm0_pg_nb_ps_hi) | 243241a524abSAlex Deucher DpmXNbPsLo(new_ps->dpmx_nb_ps_lo) | 243341a524abSAlex Deucher DpmXNbPsHi(new_ps->dpmx_nb_ps_hi)); 243441a524abSAlex Deucher WREG32_SMC(NB_DPM_CONFIG_1, nbdpmconfig1); 243541a524abSAlex Deucher } 243641a524abSAlex Deucher } 243741a524abSAlex Deucher 243841a524abSAlex Deucher static int kv_set_thermal_temperature_range(struct radeon_device *rdev, 243941a524abSAlex Deucher int min_temp, int max_temp) 244041a524abSAlex Deucher { 244141a524abSAlex Deucher int low_temp = 0 * 1000; 244241a524abSAlex Deucher int high_temp = 255 * 1000; 244341a524abSAlex Deucher u32 tmp; 244441a524abSAlex Deucher 244541a524abSAlex Deucher if (low_temp < min_temp) 244641a524abSAlex Deucher low_temp = min_temp; 244741a524abSAlex Deucher if (high_temp > max_temp) 244841a524abSAlex Deucher high_temp = max_temp; 244941a524abSAlex Deucher if (high_temp < low_temp) { 245041a524abSAlex Deucher DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp); 245141a524abSAlex Deucher return -EINVAL; 245241a524abSAlex Deucher } 245341a524abSAlex Deucher 245441a524abSAlex Deucher tmp = RREG32_SMC(CG_THERMAL_INT_CTRL); 245541a524abSAlex Deucher tmp &= ~(DIG_THERM_INTH_MASK | DIG_THERM_INTL_MASK); 245641a524abSAlex Deucher tmp |= (DIG_THERM_INTH(49 + (high_temp / 1000)) | 245741a524abSAlex Deucher DIG_THERM_INTL(49 + (low_temp / 1000))); 245841a524abSAlex Deucher WREG32_SMC(CG_THERMAL_INT_CTRL, tmp); 245941a524abSAlex Deucher 246041a524abSAlex Deucher rdev->pm.dpm.thermal.min_temp = low_temp; 246141a524abSAlex Deucher rdev->pm.dpm.thermal.max_temp = high_temp; 246241a524abSAlex Deucher 246341a524abSAlex Deucher return 0; 246441a524abSAlex Deucher } 246541a524abSAlex Deucher 246641a524abSAlex Deucher union igp_info { 246741a524abSAlex Deucher struct _ATOM_INTEGRATED_SYSTEM_INFO info; 246841a524abSAlex Deucher struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2; 246941a524abSAlex Deucher struct _ATOM_INTEGRATED_SYSTEM_INFO_V5 info_5; 247041a524abSAlex Deucher struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6; 247141a524abSAlex Deucher struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7; 247241a524abSAlex Deucher struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 info_8; 247341a524abSAlex Deucher }; 247441a524abSAlex Deucher 247541a524abSAlex Deucher static int kv_parse_sys_info_table(struct radeon_device *rdev) 247641a524abSAlex Deucher { 247741a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 247841a524abSAlex Deucher struct radeon_mode_info *mode_info = &rdev->mode_info; 247941a524abSAlex Deucher int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo); 248041a524abSAlex Deucher union igp_info *igp_info; 248141a524abSAlex Deucher u8 frev, crev; 248241a524abSAlex Deucher u16 data_offset; 248341a524abSAlex Deucher int i; 248441a524abSAlex Deucher 248541a524abSAlex Deucher if (atom_parse_data_header(mode_info->atom_context, index, NULL, 248641a524abSAlex Deucher &frev, &crev, &data_offset)) { 248741a524abSAlex Deucher igp_info = (union igp_info *)(mode_info->atom_context->bios + 248841a524abSAlex Deucher data_offset); 248941a524abSAlex Deucher 249041a524abSAlex Deucher if (crev != 8) { 249141a524abSAlex Deucher DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev); 249241a524abSAlex Deucher return -EINVAL; 249341a524abSAlex Deucher } 249441a524abSAlex Deucher pi->sys_info.bootup_sclk = le32_to_cpu(igp_info->info_8.ulBootUpEngineClock); 249541a524abSAlex Deucher pi->sys_info.bootup_uma_clk = le32_to_cpu(igp_info->info_8.ulBootUpUMAClock); 249641a524abSAlex Deucher pi->sys_info.bootup_nb_voltage_index = 249741a524abSAlex Deucher le16_to_cpu(igp_info->info_8.usBootUpNBVoltage); 249841a524abSAlex Deucher if (igp_info->info_8.ucHtcTmpLmt == 0) 249941a524abSAlex Deucher pi->sys_info.htc_tmp_lmt = 203; 250041a524abSAlex Deucher else 250141a524abSAlex Deucher pi->sys_info.htc_tmp_lmt = igp_info->info_8.ucHtcTmpLmt; 250241a524abSAlex Deucher if (igp_info->info_8.ucHtcHystLmt == 0) 250341a524abSAlex Deucher pi->sys_info.htc_hyst_lmt = 5; 250441a524abSAlex Deucher else 250541a524abSAlex Deucher pi->sys_info.htc_hyst_lmt = igp_info->info_8.ucHtcHystLmt; 250641a524abSAlex Deucher if (pi->sys_info.htc_tmp_lmt <= pi->sys_info.htc_hyst_lmt) { 250741a524abSAlex Deucher DRM_ERROR("The htcTmpLmt should be larger than htcHystLmt.\n"); 250841a524abSAlex Deucher } 250941a524abSAlex Deucher 251041a524abSAlex Deucher if (le32_to_cpu(igp_info->info_8.ulSystemConfig) & (1 << 3)) 251141a524abSAlex Deucher pi->sys_info.nb_dpm_enable = true; 251241a524abSAlex Deucher else 251341a524abSAlex Deucher pi->sys_info.nb_dpm_enable = false; 251441a524abSAlex Deucher 251541a524abSAlex Deucher for (i = 0; i < KV_NUM_NBPSTATES; i++) { 251641a524abSAlex Deucher pi->sys_info.nbp_memory_clock[i] = 251741a524abSAlex Deucher le32_to_cpu(igp_info->info_8.ulNbpStateMemclkFreq[i]); 251841a524abSAlex Deucher pi->sys_info.nbp_n_clock[i] = 251941a524abSAlex Deucher le32_to_cpu(igp_info->info_8.ulNbpStateNClkFreq[i]); 252041a524abSAlex Deucher } 252141a524abSAlex Deucher if (le32_to_cpu(igp_info->info_8.ulGPUCapInfo) & 252241a524abSAlex Deucher SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS) 252341a524abSAlex Deucher pi->caps_enable_dfs_bypass = true; 252441a524abSAlex Deucher 252541a524abSAlex Deucher sumo_construct_sclk_voltage_mapping_table(rdev, 252641a524abSAlex Deucher &pi->sys_info.sclk_voltage_mapping_table, 252741a524abSAlex Deucher igp_info->info_8.sAvail_SCLK); 252841a524abSAlex Deucher 252941a524abSAlex Deucher sumo_construct_vid_mapping_table(rdev, 253041a524abSAlex Deucher &pi->sys_info.vid_mapping_table, 253141a524abSAlex Deucher igp_info->info_8.sAvail_SCLK); 253241a524abSAlex Deucher 253341a524abSAlex Deucher kv_construct_max_power_limits_table(rdev, 253441a524abSAlex Deucher &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac); 253541a524abSAlex Deucher } 253641a524abSAlex Deucher return 0; 253741a524abSAlex Deucher } 253841a524abSAlex Deucher 253941a524abSAlex Deucher union power_info { 254041a524abSAlex Deucher struct _ATOM_POWERPLAY_INFO info; 254141a524abSAlex Deucher struct _ATOM_POWERPLAY_INFO_V2 info_2; 254241a524abSAlex Deucher struct _ATOM_POWERPLAY_INFO_V3 info_3; 254341a524abSAlex Deucher struct _ATOM_PPLIB_POWERPLAYTABLE pplib; 254441a524abSAlex Deucher struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2; 254541a524abSAlex Deucher struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3; 254641a524abSAlex Deucher }; 254741a524abSAlex Deucher 254841a524abSAlex Deucher union pplib_clock_info { 254941a524abSAlex Deucher struct _ATOM_PPLIB_R600_CLOCK_INFO r600; 255041a524abSAlex Deucher struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780; 255141a524abSAlex Deucher struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen; 255241a524abSAlex Deucher struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo; 255341a524abSAlex Deucher }; 255441a524abSAlex Deucher 255541a524abSAlex Deucher union pplib_power_state { 255641a524abSAlex Deucher struct _ATOM_PPLIB_STATE v1; 255741a524abSAlex Deucher struct _ATOM_PPLIB_STATE_V2 v2; 255841a524abSAlex Deucher }; 255941a524abSAlex Deucher 256041a524abSAlex Deucher static void kv_patch_boot_state(struct radeon_device *rdev, 256141a524abSAlex Deucher struct kv_ps *ps) 256241a524abSAlex Deucher { 256341a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 256441a524abSAlex Deucher 256541a524abSAlex Deucher ps->num_levels = 1; 256641a524abSAlex Deucher ps->levels[0] = pi->boot_pl; 256741a524abSAlex Deucher } 256841a524abSAlex Deucher 256941a524abSAlex Deucher static void kv_parse_pplib_non_clock_info(struct radeon_device *rdev, 257041a524abSAlex Deucher struct radeon_ps *rps, 257141a524abSAlex Deucher struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info, 257241a524abSAlex Deucher u8 table_rev) 257341a524abSAlex Deucher { 257441a524abSAlex Deucher struct kv_ps *ps = kv_get_ps(rps); 257541a524abSAlex Deucher 257641a524abSAlex Deucher rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings); 257741a524abSAlex Deucher rps->class = le16_to_cpu(non_clock_info->usClassification); 257841a524abSAlex Deucher rps->class2 = le16_to_cpu(non_clock_info->usClassification2); 257941a524abSAlex Deucher 258041a524abSAlex Deucher if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) { 258141a524abSAlex Deucher rps->vclk = le32_to_cpu(non_clock_info->ulVCLK); 258241a524abSAlex Deucher rps->dclk = le32_to_cpu(non_clock_info->ulDCLK); 258341a524abSAlex Deucher } else { 258441a524abSAlex Deucher rps->vclk = 0; 258541a524abSAlex Deucher rps->dclk = 0; 258641a524abSAlex Deucher } 258741a524abSAlex Deucher 258841a524abSAlex Deucher if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) { 258941a524abSAlex Deucher rdev->pm.dpm.boot_ps = rps; 259041a524abSAlex Deucher kv_patch_boot_state(rdev, ps); 259141a524abSAlex Deucher } 259241a524abSAlex Deucher if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) 259341a524abSAlex Deucher rdev->pm.dpm.uvd_ps = rps; 259441a524abSAlex Deucher } 259541a524abSAlex Deucher 259641a524abSAlex Deucher static void kv_parse_pplib_clock_info(struct radeon_device *rdev, 259741a524abSAlex Deucher struct radeon_ps *rps, int index, 259841a524abSAlex Deucher union pplib_clock_info *clock_info) 259941a524abSAlex Deucher { 260041a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 260141a524abSAlex Deucher struct kv_ps *ps = kv_get_ps(rps); 260241a524abSAlex Deucher struct kv_pl *pl = &ps->levels[index]; 260341a524abSAlex Deucher u32 sclk; 260441a524abSAlex Deucher 260541a524abSAlex Deucher sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow); 260641a524abSAlex Deucher sclk |= clock_info->sumo.ucEngineClockHigh << 16; 260741a524abSAlex Deucher pl->sclk = sclk; 260841a524abSAlex Deucher pl->vddc_index = clock_info->sumo.vddcIndex; 260941a524abSAlex Deucher 261041a524abSAlex Deucher ps->num_levels = index + 1; 261141a524abSAlex Deucher 261241a524abSAlex Deucher if (pi->caps_sclk_ds) { 261341a524abSAlex Deucher pl->ds_divider_index = 5; 261441a524abSAlex Deucher pl->ss_divider_index = 5; 261541a524abSAlex Deucher } 261641a524abSAlex Deucher } 261741a524abSAlex Deucher 261841a524abSAlex Deucher static int kv_parse_power_table(struct radeon_device *rdev) 261941a524abSAlex Deucher { 262041a524abSAlex Deucher struct radeon_mode_info *mode_info = &rdev->mode_info; 262141a524abSAlex Deucher struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; 262241a524abSAlex Deucher union pplib_power_state *power_state; 262341a524abSAlex Deucher int i, j, k, non_clock_array_index, clock_array_index; 262441a524abSAlex Deucher union pplib_clock_info *clock_info; 262541a524abSAlex Deucher struct _StateArray *state_array; 262641a524abSAlex Deucher struct _ClockInfoArray *clock_info_array; 262741a524abSAlex Deucher struct _NonClockInfoArray *non_clock_info_array; 262841a524abSAlex Deucher union power_info *power_info; 262941a524abSAlex Deucher int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); 263041a524abSAlex Deucher u16 data_offset; 263141a524abSAlex Deucher u8 frev, crev; 263241a524abSAlex Deucher u8 *power_state_offset; 263341a524abSAlex Deucher struct kv_ps *ps; 263441a524abSAlex Deucher 263541a524abSAlex Deucher if (!atom_parse_data_header(mode_info->atom_context, index, NULL, 263641a524abSAlex Deucher &frev, &crev, &data_offset)) 263741a524abSAlex Deucher return -EINVAL; 263841a524abSAlex Deucher power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); 263941a524abSAlex Deucher 264041a524abSAlex Deucher state_array = (struct _StateArray *) 264141a524abSAlex Deucher (mode_info->atom_context->bios + data_offset + 264241a524abSAlex Deucher le16_to_cpu(power_info->pplib.usStateArrayOffset)); 264341a524abSAlex Deucher clock_info_array = (struct _ClockInfoArray *) 264441a524abSAlex Deucher (mode_info->atom_context->bios + data_offset + 264541a524abSAlex Deucher le16_to_cpu(power_info->pplib.usClockInfoArrayOffset)); 264641a524abSAlex Deucher non_clock_info_array = (struct _NonClockInfoArray *) 264741a524abSAlex Deucher (mode_info->atom_context->bios + data_offset + 264841a524abSAlex Deucher le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); 264941a524abSAlex Deucher 265041a524abSAlex Deucher rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) * 265141a524abSAlex Deucher state_array->ucNumEntries, GFP_KERNEL); 265241a524abSAlex Deucher if (!rdev->pm.dpm.ps) 265341a524abSAlex Deucher return -ENOMEM; 265441a524abSAlex Deucher power_state_offset = (u8 *)state_array->states; 265541a524abSAlex Deucher for (i = 0; i < state_array->ucNumEntries; i++) { 26569af37a7dSAlex Deucher u8 *idx; 265741a524abSAlex Deucher power_state = (union pplib_power_state *)power_state_offset; 265841a524abSAlex Deucher non_clock_array_index = power_state->v2.nonClockInfoIndex; 265941a524abSAlex Deucher non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) 266041a524abSAlex Deucher &non_clock_info_array->nonClockInfo[non_clock_array_index]; 266141a524abSAlex Deucher if (!rdev->pm.power_state[i].clock_info) 266241a524abSAlex Deucher return -EINVAL; 266341a524abSAlex Deucher ps = kzalloc(sizeof(struct kv_ps), GFP_KERNEL); 266441a524abSAlex Deucher if (ps == NULL) { 266541a524abSAlex Deucher kfree(rdev->pm.dpm.ps); 266641a524abSAlex Deucher return -ENOMEM; 266741a524abSAlex Deucher } 266841a524abSAlex Deucher rdev->pm.dpm.ps[i].ps_priv = ps; 266941a524abSAlex Deucher k = 0; 26709af37a7dSAlex Deucher idx = (u8 *)&power_state->v2.clockInfoIndex[0]; 267141a524abSAlex Deucher for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) { 26729af37a7dSAlex Deucher clock_array_index = idx[j]; 267341a524abSAlex Deucher if (clock_array_index >= clock_info_array->ucNumEntries) 267441a524abSAlex Deucher continue; 267541a524abSAlex Deucher if (k >= SUMO_MAX_HARDWARE_POWERLEVELS) 267641a524abSAlex Deucher break; 267741a524abSAlex Deucher clock_info = (union pplib_clock_info *) 26789af37a7dSAlex Deucher ((u8 *)&clock_info_array->clockInfo[0] + 26799af37a7dSAlex Deucher (clock_array_index * clock_info_array->ucEntrySize)); 268041a524abSAlex Deucher kv_parse_pplib_clock_info(rdev, 268141a524abSAlex Deucher &rdev->pm.dpm.ps[i], k, 268241a524abSAlex Deucher clock_info); 268341a524abSAlex Deucher k++; 268441a524abSAlex Deucher } 268541a524abSAlex Deucher kv_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i], 268641a524abSAlex Deucher non_clock_info, 268741a524abSAlex Deucher non_clock_info_array->ucEntrySize); 268841a524abSAlex Deucher power_state_offset += 2 + power_state->v2.ucNumDPMLevels; 268941a524abSAlex Deucher } 269041a524abSAlex Deucher rdev->pm.dpm.num_ps = state_array->ucNumEntries; 269142332905SAlex Deucher 269242332905SAlex Deucher /* fill in the vce power states */ 269342332905SAlex Deucher for (i = 0; i < RADEON_MAX_VCE_LEVELS; i++) { 269442332905SAlex Deucher u32 sclk; 269542332905SAlex Deucher clock_array_index = rdev->pm.dpm.vce_states[i].clk_idx; 269642332905SAlex Deucher clock_info = (union pplib_clock_info *) 269742332905SAlex Deucher &clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize]; 269842332905SAlex Deucher sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow); 269942332905SAlex Deucher sclk |= clock_info->sumo.ucEngineClockHigh << 16; 270042332905SAlex Deucher rdev->pm.dpm.vce_states[i].sclk = sclk; 270142332905SAlex Deucher rdev->pm.dpm.vce_states[i].mclk = 0; 270242332905SAlex Deucher } 270342332905SAlex Deucher 270441a524abSAlex Deucher return 0; 270541a524abSAlex Deucher } 270641a524abSAlex Deucher 270741a524abSAlex Deucher int kv_dpm_init(struct radeon_device *rdev) 270841a524abSAlex Deucher { 270941a524abSAlex Deucher struct kv_power_info *pi; 271041a524abSAlex Deucher int ret, i; 271141a524abSAlex Deucher 271241a524abSAlex Deucher pi = kzalloc(sizeof(struct kv_power_info), GFP_KERNEL); 271341a524abSAlex Deucher if (pi == NULL) 271441a524abSAlex Deucher return -ENOMEM; 271541a524abSAlex Deucher rdev->pm.dpm.priv = pi; 271641a524abSAlex Deucher 271782f79cc5SAlex Deucher ret = r600_get_platform_caps(rdev); 271882f79cc5SAlex Deucher if (ret) 271982f79cc5SAlex Deucher return ret; 272082f79cc5SAlex Deucher 272141a524abSAlex Deucher ret = r600_parse_extended_power_table(rdev); 272241a524abSAlex Deucher if (ret) 272341a524abSAlex Deucher return ret; 272441a524abSAlex Deucher 272541a524abSAlex Deucher for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) 272641a524abSAlex Deucher pi->at[i] = TRINITY_AT_DFLT; 272741a524abSAlex Deucher 272841a524abSAlex Deucher pi->sram_end = SMC_RAM_END; 272941a524abSAlex Deucher 273072b3f918SAlex Deucher /* Enabling nb dpm on an asrock system prevents dpm from working */ 273172b3f918SAlex Deucher if (rdev->pdev->subsystem_vendor == 0x1849) 273272b3f918SAlex Deucher pi->enable_nb_dpm = false; 273372b3f918SAlex Deucher else 273441a524abSAlex Deucher pi->enable_nb_dpm = true; 273541a524abSAlex Deucher 273641a524abSAlex Deucher pi->caps_power_containment = true; 273741a524abSAlex Deucher pi->caps_cac = true; 273841a524abSAlex Deucher pi->enable_didt = false; 273941a524abSAlex Deucher if (pi->enable_didt) { 274041a524abSAlex Deucher pi->caps_sq_ramping = true; 274141a524abSAlex Deucher pi->caps_db_ramping = true; 274241a524abSAlex Deucher pi->caps_td_ramping = true; 274341a524abSAlex Deucher pi->caps_tcp_ramping = true; 274441a524abSAlex Deucher } 274541a524abSAlex Deucher 274641a524abSAlex Deucher pi->caps_sclk_ds = true; 274741a524abSAlex Deucher pi->enable_auto_thermal_throttling = true; 274841a524abSAlex Deucher pi->disable_nb_ps3_in_battery = false; 274972b3f918SAlex Deucher if (radeon_bapm == -1) { 275002ae7af5SAlex Deucher /* only enable bapm on KB, ML by default */ 275102ae7af5SAlex Deucher if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) 275209f95d5bSAlex Deucher pi->bapm_enable = true; 275302ae7af5SAlex Deucher else 275402ae7af5SAlex Deucher pi->bapm_enable = false; 275572b3f918SAlex Deucher } else if (radeon_bapm == 0) { 275672b3f918SAlex Deucher pi->bapm_enable = false; 275772b3f918SAlex Deucher } else { 275872b3f918SAlex Deucher pi->bapm_enable = true; 275972b3f918SAlex Deucher } 276041a524abSAlex Deucher pi->voltage_drop_t = 0; 276141a524abSAlex Deucher pi->caps_sclk_throttle_low_notification = false; 276241a524abSAlex Deucher pi->caps_fps = false; /* true? */ 276377df508aSAlex Deucher pi->caps_uvd_pg = true; 276441a524abSAlex Deucher pi->caps_uvd_dpm = true; 276542332905SAlex Deucher pi->caps_vce_pg = false; /* XXX true */ 276641a524abSAlex Deucher pi->caps_samu_pg = false; 276741a524abSAlex Deucher pi->caps_acp_pg = false; 276841a524abSAlex Deucher pi->caps_stable_p_state = false; 276941a524abSAlex Deucher 277041a524abSAlex Deucher ret = kv_parse_sys_info_table(rdev); 277141a524abSAlex Deucher if (ret) 277241a524abSAlex Deucher return ret; 277341a524abSAlex Deucher 277441a524abSAlex Deucher kv_patch_voltage_values(rdev); 277541a524abSAlex Deucher kv_construct_boot_state(rdev); 277641a524abSAlex Deucher 277741a524abSAlex Deucher ret = kv_parse_power_table(rdev); 277841a524abSAlex Deucher if (ret) 277941a524abSAlex Deucher return ret; 278041a524abSAlex Deucher 278141a524abSAlex Deucher pi->enable_dpm = true; 278241a524abSAlex Deucher 278341a524abSAlex Deucher return 0; 278441a524abSAlex Deucher } 278541a524abSAlex Deucher 2786ae3e40e8SAlex Deucher void kv_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, 2787ae3e40e8SAlex Deucher struct seq_file *m) 2788ae3e40e8SAlex Deucher { 2789ae3e40e8SAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 2790ae3e40e8SAlex Deucher u32 current_index = 2791ae3e40e8SAlex Deucher (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_SCLK_INDEX_MASK) >> 2792ae3e40e8SAlex Deucher CURR_SCLK_INDEX_SHIFT; 2793ae3e40e8SAlex Deucher u32 sclk, tmp; 2794ae3e40e8SAlex Deucher u16 vddc; 2795ae3e40e8SAlex Deucher 2796ae3e40e8SAlex Deucher if (current_index >= SMU__NUM_SCLK_DPM_STATE) { 2797ae3e40e8SAlex Deucher seq_printf(m, "invalid dpm profile %d\n", current_index); 2798ae3e40e8SAlex Deucher } else { 2799ae3e40e8SAlex Deucher sclk = be32_to_cpu(pi->graphics_level[current_index].SclkFrequency); 2800ae3e40e8SAlex Deucher tmp = (RREG32_SMC(SMU_VOLTAGE_STATUS) & SMU_VOLTAGE_CURRENT_LEVEL_MASK) >> 2801ae3e40e8SAlex Deucher SMU_VOLTAGE_CURRENT_LEVEL_SHIFT; 2802ae3e40e8SAlex Deucher vddc = kv_convert_8bit_index_to_voltage(rdev, (u16)tmp); 2803369283bfSAlex Deucher seq_printf(m, "uvd %sabled\n", pi->uvd_power_gated ? "dis" : "en"); 2804369283bfSAlex Deucher seq_printf(m, "vce %sabled\n", pi->vce_power_gated ? "dis" : "en"); 2805ae3e40e8SAlex Deucher seq_printf(m, "power level %d sclk: %u vddc: %u\n", 2806ae3e40e8SAlex Deucher current_index, sclk, vddc); 2807ae3e40e8SAlex Deucher } 2808ae3e40e8SAlex Deucher } 2809ae3e40e8SAlex Deucher 281041a524abSAlex Deucher void kv_dpm_print_power_state(struct radeon_device *rdev, 281141a524abSAlex Deucher struct radeon_ps *rps) 281241a524abSAlex Deucher { 281341a524abSAlex Deucher int i; 281441a524abSAlex Deucher struct kv_ps *ps = kv_get_ps(rps); 281541a524abSAlex Deucher 281641a524abSAlex Deucher r600_dpm_print_class_info(rps->class, rps->class2); 281741a524abSAlex Deucher r600_dpm_print_cap_info(rps->caps); 281841a524abSAlex Deucher printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); 281941a524abSAlex Deucher for (i = 0; i < ps->num_levels; i++) { 282041a524abSAlex Deucher struct kv_pl *pl = &ps->levels[i]; 282141a524abSAlex Deucher printk("\t\tpower level %d sclk: %u vddc: %u\n", 282241a524abSAlex Deucher i, pl->sclk, 282341a524abSAlex Deucher kv_convert_8bit_index_to_voltage(rdev, pl->vddc_index)); 282441a524abSAlex Deucher } 282541a524abSAlex Deucher r600_dpm_print_ps_status(rdev, rps); 282641a524abSAlex Deucher } 282741a524abSAlex Deucher 282841a524abSAlex Deucher void kv_dpm_fini(struct radeon_device *rdev) 282941a524abSAlex Deucher { 283041a524abSAlex Deucher int i; 283141a524abSAlex Deucher 283241a524abSAlex Deucher for (i = 0; i < rdev->pm.dpm.num_ps; i++) { 283341a524abSAlex Deucher kfree(rdev->pm.dpm.ps[i].ps_priv); 283441a524abSAlex Deucher } 283541a524abSAlex Deucher kfree(rdev->pm.dpm.ps); 283641a524abSAlex Deucher kfree(rdev->pm.dpm.priv); 283741a524abSAlex Deucher r600_free_extended_power_table(rdev); 283841a524abSAlex Deucher } 283941a524abSAlex Deucher 284041a524abSAlex Deucher void kv_dpm_display_configuration_changed(struct radeon_device *rdev) 284141a524abSAlex Deucher { 284241a524abSAlex Deucher 284341a524abSAlex Deucher } 284441a524abSAlex Deucher 284541a524abSAlex Deucher u32 kv_dpm_get_sclk(struct radeon_device *rdev, bool low) 284641a524abSAlex Deucher { 284741a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 284841a524abSAlex Deucher struct kv_ps *requested_state = kv_get_ps(&pi->requested_rps); 284941a524abSAlex Deucher 285041a524abSAlex Deucher if (low) 285141a524abSAlex Deucher return requested_state->levels[0].sclk; 285241a524abSAlex Deucher else 285341a524abSAlex Deucher return requested_state->levels[requested_state->num_levels - 1].sclk; 285441a524abSAlex Deucher } 285541a524abSAlex Deucher 285641a524abSAlex Deucher u32 kv_dpm_get_mclk(struct radeon_device *rdev, bool low) 285741a524abSAlex Deucher { 285841a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 285941a524abSAlex Deucher 286041a524abSAlex Deucher return pi->sys_info.bootup_uma_clk; 286141a524abSAlex Deucher } 286241a524abSAlex Deucher 2863