diff options
author | Evan Quan <evan.quan@amd.com> | 2020-08-13 16:39:25 +0800 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2020-08-14 16:22:41 -0400 |
commit | e098bc9612c2b60f94920461d71c92962a916e73 (patch) | |
tree | 9523440f73a9db1943a4102da7b5ef4c5fb15ca4 /drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | |
parent | e9372d23715d6802fd6d3763cb19c5a0c07ad641 (diff) |
drm/amd/pm: optimize the power related source code layout
The target is to provide a clear entry point(for power routines).
Also this can help to maintain a clear view about the frameworks
used on different ASICs. Hopefully all these can make power part
more friendly to play with.
Signed-off-by: Evan Quan <evan.quan@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c')
-rw-r--r-- | drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 5215 |
1 files changed, 0 insertions, 5215 deletions
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c deleted file mode 100644 index ffe05b7cc1f0..000000000000 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ /dev/null @@ -1,5215 +0,0 @@ -/* - * Copyright 2015 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include "pp_debug.h" -#include <linux/delay.h> -#include <linux/fb.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/slab.h> -#include <asm/div64.h> -#include <drm/amdgpu_drm.h> -#include "ppatomctrl.h" -#include "atombios.h" -#include "pptable_v1_0.h" -#include "pppcielanes.h" -#include "amd_pcie_helpers.h" -#include "hardwaremanager.h" -#include "process_pptables_v1_0.h" -#include "cgs_common.h" - -#include "smu7_common.h" - -#include "hwmgr.h" -#include "smu7_hwmgr.h" -#include "smu_ucode_xfer_vi.h" -#include "smu7_powertune.h" -#include "smu7_dyn_defaults.h" -#include "smu7_thermal.h" -#include "smu7_clockpowergating.h" -#include "processpptables.h" -#include "pp_thermal.h" -#include "smu7_baco.h" - -#include "ivsrcid/ivsrcid_vislands30.h" - -#define MC_CG_ARB_FREQ_F0 0x0a -#define MC_CG_ARB_FREQ_F1 0x0b -#define MC_CG_ARB_FREQ_F2 0x0c -#define MC_CG_ARB_FREQ_F3 0x0d - -#define MC_CG_SEQ_DRAMCONF_S0 0x05 -#define MC_CG_SEQ_DRAMCONF_S1 0x06 -#define MC_CG_SEQ_YCLK_SUSPEND 0x04 -#define MC_CG_SEQ_YCLK_RESUME 0x0a - -#define SMC_CG_IND_START 0xc0030000 -#define SMC_CG_IND_END 0xc0040000 - -#define MEM_FREQ_LOW_LATENCY 25000 -#define MEM_FREQ_HIGH_LATENCY 80000 - -#define MEM_LATENCY_HIGH 45 -#define MEM_LATENCY_LOW 35 -#define MEM_LATENCY_ERR 0xFFFF - -#define MC_SEQ_MISC0_GDDR5_SHIFT 28 -#define MC_SEQ_MISC0_GDDR5_MASK 0xf0000000 -#define MC_SEQ_MISC0_GDDR5_VALUE 5 - -#define PCIE_BUS_CLK 10000 -#define TCLK (PCIE_BUS_CLK / 10) - -static struct profile_mode_setting smu7_profiling[7] = - {{0, 0, 0, 0, 0, 0, 0, 0}, - {1, 0, 100, 30, 1, 0, 100, 10}, - {1, 10, 0, 30, 0, 0, 0, 0}, - {0, 0, 0, 0, 1, 10, 16, 31}, - {1, 0, 11, 50, 1, 0, 100, 10}, - {1, 0, 5, 30, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0}, - }; - -#define PPSMC_MSG_SetVBITimeout_VEGAM ((uint16_t) 0x310) - -#define ixPWR_SVI2_PLANE1_LOAD 0xC0200280 -#define PWR_SVI2_PLANE1_LOAD__PSI1_MASK 0x00000020L -#define PWR_SVI2_PLANE1_LOAD__PSI0_EN_MASK 0x00000040L -#define PWR_SVI2_PLANE1_LOAD__PSI1__SHIFT 0x00000005 -#define PWR_SVI2_PLANE1_LOAD__PSI0_EN__SHIFT 0x00000006 - -/** Values for the CG_THERMAL_CTRL::DPM_EVENT_SRC field. */ -enum DPM_EVENT_SRC { - DPM_EVENT_SRC_ANALOG = 0, - DPM_EVENT_SRC_EXTERNAL = 1, - DPM_EVENT_SRC_DIGITAL = 2, - DPM_EVENT_SRC_ANALOG_OR_EXTERNAL = 3, - DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL = 4 -}; - -static const unsigned long PhwVIslands_Magic = (unsigned long)(PHM_VIslands_Magic); -static int smu7_force_clock_level(struct pp_hwmgr *hwmgr, - enum pp_clock_type type, uint32_t mask); - -static struct smu7_power_state *cast_phw_smu7_power_state( - struct pp_hw_power_state *hw_ps) -{ - PP_ASSERT_WITH_CODE((PhwVIslands_Magic == hw_ps->magic), - "Invalid Powerstate Type!", - return NULL); - - return (struct smu7_power_state *)hw_ps; -} - -static const struct smu7_power_state *cast_const_phw_smu7_power_state( - const struct pp_hw_power_state *hw_ps) -{ - PP_ASSERT_WITH_CODE((PhwVIslands_Magic == hw_ps->magic), - "Invalid Powerstate Type!", - return NULL); - - return (const struct smu7_power_state *)hw_ps; -} - -/** - * Find the MC microcode version and store it in the HwMgr struct - * - * @param hwmgr the address of the powerplay hardware manager. - * @return always 0 - */ -static int smu7_get_mc_microcode_version(struct pp_hwmgr *hwmgr) -{ - cgs_write_register(hwmgr->device, mmMC_SEQ_IO_DEBUG_INDEX, 0x9F); - - hwmgr->microcode_version_info.MC = cgs_read_register(hwmgr->device, mmMC_SEQ_IO_DEBUG_DATA); - - return 0; -} - -static uint16_t smu7_get_current_pcie_speed(struct pp_hwmgr *hwmgr) -{ - uint32_t speedCntl = 0; - - /* mmPCIE_PORT_INDEX rename as mmPCIE_INDEX */ - speedCntl = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__PCIE, - ixPCIE_LC_SPEED_CNTL); - return((uint16_t)PHM_GET_FIELD(speedCntl, - PCIE_LC_SPEED_CNTL, LC_CURRENT_DATA_RATE)); -} - -static int smu7_get_current_pcie_lane_number(struct pp_hwmgr *hwmgr) -{ - uint32_t link_width; - - /* mmPCIE_PORT_INDEX rename as mmPCIE_INDEX */ - link_width = PHM_READ_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__PCIE, - PCIE_LC_LINK_WIDTH_CNTL, LC_LINK_WIDTH_RD); - - PP_ASSERT_WITH_CODE((7 >= link_width), - "Invalid PCIe lane width!", return 0); - - return decode_pcie_lane_width(link_width); -} - -/** -* Enable voltage control -* -* @param pHwMgr the address of the powerplay hardware manager. -* @return always PP_Result_OK -*/ -static int smu7_enable_smc_voltage_controller(struct pp_hwmgr *hwmgr) -{ - if (hwmgr->chip_id == CHIP_VEGAM) { - PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, - CGS_IND_REG__SMC, PWR_SVI2_PLANE1_LOAD, PSI1, 0); - PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, - CGS_IND_REG__SMC, PWR_SVI2_PLANE1_LOAD, PSI0_EN, 0); - } - - if (hwmgr->feature_mask & PP_SMC_VOLTAGE_CONTROL_MASK) - smum_send_msg_to_smc(hwmgr, PPSMC_MSG_Voltage_Cntl_Enable, NULL); - - return 0; -} - -/** -* Checks if we want to support voltage control -* -* @param hwmgr the address of the powerplay hardware manager. -*/ -static bool smu7_voltage_control(const struct pp_hwmgr *hwmgr) -{ - const struct smu7_hwmgr *data = - (const struct smu7_hwmgr *)(hwmgr->backend); - - return (SMU7_VOLTAGE_CONTROL_NONE != data->voltage_control); -} - -/** -* Enable voltage control -* -* @param hwmgr the address of the powerplay hardware manager. -* @return always 0 -*/ -static int smu7_enable_voltage_control(struct pp_hwmgr *hwmgr) -{ - /* enable voltage control */ - PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, - GENERAL_PWRMGT, VOLT_PWRMGT_EN, 1); - - return 0; -} - -static int phm_get_svi2_voltage_table_v0(pp_atomctrl_voltage_table *voltage_table, - struct phm_clock_voltage_dependency_table *voltage_dependency_table - ) -{ - uint32_t i; - - PP_ASSERT_WITH_CODE((NULL != voltage_table), - "Voltage Dependency Table empty.", return -EINVAL;); - - voltage_table->mask_low = 0; - voltage_table->phase_delay = 0; - voltage_table->count = voltage_dependency_table->count; - - for (i = 0; i < voltage_dependency_table->count; i++) { - voltage_table->entries[i].value = - voltage_dependency_table->entries[i].v; - voltage_table->entries[i].smio_low = 0; - } - - return 0; -} - - -/** -* Create Voltage Tables. -* -* @param hwmgr the address of the powerplay hardware manager. -* @return always 0 -*/ -static int smu7_construct_voltage_tables(struct pp_hwmgr *hwmgr) -{ - struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - struct phm_ppt_v1_information *table_info = - (struct phm_ppt_v1_information *)hwmgr->pptable; - int result = 0; - uint32_t tmp; - - if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) { - result = atomctrl_get_voltage_table_v3(hwmgr, - VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT, - &(data->mvdd_voltage_table)); - PP_ASSERT_WITH_CODE((0 == result), - "Failed to retrieve MVDD table.", - return result); - } else if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->mvdd_control) { - if (hwmgr->pp_table_version == PP_TABLE_V1) - result = phm_get_svi2_mvdd_voltage_table(&(data->mvdd_voltage_table), - table_info->vdd_dep_on_mclk); - else if (hwmgr->pp_table_version == PP_TABLE_V0) - result = phm_get_svi2_voltage_table_v0(&(data->mvdd_voltage_table), - hwmgr->dyn_state.mvdd_dependency_on_mclk); - - PP_ASSERT_WITH_CODE((0 == result), - "Failed to retrieve SVI2 MVDD table from dependency table.", - return result;); - } - - if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) { - result = atomctrl_get_voltage_table_v3(hwmgr, - VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT, - &(data->vddci_voltage_table)); - PP_ASSERT_WITH_CODE((0 == result), - "Failed to retrieve VDDCI table.", - return result); - } else if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) { - if (hwmgr->pp_table_version == PP_TABLE_V1) - result = phm_get_svi2_vddci_voltage_table(&(data->vddci_voltage_table), - table_info->vdd_dep_on_mclk); - else if (hwmgr->pp_table_version == PP_TABLE_V0) - result = phm_get_svi2_voltage_table_v0(&(data->vddci_voltage_table), - hwmgr->dyn_state.vddci_dependency_on_mclk); - PP_ASSERT_WITH_CODE((0 == result), - "Failed to retrieve SVI2 VDDCI table from dependency table.", - return result); - } - - if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vdd_gfx_control) { - /* VDDGFX has only SVI2 voltage control */ - result = phm_get_svi2_vdd_voltage_table(&(data->vddgfx_voltage_table), - table_info->vddgfx_lookup_table); - PP_ASSERT_WITH_CODE((0 == result), - "Failed to retrieve SVI2 VDDGFX table from lookup table.", return result;); - } - - - if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->voltage_control) { - result = atomctrl_get_voltage_table_v3(hwmgr, - VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_GPIO_LUT, - &data->vddc_voltage_table); - PP_ASSERT_WITH_CODE((0 == result), - "Failed to retrieve VDDC table.", return result;); - } else if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) { - - if (hwmgr->pp_table_version == PP_TABLE_V0) - result = phm_get_svi2_voltage_table_v0(&data->vddc_voltage_table, - hwmgr->dyn_state.vddc_dependency_on_mclk); - else if (hwmgr->pp_table_version == PP_TABLE_V1) - result = phm_get_svi2_vdd_voltage_table(&(data->vddc_voltage_table), - table_info->vddc_lookup_table); - - PP_ASSERT_WITH_CODE((0 == result), - "Failed to retrieve SVI2 VDDC table from dependency table.", return result;); - } - - tmp = smum_get_mac_definition(hwmgr, SMU_MAX_LEVELS_VDDC); - PP_ASSERT_WITH_CODE( - (data->vddc_voltage_table.count <= tmp), - "Too many voltage values for VDDC. Trimming to fit state table.", - phm_trim_voltage_table_to_fit_state_table(tmp, - &(data->vddc_voltage_table))); - - tmp = smum_get_mac_definition(hwmgr, SMU_MAX_LEVELS_VDDGFX); - PP_ASSERT_WITH_CODE( - (data->vddgfx_voltage_table.count <= tmp), - "Too many voltage values for VDDC. Trimming to fit state table.", - phm_trim_voltage_table_to_fit_state_table(tmp, - &(data->vddgfx_voltage_table))); - - tmp = smum_get_mac_definition(hwmgr, SMU_MAX_LEVELS_VDDCI); - PP_ASSERT_WITH_CODE( - (data->vddci_voltage_table.count <= tmp), - "Too many voltage values for VDDCI. Trimming to fit state table.", - phm_trim_voltage_table_to_fit_state_table(tmp, - &(data->vddci_voltage_table))); - - tmp = smum_get_mac_definition(hwmgr, SMU_MAX_LEVELS_MVDD); - PP_ASSERT_WITH_CODE( - (data->mvdd_voltage_table.count <= tmp), - "Too many voltage values for MVDD. Trimming to fit state table.", - phm_trim_voltage_table_to_fit_state_table(tmp, - &(data->mvdd_voltage_table))); - - return 0; -} - -/** -* Programs static screed detection parameters -* -* @param hwmgr the address of the powerplay hardware manager. -* @return always 0 -*/ -static int smu7_program_static_screen_threshold_parameters( - struct pp_hwmgr *hwmgr) -{ - struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - - /* Set static screen threshold unit */ - PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, - CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD_UNIT, - data->static_screen_threshold_unit); - /* Set static screen threshold */ - PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, - CG_STATIC_SCREEN_PARAMETER, STATIC_SCREEN_THRESHOLD, - data->static_screen_threshold); - - return 0; -} - -/** -* Setup display gap for glitch free memory clock switching. -* -* @param hwmgr the address of the powerplay hardware manager. -* @return always 0 -*/ -static int smu7_enable_display_gap(struct pp_hwmgr *hwmgr) -{ - uint32_t display_gap = - cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, - ixCG_DISPLAY_GAP_CNTL); - - display_gap = PHM_SET_FIELD(display_gap, CG_DISPLAY_GAP_CNTL, - DISP_GAP, DISPLAY_GAP_IGNORE); - - display_gap = PHM_SET_FIELD(display_gap, CG_DISPLAY_GAP_CNTL, - DISP_GAP_MCHG, DISPLAY_GAP_VBLANK); - - cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, - ixCG_DISPLAY_GAP_CNTL, display_gap); - - return 0; -} - -/** -* Programs activity state transition voting clients -* -* @param hwmgr the address of the powerplay hardware manager. -* @return always 0 -*/ -static int smu7_program_voting_clients(struct pp_hwmgr *hwmgr) -{ - struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - int i; - - /* Clear reset for voting clients before enabling DPM */ - PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, - SCLK_PWRMGT_CNTL, RESET_SCLK_CNT, 0); - PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, - SCLK_PWRMGT_CNTL, RESET_BUSY_CNT, 0); - - for (i = 0; i < 8; i++) - cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, - ixCG_FREQ_TRAN_VOTING_0 + i * 4, - data->voting_rights_clients[i]); - return 0; -} - -static int smu7_clear_voting_clients(struct pp_hwmgr *hwmgr) -{ - int i; - - /* Reset voting clients before disabling DPM */ - PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, - SCLK_PWRMGT_CNTL, RESET_SCLK_CNT, 1); - PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, - SCLK_PWRMGT_CNTL, RESET_BUSY_CNT, 1); - - for (i = 0; i < 8; i++) - cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, - ixCG_FREQ_TRAN_VOTING_0 + i * 4, 0); - - return 0; -} - -/* Copy one arb setting to another and then switch the active set. - * arb_src and arb_dest is one of the MC_CG_ARB_FREQ_Fx constants. - */ -static int smu7_copy_and_switch_arb_sets(struct pp_hwmgr *hwmgr, - uint32_t arb_src, uint32_t arb_dest) -{ - uint32_t mc_arb_dram_timing; - uint32_t mc_arb_dram_timing2; - uint32_t burst_time; - uint32_t mc_cg_config; - - switch (arb_src) { - case MC_CG_ARB_FREQ_F0: - mc_arb_dram_timing = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING); - mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2); - burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0); - break; - case MC_CG_ARB_FREQ_F1: - mc_arb_dram_timing = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1); - mc_arb_dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1); - burst_time = PHM_READ_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1); - break; - default: - return -EINVAL; - } - - switch (arb_dest) { - case MC_CG_ARB_FREQ_F0: - cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING, mc_arb_dram_timing); - cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2, mc_arb_dram_timing2); - PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE0, burst_time); - break; - case MC_CG_ARB_FREQ_F1: - cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING_1, mc_arb_dram_timing); - cgs_write_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2_1, mc_arb_dram_timing2); - PHM_WRITE_FIELD(hwmgr->device, MC_ARB_BURST_TIME, STATE1, burst_time); - break; - default: - return -EINVAL; - } - - mc_cg_config = cgs_read_register(hwmgr->device, mmMC_CG_CONFIG); - mc_cg_config |= 0x0000000F; - cgs_write_register(hwmgr->device, mmMC_CG_CONFIG, mc_cg_config); - PHM_WRITE_FIELD(hwmgr->device, MC_ARB_CG, CG_ARB_REQ, arb_dest); - - return 0; -} - -static int smu7_reset_to_default(struct pp_hwmgr *hwmgr) -{ - return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ResetToDefaults, NULL); -} - -/** -* Initial switch from ARB F0->F1 -* -* @param hwmgr the address of the powerplay hardware manager. -* @return always 0 -* This function is to be called from the SetPowerState table. -*/ -static int smu7_initial_switch_from_arbf0_to_f1(struct pp_hwmgr *hwmgr) -{ - return smu7_copy_and_switch_arb_sets(hwmgr, - MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1); -} - -static int smu7_force_switch_to_arbf0(struct pp_hwmgr *hwmgr) -{ - uint32_t tmp; - - tmp = (cgs_read_ind_register(hwmgr->device, - CGS_IND_REG__SMC, ixSMC_SCRATCH9) & - 0x0000ff00) >> 8; - - if (tmp == MC_CG_ARB_FREQ_F0) - return 0; - - return smu7_copy_and_switch_arb_sets(hwmgr, - tmp, MC_CG_ARB_FREQ_F0); -} - -static int smu7_setup_default_pcie_table(struct pp_hwmgr *hwmgr) -{ - struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - - struct phm_ppt_v1_information *table_info = - (struct phm_ppt_v1_information *)(hwmgr->pptable); - struct phm_ppt_v1_pcie_table *pcie_table = NULL; - - uint32_t i, max_entry; - uint32_t tmp; - - PP_ASSERT_WITH_CODE((data->use_pcie_performance_levels || - data->use_pcie_power_saving_levels), "No pcie performance levels!", - return -EINVAL); - - if (table_info != NULL) - pcie_table = table_info->pcie_table; - - if (data->use_pcie_performance_levels && - !data->use_pcie_power_saving_levels) { - data->pcie_gen_power_saving = data->pcie_gen_performance; - data->pcie_lane_power_saving = data->pcie_lane_performance; - } else if (!data->use_pcie_performance_levels && - data->use_pcie_power_saving_levels) { - data->pcie_gen_performance = data->pcie_gen_power_saving; - data->pcie_lane_performance = data->pcie_lane_power_saving; - } - tmp = smum_get_mac_definition(hwmgr, SMU_MAX_LEVELS_LINK); - phm_reset_single_dpm_table(&data->dpm_table.pcie_speed_table, - tmp, - MAX_REGULAR_DPM_NUMBER); - - if (pcie_table != NULL) { - /* max_entry is used to make sure we reserve one PCIE level - * for boot level (fix for A+A PSPP issue). - * If PCIE table from PPTable have ULV entry + 8 entries, - * then ignore the last entry.*/ - max_entry = (tmp < pcie_table->count) ? tmp : pcie_table->count; - for (i = 1; i < max_entry; i++) { - phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, i - 1, - get_pcie_gen_support(data->pcie_gen_cap, - pcie_table->entries[i].gen_speed), - get_pcie_lane_support(data->pcie_lane_cap, - pcie_table->entries[i].lane_width)); - } - data->dpm_table.pcie_speed_table.count = max_entry - 1; - smum_update_smc_table(hwmgr, SMU_BIF_TABLE); - } else { - /* Hardcode Pcie Table */ - phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 0, - get_pcie_gen_support(data->pcie_gen_cap, - PP_Min_PCIEGen), - get_pcie_lane_support(data->pcie_lane_cap, - PP_Max_PCIELane)); - phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 1, - get_pcie_gen_support(data->pcie_gen_cap, - PP_Min_PCIEGen), - get_pcie_lane_support(data->pcie_lane_cap, - PP_Max_PCIELane)); - phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 2, - get_pcie_gen_support(data->pcie_gen_cap, - PP_Max_PCIEGen), - get_pcie_lane_support(data->pcie_lane_cap, - PP_Max_PCIELane)); - phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 3, - get_pcie_gen_support(data->pcie_gen_cap, - PP_Max_PCIEGen), - get_pcie_lane_support(data->pcie_lane_cap, - PP_Max_PCIELane)); - phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 4, - get_pcie_gen_support(data->pcie_gen_cap, - PP_Max_PCIEGen), - get_pcie_lane_support(data->pcie_lane_cap, - PP_Max_PCIELane)); - phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, 5, - get_pcie_gen_support(data->pcie_gen_cap, - PP_Max_PCIEGen), - get_pcie_lane_support(data->pcie_lane_cap, - PP_Max_PCIELane)); - - data->dpm_table.pcie_speed_table.count = 6; - } - /* Populate last level for boot PCIE level, but do not increment count. */ - if (hwmgr->chip_family == AMDGPU_FAMILY_CI) { - for (i = 0; i <= data->dpm_table.pcie_speed_table.count; i++) - phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, i, - get_pcie_gen_support(data->pcie_gen_cap, - PP_Max_PCIEGen), - data->vbios_boot_state.pcie_lane_bootup_value); - } else { - phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, - data->dpm_table.pcie_speed_table.count, - get_pcie_gen_support(data->pcie_gen_cap, - PP_Min_PCIEGen), - get_pcie_lane_support(data->pcie_lane_cap, - PP_Max_PCIELane)); - } - return 0; -} - -static int smu7_reset_dpm_tables(struct pp_hwmgr *hwmgr) -{ - struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - - memset(&(data->dpm_table), 0x00, sizeof(data->dpm_table)); - - phm_reset_single_dpm_table( - &data->dpm_table.sclk_table, - smum_get_mac_definition(hwmgr, - SMU_MAX_LEVELS_GRAPHICS), - MAX_REGULAR_DPM_NUMBER); - phm_reset_single_dpm_table( - &data->dpm_table.mclk_table, - smum_get_mac_definition(hwmgr, - SMU_MAX_LEVELS_MEMORY), MAX_REGULAR_DPM_NUMBER); - - phm_reset_single_dpm_table( - &data->dpm_table.vddc_table, - smum_get_mac_definition(hwmgr, - SMU_MAX_LEVELS_VDDC), - MAX_REGULAR_DPM_NUMBER); - phm_reset_single_dpm_table( - &data->dpm_table.vddci_table, - smum_get_mac_definition(hwmgr, - SMU_MAX_LEVELS_VDDCI), MAX_REGULAR_DPM_NUMBER); - - phm_reset_single_dpm_table( - &data->dpm_table.mvdd_table, - smum_get_mac_definition(hwmgr, - SMU_MAX_LEVELS_MVDD), - MAX_REGULAR_DPM_NUMBER); - return 0; -} -/* - * This function is to initialize all DPM state tables - * for SMU7 based on the dependency table. - * Dynamic state patching function will then trim these - * state tables to the allowed range based - * on the power policy or external client requests, - * such as UVD request, etc. - */ - -static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr) -{ - struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - struct phm_clock_voltage_dependency_table *allowed_vdd_sclk_table = - hwmgr->dyn_state.vddc_dependency_on_sclk; - struct phm_clock_voltage_dependency_table *allowed_vdd_mclk_table = - hwmgr->dyn_state.vddc_dependency_on_mclk; - struct phm_cac_leakage_table *std_voltage_table = - hwmgr->dyn_state.cac_leakage_table; - uint32_t i; - - PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table != NULL, - "SCLK dependency table is missing. This table is mandatory", return -EINVAL); - PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table->count >= 1, - "SCLK dependency table has to have is missing. This table is mandatory", return -EINVAL); - - PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table != NULL, - "MCLK dependency table is missing. This table is mandatory", return -EINVAL); - PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table->count >= 1, - "VMCLK dependency table has to have is missing. This table is mandatory", return -EINVAL); - - - /* Initialize Sclk DPM table based on allow Sclk values*/ - data->dpm_table.sclk_table.count = 0; - - for (i = 0; i < allowed_vdd_sclk_table->count; i++) { - if (i == 0 || data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count-1].value != - allowed_vdd_sclk_table->entries[i].clk) { - data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].value = - allowed_vdd_sclk_table->entries[i].clk; - data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].enabled = (i == 0) ? 1 : 0; - data->dpm_table.sclk_table.count++; - } - } - - PP_ASSERT_WITH_CODE(allowed_vdd_mclk_table != NULL, - "MCLK dependency table is missing. This table is mandatory", return -EINVAL); - /* Initialize Mclk DPM table based on allow Mclk values */ - data->dpm_table.mclk_table.count = 0; - for (i = 0; i < allowed_vdd_mclk_table->count; i++) { - if (i == 0 || data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count-1].value != - allowed_vdd_mclk_table->entries[i].clk) { - data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count].value = - allowed_vdd_mclk_table->entries[i].clk; - data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count].enabled = (i == 0) ? 1 : 0; - data->dpm_table.mclk_table.count++; - } - } - - /* Initialize Vddc DPM table based on allow Vddc values. And populate corresponding std values. */ - for (i = 0; i < allowed_vdd_sclk_table->count; i++) { - data->dpm_table.vddc_table.dpm_levels[i].value = allowed_vdd_mclk_table->entries[i].v; - data->dpm_table.vddc_table.dpm_levels[i].param1 = std_voltage_table->entries[i].Leakage; - /* param1 is for corresponding std voltage */ - data->dpm_table.vddc_table.dpm_levels[i].enabled = true; - } - - data->dpm_table.vddc_table.count = allowed_vdd_sclk_table->count; - allowed_vdd_mclk_table = hwmgr->dyn_state.vddci_dependency_on_mclk; - - if (NULL != allowed_vdd_mclk_table) { - /* Initialize Vddci DPM table based on allow Mclk values */ - for (i = 0; i < allowed_vdd_mclk_table->count; i++) { - data->dpm_table.vddci_table.dpm_levels[i].value = allowed_vdd_mclk_table->entries[i].v; - data->dpm_table.vddci_table.dpm_levels[i].enabled = true; - } - data->dpm_table.vddci_table.count = allowed_vdd_mclk_table->count; - } - - allowed_vdd_mclk_table = hwmgr->dyn_state.mvdd_dependency_on_mclk; - - if (NULL != allowed_vdd_mclk_table) { - /* - * Initialize MVDD DPM table based on allow Mclk - * values - */ - for (i = 0; i < allowed_vdd_mclk_table->count; i++) { - data->dpm_table.mvdd_table.dpm_levels[i].value = allowed_vdd_mclk_table->entries[i].v; - data->dpm_table.mvdd_table.dpm_levels[i].enabled = true; - } - data->dpm_table.mvdd_table.count = allowed_vdd_mclk_table->count; - } - - return 0; -} - -static int smu7_setup_dpm_tables_v1(struct pp_hwmgr *hwmgr) -{ - struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - struct phm_ppt_v1_information *table_info = - (struct phm_ppt_v1_information *)(hwmgr->pptable); - uint32_t i; - - struct phm_ppt_v1_clock_voltage_dependency_table *dep_sclk_table; - struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table; - - if (table_info == NULL) - return -EINVAL; - - dep_sclk_table = table_info->vdd_dep_on_sclk; - dep_mclk_table = table_info->vdd_dep_on_mclk; - - PP_ASSERT_WITH_CODE(dep_sclk_table != NULL, - "SCLK dependency table is missing.", - return -EINVAL); - PP_ASSERT_WITH_CODE(dep_sclk_table->count >= 1, - "SCLK dependency table count is 0.", - return -EINVAL); - - PP_ASSERT_WITH_CODE(dep_mclk_table != NULL, - "MCLK dependency table is missing.", - return -EINVAL); - PP_ASSERT_WITH_CODE(dep_mclk_table->count >= 1, - "MCLK dependency table count is 0", - return -EINVAL); - - /* Initialize Sclk DPM table based on allow Sclk values */ - data->dpm_table.sclk_table.count = 0; - for (i = 0; i < dep_sclk_table->count; i++) { - if (i == 0 || data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count - 1].value != - dep_sclk_table->entries[i].clk) { - - data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].value = - dep_sclk_table->entries[i].clk; - - data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].enabled = - (i == 0) ? true : false; - data->dpm_table.sclk_table.count++; - } - } - if (hwmgr->platform_descriptor.overdriveLimit.engineClock == 0) - hwmgr->platform_descriptor.overdriveLimit.engineClock = dep_sclk_table->entries[i-1].clk; - /* Initialize Mclk DPM table based on allow Mclk values */ - data->dpm_table.mclk_table.count = 0; - for (i = 0; i < dep_mclk_table->count; i++) { - if (i == 0 || data->dpm_table.mclk_table.dpm_levels - [data->dpm_table.mclk_table.count - 1].value != - dep_mclk_table->entries[i].clk) { - data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count].value = - dep_mclk_table->entries[i].clk; - data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count].enabled = - (i == 0) ? true : false; - data->dpm_table.mclk_table.count++; - } - } - - if (hwmgr->platform_descriptor.overdriveLimit.memoryClock == 0) - hwmgr->platform_descriptor.overdriveLimit.memoryClock = dep_mclk_table->entries[i-1].clk; - return 0; -} - -static int smu7_odn_initial_default_setting(struct pp_hwmgr *hwmgr) -{ - struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - struct smu7_odn_dpm_table *odn_table = &(data->odn_dpm_table); - struct phm_ppt_v1_information *table_info = - (struct phm_ppt_v1_information *)(hwmgr->pptable); - uint32_t i; - - struct phm_ppt_v1_clock_voltage_dependency_table *dep_sclk_table; - struct phm_ppt_v1_clock_voltage_dependency_table *dep_mclk_table; - struct phm_odn_performance_level *entries; - - if (table_info == NULL) - return -EINVAL; - - dep_sclk_table = table_info->vdd_dep_on_sclk; - dep_mclk_table = table_info->vdd_dep_on_mclk; - - odn_table->odn_core_clock_dpm_levels.num_of_pl = - data->golden_dpm_table.sclk_table.count; - entries = odn_table->odn_core_clock_dpm_levels.entries; - for (i=0; i<data->golden_dpm_table.sclk_table.count; i++) { - entries[i].clock = data->golden_dpm_table.sclk_table.dpm_levels[i].value; - entries[i].enabled = true; - entries[i].vddc = dep_sclk_table->entries[i].vddc; - } - - smu_get_voltage_dependency_table_ppt_v1(dep_sclk_table, - (struct phm_ppt_v1_clock_voltage_dependency_table *)&(odn_table->vdd_dependency_on_sclk)); - - odn_table->odn_memory_clock_dpm_levels.num_of_pl = - data->golden_dpm_table.mclk_table.count; - entries = odn_table->odn_memory_clock_dpm_levels.entries; - for (i=0; i<data->golden_dpm_table.mclk_table.count; i++) { - entries[i].clock = data->golden_dpm_table.mclk_table.dpm_levels[i].value; - entries[i].enabled = true; - entries[i].vddc = dep_mclk_table->entries[i].vddc; - } - - smu_get_voltage_dependency_table_ppt_v1(dep_mclk_table, - (struct phm_ppt_v1_clock_voltage_dependency_table *)&(odn_table->vdd_dependency_on_mclk)); - - return 0; -} - -static void smu7_setup_voltage_range_from_vbios(struct pp_hwmgr *hwmgr) -{ - struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - struct phm_ppt_v1_clock_voltage_dependency_table *dep_sclk_table; - struct phm_ppt_v1_information *table_info = - (struct phm_ppt_v1_information *)(hwmgr->pptable); - uint32_t min_vddc = 0; - uint32_t max_vddc = 0; - - if (!table_info) - return; - - dep_sclk_table = table_info->vdd_dep_on_sclk; - - atomctrl_get_voltage_range(hwmgr, &max_vddc, &min_vddc); - - if (min_vddc == 0 || min_vddc > 2000 - || min_vddc > dep_sclk_table->entries[0].vddc) - min_vddc = dep_sclk_table->entries[0].vddc; - - if (max_vddc == 0 || max_vddc > 2000 - || max_vddc < dep_sclk_table->entries[dep_sclk_table->count-1].vddc) - max_vddc = dep_sclk_table->entries[dep_sclk_table->count-1].vddc; - - data->odn_dpm_table.min_vddc = min_vddc; - data->odn_dpm_table.max_vddc = max_vddc; -} - -static void smu7_check_dpm_table_updated(struct pp_hwmgr *hwmgr) -{ - struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - struct smu7_odn_dpm_table *odn_table = &(data->odn_dpm_table); - struct phm_ppt_v1_information *table_info = - (struct phm_ppt_v1_information *)(hwmgr->pptable); - uint32_t i; - - struct phm_ppt_v1_clock_voltage_dependency_table *dep_table; - struct phm_ppt_v1_clock_voltage_dependency_table *odn_dep_table; - - if (table_info == NULL) - return; - - for (i = 0; i < data->dpm_table.sclk_table.count; i++) { - if (odn_table->odn_core_clock_dpm_levels.entries[i].clock != - data->dpm_table.sclk_table.dpm_levels[i].value) { - data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK; - break; - } - } - - for (i = 0; i < data->dpm_table.mclk_table.count; i++) { - if (odn_table->odn_memory_clock_dpm_levels.entries[i].clock != - data->dpm_table.mclk_table.dpm_levels[i].value) { - data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_MCLK; - break; - } - } - - dep_table = table_info->vdd_dep_on_mclk; - odn_dep_table = (struct phm_ppt_v1_clock_voltage_dependency_table *)&(odn_table->vdd_dependency_on_mclk); - - for (i = 0; i < dep_table->count; i++) { - if (dep_table->entries[i].vddc != odn_dep_table->entries[i].vddc) { - data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_VDDC | DPMTABLE_OD_UPDATE_MCLK; - return; - } - } - - dep_table = table_info->vdd_dep_on_sclk; - odn_dep_table = (struct phm_ppt_v1_clock_voltage_dependency_table *)&(odn_table->vdd_dependency_on_sclk); - for (i = 0; i < dep_table->count; i++) { - if (dep_table->entries[i].vddc != odn_dep_table->entries[i].vddc) { - data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_VDDC | DPMTABLE_OD_UPDATE_SCLK; - return; - } - } - if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_VDDC) { - data->need_update_smu7_dpm_table &= ~DPMTABLE_OD_UPDATE_VDDC; - data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_OD_UPDATE_MCLK; - } -} - -static int smu7_setup_default_dpm_tables(struct pp_hwmgr *hwmgr) -{ - struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - - smu7_reset_dpm_tables(hwmgr); - - if (hwmgr->pp_table_version == PP_TABLE_V1) - smu7_setup_dpm_tables_v1(hwmgr); - else if (hwmgr->pp_table_version == PP_TABLE_V0) - smu7_setup_dpm_tables_v0(hwmgr); - - smu7_setup_default_pcie_table(hwmgr); - - /* save a copy of the default DPM table */ - memcpy(&(data->golden_dpm_table), &(data->dpm_table), - sizeof(struct smu7_dpm_table)); - - /* initialize ODN table */ - if (hwmgr->od_enabled) { - if (data->odn_dpm_table.max_vddc) { - smu7_check_dpm_table_updated(hwmgr); - } else { - smu7_setup_voltage_range_from_vbios(hwmgr); - smu7_odn_initial_default_setting(hwmgr); - } - } - return 0; -} - -static int smu7_enable_vrhot_gpio_interrupt(struct pp_hwmgr *hwmgr) -{ - - if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, - PHM_PlatformCaps_RegulatorHot)) < |