141a524abSAlex Deucher /* 241a524abSAlex Deucher * Copyright 2013 Advanced Micro Devices, Inc. 341a524abSAlex Deucher * 441a524abSAlex Deucher * Permission is hereby granted, free of charge, to any person obtaining a 541a524abSAlex Deucher * copy of this software and associated documentation files (the "Software"), 641a524abSAlex Deucher * to deal in the Software without restriction, including without limitation 741a524abSAlex Deucher * the rights to use, copy, modify, merge, publish, distribute, sublicense, 841a524abSAlex Deucher * and/or sell copies of the Software, and to permit persons to whom the 941a524abSAlex Deucher * Software is furnished to do so, subject to the following conditions: 1041a524abSAlex Deucher * 1141a524abSAlex Deucher * The above copyright notice and this permission notice shall be included in 1241a524abSAlex Deucher * all copies or substantial portions of the Software. 1341a524abSAlex Deucher * 1441a524abSAlex Deucher * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1541a524abSAlex Deucher * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1641a524abSAlex Deucher * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1741a524abSAlex Deucher * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 1841a524abSAlex Deucher * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 1941a524abSAlex Deucher * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2041a524abSAlex Deucher * OTHER DEALINGS IN THE SOFTWARE. 2141a524abSAlex Deucher * 2241a524abSAlex Deucher */ 2341a524abSAlex Deucher 2441a524abSAlex Deucher #include "drmP.h" 2541a524abSAlex Deucher #include "radeon.h" 2641a524abSAlex Deucher #include "cikd.h" 2741a524abSAlex Deucher #include "r600_dpm.h" 2841a524abSAlex Deucher #include "kv_dpm.h" 29e409b128SChristian König #include "radeon_asic.h" 30ae3e40e8SAlex Deucher #include <linux/seq_file.h> 3141a524abSAlex Deucher 3241a524abSAlex Deucher #define KV_MAX_DEEPSLEEP_DIVIDER_ID 5 3341a524abSAlex Deucher #define KV_MINIMUM_ENGINE_CLOCK 800 3441a524abSAlex Deucher #define SMC_RAM_END 0x40000 3541a524abSAlex Deucher 3641a524abSAlex Deucher static void kv_init_graphics_levels(struct radeon_device *rdev); 3741a524abSAlex Deucher static int kv_calculate_ds_divider(struct radeon_device *rdev); 3841a524abSAlex Deucher static int kv_calculate_nbps_level_settings(struct radeon_device *rdev); 3941a524abSAlex Deucher static int kv_calculate_dpm_settings(struct radeon_device *rdev); 4041a524abSAlex Deucher static void kv_enable_new_levels(struct radeon_device *rdev); 4141a524abSAlex Deucher static void kv_program_nbps_index_settings(struct radeon_device *rdev, 4241a524abSAlex Deucher struct radeon_ps *new_rps); 43136de91eSAlex Deucher static int kv_set_enabled_level(struct radeon_device *rdev, u32 level); 4441a524abSAlex Deucher static int kv_set_enabled_levels(struct radeon_device *rdev); 452b4c8022SAlex Deucher static int kv_force_dpm_highest(struct radeon_device *rdev); 4641a524abSAlex Deucher static int kv_force_dpm_lowest(struct radeon_device *rdev); 4741a524abSAlex Deucher static void kv_apply_state_adjust_rules(struct radeon_device *rdev, 4841a524abSAlex Deucher struct radeon_ps *new_rps, 4941a524abSAlex Deucher struct radeon_ps *old_rps); 5041a524abSAlex Deucher static int kv_set_thermal_temperature_range(struct radeon_device *rdev, 5141a524abSAlex Deucher int min_temp, int max_temp); 5241a524abSAlex Deucher static int kv_init_fps_limits(struct radeon_device *rdev); 5341a524abSAlex Deucher 5477df508aSAlex Deucher void kv_dpm_powergate_uvd(struct radeon_device *rdev, bool gate); 5541a524abSAlex Deucher static void kv_dpm_powergate_vce(struct radeon_device *rdev, bool gate); 5641a524abSAlex Deucher static void kv_dpm_powergate_samu(struct radeon_device *rdev, bool gate); 5741a524abSAlex Deucher static void kv_dpm_powergate_acp(struct radeon_device *rdev, bool gate); 5841a524abSAlex Deucher 5941a524abSAlex Deucher extern void cik_enter_rlc_safe_mode(struct radeon_device *rdev); 6041a524abSAlex Deucher extern void cik_exit_rlc_safe_mode(struct radeon_device *rdev); 6141a524abSAlex Deucher extern void cik_update_cg(struct radeon_device *rdev, 6241a524abSAlex Deucher u32 block, bool enable); 6341a524abSAlex Deucher 6441a524abSAlex Deucher static const struct kv_lcac_config_values sx_local_cac_cfg_kv[] = 6541a524abSAlex Deucher { 6641a524abSAlex Deucher { 0, 4, 1 }, 6741a524abSAlex Deucher { 1, 4, 1 }, 6841a524abSAlex Deucher { 2, 5, 1 }, 6941a524abSAlex Deucher { 3, 4, 2 }, 7041a524abSAlex Deucher { 4, 1, 1 }, 7141a524abSAlex Deucher { 5, 5, 2 }, 7241a524abSAlex Deucher { 6, 6, 1 }, 7341a524abSAlex Deucher { 7, 9, 2 }, 7441a524abSAlex Deucher { 0xffffffff } 7541a524abSAlex Deucher }; 7641a524abSAlex Deucher 7741a524abSAlex Deucher static const struct kv_lcac_config_values mc0_local_cac_cfg_kv[] = 7841a524abSAlex Deucher { 7941a524abSAlex Deucher { 0, 4, 1 }, 8041a524abSAlex Deucher { 0xffffffff } 8141a524abSAlex Deucher }; 8241a524abSAlex Deucher 8341a524abSAlex Deucher static const struct kv_lcac_config_values mc1_local_cac_cfg_kv[] = 8441a524abSAlex Deucher { 8541a524abSAlex Deucher { 0, 4, 1 }, 8641a524abSAlex Deucher { 0xffffffff } 8741a524abSAlex Deucher }; 8841a524abSAlex Deucher 8941a524abSAlex Deucher static const struct kv_lcac_config_values mc2_local_cac_cfg_kv[] = 9041a524abSAlex Deucher { 9141a524abSAlex Deucher { 0, 4, 1 }, 9241a524abSAlex Deucher { 0xffffffff } 9341a524abSAlex Deucher }; 9441a524abSAlex Deucher 9541a524abSAlex Deucher static const struct kv_lcac_config_values mc3_local_cac_cfg_kv[] = 9641a524abSAlex Deucher { 9741a524abSAlex Deucher { 0, 4, 1 }, 9841a524abSAlex Deucher { 0xffffffff } 9941a524abSAlex Deucher }; 10041a524abSAlex Deucher 10141a524abSAlex Deucher static const struct kv_lcac_config_values cpl_local_cac_cfg_kv[] = 10241a524abSAlex Deucher { 10341a524abSAlex Deucher { 0, 4, 1 }, 10441a524abSAlex Deucher { 1, 4, 1 }, 10541a524abSAlex Deucher { 2, 5, 1 }, 10641a524abSAlex Deucher { 3, 4, 1 }, 10741a524abSAlex Deucher { 4, 1, 1 }, 10841a524abSAlex Deucher { 5, 5, 1 }, 10941a524abSAlex Deucher { 6, 6, 1 }, 11041a524abSAlex Deucher { 7, 9, 1 }, 11141a524abSAlex Deucher { 8, 4, 1 }, 11241a524abSAlex Deucher { 9, 2, 1 }, 11341a524abSAlex Deucher { 10, 3, 1 }, 11441a524abSAlex Deucher { 11, 6, 1 }, 11541a524abSAlex Deucher { 12, 8, 2 }, 11641a524abSAlex Deucher { 13, 1, 1 }, 11741a524abSAlex Deucher { 14, 2, 1 }, 11841a524abSAlex Deucher { 15, 3, 1 }, 11941a524abSAlex Deucher { 16, 1, 1 }, 12041a524abSAlex Deucher { 17, 4, 1 }, 12141a524abSAlex Deucher { 18, 3, 1 }, 12241a524abSAlex Deucher { 19, 1, 1 }, 12341a524abSAlex Deucher { 20, 8, 1 }, 12441a524abSAlex Deucher { 21, 5, 1 }, 12541a524abSAlex Deucher { 22, 1, 1 }, 12641a524abSAlex Deucher { 23, 1, 1 }, 12741a524abSAlex Deucher { 24, 4, 1 }, 12841a524abSAlex Deucher { 27, 6, 1 }, 12941a524abSAlex Deucher { 28, 1, 1 }, 13041a524abSAlex Deucher { 0xffffffff } 13141a524abSAlex Deucher }; 13241a524abSAlex Deucher 13341a524abSAlex Deucher static const struct kv_lcac_config_reg sx0_cac_config_reg[] = 13441a524abSAlex Deucher { 13541a524abSAlex Deucher { 0xc0400d00, 0x003e0000, 17, 0x3fc00000, 22, 0x0001fffe, 1, 0x00000001, 0 } 13641a524abSAlex Deucher }; 13741a524abSAlex Deucher 13841a524abSAlex Deucher static const struct kv_lcac_config_reg mc0_cac_config_reg[] = 13941a524abSAlex Deucher { 14041a524abSAlex Deucher { 0xc0400d30, 0x003e0000, 17, 0x3fc00000, 22, 0x0001fffe, 1, 0x00000001, 0 } 14141a524abSAlex Deucher }; 14241a524abSAlex Deucher 14341a524abSAlex Deucher static const struct kv_lcac_config_reg mc1_cac_config_reg[] = 14441a524abSAlex Deucher { 14541a524abSAlex Deucher { 0xc0400d3c, 0x003e0000, 17, 0x3fc00000, 22, 0x0001fffe, 1, 0x00000001, 0 } 14641a524abSAlex Deucher }; 14741a524abSAlex Deucher 14841a524abSAlex Deucher static const struct kv_lcac_config_reg mc2_cac_config_reg[] = 14941a524abSAlex Deucher { 15041a524abSAlex Deucher { 0xc0400d48, 0x003e0000, 17, 0x3fc00000, 22, 0x0001fffe, 1, 0x00000001, 0 } 15141a524abSAlex Deucher }; 15241a524abSAlex Deucher 15341a524abSAlex Deucher static const struct kv_lcac_config_reg mc3_cac_config_reg[] = 15441a524abSAlex Deucher { 15541a524abSAlex Deucher { 0xc0400d54, 0x003e0000, 17, 0x3fc00000, 22, 0x0001fffe, 1, 0x00000001, 0 } 15641a524abSAlex Deucher }; 15741a524abSAlex Deucher 15841a524abSAlex Deucher static const struct kv_lcac_config_reg cpl_cac_config_reg[] = 15941a524abSAlex Deucher { 16041a524abSAlex Deucher { 0xc0400d80, 0x003e0000, 17, 0x3fc00000, 22, 0x0001fffe, 1, 0x00000001, 0 } 16141a524abSAlex Deucher }; 16241a524abSAlex Deucher 16341a524abSAlex Deucher static const struct kv_pt_config_reg didt_config_kv[] = 16441a524abSAlex Deucher { 16541a524abSAlex Deucher { 0x10, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 16641a524abSAlex Deucher { 0x10, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, 16741a524abSAlex Deucher { 0x10, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, 16841a524abSAlex Deucher { 0x10, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, 16941a524abSAlex Deucher { 0x11, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 17041a524abSAlex Deucher { 0x11, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, 17141a524abSAlex Deucher { 0x11, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, 17241a524abSAlex Deucher { 0x11, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, 17341a524abSAlex Deucher { 0x12, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 17441a524abSAlex Deucher { 0x12, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, 17541a524abSAlex Deucher { 0x12, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, 17641a524abSAlex Deucher { 0x12, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, 17741a524abSAlex Deucher { 0x2, 0x00003fff, 0, 0x4, KV_CONFIGREG_DIDT_IND }, 17841a524abSAlex Deucher { 0x2, 0x03ff0000, 16, 0x80, KV_CONFIGREG_DIDT_IND }, 17941a524abSAlex Deucher { 0x2, 0x78000000, 27, 0x3, KV_CONFIGREG_DIDT_IND }, 18041a524abSAlex Deucher { 0x1, 0x0000ffff, 0, 0x3FFF, KV_CONFIGREG_DIDT_IND }, 18141a524abSAlex Deucher { 0x1, 0xffff0000, 16, 0x3FFF, KV_CONFIGREG_DIDT_IND }, 18241a524abSAlex Deucher { 0x0, 0x00000001, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 18341a524abSAlex Deucher { 0x30, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 18441a524abSAlex Deucher { 0x30, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, 18541a524abSAlex Deucher { 0x30, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, 18641a524abSAlex Deucher { 0x30, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, 18741a524abSAlex Deucher { 0x31, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 18841a524abSAlex Deucher { 0x31, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, 18941a524abSAlex Deucher { 0x31, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, 19041a524abSAlex Deucher { 0x31, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, 19141a524abSAlex Deucher { 0x32, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 19241a524abSAlex Deucher { 0x32, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, 19341a524abSAlex Deucher { 0x32, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, 19441a524abSAlex Deucher { 0x32, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, 19541a524abSAlex Deucher { 0x22, 0x00003fff, 0, 0x4, KV_CONFIGREG_DIDT_IND }, 19641a524abSAlex Deucher { 0x22, 0x03ff0000, 16, 0x80, KV_CONFIGREG_DIDT_IND }, 19741a524abSAlex Deucher { 0x22, 0x78000000, 27, 0x3, KV_CONFIGREG_DIDT_IND }, 19841a524abSAlex Deucher { 0x21, 0x0000ffff, 0, 0x3FFF, KV_CONFIGREG_DIDT_IND }, 19941a524abSAlex Deucher { 0x21, 0xffff0000, 16, 0x3FFF, KV_CONFIGREG_DIDT_IND }, 20041a524abSAlex Deucher { 0x20, 0x00000001, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 20141a524abSAlex Deucher { 0x50, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 20241a524abSAlex Deucher { 0x50, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, 20341a524abSAlex Deucher { 0x50, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, 20441a524abSAlex Deucher { 0x50, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, 20541a524abSAlex Deucher { 0x51, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 20641a524abSAlex Deucher { 0x51, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, 20741a524abSAlex Deucher { 0x51, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, 20841a524abSAlex Deucher { 0x51, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, 20941a524abSAlex Deucher { 0x52, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 21041a524abSAlex Deucher { 0x52, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, 21141a524abSAlex Deucher { 0x52, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, 21241a524abSAlex Deucher { 0x52, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, 21341a524abSAlex Deucher { 0x42, 0x00003fff, 0, 0x4, KV_CONFIGREG_DIDT_IND }, 21441a524abSAlex Deucher { 0x42, 0x03ff0000, 16, 0x80, KV_CONFIGREG_DIDT_IND }, 21541a524abSAlex Deucher { 0x42, 0x78000000, 27, 0x3, KV_CONFIGREG_DIDT_IND }, 21641a524abSAlex Deucher { 0x41, 0x0000ffff, 0, 0x3FFF, KV_CONFIGREG_DIDT_IND }, 21741a524abSAlex Deucher { 0x41, 0xffff0000, 16, 0x3FFF, KV_CONFIGREG_DIDT_IND }, 21841a524abSAlex Deucher { 0x40, 0x00000001, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 21941a524abSAlex Deucher { 0x70, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 22041a524abSAlex Deucher { 0x70, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, 22141a524abSAlex Deucher { 0x70, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, 22241a524abSAlex Deucher { 0x70, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, 22341a524abSAlex Deucher { 0x71, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 22441a524abSAlex Deucher { 0x71, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, 22541a524abSAlex Deucher { 0x71, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, 22641a524abSAlex Deucher { 0x71, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, 22741a524abSAlex Deucher { 0x72, 0x000000ff, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 22841a524abSAlex Deucher { 0x72, 0x0000ff00, 8, 0x0, KV_CONFIGREG_DIDT_IND }, 22941a524abSAlex Deucher { 0x72, 0x00ff0000, 16, 0x0, KV_CONFIGREG_DIDT_IND }, 23041a524abSAlex Deucher { 0x72, 0xff000000, 24, 0x0, KV_CONFIGREG_DIDT_IND }, 23141a524abSAlex Deucher { 0x62, 0x00003fff, 0, 0x4, KV_CONFIGREG_DIDT_IND }, 23241a524abSAlex Deucher { 0x62, 0x03ff0000, 16, 0x80, KV_CONFIGREG_DIDT_IND }, 23341a524abSAlex Deucher { 0x62, 0x78000000, 27, 0x3, KV_CONFIGREG_DIDT_IND }, 23441a524abSAlex Deucher { 0x61, 0x0000ffff, 0, 0x3FFF, KV_CONFIGREG_DIDT_IND }, 23541a524abSAlex Deucher { 0x61, 0xffff0000, 16, 0x3FFF, KV_CONFIGREG_DIDT_IND }, 23641a524abSAlex Deucher { 0x60, 0x00000001, 0, 0x0, KV_CONFIGREG_DIDT_IND }, 23741a524abSAlex Deucher { 0xFFFFFFFF } 23841a524abSAlex Deucher }; 23941a524abSAlex Deucher 24041a524abSAlex Deucher static struct kv_ps *kv_get_ps(struct radeon_ps *rps) 24141a524abSAlex Deucher { 24241a524abSAlex Deucher struct kv_ps *ps = rps->ps_priv; 24341a524abSAlex Deucher 24441a524abSAlex Deucher return ps; 24541a524abSAlex Deucher } 24641a524abSAlex Deucher 24741a524abSAlex Deucher static struct kv_power_info *kv_get_pi(struct radeon_device *rdev) 24841a524abSAlex Deucher { 24941a524abSAlex Deucher struct kv_power_info *pi = rdev->pm.dpm.priv; 25041a524abSAlex Deucher 25141a524abSAlex Deucher return pi; 25241a524abSAlex Deucher } 25341a524abSAlex Deucher 25441a524abSAlex Deucher #if 0 25541a524abSAlex Deucher static void kv_program_local_cac_table(struct radeon_device *rdev, 25641a524abSAlex Deucher const struct kv_lcac_config_values *local_cac_table, 25741a524abSAlex Deucher const struct kv_lcac_config_reg *local_cac_reg) 25841a524abSAlex Deucher { 25941a524abSAlex Deucher u32 i, count, data; 26041a524abSAlex Deucher const struct kv_lcac_config_values *values = local_cac_table; 26141a524abSAlex Deucher 26241a524abSAlex Deucher while (values->block_id != 0xffffffff) { 26341a524abSAlex Deucher count = values->signal_id; 26441a524abSAlex Deucher for (i = 0; i < count; i++) { 26541a524abSAlex Deucher data = ((values->block_id << local_cac_reg->block_shift) & 26641a524abSAlex Deucher local_cac_reg->block_mask); 26741a524abSAlex Deucher data |= ((i << local_cac_reg->signal_shift) & 26841a524abSAlex Deucher local_cac_reg->signal_mask); 26941a524abSAlex Deucher data |= ((values->t << local_cac_reg->t_shift) & 27041a524abSAlex Deucher local_cac_reg->t_mask); 27141a524abSAlex Deucher data |= ((1 << local_cac_reg->enable_shift) & 27241a524abSAlex Deucher local_cac_reg->enable_mask); 27341a524abSAlex Deucher WREG32_SMC(local_cac_reg->cntl, data); 27441a524abSAlex Deucher } 27541a524abSAlex Deucher values++; 27641a524abSAlex Deucher } 27741a524abSAlex Deucher } 27841a524abSAlex Deucher #endif 27941a524abSAlex Deucher 28041a524abSAlex Deucher static int kv_program_pt_config_registers(struct radeon_device *rdev, 28141a524abSAlex Deucher const struct kv_pt_config_reg *cac_config_regs) 28241a524abSAlex Deucher { 28341a524abSAlex Deucher const struct kv_pt_config_reg *config_regs = cac_config_regs; 28441a524abSAlex Deucher u32 data; 28541a524abSAlex Deucher u32 cache = 0; 28641a524abSAlex Deucher 28741a524abSAlex Deucher if (config_regs == NULL) 28841a524abSAlex Deucher return -EINVAL; 28941a524abSAlex Deucher 29041a524abSAlex Deucher while (config_regs->offset != 0xFFFFFFFF) { 29141a524abSAlex Deucher if (config_regs->type == KV_CONFIGREG_CACHE) { 29241a524abSAlex Deucher cache |= ((config_regs->value << config_regs->shift) & config_regs->mask); 29341a524abSAlex Deucher } else { 29441a524abSAlex Deucher switch (config_regs->type) { 29541a524abSAlex Deucher case KV_CONFIGREG_SMC_IND: 29641a524abSAlex Deucher data = RREG32_SMC(config_regs->offset); 29741a524abSAlex Deucher break; 29841a524abSAlex Deucher case KV_CONFIGREG_DIDT_IND: 29941a524abSAlex Deucher data = RREG32_DIDT(config_regs->offset); 30041a524abSAlex Deucher break; 30141a524abSAlex Deucher default: 30241a524abSAlex Deucher data = RREG32(config_regs->offset << 2); 30341a524abSAlex Deucher break; 30441a524abSAlex Deucher } 30541a524abSAlex Deucher 30641a524abSAlex Deucher data &= ~config_regs->mask; 30741a524abSAlex Deucher data |= ((config_regs->value << config_regs->shift) & config_regs->mask); 30841a524abSAlex Deucher data |= cache; 30941a524abSAlex Deucher cache = 0; 31041a524abSAlex Deucher 31141a524abSAlex Deucher switch (config_regs->type) { 31241a524abSAlex Deucher case KV_CONFIGREG_SMC_IND: 31341a524abSAlex Deucher WREG32_SMC(config_regs->offset, data); 31441a524abSAlex Deucher break; 31541a524abSAlex Deucher case KV_CONFIGREG_DIDT_IND: 31641a524abSAlex Deucher WREG32_DIDT(config_regs->offset, data); 31741a524abSAlex Deucher break; 31841a524abSAlex Deucher default: 31941a524abSAlex Deucher WREG32(config_regs->offset << 2, data); 32041a524abSAlex Deucher break; 32141a524abSAlex Deucher } 32241a524abSAlex Deucher } 32341a524abSAlex Deucher config_regs++; 32441a524abSAlex Deucher } 32541a524abSAlex Deucher 32641a524abSAlex Deucher return 0; 32741a524abSAlex Deucher } 32841a524abSAlex Deucher 32941a524abSAlex Deucher static void kv_do_enable_didt(struct radeon_device *rdev, bool enable) 33041a524abSAlex Deucher { 33141a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 33241a524abSAlex Deucher u32 data; 33341a524abSAlex Deucher 33441a524abSAlex Deucher if (pi->caps_sq_ramping) { 33541a524abSAlex Deucher data = RREG32_DIDT(DIDT_SQ_CTRL0); 33641a524abSAlex Deucher if (enable) 33741a524abSAlex Deucher data |= DIDT_CTRL_EN; 33841a524abSAlex Deucher else 33941a524abSAlex Deucher data &= ~DIDT_CTRL_EN; 34041a524abSAlex Deucher WREG32_DIDT(DIDT_SQ_CTRL0, data); 34141a524abSAlex Deucher } 34241a524abSAlex Deucher 34341a524abSAlex Deucher if (pi->caps_db_ramping) { 34441a524abSAlex Deucher data = RREG32_DIDT(DIDT_DB_CTRL0); 34541a524abSAlex Deucher if (enable) 34641a524abSAlex Deucher data |= DIDT_CTRL_EN; 34741a524abSAlex Deucher else 34841a524abSAlex Deucher data &= ~DIDT_CTRL_EN; 34941a524abSAlex Deucher WREG32_DIDT(DIDT_DB_CTRL0, data); 35041a524abSAlex Deucher } 35141a524abSAlex Deucher 35241a524abSAlex Deucher if (pi->caps_td_ramping) { 35341a524abSAlex Deucher data = RREG32_DIDT(DIDT_TD_CTRL0); 35441a524abSAlex Deucher if (enable) 35541a524abSAlex Deucher data |= DIDT_CTRL_EN; 35641a524abSAlex Deucher else 35741a524abSAlex Deucher data &= ~DIDT_CTRL_EN; 35841a524abSAlex Deucher WREG32_DIDT(DIDT_TD_CTRL0, data); 35941a524abSAlex Deucher } 36041a524abSAlex Deucher 36141a524abSAlex Deucher if (pi->caps_tcp_ramping) { 36241a524abSAlex Deucher data = RREG32_DIDT(DIDT_TCP_CTRL0); 36341a524abSAlex Deucher if (enable) 36441a524abSAlex Deucher data |= DIDT_CTRL_EN; 36541a524abSAlex Deucher else 36641a524abSAlex Deucher data &= ~DIDT_CTRL_EN; 36741a524abSAlex Deucher WREG32_DIDT(DIDT_TCP_CTRL0, data); 36841a524abSAlex Deucher } 36941a524abSAlex Deucher } 37041a524abSAlex Deucher 37141a524abSAlex Deucher static int kv_enable_didt(struct radeon_device *rdev, bool enable) 37241a524abSAlex Deucher { 37341a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 37441a524abSAlex Deucher int ret; 37541a524abSAlex Deucher 37641a524abSAlex Deucher if (pi->caps_sq_ramping || 37741a524abSAlex Deucher pi->caps_db_ramping || 37841a524abSAlex Deucher pi->caps_td_ramping || 37941a524abSAlex Deucher pi->caps_tcp_ramping) { 38041a524abSAlex Deucher cik_enter_rlc_safe_mode(rdev); 38141a524abSAlex Deucher 38241a524abSAlex Deucher if (enable) { 38341a524abSAlex Deucher ret = kv_program_pt_config_registers(rdev, didt_config_kv); 38441a524abSAlex Deucher if (ret) { 38541a524abSAlex Deucher cik_exit_rlc_safe_mode(rdev); 38641a524abSAlex Deucher return ret; 38741a524abSAlex Deucher } 38841a524abSAlex Deucher } 38941a524abSAlex Deucher 39041a524abSAlex Deucher kv_do_enable_didt(rdev, enable); 39141a524abSAlex Deucher 39241a524abSAlex Deucher cik_exit_rlc_safe_mode(rdev); 39341a524abSAlex Deucher } 39441a524abSAlex Deucher 39541a524abSAlex Deucher return 0; 39641a524abSAlex Deucher } 39741a524abSAlex Deucher 39841a524abSAlex Deucher #if 0 39941a524abSAlex Deucher static void kv_initialize_hardware_cac_manager(struct radeon_device *rdev) 40041a524abSAlex Deucher { 40141a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 40241a524abSAlex Deucher 40341a524abSAlex Deucher if (pi->caps_cac) { 40441a524abSAlex Deucher WREG32_SMC(LCAC_SX0_OVR_SEL, 0); 40541a524abSAlex Deucher WREG32_SMC(LCAC_SX0_OVR_VAL, 0); 40641a524abSAlex Deucher kv_program_local_cac_table(rdev, sx_local_cac_cfg_kv, sx0_cac_config_reg); 40741a524abSAlex Deucher 40841a524abSAlex Deucher WREG32_SMC(LCAC_MC0_OVR_SEL, 0); 40941a524abSAlex Deucher WREG32_SMC(LCAC_MC0_OVR_VAL, 0); 41041a524abSAlex Deucher kv_program_local_cac_table(rdev, mc0_local_cac_cfg_kv, mc0_cac_config_reg); 41141a524abSAlex Deucher 41241a524abSAlex Deucher WREG32_SMC(LCAC_MC1_OVR_SEL, 0); 41341a524abSAlex Deucher WREG32_SMC(LCAC_MC1_OVR_VAL, 0); 41441a524abSAlex Deucher kv_program_local_cac_table(rdev, mc1_local_cac_cfg_kv, mc1_cac_config_reg); 41541a524abSAlex Deucher 41641a524abSAlex Deucher WREG32_SMC(LCAC_MC2_OVR_SEL, 0); 41741a524abSAlex Deucher WREG32_SMC(LCAC_MC2_OVR_VAL, 0); 41841a524abSAlex Deucher kv_program_local_cac_table(rdev, mc2_local_cac_cfg_kv, mc2_cac_config_reg); 41941a524abSAlex Deucher 42041a524abSAlex Deucher WREG32_SMC(LCAC_MC3_OVR_SEL, 0); 42141a524abSAlex Deucher WREG32_SMC(LCAC_MC3_OVR_VAL, 0); 42241a524abSAlex Deucher kv_program_local_cac_table(rdev, mc3_local_cac_cfg_kv, mc3_cac_config_reg); 42341a524abSAlex Deucher 42441a524abSAlex Deucher WREG32_SMC(LCAC_CPL_OVR_SEL, 0); 42541a524abSAlex Deucher WREG32_SMC(LCAC_CPL_OVR_VAL, 0); 42641a524abSAlex Deucher kv_program_local_cac_table(rdev, cpl_local_cac_cfg_kv, cpl_cac_config_reg); 42741a524abSAlex Deucher } 42841a524abSAlex Deucher } 42941a524abSAlex Deucher #endif 43041a524abSAlex Deucher 43141a524abSAlex Deucher static int kv_enable_smc_cac(struct radeon_device *rdev, bool enable) 43241a524abSAlex Deucher { 43341a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 43441a524abSAlex Deucher int ret = 0; 43541a524abSAlex Deucher 43641a524abSAlex Deucher if (pi->caps_cac) { 43741a524abSAlex Deucher if (enable) { 43841a524abSAlex Deucher ret = kv_notify_message_to_smu(rdev, PPSMC_MSG_EnableCac); 43941a524abSAlex Deucher if (ret) 44041a524abSAlex Deucher pi->cac_enabled = false; 44141a524abSAlex Deucher else 44241a524abSAlex Deucher pi->cac_enabled = true; 44341a524abSAlex Deucher } else if (pi->cac_enabled) { 44441a524abSAlex Deucher kv_notify_message_to_smu(rdev, PPSMC_MSG_DisableCac); 44541a524abSAlex Deucher pi->cac_enabled = false; 44641a524abSAlex Deucher } 44741a524abSAlex Deucher } 44841a524abSAlex Deucher 44941a524abSAlex Deucher return ret; 45041a524abSAlex Deucher } 45141a524abSAlex Deucher 45241a524abSAlex Deucher static int kv_process_firmware_header(struct radeon_device *rdev) 45341a524abSAlex Deucher { 45441a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 45541a524abSAlex Deucher u32 tmp; 45641a524abSAlex Deucher int ret; 45741a524abSAlex Deucher 45841a524abSAlex Deucher ret = kv_read_smc_sram_dword(rdev, SMU7_FIRMWARE_HEADER_LOCATION + 45941a524abSAlex Deucher offsetof(SMU7_Firmware_Header, DpmTable), 46041a524abSAlex Deucher &tmp, pi->sram_end); 46141a524abSAlex Deucher 46241a524abSAlex Deucher if (ret == 0) 46341a524abSAlex Deucher pi->dpm_table_start = tmp; 46441a524abSAlex Deucher 46541a524abSAlex Deucher ret = kv_read_smc_sram_dword(rdev, SMU7_FIRMWARE_HEADER_LOCATION + 46641a524abSAlex Deucher offsetof(SMU7_Firmware_Header, SoftRegisters), 46741a524abSAlex Deucher &tmp, pi->sram_end); 46841a524abSAlex Deucher 46941a524abSAlex Deucher if (ret == 0) 47041a524abSAlex Deucher pi->soft_regs_start = tmp; 47141a524abSAlex Deucher 47241a524abSAlex Deucher return ret; 47341a524abSAlex Deucher } 47441a524abSAlex Deucher 47541a524abSAlex Deucher static int kv_enable_dpm_voltage_scaling(struct radeon_device *rdev) 47641a524abSAlex Deucher { 47741a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 47841a524abSAlex Deucher int ret; 47941a524abSAlex Deucher 48041a524abSAlex Deucher pi->graphics_voltage_change_enable = 1; 48141a524abSAlex Deucher 48241a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 48341a524abSAlex Deucher pi->dpm_table_start + 48441a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, GraphicsVoltageChangeEnable), 48541a524abSAlex Deucher &pi->graphics_voltage_change_enable, 48641a524abSAlex Deucher sizeof(u8), pi->sram_end); 48741a524abSAlex Deucher 48841a524abSAlex Deucher return ret; 48941a524abSAlex Deucher } 49041a524abSAlex Deucher 49141a524abSAlex Deucher static int kv_set_dpm_interval(struct radeon_device *rdev) 49241a524abSAlex Deucher { 49341a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 49441a524abSAlex Deucher int ret; 49541a524abSAlex Deucher 49641a524abSAlex Deucher pi->graphics_interval = 1; 49741a524abSAlex Deucher 49841a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 49941a524abSAlex Deucher pi->dpm_table_start + 50041a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, GraphicsInterval), 50141a524abSAlex Deucher &pi->graphics_interval, 50241a524abSAlex Deucher sizeof(u8), pi->sram_end); 50341a524abSAlex Deucher 50441a524abSAlex Deucher return ret; 50541a524abSAlex Deucher } 50641a524abSAlex Deucher 50741a524abSAlex Deucher static int kv_set_dpm_boot_state(struct radeon_device *rdev) 50841a524abSAlex Deucher { 50941a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 51041a524abSAlex Deucher int ret; 51141a524abSAlex Deucher 51241a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 51341a524abSAlex Deucher pi->dpm_table_start + 51441a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, GraphicsBootLevel), 51541a524abSAlex Deucher &pi->graphics_boot_level, 51641a524abSAlex Deucher sizeof(u8), pi->sram_end); 51741a524abSAlex Deucher 51841a524abSAlex Deucher return ret; 51941a524abSAlex Deucher } 52041a524abSAlex Deucher 52141a524abSAlex Deucher static void kv_program_vc(struct radeon_device *rdev) 52241a524abSAlex Deucher { 523136de91eSAlex Deucher WREG32_SMC(CG_FTV_0, 0x3FFFC100); 52441a524abSAlex Deucher } 52541a524abSAlex Deucher 52641a524abSAlex Deucher static void kv_clear_vc(struct radeon_device *rdev) 52741a524abSAlex Deucher { 52841a524abSAlex Deucher WREG32_SMC(CG_FTV_0, 0); 52941a524abSAlex Deucher } 53041a524abSAlex Deucher 53141a524abSAlex Deucher static int kv_set_divider_value(struct radeon_device *rdev, 53241a524abSAlex Deucher u32 index, u32 sclk) 53341a524abSAlex Deucher { 53441a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 53541a524abSAlex Deucher struct atom_clock_dividers dividers; 53641a524abSAlex Deucher int ret; 53741a524abSAlex Deucher 53841a524abSAlex Deucher ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, 53941a524abSAlex Deucher sclk, false, ÷rs); 54041a524abSAlex Deucher if (ret) 54141a524abSAlex Deucher return ret; 54241a524abSAlex Deucher 54341a524abSAlex Deucher pi->graphics_level[index].SclkDid = (u8)dividers.post_div; 54441a524abSAlex Deucher pi->graphics_level[index].SclkFrequency = cpu_to_be32(sclk); 54541a524abSAlex Deucher 54641a524abSAlex Deucher return 0; 54741a524abSAlex Deucher } 54841a524abSAlex Deucher 54941a524abSAlex Deucher static u16 kv_convert_8bit_index_to_voltage(struct radeon_device *rdev, 55041a524abSAlex Deucher u16 voltage) 55141a524abSAlex Deucher { 55241a524abSAlex Deucher return 6200 - (voltage * 25); 55341a524abSAlex Deucher } 55441a524abSAlex Deucher 55541a524abSAlex Deucher static u16 kv_convert_2bit_index_to_voltage(struct radeon_device *rdev, 55641a524abSAlex Deucher u32 vid_2bit) 55741a524abSAlex Deucher { 55841a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 55941a524abSAlex Deucher u32 vid_8bit = sumo_convert_vid2_to_vid7(rdev, 56041a524abSAlex Deucher &pi->sys_info.vid_mapping_table, 56141a524abSAlex Deucher vid_2bit); 56241a524abSAlex Deucher 56341a524abSAlex Deucher return kv_convert_8bit_index_to_voltage(rdev, (u16)vid_8bit); 56441a524abSAlex Deucher } 56541a524abSAlex Deucher 56641a524abSAlex Deucher 56741a524abSAlex Deucher static int kv_set_vid(struct radeon_device *rdev, u32 index, u32 vid) 56841a524abSAlex Deucher { 56941a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 57041a524abSAlex Deucher 57141a524abSAlex Deucher pi->graphics_level[index].VoltageDownH = (u8)pi->voltage_drop_t; 57241a524abSAlex Deucher pi->graphics_level[index].MinVddNb = 57341a524abSAlex Deucher cpu_to_be32(kv_convert_2bit_index_to_voltage(rdev, vid)); 57441a524abSAlex Deucher 57541a524abSAlex Deucher return 0; 57641a524abSAlex Deucher } 57741a524abSAlex Deucher 57841a524abSAlex Deucher static int kv_set_at(struct radeon_device *rdev, u32 index, u32 at) 57941a524abSAlex Deucher { 58041a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 58141a524abSAlex Deucher 58241a524abSAlex Deucher pi->graphics_level[index].AT = cpu_to_be16((u16)at); 58341a524abSAlex Deucher 58441a524abSAlex Deucher return 0; 58541a524abSAlex Deucher } 58641a524abSAlex Deucher 58741a524abSAlex Deucher static void kv_dpm_power_level_enable(struct radeon_device *rdev, 58841a524abSAlex Deucher u32 index, bool enable) 58941a524abSAlex Deucher { 59041a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 59141a524abSAlex Deucher 59241a524abSAlex Deucher pi->graphics_level[index].EnabledForActivity = enable ? 1 : 0; 59341a524abSAlex Deucher } 59441a524abSAlex Deucher 59541a524abSAlex Deucher static void kv_start_dpm(struct radeon_device *rdev) 59641a524abSAlex Deucher { 59741a524abSAlex Deucher u32 tmp = RREG32_SMC(GENERAL_PWRMGT); 59841a524abSAlex Deucher 59941a524abSAlex Deucher tmp |= GLOBAL_PWRMGT_EN; 60041a524abSAlex Deucher WREG32_SMC(GENERAL_PWRMGT, tmp); 60141a524abSAlex Deucher 60241a524abSAlex Deucher kv_smc_dpm_enable(rdev, true); 60341a524abSAlex Deucher } 60441a524abSAlex Deucher 60541a524abSAlex Deucher static void kv_stop_dpm(struct radeon_device *rdev) 60641a524abSAlex Deucher { 60741a524abSAlex Deucher kv_smc_dpm_enable(rdev, false); 60841a524abSAlex Deucher } 60941a524abSAlex Deucher 61041a524abSAlex Deucher static void kv_start_am(struct radeon_device *rdev) 61141a524abSAlex Deucher { 61241a524abSAlex Deucher u32 sclk_pwrmgt_cntl = RREG32_SMC(SCLK_PWRMGT_CNTL); 61341a524abSAlex Deucher 61441a524abSAlex Deucher sclk_pwrmgt_cntl &= ~(RESET_SCLK_CNT | RESET_BUSY_CNT); 61541a524abSAlex Deucher sclk_pwrmgt_cntl |= DYNAMIC_PM_EN; 61641a524abSAlex Deucher 61741a524abSAlex Deucher WREG32_SMC(SCLK_PWRMGT_CNTL, sclk_pwrmgt_cntl); 61841a524abSAlex Deucher } 61941a524abSAlex Deucher 62041a524abSAlex Deucher static void kv_reset_am(struct radeon_device *rdev) 62141a524abSAlex Deucher { 62241a524abSAlex Deucher u32 sclk_pwrmgt_cntl = RREG32_SMC(SCLK_PWRMGT_CNTL); 62341a524abSAlex Deucher 62441a524abSAlex Deucher sclk_pwrmgt_cntl |= (RESET_SCLK_CNT | RESET_BUSY_CNT); 62541a524abSAlex Deucher 62641a524abSAlex Deucher WREG32_SMC(SCLK_PWRMGT_CNTL, sclk_pwrmgt_cntl); 62741a524abSAlex Deucher } 62841a524abSAlex Deucher 62941a524abSAlex Deucher static int kv_freeze_sclk_dpm(struct radeon_device *rdev, bool freeze) 63041a524abSAlex Deucher { 63141a524abSAlex Deucher return kv_notify_message_to_smu(rdev, freeze ? 63241a524abSAlex Deucher PPSMC_MSG_SCLKDPM_FreezeLevel : PPSMC_MSG_SCLKDPM_UnfreezeLevel); 63341a524abSAlex Deucher } 63441a524abSAlex Deucher 63541a524abSAlex Deucher static int kv_force_lowest_valid(struct radeon_device *rdev) 63641a524abSAlex Deucher { 63741a524abSAlex Deucher return kv_force_dpm_lowest(rdev); 63841a524abSAlex Deucher } 63941a524abSAlex Deucher 64041a524abSAlex Deucher static int kv_unforce_levels(struct radeon_device *rdev) 64141a524abSAlex Deucher { 642136de91eSAlex Deucher if (rdev->family == CHIP_KABINI) 64341a524abSAlex Deucher return kv_notify_message_to_smu(rdev, PPSMC_MSG_NoForcedLevel); 644136de91eSAlex Deucher else 645136de91eSAlex Deucher return kv_set_enabled_levels(rdev); 64641a524abSAlex Deucher } 64741a524abSAlex Deucher 64841a524abSAlex Deucher static int kv_update_sclk_t(struct radeon_device *rdev) 64941a524abSAlex Deucher { 65041a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 65141a524abSAlex Deucher u32 low_sclk_interrupt_t = 0; 65241a524abSAlex Deucher int ret = 0; 65341a524abSAlex Deucher 65441a524abSAlex Deucher if (pi->caps_sclk_throttle_low_notification) { 65541a524abSAlex Deucher low_sclk_interrupt_t = cpu_to_be32(pi->low_sclk_interrupt_t); 65641a524abSAlex Deucher 65741a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 65841a524abSAlex Deucher pi->dpm_table_start + 65941a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, LowSclkInterruptT), 66041a524abSAlex Deucher (u8 *)&low_sclk_interrupt_t, 66141a524abSAlex Deucher sizeof(u32), pi->sram_end); 66241a524abSAlex Deucher } 66341a524abSAlex Deucher return ret; 66441a524abSAlex Deucher } 66541a524abSAlex Deucher 66641a524abSAlex Deucher static int kv_program_bootup_state(struct radeon_device *rdev) 66741a524abSAlex Deucher { 66841a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 66941a524abSAlex Deucher u32 i; 67041a524abSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 67141a524abSAlex Deucher &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; 67241a524abSAlex Deucher 67341a524abSAlex Deucher if (table && table->count) { 6748c5c6fadSDan Carpenter for (i = pi->graphics_dpm_level_count - 1; i > 0; i--) { 6758c5c6fadSDan Carpenter if (table->entries[i].clk == pi->boot_pl.sclk) 67641a524abSAlex Deucher break; 67741a524abSAlex Deucher } 67841a524abSAlex Deucher 67941a524abSAlex Deucher pi->graphics_boot_level = (u8)i; 68041a524abSAlex Deucher kv_dpm_power_level_enable(rdev, i, true); 68141a524abSAlex Deucher } else { 68241a524abSAlex Deucher struct sumo_sclk_voltage_mapping_table *table = 68341a524abSAlex Deucher &pi->sys_info.sclk_voltage_mapping_table; 68441a524abSAlex Deucher 68541a524abSAlex Deucher if (table->num_max_dpm_entries == 0) 68641a524abSAlex Deucher return -EINVAL; 68741a524abSAlex Deucher 6888c5c6fadSDan Carpenter for (i = pi->graphics_dpm_level_count - 1; i > 0; i--) { 6898c5c6fadSDan Carpenter if (table->entries[i].sclk_frequency == pi->boot_pl.sclk) 69041a524abSAlex Deucher break; 69141a524abSAlex Deucher } 69241a524abSAlex Deucher 69341a524abSAlex Deucher pi->graphics_boot_level = (u8)i; 69441a524abSAlex Deucher kv_dpm_power_level_enable(rdev, i, true); 69541a524abSAlex Deucher } 69641a524abSAlex Deucher return 0; 69741a524abSAlex Deucher } 69841a524abSAlex Deucher 69941a524abSAlex Deucher static int kv_enable_auto_thermal_throttling(struct radeon_device *rdev) 70041a524abSAlex Deucher { 70141a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 70241a524abSAlex Deucher int ret; 70341a524abSAlex Deucher 70441a524abSAlex Deucher pi->graphics_therm_throttle_enable = 1; 70541a524abSAlex Deucher 70641a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 70741a524abSAlex Deucher pi->dpm_table_start + 70841a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, GraphicsThermThrottleEnable), 70941a524abSAlex Deucher &pi->graphics_therm_throttle_enable, 71041a524abSAlex Deucher sizeof(u8), pi->sram_end); 71141a524abSAlex Deucher 71241a524abSAlex Deucher return ret; 71341a524abSAlex Deucher } 71441a524abSAlex Deucher 71541a524abSAlex Deucher static int kv_upload_dpm_settings(struct radeon_device *rdev) 71641a524abSAlex Deucher { 71741a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 71841a524abSAlex Deucher int ret; 71941a524abSAlex Deucher 72041a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 72141a524abSAlex Deucher pi->dpm_table_start + 72241a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, GraphicsLevel), 72341a524abSAlex Deucher (u8 *)&pi->graphics_level, 72441a524abSAlex Deucher sizeof(SMU7_Fusion_GraphicsLevel) * SMU7_MAX_LEVELS_GRAPHICS, 72541a524abSAlex Deucher pi->sram_end); 72641a524abSAlex Deucher 72741a524abSAlex Deucher if (ret) 72841a524abSAlex Deucher return ret; 72941a524abSAlex Deucher 73041a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 73141a524abSAlex Deucher pi->dpm_table_start + 73241a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, GraphicsDpmLevelCount), 73341a524abSAlex Deucher &pi->graphics_dpm_level_count, 73441a524abSAlex Deucher sizeof(u8), pi->sram_end); 73541a524abSAlex Deucher 73641a524abSAlex Deucher return ret; 73741a524abSAlex Deucher } 73841a524abSAlex Deucher 73941a524abSAlex Deucher static u32 kv_get_clock_difference(u32 a, u32 b) 74041a524abSAlex Deucher { 74141a524abSAlex Deucher return (a >= b) ? a - b : b - a; 74241a524abSAlex Deucher } 74341a524abSAlex Deucher 74441a524abSAlex Deucher static u32 kv_get_clk_bypass(struct radeon_device *rdev, u32 clk) 74541a524abSAlex Deucher { 74641a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 74741a524abSAlex Deucher u32 value; 74841a524abSAlex Deucher 74941a524abSAlex Deucher if (pi->caps_enable_dfs_bypass) { 75041a524abSAlex Deucher if (kv_get_clock_difference(clk, 40000) < 200) 75141a524abSAlex Deucher value = 3; 75241a524abSAlex Deucher else if (kv_get_clock_difference(clk, 30000) < 200) 75341a524abSAlex Deucher value = 2; 75441a524abSAlex Deucher else if (kv_get_clock_difference(clk, 20000) < 200) 75541a524abSAlex Deucher value = 7; 75641a524abSAlex Deucher else if (kv_get_clock_difference(clk, 15000) < 200) 75741a524abSAlex Deucher value = 6; 75841a524abSAlex Deucher else if (kv_get_clock_difference(clk, 10000) < 200) 75941a524abSAlex Deucher value = 8; 76041a524abSAlex Deucher else 76141a524abSAlex Deucher value = 0; 76241a524abSAlex Deucher } else { 76341a524abSAlex Deucher value = 0; 76441a524abSAlex Deucher } 76541a524abSAlex Deucher 76641a524abSAlex Deucher return value; 76741a524abSAlex Deucher } 76841a524abSAlex Deucher 76941a524abSAlex Deucher static int kv_populate_uvd_table(struct radeon_device *rdev) 77041a524abSAlex Deucher { 77141a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 77241a524abSAlex Deucher struct radeon_uvd_clock_voltage_dependency_table *table = 77341a524abSAlex Deucher &rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table; 77441a524abSAlex Deucher struct atom_clock_dividers dividers; 77541a524abSAlex Deucher int ret; 77641a524abSAlex Deucher u32 i; 77741a524abSAlex Deucher 77841a524abSAlex Deucher if (table == NULL || table->count == 0) 77941a524abSAlex Deucher return 0; 78041a524abSAlex Deucher 78141a524abSAlex Deucher pi->uvd_level_count = 0; 78241a524abSAlex Deucher for (i = 0; i < table->count; i++) { 78341a524abSAlex Deucher if (pi->high_voltage_t && 78441a524abSAlex Deucher (pi->high_voltage_t < table->entries[i].v)) 78541a524abSAlex Deucher break; 78641a524abSAlex Deucher 78741a524abSAlex Deucher pi->uvd_level[i].VclkFrequency = cpu_to_be32(table->entries[i].vclk); 78841a524abSAlex Deucher pi->uvd_level[i].DclkFrequency = cpu_to_be32(table->entries[i].dclk); 78941a524abSAlex Deucher pi->uvd_level[i].MinVddNb = cpu_to_be16(table->entries[i].v); 79041a524abSAlex Deucher 79141a524abSAlex Deucher pi->uvd_level[i].VClkBypassCntl = 79241a524abSAlex Deucher (u8)kv_get_clk_bypass(rdev, table->entries[i].vclk); 79341a524abSAlex Deucher pi->uvd_level[i].DClkBypassCntl = 79441a524abSAlex Deucher (u8)kv_get_clk_bypass(rdev, table->entries[i].dclk); 79541a524abSAlex Deucher 79641a524abSAlex Deucher ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, 79741a524abSAlex Deucher table->entries[i].vclk, false, ÷rs); 79841a524abSAlex Deucher if (ret) 79941a524abSAlex Deucher return ret; 80041a524abSAlex Deucher pi->uvd_level[i].VclkDivider = (u8)dividers.post_div; 80141a524abSAlex Deucher 80241a524abSAlex Deucher ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, 80341a524abSAlex Deucher table->entries[i].dclk, false, ÷rs); 80441a524abSAlex Deucher if (ret) 80541a524abSAlex Deucher return ret; 80641a524abSAlex Deucher pi->uvd_level[i].DclkDivider = (u8)dividers.post_div; 80741a524abSAlex Deucher 80841a524abSAlex Deucher pi->uvd_level_count++; 80941a524abSAlex Deucher } 81041a524abSAlex Deucher 81141a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 81241a524abSAlex Deucher pi->dpm_table_start + 81341a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, UvdLevelCount), 81441a524abSAlex Deucher (u8 *)&pi->uvd_level_count, 81541a524abSAlex Deucher sizeof(u8), pi->sram_end); 81641a524abSAlex Deucher if (ret) 81741a524abSAlex Deucher return ret; 81841a524abSAlex Deucher 81941a524abSAlex Deucher pi->uvd_interval = 1; 82041a524abSAlex Deucher 82141a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 82241a524abSAlex Deucher pi->dpm_table_start + 82341a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, UVDInterval), 82441a524abSAlex Deucher &pi->uvd_interval, 82541a524abSAlex Deucher sizeof(u8), pi->sram_end); 82641a524abSAlex Deucher if (ret) 82741a524abSAlex Deucher return ret; 82841a524abSAlex Deucher 82941a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 83041a524abSAlex Deucher pi->dpm_table_start + 83141a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, UvdLevel), 83241a524abSAlex Deucher (u8 *)&pi->uvd_level, 83341a524abSAlex Deucher sizeof(SMU7_Fusion_UvdLevel) * SMU7_MAX_LEVELS_UVD, 83441a524abSAlex Deucher pi->sram_end); 83541a524abSAlex Deucher 83641a524abSAlex Deucher return ret; 83741a524abSAlex Deucher 83841a524abSAlex Deucher } 83941a524abSAlex Deucher 84041a524abSAlex Deucher static int kv_populate_vce_table(struct radeon_device *rdev) 84141a524abSAlex Deucher { 84241a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 84341a524abSAlex Deucher int ret; 84441a524abSAlex Deucher u32 i; 84541a524abSAlex Deucher struct radeon_vce_clock_voltage_dependency_table *table = 84641a524abSAlex Deucher &rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table; 84741a524abSAlex Deucher struct atom_clock_dividers dividers; 84841a524abSAlex Deucher 84941a524abSAlex Deucher if (table == NULL || table->count == 0) 85041a524abSAlex Deucher return 0; 85141a524abSAlex Deucher 85241a524abSAlex Deucher pi->vce_level_count = 0; 85341a524abSAlex Deucher for (i = 0; i < table->count; i++) { 85441a524abSAlex Deucher if (pi->high_voltage_t && 85541a524abSAlex Deucher pi->high_voltage_t < table->entries[i].v) 85641a524abSAlex Deucher break; 85741a524abSAlex Deucher 85841a524abSAlex Deucher pi->vce_level[i].Frequency = cpu_to_be32(table->entries[i].evclk); 85941a524abSAlex Deucher pi->vce_level[i].MinVoltage = cpu_to_be16(table->entries[i].v); 86041a524abSAlex Deucher 86141a524abSAlex Deucher pi->vce_level[i].ClkBypassCntl = 86241a524abSAlex Deucher (u8)kv_get_clk_bypass(rdev, table->entries[i].evclk); 86341a524abSAlex Deucher 86441a524abSAlex Deucher ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, 86541a524abSAlex Deucher table->entries[i].evclk, false, ÷rs); 86641a524abSAlex Deucher if (ret) 86741a524abSAlex Deucher return ret; 86841a524abSAlex Deucher pi->vce_level[i].Divider = (u8)dividers.post_div; 86941a524abSAlex Deucher 87041a524abSAlex Deucher pi->vce_level_count++; 87141a524abSAlex Deucher } 87241a524abSAlex Deucher 87341a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 87441a524abSAlex Deucher pi->dpm_table_start + 87541a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, VceLevelCount), 87641a524abSAlex Deucher (u8 *)&pi->vce_level_count, 87741a524abSAlex Deucher sizeof(u8), 87841a524abSAlex Deucher pi->sram_end); 87941a524abSAlex Deucher if (ret) 88041a524abSAlex Deucher return ret; 88141a524abSAlex Deucher 88241a524abSAlex Deucher pi->vce_interval = 1; 88341a524abSAlex Deucher 88441a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 88541a524abSAlex Deucher pi->dpm_table_start + 88641a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, VCEInterval), 88741a524abSAlex Deucher (u8 *)&pi->vce_interval, 88841a524abSAlex Deucher sizeof(u8), 88941a524abSAlex Deucher pi->sram_end); 89041a524abSAlex Deucher if (ret) 89141a524abSAlex Deucher return ret; 89241a524abSAlex Deucher 89341a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 89441a524abSAlex Deucher pi->dpm_table_start + 89541a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, VceLevel), 89641a524abSAlex Deucher (u8 *)&pi->vce_level, 89741a524abSAlex Deucher sizeof(SMU7_Fusion_ExtClkLevel) * SMU7_MAX_LEVELS_VCE, 89841a524abSAlex Deucher pi->sram_end); 89941a524abSAlex Deucher 90041a524abSAlex Deucher return ret; 90141a524abSAlex Deucher } 90241a524abSAlex Deucher 90341a524abSAlex Deucher static int kv_populate_samu_table(struct radeon_device *rdev) 90441a524abSAlex Deucher { 90541a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 90641a524abSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 90741a524abSAlex Deucher &rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table; 90841a524abSAlex Deucher struct atom_clock_dividers dividers; 90941a524abSAlex Deucher int ret; 91041a524abSAlex Deucher u32 i; 91141a524abSAlex Deucher 91241a524abSAlex Deucher if (table == NULL || table->count == 0) 91341a524abSAlex Deucher return 0; 91441a524abSAlex Deucher 91541a524abSAlex Deucher pi->samu_level_count = 0; 91641a524abSAlex Deucher for (i = 0; i < table->count; i++) { 91741a524abSAlex Deucher if (pi->high_voltage_t && 91841a524abSAlex Deucher pi->high_voltage_t < table->entries[i].v) 91941a524abSAlex Deucher break; 92041a524abSAlex Deucher 92141a524abSAlex Deucher pi->samu_level[i].Frequency = cpu_to_be32(table->entries[i].clk); 92241a524abSAlex Deucher pi->samu_level[i].MinVoltage = cpu_to_be16(table->entries[i].v); 92341a524abSAlex Deucher 92441a524abSAlex Deucher pi->samu_level[i].ClkBypassCntl = 92541a524abSAlex Deucher (u8)kv_get_clk_bypass(rdev, table->entries[i].clk); 92641a524abSAlex Deucher 92741a524abSAlex Deucher ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, 92841a524abSAlex Deucher table->entries[i].clk, false, ÷rs); 92941a524abSAlex Deucher if (ret) 93041a524abSAlex Deucher return ret; 93141a524abSAlex Deucher pi->samu_level[i].Divider = (u8)dividers.post_div; 93241a524abSAlex Deucher 93341a524abSAlex Deucher pi->samu_level_count++; 93441a524abSAlex Deucher } 93541a524abSAlex Deucher 93641a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 93741a524abSAlex Deucher pi->dpm_table_start + 93841a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, SamuLevelCount), 93941a524abSAlex Deucher (u8 *)&pi->samu_level_count, 94041a524abSAlex Deucher sizeof(u8), 94141a524abSAlex Deucher pi->sram_end); 94241a524abSAlex Deucher if (ret) 94341a524abSAlex Deucher return ret; 94441a524abSAlex Deucher 94541a524abSAlex Deucher pi->samu_interval = 1; 94641a524abSAlex Deucher 94741a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 94841a524abSAlex Deucher pi->dpm_table_start + 94941a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, SAMUInterval), 95041a524abSAlex Deucher (u8 *)&pi->samu_interval, 95141a524abSAlex Deucher sizeof(u8), 95241a524abSAlex Deucher pi->sram_end); 95341a524abSAlex Deucher if (ret) 95441a524abSAlex Deucher return ret; 95541a524abSAlex Deucher 95641a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 95741a524abSAlex Deucher pi->dpm_table_start + 95841a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, SamuLevel), 95941a524abSAlex Deucher (u8 *)&pi->samu_level, 96041a524abSAlex Deucher sizeof(SMU7_Fusion_ExtClkLevel) * SMU7_MAX_LEVELS_SAMU, 96141a524abSAlex Deucher pi->sram_end); 96241a524abSAlex Deucher if (ret) 96341a524abSAlex Deucher return ret; 96441a524abSAlex Deucher 96541a524abSAlex Deucher return ret; 96641a524abSAlex Deucher } 96741a524abSAlex Deucher 96841a524abSAlex Deucher 96941a524abSAlex Deucher static int kv_populate_acp_table(struct radeon_device *rdev) 97041a524abSAlex Deucher { 97141a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 97241a524abSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 97341a524abSAlex Deucher &rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table; 97441a524abSAlex Deucher struct atom_clock_dividers dividers; 97541a524abSAlex Deucher int ret; 97641a524abSAlex Deucher u32 i; 97741a524abSAlex Deucher 97841a524abSAlex Deucher if (table == NULL || table->count == 0) 97941a524abSAlex Deucher return 0; 98041a524abSAlex Deucher 98141a524abSAlex Deucher pi->acp_level_count = 0; 98241a524abSAlex Deucher for (i = 0; i < table->count; i++) { 98341a524abSAlex Deucher pi->acp_level[i].Frequency = cpu_to_be32(table->entries[i].clk); 98441a524abSAlex Deucher pi->acp_level[i].MinVoltage = cpu_to_be16(table->entries[i].v); 98541a524abSAlex Deucher 98641a524abSAlex Deucher ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, 98741a524abSAlex Deucher table->entries[i].clk, false, ÷rs); 98841a524abSAlex Deucher if (ret) 98941a524abSAlex Deucher return ret; 99041a524abSAlex Deucher pi->acp_level[i].Divider = (u8)dividers.post_div; 99141a524abSAlex Deucher 99241a524abSAlex Deucher pi->acp_level_count++; 99341a524abSAlex Deucher } 99441a524abSAlex Deucher 99541a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 99641a524abSAlex Deucher pi->dpm_table_start + 99741a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, AcpLevelCount), 99841a524abSAlex Deucher (u8 *)&pi->acp_level_count, 99941a524abSAlex Deucher sizeof(u8), 100041a524abSAlex Deucher pi->sram_end); 100141a524abSAlex Deucher if (ret) 100241a524abSAlex Deucher return ret; 100341a524abSAlex Deucher 100441a524abSAlex Deucher pi->acp_interval = 1; 100541a524abSAlex Deucher 100641a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 100741a524abSAlex Deucher pi->dpm_table_start + 100841a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, ACPInterval), 100941a524abSAlex Deucher (u8 *)&pi->acp_interval, 101041a524abSAlex Deucher sizeof(u8), 101141a524abSAlex Deucher pi->sram_end); 101241a524abSAlex Deucher if (ret) 101341a524abSAlex Deucher return ret; 101441a524abSAlex Deucher 101541a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 101641a524abSAlex Deucher pi->dpm_table_start + 101741a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, AcpLevel), 101841a524abSAlex Deucher (u8 *)&pi->acp_level, 101941a524abSAlex Deucher sizeof(SMU7_Fusion_ExtClkLevel) * SMU7_MAX_LEVELS_ACP, 102041a524abSAlex Deucher pi->sram_end); 102141a524abSAlex Deucher if (ret) 102241a524abSAlex Deucher return ret; 102341a524abSAlex Deucher 102441a524abSAlex Deucher return ret; 102541a524abSAlex Deucher } 102641a524abSAlex Deucher 102741a524abSAlex Deucher static void kv_calculate_dfs_bypass_settings(struct radeon_device *rdev) 102841a524abSAlex Deucher { 102941a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 103041a524abSAlex Deucher u32 i; 103141a524abSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 103241a524abSAlex Deucher &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; 103341a524abSAlex Deucher 103441a524abSAlex Deucher if (table && table->count) { 103541a524abSAlex Deucher for (i = 0; i < pi->graphics_dpm_level_count; i++) { 103641a524abSAlex Deucher if (pi->caps_enable_dfs_bypass) { 103741a524abSAlex Deucher if (kv_get_clock_difference(table->entries[i].clk, 40000) < 200) 103841a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 3; 103941a524abSAlex Deucher else if (kv_get_clock_difference(table->entries[i].clk, 30000) < 200) 104041a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 2; 104141a524abSAlex Deucher else if (kv_get_clock_difference(table->entries[i].clk, 26600) < 200) 104241a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 7; 104341a524abSAlex Deucher else if (kv_get_clock_difference(table->entries[i].clk , 20000) < 200) 104441a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 6; 104541a524abSAlex Deucher else if (kv_get_clock_difference(table->entries[i].clk , 10000) < 200) 104641a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 8; 104741a524abSAlex Deucher else 104841a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 0; 104941a524abSAlex Deucher } else { 105041a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 0; 105141a524abSAlex Deucher } 105241a524abSAlex Deucher } 105341a524abSAlex Deucher } else { 105441a524abSAlex Deucher struct sumo_sclk_voltage_mapping_table *table = 105541a524abSAlex Deucher &pi->sys_info.sclk_voltage_mapping_table; 105641a524abSAlex Deucher for (i = 0; i < pi->graphics_dpm_level_count; i++) { 105741a524abSAlex Deucher if (pi->caps_enable_dfs_bypass) { 105841a524abSAlex Deucher if (kv_get_clock_difference(table->entries[i].sclk_frequency, 40000) < 200) 105941a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 3; 106041a524abSAlex Deucher else if (kv_get_clock_difference(table->entries[i].sclk_frequency, 30000) < 200) 106141a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 2; 106241a524abSAlex Deucher else if (kv_get_clock_difference(table->entries[i].sclk_frequency, 26600) < 200) 106341a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 7; 106441a524abSAlex Deucher else if (kv_get_clock_difference(table->entries[i].sclk_frequency, 20000) < 200) 106541a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 6; 106641a524abSAlex Deucher else if (kv_get_clock_difference(table->entries[i].sclk_frequency, 10000) < 200) 106741a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 8; 106841a524abSAlex Deucher else 106941a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 0; 107041a524abSAlex Deucher } else { 107141a524abSAlex Deucher pi->graphics_level[i].ClkBypassCntl = 0; 107241a524abSAlex Deucher } 107341a524abSAlex Deucher } 107441a524abSAlex Deucher } 107541a524abSAlex Deucher } 107641a524abSAlex Deucher 107741a524abSAlex Deucher static int kv_enable_ulv(struct radeon_device *rdev, bool enable) 107841a524abSAlex Deucher { 107941a524abSAlex Deucher return kv_notify_message_to_smu(rdev, enable ? 108041a524abSAlex Deucher PPSMC_MSG_EnableULV : PPSMC_MSG_DisableULV); 108141a524abSAlex Deucher } 108241a524abSAlex Deucher 1083136de91eSAlex Deucher static void kv_reset_acp_boot_level(struct radeon_device *rdev) 1084136de91eSAlex Deucher { 1085136de91eSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 1086136de91eSAlex Deucher 1087136de91eSAlex Deucher pi->acp_boot_level = 0xff; 1088136de91eSAlex Deucher } 1089136de91eSAlex Deucher 109041a524abSAlex Deucher static void kv_update_current_ps(struct radeon_device *rdev, 109141a524abSAlex Deucher struct radeon_ps *rps) 109241a524abSAlex Deucher { 109341a524abSAlex Deucher struct kv_ps *new_ps = kv_get_ps(rps); 109441a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 109541a524abSAlex Deucher 109641a524abSAlex Deucher pi->current_rps = *rps; 109741a524abSAlex Deucher pi->current_ps = *new_ps; 109841a524abSAlex Deucher pi->current_rps.ps_priv = &pi->current_ps; 109941a524abSAlex Deucher } 110041a524abSAlex Deucher 110141a524abSAlex Deucher static void kv_update_requested_ps(struct radeon_device *rdev, 110241a524abSAlex Deucher struct radeon_ps *rps) 110341a524abSAlex Deucher { 110441a524abSAlex Deucher struct kv_ps *new_ps = kv_get_ps(rps); 110541a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 110641a524abSAlex Deucher 110741a524abSAlex Deucher pi->requested_rps = *rps; 110841a524abSAlex Deucher pi->requested_ps = *new_ps; 110941a524abSAlex Deucher pi->requested_rps.ps_priv = &pi->requested_ps; 111041a524abSAlex Deucher } 111141a524abSAlex Deucher 111241a524abSAlex Deucher int kv_dpm_enable(struct radeon_device *rdev) 111341a524abSAlex Deucher { 111441a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 111541a524abSAlex Deucher int ret; 111641a524abSAlex Deucher 11176500fc0cSAlex Deucher cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX | 11186500fc0cSAlex Deucher RADEON_CG_BLOCK_SDMA | 11196500fc0cSAlex Deucher RADEON_CG_BLOCK_BIF | 11206500fc0cSAlex Deucher RADEON_CG_BLOCK_HDP), false); 11216500fc0cSAlex Deucher 112241a524abSAlex Deucher ret = kv_process_firmware_header(rdev); 112341a524abSAlex Deucher if (ret) { 112441a524abSAlex Deucher DRM_ERROR("kv_process_firmware_header failed\n"); 112541a524abSAlex Deucher return ret; 112641a524abSAlex Deucher } 112741a524abSAlex Deucher kv_init_fps_limits(rdev); 112841a524abSAlex Deucher kv_init_graphics_levels(rdev); 112941a524abSAlex Deucher ret = kv_program_bootup_state(rdev); 113041a524abSAlex Deucher if (ret) { 113141a524abSAlex Deucher DRM_ERROR("kv_program_bootup_state failed\n"); 113241a524abSAlex Deucher return ret; 113341a524abSAlex Deucher } 113441a524abSAlex Deucher kv_calculate_dfs_bypass_settings(rdev); 113541a524abSAlex Deucher ret = kv_upload_dpm_settings(rdev); 113641a524abSAlex Deucher if (ret) { 113741a524abSAlex Deucher DRM_ERROR("kv_upload_dpm_settings failed\n"); 113841a524abSAlex Deucher return ret; 113941a524abSAlex Deucher } 114041a524abSAlex Deucher ret = kv_populate_uvd_table(rdev); 114141a524abSAlex Deucher if (ret) { 114241a524abSAlex Deucher DRM_ERROR("kv_populate_uvd_table failed\n"); 114341a524abSAlex Deucher return ret; 114441a524abSAlex Deucher } 114541a524abSAlex Deucher ret = kv_populate_vce_table(rdev); 114641a524abSAlex Deucher if (ret) { 114741a524abSAlex Deucher DRM_ERROR("kv_populate_vce_table failed\n"); 114841a524abSAlex Deucher return ret; 114941a524abSAlex Deucher } 115041a524abSAlex Deucher ret = kv_populate_samu_table(rdev); 115141a524abSAlex Deucher if (ret) { 115241a524abSAlex Deucher DRM_ERROR("kv_populate_samu_table failed\n"); 115341a524abSAlex Deucher return ret; 115441a524abSAlex Deucher } 115541a524abSAlex Deucher ret = kv_populate_acp_table(rdev); 115641a524abSAlex Deucher if (ret) { 115741a524abSAlex Deucher DRM_ERROR("kv_populate_acp_table failed\n"); 115841a524abSAlex Deucher return ret; 115941a524abSAlex Deucher } 116041a524abSAlex Deucher kv_program_vc(rdev); 116141a524abSAlex Deucher #if 0 116241a524abSAlex Deucher kv_initialize_hardware_cac_manager(rdev); 116341a524abSAlex Deucher #endif 116441a524abSAlex Deucher kv_start_am(rdev); 116541a524abSAlex Deucher if (pi->enable_auto_thermal_throttling) { 116641a524abSAlex Deucher ret = kv_enable_auto_thermal_throttling(rdev); 116741a524abSAlex Deucher if (ret) { 116841a524abSAlex Deucher DRM_ERROR("kv_enable_auto_thermal_throttling failed\n"); 116941a524abSAlex Deucher return ret; 117041a524abSAlex Deucher } 117141a524abSAlex Deucher } 117241a524abSAlex Deucher ret = kv_enable_dpm_voltage_scaling(rdev); 117341a524abSAlex Deucher if (ret) { 117441a524abSAlex Deucher DRM_ERROR("kv_enable_dpm_voltage_scaling failed\n"); 117541a524abSAlex Deucher return ret; 117641a524abSAlex Deucher } 117741a524abSAlex Deucher ret = kv_set_dpm_interval(rdev); 117841a524abSAlex Deucher if (ret) { 117941a524abSAlex Deucher DRM_ERROR("kv_set_dpm_interval failed\n"); 118041a524abSAlex Deucher return ret; 118141a524abSAlex Deucher } 118241a524abSAlex Deucher ret = kv_set_dpm_boot_state(rdev); 118341a524abSAlex Deucher if (ret) { 118441a524abSAlex Deucher DRM_ERROR("kv_set_dpm_boot_state failed\n"); 118541a524abSAlex Deucher return ret; 118641a524abSAlex Deucher } 118741a524abSAlex Deucher ret = kv_enable_ulv(rdev, true); 118841a524abSAlex Deucher if (ret) { 118941a524abSAlex Deucher DRM_ERROR("kv_enable_ulv failed\n"); 119041a524abSAlex Deucher return ret; 119141a524abSAlex Deucher } 119241a524abSAlex Deucher kv_start_dpm(rdev); 119341a524abSAlex Deucher ret = kv_enable_didt(rdev, true); 119441a524abSAlex Deucher if (ret) { 119541a524abSAlex Deucher DRM_ERROR("kv_enable_didt failed\n"); 119641a524abSAlex Deucher return ret; 119741a524abSAlex Deucher } 119841a524abSAlex Deucher ret = kv_enable_smc_cac(rdev, true); 119941a524abSAlex Deucher if (ret) { 120041a524abSAlex Deucher DRM_ERROR("kv_enable_smc_cac failed\n"); 120141a524abSAlex Deucher return ret; 120241a524abSAlex Deucher } 120341a524abSAlex Deucher 1204136de91eSAlex Deucher kv_reset_acp_boot_level(rdev); 1205136de91eSAlex Deucher 120641a524abSAlex Deucher if (rdev->irq.installed && 120741a524abSAlex Deucher r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { 120841a524abSAlex Deucher ret = kv_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); 120941a524abSAlex Deucher if (ret) { 121041a524abSAlex Deucher DRM_ERROR("kv_set_thermal_temperature_range failed\n"); 121141a524abSAlex Deucher return ret; 121241a524abSAlex Deucher } 121341a524abSAlex Deucher rdev->irq.dpm_thermal = true; 121441a524abSAlex Deucher radeon_irq_set(rdev); 121541a524abSAlex Deucher } 121641a524abSAlex Deucher 121764d03221SAlex Deucher ret = kv_smc_bapm_enable(rdev, false); 121864d03221SAlex Deucher if (ret) { 121964d03221SAlex Deucher DRM_ERROR("kv_smc_bapm_enable failed\n"); 122064d03221SAlex Deucher return ret; 122164d03221SAlex Deucher } 122264d03221SAlex Deucher 122341a524abSAlex Deucher /* powerdown unused blocks for now */ 122441a524abSAlex Deucher kv_dpm_powergate_acp(rdev, true); 122541a524abSAlex Deucher kv_dpm_powergate_samu(rdev, true); 122641a524abSAlex Deucher kv_dpm_powergate_vce(rdev, true); 122777df508aSAlex Deucher kv_dpm_powergate_uvd(rdev, true); 122841a524abSAlex Deucher 12296500fc0cSAlex Deucher cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX | 12306500fc0cSAlex Deucher RADEON_CG_BLOCK_SDMA | 12316500fc0cSAlex Deucher RADEON_CG_BLOCK_BIF | 12326500fc0cSAlex Deucher RADEON_CG_BLOCK_HDP), true); 12336500fc0cSAlex Deucher 123441a524abSAlex Deucher kv_update_current_ps(rdev, rdev->pm.dpm.boot_ps); 123541a524abSAlex Deucher 123641a524abSAlex Deucher return ret; 123741a524abSAlex Deucher } 123841a524abSAlex Deucher 123941a524abSAlex Deucher void kv_dpm_disable(struct radeon_device *rdev) 124041a524abSAlex Deucher { 12416500fc0cSAlex Deucher cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX | 12426500fc0cSAlex Deucher RADEON_CG_BLOCK_SDMA | 12436500fc0cSAlex Deucher RADEON_CG_BLOCK_BIF | 12446500fc0cSAlex Deucher RADEON_CG_BLOCK_HDP), false); 12456500fc0cSAlex Deucher 124664d03221SAlex Deucher kv_smc_bapm_enable(rdev, false); 124764d03221SAlex Deucher 124839c88ae3SAlex Deucher /* powerup blocks */ 124939c88ae3SAlex Deucher kv_dpm_powergate_acp(rdev, false); 125039c88ae3SAlex Deucher kv_dpm_powergate_samu(rdev, false); 125139c88ae3SAlex Deucher kv_dpm_powergate_vce(rdev, false); 125239c88ae3SAlex Deucher kv_dpm_powergate_uvd(rdev, false); 125339c88ae3SAlex Deucher 125441a524abSAlex Deucher kv_enable_smc_cac(rdev, false); 125541a524abSAlex Deucher kv_enable_didt(rdev, false); 125641a524abSAlex Deucher kv_clear_vc(rdev); 125741a524abSAlex Deucher kv_stop_dpm(rdev); 125841a524abSAlex Deucher kv_enable_ulv(rdev, false); 125941a524abSAlex Deucher kv_reset_am(rdev); 126041a524abSAlex Deucher 126141a524abSAlex Deucher kv_update_current_ps(rdev, rdev->pm.dpm.boot_ps); 126241a524abSAlex Deucher } 126341a524abSAlex Deucher 126441a524abSAlex Deucher #if 0 126541a524abSAlex Deucher static int kv_write_smc_soft_register(struct radeon_device *rdev, 126641a524abSAlex Deucher u16 reg_offset, u32 value) 126741a524abSAlex Deucher { 126841a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 126941a524abSAlex Deucher 127041a524abSAlex Deucher return kv_copy_bytes_to_smc(rdev, pi->soft_regs_start + reg_offset, 127141a524abSAlex Deucher (u8 *)&value, sizeof(u16), pi->sram_end); 127241a524abSAlex Deucher } 127341a524abSAlex Deucher 127441a524abSAlex Deucher static int kv_read_smc_soft_register(struct radeon_device *rdev, 127541a524abSAlex Deucher u16 reg_offset, u32 *value) 127641a524abSAlex Deucher { 127741a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 127841a524abSAlex Deucher 127941a524abSAlex Deucher return kv_read_smc_sram_dword(rdev, pi->soft_regs_start + reg_offset, 128041a524abSAlex Deucher value, pi->sram_end); 128141a524abSAlex Deucher } 128241a524abSAlex Deucher #endif 128341a524abSAlex Deucher 128441a524abSAlex Deucher static void kv_init_sclk_t(struct radeon_device *rdev) 128541a524abSAlex Deucher { 128641a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 128741a524abSAlex Deucher 128841a524abSAlex Deucher pi->low_sclk_interrupt_t = 0; 128941a524abSAlex Deucher } 129041a524abSAlex Deucher 129141a524abSAlex Deucher static int kv_init_fps_limits(struct radeon_device *rdev) 129241a524abSAlex Deucher { 129341a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 129441a524abSAlex Deucher int ret = 0; 129541a524abSAlex Deucher 129641a524abSAlex Deucher if (pi->caps_fps) { 129741a524abSAlex Deucher u16 tmp; 129841a524abSAlex Deucher 129941a524abSAlex Deucher tmp = 45; 130041a524abSAlex Deucher pi->fps_high_t = cpu_to_be16(tmp); 130141a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 130241a524abSAlex Deucher pi->dpm_table_start + 130341a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, FpsHighT), 130441a524abSAlex Deucher (u8 *)&pi->fps_high_t, 130541a524abSAlex Deucher sizeof(u16), pi->sram_end); 130641a524abSAlex Deucher 130741a524abSAlex Deucher tmp = 30; 130841a524abSAlex Deucher pi->fps_low_t = cpu_to_be16(tmp); 130941a524abSAlex Deucher 131041a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 131141a524abSAlex Deucher pi->dpm_table_start + 131241a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, FpsLowT), 131341a524abSAlex Deucher (u8 *)&pi->fps_low_t, 131441a524abSAlex Deucher sizeof(u16), pi->sram_end); 131541a524abSAlex Deucher 131641a524abSAlex Deucher } 131741a524abSAlex Deucher return ret; 131841a524abSAlex Deucher } 131941a524abSAlex Deucher 132041a524abSAlex Deucher static void kv_init_powergate_state(struct radeon_device *rdev) 132141a524abSAlex Deucher { 132241a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 132341a524abSAlex Deucher 132441a524abSAlex Deucher pi->uvd_power_gated = false; 132541a524abSAlex Deucher pi->vce_power_gated = false; 132641a524abSAlex Deucher pi->samu_power_gated = false; 132741a524abSAlex Deucher pi->acp_power_gated = false; 132841a524abSAlex Deucher 132941a524abSAlex Deucher } 133041a524abSAlex Deucher 133141a524abSAlex Deucher static int kv_enable_uvd_dpm(struct radeon_device *rdev, bool enable) 133241a524abSAlex Deucher { 133341a524abSAlex Deucher return kv_notify_message_to_smu(rdev, enable ? 133441a524abSAlex Deucher PPSMC_MSG_UVDDPM_Enable : PPSMC_MSG_UVDDPM_Disable); 133541a524abSAlex Deucher } 133641a524abSAlex Deucher 133741a524abSAlex Deucher #if 0 133841a524abSAlex Deucher static int kv_enable_vce_dpm(struct radeon_device *rdev, bool enable) 133941a524abSAlex Deucher { 134041a524abSAlex Deucher return kv_notify_message_to_smu(rdev, enable ? 134141a524abSAlex Deucher PPSMC_MSG_VCEDPM_Enable : PPSMC_MSG_VCEDPM_Disable); 134241a524abSAlex Deucher } 134341a524abSAlex Deucher #endif 134441a524abSAlex Deucher 134541a524abSAlex Deucher static int kv_enable_samu_dpm(struct radeon_device *rdev, bool enable) 134641a524abSAlex Deucher { 134741a524abSAlex Deucher return kv_notify_message_to_smu(rdev, enable ? 134841a524abSAlex Deucher PPSMC_MSG_SAMUDPM_Enable : PPSMC_MSG_SAMUDPM_Disable); 134941a524abSAlex Deucher } 135041a524abSAlex Deucher 135141a524abSAlex Deucher static int kv_enable_acp_dpm(struct radeon_device *rdev, bool enable) 135241a524abSAlex Deucher { 135341a524abSAlex Deucher return kv_notify_message_to_smu(rdev, enable ? 135441a524abSAlex Deucher PPSMC_MSG_ACPDPM_Enable : PPSMC_MSG_ACPDPM_Disable); 135541a524abSAlex Deucher } 135641a524abSAlex Deucher 135741a524abSAlex Deucher static int kv_update_uvd_dpm(struct radeon_device *rdev, bool gate) 135841a524abSAlex Deucher { 135941a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 136041a524abSAlex Deucher struct radeon_uvd_clock_voltage_dependency_table *table = 136141a524abSAlex Deucher &rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table; 136241a524abSAlex Deucher int ret; 136341a524abSAlex Deucher 136441a524abSAlex Deucher if (!gate) { 136541a524abSAlex Deucher if (!pi->caps_uvd_dpm || table->count || pi->caps_stable_p_state) 136641a524abSAlex Deucher pi->uvd_boot_level = table->count - 1; 136741a524abSAlex Deucher else 136841a524abSAlex Deucher pi->uvd_boot_level = 0; 136941a524abSAlex Deucher 137041a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 137141a524abSAlex Deucher pi->dpm_table_start + 137241a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, UvdBootLevel), 137341a524abSAlex Deucher (uint8_t *)&pi->uvd_boot_level, 137441a524abSAlex Deucher sizeof(u8), pi->sram_end); 137541a524abSAlex Deucher if (ret) 137641a524abSAlex Deucher return ret; 137741a524abSAlex Deucher 137841a524abSAlex Deucher if (!pi->caps_uvd_dpm || 137941a524abSAlex Deucher pi->caps_stable_p_state) 138041a524abSAlex Deucher kv_send_msg_to_smc_with_parameter(rdev, 138141a524abSAlex Deucher PPSMC_MSG_UVDDPM_SetEnabledMask, 138241a524abSAlex Deucher (1 << pi->uvd_boot_level)); 138341a524abSAlex Deucher } 138441a524abSAlex Deucher 138541a524abSAlex Deucher return kv_enable_uvd_dpm(rdev, !gate); 138641a524abSAlex Deucher } 138741a524abSAlex Deucher 138841a524abSAlex Deucher #if 0 138941a524abSAlex Deucher static u8 kv_get_vce_boot_level(struct radeon_device *rdev) 139041a524abSAlex Deucher { 139141a524abSAlex Deucher u8 i; 139241a524abSAlex Deucher struct radeon_vce_clock_voltage_dependency_table *table = 139341a524abSAlex Deucher &rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table; 139441a524abSAlex Deucher 139541a524abSAlex Deucher for (i = 0; i < table->count; i++) { 139641a524abSAlex Deucher if (table->entries[i].evclk >= 0) /* XXX */ 139741a524abSAlex Deucher break; 139841a524abSAlex Deucher } 139941a524abSAlex Deucher 140041a524abSAlex Deucher return i; 140141a524abSAlex Deucher } 140241a524abSAlex Deucher 140341a524abSAlex Deucher static int kv_update_vce_dpm(struct radeon_device *rdev, 140441a524abSAlex Deucher struct radeon_ps *radeon_new_state, 140541a524abSAlex Deucher struct radeon_ps *radeon_current_state) 140641a524abSAlex Deucher { 140741a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 140841a524abSAlex Deucher struct radeon_vce_clock_voltage_dependency_table *table = 140941a524abSAlex Deucher &rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table; 141041a524abSAlex Deucher int ret; 141141a524abSAlex Deucher 141241a524abSAlex Deucher if (radeon_new_state->evclk > 0 && radeon_current_state->evclk == 0) { 141341a524abSAlex Deucher if (pi->caps_stable_p_state) 141441a524abSAlex Deucher pi->vce_boot_level = table->count - 1; 141541a524abSAlex Deucher else 141641a524abSAlex Deucher pi->vce_boot_level = kv_get_vce_boot_level(rdev); 141741a524abSAlex Deucher 141841a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 141941a524abSAlex Deucher pi->dpm_table_start + 142041a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, VceBootLevel), 142141a524abSAlex Deucher (u8 *)&pi->vce_boot_level, 142241a524abSAlex Deucher sizeof(u8), 142341a524abSAlex Deucher pi->sram_end); 142441a524abSAlex Deucher if (ret) 142541a524abSAlex Deucher return ret; 142641a524abSAlex Deucher 142741a524abSAlex Deucher if (pi->caps_stable_p_state) 142841a524abSAlex Deucher kv_send_msg_to_smc_with_parameter(rdev, 142941a524abSAlex Deucher PPSMC_MSG_VCEDPM_SetEnabledMask, 143041a524abSAlex Deucher (1 << pi->vce_boot_level)); 143141a524abSAlex Deucher 143241a524abSAlex Deucher kv_enable_vce_dpm(rdev, true); 143341a524abSAlex Deucher } else if (radeon_new_state->evclk == 0 && radeon_current_state->evclk > 0) { 143441a524abSAlex Deucher kv_enable_vce_dpm(rdev, false); 143541a524abSAlex Deucher } 143641a524abSAlex Deucher 143741a524abSAlex Deucher return 0; 143841a524abSAlex Deucher } 143941a524abSAlex Deucher #endif 144041a524abSAlex Deucher 144141a524abSAlex Deucher static int kv_update_samu_dpm(struct radeon_device *rdev, bool gate) 144241a524abSAlex Deucher { 144341a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 144441a524abSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 144541a524abSAlex Deucher &rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table; 144641a524abSAlex Deucher int ret; 144741a524abSAlex Deucher 144841a524abSAlex Deucher if (!gate) { 144941a524abSAlex Deucher if (pi->caps_stable_p_state) 145041a524abSAlex Deucher pi->samu_boot_level = table->count - 1; 145141a524abSAlex Deucher else 145241a524abSAlex Deucher pi->samu_boot_level = 0; 145341a524abSAlex Deucher 145441a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 145541a524abSAlex Deucher pi->dpm_table_start + 145641a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, SamuBootLevel), 145741a524abSAlex Deucher (u8 *)&pi->samu_boot_level, 145841a524abSAlex Deucher sizeof(u8), 145941a524abSAlex Deucher pi->sram_end); 146041a524abSAlex Deucher if (ret) 146141a524abSAlex Deucher return ret; 146241a524abSAlex Deucher 146341a524abSAlex Deucher if (pi->caps_stable_p_state) 146441a524abSAlex Deucher kv_send_msg_to_smc_with_parameter(rdev, 146541a524abSAlex Deucher PPSMC_MSG_SAMUDPM_SetEnabledMask, 146641a524abSAlex Deucher (1 << pi->samu_boot_level)); 146741a524abSAlex Deucher } 146841a524abSAlex Deucher 146941a524abSAlex Deucher return kv_enable_samu_dpm(rdev, !gate); 147041a524abSAlex Deucher } 147141a524abSAlex Deucher 1472136de91eSAlex Deucher static u8 kv_get_acp_boot_level(struct radeon_device *rdev) 1473136de91eSAlex Deucher { 1474136de91eSAlex Deucher u8 i; 1475136de91eSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 1476136de91eSAlex Deucher &rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table; 1477136de91eSAlex Deucher 1478136de91eSAlex Deucher for (i = 0; i < table->count; i++) { 1479136de91eSAlex Deucher if (table->entries[i].clk >= 0) /* XXX */ 1480136de91eSAlex Deucher break; 1481136de91eSAlex Deucher } 1482136de91eSAlex Deucher 1483136de91eSAlex Deucher if (i >= table->count) 1484136de91eSAlex Deucher i = table->count - 1; 1485136de91eSAlex Deucher 1486136de91eSAlex Deucher return i; 1487136de91eSAlex Deucher } 1488136de91eSAlex Deucher 1489136de91eSAlex Deucher static void kv_update_acp_boot_level(struct radeon_device *rdev) 1490136de91eSAlex Deucher { 1491136de91eSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 1492136de91eSAlex Deucher u8 acp_boot_level; 1493136de91eSAlex Deucher 1494136de91eSAlex Deucher if (!pi->caps_stable_p_state) { 1495136de91eSAlex Deucher acp_boot_level = kv_get_acp_boot_level(rdev); 1496136de91eSAlex Deucher if (acp_boot_level != pi->acp_boot_level) { 1497136de91eSAlex Deucher pi->acp_boot_level = acp_boot_level; 1498136de91eSAlex Deucher kv_send_msg_to_smc_with_parameter(rdev, 1499136de91eSAlex Deucher PPSMC_MSG_ACPDPM_SetEnabledMask, 1500136de91eSAlex Deucher (1 << pi->acp_boot_level)); 1501136de91eSAlex Deucher } 1502136de91eSAlex Deucher } 1503136de91eSAlex Deucher } 1504136de91eSAlex Deucher 150541a524abSAlex Deucher static int kv_update_acp_dpm(struct radeon_device *rdev, bool gate) 150641a524abSAlex Deucher { 150741a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 150841a524abSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 150941a524abSAlex Deucher &rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table; 151041a524abSAlex Deucher int ret; 151141a524abSAlex Deucher 151241a524abSAlex Deucher if (!gate) { 151341a524abSAlex Deucher if (pi->caps_stable_p_state) 151441a524abSAlex Deucher pi->acp_boot_level = table->count - 1; 151541a524abSAlex Deucher else 1516136de91eSAlex Deucher pi->acp_boot_level = kv_get_acp_boot_level(rdev); 151741a524abSAlex Deucher 151841a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 151941a524abSAlex Deucher pi->dpm_table_start + 152041a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, AcpBootLevel), 152141a524abSAlex Deucher (u8 *)&pi->acp_boot_level, 152241a524abSAlex Deucher sizeof(u8), 152341a524abSAlex Deucher pi->sram_end); 152441a524abSAlex Deucher if (ret) 152541a524abSAlex Deucher return ret; 152641a524abSAlex Deucher 152741a524abSAlex Deucher if (pi->caps_stable_p_state) 152841a524abSAlex Deucher kv_send_msg_to_smc_with_parameter(rdev, 152941a524abSAlex Deucher PPSMC_MSG_ACPDPM_SetEnabledMask, 153041a524abSAlex Deucher (1 << pi->acp_boot_level)); 153141a524abSAlex Deucher } 153241a524abSAlex Deucher 153341a524abSAlex Deucher return kv_enable_acp_dpm(rdev, !gate); 153441a524abSAlex Deucher } 153541a524abSAlex Deucher 153677df508aSAlex Deucher void kv_dpm_powergate_uvd(struct radeon_device *rdev, bool gate) 153741a524abSAlex Deucher { 153841a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 153941a524abSAlex Deucher 154041a524abSAlex Deucher if (pi->uvd_power_gated == gate) 154141a524abSAlex Deucher return; 154241a524abSAlex Deucher 154341a524abSAlex Deucher pi->uvd_power_gated = gate; 154441a524abSAlex Deucher 154541a524abSAlex Deucher if (gate) { 1546f30df435SAlex Deucher if (pi->caps_uvd_pg) { 1547e409b128SChristian König uvd_v1_0_stop(rdev); 154877df508aSAlex Deucher cik_update_cg(rdev, RADEON_CG_BLOCK_UVD, false); 1549f30df435SAlex Deucher } 155077df508aSAlex Deucher kv_update_uvd_dpm(rdev, gate); 155141a524abSAlex Deucher if (pi->caps_uvd_pg) 155241a524abSAlex Deucher kv_notify_message_to_smu(rdev, PPSMC_MSG_UVDPowerOFF); 155341a524abSAlex Deucher } else { 1554f30df435SAlex Deucher if (pi->caps_uvd_pg) { 155541a524abSAlex Deucher kv_notify_message_to_smu(rdev, PPSMC_MSG_UVDPowerON); 1556e409b128SChristian König uvd_v4_2_resume(rdev); 1557e409b128SChristian König uvd_v1_0_start(rdev); 155877df508aSAlex Deucher cik_update_cg(rdev, RADEON_CG_BLOCK_UVD, true); 1559f30df435SAlex Deucher } 156077df508aSAlex Deucher kv_update_uvd_dpm(rdev, gate); 156141a524abSAlex Deucher } 156241a524abSAlex Deucher } 156341a524abSAlex Deucher 156441a524abSAlex Deucher static void kv_dpm_powergate_vce(struct radeon_device *rdev, bool gate) 156541a524abSAlex Deucher { 156641a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 156741a524abSAlex Deucher 156841a524abSAlex Deucher if (pi->vce_power_gated == gate) 156941a524abSAlex Deucher return; 157041a524abSAlex Deucher 157141a524abSAlex Deucher pi->vce_power_gated = gate; 157241a524abSAlex Deucher 157341a524abSAlex Deucher if (gate) { 157441a524abSAlex Deucher if (pi->caps_vce_pg) 157541a524abSAlex Deucher kv_notify_message_to_smu(rdev, PPSMC_MSG_VCEPowerOFF); 157641a524abSAlex Deucher } else { 157741a524abSAlex Deucher if (pi->caps_vce_pg) 157841a524abSAlex Deucher kv_notify_message_to_smu(rdev, PPSMC_MSG_VCEPowerON); 157941a524abSAlex Deucher } 158041a524abSAlex Deucher } 158141a524abSAlex Deucher 158241a524abSAlex Deucher static void kv_dpm_powergate_samu(struct radeon_device *rdev, bool gate) 158341a524abSAlex Deucher { 158441a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 158541a524abSAlex Deucher 158641a524abSAlex Deucher if (pi->samu_power_gated == gate) 158741a524abSAlex Deucher return; 158841a524abSAlex Deucher 158941a524abSAlex Deucher pi->samu_power_gated = gate; 159041a524abSAlex Deucher 159141a524abSAlex Deucher if (gate) { 159241a524abSAlex Deucher kv_update_samu_dpm(rdev, true); 159341a524abSAlex Deucher if (pi->caps_samu_pg) 159441a524abSAlex Deucher kv_notify_message_to_smu(rdev, PPSMC_MSG_SAMPowerOFF); 159541a524abSAlex Deucher } else { 159641a524abSAlex Deucher if (pi->caps_samu_pg) 159741a524abSAlex Deucher kv_notify_message_to_smu(rdev, PPSMC_MSG_SAMPowerON); 159841a524abSAlex Deucher kv_update_samu_dpm(rdev, false); 159941a524abSAlex Deucher } 160041a524abSAlex Deucher } 160141a524abSAlex Deucher 160241a524abSAlex Deucher static void kv_dpm_powergate_acp(struct radeon_device *rdev, bool gate) 160341a524abSAlex Deucher { 160441a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 160541a524abSAlex Deucher 160641a524abSAlex Deucher if (pi->acp_power_gated == gate) 160741a524abSAlex Deucher return; 160841a524abSAlex Deucher 160941a524abSAlex Deucher if (rdev->family == CHIP_KABINI) 161041a524abSAlex Deucher return; 161141a524abSAlex Deucher 161241a524abSAlex Deucher pi->acp_power_gated = gate; 161341a524abSAlex Deucher 161441a524abSAlex Deucher if (gate) { 161541a524abSAlex Deucher kv_update_acp_dpm(rdev, true); 161641a524abSAlex Deucher if (pi->caps_acp_pg) 161741a524abSAlex Deucher kv_notify_message_to_smu(rdev, PPSMC_MSG_ACPPowerOFF); 161841a524abSAlex Deucher } else { 161941a524abSAlex Deucher if (pi->caps_acp_pg) 162041a524abSAlex Deucher kv_notify_message_to_smu(rdev, PPSMC_MSG_ACPPowerON); 162141a524abSAlex Deucher kv_update_acp_dpm(rdev, false); 162241a524abSAlex Deucher } 162341a524abSAlex Deucher } 162441a524abSAlex Deucher 162541a524abSAlex Deucher static void kv_set_valid_clock_range(struct radeon_device *rdev, 162641a524abSAlex Deucher struct radeon_ps *new_rps) 162741a524abSAlex Deucher { 162841a524abSAlex Deucher struct kv_ps *new_ps = kv_get_ps(new_rps); 162941a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 163041a524abSAlex Deucher u32 i; 163141a524abSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 163241a524abSAlex Deucher &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; 163341a524abSAlex Deucher 163441a524abSAlex Deucher if (table && table->count) { 163541a524abSAlex Deucher for (i = 0; i < pi->graphics_dpm_level_count; i++) { 163641a524abSAlex Deucher if ((table->entries[i].clk >= new_ps->levels[0].sclk) || 163741a524abSAlex Deucher (i == (pi->graphics_dpm_level_count - 1))) { 163841a524abSAlex Deucher pi->lowest_valid = i; 163941a524abSAlex Deucher break; 164041a524abSAlex Deucher } 164141a524abSAlex Deucher } 164241a524abSAlex Deucher 16438c5c6fadSDan Carpenter for (i = pi->graphics_dpm_level_count - 1; i > 0; i--) { 16448c5c6fadSDan Carpenter if (table->entries[i].clk <= new_ps->levels[new_ps->num_levels - 1].sclk) 164541a524abSAlex Deucher break; 164641a524abSAlex Deucher } 16478c5c6fadSDan Carpenter pi->highest_valid = i; 164841a524abSAlex Deucher 164941a524abSAlex Deucher if (pi->lowest_valid > pi->highest_valid) { 165041a524abSAlex Deucher if ((new_ps->levels[0].sclk - table->entries[pi->highest_valid].clk) > 165141a524abSAlex Deucher (table->entries[pi->lowest_valid].clk - new_ps->levels[new_ps->num_levels - 1].sclk)) 165241a524abSAlex Deucher pi->highest_valid = pi->lowest_valid; 165341a524abSAlex Deucher else 165441a524abSAlex Deucher pi->lowest_valid = pi->highest_valid; 165541a524abSAlex Deucher } 165641a524abSAlex Deucher } else { 165741a524abSAlex Deucher struct sumo_sclk_voltage_mapping_table *table = 165841a524abSAlex Deucher &pi->sys_info.sclk_voltage_mapping_table; 165941a524abSAlex Deucher 166041a524abSAlex Deucher for (i = 0; i < (int)pi->graphics_dpm_level_count; i++) { 166141a524abSAlex Deucher if (table->entries[i].sclk_frequency >= new_ps->levels[0].sclk || 166241a524abSAlex Deucher i == (int)(pi->graphics_dpm_level_count - 1)) { 166341a524abSAlex Deucher pi->lowest_valid = i; 166441a524abSAlex Deucher break; 166541a524abSAlex Deucher } 166641a524abSAlex Deucher } 166741a524abSAlex Deucher 16688c5c6fadSDan Carpenter for (i = pi->graphics_dpm_level_count - 1; i > 0; i--) { 166941a524abSAlex Deucher if (table->entries[i].sclk_frequency <= 16708c5c6fadSDan Carpenter new_ps->levels[new_ps->num_levels - 1].sclk) 167141a524abSAlex Deucher break; 167241a524abSAlex Deucher } 16738c5c6fadSDan Carpenter pi->highest_valid = i; 167441a524abSAlex Deucher 167541a524abSAlex Deucher if (pi->lowest_valid > pi->highest_valid) { 167641a524abSAlex Deucher if ((new_ps->levels[0].sclk - 167741a524abSAlex Deucher table->entries[pi->highest_valid].sclk_frequency) > 167841a524abSAlex Deucher (table->entries[pi->lowest_valid].sclk_frequency - 167941a524abSAlex Deucher new_ps->levels[new_ps->num_levels -1].sclk)) 168041a524abSAlex Deucher pi->highest_valid = pi->lowest_valid; 168141a524abSAlex Deucher else 168241a524abSAlex Deucher pi->lowest_valid = pi->highest_valid; 168341a524abSAlex Deucher } 168441a524abSAlex Deucher } 168541a524abSAlex Deucher } 168641a524abSAlex Deucher 168741a524abSAlex Deucher static int kv_update_dfs_bypass_settings(struct radeon_device *rdev, 168841a524abSAlex Deucher struct radeon_ps *new_rps) 168941a524abSAlex Deucher { 169041a524abSAlex Deucher struct kv_ps *new_ps = kv_get_ps(new_rps); 169141a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 169241a524abSAlex Deucher int ret = 0; 169341a524abSAlex Deucher u8 clk_bypass_cntl; 169441a524abSAlex Deucher 169541a524abSAlex Deucher if (pi->caps_enable_dfs_bypass) { 169641a524abSAlex Deucher clk_bypass_cntl = new_ps->need_dfs_bypass ? 169741a524abSAlex Deucher pi->graphics_level[pi->graphics_boot_level].ClkBypassCntl : 0; 169841a524abSAlex Deucher ret = kv_copy_bytes_to_smc(rdev, 169941a524abSAlex Deucher (pi->dpm_table_start + 170041a524abSAlex Deucher offsetof(SMU7_Fusion_DpmTable, GraphicsLevel) + 170141a524abSAlex Deucher (pi->graphics_boot_level * sizeof(SMU7_Fusion_GraphicsLevel)) + 170241a524abSAlex Deucher offsetof(SMU7_Fusion_GraphicsLevel, ClkBypassCntl)), 170341a524abSAlex Deucher &clk_bypass_cntl, 170441a524abSAlex Deucher sizeof(u8), pi->sram_end); 170541a524abSAlex Deucher } 170641a524abSAlex Deucher 170741a524abSAlex Deucher return ret; 170841a524abSAlex Deucher } 170941a524abSAlex Deucher 171041a524abSAlex Deucher static int kv_enable_nb_dpm(struct radeon_device *rdev) 171141a524abSAlex Deucher { 171241a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 171341a524abSAlex Deucher int ret = 0; 171441a524abSAlex Deucher 171541a524abSAlex Deucher if (pi->enable_nb_dpm && !pi->nb_dpm_enabled) { 171641a524abSAlex Deucher ret = kv_notify_message_to_smu(rdev, PPSMC_MSG_NBDPM_Enable); 171741a524abSAlex Deucher if (ret == 0) 171841a524abSAlex Deucher pi->nb_dpm_enabled = true; 171941a524abSAlex Deucher } 172041a524abSAlex Deucher 172141a524abSAlex Deucher return ret; 172241a524abSAlex Deucher } 172341a524abSAlex Deucher 17242b4c8022SAlex Deucher int kv_dpm_force_performance_level(struct radeon_device *rdev, 17252b4c8022SAlex Deucher enum radeon_dpm_forced_level level) 17262b4c8022SAlex Deucher { 17272b4c8022SAlex Deucher int ret; 17282b4c8022SAlex Deucher 17292b4c8022SAlex Deucher if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { 17302b4c8022SAlex Deucher ret = kv_force_dpm_highest(rdev); 17312b4c8022SAlex Deucher if (ret) 17322b4c8022SAlex Deucher return ret; 17332b4c8022SAlex Deucher } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) { 17342b4c8022SAlex Deucher ret = kv_force_dpm_lowest(rdev); 17352b4c8022SAlex Deucher if (ret) 17362b4c8022SAlex Deucher return ret; 17372b4c8022SAlex Deucher } else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) { 17382b4c8022SAlex Deucher ret = kv_unforce_levels(rdev); 17392b4c8022SAlex Deucher if (ret) 17402b4c8022SAlex Deucher return ret; 17412b4c8022SAlex Deucher } 17422b4c8022SAlex Deucher 17432b4c8022SAlex Deucher rdev->pm.dpm.forced_level = level; 17442b4c8022SAlex Deucher 17452b4c8022SAlex Deucher return 0; 17462b4c8022SAlex Deucher } 17472b4c8022SAlex Deucher 174841a524abSAlex Deucher int kv_dpm_pre_set_power_state(struct radeon_device *rdev) 174941a524abSAlex Deucher { 175041a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 175141a524abSAlex Deucher struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps; 175241a524abSAlex Deucher struct radeon_ps *new_ps = &requested_ps; 175341a524abSAlex Deucher 175441a524abSAlex Deucher kv_update_requested_ps(rdev, new_ps); 175541a524abSAlex Deucher 175641a524abSAlex Deucher kv_apply_state_adjust_rules(rdev, 175741a524abSAlex Deucher &pi->requested_rps, 175841a524abSAlex Deucher &pi->current_rps); 175941a524abSAlex Deucher 176041a524abSAlex Deucher return 0; 176141a524abSAlex Deucher } 176241a524abSAlex Deucher 176341a524abSAlex Deucher int kv_dpm_set_power_state(struct radeon_device *rdev) 176441a524abSAlex Deucher { 176541a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 176641a524abSAlex Deucher struct radeon_ps *new_ps = &pi->requested_rps; 176741a524abSAlex Deucher /*struct radeon_ps *old_ps = &pi->current_rps;*/ 176841a524abSAlex Deucher int ret; 176941a524abSAlex Deucher 17706500fc0cSAlex Deucher cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX | 17716500fc0cSAlex Deucher RADEON_CG_BLOCK_SDMA | 17726500fc0cSAlex Deucher RADEON_CG_BLOCK_BIF | 17736500fc0cSAlex Deucher RADEON_CG_BLOCK_HDP), false); 17746500fc0cSAlex Deucher 177541a524abSAlex Deucher if (rdev->family == CHIP_KABINI) { 177641a524abSAlex Deucher if (pi->enable_dpm) { 177741a524abSAlex Deucher kv_set_valid_clock_range(rdev, new_ps); 177841a524abSAlex Deucher kv_update_dfs_bypass_settings(rdev, new_ps); 177941a524abSAlex Deucher ret = kv_calculate_ds_divider(rdev); 178041a524abSAlex Deucher if (ret) { 178141a524abSAlex Deucher DRM_ERROR("kv_calculate_ds_divider failed\n"); 178241a524abSAlex Deucher return ret; 178341a524abSAlex Deucher } 178441a524abSAlex Deucher kv_calculate_nbps_level_settings(rdev); 178541a524abSAlex Deucher kv_calculate_dpm_settings(rdev); 178641a524abSAlex Deucher kv_force_lowest_valid(rdev); 178741a524abSAlex Deucher kv_enable_new_levels(rdev); 178841a524abSAlex Deucher kv_upload_dpm_settings(rdev); 178941a524abSAlex Deucher kv_program_nbps_index_settings(rdev, new_ps); 179041a524abSAlex Deucher kv_unforce_levels(rdev); 179141a524abSAlex Deucher kv_set_enabled_levels(rdev); 179241a524abSAlex Deucher kv_force_lowest_valid(rdev); 179341a524abSAlex Deucher kv_unforce_levels(rdev); 179441a524abSAlex Deucher #if 0 179541a524abSAlex Deucher ret = kv_update_vce_dpm(rdev, new_ps, old_ps); 179641a524abSAlex Deucher if (ret) { 179741a524abSAlex Deucher DRM_ERROR("kv_update_vce_dpm failed\n"); 179841a524abSAlex Deucher return ret; 179941a524abSAlex Deucher } 180041a524abSAlex Deucher #endif 180141a524abSAlex Deucher kv_update_sclk_t(rdev); 180241a524abSAlex Deucher } 180341a524abSAlex Deucher } else { 180441a524abSAlex Deucher if (pi->enable_dpm) { 180541a524abSAlex Deucher kv_set_valid_clock_range(rdev, new_ps); 180641a524abSAlex Deucher kv_update_dfs_bypass_settings(rdev, new_ps); 180741a524abSAlex Deucher ret = kv_calculate_ds_divider(rdev); 180841a524abSAlex Deucher if (ret) { 180941a524abSAlex Deucher DRM_ERROR("kv_calculate_ds_divider failed\n"); 181041a524abSAlex Deucher return ret; 181141a524abSAlex Deucher } 181241a524abSAlex Deucher kv_calculate_nbps_level_settings(rdev); 181341a524abSAlex Deucher kv_calculate_dpm_settings(rdev); 181441a524abSAlex Deucher kv_freeze_sclk_dpm(rdev, true); 181541a524abSAlex Deucher kv_upload_dpm_settings(rdev); 181641a524abSAlex Deucher kv_program_nbps_index_settings(rdev, new_ps); 181741a524abSAlex Deucher kv_freeze_sclk_dpm(rdev, false); 181841a524abSAlex Deucher kv_set_enabled_levels(rdev); 181941a524abSAlex Deucher #if 0 182041a524abSAlex Deucher ret = kv_update_vce_dpm(rdev, new_ps, old_ps); 182141a524abSAlex Deucher if (ret) { 182241a524abSAlex Deucher DRM_ERROR("kv_update_vce_dpm failed\n"); 182341a524abSAlex Deucher return ret; 182441a524abSAlex Deucher } 182541a524abSAlex Deucher #endif 1826136de91eSAlex Deucher kv_update_acp_boot_level(rdev); 182741a524abSAlex Deucher kv_update_sclk_t(rdev); 182841a524abSAlex Deucher kv_enable_nb_dpm(rdev); 182941a524abSAlex Deucher } 183041a524abSAlex Deucher } 18316500fc0cSAlex Deucher 18326500fc0cSAlex Deucher cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX | 18336500fc0cSAlex Deucher RADEON_CG_BLOCK_SDMA | 18346500fc0cSAlex Deucher RADEON_CG_BLOCK_BIF | 18356500fc0cSAlex Deucher RADEON_CG_BLOCK_HDP), true); 18366500fc0cSAlex Deucher 18372b4c8022SAlex Deucher rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO; 183841a524abSAlex Deucher return 0; 183941a524abSAlex Deucher } 184041a524abSAlex Deucher 184141a524abSAlex Deucher void kv_dpm_post_set_power_state(struct radeon_device *rdev) 184241a524abSAlex Deucher { 184341a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 184441a524abSAlex Deucher struct radeon_ps *new_ps = &pi->requested_rps; 184541a524abSAlex Deucher 184641a524abSAlex Deucher kv_update_current_ps(rdev, new_ps); 184741a524abSAlex Deucher } 184841a524abSAlex Deucher 184941a524abSAlex Deucher void kv_dpm_setup_asic(struct radeon_device *rdev) 185041a524abSAlex Deucher { 185141a524abSAlex Deucher sumo_take_smu_control(rdev, true); 185241a524abSAlex Deucher kv_init_powergate_state(rdev); 185341a524abSAlex Deucher kv_init_sclk_t(rdev); 185441a524abSAlex Deucher } 185541a524abSAlex Deucher 185641a524abSAlex Deucher void kv_dpm_reset_asic(struct radeon_device *rdev) 185741a524abSAlex Deucher { 1858136de91eSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 1859136de91eSAlex Deucher 1860136de91eSAlex Deucher if (rdev->family == CHIP_KABINI) { 186141a524abSAlex Deucher kv_force_lowest_valid(rdev); 186241a524abSAlex Deucher kv_init_graphics_levels(rdev); 186341a524abSAlex Deucher kv_program_bootup_state(rdev); 186441a524abSAlex Deucher kv_upload_dpm_settings(rdev); 186541a524abSAlex Deucher kv_force_lowest_valid(rdev); 186641a524abSAlex Deucher kv_unforce_levels(rdev); 1867136de91eSAlex Deucher } else { 1868136de91eSAlex Deucher kv_init_graphics_levels(rdev); 1869136de91eSAlex Deucher kv_program_bootup_state(rdev); 1870136de91eSAlex Deucher kv_freeze_sclk_dpm(rdev, true); 1871136de91eSAlex Deucher kv_upload_dpm_settings(rdev); 1872136de91eSAlex Deucher kv_freeze_sclk_dpm(rdev, false); 1873136de91eSAlex Deucher kv_set_enabled_level(rdev, pi->graphics_boot_level); 1874136de91eSAlex Deucher } 187541a524abSAlex Deucher } 187641a524abSAlex Deucher 187741a524abSAlex Deucher //XXX use sumo_dpm_display_configuration_changed 187841a524abSAlex Deucher 187941a524abSAlex Deucher static void kv_construct_max_power_limits_table(struct radeon_device *rdev, 188041a524abSAlex Deucher struct radeon_clock_and_voltage_limits *table) 188141a524abSAlex Deucher { 188241a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 188341a524abSAlex Deucher 188441a524abSAlex Deucher if (pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries > 0) { 188541a524abSAlex Deucher int idx = pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries - 1; 188641a524abSAlex Deucher table->sclk = 188741a524abSAlex Deucher pi->sys_info.sclk_voltage_mapping_table.entries[idx].sclk_frequency; 188841a524abSAlex Deucher table->vddc = 188941a524abSAlex Deucher kv_convert_2bit_index_to_voltage(rdev, 189041a524abSAlex Deucher pi->sys_info.sclk_voltage_mapping_table.entries[idx].vid_2bit); 189141a524abSAlex Deucher } 189241a524abSAlex Deucher 189341a524abSAlex Deucher table->mclk = pi->sys_info.nbp_memory_clock[0]; 189441a524abSAlex Deucher } 189541a524abSAlex Deucher 189641a524abSAlex Deucher static void kv_patch_voltage_values(struct radeon_device *rdev) 189741a524abSAlex Deucher { 189841a524abSAlex Deucher int i; 189941a524abSAlex Deucher struct radeon_uvd_clock_voltage_dependency_table *table = 190041a524abSAlex Deucher &rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table; 190141a524abSAlex Deucher 190241a524abSAlex Deucher if (table->count) { 190341a524abSAlex Deucher for (i = 0; i < table->count; i++) 190441a524abSAlex Deucher table->entries[i].v = 190541a524abSAlex Deucher kv_convert_8bit_index_to_voltage(rdev, 190641a524abSAlex Deucher table->entries[i].v); 190741a524abSAlex Deucher } 190841a524abSAlex Deucher 190941a524abSAlex Deucher } 191041a524abSAlex Deucher 191141a524abSAlex Deucher static void kv_construct_boot_state(struct radeon_device *rdev) 191241a524abSAlex Deucher { 191341a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 191441a524abSAlex Deucher 191541a524abSAlex Deucher pi->boot_pl.sclk = pi->sys_info.bootup_sclk; 191641a524abSAlex Deucher pi->boot_pl.vddc_index = pi->sys_info.bootup_nb_voltage_index; 191741a524abSAlex Deucher pi->boot_pl.ds_divider_index = 0; 191841a524abSAlex Deucher pi->boot_pl.ss_divider_index = 0; 191941a524abSAlex Deucher pi->boot_pl.allow_gnb_slow = 1; 192041a524abSAlex Deucher pi->boot_pl.force_nbp_state = 0; 192141a524abSAlex Deucher pi->boot_pl.display_wm = 0; 192241a524abSAlex Deucher pi->boot_pl.vce_wm = 0; 192341a524abSAlex Deucher } 192441a524abSAlex Deucher 19252b4c8022SAlex Deucher static int kv_force_dpm_highest(struct radeon_device *rdev) 19262b4c8022SAlex Deucher { 19272b4c8022SAlex Deucher int ret; 19282b4c8022SAlex Deucher u32 enable_mask, i; 19292b4c8022SAlex Deucher 19302b4c8022SAlex Deucher ret = kv_dpm_get_enable_mask(rdev, &enable_mask); 19312b4c8022SAlex Deucher if (ret) 19322b4c8022SAlex Deucher return ret; 19332b4c8022SAlex Deucher 19348c5c6fadSDan Carpenter for (i = SMU7_MAX_LEVELS_GRAPHICS - 1; i > 0; i--) { 19352b4c8022SAlex Deucher if (enable_mask & (1 << i)) 19362b4c8022SAlex Deucher break; 19372b4c8022SAlex Deucher } 19382b4c8022SAlex Deucher 1939136de91eSAlex Deucher if (rdev->family == CHIP_KABINI) 19402b4c8022SAlex Deucher return kv_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_DPM_ForceState, i); 1941136de91eSAlex Deucher else 1942136de91eSAlex Deucher return kv_set_enabled_level(rdev, i); 19432b4c8022SAlex Deucher } 19442b4c8022SAlex Deucher 194541a524abSAlex Deucher static int kv_force_dpm_lowest(struct radeon_device *rdev) 194641a524abSAlex Deucher { 194741a524abSAlex Deucher int ret; 194841a524abSAlex Deucher u32 enable_mask, i; 194941a524abSAlex Deucher 195041a524abSAlex Deucher ret = kv_dpm_get_enable_mask(rdev, &enable_mask); 195141a524abSAlex Deucher if (ret) 195241a524abSAlex Deucher return ret; 195341a524abSAlex Deucher 195441a524abSAlex Deucher for (i = 0; i < SMU7_MAX_LEVELS_GRAPHICS; i++) { 195541a524abSAlex Deucher if (enable_mask & (1 << i)) 195641a524abSAlex Deucher break; 195741a524abSAlex Deucher } 195841a524abSAlex Deucher 1959136de91eSAlex Deucher if (rdev->family == CHIP_KABINI) 196041a524abSAlex Deucher return kv_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_DPM_ForceState, i); 1961136de91eSAlex Deucher else 1962136de91eSAlex Deucher return kv_set_enabled_level(rdev, i); 196341a524abSAlex Deucher } 196441a524abSAlex Deucher 196541a524abSAlex Deucher static u8 kv_get_sleep_divider_id_from_clock(struct radeon_device *rdev, 196641a524abSAlex Deucher u32 sclk, u32 min_sclk_in_sr) 196741a524abSAlex Deucher { 196841a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 196941a524abSAlex Deucher u32 i; 197041a524abSAlex Deucher u32 temp; 197141a524abSAlex Deucher u32 min = (min_sclk_in_sr > KV_MINIMUM_ENGINE_CLOCK) ? 197241a524abSAlex Deucher min_sclk_in_sr : KV_MINIMUM_ENGINE_CLOCK; 197341a524abSAlex Deucher 197441a524abSAlex Deucher if (sclk < min) 197541a524abSAlex Deucher return 0; 197641a524abSAlex Deucher 197741a524abSAlex Deucher if (!pi->caps_sclk_ds) 197841a524abSAlex Deucher return 0; 197941a524abSAlex Deucher 19808c5c6fadSDan Carpenter for (i = KV_MAX_DEEPSLEEP_DIVIDER_ID; i > 0; i--) { 198141a524abSAlex Deucher temp = sclk / sumo_get_sleep_divider_from_id(i); 19828c5c6fadSDan Carpenter if (temp >= min) 198341a524abSAlex Deucher break; 198441a524abSAlex Deucher } 198541a524abSAlex Deucher 198641a524abSAlex Deucher return (u8)i; 198741a524abSAlex Deucher } 198841a524abSAlex Deucher 198941a524abSAlex Deucher static int kv_get_high_voltage_limit(struct radeon_device *rdev, int *limit) 199041a524abSAlex Deucher { 199141a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 199241a524abSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 199341a524abSAlex Deucher &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; 199441a524abSAlex Deucher int i; 199541a524abSAlex Deucher 199641a524abSAlex Deucher if (table && table->count) { 199741a524abSAlex Deucher for (i = table->count - 1; i >= 0; i--) { 199841a524abSAlex Deucher if (pi->high_voltage_t && 199941a524abSAlex Deucher (kv_convert_8bit_index_to_voltage(rdev, table->entries[i].v) <= 200041a524abSAlex Deucher pi->high_voltage_t)) { 200141a524abSAlex Deucher *limit = i; 200241a524abSAlex Deucher return 0; 200341a524abSAlex Deucher } 200441a524abSAlex Deucher } 200541a524abSAlex Deucher } else { 200641a524abSAlex Deucher struct sumo_sclk_voltage_mapping_table *table = 200741a524abSAlex Deucher &pi->sys_info.sclk_voltage_mapping_table; 200841a524abSAlex Deucher 200941a524abSAlex Deucher for (i = table->num_max_dpm_entries - 1; i >= 0; i--) { 201041a524abSAlex Deucher if (pi->high_voltage_t && 201141a524abSAlex Deucher (kv_convert_2bit_index_to_voltage(rdev, table->entries[i].vid_2bit) <= 201241a524abSAlex Deucher pi->high_voltage_t)) { 201341a524abSAlex Deucher *limit = i; 201441a524abSAlex Deucher return 0; 201541a524abSAlex Deucher } 201641a524abSAlex Deucher } 201741a524abSAlex Deucher } 201841a524abSAlex Deucher 201941a524abSAlex Deucher *limit = 0; 202041a524abSAlex Deucher return 0; 202141a524abSAlex Deucher } 202241a524abSAlex Deucher 202341a524abSAlex Deucher static void kv_apply_state_adjust_rules(struct radeon_device *rdev, 202441a524abSAlex Deucher struct radeon_ps *new_rps, 202541a524abSAlex Deucher struct radeon_ps *old_rps) 202641a524abSAlex Deucher { 202741a524abSAlex Deucher struct kv_ps *ps = kv_get_ps(new_rps); 202841a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 202941a524abSAlex Deucher u32 min_sclk = 10000; /* ??? */ 203041a524abSAlex Deucher u32 sclk, mclk = 0; 203141a524abSAlex Deucher int i, limit; 203241a524abSAlex Deucher bool force_high; 203341a524abSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 203441a524abSAlex Deucher &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; 203541a524abSAlex Deucher u32 stable_p_state_sclk = 0; 203641a524abSAlex Deucher struct radeon_clock_and_voltage_limits *max_limits = 203741a524abSAlex Deucher &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; 203841a524abSAlex Deucher 203941a524abSAlex Deucher mclk = max_limits->mclk; 204041a524abSAlex Deucher sclk = min_sclk; 204141a524abSAlex Deucher 204241a524abSAlex Deucher if (pi->caps_stable_p_state) { 204341a524abSAlex Deucher stable_p_state_sclk = (max_limits->sclk * 75) / 100; 204441a524abSAlex Deucher 204541a524abSAlex Deucher for (i = table->count - 1; i >= 0; i++) { 204641a524abSAlex Deucher if (stable_p_state_sclk >= table->entries[i].clk) { 204741a524abSAlex Deucher stable_p_state_sclk = table->entries[i].clk; 204841a524abSAlex Deucher break; 204941a524abSAlex Deucher } 205041a524abSAlex Deucher } 205141a524abSAlex Deucher 205241a524abSAlex Deucher if (i > 0) 205341a524abSAlex Deucher stable_p_state_sclk = table->entries[0].clk; 205441a524abSAlex Deucher 205541a524abSAlex Deucher sclk = stable_p_state_sclk; 205641a524abSAlex Deucher } 205741a524abSAlex Deucher 205841a524abSAlex Deucher ps->need_dfs_bypass = true; 205941a524abSAlex Deucher 206041a524abSAlex Deucher for (i = 0; i < ps->num_levels; i++) { 206141a524abSAlex Deucher if (ps->levels[i].sclk < sclk) 206241a524abSAlex Deucher ps->levels[i].sclk = sclk; 206341a524abSAlex Deucher } 206441a524abSAlex Deucher 206541a524abSAlex Deucher if (table && table->count) { 206641a524abSAlex Deucher for (i = 0; i < ps->num_levels; i++) { 206741a524abSAlex Deucher if (pi->high_voltage_t && 206841a524abSAlex Deucher (pi->high_voltage_t < 206941a524abSAlex Deucher kv_convert_8bit_index_to_voltage(rdev, ps->levels[i].vddc_index))) { 207041a524abSAlex Deucher kv_get_high_voltage_limit(rdev, &limit); 207141a524abSAlex Deucher ps->levels[i].sclk = table->entries[limit].clk; 207241a524abSAlex Deucher } 207341a524abSAlex Deucher } 207441a524abSAlex Deucher } else { 207541a524abSAlex Deucher struct sumo_sclk_voltage_mapping_table *table = 207641a524abSAlex Deucher &pi->sys_info.sclk_voltage_mapping_table; 207741a524abSAlex Deucher 207841a524abSAlex Deucher for (i = 0; i < ps->num_levels; i++) { 207941a524abSAlex Deucher if (pi->high_voltage_t && 208041a524abSAlex Deucher (pi->high_voltage_t < 208141a524abSAlex Deucher kv_convert_8bit_index_to_voltage(rdev, ps->levels[i].vddc_index))) { 208241a524abSAlex Deucher kv_get_high_voltage_limit(rdev, &limit); 208341a524abSAlex Deucher ps->levels[i].sclk = table->entries[limit].sclk_frequency; 208441a524abSAlex Deucher } 208541a524abSAlex Deucher } 208641a524abSAlex Deucher } 208741a524abSAlex Deucher 208841a524abSAlex Deucher if (pi->caps_stable_p_state) { 208941a524abSAlex Deucher for (i = 0; i < ps->num_levels; i++) { 209041a524abSAlex Deucher ps->levels[i].sclk = stable_p_state_sclk; 209141a524abSAlex Deucher } 209241a524abSAlex Deucher } 209341a524abSAlex Deucher 209441a524abSAlex Deucher pi->video_start = new_rps->dclk || new_rps->vclk; 209541a524abSAlex Deucher 209641a524abSAlex Deucher if ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == 209741a524abSAlex Deucher ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) 209841a524abSAlex Deucher pi->battery_state = true; 209941a524abSAlex Deucher else 210041a524abSAlex Deucher pi->battery_state = false; 210141a524abSAlex Deucher 210241a524abSAlex Deucher if (rdev->family == CHIP_KABINI) { 210341a524abSAlex Deucher ps->dpm0_pg_nb_ps_lo = 0x1; 210441a524abSAlex Deucher ps->dpm0_pg_nb_ps_hi = 0x0; 210541a524abSAlex Deucher ps->dpmx_nb_ps_lo = 0x1; 210641a524abSAlex Deucher ps->dpmx_nb_ps_hi = 0x0; 210741a524abSAlex Deucher } else { 2108136de91eSAlex Deucher ps->dpm0_pg_nb_ps_lo = 0x3; 210941a524abSAlex Deucher ps->dpm0_pg_nb_ps_hi = 0x0; 2110136de91eSAlex Deucher ps->dpmx_nb_ps_lo = 0x3; 2111136de91eSAlex Deucher ps->dpmx_nb_ps_hi = 0x0; 211241a524abSAlex Deucher 2113136de91eSAlex Deucher if (pi->sys_info.nb_dpm_enable) { 211441a524abSAlex Deucher force_high = (mclk >= pi->sys_info.nbp_memory_clock[3]) || 211541a524abSAlex Deucher pi->video_start || (rdev->pm.dpm.new_active_crtc_count >= 3) || 211641a524abSAlex Deucher pi->disable_nb_ps3_in_battery; 211741a524abSAlex Deucher ps->dpm0_pg_nb_ps_lo = force_high ? 0x2 : 0x3; 211841a524abSAlex Deucher ps->dpm0_pg_nb_ps_hi = 0x2; 211941a524abSAlex Deucher ps->dpmx_nb_ps_lo = force_high ? 0x2 : 0x3; 212041a524abSAlex Deucher ps->dpmx_nb_ps_hi = 0x2; 212141a524abSAlex Deucher } 212241a524abSAlex Deucher } 212341a524abSAlex Deucher } 212441a524abSAlex Deucher 212541a524abSAlex Deucher static void kv_dpm_power_level_enabled_for_throttle(struct radeon_device *rdev, 212641a524abSAlex Deucher u32 index, bool enable) 212741a524abSAlex Deucher { 212841a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 212941a524abSAlex Deucher 213041a524abSAlex Deucher pi->graphics_level[index].EnabledForThrottle = enable ? 1 : 0; 213141a524abSAlex Deucher } 213241a524abSAlex Deucher 213341a524abSAlex Deucher static int kv_calculate_ds_divider(struct radeon_device *rdev) 213441a524abSAlex Deucher { 213541a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 213641a524abSAlex Deucher u32 sclk_in_sr = 10000; /* ??? */ 213741a524abSAlex Deucher u32 i; 213841a524abSAlex Deucher 213941a524abSAlex Deucher if (pi->lowest_valid > pi->highest_valid) 214041a524abSAlex Deucher return -EINVAL; 214141a524abSAlex Deucher 214241a524abSAlex Deucher for (i = pi->lowest_valid; i <= pi->highest_valid; i++) { 214341a524abSAlex Deucher pi->graphics_level[i].DeepSleepDivId = 214441a524abSAlex Deucher kv_get_sleep_divider_id_from_clock(rdev, 214541a524abSAlex Deucher be32_to_cpu(pi->graphics_level[i].SclkFrequency), 214641a524abSAlex Deucher sclk_in_sr); 214741a524abSAlex Deucher } 214841a524abSAlex Deucher return 0; 214941a524abSAlex Deucher } 215041a524abSAlex Deucher 215141a524abSAlex Deucher static int kv_calculate_nbps_level_settings(struct radeon_device *rdev) 215241a524abSAlex Deucher { 215341a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 215441a524abSAlex Deucher u32 i; 215541a524abSAlex Deucher bool force_high; 215641a524abSAlex Deucher struct radeon_clock_and_voltage_limits *max_limits = 215741a524abSAlex Deucher &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac; 215841a524abSAlex Deucher u32 mclk = max_limits->mclk; 215941a524abSAlex Deucher 216041a524abSAlex Deucher if (pi->lowest_valid > pi->highest_valid) 216141a524abSAlex Deucher return -EINVAL; 216241a524abSAlex Deucher 216341a524abSAlex Deucher if (rdev->family == CHIP_KABINI) { 216441a524abSAlex Deucher for (i = pi->lowest_valid; i <= pi->highest_valid; i++) { 216541a524abSAlex Deucher pi->graphics_level[i].GnbSlow = 1; 216641a524abSAlex Deucher pi->graphics_level[i].ForceNbPs1 = 0; 216741a524abSAlex Deucher pi->graphics_level[i].UpH = 0; 216841a524abSAlex Deucher } 216941a524abSAlex Deucher 217041a524abSAlex Deucher if (!pi->sys_info.nb_dpm_enable) 217141a524abSAlex Deucher return 0; 217241a524abSAlex Deucher 217341a524abSAlex Deucher force_high = ((mclk >= pi->sys_info.nbp_memory_clock[3]) || 217441a524abSAlex Deucher (rdev->pm.dpm.new_active_crtc_count >= 3) || pi->video_start); 217541a524abSAlex Deucher 217641a524abSAlex Deucher if (force_high) { 217741a524abSAlex Deucher for (i = pi->lowest_valid; i <= pi->highest_valid; i++) 217841a524abSAlex Deucher pi->graphics_level[i].GnbSlow = 0; 217941a524abSAlex Deucher } else { 218041a524abSAlex Deucher if (pi->battery_state) 218141a524abSAlex Deucher pi->graphics_level[0].ForceNbPs1 = 1; 218241a524abSAlex Deucher 218341a524abSAlex Deucher pi->graphics_level[1].GnbSlow = 0; 218441a524abSAlex Deucher pi->graphics_level[2].GnbSlow = 0; 218541a524abSAlex Deucher pi->graphics_level[3].GnbSlow = 0; 218641a524abSAlex Deucher pi->graphics_level[4].GnbSlow = 0; 218741a524abSAlex Deucher } 218841a524abSAlex Deucher } else { 218941a524abSAlex Deucher for (i = pi->lowest_valid; i <= pi->highest_valid; i++) { 219041a524abSAlex Deucher pi->graphics_level[i].GnbSlow = 1; 219141a524abSAlex Deucher pi->graphics_level[i].ForceNbPs1 = 0; 219241a524abSAlex Deucher pi->graphics_level[i].UpH = 0; 219341a524abSAlex Deucher } 219441a524abSAlex Deucher 219541a524abSAlex Deucher if (pi->sys_info.nb_dpm_enable && pi->battery_state) { 219641a524abSAlex Deucher pi->graphics_level[pi->lowest_valid].UpH = 0x28; 219741a524abSAlex Deucher pi->graphics_level[pi->lowest_valid].GnbSlow = 0; 219841a524abSAlex Deucher if (pi->lowest_valid != pi->highest_valid) 219941a524abSAlex Deucher pi->graphics_level[pi->lowest_valid].ForceNbPs1 = 1; 220041a524abSAlex Deucher } 220141a524abSAlex Deucher } 220241a524abSAlex Deucher return 0; 220341a524abSAlex Deucher } 220441a524abSAlex Deucher 220541a524abSAlex Deucher static int kv_calculate_dpm_settings(struct radeon_device *rdev) 220641a524abSAlex Deucher { 220741a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 220841a524abSAlex Deucher u32 i; 220941a524abSAlex Deucher 221041a524abSAlex Deucher if (pi->lowest_valid > pi->highest_valid) 221141a524abSAlex Deucher return -EINVAL; 221241a524abSAlex Deucher 221341a524abSAlex Deucher for (i = pi->lowest_valid; i <= pi->highest_valid; i++) 221441a524abSAlex Deucher pi->graphics_level[i].DisplayWatermark = (i == pi->highest_valid) ? 1 : 0; 221541a524abSAlex Deucher 221641a524abSAlex Deucher return 0; 221741a524abSAlex Deucher } 221841a524abSAlex Deucher 221941a524abSAlex Deucher static void kv_init_graphics_levels(struct radeon_device *rdev) 222041a524abSAlex Deucher { 222141a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 222241a524abSAlex Deucher u32 i; 222341a524abSAlex Deucher struct radeon_clock_voltage_dependency_table *table = 222441a524abSAlex Deucher &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk; 222541a524abSAlex Deucher 222641a524abSAlex Deucher if (table && table->count) { 222741a524abSAlex Deucher u32 vid_2bit; 222841a524abSAlex Deucher 222941a524abSAlex Deucher pi->graphics_dpm_level_count = 0; 223041a524abSAlex Deucher for (i = 0; i < table->count; i++) { 223141a524abSAlex Deucher if (pi->high_voltage_t && 223241a524abSAlex Deucher (pi->high_voltage_t < 223341a524abSAlex Deucher kv_convert_8bit_index_to_voltage(rdev, table->entries[i].v))) 223441a524abSAlex Deucher break; 223541a524abSAlex Deucher 223641a524abSAlex Deucher kv_set_divider_value(rdev, i, table->entries[i].clk); 223741a524abSAlex Deucher vid_2bit = sumo_convert_vid7_to_vid2(rdev, 223841a524abSAlex Deucher &pi->sys_info.vid_mapping_table, 223941a524abSAlex Deucher table->entries[i].v); 224041a524abSAlex Deucher kv_set_vid(rdev, i, vid_2bit); 224141a524abSAlex Deucher kv_set_at(rdev, i, pi->at[i]); 224241a524abSAlex Deucher kv_dpm_power_level_enabled_for_throttle(rdev, i, true); 224341a524abSAlex Deucher pi->graphics_dpm_level_count++; 224441a524abSAlex Deucher } 224541a524abSAlex Deucher } else { 224641a524abSAlex Deucher struct sumo_sclk_voltage_mapping_table *table = 224741a524abSAlex Deucher &pi->sys_info.sclk_voltage_mapping_table; 224841a524abSAlex Deucher 224941a524abSAlex Deucher pi->graphics_dpm_level_count = 0; 225041a524abSAlex Deucher for (i = 0; i < table->num_max_dpm_entries; i++) { 225141a524abSAlex Deucher if (pi->high_voltage_t && 225241a524abSAlex Deucher pi->high_voltage_t < 225341a524abSAlex Deucher kv_convert_2bit_index_to_voltage(rdev, table->entries[i].vid_2bit)) 225441a524abSAlex Deucher break; 225541a524abSAlex Deucher 225641a524abSAlex Deucher kv_set_divider_value(rdev, i, table->entries[i].sclk_frequency); 225741a524abSAlex Deucher kv_set_vid(rdev, i, table->entries[i].vid_2bit); 225841a524abSAlex Deucher kv_set_at(rdev, i, pi->at[i]); 225941a524abSAlex Deucher kv_dpm_power_level_enabled_for_throttle(rdev, i, true); 226041a524abSAlex Deucher pi->graphics_dpm_level_count++; 226141a524abSAlex Deucher } 226241a524abSAlex Deucher } 226341a524abSAlex Deucher 226441a524abSAlex Deucher for (i = 0; i < SMU7_MAX_LEVELS_GRAPHICS; i++) 226541a524abSAlex Deucher kv_dpm_power_level_enable(rdev, i, false); 226641a524abSAlex Deucher } 226741a524abSAlex Deucher 226841a524abSAlex Deucher static void kv_enable_new_levels(struct radeon_device *rdev) 226941a524abSAlex Deucher { 227041a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 227141a524abSAlex Deucher u32 i; 227241a524abSAlex Deucher 227341a524abSAlex Deucher for (i = 0; i < SMU7_MAX_LEVELS_GRAPHICS; i++) { 227441a524abSAlex Deucher if (i >= pi->lowest_valid && i <= pi->highest_valid) 227541a524abSAlex Deucher kv_dpm_power_level_enable(rdev, i, true); 227641a524abSAlex Deucher } 227741a524abSAlex Deucher } 227841a524abSAlex Deucher 2279136de91eSAlex Deucher static int kv_set_enabled_level(struct radeon_device *rdev, u32 level) 2280136de91eSAlex Deucher { 2281136de91eSAlex Deucher u32 new_mask = (1 << level); 2282136de91eSAlex Deucher 2283136de91eSAlex Deucher return kv_send_msg_to_smc_with_parameter(rdev, 2284136de91eSAlex Deucher PPSMC_MSG_SCLKDPM_SetEnabledMask, 2285136de91eSAlex Deucher new_mask); 2286136de91eSAlex Deucher } 2287136de91eSAlex Deucher 228841a524abSAlex Deucher static int kv_set_enabled_levels(struct radeon_device *rdev) 228941a524abSAlex Deucher { 229041a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 229141a524abSAlex Deucher u32 i, new_mask = 0; 229241a524abSAlex Deucher 229341a524abSAlex Deucher for (i = pi->lowest_valid; i <= pi->highest_valid; i++) 229441a524abSAlex Deucher new_mask |= (1 << i); 229541a524abSAlex Deucher 229641a524abSAlex Deucher return kv_send_msg_to_smc_with_parameter(rdev, 229741a524abSAlex Deucher PPSMC_MSG_SCLKDPM_SetEnabledMask, 229841a524abSAlex Deucher new_mask); 229941a524abSAlex Deucher } 230041a524abSAlex Deucher 230141a524abSAlex Deucher static void kv_program_nbps_index_settings(struct radeon_device *rdev, 230241a524abSAlex Deucher struct radeon_ps *new_rps) 230341a524abSAlex Deucher { 230441a524abSAlex Deucher struct kv_ps *new_ps = kv_get_ps(new_rps); 230541a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 230641a524abSAlex Deucher u32 nbdpmconfig1; 230741a524abSAlex Deucher 230841a524abSAlex Deucher if (rdev->family == CHIP_KABINI) 230941a524abSAlex Deucher return; 231041a524abSAlex Deucher 231141a524abSAlex Deucher if (pi->sys_info.nb_dpm_enable) { 231241a524abSAlex Deucher nbdpmconfig1 = RREG32_SMC(NB_DPM_CONFIG_1); 231341a524abSAlex Deucher nbdpmconfig1 &= ~(Dpm0PgNbPsLo_MASK | Dpm0PgNbPsHi_MASK | 231441a524abSAlex Deucher DpmXNbPsLo_MASK | DpmXNbPsHi_MASK); 231541a524abSAlex Deucher nbdpmconfig1 |= (Dpm0PgNbPsLo(new_ps->dpm0_pg_nb_ps_lo) | 231641a524abSAlex Deucher Dpm0PgNbPsHi(new_ps->dpm0_pg_nb_ps_hi) | 231741a524abSAlex Deucher DpmXNbPsLo(new_ps->dpmx_nb_ps_lo) | 231841a524abSAlex Deucher DpmXNbPsHi(new_ps->dpmx_nb_ps_hi)); 231941a524abSAlex Deucher WREG32_SMC(NB_DPM_CONFIG_1, nbdpmconfig1); 232041a524abSAlex Deucher } 232141a524abSAlex Deucher } 232241a524abSAlex Deucher 232341a524abSAlex Deucher static int kv_set_thermal_temperature_range(struct radeon_device *rdev, 232441a524abSAlex Deucher int min_temp, int max_temp) 232541a524abSAlex Deucher { 232641a524abSAlex Deucher int low_temp = 0 * 1000; 232741a524abSAlex Deucher int high_temp = 255 * 1000; 232841a524abSAlex Deucher u32 tmp; 232941a524abSAlex Deucher 233041a524abSAlex Deucher if (low_temp < min_temp) 233141a524abSAlex Deucher low_temp = min_temp; 233241a524abSAlex Deucher if (high_temp > max_temp) 233341a524abSAlex Deucher high_temp = max_temp; 233441a524abSAlex Deucher if (high_temp < low_temp) { 233541a524abSAlex Deucher DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp); 233641a524abSAlex Deucher return -EINVAL; 233741a524abSAlex Deucher } 233841a524abSAlex Deucher 233941a524abSAlex Deucher tmp = RREG32_SMC(CG_THERMAL_INT_CTRL); 234041a524abSAlex Deucher tmp &= ~(DIG_THERM_INTH_MASK | DIG_THERM_INTL_MASK); 234141a524abSAlex Deucher tmp |= (DIG_THERM_INTH(49 + (high_temp / 1000)) | 234241a524abSAlex Deucher DIG_THERM_INTL(49 + (low_temp / 1000))); 234341a524abSAlex Deucher WREG32_SMC(CG_THERMAL_INT_CTRL, tmp); 234441a524abSAlex Deucher 234541a524abSAlex Deucher rdev->pm.dpm.thermal.min_temp = low_temp; 234641a524abSAlex Deucher rdev->pm.dpm.thermal.max_temp = high_temp; 234741a524abSAlex Deucher 234841a524abSAlex Deucher return 0; 234941a524abSAlex Deucher } 235041a524abSAlex Deucher 235141a524abSAlex Deucher union igp_info { 235241a524abSAlex Deucher struct _ATOM_INTEGRATED_SYSTEM_INFO info; 235341a524abSAlex Deucher struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2; 235441a524abSAlex Deucher struct _ATOM_INTEGRATED_SYSTEM_INFO_V5 info_5; 235541a524abSAlex Deucher struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6; 235641a524abSAlex Deucher struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7; 235741a524abSAlex Deucher struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 info_8; 235841a524abSAlex Deucher }; 235941a524abSAlex Deucher 236041a524abSAlex Deucher static int kv_parse_sys_info_table(struct radeon_device *rdev) 236141a524abSAlex Deucher { 236241a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 236341a524abSAlex Deucher struct radeon_mode_info *mode_info = &rdev->mode_info; 236441a524abSAlex Deucher int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo); 236541a524abSAlex Deucher union igp_info *igp_info; 236641a524abSAlex Deucher u8 frev, crev; 236741a524abSAlex Deucher u16 data_offset; 236841a524abSAlex Deucher int i; 236941a524abSAlex Deucher 237041a524abSAlex Deucher if (atom_parse_data_header(mode_info->atom_context, index, NULL, 237141a524abSAlex Deucher &frev, &crev, &data_offset)) { 237241a524abSAlex Deucher igp_info = (union igp_info *)(mode_info->atom_context->bios + 237341a524abSAlex Deucher data_offset); 237441a524abSAlex Deucher 237541a524abSAlex Deucher if (crev != 8) { 237641a524abSAlex Deucher DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev); 237741a524abSAlex Deucher return -EINVAL; 237841a524abSAlex Deucher } 237941a524abSAlex Deucher pi->sys_info.bootup_sclk = le32_to_cpu(igp_info->info_8.ulBootUpEngineClock); 238041a524abSAlex Deucher pi->sys_info.bootup_uma_clk = le32_to_cpu(igp_info->info_8.ulBootUpUMAClock); 238141a524abSAlex Deucher pi->sys_info.bootup_nb_voltage_index = 238241a524abSAlex Deucher le16_to_cpu(igp_info->info_8.usBootUpNBVoltage); 238341a524abSAlex Deucher if (igp_info->info_8.ucHtcTmpLmt == 0) 238441a524abSAlex Deucher pi->sys_info.htc_tmp_lmt = 203; 238541a524abSAlex Deucher else 238641a524abSAlex Deucher pi->sys_info.htc_tmp_lmt = igp_info->info_8.ucHtcTmpLmt; 238741a524abSAlex Deucher if (igp_info->info_8.ucHtcHystLmt == 0) 238841a524abSAlex Deucher pi->sys_info.htc_hyst_lmt = 5; 238941a524abSAlex Deucher else 239041a524abSAlex Deucher pi->sys_info.htc_hyst_lmt = igp_info->info_8.ucHtcHystLmt; 239141a524abSAlex Deucher if (pi->sys_info.htc_tmp_lmt <= pi->sys_info.htc_hyst_lmt) { 239241a524abSAlex Deucher DRM_ERROR("The htcTmpLmt should be larger than htcHystLmt.\n"); 239341a524abSAlex Deucher } 239441a524abSAlex Deucher 239541a524abSAlex Deucher if (le32_to_cpu(igp_info->info_8.ulSystemConfig) & (1 << 3)) 239641a524abSAlex Deucher pi->sys_info.nb_dpm_enable = true; 239741a524abSAlex Deucher else 239841a524abSAlex Deucher pi->sys_info.nb_dpm_enable = false; 239941a524abSAlex Deucher 240041a524abSAlex Deucher for (i = 0; i < KV_NUM_NBPSTATES; i++) { 240141a524abSAlex Deucher pi->sys_info.nbp_memory_clock[i] = 240241a524abSAlex Deucher le32_to_cpu(igp_info->info_8.ulNbpStateMemclkFreq[i]); 240341a524abSAlex Deucher pi->sys_info.nbp_n_clock[i] = 240441a524abSAlex Deucher le32_to_cpu(igp_info->info_8.ulNbpStateNClkFreq[i]); 240541a524abSAlex Deucher } 240641a524abSAlex Deucher if (le32_to_cpu(igp_info->info_8.ulGPUCapInfo) & 240741a524abSAlex Deucher SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS) 240841a524abSAlex Deucher pi->caps_enable_dfs_bypass = true; 240941a524abSAlex Deucher 241041a524abSAlex Deucher sumo_construct_sclk_voltage_mapping_table(rdev, 241141a524abSAlex Deucher &pi->sys_info.sclk_voltage_mapping_table, 241241a524abSAlex Deucher igp_info->info_8.sAvail_SCLK); 241341a524abSAlex Deucher 241441a524abSAlex Deucher sumo_construct_vid_mapping_table(rdev, 241541a524abSAlex Deucher &pi->sys_info.vid_mapping_table, 241641a524abSAlex Deucher igp_info->info_8.sAvail_SCLK); 241741a524abSAlex Deucher 241841a524abSAlex Deucher kv_construct_max_power_limits_table(rdev, 241941a524abSAlex Deucher &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac); 242041a524abSAlex Deucher } 242141a524abSAlex Deucher return 0; 242241a524abSAlex Deucher } 242341a524abSAlex Deucher 242441a524abSAlex Deucher union power_info { 242541a524abSAlex Deucher struct _ATOM_POWERPLAY_INFO info; 242641a524abSAlex Deucher struct _ATOM_POWERPLAY_INFO_V2 info_2; 242741a524abSAlex Deucher struct _ATOM_POWERPLAY_INFO_V3 info_3; 242841a524abSAlex Deucher struct _ATOM_PPLIB_POWERPLAYTABLE pplib; 242941a524abSAlex Deucher struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2; 243041a524abSAlex Deucher struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3; 243141a524abSAlex Deucher }; 243241a524abSAlex Deucher 243341a524abSAlex Deucher union pplib_clock_info { 243441a524abSAlex Deucher struct _ATOM_PPLIB_R600_CLOCK_INFO r600; 243541a524abSAlex Deucher struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780; 243641a524abSAlex Deucher struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen; 243741a524abSAlex Deucher struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo; 243841a524abSAlex Deucher }; 243941a524abSAlex Deucher 244041a524abSAlex Deucher union pplib_power_state { 244141a524abSAlex Deucher struct _ATOM_PPLIB_STATE v1; 244241a524abSAlex Deucher struct _ATOM_PPLIB_STATE_V2 v2; 244341a524abSAlex Deucher }; 244441a524abSAlex Deucher 244541a524abSAlex Deucher static void kv_patch_boot_state(struct radeon_device *rdev, 244641a524abSAlex Deucher struct kv_ps *ps) 244741a524abSAlex Deucher { 244841a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 244941a524abSAlex Deucher 245041a524abSAlex Deucher ps->num_levels = 1; 245141a524abSAlex Deucher ps->levels[0] = pi->boot_pl; 245241a524abSAlex Deucher } 245341a524abSAlex Deucher 245441a524abSAlex Deucher static void kv_parse_pplib_non_clock_info(struct radeon_device *rdev, 245541a524abSAlex Deucher struct radeon_ps *rps, 245641a524abSAlex Deucher struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info, 245741a524abSAlex Deucher u8 table_rev) 245841a524abSAlex Deucher { 245941a524abSAlex Deucher struct kv_ps *ps = kv_get_ps(rps); 246041a524abSAlex Deucher 246141a524abSAlex Deucher rps->caps = le32_to_cpu(non_clock_info->ulCapsAndSettings); 246241a524abSAlex Deucher rps->class = le16_to_cpu(non_clock_info->usClassification); 246341a524abSAlex Deucher rps->class2 = le16_to_cpu(non_clock_info->usClassification2); 246441a524abSAlex Deucher 246541a524abSAlex Deucher if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) { 246641a524abSAlex Deucher rps->vclk = le32_to_cpu(non_clock_info->ulVCLK); 246741a524abSAlex Deucher rps->dclk = le32_to_cpu(non_clock_info->ulDCLK); 246841a524abSAlex Deucher } else { 246941a524abSAlex Deucher rps->vclk = 0; 247041a524abSAlex Deucher rps->dclk = 0; 247141a524abSAlex Deucher } 247241a524abSAlex Deucher 247341a524abSAlex Deucher if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) { 247441a524abSAlex Deucher rdev->pm.dpm.boot_ps = rps; 247541a524abSAlex Deucher kv_patch_boot_state(rdev, ps); 247641a524abSAlex Deucher } 247741a524abSAlex Deucher if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) 247841a524abSAlex Deucher rdev->pm.dpm.uvd_ps = rps; 247941a524abSAlex Deucher } 248041a524abSAlex Deucher 248141a524abSAlex Deucher static void kv_parse_pplib_clock_info(struct radeon_device *rdev, 248241a524abSAlex Deucher struct radeon_ps *rps, int index, 248341a524abSAlex Deucher union pplib_clock_info *clock_info) 248441a524abSAlex Deucher { 248541a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 248641a524abSAlex Deucher struct kv_ps *ps = kv_get_ps(rps); 248741a524abSAlex Deucher struct kv_pl *pl = &ps->levels[index]; 248841a524abSAlex Deucher u32 sclk; 248941a524abSAlex Deucher 249041a524abSAlex Deucher sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow); 249141a524abSAlex Deucher sclk |= clock_info->sumo.ucEngineClockHigh << 16; 249241a524abSAlex Deucher pl->sclk = sclk; 249341a524abSAlex Deucher pl->vddc_index = clock_info->sumo.vddcIndex; 249441a524abSAlex Deucher 249541a524abSAlex Deucher ps->num_levels = index + 1; 249641a524abSAlex Deucher 249741a524abSAlex Deucher if (pi->caps_sclk_ds) { 249841a524abSAlex Deucher pl->ds_divider_index = 5; 249941a524abSAlex Deucher pl->ss_divider_index = 5; 250041a524abSAlex Deucher } 250141a524abSAlex Deucher } 250241a524abSAlex Deucher 250341a524abSAlex Deucher static int kv_parse_power_table(struct radeon_device *rdev) 250441a524abSAlex Deucher { 250541a524abSAlex Deucher struct radeon_mode_info *mode_info = &rdev->mode_info; 250641a524abSAlex Deucher struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; 250741a524abSAlex Deucher union pplib_power_state *power_state; 250841a524abSAlex Deucher int i, j, k, non_clock_array_index, clock_array_index; 250941a524abSAlex Deucher union pplib_clock_info *clock_info; 251041a524abSAlex Deucher struct _StateArray *state_array; 251141a524abSAlex Deucher struct _ClockInfoArray *clock_info_array; 251241a524abSAlex Deucher struct _NonClockInfoArray *non_clock_info_array; 251341a524abSAlex Deucher union power_info *power_info; 251441a524abSAlex Deucher int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); 251541a524abSAlex Deucher u16 data_offset; 251641a524abSAlex Deucher u8 frev, crev; 251741a524abSAlex Deucher u8 *power_state_offset; 251841a524abSAlex Deucher struct kv_ps *ps; 251941a524abSAlex Deucher 252041a524abSAlex Deucher if (!atom_parse_data_header(mode_info->atom_context, index, NULL, 252141a524abSAlex Deucher &frev, &crev, &data_offset)) 252241a524abSAlex Deucher return -EINVAL; 252341a524abSAlex Deucher power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); 252441a524abSAlex Deucher 252541a524abSAlex Deucher state_array = (struct _StateArray *) 252641a524abSAlex Deucher (mode_info->atom_context->bios + data_offset + 252741a524abSAlex Deucher le16_to_cpu(power_info->pplib.usStateArrayOffset)); 252841a524abSAlex Deucher clock_info_array = (struct _ClockInfoArray *) 252941a524abSAlex Deucher (mode_info->atom_context->bios + data_offset + 253041a524abSAlex Deucher le16_to_cpu(power_info->pplib.usClockInfoArrayOffset)); 253141a524abSAlex Deucher non_clock_info_array = (struct _NonClockInfoArray *) 253241a524abSAlex Deucher (mode_info->atom_context->bios + data_offset + 253341a524abSAlex Deucher le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); 253441a524abSAlex Deucher 253541a524abSAlex Deucher rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) * 253641a524abSAlex Deucher state_array->ucNumEntries, GFP_KERNEL); 253741a524abSAlex Deucher if (!rdev->pm.dpm.ps) 253841a524abSAlex Deucher return -ENOMEM; 253941a524abSAlex Deucher power_state_offset = (u8 *)state_array->states; 254041a524abSAlex Deucher rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps); 254141a524abSAlex Deucher rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime); 254241a524abSAlex Deucher rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime); 254341a524abSAlex Deucher for (i = 0; i < state_array->ucNumEntries; i++) { 25449af37a7dSAlex Deucher u8 *idx; 254541a524abSAlex Deucher power_state = (union pplib_power_state *)power_state_offset; 254641a524abSAlex Deucher non_clock_array_index = power_state->v2.nonClockInfoIndex; 254741a524abSAlex Deucher non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) 254841a524abSAlex Deucher &non_clock_info_array->nonClockInfo[non_clock_array_index]; 254941a524abSAlex Deucher if (!rdev->pm.power_state[i].clock_info) 255041a524abSAlex Deucher return -EINVAL; 255141a524abSAlex Deucher ps = kzalloc(sizeof(struct kv_ps), GFP_KERNEL); 255241a524abSAlex Deucher if (ps == NULL) { 255341a524abSAlex Deucher kfree(rdev->pm.dpm.ps); 255441a524abSAlex Deucher return -ENOMEM; 255541a524abSAlex Deucher } 255641a524abSAlex Deucher rdev->pm.dpm.ps[i].ps_priv = ps; 255741a524abSAlex Deucher k = 0; 25589af37a7dSAlex Deucher idx = (u8 *)&power_state->v2.clockInfoIndex[0]; 255941a524abSAlex Deucher for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) { 25609af37a7dSAlex Deucher clock_array_index = idx[j]; 256141a524abSAlex Deucher if (clock_array_index >= clock_info_array->ucNumEntries) 256241a524abSAlex Deucher continue; 256341a524abSAlex Deucher if (k >= SUMO_MAX_HARDWARE_POWERLEVELS) 256441a524abSAlex Deucher break; 256541a524abSAlex Deucher clock_info = (union pplib_clock_info *) 25669af37a7dSAlex Deucher ((u8 *)&clock_info_array->clockInfo[0] + 25679af37a7dSAlex Deucher (clock_array_index * clock_info_array->ucEntrySize)); 256841a524abSAlex Deucher kv_parse_pplib_clock_info(rdev, 256941a524abSAlex Deucher &rdev->pm.dpm.ps[i], k, 257041a524abSAlex Deucher clock_info); 257141a524abSAlex Deucher k++; 257241a524abSAlex Deucher } 257341a524abSAlex Deucher kv_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i], 257441a524abSAlex Deucher non_clock_info, 257541a524abSAlex Deucher non_clock_info_array->ucEntrySize); 257641a524abSAlex Deucher power_state_offset += 2 + power_state->v2.ucNumDPMLevels; 257741a524abSAlex Deucher } 257841a524abSAlex Deucher rdev->pm.dpm.num_ps = state_array->ucNumEntries; 257941a524abSAlex Deucher return 0; 258041a524abSAlex Deucher } 258141a524abSAlex Deucher 258241a524abSAlex Deucher int kv_dpm_init(struct radeon_device *rdev) 258341a524abSAlex Deucher { 258441a524abSAlex Deucher struct kv_power_info *pi; 258541a524abSAlex Deucher int ret, i; 258641a524abSAlex Deucher 258741a524abSAlex Deucher pi = kzalloc(sizeof(struct kv_power_info), GFP_KERNEL); 258841a524abSAlex Deucher if (pi == NULL) 258941a524abSAlex Deucher return -ENOMEM; 259041a524abSAlex Deucher rdev->pm.dpm.priv = pi; 259141a524abSAlex Deucher 259241a524abSAlex Deucher ret = r600_parse_extended_power_table(rdev); 259341a524abSAlex Deucher if (ret) 259441a524abSAlex Deucher return ret; 259541a524abSAlex Deucher 259641a524abSAlex Deucher for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) 259741a524abSAlex Deucher pi->at[i] = TRINITY_AT_DFLT; 259841a524abSAlex Deucher 259941a524abSAlex Deucher pi->sram_end = SMC_RAM_END; 260041a524abSAlex Deucher 260141a524abSAlex Deucher if (rdev->family == CHIP_KABINI) 260241a524abSAlex Deucher pi->high_voltage_t = 4001; 260341a524abSAlex Deucher 260441a524abSAlex Deucher pi->enable_nb_dpm = true; 260541a524abSAlex Deucher 260641a524abSAlex Deucher pi->caps_power_containment = true; 260741a524abSAlex Deucher pi->caps_cac = true; 260841a524abSAlex Deucher pi->enable_didt = false; 260941a524abSAlex Deucher if (pi->enable_didt) { 261041a524abSAlex Deucher pi->caps_sq_ramping = true; 261141a524abSAlex Deucher pi->caps_db_ramping = true; 261241a524abSAlex Deucher pi->caps_td_ramping = true; 261341a524abSAlex Deucher pi->caps_tcp_ramping = true; 261441a524abSAlex Deucher } 261541a524abSAlex Deucher 261641a524abSAlex Deucher pi->caps_sclk_ds = true; 261741a524abSAlex Deucher pi->enable_auto_thermal_throttling = true; 261841a524abSAlex Deucher pi->disable_nb_ps3_in_battery = false; 261941a524abSAlex Deucher pi->bapm_enable = true; 262041a524abSAlex Deucher pi->voltage_drop_t = 0; 262141a524abSAlex Deucher pi->caps_sclk_throttle_low_notification = false; 262241a524abSAlex Deucher pi->caps_fps = false; /* true? */ 262377df508aSAlex Deucher pi->caps_uvd_pg = true; 262441a524abSAlex Deucher pi->caps_uvd_dpm = true; 262541a524abSAlex Deucher pi->caps_vce_pg = false; 262641a524abSAlex Deucher pi->caps_samu_pg = false; 262741a524abSAlex Deucher pi->caps_acp_pg = false; 262841a524abSAlex Deucher pi->caps_stable_p_state = false; 262941a524abSAlex Deucher 263041a524abSAlex Deucher ret = kv_parse_sys_info_table(rdev); 263141a524abSAlex Deucher if (ret) 263241a524abSAlex Deucher return ret; 263341a524abSAlex Deucher 263441a524abSAlex Deucher kv_patch_voltage_values(rdev); 263541a524abSAlex Deucher kv_construct_boot_state(rdev); 263641a524abSAlex Deucher 263741a524abSAlex Deucher ret = kv_parse_power_table(rdev); 263841a524abSAlex Deucher if (ret) 263941a524abSAlex Deucher return ret; 264041a524abSAlex Deucher 264141a524abSAlex Deucher pi->enable_dpm = true; 264241a524abSAlex Deucher 264341a524abSAlex Deucher return 0; 264441a524abSAlex Deucher } 264541a524abSAlex Deucher 2646ae3e40e8SAlex Deucher void kv_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, 2647ae3e40e8SAlex Deucher struct seq_file *m) 2648ae3e40e8SAlex Deucher { 2649ae3e40e8SAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 2650ae3e40e8SAlex Deucher u32 current_index = 2651ae3e40e8SAlex Deucher (RREG32_SMC(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_SCLK_INDEX_MASK) >> 2652ae3e40e8SAlex Deucher CURR_SCLK_INDEX_SHIFT; 2653ae3e40e8SAlex Deucher u32 sclk, tmp; 2654ae3e40e8SAlex Deucher u16 vddc; 2655ae3e40e8SAlex Deucher 2656ae3e40e8SAlex Deucher if (current_index >= SMU__NUM_SCLK_DPM_STATE) { 2657ae3e40e8SAlex Deucher seq_printf(m, "invalid dpm profile %d\n", current_index); 2658ae3e40e8SAlex Deucher } else { 2659ae3e40e8SAlex Deucher sclk = be32_to_cpu(pi->graphics_level[current_index].SclkFrequency); 2660ae3e40e8SAlex Deucher tmp = (RREG32_SMC(SMU_VOLTAGE_STATUS) & SMU_VOLTAGE_CURRENT_LEVEL_MASK) >> 2661ae3e40e8SAlex Deucher SMU_VOLTAGE_CURRENT_LEVEL_SHIFT; 2662ae3e40e8SAlex Deucher vddc = kv_convert_8bit_index_to_voltage(rdev, (u16)tmp); 2663ae3e40e8SAlex Deucher seq_printf(m, "power level %d sclk: %u vddc: %u\n", 2664ae3e40e8SAlex Deucher current_index, sclk, vddc); 2665ae3e40e8SAlex Deucher } 2666ae3e40e8SAlex Deucher } 2667ae3e40e8SAlex Deucher 266841a524abSAlex Deucher void kv_dpm_print_power_state(struct radeon_device *rdev, 266941a524abSAlex Deucher struct radeon_ps *rps) 267041a524abSAlex Deucher { 267141a524abSAlex Deucher int i; 267241a524abSAlex Deucher struct kv_ps *ps = kv_get_ps(rps); 267341a524abSAlex Deucher 267441a524abSAlex Deucher r600_dpm_print_class_info(rps->class, rps->class2); 267541a524abSAlex Deucher r600_dpm_print_cap_info(rps->caps); 267641a524abSAlex Deucher printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); 267741a524abSAlex Deucher for (i = 0; i < ps->num_levels; i++) { 267841a524abSAlex Deucher struct kv_pl *pl = &ps->levels[i]; 267941a524abSAlex Deucher printk("\t\tpower level %d sclk: %u vddc: %u\n", 268041a524abSAlex Deucher i, pl->sclk, 268141a524abSAlex Deucher kv_convert_8bit_index_to_voltage(rdev, pl->vddc_index)); 268241a524abSAlex Deucher } 268341a524abSAlex Deucher r600_dpm_print_ps_status(rdev, rps); 268441a524abSAlex Deucher } 268541a524abSAlex Deucher 268641a524abSAlex Deucher void kv_dpm_fini(struct radeon_device *rdev) 268741a524abSAlex Deucher { 268841a524abSAlex Deucher int i; 268941a524abSAlex Deucher 269041a524abSAlex Deucher for (i = 0; i < rdev->pm.dpm.num_ps; i++) { 269141a524abSAlex Deucher kfree(rdev->pm.dpm.ps[i].ps_priv); 269241a524abSAlex Deucher } 269341a524abSAlex Deucher kfree(rdev->pm.dpm.ps); 269441a524abSAlex Deucher kfree(rdev->pm.dpm.priv); 269541a524abSAlex Deucher r600_free_extended_power_table(rdev); 269641a524abSAlex Deucher } 269741a524abSAlex Deucher 269841a524abSAlex Deucher void kv_dpm_display_configuration_changed(struct radeon_device *rdev) 269941a524abSAlex Deucher { 270041a524abSAlex Deucher 270141a524abSAlex Deucher } 270241a524abSAlex Deucher 270341a524abSAlex Deucher u32 kv_dpm_get_sclk(struct radeon_device *rdev, bool low) 270441a524abSAlex Deucher { 270541a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 270641a524abSAlex Deucher struct kv_ps *requested_state = kv_get_ps(&pi->requested_rps); 270741a524abSAlex Deucher 270841a524abSAlex Deucher if (low) 270941a524abSAlex Deucher return requested_state->levels[0].sclk; 271041a524abSAlex Deucher else 271141a524abSAlex Deucher return requested_state->levels[requested_state->num_levels - 1].sclk; 271241a524abSAlex Deucher } 271341a524abSAlex Deucher 271441a524abSAlex Deucher u32 kv_dpm_get_mclk(struct radeon_device *rdev, bool low) 271541a524abSAlex Deucher { 271641a524abSAlex Deucher struct kv_power_info *pi = kv_get_pi(rdev); 271741a524abSAlex Deucher 271841a524abSAlex Deucher return pi->sys_info.bootup_uma_clk; 271941a524abSAlex Deucher } 272041a524abSAlex Deucher 2721