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 2464a9dfc4SMasahiro Yamada #include <drm/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 1172410af8d7SAlex Deucher static void kv_enable_thermal_int(struct radeon_device *rdev, bool enable) 1173410af8d7SAlex Deucher { 1174410af8d7SAlex Deucher u32 thermal_int; 1175410af8d7SAlex Deucher 1176410af8d7SAlex Deucher thermal_int = RREG32_SMC(CG_THERMAL_INT_CTRL); 1177410af8d7SAlex Deucher if (enable) 1178410af8d7SAlex Deucher thermal_int |= THERM_INTH_MASK | THERM_INTL_MASK; 1179410af8d7SAlex Deucher else 1180410af8d7SAlex Deucher thermal_int &= ~(THERM_INTH_MASK | THERM_INTL_MASK); 1181410af8d7SAlex Deucher WREG32_SMC(CG_THERMAL_INT_CTRL, thermal_int); 1182410af8d7SAlex Deucher 1183410af8d7SAlex Deucher } 1184410af8d7SAlex Deucher 118541a524abSAlex Deucher int kv_dpm_enable(struct radeon_device *rdev) 118641a524abSAlex Deucher { 118741a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 118841a524abSAlex Deucher int ret; 118941a524abSAlex Deucher 119041a524abSAlex Deucher ret = kv_process_firmware_header(rdev); 119141a524abSAlex Deucher if (ret) { 119241a524abSAlex Deucher DRM_ERROR("kv_process_firmware_header failed\n"); 119341a524abSAlex Deucher return ret; 119441a524abSAlex Deucher } 119541a524abSAlex Deucher kv_init_fps_limits(rdev); 119641a524abSAlex Deucher kv_init_graphics_levels(rdev); 119741a524abSAlex Deucher ret = kv_program_bootup_state(rdev); 119841a524abSAlex Deucher if (ret) { 119941a524abSAlex Deucher DRM_ERROR("kv_program_bootup_state failed\n"); 120041a524abSAlex Deucher return ret; 120141a524abSAlex Deucher } 120241a524abSAlex Deucher kv_calculate_dfs_bypass_settings(rdev); 120341a524abSAlex Deucher ret = kv_upload_dpm_settings(rdev); 120441a524abSAlex Deucher if (ret) { 120541a524abSAlex Deucher DRM_ERROR("kv_upload_dpm_settings failed\n"); 120641a524abSAlex Deucher return ret; 120741a524abSAlex Deucher } 120841a524abSAlex Deucher ret = kv_populate_uvd_table(rdev); 120941a524abSAlex Deucher if (ret) { 121041a524abSAlex Deucher DRM_ERROR("kv_populate_uvd_table failed\n"); 121141a524abSAlex Deucher return ret; 121241a524abSAlex Deucher } 121341a524abSAlex Deucher ret = kv_populate_vce_table(rdev); 121441a524abSAlex Deucher if (ret) { 121541a524abSAlex Deucher DRM_ERROR("kv_populate_vce_table failed\n"); 121641a524abSAlex Deucher return ret; 121741a524abSAlex Deucher } 121841a524abSAlex Deucher ret = kv_populate_samu_table(rdev); 121941a524abSAlex Deucher if (ret) { 122041a524abSAlex Deucher DRM_ERROR("kv_populate_samu_table failed\n"); 122141a524abSAlex Deucher return ret; 122241a524abSAlex Deucher } 122341a524abSAlex Deucher ret = kv_populate_acp_table(rdev); 122441a524abSAlex Deucher if (ret) { 122541a524abSAlex Deucher DRM_ERROR("kv_populate_acp_table failed\n"); 122641a524abSAlex Deucher return ret; 122741a524abSAlex Deucher } 122841a524abSAlex Deucher kv_program_vc(rdev); 122941a524abSAlex Deucher #if 0 123041a524abSAlex Deucher kv_initialize_hardware_cac_manager(rdev); 123141a524abSAlex Deucher #endif 123241a524abSAlex Deucher kv_start_am(rdev); 123341a524abSAlex Deucher if (pi->enable_auto_thermal_throttling) { 123441a524abSAlex Deucher ret = kv_enable_auto_thermal_throttling(rdev); 123541a524abSAlex Deucher if (ret) { 123641a524abSAlex Deucher DRM_ERROR("kv_enable_auto_thermal_throttling failed\n"); 123741a524abSAlex Deucher return ret; 123841a524abSAlex Deucher } 123941a524abSAlex Deucher } 124041a524abSAlex Deucher ret = kv_enable_dpm_voltage_scaling(rdev); 124141a524abSAlex Deucher if (ret) { 124241a524abSAlex Deucher DRM_ERROR("kv_enable_dpm_voltage_scaling failed\n"); 124341a524abSAlex Deucher return ret; 124441a524abSAlex Deucher } 124541a524abSAlex Deucher ret = kv_set_dpm_interval(rdev); 124641a524abSAlex Deucher if (ret) { 124741a524abSAlex Deucher DRM_ERROR("kv_set_dpm_interval failed\n"); 124841a524abSAlex Deucher return ret; 124941a524abSAlex Deucher } 125041a524abSAlex Deucher ret = kv_set_dpm_boot_state(rdev); 125141a524abSAlex Deucher if (ret) { 125241a524abSAlex Deucher DRM_ERROR("kv_set_dpm_boot_state failed\n"); 125341a524abSAlex Deucher return ret; 125441a524abSAlex Deucher } 125541a524abSAlex Deucher ret = kv_enable_ulv(rdev, true); 125641a524abSAlex Deucher if (ret) { 125741a524abSAlex Deucher DRM_ERROR("kv_enable_ulv failed\n"); 125841a524abSAlex Deucher return ret; 125941a524abSAlex Deucher } 126041a524abSAlex Deucher kv_start_dpm(rdev); 126141a524abSAlex Deucher ret = kv_enable_didt(rdev, true); 126241a524abSAlex Deucher if (ret) { 126341a524abSAlex Deucher DRM_ERROR("kv_enable_didt failed\n"); 126441a524abSAlex Deucher return ret; 126541a524abSAlex Deucher } 126641a524abSAlex Deucher ret = kv_enable_smc_cac(rdev, true); 126741a524abSAlex Deucher if (ret) { 126841a524abSAlex Deucher DRM_ERROR("kv_enable_smc_cac failed\n"); 126941a524abSAlex Deucher return ret; 127041a524abSAlex Deucher } 127141a524abSAlex Deucher 1272136de91eSAlex Deucher kv_reset_acp_boot_level(rdev); 1273136de91eSAlex Deucher 127464d03221SAlex Deucher ret = kv_smc_bapm_enable(rdev, false); 127564d03221SAlex Deucher if (ret) { 127664d03221SAlex Deucher DRM_ERROR("kv_smc_bapm_enable failed\n"); 127764d03221SAlex Deucher return ret; 127864d03221SAlex Deucher } 127964d03221SAlex Deucher 128041a524abSAlex Deucher kv_update_current_ps(rdev, rdev->pm.dpm.boot_ps); 128141a524abSAlex Deucher 128241a524abSAlex Deucher return ret; 128341a524abSAlex Deucher } 128441a524abSAlex Deucher 1285d8852c34SAlex Deucher int kv_dpm_late_enable(struct radeon_device *rdev) 1286d8852c34SAlex Deucher { 12877c7e867cSDave Jones int ret = 0; 1288d8852c34SAlex Deucher 1289d8852c34SAlex Deucher if (rdev->irq.installed && 1290d8852c34SAlex Deucher r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { 1291d8852c34SAlex Deucher ret = kv_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); 1292d8852c34SAlex Deucher if (ret) { 1293d8852c34SAlex Deucher DRM_ERROR("kv_set_thermal_temperature_range failed\n"); 1294d8852c34SAlex Deucher return ret; 1295d8852c34SAlex Deucher } 1296410af8d7SAlex Deucher kv_enable_thermal_int(rdev, true); 1297d8852c34SAlex Deucher } 1298d8852c34SAlex Deucher 1299d8852c34SAlex Deucher /* powerdown unused blocks for now */ 1300d8852c34SAlex Deucher kv_dpm_powergate_acp(rdev, true); 1301d8852c34SAlex Deucher kv_dpm_powergate_samu(rdev, true); 1302d8852c34SAlex Deucher kv_dpm_powergate_vce(rdev, true); 1303d8852c34SAlex Deucher kv_dpm_powergate_uvd(rdev, true); 1304d8852c34SAlex Deucher 1305d8852c34SAlex Deucher return ret; 1306d8852c34SAlex Deucher } 1307d8852c34SAlex Deucher 130841a524abSAlex Deucher void kv_dpm_disable(struct radeon_device *rdev) 130941a524abSAlex Deucher { 131064d03221SAlex Deucher kv_smc_bapm_enable(rdev, false); 131164d03221SAlex Deucher 131239da0384SAlex Deucher if (rdev->family == CHIP_MULLINS) 131339da0384SAlex Deucher kv_enable_nb_dpm(rdev, false); 131439da0384SAlex Deucher 131539c88ae3SAlex Deucher /* powerup blocks */ 131639c88ae3SAlex Deucher kv_dpm_powergate_acp(rdev, false); 131739c88ae3SAlex Deucher kv_dpm_powergate_samu(rdev, false); 131839c88ae3SAlex Deucher kv_dpm_powergate_vce(rdev, false); 131939c88ae3SAlex Deucher kv_dpm_powergate_uvd(rdev, false); 132039c88ae3SAlex Deucher 132141a524abSAlex Deucher kv_enable_smc_cac(rdev, false); 132241a524abSAlex Deucher kv_enable_didt(rdev, false); 132341a524abSAlex Deucher kv_clear_vc(rdev); 132441a524abSAlex Deucher kv_stop_dpm(rdev); 132541a524abSAlex Deucher kv_enable_ulv(rdev, false); 132641a524abSAlex Deucher kv_reset_am(rdev); 1327410af8d7SAlex Deucher kv_enable_thermal_int(rdev, false); 132841a524abSAlex Deucher 132941a524abSAlex Deucher kv_update_current_ps(rdev, rdev->pm.dpm.boot_ps); 133041a524abSAlex Deucher } 133141a524abSAlex Deucher 133241a524abSAlex Deucher #if 0 133341a524abSAlex Deucher static int kv_write_smc_soft_register(struct radeon_device *rdev, 133441a524abSAlex Deucher u16 reg_offset, u32 value) 133541a524abSAlex Deucher { 133641a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 133741a524abSAlex Deucher 133841a524abSAlex Deucher return kv_copy_bytes_to_smc(rdev, pi->soft_regs_start + reg_offset, 133941a524abSAlex Deucher (u8 *)&value, sizeof(u16), pi->sram_end); 134041a524abSAlex Deucher } 134141a524abSAlex Deucher 134241a524abSAlex Deucher static int kv_read_smc_soft_register(struct radeon_device *rdev, 134341a524abSAlex Deucher u16 reg_offset, u32 *value) 134441a524abSAlex Deucher { 134541a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 134641a524abSAlex Deucher 134741a524abSAlex Deucher return kv_read_smc_sram_dword(rdev, pi->soft_regs_start + reg_offset, 134841a524abSAlex Deucher value, pi->sram_end); 134941a524abSAlex Deucher } 135041a524abSAlex Deucher #endif 135141a524abSAlex Deucher 135241a524abSAlex Deucher static void kv_init_sclk_t(struct radeon_device *rdev) 135341a524abSAlex Deucher { 135441a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 135541a524abSAlex Deucher 135641a524abSAlex Deucher pi->low_sclk_interrupt_t = 0; 135741a524abSAlex Deucher } 135841a524abSAlex Deucher 135941a524abSAlex Deucher static int kv_init_fps_limits(struct radeon_device *rdev) 136041a524abSAlex Deucher { 136141a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 136241a524abSAlex Deucher int ret = 0; 136341a524abSAlex Deucher 136441a524abSAlex Deucher if (pi->caps_fps) { 136541a524abSAlex Deucher u16 tmp; 136641a524abSAlex Deucher 136741a524abSAlex Deucher tmp = 45; 136841a524abSAlex Deucher pi->fps_high_t = cpu_to_be16(tmp); 136941a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 137041a524abSAlex Deucher pi->dpm_table_start + 137141a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, FpsHighT), 137241a524abSAlex Deucher (u8 *)&pi->fps_high_t, 137341a524abSAlex Deucher sizeof(u16), pi->sram_end); 137441a524abSAlex Deucher 137541a524abSAlex Deucher tmp = 30; 137641a524abSAlex Deucher pi->fps_low_t = cpu_to_be16(tmp); 137741a524abSAlex Deucher 137841a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 137941a524abSAlex Deucher pi->dpm_table_start + 138041a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, FpsLowT), 138141a524abSAlex Deucher (u8 *)&pi->fps_low_t, 138241a524abSAlex Deucher sizeof(u16), pi->sram_end); 138341a524abSAlex Deucher 138441a524abSAlex Deucher } 138541a524abSAlex Deucher return ret; 138641a524abSAlex Deucher } 138741a524abSAlex Deucher 138841a524abSAlex Deucher static void kv_init_powergate_state(struct radeon_device *rdev) 138941a524abSAlex Deucher { 139041a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 139141a524abSAlex Deucher 139241a524abSAlex Deucher pi->uvd_power_gated = false; 139341a524abSAlex Deucher pi->vce_power_gated = false; 139441a524abSAlex Deucher pi->samu_power_gated = false; 139541a524abSAlex Deucher pi->acp_power_gated = false; 139641a524abSAlex Deucher 139741a524abSAlex Deucher } 139841a524abSAlex Deucher 139941a524abSAlex Deucher static int kv_enable_uvd_dpm(struct radeon_device *rdev, bool enable) 140041a524abSAlex Deucher { 140141a524abSAlex Deucher return kv_notify_message_to_smu(rdev, enable ? 140241a524abSAlex Deucher PPSMC_MSG_UVDDPM_Enable : PPSMC_MSG_UVDDPM_Disable); 140341a524abSAlex Deucher } 140441a524abSAlex Deucher 140541a524abSAlex Deucher static int kv_enable_vce_dpm(struct radeon_device *rdev, bool enable) 140641a524abSAlex Deucher { 140741a524abSAlex Deucher return kv_notify_message_to_smu(rdev, enable ? 140841a524abSAlex Deucher PPSMC_MSG_VCEDPM_Enable : PPSMC_MSG_VCEDPM_Disable); 140941a524abSAlex Deucher } 141041a524abSAlex Deucher 141141a524abSAlex Deucher static int kv_enable_samu_dpm(struct radeon_device *rdev, bool enable) 141241a524abSAlex Deucher { 141341a524abSAlex Deucher return kv_notify_message_to_smu(rdev, enable ? 141441a524abSAlex Deucher PPSMC_MSG_SAMUDPM_Enable : PPSMC_MSG_SAMUDPM_Disable); 141541a524abSAlex Deucher } 141641a524abSAlex Deucher 141741a524abSAlex Deucher static int kv_enable_acp_dpm(struct radeon_device *rdev, bool enable) 141841a524abSAlex Deucher { 141941a524abSAlex Deucher return kv_notify_message_to_smu(rdev, enable ? 142041a524abSAlex Deucher PPSMC_MSG_ACPDPM_Enable : PPSMC_MSG_ACPDPM_Disable); 142141a524abSAlex Deucher } 142241a524abSAlex Deucher 142341a524abSAlex Deucher static int kv_update_uvd_dpm(struct radeon_device *rdev, bool gate) 142441a524abSAlex Deucher { 142541a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 142641a524abSAlex Deucher struct radeon_uvd_clock_voltage_dependency_table *table = 142741a524abSAlex Deucher &rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table; 142841a524abSAlex Deucher int ret; 142947f5c746SAlex Deucher u32 mask; 143041a524abSAlex Deucher 143141a524abSAlex Deucher if (!gate) { 143247f5c746SAlex Deucher if (table->count) 143341a524abSAlex Deucher pi->uvd_boot_level = table->count - 1; 143441a524abSAlex Deucher else 143541a524abSAlex Deucher pi->uvd_boot_level = 0; 143641a524abSAlex Deucher 143747f5c746SAlex Deucher if (!pi->caps_uvd_dpm || pi->caps_stable_p_state) { 143847f5c746SAlex Deucher mask = 1 << pi->uvd_boot_level; 143947f5c746SAlex Deucher } else { 144047f5c746SAlex Deucher mask = 0x1f; 144147f5c746SAlex Deucher } 144247f5c746SAlex Deucher 144341a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 144441a524abSAlex Deucher pi->dpm_table_start + 144541a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, UvdBootLevel), 144641a524abSAlex Deucher (uint8_t *)&pi->uvd_boot_level, 144741a524abSAlex Deucher sizeof(u8), pi->sram_end); 144841a524abSAlex Deucher if (ret) 144941a524abSAlex Deucher return ret; 145041a524abSAlex Deucher 145141a524abSAlex Deucher kv_send_msg_to_smc_with_parameter(rdev, 145241a524abSAlex Deucher PPSMC_MSG_UVDDPM_SetEnabledMask, 145347f5c746SAlex Deucher mask); 145441a524abSAlex Deucher } 145541a524abSAlex Deucher 145641a524abSAlex Deucher return kv_enable_uvd_dpm(rdev, !gate); 145741a524abSAlex Deucher } 145841a524abSAlex Deucher 1459c83dec3bSAlex Deucher static u8 kv_get_vce_boot_level(struct radeon_device *rdev, u32 evclk) 146041a524abSAlex Deucher { 146141a524abSAlex Deucher u8 i; 146241a524abSAlex Deucher struct radeon_vce_clock_voltage_dependency_table *table = 146341a524abSAlex Deucher &rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table; 146441a524abSAlex Deucher 146541a524abSAlex Deucher for (i = 0; i < table->count; i++) { 1466c83dec3bSAlex Deucher if (table->entries[i].evclk >= evclk) 146741a524abSAlex Deucher break; 146841a524abSAlex Deucher } 146941a524abSAlex Deucher 147041a524abSAlex Deucher return i; 147141a524abSAlex Deucher } 147241a524abSAlex Deucher 147341a524abSAlex Deucher static int kv_update_vce_dpm(struct radeon_device *rdev, 147441a524abSAlex Deucher struct radeon_ps *radeon_new_state, 147541a524abSAlex Deucher struct radeon_ps *radeon_current_state) 147641a524abSAlex Deucher { 147741a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 147841a524abSAlex Deucher struct radeon_vce_clock_voltage_dependency_table *table = 147941a524abSAlex Deucher &rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table; 148041a524abSAlex Deucher int ret; 148141a524abSAlex Deucher 148241a524abSAlex Deucher if (radeon_new_state->evclk > 0 && radeon_current_state->evclk == 0) { 148342332905SAlex Deucher kv_dpm_powergate_vce(rdev, false); 1484a1d6f97cSAlex Deucher /* turn the clocks on when encoding */ 1485a1d6f97cSAlex Deucher cik_update_cg(rdev, RADEON_CG_BLOCK_VCE, false); 148641a524abSAlex Deucher if (pi->caps_stable_p_state) 148741a524abSAlex Deucher pi->vce_boot_level = table->count - 1; 148841a524abSAlex Deucher else 1489c83dec3bSAlex Deucher pi->vce_boot_level = kv_get_vce_boot_level(rdev, radeon_new_state->evclk); 149041a524abSAlex Deucher 149141a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 149241a524abSAlex Deucher pi->dpm_table_start + 149341a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, VceBootLevel), 149441a524abSAlex Deucher (u8 *)&pi->vce_boot_level, 149541a524abSAlex Deucher sizeof(u8), 149641a524abSAlex Deucher pi->sram_end); 149741a524abSAlex Deucher if (ret) 149841a524abSAlex Deucher return ret; 149941a524abSAlex Deucher 150041a524abSAlex Deucher if (pi->caps_stable_p_state) 150141a524abSAlex Deucher kv_send_msg_to_smc_with_parameter(rdev, 150241a524abSAlex Deucher PPSMC_MSG_VCEDPM_SetEnabledMask, 150341a524abSAlex Deucher (1 << pi->vce_boot_level)); 150441a524abSAlex Deucher 150541a524abSAlex Deucher kv_enable_vce_dpm(rdev, true); 150641a524abSAlex Deucher } else if (radeon_new_state->evclk == 0 && radeon_current_state->evclk > 0) { 150741a524abSAlex Deucher kv_enable_vce_dpm(rdev, false); 1508a1d6f97cSAlex Deucher /* turn the clocks off when not encoding */ 1509a1d6f97cSAlex Deucher cik_update_cg(rdev, RADEON_CG_BLOCK_VCE, true); 151042332905SAlex Deucher kv_dpm_powergate_vce(rdev, true); 151141a524abSAlex Deucher } 151241a524abSAlex Deucher 151341a524abSAlex Deucher return 0; 151441a524abSAlex Deucher } 151541a524abSAlex Deucher 151641a524abSAlex Deucher static int kv_update_samu_dpm(struct radeon_device *rdev, bool gate) 151741a524abSAlex Deucher { 151841a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 151941a524abSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 152041a524abSAlex Deucher &rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table; 152141a524abSAlex Deucher int ret; 152241a524abSAlex Deucher 152341a524abSAlex Deucher if (!gate) { 152441a524abSAlex Deucher if (pi->caps_stable_p_state) 152541a524abSAlex Deucher pi->samu_boot_level = table->count - 1; 152641a524abSAlex Deucher else 152741a524abSAlex Deucher pi->samu_boot_level = 0; 152841a524abSAlex Deucher 152941a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 153041a524abSAlex Deucher pi->dpm_table_start + 153141a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, SamuBootLevel), 153241a524abSAlex Deucher (u8 *)&pi->samu_boot_level, 153341a524abSAlex Deucher sizeof(u8), 153441a524abSAlex Deucher pi->sram_end); 153541a524abSAlex Deucher if (ret) 153641a524abSAlex Deucher return ret; 153741a524abSAlex Deucher 153841a524abSAlex Deucher if (pi->caps_stable_p_state) 153941a524abSAlex Deucher kv_send_msg_to_smc_with_parameter(rdev, 154041a524abSAlex Deucher PPSMC_MSG_SAMUDPM_SetEnabledMask, 154141a524abSAlex Deucher (1 << pi->samu_boot_level)); 154241a524abSAlex Deucher } 154341a524abSAlex Deucher 154441a524abSAlex Deucher return kv_enable_samu_dpm(rdev, !gate); 154541a524abSAlex Deucher } 154641a524abSAlex Deucher 1547136de91eSAlex Deucher static u8 kv_get_acp_boot_level(struct radeon_device *rdev) 1548136de91eSAlex Deucher { 1549136de91eSAlex Deucher u8 i; 1550136de91eSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 1551136de91eSAlex Deucher &rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table; 1552136de91eSAlex Deucher 1553136de91eSAlex Deucher for (i = 0; i < table->count; i++) { 1554136de91eSAlex Deucher if (table->entries[i].clk >= 0) /* XXX */ 1555136de91eSAlex Deucher break; 1556136de91eSAlex Deucher } 1557136de91eSAlex Deucher 1558136de91eSAlex Deucher if (i >= table->count) 1559136de91eSAlex Deucher i = table->count - 1; 1560136de91eSAlex Deucher 1561136de91eSAlex Deucher return i; 1562136de91eSAlex Deucher } 1563136de91eSAlex Deucher 1564136de91eSAlex Deucher static void kv_update_acp_boot_level(struct radeon_device *rdev) 1565136de91eSAlex Deucher { 1566136de91eSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 1567136de91eSAlex Deucher u8 acp_boot_level; 1568136de91eSAlex Deucher 1569136de91eSAlex Deucher if (!pi->caps_stable_p_state) { 1570136de91eSAlex Deucher acp_boot_level = kv_get_acp_boot_level(rdev); 1571136de91eSAlex Deucher if (acp_boot_level != pi->acp_boot_level) { 1572136de91eSAlex Deucher pi->acp_boot_level = acp_boot_level; 1573136de91eSAlex Deucher kv_send_msg_to_smc_with_parameter(rdev, 1574136de91eSAlex Deucher PPSMC_MSG_ACPDPM_SetEnabledMask, 1575136de91eSAlex Deucher (1 << pi->acp_boot_level)); 1576136de91eSAlex Deucher } 1577136de91eSAlex Deucher } 1578136de91eSAlex Deucher } 1579136de91eSAlex Deucher 158041a524abSAlex Deucher static int kv_update_acp_dpm(struct radeon_device *rdev, bool gate) 158141a524abSAlex Deucher { 158241a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 158341a524abSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 158441a524abSAlex Deucher &rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table; 158541a524abSAlex Deucher int ret; 158641a524abSAlex Deucher 158741a524abSAlex Deucher if (!gate) { 158841a524abSAlex Deucher if (pi->caps_stable_p_state) 158941a524abSAlex Deucher pi->acp_boot_level = table->count - 1; 159041a524abSAlex Deucher else 1591136de91eSAlex Deucher pi->acp_boot_level = kv_get_acp_boot_level(rdev); 159241a524abSAlex Deucher 159341a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 159441a524abSAlex Deucher pi->dpm_table_start + 159541a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, AcpBootLevel), 159641a524abSAlex Deucher (u8 *)&pi->acp_boot_level, 159741a524abSAlex Deucher sizeof(u8), 159841a524abSAlex Deucher pi->sram_end); 159941a524abSAlex Deucher if (ret) 160041a524abSAlex Deucher return ret; 160141a524abSAlex Deucher 160241a524abSAlex Deucher if (pi->caps_stable_p_state) 160341a524abSAlex Deucher kv_send_msg_to_smc_with_parameter(rdev, 160441a524abSAlex Deucher PPSMC_MSG_ACPDPM_SetEnabledMask, 160541a524abSAlex Deucher (1 << pi->acp_boot_level)); 160641a524abSAlex Deucher } 160741a524abSAlex Deucher 160841a524abSAlex Deucher return kv_enable_acp_dpm(rdev, !gate); 160941a524abSAlex Deucher } 161041a524abSAlex Deucher 161177df508aSAlex Deucher void kv_dpm_powergate_uvd(struct radeon_device *rdev, bool gate) 161241a524abSAlex Deucher { 161341a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 161441a524abSAlex Deucher 161541a524abSAlex Deucher if (pi->uvd_power_gated == gate) 161641a524abSAlex Deucher return; 161741a524abSAlex Deucher 161841a524abSAlex Deucher pi->uvd_power_gated = gate; 161941a524abSAlex Deucher 162041a524abSAlex Deucher if (gate) { 1621f30df435SAlex Deucher if (pi->caps_uvd_pg) { 1622e409b128SChristian König uvd_v1_0_stop(rdev); 162377df508aSAlex Deucher cik_update_cg(rdev, RADEON_CG_BLOCK_UVD, false); 1624f30df435SAlex Deucher } 162577df508aSAlex Deucher kv_update_uvd_dpm(rdev, gate); 162641a524abSAlex Deucher if (pi->caps_uvd_pg) 162741a524abSAlex Deucher kv_notify_message_to_smu(rdev, PPSMC_MSG_UVDPowerOFF); 162841a524abSAlex Deucher } else { 1629f30df435SAlex Deucher if (pi->caps_uvd_pg) { 163041a524abSAlex Deucher kv_notify_message_to_smu(rdev, PPSMC_MSG_UVDPowerON); 1631e409b128SChristian König uvd_v4_2_resume(rdev); 1632e409b128SChristian König uvd_v1_0_start(rdev); 163377df508aSAlex Deucher cik_update_cg(rdev, RADEON_CG_BLOCK_UVD, true); 1634f30df435SAlex Deucher } 163577df508aSAlex Deucher kv_update_uvd_dpm(rdev, gate); 163641a524abSAlex Deucher } 163741a524abSAlex Deucher } 163841a524abSAlex Deucher 163941a524abSAlex Deucher static void kv_dpm_powergate_vce(struct radeon_device *rdev, bool gate) 164041a524abSAlex Deucher { 164141a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 164241a524abSAlex Deucher 164341a524abSAlex Deucher if (pi->vce_power_gated == gate) 164441a524abSAlex Deucher return; 164541a524abSAlex Deucher 164641a524abSAlex Deucher pi->vce_power_gated = gate; 164741a524abSAlex Deucher 164841a524abSAlex Deucher if (gate) { 164944493ba9SAlex Deucher if (pi->caps_vce_pg) { 165044493ba9SAlex Deucher /* XXX do we need a vce_v1_0_stop() ? */ 165141a524abSAlex Deucher kv_notify_message_to_smu(rdev, PPSMC_MSG_VCEPowerOFF); 165244493ba9SAlex Deucher } 165341a524abSAlex Deucher } else { 165444493ba9SAlex Deucher if (pi->caps_vce_pg) { 165541a524abSAlex Deucher kv_notify_message_to_smu(rdev, PPSMC_MSG_VCEPowerON); 165644493ba9SAlex Deucher vce_v2_0_resume(rdev); 165744493ba9SAlex Deucher vce_v1_0_start(rdev); 165844493ba9SAlex Deucher } 165941a524abSAlex Deucher } 166041a524abSAlex Deucher } 166141a524abSAlex Deucher 166241a524abSAlex Deucher static void kv_dpm_powergate_samu(struct radeon_device *rdev, bool gate) 166341a524abSAlex Deucher { 166441a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 166541a524abSAlex Deucher 166641a524abSAlex Deucher if (pi->samu_power_gated == gate) 166741a524abSAlex Deucher return; 166841a524abSAlex Deucher 166941a524abSAlex Deucher pi->samu_power_gated = gate; 167041a524abSAlex Deucher 167141a524abSAlex Deucher if (gate) { 167241a524abSAlex Deucher kv_update_samu_dpm(rdev, true); 167341a524abSAlex Deucher if (pi->caps_samu_pg) 167441a524abSAlex Deucher kv_notify_message_to_smu(rdev, PPSMC_MSG_SAMPowerOFF); 167541a524abSAlex Deucher } else { 167641a524abSAlex Deucher if (pi->caps_samu_pg) 167741a524abSAlex Deucher kv_notify_message_to_smu(rdev, PPSMC_MSG_SAMPowerON); 167841a524abSAlex Deucher kv_update_samu_dpm(rdev, false); 167941a524abSAlex Deucher } 168041a524abSAlex Deucher } 168141a524abSAlex Deucher 168241a524abSAlex Deucher static void kv_dpm_powergate_acp(struct radeon_device *rdev, bool gate) 168341a524abSAlex Deucher { 168441a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 168541a524abSAlex Deucher 168641a524abSAlex Deucher if (pi->acp_power_gated == gate) 168741a524abSAlex Deucher return; 168841a524abSAlex Deucher 16897d032a4bSSamuel Li if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) 169041a524abSAlex Deucher return; 169141a524abSAlex Deucher 169241a524abSAlex Deucher pi->acp_power_gated = gate; 169341a524abSAlex Deucher 169441a524abSAlex Deucher if (gate) { 169541a524abSAlex Deucher kv_update_acp_dpm(rdev, true); 169641a524abSAlex Deucher if (pi->caps_acp_pg) 169741a524abSAlex Deucher kv_notify_message_to_smu(rdev, PPSMC_MSG_ACPPowerOFF); 169841a524abSAlex Deucher } else { 169941a524abSAlex Deucher if (pi->caps_acp_pg) 170041a524abSAlex Deucher kv_notify_message_to_smu(rdev, PPSMC_MSG_ACPPowerON); 170141a524abSAlex Deucher kv_update_acp_dpm(rdev, false); 170241a524abSAlex Deucher } 170341a524abSAlex Deucher } 170441a524abSAlex Deucher 170541a524abSAlex Deucher static void kv_set_valid_clock_range(struct radeon_device *rdev, 170641a524abSAlex Deucher struct radeon_ps *new_rps) 170741a524abSAlex Deucher { 170841a524abSAlex Deucher struct kv_ps *new_ps = kv_get_ps(new_rps); 170941a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 171041a524abSAlex Deucher u32 i; 171141a524abSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 171241a524abSAlex Deucher &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; 171341a524abSAlex Deucher 171441a524abSAlex Deucher if (table && table->count) { 171541a524abSAlex Deucher for (i = 0; i < pi->graphics_dpm_level_count; i++) { 171641a524abSAlex Deucher if ((table->entries[i].clk >= new_ps->levels[0].sclk) || 171741a524abSAlex Deucher (i == (pi->graphics_dpm_level_count - 1))) { 171841a524abSAlex Deucher pi->lowest_valid = i; 171941a524abSAlex Deucher break; 172041a524abSAlex Deucher } 172141a524abSAlex Deucher } 172241a524abSAlex Deucher 17238c5c6fadSDan Carpenter for (i = pi->graphics_dpm_level_count - 1; i > 0; i--) { 17248c5c6fadSDan Carpenter if (table->entries[i].clk <= new_ps->levels[new_ps->num_levels - 1].sclk) 172541a524abSAlex Deucher break; 172641a524abSAlex Deucher } 17278c5c6fadSDan Carpenter pi->highest_valid = i; 172841a524abSAlex Deucher 172941a524abSAlex Deucher if (pi->lowest_valid > pi->highest_valid) { 173041a524abSAlex Deucher if ((new_ps->levels[0].sclk - table->entries[pi->highest_valid].clk) > 173141a524abSAlex Deucher (table->entries[pi->lowest_valid].clk - new_ps->levels[new_ps->num_levels - 1].sclk)) 173241a524abSAlex Deucher pi->highest_valid = pi->lowest_valid; 173341a524abSAlex Deucher else 173441a524abSAlex Deucher pi->lowest_valid = pi->highest_valid; 173541a524abSAlex Deucher } 173641a524abSAlex Deucher } else { 173741a524abSAlex Deucher struct sumo_sclk_voltage_mapping_table *table = 173841a524abSAlex Deucher &pi->sys_info.sclk_voltage_mapping_table; 173941a524abSAlex Deucher 174041a524abSAlex Deucher for (i = 0; i < (int)pi->graphics_dpm_level_count; i++) { 174141a524abSAlex Deucher if (table->entries[i].sclk_frequency >= new_ps->levels[0].sclk || 174241a524abSAlex Deucher i == (int)(pi->graphics_dpm_level_count - 1)) { 174341a524abSAlex Deucher pi->lowest_valid = i; 174441a524abSAlex Deucher break; 174541a524abSAlex Deucher } 174641a524abSAlex Deucher } 174741a524abSAlex Deucher 17488c5c6fadSDan Carpenter for (i = pi->graphics_dpm_level_count - 1; i > 0; i--) { 174941a524abSAlex Deucher if (table->entries[i].sclk_frequency <= 17508c5c6fadSDan Carpenter new_ps->levels[new_ps->num_levels - 1].sclk) 175141a524abSAlex Deucher break; 175241a524abSAlex Deucher } 17538c5c6fadSDan Carpenter pi->highest_valid = i; 175441a524abSAlex Deucher 175541a524abSAlex Deucher if (pi->lowest_valid > pi->highest_valid) { 175641a524abSAlex Deucher if ((new_ps->levels[0].sclk - 175741a524abSAlex Deucher table->entries[pi->highest_valid].sclk_frequency) > 175841a524abSAlex Deucher (table->entries[pi->lowest_valid].sclk_frequency - 175941a524abSAlex Deucher new_ps->levels[new_ps->num_levels -1].sclk)) 176041a524abSAlex Deucher pi->highest_valid = pi->lowest_valid; 176141a524abSAlex Deucher else 176241a524abSAlex Deucher pi->lowest_valid = pi->highest_valid; 176341a524abSAlex Deucher } 176441a524abSAlex Deucher } 176541a524abSAlex Deucher } 176641a524abSAlex Deucher 176741a524abSAlex Deucher static int kv_update_dfs_bypass_settings(struct radeon_device *rdev, 176841a524abSAlex Deucher struct radeon_ps *new_rps) 176941a524abSAlex Deucher { 177041a524abSAlex Deucher struct kv_ps *new_ps = kv_get_ps(new_rps); 177141a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 177241a524abSAlex Deucher int ret = 0; 177341a524abSAlex Deucher u8 clk_bypass_cntl; 177441a524abSAlex Deucher 177541a524abSAlex Deucher if (pi->caps_enable_dfs_bypass) { 177641a524abSAlex Deucher clk_bypass_cntl = new_ps->need_dfs_bypass ? 177741a524abSAlex Deucher pi->graphics_level[pi->graphics_boot_level].ClkBypassCntl : 0; 177841a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 177941a524abSAlex Deucher (pi->dpm_table_start + 178041a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, GraphicsLevel) + 178141a524abSAlex Deucher (pi->graphics_boot_level * sizeof(SMU7_Fusion_GraphicsLevel)) + 178241a524abSAlex Deucher offsetof(SMU7_Fusion_GraphicsLevel, ClkBypassCntl)), 178341a524abSAlex Deucher &clk_bypass_cntl, 178441a524abSAlex Deucher sizeof(u8), pi->sram_end); 178541a524abSAlex Deucher } 178641a524abSAlex Deucher 178741a524abSAlex Deucher return ret; 178841a524abSAlex Deucher } 178941a524abSAlex Deucher 179039da0384SAlex Deucher static int kv_enable_nb_dpm(struct radeon_device *rdev, 179139da0384SAlex Deucher bool enable) 179241a524abSAlex Deucher { 179341a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 179441a524abSAlex Deucher int ret = 0; 179541a524abSAlex Deucher 179639da0384SAlex Deucher if (enable) { 179741a524abSAlex Deucher if (pi->enable_nb_dpm && !pi->nb_dpm_enabled) { 179841a524abSAlex Deucher ret = kv_notify_message_to_smu(rdev, PPSMC_MSG_NBDPM_Enable); 179941a524abSAlex Deucher if (ret == 0) 180041a524abSAlex Deucher pi->nb_dpm_enabled = true; 180141a524abSAlex Deucher } 180239da0384SAlex Deucher } else { 180339da0384SAlex Deucher if (pi->enable_nb_dpm && pi->nb_dpm_enabled) { 180439da0384SAlex Deucher ret = kv_notify_message_to_smu(rdev, PPSMC_MSG_NBDPM_Disable); 180539da0384SAlex Deucher if (ret == 0) 180639da0384SAlex Deucher pi->nb_dpm_enabled = false; 180739da0384SAlex Deucher } 180839da0384SAlex Deucher } 180941a524abSAlex Deucher 181041a524abSAlex Deucher return ret; 181141a524abSAlex Deucher } 181241a524abSAlex Deucher 18132b4c8022SAlex Deucher int kv_dpm_force_performance_level(struct radeon_device *rdev, 18142b4c8022SAlex Deucher enum radeon_dpm_forced_level level) 18152b4c8022SAlex Deucher { 18162b4c8022SAlex Deucher int ret; 18172b4c8022SAlex Deucher 18182b4c8022SAlex Deucher if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { 18192b4c8022SAlex Deucher ret = kv_force_dpm_highest(rdev); 18202b4c8022SAlex Deucher if (ret) 18212b4c8022SAlex Deucher return ret; 18222b4c8022SAlex Deucher } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) { 18232b4c8022SAlex Deucher ret = kv_force_dpm_lowest(rdev); 18242b4c8022SAlex Deucher if (ret) 18252b4c8022SAlex Deucher return ret; 18262b4c8022SAlex Deucher } else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) { 18272b4c8022SAlex Deucher ret = kv_unforce_levels(rdev); 18282b4c8022SAlex Deucher if (ret) 18292b4c8022SAlex Deucher return ret; 18302b4c8022SAlex Deucher } 18312b4c8022SAlex Deucher 18322b4c8022SAlex Deucher rdev->pm.dpm.forced_level = level; 18332b4c8022SAlex Deucher 18342b4c8022SAlex Deucher return 0; 18352b4c8022SAlex Deucher } 18362b4c8022SAlex Deucher 183741a524abSAlex Deucher int kv_dpm_pre_set_power_state(struct radeon_device *rdev) 183841a524abSAlex Deucher { 183941a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 184041a524abSAlex Deucher struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps; 184141a524abSAlex Deucher struct radeon_ps *new_ps = &requested_ps; 184241a524abSAlex Deucher 184341a524abSAlex Deucher kv_update_requested_ps(rdev, new_ps); 184441a524abSAlex Deucher 184541a524abSAlex Deucher kv_apply_state_adjust_rules(rdev, 184641a524abSAlex Deucher &pi->requested_rps, 184741a524abSAlex Deucher &pi->current_rps); 184841a524abSAlex Deucher 184941a524abSAlex Deucher return 0; 185041a524abSAlex Deucher } 185141a524abSAlex Deucher 185241a524abSAlex Deucher int kv_dpm_set_power_state(struct radeon_device *rdev) 185341a524abSAlex Deucher { 185441a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 185541a524abSAlex Deucher struct radeon_ps *new_ps = &pi->requested_rps; 185642332905SAlex Deucher struct radeon_ps *old_ps = &pi->current_rps; 185741a524abSAlex Deucher int ret; 185841a524abSAlex Deucher 1859b7a5ae97SAlex Deucher if (pi->bapm_enable) { 1860b7a5ae97SAlex Deucher ret = kv_smc_bapm_enable(rdev, rdev->pm.dpm.ac_power); 1861b7a5ae97SAlex Deucher if (ret) { 1862b7a5ae97SAlex Deucher DRM_ERROR("kv_smc_bapm_enable failed\n"); 1863b7a5ae97SAlex Deucher return ret; 1864b7a5ae97SAlex Deucher } 1865b7a5ae97SAlex Deucher } 1866b7a5ae97SAlex Deucher 18677d032a4bSSamuel Li if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) { 186841a524abSAlex Deucher if (pi->enable_dpm) { 186941a524abSAlex Deucher kv_set_valid_clock_range(rdev, new_ps); 187041a524abSAlex Deucher kv_update_dfs_bypass_settings(rdev, new_ps); 187141a524abSAlex Deucher ret = kv_calculate_ds_divider(rdev); 187241a524abSAlex Deucher if (ret) { 187341a524abSAlex Deucher DRM_ERROR("kv_calculate_ds_divider failed\n"); 187441a524abSAlex Deucher return ret; 187541a524abSAlex Deucher } 187641a524abSAlex Deucher kv_calculate_nbps_level_settings(rdev); 187741a524abSAlex Deucher kv_calculate_dpm_settings(rdev); 187841a524abSAlex Deucher kv_force_lowest_valid(rdev); 187941a524abSAlex Deucher kv_enable_new_levels(rdev); 188041a524abSAlex Deucher kv_upload_dpm_settings(rdev); 188141a524abSAlex Deucher kv_program_nbps_index_settings(rdev, new_ps); 188241a524abSAlex Deucher kv_unforce_levels(rdev); 188341a524abSAlex Deucher kv_set_enabled_levels(rdev); 188441a524abSAlex Deucher kv_force_lowest_valid(rdev); 188541a524abSAlex Deucher kv_unforce_levels(rdev); 188642332905SAlex Deucher 188741a524abSAlex Deucher ret = kv_update_vce_dpm(rdev, new_ps, old_ps); 188841a524abSAlex Deucher if (ret) { 188941a524abSAlex Deucher DRM_ERROR("kv_update_vce_dpm failed\n"); 189041a524abSAlex Deucher return ret; 189141a524abSAlex Deucher } 189241a524abSAlex Deucher kv_update_sclk_t(rdev); 189347f5c746SAlex Deucher if (rdev->family == CHIP_MULLINS) 189439da0384SAlex Deucher kv_enable_nb_dpm(rdev, true); 189541a524abSAlex Deucher } 189641a524abSAlex Deucher } else { 189741a524abSAlex Deucher if (pi->enable_dpm) { 189841a524abSAlex Deucher kv_set_valid_clock_range(rdev, new_ps); 189941a524abSAlex Deucher kv_update_dfs_bypass_settings(rdev, new_ps); 190041a524abSAlex Deucher ret = kv_calculate_ds_divider(rdev); 190141a524abSAlex Deucher if (ret) { 190241a524abSAlex Deucher DRM_ERROR("kv_calculate_ds_divider failed\n"); 190341a524abSAlex Deucher return ret; 190441a524abSAlex Deucher } 190541a524abSAlex Deucher kv_calculate_nbps_level_settings(rdev); 190641a524abSAlex Deucher kv_calculate_dpm_settings(rdev); 190741a524abSAlex Deucher kv_freeze_sclk_dpm(rdev, true); 190841a524abSAlex Deucher kv_upload_dpm_settings(rdev); 190941a524abSAlex Deucher kv_program_nbps_index_settings(rdev, new_ps); 191041a524abSAlex Deucher kv_freeze_sclk_dpm(rdev, false); 191141a524abSAlex Deucher kv_set_enabled_levels(rdev); 191241a524abSAlex Deucher ret = kv_update_vce_dpm(rdev, new_ps, old_ps); 191341a524abSAlex Deucher if (ret) { 191441a524abSAlex Deucher DRM_ERROR("kv_update_vce_dpm failed\n"); 191541a524abSAlex Deucher return ret; 191641a524abSAlex Deucher } 1917136de91eSAlex Deucher kv_update_acp_boot_level(rdev); 191841a524abSAlex Deucher kv_update_sclk_t(rdev); 191939da0384SAlex Deucher kv_enable_nb_dpm(rdev, true); 192041a524abSAlex Deucher } 192141a524abSAlex Deucher } 19226500fc0cSAlex Deucher 192341a524abSAlex Deucher return 0; 192441a524abSAlex Deucher } 192541a524abSAlex Deucher 192641a524abSAlex Deucher void kv_dpm_post_set_power_state(struct radeon_device *rdev) 192741a524abSAlex Deucher { 192841a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 192941a524abSAlex Deucher struct radeon_ps *new_ps = &pi->requested_rps; 193041a524abSAlex Deucher 193141a524abSAlex Deucher kv_update_current_ps(rdev, new_ps); 193241a524abSAlex Deucher } 193341a524abSAlex Deucher 193441a524abSAlex Deucher void kv_dpm_setup_asic(struct radeon_device *rdev) 193541a524abSAlex Deucher { 193641a524abSAlex Deucher sumo_take_smu_control(rdev, true); 193741a524abSAlex Deucher kv_init_powergate_state(rdev); 193841a524abSAlex Deucher kv_init_sclk_t(rdev); 193941a524abSAlex Deucher } 194041a524abSAlex Deucher 1941dafc519dSAlex Deucher #if 0 194241a524abSAlex Deucher void kv_dpm_reset_asic(struct radeon_device *rdev) 194341a524abSAlex Deucher { 1944136de91eSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 1945136de91eSAlex Deucher 19467d032a4bSSamuel Li if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) { 194741a524abSAlex Deucher kv_force_lowest_valid(rdev); 194841a524abSAlex Deucher kv_init_graphics_levels(rdev); 194941a524abSAlex Deucher kv_program_bootup_state(rdev); 195041a524abSAlex Deucher kv_upload_dpm_settings(rdev); 195141a524abSAlex Deucher kv_force_lowest_valid(rdev); 195241a524abSAlex Deucher kv_unforce_levels(rdev); 1953136de91eSAlex Deucher } else { 1954136de91eSAlex Deucher kv_init_graphics_levels(rdev); 1955136de91eSAlex Deucher kv_program_bootup_state(rdev); 1956136de91eSAlex Deucher kv_freeze_sclk_dpm(rdev, true); 1957136de91eSAlex Deucher kv_upload_dpm_settings(rdev); 1958136de91eSAlex Deucher kv_freeze_sclk_dpm(rdev, false); 1959136de91eSAlex Deucher kv_set_enabled_level(rdev, pi->graphics_boot_level); 1960136de91eSAlex Deucher } 196141a524abSAlex Deucher } 1962dafc519dSAlex Deucher #endif 196341a524abSAlex Deucher 196441a524abSAlex Deucher //XXX use sumo_dpm_display_configuration_changed 196541a524abSAlex Deucher 196641a524abSAlex Deucher static void kv_construct_max_power_limits_table(struct radeon_device *rdev, 196741a524abSAlex Deucher struct radeon_clock_and_voltage_limits *table) 196841a524abSAlex Deucher { 196941a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 197041a524abSAlex Deucher 197141a524abSAlex Deucher if (pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries > 0) { 197241a524abSAlex Deucher int idx = pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries - 1; 197341a524abSAlex Deucher table->sclk = 197441a524abSAlex Deucher pi->sys_info.sclk_voltage_mapping_table.entries[idx].sclk_frequency; 197541a524abSAlex Deucher table->vddc = 197641a524abSAlex Deucher kv_convert_2bit_index_to_voltage(rdev, 197741a524abSAlex Deucher pi->sys_info.sclk_voltage_mapping_table.entries[idx].vid_2bit); 197841a524abSAlex Deucher } 197941a524abSAlex Deucher 198041a524abSAlex Deucher table->mclk = pi->sys_info.nbp_memory_clock[0]; 198141a524abSAlex Deucher } 198241a524abSAlex Deucher 198341a524abSAlex Deucher static void kv_patch_voltage_values(struct radeon_device *rdev) 198441a524abSAlex Deucher { 198541a524abSAlex Deucher int i; 198647f5c746SAlex Deucher struct radeon_uvd_clock_voltage_dependency_table *uvd_table = 198741a524abSAlex Deucher &rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table; 198847f5c746SAlex Deucher struct radeon_vce_clock_voltage_dependency_table *vce_table = 198947f5c746SAlex Deucher &rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table; 199047f5c746SAlex Deucher struct radeon_clock_voltage_dependency_table *samu_table = 199147f5c746SAlex Deucher &rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table; 199247f5c746SAlex Deucher struct radeon_clock_voltage_dependency_table *acp_table = 199347f5c746SAlex Deucher &rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table; 199441a524abSAlex Deucher 199547f5c746SAlex Deucher if (uvd_table->count) { 199647f5c746SAlex Deucher for (i = 0; i < uvd_table->count; i++) 199747f5c746SAlex Deucher uvd_table->entries[i].v = 199841a524abSAlex Deucher kv_convert_8bit_index_to_voltage(rdev, 199947f5c746SAlex Deucher uvd_table->entries[i].v); 200047f5c746SAlex Deucher } 200147f5c746SAlex Deucher 200247f5c746SAlex Deucher if (vce_table->count) { 200347f5c746SAlex Deucher for (i = 0; i < vce_table->count; i++) 200447f5c746SAlex Deucher vce_table->entries[i].v = 200547f5c746SAlex Deucher kv_convert_8bit_index_to_voltage(rdev, 200647f5c746SAlex Deucher vce_table->entries[i].v); 200747f5c746SAlex Deucher } 200847f5c746SAlex Deucher 200947f5c746SAlex Deucher if (samu_table->count) { 201047f5c746SAlex Deucher for (i = 0; i < samu_table->count; i++) 201147f5c746SAlex Deucher samu_table->entries[i].v = 201247f5c746SAlex Deucher kv_convert_8bit_index_to_voltage(rdev, 201347f5c746SAlex Deucher samu_table->entries[i].v); 201447f5c746SAlex Deucher } 201547f5c746SAlex Deucher 201647f5c746SAlex Deucher if (acp_table->count) { 201747f5c746SAlex Deucher for (i = 0; i < acp_table->count; i++) 201847f5c746SAlex Deucher acp_table->entries[i].v = 201947f5c746SAlex Deucher kv_convert_8bit_index_to_voltage(rdev, 202047f5c746SAlex Deucher acp_table->entries[i].v); 202141a524abSAlex Deucher } 202241a524abSAlex Deucher 202341a524abSAlex Deucher } 202441a524abSAlex Deucher 202541a524abSAlex Deucher static void kv_construct_boot_state(struct radeon_device *rdev) 202641a524abSAlex Deucher { 202741a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 202841a524abSAlex Deucher 202941a524abSAlex Deucher pi->boot_pl.sclk = pi->sys_info.bootup_sclk; 203041a524abSAlex Deucher pi->boot_pl.vddc_index = pi->sys_info.bootup_nb_voltage_index; 203141a524abSAlex Deucher pi->boot_pl.ds_divider_index = 0; 203241a524abSAlex Deucher pi->boot_pl.ss_divider_index = 0; 203341a524abSAlex Deucher pi->boot_pl.allow_gnb_slow = 1; 203441a524abSAlex Deucher pi->boot_pl.force_nbp_state = 0; 203541a524abSAlex Deucher pi->boot_pl.display_wm = 0; 203641a524abSAlex Deucher pi->boot_pl.vce_wm = 0; 203741a524abSAlex Deucher } 203841a524abSAlex Deucher 20392b4c8022SAlex Deucher static int kv_force_dpm_highest(struct radeon_device *rdev) 20402b4c8022SAlex Deucher { 20412b4c8022SAlex Deucher int ret; 20422b4c8022SAlex Deucher u32 enable_mask, i; 20432b4c8022SAlex Deucher 20442b4c8022SAlex Deucher ret = kv_dpm_get_enable_mask(rdev, &enable_mask); 20452b4c8022SAlex Deucher if (ret) 20462b4c8022SAlex Deucher return ret; 20472b4c8022SAlex Deucher 20488c5c6fadSDan Carpenter for (i = SMU7_MAX_LEVELS_GRAPHICS - 1; i > 0; i--) { 20492b4c8022SAlex Deucher if (enable_mask & (1 << i)) 20502b4c8022SAlex Deucher break; 20512b4c8022SAlex Deucher } 20522b4c8022SAlex Deucher 20537d032a4bSSamuel Li if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) 20542b4c8022SAlex Deucher return kv_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_DPM_ForceState, i); 2055136de91eSAlex Deucher else 2056136de91eSAlex Deucher return kv_set_enabled_level(rdev, i); 20572b4c8022SAlex Deucher } 20582b4c8022SAlex Deucher 205941a524abSAlex Deucher static int kv_force_dpm_lowest(struct radeon_device *rdev) 206041a524abSAlex Deucher { 206141a524abSAlex Deucher int ret; 206241a524abSAlex Deucher u32 enable_mask, i; 206341a524abSAlex Deucher 206441a524abSAlex Deucher ret = kv_dpm_get_enable_mask(rdev, &enable_mask); 206541a524abSAlex Deucher if (ret) 206641a524abSAlex Deucher return ret; 206741a524abSAlex Deucher 206841a524abSAlex Deucher for (i = 0; i < SMU7_MAX_LEVELS_GRAPHICS; i++) { 206941a524abSAlex Deucher if (enable_mask & (1 << i)) 207041a524abSAlex Deucher break; 207141a524abSAlex Deucher } 207241a524abSAlex Deucher 20737d032a4bSSamuel Li if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) 207441a524abSAlex Deucher return kv_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_DPM_ForceState, i); 2075136de91eSAlex Deucher else 2076136de91eSAlex Deucher return kv_set_enabled_level(rdev, i); 207741a524abSAlex Deucher } 207841a524abSAlex Deucher 207941a524abSAlex Deucher static u8 kv_get_sleep_divider_id_from_clock(struct radeon_device *rdev, 208041a524abSAlex Deucher u32 sclk, u32 min_sclk_in_sr) 208141a524abSAlex Deucher { 208241a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 208341a524abSAlex Deucher u32 i; 208441a524abSAlex Deucher u32 temp; 208541a524abSAlex Deucher u32 min = (min_sclk_in_sr > KV_MINIMUM_ENGINE_CLOCK) ? 208641a524abSAlex Deucher min_sclk_in_sr : KV_MINIMUM_ENGINE_CLOCK; 208741a524abSAlex Deucher 208841a524abSAlex Deucher if (sclk < min) 208941a524abSAlex Deucher return 0; 209041a524abSAlex Deucher 209141a524abSAlex Deucher if (!pi->caps_sclk_ds) 209241a524abSAlex Deucher return 0; 209341a524abSAlex Deucher 20948c5c6fadSDan Carpenter for (i = KV_MAX_DEEPSLEEP_DIVIDER_ID; i > 0; i--) { 209541a524abSAlex Deucher temp = sclk / sumo_get_sleep_divider_from_id(i); 20968c5c6fadSDan Carpenter if (temp >= min) 209741a524abSAlex Deucher break; 209841a524abSAlex Deucher } 209941a524abSAlex Deucher 210041a524abSAlex Deucher return (u8)i; 210141a524abSAlex Deucher } 210241a524abSAlex Deucher 210341a524abSAlex Deucher static int kv_get_high_voltage_limit(struct radeon_device *rdev, int *limit) 210441a524abSAlex Deucher { 210541a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 210641a524abSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 210741a524abSAlex Deucher &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; 210841a524abSAlex Deucher int i; 210941a524abSAlex Deucher 211041a524abSAlex Deucher if (table && table->count) { 211141a524abSAlex Deucher for (i = table->count - 1; i >= 0; i--) { 211241a524abSAlex Deucher if (pi->high_voltage_t && 211341a524abSAlex Deucher (kv_convert_8bit_index_to_voltage(rdev, table->entries[i].v) <= 211441a524abSAlex Deucher pi->high_voltage_t)) { 211541a524abSAlex Deucher *limit = i; 211641a524abSAlex Deucher return 0; 211741a524abSAlex Deucher } 211841a524abSAlex Deucher } 211941a524abSAlex Deucher } else { 212041a524abSAlex Deucher struct sumo_sclk_voltage_mapping_table *table = 212141a524abSAlex Deucher &pi->sys_info.sclk_voltage_mapping_table; 212241a524abSAlex Deucher 212341a524abSAlex Deucher for (i = table->num_max_dpm_entries - 1; i >= 0; i--) { 212441a524abSAlex Deucher if (pi->high_voltage_t && 212541a524abSAlex Deucher (kv_convert_2bit_index_to_voltage(rdev, table->entries[i].vid_2bit) <= 212641a524abSAlex Deucher pi->high_voltage_t)) { 212741a524abSAlex Deucher *limit = i; 212841a524abSAlex Deucher return 0; 212941a524abSAlex Deucher } 213041a524abSAlex Deucher } 213141a524abSAlex Deucher } 213241a524abSAlex Deucher 213341a524abSAlex Deucher *limit = 0; 213441a524abSAlex Deucher return 0; 213541a524abSAlex Deucher } 213641a524abSAlex Deucher 213741a524abSAlex Deucher static void kv_apply_state_adjust_rules(struct radeon_device *rdev, 213841a524abSAlex Deucher struct radeon_ps *new_rps, 213941a524abSAlex Deucher struct radeon_ps *old_rps) 214041a524abSAlex Deucher { 214141a524abSAlex Deucher struct kv_ps *ps = kv_get_ps(new_rps); 214241a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 214341a524abSAlex Deucher u32 min_sclk = 10000; /* ??? */ 214441a524abSAlex Deucher u32 sclk, mclk = 0; 214541a524abSAlex Deucher int i, limit; 214641a524abSAlex Deucher bool force_high; 214741a524abSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 214841a524abSAlex Deucher &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; 214941a524abSAlex Deucher u32 stable_p_state_sclk = 0; 215041a524abSAlex Deucher struct radeon_clock_and_voltage_limits *max_limits = 215141a524abSAlex Deucher &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; 215241a524abSAlex Deucher 215342332905SAlex Deucher if (new_rps->vce_active) { 215442332905SAlex Deucher new_rps->evclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].evclk; 215542332905SAlex Deucher new_rps->ecclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].ecclk; 215642332905SAlex Deucher } else { 215742332905SAlex Deucher new_rps->evclk = 0; 215842332905SAlex Deucher new_rps->ecclk = 0; 215942332905SAlex Deucher } 216042332905SAlex Deucher 216141a524abSAlex Deucher mclk = max_limits->mclk; 216241a524abSAlex Deucher sclk = min_sclk; 216341a524abSAlex Deucher 216441a524abSAlex Deucher if (pi->caps_stable_p_state) { 216541a524abSAlex Deucher stable_p_state_sclk = (max_limits->sclk * 75) / 100; 216641a524abSAlex Deucher 2167a8efd588Stom will for (i = table->count - 1; i >= 0; i--) { 216841a524abSAlex Deucher if (stable_p_state_sclk >= table->entries[i].clk) { 216941a524abSAlex Deucher stable_p_state_sclk = table->entries[i].clk; 217041a524abSAlex Deucher break; 217141a524abSAlex Deucher } 217241a524abSAlex Deucher } 217341a524abSAlex Deucher 217441a524abSAlex Deucher if (i > 0) 217541a524abSAlex Deucher stable_p_state_sclk = table->entries[0].clk; 217641a524abSAlex Deucher 217741a524abSAlex Deucher sclk = stable_p_state_sclk; 217841a524abSAlex Deucher } 217941a524abSAlex Deucher 218042332905SAlex Deucher if (new_rps->vce_active) { 218142332905SAlex Deucher if (sclk < rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk) 218242332905SAlex Deucher sclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk; 218342332905SAlex Deucher } 218442332905SAlex Deucher 218541a524abSAlex Deucher ps->need_dfs_bypass = true; 218641a524abSAlex Deucher 218741a524abSAlex Deucher for (i = 0; i < ps->num_levels; i++) { 218841a524abSAlex Deucher if (ps->levels[i].sclk < sclk) 218941a524abSAlex Deucher ps->levels[i].sclk = sclk; 219041a524abSAlex Deucher } 219141a524abSAlex Deucher 219241a524abSAlex Deucher if (table && table->count) { 219341a524abSAlex Deucher for (i = 0; i < ps->num_levels; i++) { 219441a524abSAlex Deucher if (pi->high_voltage_t && 219541a524abSAlex Deucher (pi->high_voltage_t < 219641a524abSAlex Deucher kv_convert_8bit_index_to_voltage(rdev, ps->levels[i].vddc_index))) { 219741a524abSAlex Deucher kv_get_high_voltage_limit(rdev, &limit); 219841a524abSAlex Deucher ps->levels[i].sclk = table->entries[limit].clk; 219941a524abSAlex Deucher } 220041a524abSAlex Deucher } 220141a524abSAlex Deucher } else { 220241a524abSAlex Deucher struct sumo_sclk_voltage_mapping_table *table = 220341a524abSAlex Deucher &pi->sys_info.sclk_voltage_mapping_table; 220441a524abSAlex Deucher 220541a524abSAlex Deucher for (i = 0; i < ps->num_levels; i++) { 220641a524abSAlex Deucher if (pi->high_voltage_t && 220741a524abSAlex Deucher (pi->high_voltage_t < 220841a524abSAlex Deucher kv_convert_8bit_index_to_voltage(rdev, ps->levels[i].vddc_index))) { 220941a524abSAlex Deucher kv_get_high_voltage_limit(rdev, &limit); 221041a524abSAlex Deucher ps->levels[i].sclk = table->entries[limit].sclk_frequency; 221141a524abSAlex Deucher } 221241a524abSAlex Deucher } 221341a524abSAlex Deucher } 221441a524abSAlex Deucher 221541a524abSAlex Deucher if (pi->caps_stable_p_state) { 221641a524abSAlex Deucher for (i = 0; i < ps->num_levels; i++) { 221741a524abSAlex Deucher ps->levels[i].sclk = stable_p_state_sclk; 221841a524abSAlex Deucher } 221941a524abSAlex Deucher } 222041a524abSAlex Deucher 222142332905SAlex Deucher pi->video_start = new_rps->dclk || new_rps->vclk || 222242332905SAlex Deucher new_rps->evclk || new_rps->ecclk; 222341a524abSAlex Deucher 222441a524abSAlex Deucher if ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == 222541a524abSAlex Deucher ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) 222641a524abSAlex Deucher pi->battery_state = true; 222741a524abSAlex Deucher else 222841a524abSAlex Deucher pi->battery_state = false; 222941a524abSAlex Deucher 22307d032a4bSSamuel Li if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) { 223141a524abSAlex Deucher ps->dpm0_pg_nb_ps_lo = 0x1; 223241a524abSAlex Deucher ps->dpm0_pg_nb_ps_hi = 0x0; 223341a524abSAlex Deucher ps->dpmx_nb_ps_lo = 0x1; 223441a524abSAlex Deucher ps->dpmx_nb_ps_hi = 0x0; 223541a524abSAlex Deucher } else { 2236136de91eSAlex Deucher ps->dpm0_pg_nb_ps_lo = 0x3; 223741a524abSAlex Deucher ps->dpm0_pg_nb_ps_hi = 0x0; 2238136de91eSAlex Deucher ps->dpmx_nb_ps_lo = 0x3; 2239136de91eSAlex Deucher ps->dpmx_nb_ps_hi = 0x0; 224041a524abSAlex Deucher 2241136de91eSAlex Deucher if (pi->sys_info.nb_dpm_enable) { 224241a524abSAlex Deucher force_high = (mclk >= pi->sys_info.nbp_memory_clock[3]) || 224341a524abSAlex Deucher pi->video_start || (rdev->pm.dpm.new_active_crtc_count >= 3) || 224441a524abSAlex Deucher pi->disable_nb_ps3_in_battery; 224541a524abSAlex Deucher ps->dpm0_pg_nb_ps_lo = force_high ? 0x2 : 0x3; 224641a524abSAlex Deucher ps->dpm0_pg_nb_ps_hi = 0x2; 224741a524abSAlex Deucher ps->dpmx_nb_ps_lo = force_high ? 0x2 : 0x3; 224841a524abSAlex Deucher ps->dpmx_nb_ps_hi = 0x2; 224941a524abSAlex Deucher } 225041a524abSAlex Deucher } 225141a524abSAlex Deucher } 225241a524abSAlex Deucher 225341a524abSAlex Deucher static void kv_dpm_power_level_enabled_for_throttle(struct radeon_device *rdev, 225441a524abSAlex Deucher u32 index, bool enable) 225541a524abSAlex Deucher { 225641a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 225741a524abSAlex Deucher 225841a524abSAlex Deucher pi->graphics_level[index].EnabledForThrottle = enable ? 1 : 0; 225941a524abSAlex Deucher } 226041a524abSAlex Deucher 226141a524abSAlex Deucher static int kv_calculate_ds_divider(struct radeon_device *rdev) 226241a524abSAlex Deucher { 226341a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 226441a524abSAlex Deucher u32 sclk_in_sr = 10000; /* ??? */ 226541a524abSAlex Deucher u32 i; 226641a524abSAlex Deucher 226741a524abSAlex Deucher if (pi->lowest_valid > pi->highest_valid) 226841a524abSAlex Deucher return -EINVAL; 226941a524abSAlex Deucher 227041a524abSAlex Deucher for (i = pi->lowest_valid; i <= pi->highest_valid; i++) { 227141a524abSAlex Deucher pi->graphics_level[i].DeepSleepDivId = 227241a524abSAlex Deucher kv_get_sleep_divider_id_from_clock(rdev, 227341a524abSAlex Deucher be32_to_cpu(pi->graphics_level[i].SclkFrequency), 227441a524abSAlex Deucher sclk_in_sr); 227541a524abSAlex Deucher } 227641a524abSAlex Deucher return 0; 227741a524abSAlex Deucher } 227841a524abSAlex Deucher 227941a524abSAlex Deucher static int kv_calculate_nbps_level_settings(struct radeon_device *rdev) 228041a524abSAlex Deucher { 228141a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 228241a524abSAlex Deucher u32 i; 228341a524abSAlex Deucher bool force_high; 228441a524abSAlex Deucher struct radeon_clock_and_voltage_limits *max_limits = 228541a524abSAlex Deucher &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; 228641a524abSAlex Deucher u32 mclk = max_limits->mclk; 228741a524abSAlex Deucher 228841a524abSAlex Deucher if (pi->lowest_valid > pi->highest_valid) 228941a524abSAlex Deucher return -EINVAL; 229041a524abSAlex Deucher 22917d032a4bSSamuel Li if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) { 229241a524abSAlex Deucher for (i = pi->lowest_valid; i <= pi->highest_valid; i++) { 229341a524abSAlex Deucher pi->graphics_level[i].GnbSlow = 1; 229441a524abSAlex Deucher pi->graphics_level[i].ForceNbPs1 = 0; 229541a524abSAlex Deucher pi->graphics_level[i].UpH = 0; 229641a524abSAlex Deucher } 229741a524abSAlex Deucher 229841a524abSAlex Deucher if (!pi->sys_info.nb_dpm_enable) 229941a524abSAlex Deucher return 0; 230041a524abSAlex Deucher 230141a524abSAlex Deucher force_high = ((mclk >= pi->sys_info.nbp_memory_clock[3]) || 230241a524abSAlex Deucher (rdev->pm.dpm.new_active_crtc_count >= 3) || pi->video_start); 230341a524abSAlex Deucher 230441a524abSAlex Deucher if (force_high) { 230541a524abSAlex Deucher for (i = pi->lowest_valid; i <= pi->highest_valid; i++) 230641a524abSAlex Deucher pi->graphics_level[i].GnbSlow = 0; 230741a524abSAlex Deucher } else { 230841a524abSAlex Deucher if (pi->battery_state) 230941a524abSAlex Deucher pi->graphics_level[0].ForceNbPs1 = 1; 231041a524abSAlex Deucher 231141a524abSAlex Deucher pi->graphics_level[1].GnbSlow = 0; 231241a524abSAlex Deucher pi->graphics_level[2].GnbSlow = 0; 231341a524abSAlex Deucher pi->graphics_level[3].GnbSlow = 0; 231441a524abSAlex Deucher pi->graphics_level[4].GnbSlow = 0; 231541a524abSAlex Deucher } 231641a524abSAlex Deucher } else { 231741a524abSAlex Deucher for (i = pi->lowest_valid; i <= pi->highest_valid; i++) { 231841a524abSAlex Deucher pi->graphics_level[i].GnbSlow = 1; 231941a524abSAlex Deucher pi->graphics_level[i].ForceNbPs1 = 0; 232041a524abSAlex Deucher pi->graphics_level[i].UpH = 0; 232141a524abSAlex Deucher } 232241a524abSAlex Deucher 232341a524abSAlex Deucher if (pi->sys_info.nb_dpm_enable && pi->battery_state) { 232441a524abSAlex Deucher pi->graphics_level[pi->lowest_valid].UpH = 0x28; 232541a524abSAlex Deucher pi->graphics_level[pi->lowest_valid].GnbSlow = 0; 232641a524abSAlex Deucher if (pi->lowest_valid != pi->highest_valid) 232741a524abSAlex Deucher pi->graphics_level[pi->lowest_valid].ForceNbPs1 = 1; 232841a524abSAlex Deucher } 232941a524abSAlex Deucher } 233041a524abSAlex Deucher return 0; 233141a524abSAlex Deucher } 233241a524abSAlex Deucher 233341a524abSAlex Deucher static int kv_calculate_dpm_settings(struct radeon_device *rdev) 233441a524abSAlex Deucher { 233541a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 233641a524abSAlex Deucher u32 i; 233741a524abSAlex Deucher 233841a524abSAlex Deucher if (pi->lowest_valid > pi->highest_valid) 233941a524abSAlex Deucher return -EINVAL; 234041a524abSAlex Deucher 234141a524abSAlex Deucher for (i = pi->lowest_valid; i <= pi->highest_valid; i++) 234241a524abSAlex Deucher pi->graphics_level[i].DisplayWatermark = (i == pi->highest_valid) ? 1 : 0; 234341a524abSAlex Deucher 234441a524abSAlex Deucher return 0; 234541a524abSAlex Deucher } 234641a524abSAlex Deucher 234741a524abSAlex Deucher static void kv_init_graphics_levels(struct radeon_device *rdev) 234841a524abSAlex Deucher { 234941a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 235041a524abSAlex Deucher u32 i; 235141a524abSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 235241a524abSAlex Deucher &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; 235341a524abSAlex Deucher 235441a524abSAlex Deucher if (table && table->count) { 235541a524abSAlex Deucher u32 vid_2bit; 235641a524abSAlex Deucher 235741a524abSAlex Deucher pi->graphics_dpm_level_count = 0; 235841a524abSAlex Deucher for (i = 0; i < table->count; i++) { 235941a524abSAlex Deucher if (pi->high_voltage_t && 236041a524abSAlex Deucher (pi->high_voltage_t < 236141a524abSAlex Deucher kv_convert_8bit_index_to_voltage(rdev, table->entries[i].v))) 236241a524abSAlex Deucher break; 236341a524abSAlex Deucher 236441a524abSAlex Deucher kv_set_divider_value(rdev, i, table->entries[i].clk); 236547f5c746SAlex Deucher vid_2bit = kv_convert_vid7_to_vid2(rdev, 236641a524abSAlex Deucher &pi->sys_info.vid_mapping_table, 236741a524abSAlex Deucher table->entries[i].v); 236841a524abSAlex Deucher kv_set_vid(rdev, i, vid_2bit); 236941a524abSAlex Deucher kv_set_at(rdev, i, pi->at[i]); 237041a524abSAlex Deucher kv_dpm_power_level_enabled_for_throttle(rdev, i, true); 237141a524abSAlex Deucher pi->graphics_dpm_level_count++; 237241a524abSAlex Deucher } 237341a524abSAlex Deucher } else { 237441a524abSAlex Deucher struct sumo_sclk_voltage_mapping_table *table = 237541a524abSAlex Deucher &pi->sys_info.sclk_voltage_mapping_table; 237641a524abSAlex Deucher 237741a524abSAlex Deucher pi->graphics_dpm_level_count = 0; 237841a524abSAlex Deucher for (i = 0; i < table->num_max_dpm_entries; i++) { 237941a524abSAlex Deucher if (pi->high_voltage_t && 238041a524abSAlex Deucher pi->high_voltage_t < 238141a524abSAlex Deucher kv_convert_2bit_index_to_voltage(rdev, table->entries[i].vid_2bit)) 238241a524abSAlex Deucher break; 238341a524abSAlex Deucher 238441a524abSAlex Deucher kv_set_divider_value(rdev, i, table->entries[i].sclk_frequency); 238541a524abSAlex Deucher kv_set_vid(rdev, i, table->entries[i].vid_2bit); 238641a524abSAlex Deucher kv_set_at(rdev, i, pi->at[i]); 238741a524abSAlex Deucher kv_dpm_power_level_enabled_for_throttle(rdev, i, true); 238841a524abSAlex Deucher pi->graphics_dpm_level_count++; 238941a524abSAlex Deucher } 239041a524abSAlex Deucher } 239141a524abSAlex Deucher 239241a524abSAlex Deucher for (i = 0; i < SMU7_MAX_LEVELS_GRAPHICS; i++) 239341a524abSAlex Deucher kv_dpm_power_level_enable(rdev, i, false); 239441a524abSAlex Deucher } 239541a524abSAlex Deucher 239641a524abSAlex Deucher static void kv_enable_new_levels(struct radeon_device *rdev) 239741a524abSAlex Deucher { 239841a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 239941a524abSAlex Deucher u32 i; 240041a524abSAlex Deucher 240141a524abSAlex Deucher for (i = 0; i < SMU7_MAX_LEVELS_GRAPHICS; i++) { 240241a524abSAlex Deucher if (i >= pi->lowest_valid && i <= pi->highest_valid) 240341a524abSAlex Deucher kv_dpm_power_level_enable(rdev, i, true); 240441a524abSAlex Deucher } 240541a524abSAlex Deucher } 240641a524abSAlex Deucher 2407136de91eSAlex Deucher static int kv_set_enabled_level(struct radeon_device *rdev, u32 level) 2408136de91eSAlex Deucher { 2409136de91eSAlex Deucher u32 new_mask = (1 << level); 2410136de91eSAlex Deucher 2411136de91eSAlex Deucher return kv_send_msg_to_smc_with_parameter(rdev, 2412136de91eSAlex Deucher PPSMC_MSG_SCLKDPM_SetEnabledMask, 2413136de91eSAlex Deucher new_mask); 2414136de91eSAlex Deucher } 2415136de91eSAlex Deucher 241641a524abSAlex Deucher static int kv_set_enabled_levels(struct radeon_device *rdev) 241741a524abSAlex Deucher { 241841a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 241941a524abSAlex Deucher u32 i, new_mask = 0; 242041a524abSAlex Deucher 242141a524abSAlex Deucher for (i = pi->lowest_valid; i <= pi->highest_valid; i++) 242241a524abSAlex Deucher new_mask |= (1 << i); 242341a524abSAlex Deucher 242441a524abSAlex Deucher return kv_send_msg_to_smc_with_parameter(rdev, 242541a524abSAlex Deucher PPSMC_MSG_SCLKDPM_SetEnabledMask, 242641a524abSAlex Deucher new_mask); 242741a524abSAlex Deucher } 242841a524abSAlex Deucher 242941a524abSAlex Deucher static void kv_program_nbps_index_settings(struct radeon_device *rdev, 243041a524abSAlex Deucher struct radeon_ps *new_rps) 243141a524abSAlex Deucher { 243241a524abSAlex Deucher struct kv_ps *new_ps = kv_get_ps(new_rps); 243341a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 243441a524abSAlex Deucher u32 nbdpmconfig1; 243541a524abSAlex Deucher 24367d032a4bSSamuel Li if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) 243741a524abSAlex Deucher return; 243841a524abSAlex Deucher 243941a524abSAlex Deucher if (pi->sys_info.nb_dpm_enable) { 244041a524abSAlex Deucher nbdpmconfig1 = RREG32_SMC(NB_DPM_CONFIG_1); 244141a524abSAlex Deucher nbdpmconfig1 &= ~(Dpm0PgNbPsLo_MASK | Dpm0PgNbPsHi_MASK | 244241a524abSAlex Deucher DpmXNbPsLo_MASK | DpmXNbPsHi_MASK); 244341a524abSAlex Deucher nbdpmconfig1 |= (Dpm0PgNbPsLo(new_ps->dpm0_pg_nb_ps_lo) | 244441a524abSAlex Deucher Dpm0PgNbPsHi(new_ps->dpm0_pg_nb_ps_hi) | 244541a524abSAlex Deucher DpmXNbPsLo(new_ps->dpmx_nb_ps_lo) | 244641a524abSAlex Deucher DpmXNbPsHi(new_ps->dpmx_nb_ps_hi)); 244741a524abSAlex Deucher WREG32_SMC(NB_DPM_CONFIG_1, nbdpmconfig1); 244841a524abSAlex Deucher } 244941a524abSAlex Deucher } 245041a524abSAlex Deucher 245141a524abSAlex Deucher static int kv_set_thermal_temperature_range(struct radeon_device *rdev, 245241a524abSAlex Deucher int min_temp, int max_temp) 245341a524abSAlex Deucher { 245441a524abSAlex Deucher int low_temp = 0 * 1000; 245541a524abSAlex Deucher int high_temp = 255 * 1000; 245641a524abSAlex Deucher u32 tmp; 245741a524abSAlex Deucher 245841a524abSAlex Deucher if (low_temp < min_temp) 245941a524abSAlex Deucher low_temp = min_temp; 246041a524abSAlex Deucher if (high_temp > max_temp) 246141a524abSAlex Deucher high_temp = max_temp; 246241a524abSAlex Deucher if (high_temp < low_temp) { 246341a524abSAlex Deucher DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp); 246441a524abSAlex Deucher return -EINVAL; 246541a524abSAlex Deucher } 246641a524abSAlex Deucher 246741a524abSAlex Deucher tmp = RREG32_SMC(CG_THERMAL_INT_CTRL); 246841a524abSAlex Deucher tmp &= ~(DIG_THERM_INTH_MASK | DIG_THERM_INTL_MASK); 246941a524abSAlex Deucher tmp |= (DIG_THERM_INTH(49 + (high_temp / 1000)) | 247041a524abSAlex Deucher DIG_THERM_INTL(49 + (low_temp / 1000))); 247141a524abSAlex Deucher WREG32_SMC(CG_THERMAL_INT_CTRL, tmp); 247241a524abSAlex Deucher 247341a524abSAlex Deucher rdev->pm.dpm.thermal.min_temp = low_temp; 247441a524abSAlex Deucher rdev->pm.dpm.thermal.max_temp = high_temp; 247541a524abSAlex Deucher 247641a524abSAlex Deucher return 0; 247741a524abSAlex Deucher } 247841a524abSAlex Deucher 247941a524abSAlex Deucher union igp_info { 248041a524abSAlex Deucher struct _ATOM_INTEGRATED_SYSTEM_INFO info; 248141a524abSAlex Deucher struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2; 248241a524abSAlex Deucher struct _ATOM_INTEGRATED_SYSTEM_INFO_V5 info_5; 248341a524abSAlex Deucher struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6; 248441a524abSAlex Deucher struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7; 248541a524abSAlex Deucher struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 info_8; 248641a524abSAlex Deucher }; 248741a524abSAlex Deucher 248841a524abSAlex Deucher static int kv_parse_sys_info_table(struct radeon_device *rdev) 248941a524abSAlex Deucher { 249041a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 249141a524abSAlex Deucher struct radeon_mode_info *mode_info = &rdev->mode_info; 249241a524abSAlex Deucher int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo); 249341a524abSAlex Deucher union igp_info *igp_info; 249441a524abSAlex Deucher u8 frev, crev; 249541a524abSAlex Deucher u16 data_offset; 249641a524abSAlex Deucher int i; 249741a524abSAlex Deucher 249841a524abSAlex Deucher if (atom_parse_data_header(mode_info->atom_context, index, NULL, 249941a524abSAlex Deucher &frev, &crev, &data_offset)) { 250041a524abSAlex Deucher igp_info = (union igp_info *)(mode_info->atom_context->bios + 250141a524abSAlex Deucher data_offset); 250241a524abSAlex Deucher 250341a524abSAlex Deucher if (crev != 8) { 250441a524abSAlex Deucher DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev); 250541a524abSAlex Deucher return -EINVAL; 250641a524abSAlex Deucher } 250741a524abSAlex Deucher pi->sys_info.bootup_sclk = le32_to_cpu(igp_info->info_8.ulBootUpEngineClock); 250841a524abSAlex Deucher pi->sys_info.bootup_uma_clk = le32_to_cpu(igp_info->info_8.ulBootUpUMAClock); 250941a524abSAlex Deucher pi->sys_info.bootup_nb_voltage_index = 251041a524abSAlex Deucher le16_to_cpu(igp_info->info_8.usBootUpNBVoltage); 251141a524abSAlex Deucher if (igp_info->info_8.ucHtcTmpLmt == 0) 251241a524abSAlex Deucher pi->sys_info.htc_tmp_lmt = 203; 251341a524abSAlex Deucher else 251441a524abSAlex Deucher pi->sys_info.htc_tmp_lmt = igp_info->info_8.ucHtcTmpLmt; 251541a524abSAlex Deucher if (igp_info->info_8.ucHtcHystLmt == 0) 251641a524abSAlex Deucher pi->sys_info.htc_hyst_lmt = 5; 251741a524abSAlex Deucher else 251841a524abSAlex Deucher pi->sys_info.htc_hyst_lmt = igp_info->info_8.ucHtcHystLmt; 251941a524abSAlex Deucher if (pi->sys_info.htc_tmp_lmt <= pi->sys_info.htc_hyst_lmt) { 252041a524abSAlex Deucher DRM_ERROR("The htcTmpLmt should be larger than htcHystLmt.\n"); 252141a524abSAlex Deucher } 252241a524abSAlex Deucher 252341a524abSAlex Deucher if (le32_to_cpu(igp_info->info_8.ulSystemConfig) & (1 << 3)) 252441a524abSAlex Deucher pi->sys_info.nb_dpm_enable = true; 252541a524abSAlex Deucher else 252641a524abSAlex Deucher pi->sys_info.nb_dpm_enable = false; 252741a524abSAlex Deucher 252841a524abSAlex Deucher for (i = 0; i < KV_NUM_NBPSTATES; i++) { 252941a524abSAlex Deucher pi->sys_info.nbp_memory_clock[i] = 253041a524abSAlex Deucher le32_to_cpu(igp_info->info_8.ulNbpStateMemclkFreq[i]); 253141a524abSAlex Deucher pi->sys_info.nbp_n_clock[i] = 253241a524abSAlex Deucher le32_to_cpu(igp_info->info_8.ulNbpStateNClkFreq[i]); 253341a524abSAlex Deucher } 253441a524abSAlex Deucher if (le32_to_cpu(igp_info->info_8.ulGPUCapInfo) & 253541a524abSAlex Deucher SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS) 253641a524abSAlex Deucher pi->caps_enable_dfs_bypass = true; 253741a524abSAlex Deucher 253841a524abSAlex Deucher sumo_construct_sclk_voltage_mapping_table(rdev, 253941a524abSAlex Deucher &pi->sys_info.sclk_voltage_mapping_table, 254041a524abSAlex Deucher igp_info->info_8.sAvail_SCLK); 254141a524abSAlex Deucher 254241a524abSAlex Deucher sumo_construct_vid_mapping_table(rdev, 254341a524abSAlex Deucher &pi->sys_info.vid_mapping_table, 254441a524abSAlex Deucher igp_info->info_8.sAvail_SCLK); 254541a524abSAlex Deucher 254641a524abSAlex Deucher kv_construct_max_power_limits_table(rdev, 254741a524abSAlex Deucher &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac); 254841a524abSAlex Deucher } 254941a524abSAlex Deucher return 0; 255041a524abSAlex Deucher } 255141a524abSAlex Deucher 255241a524abSAlex Deucher union power_info { 255341a524abSAlex Deucher struct _ATOM_POWERPLAY_INFO info; 255441a524abSAlex Deucher struct _ATOM_POWERPLAY_INFO_V2 info_2; 255541a524abSAlex Deucher struct _ATOM_POWERPLAY_INFO_V3 info_3; 255641a524abSAlex Deucher struct _ATOM_PPLIB_POWERPLAYTABLE pplib; 255741a524abSAlex Deucher struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2; 255841a524abSAlex Deucher struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3; 255941a524abSAlex Deucher }; 256041a524abSAlex Deucher 256141a524abSAlex Deucher union pplib_clock_info { 256241a524abSAlex Deucher struct _ATOM_PPLIB_R600_CLOCK_INFO r600; 256341a524abSAlex Deucher struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780; 256441a524abSAlex Deucher struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen; 256541a524abSAlex Deucher struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo; 256641a524abSAlex Deucher }; 256741a524abSAlex Deucher 256841a524abSAlex Deucher union pplib_power_state { 256941a524abSAlex Deucher struct _ATOM_PPLIB_STATE v1; 257041a524abSAlex Deucher struct _ATOM_PPLIB_STATE_V2 v2; 257141a524abSAlex Deucher }; 257241a524abSAlex Deucher 257341a524abSAlex Deucher static void kv_patch_boot_state(struct radeon_device *rdev, 257441a524abSAlex Deucher struct kv_ps *ps) 257541a524abSAlex Deucher { 257641a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 257741a524abSAlex Deucher 257841a524abSAlex Deucher ps->num_levels = 1; 257941a524abSAlex Deucher ps->levels[0] = pi->boot_pl; 258041a524abSAlex Deucher } 258141a524abSAlex Deucher 258241a524abSAlex Deucher static void kv_parse_pplib_non_clock_info(struct radeon_device *rdev, 258341a524abSAlex Deucher struct radeon_ps *rps, 258441a524abSAlex Deucher struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info, 258541a524abSAlex Deucher u8 table_rev) 258641a524abSAlex Deucher { 258741a524abSAlex Deucher struct kv_ps *ps = kv_get_ps(rps); 258841a524abSAlex Deucher 258941a524abSAlex Deucher rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings); 259041a524abSAlex Deucher rps->class = le16_to_cpu(non_clock_info->usClassification); 259141a524abSAlex Deucher rps->class2 = le16_to_cpu(non_clock_info->usClassification2); 259241a524abSAlex Deucher 259341a524abSAlex Deucher if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) { 259441a524abSAlex Deucher rps->vclk = le32_to_cpu(non_clock_info->ulVCLK); 259541a524abSAlex Deucher rps->dclk = le32_to_cpu(non_clock_info->ulDCLK); 259641a524abSAlex Deucher } else { 259741a524abSAlex Deucher rps->vclk = 0; 259841a524abSAlex Deucher rps->dclk = 0; 259941a524abSAlex Deucher } 260041a524abSAlex Deucher 260141a524abSAlex Deucher if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) { 260241a524abSAlex Deucher rdev->pm.dpm.boot_ps = rps; 260341a524abSAlex Deucher kv_patch_boot_state(rdev, ps); 260441a524abSAlex Deucher } 260541a524abSAlex Deucher if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) 260641a524abSAlex Deucher rdev->pm.dpm.uvd_ps = rps; 260741a524abSAlex Deucher } 260841a524abSAlex Deucher 260941a524abSAlex Deucher static void kv_parse_pplib_clock_info(struct radeon_device *rdev, 261041a524abSAlex Deucher struct radeon_ps *rps, int index, 261141a524abSAlex Deucher union pplib_clock_info *clock_info) 261241a524abSAlex Deucher { 261341a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 261441a524abSAlex Deucher struct kv_ps *ps = kv_get_ps(rps); 261541a524abSAlex Deucher struct kv_pl *pl = &ps->levels[index]; 261641a524abSAlex Deucher u32 sclk; 261741a524abSAlex Deucher 261841a524abSAlex Deucher sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow); 261941a524abSAlex Deucher sclk |= clock_info->sumo.ucEngineClockHigh << 16; 262041a524abSAlex Deucher pl->sclk = sclk; 262141a524abSAlex Deucher pl->vddc_index = clock_info->sumo.vddcIndex; 262241a524abSAlex Deucher 262341a524abSAlex Deucher ps->num_levels = index + 1; 262441a524abSAlex Deucher 262541a524abSAlex Deucher if (pi->caps_sclk_ds) { 262641a524abSAlex Deucher pl->ds_divider_index = 5; 262741a524abSAlex Deucher pl->ss_divider_index = 5; 262841a524abSAlex Deucher } 262941a524abSAlex Deucher } 263041a524abSAlex Deucher 263141a524abSAlex Deucher static int kv_parse_power_table(struct radeon_device *rdev) 263241a524abSAlex Deucher { 263341a524abSAlex Deucher struct radeon_mode_info *mode_info = &rdev->mode_info; 263441a524abSAlex Deucher struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; 263541a524abSAlex Deucher union pplib_power_state *power_state; 263641a524abSAlex Deucher int i, j, k, non_clock_array_index, clock_array_index; 263741a524abSAlex Deucher union pplib_clock_info *clock_info; 263841a524abSAlex Deucher struct _StateArray *state_array; 263941a524abSAlex Deucher struct _ClockInfoArray *clock_info_array; 264041a524abSAlex Deucher struct _NonClockInfoArray *non_clock_info_array; 264141a524abSAlex Deucher union power_info *power_info; 264241a524abSAlex Deucher int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); 264341a524abSAlex Deucher u16 data_offset; 264441a524abSAlex Deucher u8 frev, crev; 264541a524abSAlex Deucher u8 *power_state_offset; 264641a524abSAlex Deucher struct kv_ps *ps; 264741a524abSAlex Deucher 264841a524abSAlex Deucher if (!atom_parse_data_header(mode_info->atom_context, index, NULL, 264941a524abSAlex Deucher &frev, &crev, &data_offset)) 265041a524abSAlex Deucher return -EINVAL; 265141a524abSAlex Deucher power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); 265241a524abSAlex Deucher 265341a524abSAlex Deucher state_array = (struct _StateArray *) 265441a524abSAlex Deucher (mode_info->atom_context->bios + data_offset + 265541a524abSAlex Deucher le16_to_cpu(power_info->pplib.usStateArrayOffset)); 265641a524abSAlex Deucher clock_info_array = (struct _ClockInfoArray *) 265741a524abSAlex Deucher (mode_info->atom_context->bios + data_offset + 265841a524abSAlex Deucher le16_to_cpu(power_info->pplib.usClockInfoArrayOffset)); 265941a524abSAlex Deucher non_clock_info_array = (struct _NonClockInfoArray *) 266041a524abSAlex Deucher (mode_info->atom_context->bios + data_offset + 266141a524abSAlex Deucher le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); 266241a524abSAlex Deucher 26636396bb22SKees Cook rdev->pm.dpm.ps = kcalloc(state_array->ucNumEntries, 26646396bb22SKees Cook sizeof(struct radeon_ps), 26656396bb22SKees Cook GFP_KERNEL); 266641a524abSAlex Deucher if (!rdev->pm.dpm.ps) 266741a524abSAlex Deucher return -ENOMEM; 266841a524abSAlex Deucher power_state_offset = (u8 *)state_array->states; 266941a524abSAlex Deucher for (i = 0; i < state_array->ucNumEntries; i++) { 26709af37a7dSAlex Deucher u8 *idx; 267141a524abSAlex Deucher power_state = (union pplib_power_state *)power_state_offset; 267241a524abSAlex Deucher non_clock_array_index = power_state->v2.nonClockInfoIndex; 267341a524abSAlex Deucher non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) 267441a524abSAlex Deucher &non_clock_info_array->nonClockInfo[non_clock_array_index]; 267541a524abSAlex Deucher if (!rdev->pm.power_state[i].clock_info) 267641a524abSAlex Deucher return -EINVAL; 267741a524abSAlex Deucher ps = kzalloc(sizeof(struct kv_ps), GFP_KERNEL); 267841a524abSAlex Deucher if (ps == NULL) { 267941a524abSAlex Deucher kfree(rdev->pm.dpm.ps); 268041a524abSAlex Deucher return -ENOMEM; 268141a524abSAlex Deucher } 268241a524abSAlex Deucher rdev->pm.dpm.ps[i].ps_priv = ps; 268341a524abSAlex Deucher k = 0; 26849af37a7dSAlex Deucher idx = (u8 *)&power_state->v2.clockInfoIndex[0]; 268541a524abSAlex Deucher for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) { 26869af37a7dSAlex Deucher clock_array_index = idx[j]; 268741a524abSAlex Deucher if (clock_array_index >= clock_info_array->ucNumEntries) 268841a524abSAlex Deucher continue; 268941a524abSAlex Deucher if (k >= SUMO_MAX_HARDWARE_POWERLEVELS) 269041a524abSAlex Deucher break; 269141a524abSAlex Deucher clock_info = (union pplib_clock_info *) 26929af37a7dSAlex Deucher ((u8 *)&clock_info_array->clockInfo[0] + 26939af37a7dSAlex Deucher (clock_array_index * clock_info_array->ucEntrySize)); 269441a524abSAlex Deucher kv_parse_pplib_clock_info(rdev, 269541a524abSAlex Deucher &rdev->pm.dpm.ps[i], k, 269641a524abSAlex Deucher clock_info); 269741a524abSAlex Deucher k++; 269841a524abSAlex Deucher } 269941a524abSAlex Deucher kv_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i], 270041a524abSAlex Deucher non_clock_info, 270141a524abSAlex Deucher non_clock_info_array->ucEntrySize); 270241a524abSAlex Deucher power_state_offset += 2 + power_state->v2.ucNumDPMLevels; 270341a524abSAlex Deucher } 270441a524abSAlex Deucher rdev->pm.dpm.num_ps = state_array->ucNumEntries; 270542332905SAlex Deucher 270642332905SAlex Deucher /* fill in the vce power states */ 270742332905SAlex Deucher for (i = 0; i < RADEON_MAX_VCE_LEVELS; i++) { 270842332905SAlex Deucher u32 sclk; 270942332905SAlex Deucher clock_array_index = rdev->pm.dpm.vce_states[i].clk_idx; 271042332905SAlex Deucher clock_info = (union pplib_clock_info *) 271142332905SAlex Deucher &clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize]; 271242332905SAlex Deucher sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow); 271342332905SAlex Deucher sclk |= clock_info->sumo.ucEngineClockHigh << 16; 271442332905SAlex Deucher rdev->pm.dpm.vce_states[i].sclk = sclk; 271542332905SAlex Deucher rdev->pm.dpm.vce_states[i].mclk = 0; 271642332905SAlex Deucher } 271742332905SAlex Deucher 271841a524abSAlex Deucher return 0; 271941a524abSAlex Deucher } 272041a524abSAlex Deucher 272141a524abSAlex Deucher int kv_dpm_init(struct radeon_device *rdev) 272241a524abSAlex Deucher { 272341a524abSAlex Deucher struct kv_power_info *pi; 272441a524abSAlex Deucher int ret, i; 272541a524abSAlex Deucher 272641a524abSAlex Deucher pi = kzalloc(sizeof(struct kv_power_info), GFP_KERNEL); 272741a524abSAlex Deucher if (pi == NULL) 272841a524abSAlex Deucher return -ENOMEM; 272941a524abSAlex Deucher rdev->pm.dpm.priv = pi; 273041a524abSAlex Deucher 273182f79cc5SAlex Deucher ret = r600_get_platform_caps(rdev); 273282f79cc5SAlex Deucher if (ret) 273382f79cc5SAlex Deucher return ret; 273482f79cc5SAlex Deucher 273541a524abSAlex Deucher ret = r600_parse_extended_power_table(rdev); 273641a524abSAlex Deucher if (ret) 273741a524abSAlex Deucher return ret; 273841a524abSAlex Deucher 273941a524abSAlex Deucher for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) 274041a524abSAlex Deucher pi->at[i] = TRINITY_AT_DFLT; 274141a524abSAlex Deucher 274241a524abSAlex Deucher pi->sram_end = SMC_RAM_END; 274341a524abSAlex Deucher 274472b3f918SAlex Deucher /* Enabling nb dpm on an asrock system prevents dpm from working */ 274572b3f918SAlex Deucher if (rdev->pdev->subsystem_vendor == 0x1849) 274672b3f918SAlex Deucher pi->enable_nb_dpm = false; 274772b3f918SAlex Deucher else 274841a524abSAlex Deucher pi->enable_nb_dpm = true; 274941a524abSAlex Deucher 275041a524abSAlex Deucher pi->caps_power_containment = true; 275141a524abSAlex Deucher pi->caps_cac = true; 275241a524abSAlex Deucher pi->enable_didt = false; 275341a524abSAlex Deucher if (pi->enable_didt) { 275441a524abSAlex Deucher pi->caps_sq_ramping = true; 275541a524abSAlex Deucher pi->caps_db_ramping = true; 275641a524abSAlex Deucher pi->caps_td_ramping = true; 275741a524abSAlex Deucher pi->caps_tcp_ramping = true; 275841a524abSAlex Deucher } 275941a524abSAlex Deucher 276041a524abSAlex Deucher pi->caps_sclk_ds = true; 276141a524abSAlex Deucher pi->enable_auto_thermal_throttling = true; 276241a524abSAlex Deucher pi->disable_nb_ps3_in_battery = false; 276372b3f918SAlex Deucher if (radeon_bapm == -1) { 276402ae7af5SAlex Deucher /* only enable bapm on KB, ML by default */ 276502ae7af5SAlex Deucher if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS) 276609f95d5bSAlex Deucher pi->bapm_enable = true; 276702ae7af5SAlex Deucher else 276802ae7af5SAlex Deucher pi->bapm_enable = false; 276972b3f918SAlex Deucher } else if (radeon_bapm == 0) { 277072b3f918SAlex Deucher pi->bapm_enable = false; 277172b3f918SAlex Deucher } else { 277272b3f918SAlex Deucher pi->bapm_enable = true; 277372b3f918SAlex Deucher } 277441a524abSAlex Deucher pi->voltage_drop_t = 0; 277541a524abSAlex Deucher pi->caps_sclk_throttle_low_notification = false; 277641a524abSAlex Deucher pi->caps_fps = false; /* true? */ 277777df508aSAlex Deucher pi->caps_uvd_pg = true; 277841a524abSAlex Deucher pi->caps_uvd_dpm = true; 277942332905SAlex Deucher pi->caps_vce_pg = false; /* XXX true */ 278041a524abSAlex Deucher pi->caps_samu_pg = false; 278141a524abSAlex Deucher pi->caps_acp_pg = false; 278241a524abSAlex Deucher pi->caps_stable_p_state = false; 278341a524abSAlex Deucher 278441a524abSAlex Deucher ret = kv_parse_sys_info_table(rdev); 278541a524abSAlex Deucher if (ret) 278641a524abSAlex Deucher return ret; 278741a524abSAlex Deucher 278841a524abSAlex Deucher kv_patch_voltage_values(rdev); 278941a524abSAlex Deucher kv_construct_boot_state(rdev); 279041a524abSAlex Deucher 279141a524abSAlex Deucher ret = kv_parse_power_table(rdev); 279241a524abSAlex Deucher if (ret) 279341a524abSAlex Deucher return ret; 279441a524abSAlex Deucher 279541a524abSAlex Deucher pi->enable_dpm = true; 279641a524abSAlex Deucher 279741a524abSAlex Deucher return 0; 279841a524abSAlex Deucher } 279941a524abSAlex Deucher 2800ae3e40e8SAlex Deucher void kv_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, 2801ae3e40e8SAlex Deucher struct seq_file *m) 2802ae3e40e8SAlex Deucher { 2803ae3e40e8SAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 2804ae3e40e8SAlex Deucher u32 current_index = 2805ae3e40e8SAlex Deucher (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_SCLK_INDEX_MASK) >> 2806ae3e40e8SAlex Deucher CURR_SCLK_INDEX_SHIFT; 2807ae3e40e8SAlex Deucher u32 sclk, tmp; 2808ae3e40e8SAlex Deucher u16 vddc; 2809ae3e40e8SAlex Deucher 2810ae3e40e8SAlex Deucher if (current_index >= SMU__NUM_SCLK_DPM_STATE) { 2811ae3e40e8SAlex Deucher seq_printf(m, "invalid dpm profile %d\n", current_index); 2812ae3e40e8SAlex Deucher } else { 2813ae3e40e8SAlex Deucher sclk = be32_to_cpu(pi->graphics_level[current_index].SclkFrequency); 2814ae3e40e8SAlex Deucher tmp = (RREG32_SMC(SMU_VOLTAGE_STATUS) & SMU_VOLTAGE_CURRENT_LEVEL_MASK) >> 2815ae3e40e8SAlex Deucher SMU_VOLTAGE_CURRENT_LEVEL_SHIFT; 2816ae3e40e8SAlex Deucher vddc = kv_convert_8bit_index_to_voltage(rdev, (u16)tmp); 2817369283bfSAlex Deucher seq_printf(m, "uvd %sabled\n", pi->uvd_power_gated ? "dis" : "en"); 2818369283bfSAlex Deucher seq_printf(m, "vce %sabled\n", pi->vce_power_gated ? "dis" : "en"); 2819ae3e40e8SAlex Deucher seq_printf(m, "power level %d sclk: %u vddc: %u\n", 2820ae3e40e8SAlex Deucher current_index, sclk, vddc); 2821ae3e40e8SAlex Deucher } 2822ae3e40e8SAlex Deucher } 2823ae3e40e8SAlex Deucher 28249b23bad0SAlex Deucher u32 kv_dpm_get_current_sclk(struct radeon_device *rdev) 28259b23bad0SAlex Deucher { 28269b23bad0SAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 28279b23bad0SAlex Deucher u32 current_index = 28289b23bad0SAlex Deucher (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_SCLK_INDEX_MASK) >> 28299b23bad0SAlex Deucher CURR_SCLK_INDEX_SHIFT; 28309b23bad0SAlex Deucher u32 sclk; 28319b23bad0SAlex Deucher 28329b23bad0SAlex Deucher if (current_index >= SMU__NUM_SCLK_DPM_STATE) { 28339b23bad0SAlex Deucher return 0; 28349b23bad0SAlex Deucher } else { 28359b23bad0SAlex Deucher sclk = be32_to_cpu(pi->graphics_level[current_index].SclkFrequency); 28369b23bad0SAlex Deucher return sclk; 28379b23bad0SAlex Deucher } 28389b23bad0SAlex Deucher } 28399b23bad0SAlex Deucher 28409b23bad0SAlex Deucher u32 kv_dpm_get_current_mclk(struct radeon_device *rdev) 28419b23bad0SAlex Deucher { 28429b23bad0SAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 28439b23bad0SAlex Deucher 28449b23bad0SAlex Deucher return pi->sys_info.bootup_uma_clk; 28459b23bad0SAlex Deucher } 28469b23bad0SAlex Deucher 284741a524abSAlex Deucher void kv_dpm_print_power_state(struct radeon_device *rdev, 284841a524abSAlex Deucher struct radeon_ps *rps) 284941a524abSAlex Deucher { 285041a524abSAlex Deucher int i; 285141a524abSAlex Deucher struct kv_ps *ps = kv_get_ps(rps); 285241a524abSAlex Deucher 285341a524abSAlex Deucher r600_dpm_print_class_info(rps->class, rps->class2); 285441a524abSAlex Deucher r600_dpm_print_cap_info(rps->caps); 285541a524abSAlex Deucher printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); 285641a524abSAlex Deucher for (i = 0; i < ps->num_levels; i++) { 285741a524abSAlex Deucher struct kv_pl *pl = &ps->levels[i]; 285841a524abSAlex Deucher printk("\t\tpower level %d sclk: %u vddc: %u\n", 285941a524abSAlex Deucher i, pl->sclk, 286041a524abSAlex Deucher kv_convert_8bit_index_to_voltage(rdev, pl->vddc_index)); 286141a524abSAlex Deucher } 286241a524abSAlex Deucher r600_dpm_print_ps_status(rdev, rps); 286341a524abSAlex Deucher } 286441a524abSAlex Deucher 286541a524abSAlex Deucher void kv_dpm_fini(struct radeon_device *rdev) 286641a524abSAlex Deucher { 286741a524abSAlex Deucher int i; 286841a524abSAlex Deucher 286941a524abSAlex Deucher for (i = 0; i < rdev->pm.dpm.num_ps; i++) { 287041a524abSAlex Deucher kfree(rdev->pm.dpm.ps[i].ps_priv); 287141a524abSAlex Deucher } 287241a524abSAlex Deucher kfree(rdev->pm.dpm.ps); 287341a524abSAlex Deucher kfree(rdev->pm.dpm.priv); 287441a524abSAlex Deucher r600_free_extended_power_table(rdev); 287541a524abSAlex Deucher } 287641a524abSAlex Deucher 287741a524abSAlex Deucher void kv_dpm_display_configuration_changed(struct radeon_device *rdev) 287841a524abSAlex Deucher { 287941a524abSAlex Deucher 288041a524abSAlex Deucher } 288141a524abSAlex Deucher 288241a524abSAlex Deucher u32 kv_dpm_get_sclk(struct radeon_device *rdev, bool low) 288341a524abSAlex Deucher { 288441a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 288541a524abSAlex Deucher struct kv_ps *requested_state = kv_get_ps(&pi->requested_rps); 288641a524abSAlex Deucher 288741a524abSAlex Deucher if (low) 288841a524abSAlex Deucher return requested_state->levels[0].sclk; 288941a524abSAlex Deucher else 289041a524abSAlex Deucher return requested_state->levels[requested_state->num_levels - 1].sclk; 289141a524abSAlex Deucher } 289241a524abSAlex Deucher 289341a524abSAlex Deucher u32 kv_dpm_get_mclk(struct radeon_device *rdev, bool low) 289441a524abSAlex Deucher { 289541a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 289641a524abSAlex Deucher 289741a524abSAlex Deucher return pi->sys_info.bootup_uma_clk; 289841a524abSAlex Deucher } 289941a524abSAlex Deucher 2900