diff options
Diffstat (limited to 'drivers/gpu/drm/amd/powerplay/smumgr')
25 files changed, 2761 insertions, 2229 deletions
diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/Makefile b/drivers/gpu/drm/amd/powerplay/smumgr/Makefile index 98e701e4f553..958755075421 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/Makefile +++ b/drivers/gpu/drm/amd/powerplay/smumgr/Makefile @@ -23,9 +23,10 @@ # Makefile for the 'smu manager' sub-component of powerplay. # It provides the smu management services for the driver. -SMU_MGR = smumgr.o cz_smumgr.o tonga_smumgr.o fiji_smumgr.o \ +SMU_MGR = smumgr.o smu8_smumgr.o tonga_smumgr.o fiji_smumgr.o \ polaris10_smumgr.o iceland_smumgr.o \ - smu7_smumgr.o vega10_smumgr.o rv_smumgr.o ci_smumgr.o + smu7_smumgr.o vega10_smumgr.o smu10_smumgr.o ci_smumgr.o \ + vega12_smumgr.o AMD_PP_SMUMGR = $(addprefix $(AMD_PP_PATH)/smumgr/,$(SMU_MGR)) diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c index 0b4a55660de4..08d000140eca 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c @@ -236,13 +236,10 @@ static int ci_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, static void ci_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr) { struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend); - struct cgs_system_info sys_info = {0}; + struct amdgpu_device *adev = hwmgr->adev; uint32_t dev_id; - sys_info.size = sizeof(struct cgs_system_info); - sys_info.info_id = CGS_SYSTEM_INFO_PCIE_DEV; - cgs_query_system_info(hwmgr->device, &sys_info); - dev_id = (uint32_t)sys_info.value; + dev_id = adev->pdev->device; switch (dev_id) { case 0x67BA: @@ -411,8 +408,7 @@ static uint8_t ci_get_sleep_divider_id_from_clock(uint32_t clock, } static int ci_populate_single_graphic_level(struct pp_hwmgr *hwmgr, - uint32_t clock, uint16_t sclk_al_threshold, - struct SMU7_Discrete_GraphicsLevel *level) + uint32_t clock, struct SMU7_Discrete_GraphicsLevel *level) { int result; struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); @@ -438,14 +434,14 @@ static int ci_populate_single_graphic_level(struct pp_hwmgr *hwmgr, clock, &level->MinVddcPhases); - level->ActivityLevel = sclk_al_threshold; + level->ActivityLevel = data->current_profile_setting.sclk_activity; level->CcPwrDynRm = 0; level->CcPwrDynRm1 = 0; level->EnabledForActivity = 0; /* this level can be used for throttling.*/ level->EnabledForThrottle = 1; - level->UpH = 0; - level->DownH = 0; + level->UpH = data->current_profile_setting.sclk_up_hyst; + level->DownH = data->current_profile_setting.sclk_down_hyst; level->VoltageDownH = 0; level->PowerThrottle = 0; @@ -492,7 +488,6 @@ static int ci_populate_all_graphic_levels(struct pp_hwmgr *hwmgr) for (i = 0; i < dpm_table->sclk_table.count; i++) { result = ci_populate_single_graphic_level(hwmgr, dpm_table->sclk_table.dpm_levels[i].value, - (uint16_t)smu_data->activity_target[i], &levels[i]); if (result) return result; @@ -860,10 +855,13 @@ static int ci_populate_smc_vddc_table(struct pp_hwmgr *hwmgr, PP_ASSERT_WITH_CODE(0 == result, "do not populate SMC VDDC voltage table", return -EINVAL); /* GPIO voltage control */ - if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->voltage_control) - table->VddcLevel[count].Smio |= data->vddc_voltage_table.entries[count].smio_low; - else + if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->voltage_control) { + table->VddcLevel[count].Smio = (uint8_t) count; + table->Smio[count] |= data->vddc_voltage_table.entries[count].smio_low; + table->SmioMaskVddcVid |= data->vddc_voltage_table.entries[count].smio_low; + } else { table->VddcLevel[count].Smio = 0; + } } CONVERT_FROM_HOST_TO_SMC_UL(table->VddcLevelCount); @@ -885,10 +883,13 @@ static int ci_populate_smc_vdd_ci_table(struct pp_hwmgr *hwmgr, &(data->vddci_voltage_table.entries[count]), &(table->VddciLevel[count])); PP_ASSERT_WITH_CODE(result == 0, "do not populate SMC VDDCI voltage table", return -EINVAL); - if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) - table->VddciLevel[count].Smio |= data->vddci_voltage_table.entries[count].smio_low; - else - table->VddciLevel[count].Smio |= 0; + if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) { + table->VddciLevel[count].Smio = (uint8_t) count; + table->Smio[count] |= data->vddci_voltage_table.entries[count].smio_low; + table->SmioMaskVddciVid |= data->vddci_voltage_table.entries[count].smio_low; + } else { + table->VddciLevel[count].Smio = 0; + } } CONVERT_FROM_HOST_TO_SMC_UL(table->VddciLevelCount); @@ -910,10 +911,13 @@ static int ci_populate_smc_mvdd_table(struct pp_hwmgr *hwmgr, &(data->mvdd_voltage_table.entries[count]), &table->MvddLevel[count]); PP_ASSERT_WITH_CODE(result == 0, "do not populate SMC mvdd voltage table", return -EINVAL); - if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) - table->MvddLevel[count].Smio |= data->mvdd_voltage_table.entries[count].smio_low; - else - table->MvddLevel[count].Smio |= 0; + if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) { + table->MvddLevel[count].Smio = (uint8_t) count; + table->Smio[count] |= data->mvdd_voltage_table.entries[count].smio_low; + table->SmioMaskMvddVid |= data->mvdd_voltage_table.entries[count].smio_low; + } else { + table->MvddLevel[count].Smio = 0; + } } CONVERT_FROM_HOST_TO_SMC_UL(table->MvddLevelCount); @@ -1217,12 +1221,12 @@ static int ci_populate_single_memory_level( memory_level->EnabledForThrottle = 1; memory_level->EnabledForActivity = 1; - memory_level->UpH = 0; - memory_level->DownH = 100; + memory_level->UpH = data->current_profile_setting.mclk_up_hyst; + memory_level->DownH = data->current_profile_setting.mclk_down_hyst; memory_level->VoltageDownH = 0; /* Indicates maximum activity level for this performance level.*/ - memory_level->ActivityLevel = (uint16_t)data->mclk_activity_target; + memory_level->ActivityLevel = data->current_profile_setting.mclk_activity; memory_level->StutterEnable = 0; memory_level->StrobeEnable = 0; memory_level->EdcReadEnable = 0; @@ -1302,7 +1306,7 @@ static int ci_populate_all_memory_levels(struct pp_hwmgr *hwmgr) struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend); struct smu7_dpm_table *dpm_table = &data->dpm_table; int result; - struct cgs_system_info sys_info = {0}; + struct amdgpu_device *adev = hwmgr->adev; uint32_t dev_id; uint32_t level_array_address = smu_data->dpm_table_start + offsetof(SMU7_Discrete_DpmTable, MemoryLevel); @@ -1323,10 +1327,7 @@ static int ci_populate_all_memory_levels(struct pp_hwmgr *hwmgr) smu_data->smc_state_table.MemoryLevel[0].EnabledForActivity = 1; - sys_info.size = sizeof(struct cgs_system_info); - sys_info.info_id = CGS_SYSTEM_INFO_PCIE_DEV; - cgs_query_system_info(hwmgr->device, &sys_info); - dev_id = (uint32_t)sys_info.value; + dev_id = adev->pdev->device; if ((dpm_table->mclk_table.count >= 2) && ((dev_id == 0x67B0) || (dev_id == 0x67B1))) { @@ -1506,7 +1507,7 @@ static int ci_populate_smc_acpi_level(struct pp_hwmgr *hwmgr, table->MemoryACPILevel.DownH = 100; table->MemoryACPILevel.VoltageDownH = 0; /* Indicates maximum activity level for this performance level.*/ - table->MemoryACPILevel.ActivityLevel = PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target); + table->MemoryACPILevel.ActivityLevel = PP_HOST_TO_SMC_US(data->current_profile_setting.mclk_activity); table->MemoryACPILevel.StutterEnable = 0; table->MemoryACPILevel.StrobeEnable = 0; @@ -1941,6 +1942,37 @@ static int ci_start_smc(struct pp_hwmgr *hwmgr) return 0; } +static int ci_populate_vr_config(struct pp_hwmgr *hwmgr, SMU7_Discrete_DpmTable *table) +{ + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + uint16_t config; + + config = VR_SVI2_PLANE_1; + table->VRConfig |= (config<<VRCONF_VDDGFX_SHIFT); + + if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->voltage_control) { + config = VR_SVI2_PLANE_2; + table->VRConfig |= config; + } else { + pr_info("VDDCshould be on SVI2 controller!"); + } + + if (SMU7_VOLTAGE_CONTROL_BY_SVID2 == data->vddci_control) { + config = VR_SVI2_PLANE_2; + table->VRConfig |= (config<<VRCONF_VDDCI_SHIFT); + } else if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->vddci_control) { + config = VR_SMIO_PATTERN_1; + table->VRConfig |= (config<<VRCONF_VDDCI_SHIFT); + } + + if (SMU7_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) { + config = VR_SMIO_PATTERN_2; + table->VRConfig |= (config<<VRCONF_MVDD_SHIFT); + } + + return 0; +} + static int ci_init_smc_table(struct pp_hwmgr *hwmgr) { int result; @@ -2064,6 +2096,11 @@ static int ci_init_smc_table(struct pp_hwmgr *hwmgr) table->PCIeBootLinkLevel = (uint8_t)data->dpm_table.pcie_speed_table.count; table->PCIeGenInterval = 1; + result = ci_populate_vr_config(hwmgr, table); + PP_ASSERT_WITH_CODE(0 == result, + "Failed to populate VRConfig setting!", return result); + data->vr_config = table->VRConfig; + ci_populate_smc_svi2_config(hwmgr, table); for (i = 0; i < SMU7_MAX_ENTRIES_SMIO; i++) @@ -2084,6 +2121,7 @@ static int ci_init_smc_table(struct pp_hwmgr *hwmgr) table->AcDcGpio = SMU7_UNUSED_GPIO_PIN; CONVERT_FROM_HOST_TO_SMC_UL(table->SystemFlags); + CONVERT_FROM_HOST_TO_SMC_UL(table->VRConfig); CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMaskVddcVid); CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMaskVddcPhase); CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMaskVddciVid); @@ -2184,7 +2222,7 @@ static int ci_thermal_setup_fan_table(struct pp_hwmgr *hwmgr) fan_table.TempRespLim = cpu_to_be16(5); - reference_clock = smu7_get_xclk(hwmgr); + reference_clock = amdgpu_asic_get_xclk((struct amdgpu_device *)hwmgr->adev); fan_table.RefreshPeriod = cpu_to_be32((hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay * reference_clock) / 1600); @@ -2728,35 +2766,8 @@ static bool ci_is_dpm_running(struct pp_hwmgr *hwmgr) return ci_is_smc_ram_running(hwmgr); } -static int ci_populate_requested_graphic_levels(struct pp_hwmgr *hwmgr, - struct amd_pp_profile *request) -{ - struct ci_smumgr *smu_data = (struct ci_smumgr *) - (hwmgr->smu_backend); - struct SMU7_Discrete_GraphicsLevel *levels = - smu_data->smc_state_table.GraphicsLevel; - uint32_t array = smu_data->dpm_table_start + - offsetof(SMU7_Discrete_DpmTable, GraphicsLevel); - uint32_t array_size = sizeof(struct SMU7_Discrete_GraphicsLevel) * - SMU7_MAX_LEVELS_GRAPHICS; - uint32_t i; - - for (i = 0; i < smu_data->smc_state_table.GraphicsDpmLevelCount; i++) { - levels[i].ActivityLevel = - cpu_to_be16(request->activity_threshold); - levels[i].EnabledForActivity = 1; - levels[i].UpH = request->up_hyst; - levels[i].DownH = request->down_hyst; - } - - return ci_copy_bytes_to_smc(hwmgr, array, (uint8_t *)levels, - array_size, SMC_RAM_END); -} - - static int ci_smu_init(struct pp_hwmgr *hwmgr) { - int i; struct ci_smumgr *ci_priv = NULL; ci_priv = kzalloc(sizeof(struct ci_smumgr), GFP_KERNEL); @@ -2764,9 +2775,6 @@ static int ci_smu_init(struct pp_hwmgr *hwmgr) if (ci_priv == NULL) return -ENOMEM; - for (i = 0; i < SMU7_MAX_LEVELS_GRAPHICS; i++) - ci_priv->activity_target[i] = 30; - hwmgr->smu_backend = ci_priv; return 0; @@ -2785,6 +2793,102 @@ static int ci_start_smu(struct pp_hwmgr *hwmgr) return 0; } +static int ci_update_dpm_settings(struct pp_hwmgr *hwmgr, + void *profile_setting) +{ + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + struct ci_smumgr *smu_data = (struct ci_smumgr *) + (hwmgr->smu_backend); + struct profile_mode_setting *setting; + struct SMU7_Discrete_GraphicsLevel *levels = + smu_data->smc_state_table.GraphicsLevel; + uint32_t array = smu_data->dpm_table_start + + offsetof(SMU7_Discrete_DpmTable, GraphicsLevel); + + uint32_t mclk_array = smu_data->dpm_table_start + + offsetof(SMU7_Discrete_DpmTable, MemoryLevel); + struct SMU7_Discrete_MemoryLevel *mclk_levels = + smu_data->smc_state_table.MemoryLevel; + uint32_t i; + uint32_t offset, up_hyst_offset, down_hyst_offset, clk_activity_offset, tmp; + + if (profile_setting == NULL) + return -EINVAL; + + setting = (struct profile_mode_setting *)profile_setting; + + if (setting->bupdate_sclk) { + if (!data->sclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_FreezeLevel); + for (i = 0; i < smu_data->smc_state_table.GraphicsDpmLevelCount; i++) { + if (levels[i].ActivityLevel != + cpu_to_be16(setting->sclk_activity)) { + levels[i].ActivityLevel = cpu_to_be16(setting->sclk_activity); + + clk_activity_offset = array + (sizeof(SMU7_Discrete_GraphicsLevel) * i) + + offsetof(SMU7_Discrete_GraphicsLevel, ActivityLevel); + offset = clk_activity_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(clk_activity_offset, tmp, levels[i].ActivityLevel, sizeof(uint16_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + + } + if (levels[i].UpH != setting->sclk_up_hyst || + levels[i].DownH != setting->sclk_down_hyst) { + levels[i].UpH = setting->sclk_up_hyst; + levels[i].DownH = setting->sclk_down_hyst; + up_hyst_offset = array + (sizeof(SMU7_Discrete_GraphicsLevel) * i) + + offsetof(SMU7_Discrete_GraphicsLevel, UpH); + down_hyst_offset = array + (sizeof(SMU7_Discrete_GraphicsLevel) * i) + + offsetof(SMU7_Discrete_GraphicsLevel, DownH); + offset = up_hyst_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(up_hyst_offset, tmp, levels[i].UpH, sizeof(uint8_t)); + tmp = phm_set_field_to_u32(down_hyst_offset, tmp, levels[i].DownH, sizeof(uint8_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + } + } + if (!data->sclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_UnfreezeLevel); + } + + if (setting->bupdate_mclk) { + if (!data->mclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_FreezeLevel); + for (i = 0; i < smu_data->smc_state_table.MemoryDpmLevelCount; i++) { + if (mclk_levels[i].ActivityLevel != + cpu_to_be16(setting->mclk_activity)) { + mclk_levels[i].ActivityLevel = cpu_to_be16(setting->mclk_activity); + + clk_activity_offset = mclk_array + (sizeof(SMU7_Discrete_MemoryLevel) * i) + + offsetof(SMU7_Discrete_MemoryLevel, ActivityLevel); + offset = clk_activity_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(clk_activity_offset, tmp, mclk_levels[i].ActivityLevel, sizeof(uint16_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + + } + if (mclk_levels[i].UpH != setting->mclk_up_hyst || + mclk_levels[i].DownH != setting->mclk_down_hyst) { + mclk_levels[i].UpH = setting->mclk_up_hyst; + mclk_levels[i].DownH = setting->mclk_down_hyst; + up_hyst_offset = mclk_array + (sizeof(SMU7_Discrete_MemoryLevel) * i) + + offsetof(SMU7_Discrete_MemoryLevel, UpH); + down_hyst_offset = mclk_array + (sizeof(SMU7_Discrete_MemoryLevel) * i) + + offsetof(SMU7_Discrete_MemoryLevel, DownH); + offset = up_hyst_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(up_hyst_offset, tmp, mclk_levels[i].UpH, sizeof(uint8_t)); + tmp = phm_set_field_to_u32(down_hyst_offset, tmp, mclk_levels[i].DownH, sizeof(uint8_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + } + } + if (!data->mclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_UnfreezeLevel); + } + return 0; +} + const struct pp_smumgr_func ci_smu_funcs = { .smu_init = ci_smu_init, .smu_fini = ci_smu_fini, @@ -2806,5 +2910,5 @@ const struct pp_smumgr_func ci_smu_funcs = { .get_mac_definition = ci_get_mac_definition, .initialize_mc_reg_table = ci_initialize_mc_reg_table, .is_dpm_running = ci_is_dpm_running, - .populate_requested_graphic_levels = ci_populate_requested_graphic_levels, + .update_dpm_settings = ci_update_dpm_settings, }; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.h index 8189cfa17c46..a8282705c569 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.h @@ -70,8 +70,6 @@ struct ci_smumgr { const struct ci_pt_defaults *power_tune_defaults; SMU7_Discrete_MCRegisters mc_regs; struct ci_mc_reg_table mc_reg_table; - uint32_t activity_target[SMU7_MAX_LEVELS_GRAPHICS]; - }; #endif diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.c deleted file mode 100644 index 4d3aff381bca..000000000000 --- a/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.c +++ /dev/null @@ -1,871 +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 <linux/delay.h> -#include <linux/gfp.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/types.h> - -#include "cgs_common.h" -#include "smu/smu_8_0_d.h" -#include "smu/smu_8_0_sh_mask.h" -#include "smu8.h" -#include "smu8_fusion.h" -#include "cz_smumgr.h" -#include "cz_ppsmc.h" -#include "smu_ucode_xfer_cz.h" -#include "gca/gfx_8_0_d.h" -#include "gca/gfx_8_0_sh_mask.h" -#include "smumgr.h" - -#define SIZE_ALIGN_32(x) (((x) + 31) / 32 * 32) - -static const enum cz_scratch_entry firmware_list[] = { - CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0, - CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G, -}; - -static int cz_smum_get_argument(struct pp_hwmgr *hwmgr) -{ - if (hwmgr == NULL || hwmgr->device == NULL) - return -EINVAL; - - return cgs_read_register(hwmgr->device, - mmSMU_MP1_SRBM2P_ARG_0); -} - -static int cz_send_msg_to_smc_async(struct pp_hwmgr *hwmgr, uint16_t msg) -{ - int result = 0; - - if (hwmgr == NULL || hwmgr->device == NULL) - return -EINVAL; - - result = PHM_WAIT_FIELD_UNEQUAL(hwmgr, - SMU_MP1_SRBM2P_RESP_0, CONTENT, 0); - if (result != 0) { - pr_err("cz_send_msg_to_smc_async (0x%04x) failed\n", msg); - return result; - } - - cgs_write_register(hwmgr->device, mmSMU_MP1_SRBM2P_RESP_0, 0); - cgs_write_register(hwmgr->device, mmSMU_MP1_SRBM2P_MSG_0, msg); - - return 0; -} - -/* Send a message to the SMC, and wait for its response.*/ -static int cz_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg) -{ - int result = 0; - - result = cz_send_msg_to_smc_async(hwmgr, msg); - if (result != 0) - return result; - - return PHM_WAIT_FIELD_UNEQUAL(hwmgr, - SMU_MP1_SRBM2P_RESP_0, CONTENT, 0); -} - -static int cz_set_smc_sram_address(struct pp_hwmgr *hwmgr, - uint32_t smc_address, uint32_t limit) -{ - if (hwmgr == NULL || hwmgr->device == NULL) - return -EINVAL; - - if (0 != (3 & smc_address)) { - pr_err("SMC address must be 4 byte aligned\n"); - return -EINVAL; - } - - if (limit <= (smc_address + 3)) { - pr_err("SMC address beyond the SMC RAM area\n"); - return -EINVAL; - } - - cgs_write_register(hwmgr->device, mmMP0PUB_IND_INDEX_0, - SMN_MP1_SRAM_START_ADDR + smc_address); - - return 0; -} - -static int cz_write_smc_sram_dword(struct pp_hwmgr *hwmgr, - uint32_t smc_address, uint32_t value, uint32_t limit) -{ - int result; - - if (hwmgr == NULL || hwmgr->device == NULL) - return -EINVAL; - - result = cz_set_smc_sram_address(hwmgr, smc_address, limit); - if (!result) - cgs_write_register(hwmgr->device, mmMP0PUB_IND_DATA_0, value); - - return result; -} - -static int cz_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, - uint16_t msg, uint32_t parameter) -{ - if (hwmgr == NULL || hwmgr->device == NULL) - return -EINVAL; - - cgs_write_register(hwmgr->device, mmSMU_MP1_SRBM2P_ARG_0, parameter); - - return cz_send_msg_to_smc(hwmgr, msg); -} - -static int cz_check_fw_load_finish(struct pp_hwmgr *hwmgr, - uint32_t firmware) -{ - int i; - uint32_t index = SMN_MP1_SRAM_START_ADDR + - SMU8_FIRMWARE_HEADER_LOCATION + - offsetof(struct SMU8_Firmware_Header, UcodeLoadStatus); - - if (hwmgr == NULL || hwmgr->device == NULL) - return -EINVAL; - - cgs_write_register(hwmgr->device, mmMP0PUB_IND_INDEX, index); - - for (i = 0; i < hwmgr->usec_timeout; i++) { - if (firmware == - (cgs_read_register(hwmgr->device, mmMP0PUB_IND_DATA) & firmware)) - break; - udelay(1); - } - - if (i >= hwmgr->usec_timeout) { - pr_err("SMU check loaded firmware failed.\n"); - return -EINVAL; - } - - return 0; -} - -static int cz_load_mec_firmware(struct pp_hwmgr *hwmgr) -{ - uint32_t reg_data; - uint32_t tmp; - int ret = 0; - struct cgs_firmware_info info = {0}; - struct cz_smumgr *cz_smu; - - if (hwmgr == NULL || hwmgr->device == NULL) - return -EINVAL; - - cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - ret = cgs_get_firmware_info(hwmgr->device, - CGS_UCODE_ID_CP_MEC, &info); - - if (ret) - return -EINVAL; - - /* Disable MEC parsing/prefetching */ - tmp = cgs_read_register(hwmgr->device, - mmCP_MEC_CNTL); - tmp = PHM_SET_FIELD(tmp, CP_MEC_CNTL, MEC_ME1_HALT, 1); - tmp = PHM_SET_FIELD(tmp, CP_MEC_CNTL, MEC_ME2_HALT, 1); - cgs_write_register(hwmgr->device, mmCP_MEC_CNTL, tmp); - - tmp = cgs_read_register(hwmgr->device, - mmCP_CPC_IC_BASE_CNTL); - - tmp = PHM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, VMID, 0); - tmp = PHM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, ATC, 0); - tmp = PHM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, CACHE_POLICY, 0); - tmp = PHM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, MTYPE, 1); - cgs_write_register(hwmgr->device, mmCP_CPC_IC_BASE_CNTL, tmp); - - reg_data = smu_lower_32_bits(info.mc_addr) & - PHM_FIELD_MASK(CP_CPC_IC_BASE_LO, IC_BASE_LO); - cgs_write_register(hwmgr->device, mmCP_CPC_IC_BASE_LO, reg_data); - - reg_data = smu_upper_32_bits(info.mc_addr) & - PHM_FIELD_MASK(CP_CPC_IC_BASE_HI, IC_BASE_HI); - cgs_write_register(hwmgr->device, mmCP_CPC_IC_BASE_HI, reg_data); - - return 0; -} - -static uint8_t cz_translate_firmware_enum_to_arg(struct pp_hwmgr *hwmgr, - enum cz_scratch_entry firmware_enum) -{ - uint8_t ret = 0; - - switch (firmware_enum) { - case CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0: - ret = UCODE_ID_SDMA0; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1: - if (hwmgr->chip_id == CHIP_STONEY) - ret = UCODE_ID_SDMA0; - else - ret = UCODE_ID_SDMA1; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE: - ret = UCODE_ID_CP_CE; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP: - ret = UCODE_ID_CP_PFP; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME: - ret = UCODE_ID_CP_ME; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1: - ret = UCODE_ID_CP_MEC_JT1; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2: - if (hwmgr->chip_id == CHIP_STONEY) - ret = UCODE_ID_CP_MEC_JT1; - else - ret = UCODE_ID_CP_MEC_JT2; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_GMCON_RENG: - ret = UCODE_ID_GMCON_RENG; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G: - ret = UCODE_ID_RLC_G; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH: - ret = UCODE_ID_RLC_SCRATCH; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM: - ret = UCODE_ID_RLC_SRM_ARAM; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM: - ret = UCODE_ID_RLC_SRM_DRAM; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_ERAM: - ret = UCODE_ID_DMCU_ERAM; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_IRAM: - ret = UCODE_ID_DMCU_IRAM; - break; - case CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING: - ret = TASK_ARG_INIT_MM_PWR_LOG; - break; - case CZ_SCRATCH_ENTRY_DATA_ID_SDMA_HALT: - case CZ_SCRATCH_ENTRY_DATA_ID_SYS_CLOCKGATING: - case CZ_SCRATCH_ENTRY_DATA_ID_SDMA_RING_REGS: - case CZ_SCRATCH_ENTRY_DATA_ID_NONGFX_REINIT: - case CZ_SCRATCH_ENTRY_DATA_ID_SDMA_START: - case CZ_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS: - ret = TASK_ARG_REG_MMIO; - break; - case CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE: - ret = TASK_ARG_INIT_CLK_TABLE; - break; - } - - return ret; -} - -static enum cgs_ucode_id cz_convert_fw_type_to_cgs(uint32_t fw_type) -{ - enum cgs_ucode_id result = CGS_UCODE_ID_MAXIMUM; - - switch (fw_type) { - case UCODE_ID_SDMA0: - result = CGS_UCODE_ID_SDMA0; - break; - case UCODE_ID_SDMA1: - result = CGS_UCODE_ID_SDMA1; - break; - case UCODE_ID_CP_CE: - result = CGS_UCODE_ID_CP_CE; - break; - case UCODE_ID_CP_PFP: - result = CGS_UCODE_ID_CP_PFP; - break; - case UCODE_ID_CP_ME: - result = CGS_UCODE_ID_CP_ME; - break; - case UCODE_ID_CP_MEC_JT1: - result = CGS_UCODE_ID_CP_MEC_JT1; - break; - case UCODE_ID_CP_MEC_JT2: - result = CGS_UCODE_ID_CP_MEC_JT2; - break; - case UCODE_ID_RLC_G: - result = CGS_UCODE_ID_RLC_G; - break; - default: - break; - } - - return result; -} - -static int cz_smu_populate_single_scratch_task( - struct pp_hwmgr *hwmgr, - enum cz_scratch_entry fw_enum, - uint8_t type, bool is_last) -{ - uint8_t i; - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr; - struct SMU_Task *task = &toc->tasks[cz_smu->toc_entry_used_count++]; - - task->type = type; - task->arg = cz_translate_firmware_enum_to_arg(hwmgr, fw_enum); - task->next = is_last ? END_OF_TASK_LIST : cz_smu->toc_entry_used_count; - - for (i = 0; i < cz_smu->scratch_buffer_length; i++) - if (cz_smu->scratch_buffer[i].firmware_ID == fw_enum) - break; - - if (i >= cz_smu->scratch_buffer_length) { - pr_err("Invalid Firmware Type\n"); - return -EINVAL; - } - - task->addr.low = cz_smu->scratch_buffer[i].mc_addr_low; - task->addr.high = cz_smu->scratch_buffer[i].mc_addr_high; - task->size_bytes = cz_smu->scratch_buffer[i].data_size; - - if (CZ_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS == fw_enum) { - struct cz_ih_meta_data *pIHReg_restore = - (struct cz_ih_meta_data *)cz_smu->scratch_buffer[i].kaddr; - pIHReg_restore->command = - METADATA_CMD_MODE0 | METADATA_PERFORM_ON_LOAD; - } - - return 0; -} - -static int cz_smu_populate_single_ucode_load_task( - struct pp_hwmgr *hwmgr, - enum cz_scratch_entry fw_enum, - bool is_last) -{ - uint8_t i; - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr; - struct SMU_Task *task = &toc->tasks[cz_smu->toc_entry_used_count++]; - - task->type = TASK_TYPE_UCODE_LOAD; - task->arg = cz_translate_firmware_enum_to_arg(hwmgr, fw_enum); - task->next = is_last ? END_OF_TASK_LIST : cz_smu->toc_entry_used_count; - - for (i = 0; i < cz_smu->driver_buffer_length; i++) - if (cz_smu->driver_buffer[i].firmware_ID == fw_enum) - break; - - if (i >= cz_smu->driver_buffer_length) { - pr_err("Invalid Firmware Type\n"); - return -EINVAL; - } - - task->addr.low = cz_smu->driver_buffer[i].mc_addr_low; - task->addr.high = cz_smu->driver_buffer[i].mc_addr_high; - task->size_bytes = cz_smu->driver_buffer[i].data_size; - - return 0; -} - -static int cz_smu_construct_toc_for_rlc_aram_save(struct pp_hwmgr *hwmgr) -{ - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - - cz_smu->toc_entry_aram = cz_smu->toc_entry_used_count; - cz_smu_populate_single_scratch_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM, - TASK_TYPE_UCODE_SAVE, true); - - return 0; -} - -static int cz_smu_initialize_toc_empty_job_list(struct pp_hwmgr *hwmgr) -{ - int i; - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr; - - for (i = 0; i < NUM_JOBLIST_ENTRIES; i++) - toc->JobList[i] = (uint8_t)IGNORE_JOB; - - return 0; -} - -static int cz_smu_construct_toc_for_vddgfx_enter(struct pp_hwmgr *hwmgr) -{ - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr; - - toc->JobList[JOB_GFX_SAVE] = (uint8_t)cz_smu->toc_entry_used_count; - cz_smu_populate_single_scratch_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH, - TASK_TYPE_UCODE_SAVE, false); - - cz_smu_populate_single_scratch_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM, - TASK_TYPE_UCODE_SAVE, true); - - return 0; -} - - -static int cz_smu_construct_toc_for_vddgfx_exit(struct pp_hwmgr *hwmgr) -{ - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - struct TOC *toc = (struct TOC *)cz_smu->toc_buffer.kaddr; - - toc->JobList[JOB_GFX_RESTORE] = (uint8_t)cz_smu->toc_entry_used_count; - - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE, false); - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP, false); - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME, false); - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false); - - if (hwmgr->chip_id == CHIP_STONEY) - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false); - else - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, false); - - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G, false); - - /* populate scratch */ - cz_smu_populate_single_scratch_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH, - TASK_TYPE_UCODE_LOAD, false); - - cz_smu_populate_single_scratch_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM, - TASK_TYPE_UCODE_LOAD, false); - - cz_smu_populate_single_scratch_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM, - TASK_TYPE_UCODE_LOAD, true); - - return 0; -} - -static int cz_smu_construct_toc_for_power_profiling(struct pp_hwmgr *hwmgr) -{ - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - - cz_smu->toc_entry_power_profiling_index = cz_smu->toc_entry_used_count; - - cz_smu_populate_single_scratch_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING, - TASK_TYPE_INITIALIZE, true); - return 0; -} - -static int cz_smu_construct_toc_for_bootup(struct pp_hwmgr *hwmgr) -{ - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - - cz_smu->toc_entry_initialize_index = cz_smu->toc_entry_used_count; - - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0, false); - if (hwmgr->chip_id != CHIP_STONEY) - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1, false); - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE, false); - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP, false); - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME, false); - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false); - if (hwmgr->chip_id != CHIP_STONEY) - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, false); - cz_smu_populate_single_ucode_load_task(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G, true); - - return 0; -} - -static int cz_smu_construct_toc_for_clock_table(struct pp_hwmgr *hwmgr) -{ - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - - cz_smu->toc_entry_clock_table = cz_smu->toc_entry_used_count; - - cz_smu_populate_single_scratch_task(hwmgr, - CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE, - TASK_TYPE_INITIALIZE, true); - - return 0; -} - -static int cz_smu_construct_toc(struct pp_hwmgr *hwmgr) -{ - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - - cz_smu->toc_entry_used_count = 0; - cz_smu_initialize_toc_empty_job_list(hwmgr); - cz_smu_construct_toc_for_rlc_aram_save(hwmgr); - cz_smu_construct_toc_for_vddgfx_enter(hwmgr); - cz_smu_construct_toc_for_vddgfx_exit(hwmgr); - cz_smu_construct_toc_for_power_profiling(hwmgr); - cz_smu_construct_toc_for_bootup(hwmgr); - cz_smu_construct_toc_for_clock_table(hwmgr); - - return 0; -} - -static int cz_smu_populate_firmware_entries(struct pp_hwmgr *hwmgr) -{ - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - uint32_t firmware_type; - uint32_t i; - int ret; - enum cgs_ucode_id ucode_id; - struct cgs_firmware_info info = {0}; - - cz_smu->driver_buffer_length = 0; - - for (i = 0; i < ARRAY_SIZE(firmware_list); i++) { - - firmware_type = cz_translate_firmware_enum_to_arg(hwmgr, - firmware_list[i]); - - ucode_id = cz_convert_fw_type_to_cgs(firmware_type); - - ret = cgs_get_firmware_info(hwmgr->device, - ucode_id, &info); - - if (ret == 0) { - cz_smu->driver_buffer[i].mc_addr_high = - smu_upper_32_bits(info.mc_addr); - - cz_smu->driver_buffer[i].mc_addr_low = - smu_lower_32_bits(info.mc_addr); - - cz_smu->driver_buffer[i].data_size = info.image_size; - - cz_smu->driver_buffer[i].firmware_ID = firmware_list[i]; - cz_smu->driver_buffer_length++; - } - } - - return 0; -} - -static int cz_smu_populate_single_scratch_entry( - struct pp_hwmgr *hwmgr, - enum cz_scratch_entry scratch_type, - uint32_t ulsize_byte, - struct cz_buffer_entry *entry) -{ - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - long long mc_addr = - ((long long)(cz_smu->smu_buffer.mc_addr_high) << 32) - | cz_smu->smu_buffer.mc_addr_low; - - uint32_t ulsize_aligned = SIZE_ALIGN_32(ulsize_byte); - - mc_addr += cz_smu->smu_buffer_used_bytes; - - entry->data_size = ulsize_byte; - entry->kaddr = (char *) cz_smu->smu_buffer.kaddr + - cz_smu->smu_buffer_used_bytes; - entry->mc_addr_low = smu_lower_32_bits(mc_addr); - entry->mc_addr_high = smu_upper_32_bits(mc_addr); - entry->firmware_ID = scratch_type; - - cz_smu->smu_buffer_used_bytes += ulsize_aligned; - - return 0; -} - -static int cz_download_pptable_settings(struct pp_hwmgr *hwmgr, void **table) -{ - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - unsigned long i; - - for (i = 0; i < cz_smu->scratch_buffer_length; i++) { - if (cz_smu->scratch_buffer[i].firmware_ID - == CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE) - break; - } - - *table = (struct SMU8_Fusion_ClkTable *)cz_smu->scratch_buffer[i].kaddr; - - cz_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SetClkTableAddrHi, - cz_smu->scratch_buffer[i].mc_addr_high); - - cz_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SetClkTableAddrLo, - cz_smu->scratch_buffer[i].mc_addr_low); - - cz_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_ExecuteJob, - cz_smu->toc_entry_clock_table); - - cz_send_msg_to_smc(hwmgr, PPSMC_MSG_ClkTableXferToDram); - - return 0; -} - -static int cz_upload_pptable_settings(struct pp_hwmgr *hwmgr) -{ - struct cz_smumgr *cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - unsigned long i; - - for (i = 0; i < cz_smu->scratch_buffer_length; i++) { - if (cz_smu->scratch_buffer[i].firmware_ID - == CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE) - break; - } - - cz_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SetClkTableAddrHi, - cz_smu->scratch_buffer[i].mc_addr_high); - - cz_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SetClkTableAddrLo, - cz_smu->scratch_buffer[i].mc_addr_low); - - cz_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_ExecuteJob, - cz_smu->toc_entry_clock_table); - - cz_send_msg_to_smc(hwmgr, PPSMC_MSG_ClkTableXferToSmu); - - return 0; -} - -static int cz_request_smu_load_fw(struct pp_hwmgr *hwmgr) -{ - struct cz_smumgr *cz_smu = (struct cz_smumgr *)(hwmgr->smu_backend); - uint32_t smc_address; - - if (!hwmgr->reload_fw) { - pr_info("skip reloading...\n"); - return 0; - } - - cz_smu_populate_firmware_entries(hwmgr); - - cz_smu_construct_toc(hwmgr); - - smc_address = SMU8_FIRMWARE_HEADER_LOCATION + - offsetof(struct SMU8_Firmware_Header, UcodeLoadStatus); - - cz_write_smc_sram_dword(hwmgr, smc_address, 0, smc_address+4); - - cz_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_DriverDramAddrHi, - cz_smu->toc_buffer.mc_addr_high); - - cz_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_DriverDramAddrLo, - cz_smu->toc_buffer.mc_addr_low); - - cz_send_msg_to_smc(hwmgr, PPSMC_MSG_InitJobs); - - cz_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_ExecuteJob, - cz_smu->toc_entry_aram); - cz_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_ExecuteJob, - cz_smu->toc_entry_power_profiling_index); - - return cz_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_ExecuteJob, - cz_smu->toc_entry_initialize_index); -} - -static int cz_start_smu(struct pp_hwmgr *hwmgr) -{ - int ret = 0; - uint32_t fw_to_check = 0; - struct cgs_firmware_info info = {0}; - uint32_t index = SMN_MP1_SRAM_START_ADDR + - SMU8_FIRMWARE_HEADER_LOCATION + - offsetof(struct SMU8_Firmware_Header, Version); - - - if (hwmgr == NULL || hwmgr->device == NULL) - return -EINVAL; - - cgs_write_register(hwmgr->device, mmMP0PUB_IND_INDEX, index); - hwmgr->smu_version = cgs_read_register(hwmgr->device, mmMP0PUB_IND_DATA); - info.version = hwmgr->smu_version >> 8; - cgs_get_firmware_info(hwmgr->device, CGS_UCODE_ID_SMU, &info); - - fw_to_check = UCODE_ID_RLC_G_MASK | - UCODE_ID_SDMA0_MASK | - UCODE_ID_SDMA1_MASK | - UCODE_ID_CP_CE_MASK | - UCODE_ID_CP_ME_MASK | - UCODE_ID_CP_PFP_MASK | - UCODE_ID_CP_MEC_JT1_MASK | - UCODE_ID_CP_MEC_JT2_MASK; - - if (hwmgr->chip_id == CHIP_STONEY) - fw_to_check &= ~(UCODE_ID_SDMA1_MASK | UCODE_ID_CP_MEC_JT2_MASK); - - ret = cz_request_smu_load_fw(hwmgr); - if (ret) - pr_err("SMU firmware load failed\n"); - - cz_check_fw_load_finish(hwmgr, fw_to_check); - - ret = cz_load_mec_firmware(hwmgr); - if (ret) - pr_err("Mec Firmware load failed\n"); - - return ret; -} - -static int cz_smu_init(struct pp_hwmgr *hwmgr) -{ - uint64_t mc_addr = 0; - int ret = 0; - struct cz_smumgr *cz_smu; - - cz_smu = kzalloc(sizeof(struct cz_smumgr), GFP_KERNEL); - if (cz_smu == NULL) - return -ENOMEM; - - hwmgr->smu_backend = cz_smu; - - cz_smu->toc_buffer.data_size = 4096; - cz_smu->smu_buffer.data_size = - ALIGN(UCODE_ID_RLC_SCRATCH_SIZE_BYTE, 32) + - ALIGN(UCODE_ID_RLC_SRM_ARAM_SIZE_BYTE, 32) + - ALIGN(UCODE_ID_RLC_SRM_DRAM_SIZE_BYTE, 32) + - ALIGN(sizeof(struct SMU8_MultimediaPowerLogData), 32) + - ALIGN(sizeof(struct SMU8_Fusion_ClkTable), 32); - - ret = smu_allocate_memory(hwmgr->device, - cz_smu->toc_buffer.data_size, - CGS_GPU_MEM_TYPE__GART_CACHEABLE, - PAGE_SIZE, - &mc_addr, - &cz_smu->toc_buffer.kaddr, - &cz_smu->toc_buffer.handle); - if (ret != 0) - return -1; - - cz_smu->toc_buffer.mc_addr_high = smu_upper_32_bits(mc_addr); - cz_smu->toc_buffer.mc_addr_low = smu_lower_32_bits(mc_addr); - - ret = smu_allocate_memory(hwmgr->device, - cz_smu->smu_buffer.data_size, - CGS_GPU_MEM_TYPE__GART_CACHEABLE, - PAGE_SIZE, - &mc_addr, - &cz_smu->smu_buffer.kaddr, - &cz_smu->smu_buffer.handle); - if (ret != 0) - return -1; - - cz_smu->smu_buffer.mc_addr_high = smu_upper_32_bits(mc_addr); - cz_smu->smu_buffer.mc_addr_low = smu_lower_32_bits(mc_addr); - - if (0 != cz_smu_populate_single_scratch_entry(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH, - UCODE_ID_RLC_SCRATCH_SIZE_BYTE, - &cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) { - pr_err("Error when Populate Firmware Entry.\n"); - return -1; - } - - if (0 != cz_smu_populate_single_scratch_entry(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM, - UCODE_ID_RLC_SRM_ARAM_SIZE_BYTE, - &cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) { - pr_err("Error when Populate Firmware Entry.\n"); - return -1; - } - if (0 != cz_smu_populate_single_scratch_entry(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM, - UCODE_ID_RLC_SRM_DRAM_SIZE_BYTE, - &cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) { - pr_err("Error when Populate Firmware Entry.\n"); - return -1; - } - - if (0 != cz_smu_populate_single_scratch_entry(hwmgr, - CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING, - sizeof(struct SMU8_MultimediaPowerLogData), - &cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) { - pr_err("Error when Populate Firmware Entry.\n"); - return -1; - } - - if (0 != cz_smu_populate_single_scratch_entry(hwmgr, - CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE, - sizeof(struct SMU8_Fusion_ClkTable), - &cz_smu->scratch_buffer[cz_smu->scratch_buffer_length++])) { - pr_err("Error when Populate Firmware Entry.\n"); - return -1; - } - - return 0; -} - -static int cz_smu_fini(struct pp_hwmgr *hwmgr) -{ - struct cz_smumgr *cz_smu; - - if (hwmgr == NULL || hwmgr->device == NULL) - return -EINVAL; - - cz_smu = (struct cz_smumgr *)hwmgr->smu_backend; - if (cz_smu) { - cgs_free_gpu_mem(hwmgr->device, - cz_smu->toc_buffer.handle); - cgs_free_gpu_mem(hwmgr->device, - cz_smu->smu_buffer.handle); - kfree(cz_smu); - } - - return 0; -} - -const struct pp_smumgr_func cz_smu_funcs = { - .smu_init = cz_smu_init, - .smu_fini = cz_smu_fini, - .start_smu = cz_start_smu, - .check_fw_load_finish = cz_check_fw_load_finish, - .request_smu_load_fw = NULL, - .request_smu_load_specific_fw = NULL, - .get_argument = cz_smum_get_argument, - .send_msg_to_smc = cz_send_msg_to_smc, - .send_msg_to_smc_with_parameter = cz_send_msg_to_smc_with_parameter, - .download_pptable_settings = cz_download_pptable_settings, - .upload_pptable_settings = cz_upload_pptable_settings, -}; - diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.h deleted file mode 100644 index 7c3a290c8957..000000000000 --- a/drivers/gpu/drm/amd/powerplay/smumgr/cz_smumgr.h +++ /dev/null @@ -1,98 +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. - * - */ -#ifndef _CZ_SMUMGR_H_ -#define _CZ_SMUMGR_H_ - - -#define MAX_NUM_FIRMWARE 8 -#define MAX_NUM_SCRATCH 11 -#define CZ_SCRATCH_SIZE_NONGFX_CLOCKGATING 1024 -#define CZ_SCRATCH_SIZE_NONGFX_GOLDENSETTING 2048 -#define CZ_SCRATCH_SIZE_SDMA_METADATA 1024 -#define CZ_SCRATCH_SIZE_IH ((2*256+1)*4) - -enum cz_scratch_entry { - CZ_SCRATCH_ENTRY_UCODE_ID_SDMA0 = 0, - CZ_SCRATCH_ENTRY_UCODE_ID_SDMA1, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_CE, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_PFP, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_ME, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, - CZ_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, - CZ_SCRATCH_ENTRY_UCODE_ID_GMCON_RENG, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_G, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM, - CZ_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM, - CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_ERAM, - CZ_SCRATCH_ENTRY_UCODE_ID_DMCU_IRAM, - CZ_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING, - CZ_SCRATCH_ENTRY_DATA_ID_SDMA_HALT, - CZ_SCRATCH_ENTRY_DATA_ID_SYS_CLOCKGATING, - CZ_SCRATCH_ENTRY_DATA_ID_SDMA_RING_REGS, - CZ_SCRATCH_ENTRY_DATA_ID_NONGFX_REINIT, - CZ_SCRATCH_ENTRY_DATA_ID_SDMA_START, - CZ_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS, - CZ_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE -}; - -struct cz_buffer_entry { - uint32_t data_size; - uint32_t mc_addr_low; - uint32_t mc_addr_high; - void *kaddr; - enum cz_scratch_entry firmware_ID; - unsigned long handle; /* as bo handle used when release bo */ -}; - -struct cz_register_index_data_pair { - uint32_t offset; - uint32_t value; -}; - -struct cz_ih_meta_data { - uint32_t command; - struct cz_register_index_data_pair register_index_value_pair[1]; -}; - -struct cz_smumgr { - uint8_t driver_buffer_length; - uint8_t scratch_buffer_length; - uint16_t toc_entry_used_count; - uint16_t toc_entry_initialize_index; - uint16_t toc_entry_power_profiling_index; - uint16_t toc_entry_aram; - uint16_t toc_entry_ih_register_restore_task_index; - uint16_t toc_entry_clock_table; - uint16_t ih_register_restore_task_size; - uint16_t smu_buffer_used_bytes; - - struct cz_buffer_entry toc_buffer; - struct cz_buffer_entry smu_buffer; - struct cz_buffer_entry firmware_buffer; - struct cz_buffer_entry driver_buffer[MAX_NUM_FIRMWARE]; - struct cz_buffer_entry meta_data_buffer[MAX_NUM_FIRMWARE]; - struct cz_buffer_entry scratch_buffer[MAX_NUM_SCRATCH]; -}; - -#endif diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c index 085d81c8b332..faef78321446 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c @@ -205,9 +205,9 @@ static int fiji_start_avfs_btc(struct pp_hwmgr *hwmgr) int result = 0; struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend); - if (0 != smu_data->avfs.avfs_btc_param) { + if (0 != smu_data->avfs_btc_param) { if (0 != smu7_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_PerformBtc, smu_data->avfs.avfs_btc_param)) { + PPSMC_MSG_PerformBtc, smu_data->avfs_btc_param)) { pr_info("[AVFS][Fiji_PerformBtc] PerformBTC SMU msg failed"); result = -EINVAL; } @@ -261,43 +261,24 @@ static int fiji_setup_graphics_level_structure(struct pp_hwmgr *hwmgr) return 0; } -static int fiji_avfs_event_mgr(struct pp_hwmgr *hwmgr, bool smu_started) +static int fiji_avfs_event_mgr(struct pp_hwmgr *hwmgr) { - struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend); + if (!hwmgr->avfs_supported) + return 0; - switch (smu_data->avfs.avfs_btc_status) { - case AVFS_BTC_COMPLETED_PREVIOUSLY: - break; + PP_ASSERT_WITH_CODE(0 == fiji_setup_graphics_level_structure(hwmgr), + "[AVFS][fiji_avfs_event_mgr] Could not Copy Graphics Level" + " table over to SMU", + return -EINVAL); + PP_ASSERT_WITH_CODE(0 == smu7_setup_pwr_virus(hwmgr), + "[AVFS][fiji_avfs_event_mgr] Could not setup " + "Pwr Virus for AVFS ", + return -EINVAL); + PP_ASSERT_WITH_CODE(0 == fiji_start_avfs_btc(hwmgr), + "[AVFS][fiji_avfs_event_mgr] Failure at " + "fiji_start_avfs_btc. AVFS Disabled", + return -EINVAL); - case AVFS_BTC_BOOT: /*Cold Boot State - Post SMU Start*/ - if (!smu_started) - break; - smu_data->avfs.avfs_btc_status = AVFS_BTC_FAILED; - PP_ASSERT_WITH_CODE(0 == fiji_setup_graphics_level_structure(hwmgr), - "[AVFS][fiji_avfs_event_mgr] Could not Copy Graphics Level" - " table over to SMU", - return -EINVAL;); - smu_data->avfs.avfs_btc_status = AVFS_BTC_VIRUS_FAIL; - PP_ASSERT_WITH_CODE(0 == smu7_setup_pwr_virus(hwmgr), - "[AVFS][fiji_avfs_event_mgr] Could not setup " - "Pwr Virus for AVFS ", - return -EINVAL;); - smu_data->avfs.avfs_btc_status = AVFS_BTC_FAILED; - PP_ASSERT_WITH_CODE(0 == fiji_start_avfs_btc(hwmgr), - "[AVFS][fiji_avfs_event_mgr] Failure at " - "fiji_start_avfs_btc. AVFS Disabled", - return -EINVAL;); - - smu_data->avfs.avfs_btc_status = AVFS_BTC_ENABLEAVFS; - break; - case AVFS_BTC_DISABLED: /* Do nothing */ - case AVFS_BTC_NOTSUPPORTED: /* Do nothing */ - case AVFS_BTC_ENABLEAVFS: - break; - default: - pr_err("AVFS failed status is %x !\n", smu_data->avfs.avfs_btc_status); - break; - } return 0; } @@ -309,8 +290,6 @@ static int fiji_start_smu(struct pp_hwmgr *hwmgr) /* Only start SMC if SMC RAM is not running */ if (!(smu7_is_smc_ram_running(hwmgr) || cgs_is_virtualization_enabled(hwmgr->device))) { - fiji_avfs_event_mgr(hwmgr, false); - /* Check if SMU is running in protected mode */ if (0 == PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, @@ -323,7 +302,8 @@ static int fiji_start_smu(struct pp_hwmgr *hwmgr) if (result) return result; } - fiji_avfs_event_mgr(hwmgr, true); + if (fiji_avfs_event_mgr(hwmgr)) + hwmgr->avfs_supported = false; } /* To initialize all clock gating before RLC loaded and running.*/ @@ -368,7 +348,6 @@ static bool fiji_is_hw_avfs_present(struct pp_hwmgr *hwmgr) static int fiji_smu_init(struct pp_hwmgr *hwmgr) { - int i; struct fiji_smumgr *fiji_priv = NULL; fiji_priv = kzalloc(sizeof(struct fiji_smumgr), GFP_KERNEL); @@ -378,11 +357,10 @@ static int fiji_smu_init(struct pp_hwmgr *hwmgr) hwmgr->smu_backend = fiji_priv; - if (smu7_init(hwmgr)) + if (smu7_init(hwmgr)) { + kfree(fiji_priv); return -EINVAL; - - for (i = 0; i < SMU73_MAX_LEVELS_GRAPHICS; i++) - fiji_priv->activity_target[i] = 30; + } return 0; } @@ -972,8 +950,7 @@ static int fiji_calculate_sclk_params(struct pp_hwmgr *hwmgr, } static int fiji_populate_single_graphic_level(struct pp_hwmgr *hwmgr, - uint32_t clock, uint16_t sclk_al_threshold, - struct SMU73_Discrete_GraphicsLevel *level) + uint32_t clock, struct SMU73_Discrete_GraphicsLevel *level) { int result; /* PP_Clocks minClocks; */ @@ -981,12 +958,18 @@ static int fiji_populate_single_graphic_level(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); + phm_ppt_v1_clock_voltage_dependency_table *vdd_dep_table = NULL; result = fiji_calculate_sclk_params(hwmgr, clock, level); + if (hwmgr->od_enabled) + vdd_dep_table = (phm_ppt_v1_clock_voltage_dependency_table *)&data->odn_dpm_table.vdd_dependency_on_sclk; + else + vdd_dep_table = table_info->vdd_dep_on_sclk; + /* populate graphics levels */ result = fiji_get_dependency_volt_by_clk(hwmgr, - table_info->vdd_dep_on_sclk, clock, + vdd_dep_table, clock, (uint32_t *)(&level->MinVoltage), &mvdd); PP_ASSERT_WITH_CODE((0 == result), "can not find VDDC voltage value for " @@ -994,13 +977,13 @@ static int fiji_populate_single_graphic_level(struct pp_hwmgr *hwmgr, return result); level->SclkFrequency = clock; - level->ActivityLevel = sclk_al_threshold; + level->ActivityLevel = data->current_profile_setting.sclk_activity; level->CcPwrDynRm = 0; level->CcPwrDynRm1 = 0; level->EnabledForActivity = 0; level->EnabledForThrottle = 1; - level->UpHyst = 10; - level->DownHyst = 0; + level->UpHyst = data->current_profile_setting.sclk_up_hyst; + level->DownHyst = data->current_profile_setting.sclk_down_hyst; level->VoltageDownHyst = 0; level->PowerThrottle = 0; @@ -1057,7 +1040,6 @@ static int fiji_populate_all_graphic_levels(struct pp_hwmgr *hwmgr) for (i = 0; i < dpm_table->sclk_table.count; i++) { result = fiji_populate_single_graphic_level(hwmgr, dpm_table->sclk_table.dpm_levels[i].value, - (uint16_t)smu_data->activity_target[i], &levels[i]); if (result) return result; @@ -1202,10 +1184,16 @@ static int fiji_populate_single_memory_level(struct pp_hwmgr *hwmgr, (struct phm_ppt_v1_information *)(hwmgr->pptable); int result = 0; uint32_t mclk_stutter_mode_threshold = 60000; + phm_ppt_v1_clock_voltage_dependency_table *vdd_dep_table = NULL; - if (table_info->vdd_dep_on_mclk) { + if (hwmgr->od_enabled) + vdd_dep_table = (phm_ppt_v1_clock_voltage_dependency_table *)&data->odn_dpm_table.vdd_dependency_on_mclk; + else + vdd_dep_table = table_info->vdd_dep_on_mclk; + + if (vdd_dep_table) { result = fiji_get_dependency_volt_by_clk(hwmgr, - table_info->vdd_dep_on_mclk, clock, + vdd_dep_table, clock, (uint32_t *)(&mem_level->MinVoltage), &mem_level->MinMvdd); PP_ASSERT_WITH_CODE((0 == result), "can not find MinVddc voltage value from memory " @@ -1214,10 +1202,10 @@ static int fiji_populate_single_memory_level(struct pp_hwmgr *hwmgr, mem_level->EnabledForThrottle = 1; mem_level->EnabledForActivity = 0; - mem_level->UpHyst = 0; - mem_level->DownHyst = 100; + mem_level->UpHyst = data->current_profile_setting.mclk_up_hyst; + mem_level->DownHyst = data->current_profile_setting.mclk_down_hyst; mem_level->VoltageDownHyst = 0; - mem_level->ActivityLevel = (uint16_t)data->mclk_activity_target; + mem_level->ActivityLevel = data->current_profile_setting.mclk_activity; mem_level->StutterEnable = false; mem_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW; @@ -1435,7 +1423,7 @@ static int fiji_populate_smc_acpi_level(struct pp_hwmgr *hwmgr, table->MemoryACPILevel.DownHyst = 100; table->MemoryACPILevel.VoltageDownHyst = 0; table->MemoryACPILevel.ActivityLevel = - PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target); + PP_HOST_TO_SMC_US(data->current_profile_setting.mclk_activity); table->MemoryACPILevel.StutterEnable = false; CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MclkFrequency); @@ -1799,7 +1787,7 @@ static int fiji_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr) phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_ClockStretcher); PP_ASSERT_WITH_CODE(false, - "Stretch Amount in PPTable not supported\n", + "Stretch Amount in PPTable not supported", return -EINVAL); } @@ -1954,44 +1942,6 @@ static int fiji_init_arb_table_index(struct pp_hwmgr *hwmgr) smu_data->smu7_data.arb_table_start, tmp, SMC_RAM_END); } -static int fiji_save_default_power_profile(struct pp_hwmgr *hwmgr) -{ - struct fiji_smumgr *data = (struct fiji_smumgr *)(hwmgr->smu_backend); - struct SMU73_Discrete_GraphicsLevel *levels = - data->smc_state_table.GraphicsLevel; - unsigned min_level = 1; - - hwmgr->default_gfx_power_profile.activity_threshold = - be16_to_cpu(levels[0].ActivityLevel); - hwmgr->default_gfx_power_profile.up_hyst = levels[0].UpHyst; - hwmgr->default_gfx_power_profile.down_hyst = levels[0].DownHyst; - hwmgr->default_gfx_power_profile.type = AMD_PP_GFX_PROFILE; - - hwmgr->default_compute_power_profile = hwmgr->default_gfx_power_profile; - hwmgr->default_compute_power_profile.type = AMD_PP_COMPUTE_PROFILE; - - /* Workaround compute SDMA instability: disable lowest SCLK - * DPM level. Optimize compute power profile: Use only highest - * 2 power levels (if more than 2 are available), Hysteresis: - * 0ms up, 5ms down - */ - if (data->smc_state_table.GraphicsDpmLevelCount > 2) - min_level = data->smc_state_table.GraphicsDpmLevelCount - 2; - else if (data->smc_state_table.GraphicsDpmLevelCount == 2) - min_level = 1; - else - min_level = 0; - hwmgr->default_compute_power_profile.min_sclk = - be32_to_cpu(levels[min_level].SclkFrequency); - hwmgr->default_compute_power_profile.up_hyst = 0; - hwmgr->default_compute_power_profile.down_hyst = 5; - - hwmgr->gfx_power_profile = hwmgr->default_gfx_power_profile; - hwmgr->compute_power_profile = hwmgr->default_compute_power_profile; - - return 0; -} - static int fiji_setup_dpm_led_config(struct pp_hwmgr *hwmgr) { pp_atomctrl_voltage_table param_led_dpm; @@ -2141,7 +2091,7 @@ static int fiji_init_smc_table(struct pp_hwmgr *hwmgr) result = fiji_populate_vr_config(hwmgr, table); PP_ASSERT_WITH_CODE(0 == result, "Failed to populate VRConfig setting!", return result); - + data->vr_config = table->VRConfig; table->ThermGpio = 17; table->SclkStepSize = 0x4000; @@ -2232,8 +2182,6 @@ static int fiji_init_smc_table(struct pp_hwmgr *hwmgr) PP_ASSERT_WITH_CODE(0 == result, "Failed to setup dpm led config", return result); - fiji_save_default_power_profile(hwmgr); - return 0; } @@ -2309,7 +2257,7 @@ static int fiji_thermal_setup_fan_table(struct pp_hwmgr *hwmgr) fan_table.TempRespLim = cpu_to_be16(5); - reference_clock = smu7_get_xclk(hwmgr); + reference_clock = amdgpu_asic_get_xclk((struct amdgpu_device *)hwmgr->adev); fan_table.RefreshPeriod = cpu_to_be32((hwmgr-> thermal_controller.advanceFanControlParameters.ulCycleDelay * @@ -2349,19 +2297,12 @@ static int fiji_thermal_setup_fan_table(struct pp_hwmgr *hwmgr) static int fiji_thermal_avfs_enable(struct pp_hwmgr *hwmgr) { - int ret; - struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend); - - if (smu_data->avfs.avfs_btc_status != AVFS_BTC_ENABLEAVFS) + if (!hwmgr->avfs_supported) return 0; - ret = smum_send_msg_to_smc(hwmgr, PPSMC_MSG_EnableAvfs); - - if (!ret) - /* If this param is not changed, this function could fire unnecessarily */ - smu_data->avfs.avfs_btc_status = AVFS_BTC_COMPLETED_PREVIOUSLY; + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_EnableAvfs); - return ret; + return 0; } static int fiji_program_mem_timing_parameters(struct pp_hwmgr *hwmgr) @@ -2688,29 +2629,100 @@ static bool fiji_is_dpm_running(struct pp_hwmgr *hwmgr) ? true : false; } -static int fiji_populate_requested_graphic_levels(struct pp_hwmgr *hwmgr, - struct amd_pp_profile *request) +static int fiji_update_dpm_settings(struct pp_hwmgr *hwmgr, + void *profile_setting) { + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); struct fiji_smumgr *smu_data = (struct fiji_smumgr *) (hwmgr->smu_backend); + struct profile_mode_setting *setting; struct SMU73_Discrete_GraphicsLevel *levels = smu_data->smc_state_table.GraphicsLevel; uint32_t array = smu_data->smu7_data.dpm_table_start + offsetof(SMU73_Discrete_DpmTable, GraphicsLevel); - uint32_t array_size = sizeof(struct SMU73_Discrete_GraphicsLevel) * - SMU73_MAX_LEVELS_GRAPHICS; + + uint32_t mclk_array = smu_data->smu7_data.dpm_table_start + + offsetof(SMU73_Discrete_DpmTable, MemoryLevel); + struct SMU73_Discrete_MemoryLevel *mclk_levels = + smu_data->smc_state_table.MemoryLevel; uint32_t i; + uint32_t offset, up_hyst_offset, down_hyst_offset, clk_activity_offset, tmp; - for (i = 0; i < smu_data->smc_state_table.GraphicsDpmLevelCount; i++) { - levels[i].ActivityLevel = - cpu_to_be16(request->activity_threshold); - levels[i].EnabledForActivity = 1; - levels[i].UpHyst = request->up_hyst; - levels[i].DownHyst = request->down_hyst; + if (profile_setting == NULL) + return -EINVAL; + + setting = (struct profile_mode_setting *)profile_setting; + + if (setting->bupdate_sclk) { + if (!data->sclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_FreezeLevel); + for (i = 0; i < smu_data->smc_state_table.GraphicsDpmLevelCount; i++) { + if (levels[i].ActivityLevel != + cpu_to_be16(setting->sclk_activity)) { + levels[i].ActivityLevel = cpu_to_be16(setting->sclk_activity); + + clk_activity_offset = array + (sizeof(SMU73_Discrete_GraphicsLevel) * i) + + offsetof(SMU73_Discrete_GraphicsLevel, ActivityLevel); + offset = clk_activity_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(clk_activity_offset, tmp, levels[i].ActivityLevel, sizeof(uint16_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + + } + if (levels[i].UpHyst != setting->sclk_up_hyst || + levels[i].DownHyst != setting->sclk_down_hyst) { + levels[i].UpHyst = setting->sclk_up_hyst; + levels[i].DownHyst = setting->sclk_down_hyst; + up_hyst_offset = array + (sizeof(SMU73_Discrete_GraphicsLevel) * i) + + offsetof(SMU73_Discrete_GraphicsLevel, UpHyst); + down_hyst_offset = array + (sizeof(SMU73_Discrete_GraphicsLevel) * i) + + offsetof(SMU73_Discrete_GraphicsLevel, DownHyst); + offset = up_hyst_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(up_hyst_offset, tmp, levels[i].UpHyst, sizeof(uint8_t)); + tmp = phm_set_field_to_u32(down_hyst_offset, tmp, levels[i].DownHyst, sizeof(uint8_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + } + } + if (!data->sclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_UnfreezeLevel); } - return smu7_copy_bytes_to_smc(hwmgr, array, (uint8_t *)levels, - array_size, SMC_RAM_END); + if (setting->bupdate_mclk) { + if (!data->mclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_FreezeLevel); + for (i = 0; i < smu_data->smc_state_table.MemoryDpmLevelCount; i++) { + if (mclk_levels[i].ActivityLevel != + cpu_to_be16(setting->mclk_activity)) { + mclk_levels[i].ActivityLevel = cpu_to_be16(setting->mclk_activity); + + clk_activity_offset = mclk_array + (sizeof(SMU73_Discrete_MemoryLevel) * i) + + offsetof(SMU73_Discrete_MemoryLevel, ActivityLevel); + offset = clk_activity_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(clk_activity_offset, tmp, mclk_levels[i].ActivityLevel, sizeof(uint16_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + + } + if (mclk_levels[i].UpHyst != setting->mclk_up_hyst || + mclk_levels[i].DownHyst != setting->mclk_down_hyst) { + mclk_levels[i].UpHyst = setting->mclk_up_hyst; + mclk_levels[i].DownHyst = setting->mclk_down_hyst; + up_hyst_offset = mclk_array + (sizeof(SMU73_Discrete_MemoryLevel) * i) + + offsetof(SMU73_Discrete_MemoryLevel, UpHyst); + down_hyst_offset = mclk_array + (sizeof(SMU73_Discrete_MemoryLevel) * i) + + offsetof(SMU73_Discrete_MemoryLevel, DownHyst); + offset = up_hyst_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(up_hyst_offset, tmp, mclk_levels[i].UpHyst, sizeof(uint8_t)); + tmp = phm_set_field_to_u32(down_hyst_offset, tmp, mclk_levels[i].DownHyst, sizeof(uint8_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + } + } + if (!data->mclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_UnfreezeLevel); + } + return 0; } const struct pp_smumgr_func fiji_smu_funcs = { @@ -2736,6 +2748,6 @@ const struct pp_smumgr_func fiji_smu_funcs = { .get_mac_definition = fiji_get_mac_definition, .initialize_mc_reg_table = fiji_initialize_mc_reg_table, .is_dpm_running = fiji_is_dpm_running, - .populate_requested_graphic_levels = fiji_populate_requested_graphic_levels, .is_hw_avfs_present = fiji_is_hw_avfs_present, + .update_dpm_settings = fiji_update_dpm_settings, }; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.h index 279647772578..6d3746268ccf 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.h @@ -43,8 +43,6 @@ struct fiji_smumgr { struct SMU73_Discrete_Ulv ulv_setting; struct SMU73_Discrete_PmFuses power_tune_table; const struct fiji_pt_defaults *power_tune_defaults; - uint32_t activity_target[SMU73_MAX_LEVELS_GRAPHICS]; - }; #endif diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c index 125312691f75..d4bb934e7334 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.c @@ -262,7 +262,6 @@ static int iceland_start_smu(struct pp_hwmgr *hwmgr) static int iceland_smu_init(struct pp_hwmgr *hwmgr) { - int i; struct iceland_smumgr *iceland_priv = NULL; iceland_priv = kzalloc(sizeof(struct iceland_smumgr), GFP_KERNEL); @@ -272,11 +271,10 @@ static int iceland_smu_init(struct pp_hwmgr *hwmgr) hwmgr->smu_backend = iceland_priv; - if (smu7_init(hwmgr)) + if (smu7_init(hwmgr)) { + kfree(iceland_priv); return -EINVAL; - - for (i = 0; i < SMU71_MAX_LEVELS_GRAPHICS; i++) - iceland_priv->activity_target[i] = 30; + } return 0; } @@ -285,13 +283,10 @@ static int iceland_smu_init(struct pp_hwmgr *hwmgr) static void iceland_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr) { struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(hwmgr->smu_backend); - struct cgs_system_info sys_info = {0}; + struct amdgpu_device *adev = hwmgr->adev; uint32_t dev_id; - sys_info.size = sizeof(struct cgs_system_info); - sys_info.info_id = CGS_SYSTEM_INFO_PCIE_DEV; - cgs_query_system_info(hwmgr->device, &sys_info); - dev_id = (uint32_t)sys_info.value; + dev_id = adev->pdev->device; switch (dev_id) { case DEVICE_ID_VI_ICELAND_M_6900: @@ -546,7 +541,7 @@ static int iceland_get_std_voltage_value_sidd(struct pp_hwmgr *hwmgr, /* SCLK/VDDC Dependency Table has to exist. */ PP_ASSERT_WITH_CODE(NULL != hwmgr->dyn_state.vddc_dependency_on_sclk, - "The SCLK/VDDC Dependency Table does not exist.\n", + "The SCLK/VDDC Dependency Table does not exist.", return -EINVAL); if (NULL == hwmgr->dyn_state.cac_leakage_table) { @@ -898,7 +893,6 @@ static int iceland_populate_phase_value_based_on_sclk(struct pp_hwmgr *hwmgr, static int iceland_populate_single_graphic_level(struct pp_hwmgr *hwmgr, uint32_t engine_clock, - uint16_t sclk_activity_level_threshold, SMU71_Discrete_GraphicsLevel *graphic_level) { int result; @@ -924,7 +918,7 @@ static int iceland_populate_single_graphic_level(struct pp_hwmgr *hwmgr, &graphic_level->MinVddcPhases); /* Indicates maximum activity level for this performance level. 50% for now*/ - graphic_level->ActivityLevel = sclk_activity_level_threshold; + graphic_level->ActivityLevel = data->current_profile_setting.sclk_activity; graphic_level->CcPwrDynRm = 0; graphic_level->CcPwrDynRm1 = 0; @@ -932,8 +926,8 @@ static int iceland_populate_single_graphic_level(struct pp_hwmgr *hwmgr, graphic_level->EnabledForActivity = 0; /* this level can be used for throttling.*/ graphic_level->EnabledForThrottle = 1; - graphic_level->UpHyst = 0; - graphic_level->DownHyst = 100; + graphic_level->UpHyst = data->current_profile_setting.sclk_up_hyst; + graphic_level->DownHyst = data->current_profile_setting.sclk_down_hyst; graphic_level->VoltageDownHyst = 0; graphic_level->PowerThrottle = 0; @@ -989,7 +983,6 @@ static int iceland_populate_all_graphic_levels(struct pp_hwmgr *hwmgr) for (i = 0; i < dpm_table->sclk_table.count; i++) { result = iceland_populate_single_graphic_level(hwmgr, dpm_table->sclk_table.dpm_levels[i].value, - (uint16_t)smu_data->activity_target[i], &(smu_data->smc_state_table.GraphicsLevel[i])); if (result != 0) return result; @@ -1275,12 +1268,12 @@ static int iceland_populate_single_memory_level( memory_level->EnabledForThrottle = 1; memory_level->EnabledForActivity = 0; - memory_level->UpHyst = 0; - memory_level->DownHyst = 100; + memory_level->UpHyst = data->current_profile_setting.mclk_up_hyst; + memory_level->DownHyst = data->current_profile_setting.mclk_down_hyst; memory_level->VoltageDownHyst = 0; /* Indicates maximum activity level for this performance level.*/ - memory_level->ActivityLevel = (uint16_t)data->mclk_activity_target; + memory_level->ActivityLevel = data->current_profile_setting.mclk_activity; memory_level->StutterEnable = 0; memory_level->StrobeEnable = 0; memory_level->EdcReadEnable = 0; @@ -1561,7 +1554,7 @@ static int iceland_populate_smc_acpi_level(struct pp_hwmgr *hwmgr, table->MemoryACPILevel.DownHyst = 100; table->MemoryACPILevel.VoltageDownHyst = 0; /* Indicates maximum activity level for this performance level.*/ - table->MemoryACPILevel.ActivityLevel = PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target); + table->MemoryACPILevel.ActivityLevel = PP_HOST_TO_SMC_US(data->current_profile_setting.mclk_activity); table->MemoryACPILevel.StutterEnable = 0; table->MemoryACPILevel.StrobeEnable = 0; @@ -2165,7 +2158,7 @@ int iceland_thermal_setup_fan_table(struct pp_hwmgr *hwmgr) fan_table.TempRespLim = cpu_to_be16(5); - reference_clock = smu7_get_xclk(hwmgr); + reference_clock = amdgpu_asic_get_xclk((struct amdgpu_device *)hwmgr->adev); fan_table.RefreshPeriod = cpu_to_be32((hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay * reference_clock) / 1600); diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.h index 802472530d34..f32c506779c9 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/smumgr/iceland_smumgr.h @@ -65,7 +65,6 @@ struct iceland_smumgr { const struct iceland_pt_defaults *power_tune_defaults; SMU71_Discrete_MCRegisters mc_regs; struct iceland_mc_reg_table mc_reg_table; - uint32_t activity_target[SMU71_MAX_LEVELS_GRAPHICS]; }; #endif diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c index cdb47657b567..997a777dd35b 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c @@ -99,13 +99,13 @@ static int polaris10_perform_btc(struct pp_hwmgr *hwmgr) int result = 0; struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend); - if (0 != smu_data->avfs.avfs_btc_param) { - if (0 != smu7_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_PerformBtc, smu_data->avfs.avfs_btc_param)) { + if (0 != smu_data->avfs_btc_param) { + if (0 != smu7_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_PerformBtc, smu_data->avfs_btc_param)) { pr_info("[AVFS][SmuPolaris10_PerformBtc] PerformBTC SMU msg failed"); result = -1; } } - if (smu_data->avfs.avfs_btc_param > 1) { + if (smu_data->avfs_btc_param > 1) { /* Soft-Reset to reset the engine before loading uCode */ /* halt */ cgs_write_register(hwmgr->device, mmCP_MEC_CNTL, 0x50000000); @@ -172,47 +172,28 @@ static int polaris10_setup_graphics_level_structure(struct pp_hwmgr *hwmgr) } -static int -polaris10_avfs_event_mgr(struct pp_hwmgr *hwmgr, bool SMU_VFT_INTACT) +static int polaris10_avfs_event_mgr(struct pp_hwmgr *hwmgr) { struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend); - switch (smu_data->avfs.avfs_btc_status) { - case AVFS_BTC_COMPLETED_PREVIOUSLY: - break; - - case AVFS_BTC_BOOT: /* Cold Boot State - Post SMU Start */ - - smu_data->avfs.avfs_btc_status = AVFS_BTC_DPMTABLESETUP_FAILED; - PP_ASSERT_WITH_CODE(0 == polaris10_setup_graphics_level_structure(hwmgr), - "[AVFS][Polaris10_AVFSEventMgr] Could not Copy Graphics Level table over to SMU", - return -EINVAL); - - if (smu_data->avfs.avfs_btc_param > 1) { - pr_info("[AVFS][Polaris10_AVFSEventMgr] AC BTC has not been successfully verified on Fiji. There may be in this setting."); - smu_data->avfs.avfs_btc_status = AVFS_BTC_VIRUS_FAIL; - PP_ASSERT_WITH_CODE(0 == smu7_setup_pwr_virus(hwmgr), - "[AVFS][Polaris10_AVFSEventMgr] Could not setup Pwr Virus for AVFS ", - return -EINVAL); - } - - smu_data->avfs.avfs_btc_status = AVFS_BTC_FAILED; - PP_ASSERT_WITH_CODE(0 == polaris10_perform_btc(hwmgr), - "[AVFS][Polaris10_AVFSEventMgr] Failure at SmuPolaris10_PerformBTC. AVFS Disabled", - return -EINVAL); - smu_data->avfs.avfs_btc_status = AVFS_BTC_ENABLEAVFS; - break; + if (!hwmgr->avfs_supported) + return 0; - case AVFS_BTC_DISABLED: - case AVFS_BTC_ENABLEAVFS: - case AVFS_BTC_NOTSUPPORTED: - break; + PP_ASSERT_WITH_CODE(0 == polaris10_setup_graphics_level_structure(hwmgr), + "[AVFS][Polaris10_AVFSEventMgr] Could not Copy Graphics Level table over to SMU", + return -EINVAL); - default: - pr_err("AVFS failed status is %x!\n", smu_data->avfs.avfs_btc_status); - break; + if (smu_data->avfs_btc_param > 1) { + pr_info("[AVFS][Polaris10_AVFSEventMgr] AC BTC has not been successfully verified on Fiji. There may be in this setting."); + PP_ASSERT_WITH_CODE(0 == smu7_setup_pwr_virus(hwmgr), + "[AVFS][Polaris10_AVFSEventMgr] Could not setup Pwr Virus for AVFS ", + return -EINVAL); } + PP_ASSERT_WITH_CODE(0 == polaris10_perform_btc(hwmgr), + "[AVFS][Polaris10_AVFSEventMgr] Failure at SmuPolaris10_PerformBTC. AVFS Disabled", + return -EINVAL); + return 0; } @@ -312,11 +293,10 @@ static int polaris10_start_smu(struct pp_hwmgr *hwmgr) { int result = 0; struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(hwmgr->smu_backend); - bool SMU_VFT_INTACT; /* Only start SMC if SMC RAM is not running */ - if (!smu7_is_smc_ram_running(hwmgr)) { - SMU_VFT_INTACT = false; + if (!(smu7_is_smc_ram_running(hwmgr) + || cgs_is_virtualization_enabled(hwmgr->device))) { smu_data->protected_mode = (uint8_t) (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SMU_FIRMWARE, SMU_MODE)); smu_data->smu7_data.security_hard_key = (uint8_t) (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SMU_FIRMWARE, SMU_SEL)); @@ -337,11 +317,9 @@ static int polaris10_start_smu(struct pp_hwmgr *hwmgr) if (result != 0) PP_ASSERT_WITH_CODE(0, "Failed to load SMU ucode.", return result); - polaris10_avfs_event_mgr(hwmgr, true); - } else - SMU_VFT_INTACT = true; /*Driver went offline but SMU was still alive and contains the VFT table */ + polaris10_avfs_event_mgr(hwmgr); + } - polaris10_avfs_event_mgr(hwmgr, SMU_VFT_INTACT); /* Setup SoftRegsStart here for register lookup in case DummyBackEnd is used and ProcessFirmwareHeader is not executed */ smu7_read_smc_sram_dword(hwmgr, SMU7_FIRMWARE_HEADER_LOCATION + offsetof(SMU74_Firmware_Header, SoftRegisters), &(smu_data->smu7_data.soft_regs_start), 0x40000); @@ -366,7 +344,6 @@ static bool polaris10_is_hw_avfs_present(struct pp_hwmgr *hwmgr) static int polaris10_smu_init(struct pp_hwmgr *hwmgr) { struct polaris10_smumgr *smu_data; - int i; smu_data = kzalloc(sizeof(struct polaris10_smumgr), GFP_KERNEL); if (smu_data == NULL) @@ -374,11 +351,10 @@ static int polaris10_smu_init(struct pp_hwmgr *hwmgr) hwmgr->smu_backend = smu_data; - if (smu7_init(hwmgr)) + if (smu7_init(hwmgr)) { + kfree(smu_data); return -EINVAL; - - for (i = 0; i < SMU74_MAX_LEVELS_GRAPHICS; i++) - smu_data->activity_target[i] = PPPOLARIS10_TARGETACTIVITY_DFLT; + } return 0; } @@ -837,7 +813,7 @@ static void polaris10_get_sclk_range_table(struct pp_hwmgr *hwmgr, struct pp_atom_ctrl_sclk_range_table range_table_from_vbios = { { {0} } }; - ref_clk = smu7_get_xclk(hwmgr); + ref_clk = amdgpu_asic_get_xclk((struct amdgpu_device *)hwmgr->adev); if (0 == atomctrl_get_smc_sclk_range_table(hwmgr, &range_table_from_vbios)) { for (i = 0; i < NUM_SCLK_RANGE; i++) { @@ -902,7 +878,7 @@ static int polaris10_calculate_sclk_params(struct pp_hwmgr *hwmgr, return result; } - ref_clock = smu7_get_xclk(hwmgr); + ref_clock = amdgpu_asic_get_xclk((struct amdgpu_device *)hwmgr->adev); for (i = 0; i < NUM_SCLK_RANGE; i++) { if (clock > smu_data->range_table[i].trans_lower_frequency @@ -938,8 +914,7 @@ static int polaris10_calculate_sclk_params(struct pp_hwmgr *hwmgr, } static int polaris10_populate_single_graphic_level(struct pp_hwmgr *hwmgr, - uint32_t clock, uint16_t sclk_al_threshold, - struct SMU74_Discrete_GraphicsLevel *level) + uint32_t clock, struct SMU74_Discrete_GraphicsLevel *level) { int result; /* PP_Clocks minClocks; */ @@ -948,26 +923,32 @@ static int polaris10_populate_single_graphic_level(struct pp_hwmgr *hwmgr, struct phm_ppt_v1_information *table_info = (struct phm_ppt_v1_information *)(hwmgr->pptable); SMU_SclkSetting curr_sclk_setting = { 0 }; + phm_ppt_v1_clock_voltage_dependency_table *vdd_dep_table = NULL; result = polaris10_calculate_sclk_params(hwmgr, clock, &curr_sclk_setting); + if (hwmgr->od_enabled) + vdd_dep_table = (phm_ppt_v1_clock_voltage_dependency_table *)&data->odn_dpm_table.vdd_dependency_on_sclk; + else + vdd_dep_table = table_info->vdd_dep_on_sclk; + /* populate graphics levels */ result = polaris10_get_dependency_volt_by_clk(hwmgr, - table_info->vdd_dep_on_sclk, clock, + vdd_dep_table, clock, &level->MinVoltage, &mvdd); PP_ASSERT_WITH_CODE((0 == result), "can not find VDDC voltage value for " "VDDC engine clock dependency table", return result); - level->ActivityLevel = sclk_al_threshold; + level->ActivityLevel = data->current_profile_setting.sclk_activity; level->CcPwrDynRm = 0; level->CcPwrDynRm1 = 0; level->EnabledForActivity = 0; level->EnabledForThrottle = 1; - level->UpHyst = 10; - level->DownHyst = 0; + level->UpHyst = data->current_profile_setting.sclk_up_hyst; + level->DownHyst = data->current_profile_setting.sclk_down_hyst; level->VoltageDownHyst = 0; level->PowerThrottle = 0; data->display_timing.min_clock_in_sr = hwmgr->display_config.min_core_set_clock_in_sr; @@ -1031,7 +1012,6 @@ static int polaris10_populate_all_graphic_levels(struct pp_hwmgr *hwmgr) result = polaris10_populate_single_graphic_level(hwmgr, dpm_table->sclk_table.dpm_levels[i].value, - (uint16_t)smu_data->activity_target[i], &(smu_data->smc_state_table.GraphicsLevel[i])); if (result) return result; @@ -1107,12 +1087,18 @@ static int polaris10_populate_single_memory_level(struct pp_hwmgr *hwmgr, int result = 0; struct cgs_display_info info = {0, 0, NULL}; uint32_t mclk_stutter_mode_threshold = 40000; + phm_ppt_v1_clock_voltage_dependency_table *vdd_dep_table = NULL; cgs_get_active_displays_info(hwmgr->device, &info); - if (table_info->vdd_dep_on_mclk) { + if (hwmgr->od_enabled) + vdd_dep_table = (phm_ppt_v1_clock_voltage_dependency_table *)&data->odn_dpm_table.vdd_dependency_on_mclk; + else + vdd_dep_table = table_info->vdd_dep_on_mclk; + + if (vdd_dep_table) { result = polaris10_get_dependency_volt_by_clk(hwmgr, - table_info->vdd_dep_on_mclk, clock, + vdd_dep_table, clock, &mem_level->MinVoltage, &mem_level->MinMvdd); PP_ASSERT_WITH_CODE((0 == result), "can not find MinVddc voltage value from memory " @@ -1122,10 +1108,10 @@ static int polaris10_populate_single_memory_level(struct pp_hwmgr *hwmgr, mem_level->MclkFrequency = clock; mem_level->EnabledForThrottle = 1; mem_level->EnabledForActivity = 0; - mem_level->UpHyst = 0; - mem_level->DownHyst = 100; + mem_level->UpHyst = data->current_profile_setting.mclk_up_hyst; + mem_level->DownHyst = data->current_profile_setting.mclk_down_hyst; mem_level->VoltageDownHyst = 0; - mem_level->ActivityLevel = (uint16_t)data->mclk_activity_target; + mem_level->ActivityLevel = data->current_profile_setting.mclk_activity; mem_level->StutterEnable = false; mem_level->DisplayWatermark = PPSMC_DISPLAY_WATERMARK_LOW; @@ -1306,7 +1292,7 @@ static int polaris10_populate_smc_acpi_level(struct pp_hwmgr *hwmgr, table->MemoryACPILevel.DownHyst = 100; table->MemoryACPILevel.VoltageDownHyst = 0; table->MemoryACPILevel.ActivityLevel = - PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target); + PP_HOST_TO_SMC_US(data->current_profile_setting.mclk_activity); CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MclkFrequency); CONVERT_FROM_HOST_TO_SMC_UL(table->MemoryACPILevel.MinVoltage); @@ -1652,7 +1638,7 @@ static int polaris10_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr) phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_ClockStretcher); PP_ASSERT_WITH_CODE(false, - "Stretch Amount in PPTable not supported\n", + "Stretch Amount in PPTable not supported", return -EINVAL); } @@ -1726,8 +1712,8 @@ static int polaris10_populate_avfs_parameters(struct pp_hwmgr *hwmgr) table_info->vdd_dep_on_sclk; - if (((struct smu7_smumgr *)smu_data)->avfs.avfs_btc_status == AVFS_BTC_NOTSUPPORTED) - return result; + if (!hwmgr->avfs_supported) + return 0; result = atomctrl_get_avfs_information(hwmgr, &avfs_params); @@ -1834,42 +1820,6 @@ static void polaris10_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr) } -static void polaris10_save_default_power_profile(struct pp_hwmgr *hwmgr) -{ - struct polaris10_smumgr *data = (struct polaris10_smumgr *)(hwmgr->smu_backend); - struct SMU74_Discrete_GraphicsLevel *levels = - data->smc_state_table.GraphicsLevel; - unsigned min_level = 1; - - hwmgr->default_gfx_power_profile.activity_threshold = - be16_to_cpu(levels[0].ActivityLevel); - hwmgr->default_gfx_power_profile.up_hyst = levels[0].UpHyst; - hwmgr->default_gfx_power_profile.down_hyst = levels[0].DownHyst; - hwmgr->default_gfx_power_profile.type = AMD_PP_GFX_PROFILE; - - hwmgr->default_compute_power_profile = hwmgr->default_gfx_power_profile; - hwmgr->default_compute_power_profile.type = AMD_PP_COMPUTE_PROFILE; - - /* Workaround compute SDMA instability: disable lowest SCLK - * DPM level. Optimize compute power profile: Use only highest - * 2 power levels (if more than 2 are available), Hysteresis: - * 0ms up, 5ms down - */ - if (data->smc_state_table.GraphicsDpmLevelCount > 2) - min_level = data->smc_state_table.GraphicsDpmLevelCount - 2; - else if (data->smc_state_table.GraphicsDpmLevelCount == 2) - min_level = 1; - else - min_level = 0; - hwmgr->default_compute_power_profile.min_sclk = - be32_to_cpu(levels[min_level].SclkSetting.SclkFrequency); - hwmgr->default_compute_power_profile.up_hyst = 0; - hwmgr->default_compute_power_profile.down_hyst = 5; - - hwmgr->gfx_power_profile = hwmgr->default_gfx_power_profile; - hwmgr->compute_power_profile = hwmgr->default_compute_power_profile; -} - static int polaris10_init_smc_table(struct pp_hwmgr *hwmgr) { int result; @@ -1991,7 +1941,7 @@ static int polaris10_init_smc_table(struct pp_hwmgr *hwmgr) result = polaris10_populate_vr_config(hwmgr, table); PP_ASSERT_WITH_CODE(0 == result, "Failed to populate VRConfig setting!", return result); - + hw_data->vr_config = table->VRConfig; table->ThermGpio = 17; table->SclkStepSize = 0x4000; @@ -2084,8 +2034,6 @@ static int polaris10_init_smc_table(struct pp_hwmgr *hwmgr) PP_ASSERT_WITH_CODE(0 == result, "Failed to populate PM fuses to SMC memory!", return result); - polaris10_save_default_power_profile(hwmgr); - return 0; } @@ -2102,24 +2050,17 @@ static int polaris10_program_mem_timing_parameters(struct pp_hwmgr *hwmgr) int polaris10_thermal_avfs_enable(struct pp_hwmgr *hwmgr) { - int ret; - struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend); struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - if (smu_data->avfs.avfs_btc_status == AVFS_BTC_NOTSUPPORTED) + if (!hwmgr->avfs_supported) return 0; - ret = smum_send_msg_to_smc_with_parameter(hwmgr, + smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetGBDroopSettings, data->avfs_vdroop_override_setting); - ret = (smum_send_msg_to_smc(hwmgr, PPSMC_MSG_EnableAvfs) == 0) ? - 0 : -1; - - if (!ret) - /* If this param is not changed, this function could fire unnecessarily */ - smu_data->avfs.avfs_btc_status = AVFS_BTC_COMPLETED_PREVIOUSLY; + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_EnableAvfs); - return ret; + return 0; } static int polaris10_thermal_setup_fan_table(struct pp_hwmgr *hwmgr) @@ -2193,7 +2134,7 @@ static int polaris10_thermal_setup_fan_table(struct pp_hwmgr *hwmgr) fan_table.TempRespLim = cpu_to_be16(5); - reference_clock = smu7_get_xclk(hwmgr); + reference_clock = amdgpu_asic_get_xclk((struct amdgpu_device *)hwmgr->adev); fan_table.RefreshPeriod = cpu_to_be32((hwmgr-> thermal_controller.advanceFanControlParameters.ulCycleDelay * @@ -2544,29 +2485,100 @@ static bool polaris10_is_dpm_running(struct pp_hwmgr *hwmgr) ? true : false; } -static int polaris10_populate_requested_graphic_levels(struct pp_hwmgr *hwmgr, - struct amd_pp_profile *request) +static int polaris10_update_dpm_settings(struct pp_hwmgr *hwmgr, + void *profile_setting) { + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *) (hwmgr->smu_backend); + struct profile_mode_setting *setting; struct SMU74_Discrete_GraphicsLevel *levels = smu_data->smc_state_table.GraphicsLevel; uint32_t array = smu_data->smu7_data.dpm_table_start + offsetof(SMU74_Discrete_DpmTable, GraphicsLevel); - uint32_t array_size = sizeof(struct SMU74_Discrete_GraphicsLevel) * - SMU74_MAX_LEVELS_GRAPHICS; + + uint32_t mclk_array = smu_data->smu7_data.dpm_table_start + + offsetof(SMU74_Discrete_DpmTable, MemoryLevel); + struct SMU74_Discrete_MemoryLevel *mclk_levels = + smu_data->smc_state_table.MemoryLevel; uint32_t i; + uint32_t offset, up_hyst_offset, down_hyst_offset, clk_activity_offset, tmp; - for (i = 0; i < smu_data->smc_state_table.GraphicsDpmLevelCount; i++) { - levels[i].ActivityLevel = - cpu_to_be16(request->activity_threshold); - levels[i].EnabledForActivity = 1; - levels[i].UpHyst = request->up_hyst; - levels[i].DownHyst = request->down_hyst; + if (profile_setting == NULL) + return -EINVAL; + + setting = (struct profile_mode_setting *)profile_setting; + + if (setting->bupdate_sclk) { + if (!data->sclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_FreezeLevel); + for (i = 0; i < smu_data->smc_state_table.GraphicsDpmLevelCount; i++) { + if (levels[i].ActivityLevel != + cpu_to_be16(setting->sclk_activity)) { + levels[i].ActivityLevel = cpu_to_be16(setting->sclk_activity); + + clk_activity_offset = array + (sizeof(SMU74_Discrete_GraphicsLevel) * i) + + offsetof(SMU74_Discrete_GraphicsLevel, ActivityLevel); + offset = clk_activity_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(clk_activity_offset, tmp, levels[i].ActivityLevel, sizeof(uint16_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + + } + if (levels[i].UpHyst != setting->sclk_up_hyst || + levels[i].DownHyst != setting->sclk_down_hyst) { + levels[i].UpHyst = setting->sclk_up_hyst; + levels[i].DownHyst = setting->sclk_down_hyst; + up_hyst_offset = array + (sizeof(SMU74_Discrete_GraphicsLevel) * i) + + offsetof(SMU74_Discrete_GraphicsLevel, UpHyst); + down_hyst_offset = array + (sizeof(SMU74_Discrete_GraphicsLevel) * i) + + offsetof(SMU74_Discrete_GraphicsLevel, DownHyst); + offset = up_hyst_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(up_hyst_offset, tmp, levels[i].UpHyst, sizeof(uint8_t)); + tmp = phm_set_field_to_u32(down_hyst_offset, tmp, levels[i].DownHyst, sizeof(uint8_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + } + } + if (!data->sclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_UnfreezeLevel); } - return smu7_copy_bytes_to_smc(hwmgr, array, (uint8_t *)levels, - array_size, SMC_RAM_END); + if (setting->bupdate_mclk) { + if (!data->mclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_FreezeLevel); + for (i = 0; i < smu_data->smc_state_table.MemoryDpmLevelCount; i++) { + if (mclk_levels[i].ActivityLevel != + cpu_to_be16(setting->mclk_activity)) { + mclk_levels[i].ActivityLevel = cpu_to_be16(setting->mclk_activity); + + clk_activity_offset = mclk_array + (sizeof(SMU74_Discrete_MemoryLevel) * i) + + offsetof(SMU74_Discrete_MemoryLevel, ActivityLevel); + offset = clk_activity_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(clk_activity_offset, tmp, mclk_levels[i].ActivityLevel, sizeof(uint16_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + + } + if (mclk_levels[i].UpHyst != setting->mclk_up_hyst || + mclk_levels[i].DownHyst != setting->mclk_down_hyst) { + mclk_levels[i].UpHyst = setting->mclk_up_hyst; + mclk_levels[i].DownHyst = setting->mclk_down_hyst; + up_hyst_offset = mclk_array + (sizeof(SMU74_Discrete_MemoryLevel) * i) + + offsetof(SMU74_Discrete_MemoryLevel, UpHyst); + down_hyst_offset = mclk_array + (sizeof(SMU74_Discrete_MemoryLevel) * i) + + offsetof(SMU74_Discrete_MemoryLevel, DownHyst); + offset = up_hyst_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(up_hyst_offset, tmp, mclk_levels[i].UpHyst, sizeof(uint8_t)); + tmp = phm_set_field_to_u32(down_hyst_offset, tmp, mclk_levels[i].DownHyst, sizeof(uint8_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + } + } + if (!data->mclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_UnfreezeLevel); + } + return 0; } const struct pp_smumgr_func polaris10_smu_funcs = { @@ -2591,6 +2603,6 @@ const struct pp_smumgr_func polaris10_smu_funcs = { .populate_all_memory_levels = polaris10_populate_all_memory_levels, .get_mac_definition = polaris10_get_mac_definition, .is_dpm_running = polaris10_is_dpm_running, - .populate_requested_graphic_levels = polaris10_populate_requested_graphic_levels, .is_hw_avfs_present = polaris10_is_hw_avfs_present, + .update_dpm_settings = polaris10_update_dpm_settings, }; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.h index 5e19c24b0561..1ec425df9eda 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.h @@ -59,7 +59,6 @@ struct polaris10_smumgr { struct SMU74_Discrete_PmFuses power_tune_table; struct polaris10_range_table range_table[NUM_SCLK_RANGE]; const struct polaris10_pt_defaults *power_tune_defaults; - uint32_t activity_target[SMU74_MAX_LEVELS_GRAPHICS]; uint32_t bif_sclk_table[SMU74_MAX_LEVELS_LINK]; }; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/rv_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/rv_smumgr.c deleted file mode 100644 index 2d662b44af54..000000000000 --- a/drivers/gpu/drm/amd/powerplay/smumgr/rv_smumgr.c +++ /dev/null @@ -1,406 +0,0 @@ -/* - * Copyright 2016 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 "smumgr.h" -#include "rv_inc.h" -#include "pp_soc15.h" -#include "rv_smumgr.h" -#include "ppatomctrl.h" -#include "rv_ppsmc.h" -#include "smu10_driver_if.h" -#include "smu10.h" -#include "ppatomctrl.h" -#include "pp_debug.h" -#include "smu_ucode_xfer_vi.h" -#include "smu7_smumgr.h" - -#define VOLTAGE_SCALE 4 - -#define BUFFER_SIZE 80000 -#define MAX_STRING_SIZE 15 -#define BUFFER_SIZETWO 131072 - -#define MP0_Public 0x03800000 -#define MP0_SRAM 0x03900000 -#define MP1_Public 0x03b00000 -#define MP1_SRAM 0x03c00004 - -#define smnMP1_FIRMWARE_FLAGS 0x3010028 - - -bool rv_is_smc_ram_running(struct pp_hwmgr *hwmgr) -{ - uint32_t mp1_fw_flags, reg; - - reg = soc15_get_register_offset(NBIF_HWID, 0, - mmPCIE_INDEX2_BASE_IDX, mmPCIE_INDEX2); - - cgs_write_register(hwmgr->device, reg, - (MP1_Public | (smnMP1_FIRMWARE_FLAGS & 0xffffffff))); - - reg = soc15_get_register_offset(NBIF_HWID, 0, - mmPCIE_DATA2_BASE_IDX, mmPCIE_DATA2); - - mp1_fw_flags = cgs_read_register(hwmgr->device, reg); - - if (mp1_fw_flags & MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK) - return true; - - return false; -} - -static uint32_t rv_wait_for_response(struct pp_hwmgr *hwmgr) -{ - uint32_t reg; - - if (!rv_is_smc_ram_running(hwmgr)) - return -EINVAL; - - reg = soc15_get_register_offset(MP1_HWID, 0, - mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90); - - phm_wait_for_register_unequal(hwmgr, reg, - 0, MP1_C2PMSG_90__CONTENT_MASK); - - return cgs_read_register(hwmgr->device, reg); -} - -int rv_send_msg_to_smc_without_waiting(struct pp_hwmgr *hwmgr, - uint16_t msg) -{ - uint32_t reg; - - if (!rv_is_smc_ram_running(hwmgr)) - return -EINVAL; - - reg = soc15_get_register_offset(MP1_HWID, 0, - mmMP1_SMN_C2PMSG_66_BASE_IDX, mmMP1_SMN_C2PMSG_66); - cgs_write_register(hwmgr->device, reg, msg); - - return 0; -} - -int rv_read_arg_from_smc(struct pp_hwmgr *hwmgr, uint32_t *arg) -{ - uint32_t reg; - - reg = soc15_get_register_offset(MP1_HWID, 0, - mmMP1_SMN_C2PMSG_82_BASE_IDX, mmMP1_SMN_C2PMSG_82); - - *arg = cgs_read_register(hwmgr->device, reg); - - return 0; -} - -int rv_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg) -{ - uint32_t reg; - - rv_wait_for_response(hwmgr); - - reg = soc15_get_register_offset(MP1_HWID, 0, - mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90); - cgs_write_register(hwmgr->device, reg, 0); - - rv_send_msg_to_smc_without_waiting(hwmgr, msg); - - if (rv_wait_for_response(hwmgr) == 0) - printk("Failed to send Message %x.\n", msg); - - return 0; -} - - -int rv_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, - uint16_t msg, uint32_t parameter) -{ - uint32_t reg; - - rv_wait_for_response(hwmgr); - - reg = soc15_get_register_offset(MP1_HWID, 0, - mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90); - cgs_write_register(hwmgr->device, reg, 0); - - reg = soc15_get_register_offset(MP1_HWID, 0, - mmMP1_SMN_C2PMSG_82_BASE_IDX, mmMP1_SMN_C2PMSG_82); - cgs_write_register(hwmgr->device, reg, parameter); - - rv_send_msg_to_smc_without_waiting(hwmgr, msg); - - - if (rv_wait_for_response(hwmgr) == 0) - printk("Failed to send Message %x.\n", msg); - - return 0; -} - -int rv_copy_table_from_smc(struct pp_hwmgr *hwmgr, - uint8_t *table, int16_t table_id) -{ - struct rv_smumgr *priv = - (struct rv_smumgr *)(hwmgr->smu_backend); - - PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE, - "Invalid SMU Table ID!", return -EINVAL;); - PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0, - "Invalid SMU Table version!", return -EINVAL;); - PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0, - "Invalid SMU Table Length!", return -EINVAL;); - PP_ASSERT_WITH_CODE(rv_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SetDriverDramAddrHigh, - priv->smu_tables.entry[table_id].table_addr_high) == 0, - "[CopyTableFromSMC] Attempt to Set Dram Addr High Failed!", return -EINVAL;); - PP_ASSERT_WITH_CODE(rv_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SetDriverDramAddrLow, - priv->smu_tables.entry[table_id].table_addr_low) == 0, - "[CopyTableFromSMC] Attempt to Set Dram Addr Low Failed!", - return -EINVAL;); - PP_ASSERT_WITH_CODE(rv_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_TransferTableSmu2Dram, - priv->smu_tables.entry[table_id].table_id) == 0, - "[CopyTableFromSMC] Attempt to Transfer Table From SMU Failed!", - return -EINVAL;); - - memcpy(table, priv->smu_tables.entry[table_id].table, - priv->smu_tables.entry[table_id].size); - - return 0; -} - -int rv_copy_table_to_smc(struct pp_hwmgr *hwmgr, - uint8_t *table, int16_t table_id) -{ - struct rv_smumgr *priv = - (struct rv_smumgr *)(hwmgr->smu_backend); - - PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE, - "Invalid SMU Table ID!", return -EINVAL;); - PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0, - "Invalid SMU Table version!", return -EINVAL;); - PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0, - "Invalid SMU Table Length!", return -EINVAL;); - - memcpy(priv->smu_tables.entry[table_id].table, table, - priv->smu_tables.entry[table_id].size); - - PP_ASSERT_WITH_CODE(rv_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SetDriverDramAddrHigh, - priv->smu_tables.entry[table_id].table_addr_high) == 0, - "[CopyTableToSMC] Attempt to Set Dram Addr High Failed!", - return -EINVAL;); - PP_ASSERT_WITH_CODE(rv_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SetDriverDramAddrLow, - priv->smu_tables.entry[table_id].table_addr_low) == 0, - "[CopyTableToSMC] Attempt to Set Dram Addr Low Failed!", - return -EINVAL;); - PP_ASSERT_WITH_CODE(rv_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_TransferTableDram2Smu, - priv->smu_tables.entry[table_id].table_id) == 0, - "[CopyTableToSMC] Attempt to Transfer Table To SMU Failed!", - return -EINVAL;); - - return 0; -} - -static int rv_verify_smc_interface(struct pp_hwmgr *hwmgr) -{ - uint32_t smc_driver_if_version; - - PP_ASSERT_WITH_CODE(!rv_send_msg_to_smc(hwmgr, - PPSMC_MSG_GetDriverIfVersion), - "Attempt to get SMC IF Version Number Failed!", - return -EINVAL); - PP_ASSERT_WITH_CODE(!rv_read_arg_from_smc(hwmgr, - &smc_driver_if_version), - "Attempt to read SMC IF Version Number Failed!", - return -EINVAL); - - if (smc_driver_if_version != SMU10_DRIVER_IF_VERSION) - return -EINVAL; - - return 0; -} - -/* sdma is disabled by default in vbios, need to re-enable in driver */ -static int rv_smc_enable_sdma(struct pp_hwmgr *hwmgr) -{ - PP_ASSERT_WITH_CODE(!rv_send_msg_to_smc(hwmgr, - PPSMC_MSG_PowerUpSdma), - "Attempt to power up sdma Failed!", - return -EINVAL); - - return 0; -} - -static int rv_smc_disable_sdma(struct pp_hwmgr *hwmgr) -{ - PP_ASSERT_WITH_CODE(!rv_send_msg_to_smc(hwmgr, - PPSMC_MSG_PowerDownSdma), - "Attempt to power down sdma Failed!", - return -EINVAL); - - return 0; -} - -/* vcn is disabled by default in vbios, need to re-enable in driver */ -static int rv_smc_enable_vcn(struct pp_hwmgr *hwmgr) -{ - PP_ASSERT_WITH_CODE(!rv_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_PowerUpVcn, 0), - "Attempt to power up vcn Failed!", - return -EINVAL); - - return 0; -} - -static int rv_smc_disable_vcn(struct pp_hwmgr *hwmgr) -{ - PP_ASSERT_WITH_CODE(!rv_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_PowerDownVcn, 0), - "Attempt to power down vcn Failed!", - return -EINVAL); - - return 0; -} - -static int rv_smu_fini(struct pp_hwmgr *hwmgr) -{ - struct rv_smumgr *priv = - (struct rv_smumgr *)(hwmgr->smu_backend); - - if (priv) { - rv_smc_disable_sdma(hwmgr); - rv_smc_disable_vcn(hwmgr); - cgs_free_gpu_mem(hwmgr->device, - priv->smu_tables.entry[WMTABLE].handle); - cgs_free_gpu_mem(hwmgr->device, - priv->smu_tables.entry[CLOCKTABLE].handle); - kfree(hwmgr->smu_backend); - hwmgr->smu_backend = NULL; - } - - return 0; -} - -static int rv_start_smu(struct pp_hwmgr *hwmgr) -{ - struct cgs_firmware_info info = {0}; - - smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetSmuVersion); - rv_read_arg_from_smc(hwmgr, &hwmgr->smu_version); - info.version = hwmgr->smu_version >> 8; - - cgs_get_firmware_info(hwmgr->device, CGS_UCODE_ID_SMU, &info); - - if (rv_verify_smc_interface(hwmgr)) - return -EINVAL; - if (rv_smc_enable_sdma(hwmgr)) - return -EINVAL; - if (rv_smc_enable_vcn(hwmgr)) - return -EINVAL; - - return 0; -} - -static int rv_smu_init(struct pp_hwmgr *hwmgr) -{ - struct rv_smumgr *priv; - uint64_t mc_addr; - void *kaddr = NULL; - unsigned long handle; - - priv = kzalloc(sizeof(struct rv_smumgr), GFP_KERNEL); - - if (!priv) - return -ENOMEM; - - hwmgr->smu_backend = priv; - - /* allocate space for watermarks table */ - smu_allocate_memory(hwmgr->device, - sizeof(Watermarks_t), - CGS_GPU_MEM_TYPE__GART_CACHEABLE, - PAGE_SIZE, - &mc_addr, - &kaddr, - &handle); - - PP_ASSERT_WITH_CODE(kaddr, - "[rv_smu_init] Out of memory for wmtable.", - kfree(hwmgr->smu_backend); - hwmgr->smu_backend = NULL; - return -EINVAL); - - priv->smu_tables.entry[WMTABLE].version = 0x01; - priv->smu_tables.entry[WMTABLE].size = sizeof(Watermarks_t); - priv->smu_tables.entry[WMTABLE].table_id = TABLE_WATERMARKS; - priv->smu_tables.entry[WMTABLE].table_addr_high = - smu_upper_32_bits(mc_addr); - priv->smu_tables.entry[WMTABLE].table_addr_low = - smu_lower_32_bits(mc_addr); - priv->smu_tables.entry[WMTABLE].table = kaddr; - priv->smu_tables.entry[WMTABLE].handle = handle; - - /* allocate space for watermarks table */ - smu_allocate_memory(hwmgr->device, - sizeof(DpmClocks_t), - CGS_GPU_MEM_TYPE__GART_CACHEABLE, - PAGE_SIZE, - &mc_addr, - &kaddr, - &handle); - - PP_ASSERT_WITH_CODE(kaddr, - "[rv_smu_init] Out of memory for CLOCKTABLE.", - cgs_free_gpu_mem(hwmgr->device, - (cgs_handle_t)priv->smu_tables.entry[WMTABLE].handle); - kfree(hwmgr->smu_backend); - hwmgr->smu_backend = NULL; - return -EINVAL); - - priv->smu_tables.entry[CLOCKTABLE].version = 0x01; - priv->smu_tables.entry[CLOCKTABLE].size = sizeof(DpmClocks_t); - priv->smu_tables.entry[CLOCKTABLE].table_id = TABLE_DPMCLOCKS; - priv->smu_tables.entry[CLOCKTABLE].table_addr_high = - smu_upper_32_bits(mc_addr); - priv->smu_tables.entry[CLOCKTABLE].table_addr_low = - smu_lower_32_bits(mc_addr); - priv->smu_tables.entry[CLOCKTABLE].table = kaddr; - priv->smu_tables.entry[CLOCKTABLE].handle = handle; - - return 0; -} - -const struct pp_smumgr_func rv_smu_funcs = { - .smu_init = &rv_smu_init, - .smu_fini = &rv_smu_fini, - .start_smu = &rv_start_smu, - .request_smu_load_specific_fw = NULL, - .send_msg_to_smc = &rv_send_msg_to_smc, - .send_msg_to_smc_with_parameter = &rv_send_msg_to_smc_with_parameter, - .download_pptable_settings = NULL, - .upload_pptable_settings = NULL, -}; - - diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.c new file mode 100644 index 000000000000..bc53f2beda30 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.c @@ -0,0 +1,344 @@ +/* + * Copyright 2016 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 "smumgr.h" +#include "smu10_inc.h" +#include "pp_soc15.h" +#include "smu10_smumgr.h" +#include "ppatomctrl.h" +#include "rv_ppsmc.h" +#include "smu10_driver_if.h" +#include "smu10.h" +#include "ppatomctrl.h" +#include "pp_debug.h" + + +#define VOLTAGE_SCALE 4 + +#define BUFFER_SIZE 80000 +#define MAX_STRING_SIZE 15 +#define BUFFER_SIZETWO 131072 + +#define MP0_Public 0x03800000 +#define MP0_SRAM 0x03900000 +#define MP1_Public 0x03b00000 +#define MP1_SRAM 0x03c00004 + +#define smnMP1_FIRMWARE_FLAGS 0x3010028 + + +static uint32_t smu10_wait_for_response(struct pp_hwmgr *hwmgr) +{ + uint32_t reg; + + reg = soc15_get_register_offset(MP1_HWID, 0, + mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90); + + phm_wait_for_register_unequal(hwmgr, reg, + 0, MP1_C2PMSG_90__CONTENT_MASK); + + return cgs_read_register(hwmgr->device, reg); +} + +static int smu10_send_msg_to_smc_without_waiting(struct pp_hwmgr *hwmgr, + uint16_t msg) +{ + uint32_t reg; + + reg = soc15_get_register_offset(MP1_HWID, 0, + mmMP1_SMN_C2PMSG_66_BASE_IDX, mmMP1_SMN_C2PMSG_66); + cgs_write_register(hwmgr->device, reg, msg); + + return 0; +} + +static int smu10_read_arg_from_smc(struct pp_hwmgr *hwmgr) +{ + uint32_t reg; + + reg = soc15_get_register_offset(MP1_HWID, 0, + mmMP1_SMN_C2PMSG_82_BASE_IDX, mmMP1_SMN_C2PMSG_82); + + return cgs_read_register(hwmgr->device, reg); +} + +static int smu10_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg) +{ + uint32_t reg; + + smu10_wait_for_response(hwmgr); + + reg = soc15_get_register_offset(MP1_HWID, 0, + mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90); + cgs_write_register(hwmgr->device, reg, 0); + + smu10_send_msg_to_smc_without_waiting(hwmgr, msg); + + if (smu10_wait_for_response(hwmgr) == 0) + printk("Failed to send Message %x.\n", msg); + + return 0; +} + + +static int smu10_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, + uint16_t msg, uint32_t parameter) +{ + uint32_t reg; + + smu10_wait_for_response(hwmgr); + + reg = soc15_get_register_offset(MP1_HWID, 0, + mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90); + cgs_write_register(hwmgr->device, reg, 0); + + reg = soc15_get_register_offset(MP1_HWID, 0, + mmMP1_SMN_C2PMSG_82_BASE_IDX, mmMP1_SMN_C2PMSG_82); + cgs_write_register(hwmgr->device, reg, parameter); + + smu10_send_msg_to_smc_without_waiting(hwmgr, msg); + + + if (smu10_wait_for_response(hwmgr) == 0) + printk("Failed to send Message %x.\n", msg); + + return 0; +} + +static int smu10_copy_table_from_smc(struct pp_hwmgr *hwmgr, + uint8_t *table, int16_t table_id) +{ + struct smu10_smumgr *priv = + (struct smu10_smumgr *)(hwmgr->smu_backend); + + PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE, + "Invalid SMU Table ID!", return -EINVAL;); + PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0, + "Invalid SMU Table version!", return -EINVAL;); + PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0, + "Invalid SMU Table Length!", return -EINVAL;); + smu10_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetDriverDramAddrHigh, + upper_32_bits(priv->smu_tables.entry[table_id].mc_addr)); + smu10_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetDriverDramAddrLow, + lower_32_bits(priv->smu_tables.entry[table_id].mc_addr)); + smu10_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_TransferTableSmu2Dram, + priv->smu_tables.entry[table_id].table_id); + + memcpy(table, (uint8_t *)priv->smu_tables.entry[table_id].table, + priv->smu_tables.entry[table_id].size); + + return 0; +} + +static int smu10_copy_table_to_smc(struct pp_hwmgr *hwmgr, + uint8_t *table, int16_t table_id) +{ + struct smu10_smumgr *priv = + (struct smu10_smumgr *)(hwmgr->smu_backend); + + PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE, + "Invalid SMU Table ID!", return -EINVAL;); + PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0, + "Invalid SMU Table version!", return -EINVAL;); + PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0, + "Invalid SMU Table Length!", return -EINVAL;); + + memcpy(priv->smu_tables.entry[table_id].table, table, + priv->smu_tables.entry[table_id].size); + + smu10_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetDriverDramAddrHigh, + upper_32_bits(priv->smu_tables.entry[table_id].mc_addr)); + smu10_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetDriverDramAddrLow, + lower_32_bits(priv->smu_tables.entry[table_id].mc_addr)); + smu10_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_TransferTableDram2Smu, + priv->smu_tables.entry[table_id].table_id); + + return 0; +} + +static int smu10_verify_smc_interface(struct pp_hwmgr *hwmgr) +{ + uint32_t smc_driver_if_version; + + smu10_send_msg_to_smc(hwmgr, + PPSMC_MSG_GetDriverIfVersion); + smc_driver_if_version = smu10_read_arg_from_smc(hwmgr); + + if (smc_driver_if_version != SMU10_DRIVER_IF_VERSION) { + pr_err("Attempt to read SMC IF Version Number Failed!\n"); + return -EINVAL; + } + + return 0; +} + +/* sdma is disabled by default in vbios, need to re-enable in driver */ +static void smu10_smc_enable_sdma(struct pp_hwmgr *hwmgr) +{ + smu10_send_msg_to_smc(hwmgr, + PPSMC_MSG_PowerUpSdma); +} + +static void smu10_smc_disable_sdma(struct pp_hwmgr *hwmgr) +{ + smu10_send_msg_to_smc(hwmgr, + PPSMC_MSG_PowerDownSdma); +} + +/* vcn is disabled by default in vbios, need to re-enable in driver */ +static void smu10_smc_enable_vcn(struct pp_hwmgr *hwmgr) +{ + smu10_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_PowerUpVcn, 0); +} + +static void smu10_smc_disable_vcn(struct pp_hwmgr *hwmgr) +{ + smu10_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_PowerDownVcn, 0); +} + +static int smu10_smu_fini(struct pp_hwmgr *hwmgr) +{ + struct smu10_smumgr *priv = + (struct smu10_smumgr *)(hwmgr->smu_backend); + + if (priv) { + smu10_smc_disable_sdma(hwmgr); + smu10_smc_disable_vcn(hwmgr); + amdgpu_bo_free_kernel(&priv->smu_tables.entry[SMU10_WMTABLE].handle, + &priv->smu_tables.entry[SMU10_WMTABLE].mc_addr, + &priv->smu_tables.entry[SMU10_WMTABLE].table); + amdgpu_bo_free_kernel(&priv->smu_tables.entry[SMU10_CLOCKTABLE].handle, + &priv->smu_tables.entry[SMU10_CLOCKTABLE].mc_addr, + &priv->smu_tables.entry[SMU10_CLOCKTABLE].table); + kfree(hwmgr->smu_backend); + hwmgr->smu_backend = NULL; + } + + return 0; +} + +static int smu10_start_smu(struct pp_hwmgr *hwmgr) +{ + struct amdgpu_device *adev = hwmgr->adev; + + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetSmuVersion); + hwmgr->smu_version = smu10_read_arg_from_smc(hwmgr); + adev->pm.fw_version = hwmgr->smu_version >> 8; + + if (smu10_verify_smc_interface(hwmgr)) + return -EINVAL; + smu10_smc_enable_sdma(hwmgr); + smu10_smc_enable_vcn(hwmgr); + return 0; +} + +static int smu10_smu_init(struct pp_hwmgr *hwmgr) +{ + struct smu10_smumgr *priv; + int r; + + priv = kzalloc(sizeof(struct smu10_smumgr), GFP_KERNEL); + + if (!priv) + return -ENOMEM; + + hwmgr->smu_backend = priv; + + /* allocate space for watermarks table */ + r = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, + sizeof(Watermarks_t), + PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, + &priv->smu_tables.entry[SMU10_WMTABLE].handle, + &priv->smu_tables.entry[SMU10_WMTABLE].mc_addr, + &priv->smu_tables.entry[SMU10_WMTABLE].table); + + if (r) + goto err0; + + priv->smu_tables.entry[SMU10_WMTABLE].version = 0x01; + priv->smu_tables.entry[SMU10_WMTABLE].size = sizeof(Watermarks_t); + priv->smu_tables.entry[SMU10_WMTABLE].table_id = TABLE_WATERMARKS; + + /* allocate space for watermarks table */ + r = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, + sizeof(DpmClocks_t), + PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, + &priv->smu_tables.entry[SMU10_CLOCKTABLE].handle, + &priv->smu_tables.entry[SMU10_CLOCKTABLE].mc_addr, + &priv->smu_tables.entry[SMU10_CLOCKTABLE].table); + + if (r) + goto err1; + + priv->smu_tables.entry[SMU10_CLOCKTABLE].version = 0x01; + priv->smu_tables.entry[SMU10_CLOCKTABLE].size = sizeof(DpmClocks_t); + priv->smu_tables.entry[SMU10_CLOCKTABLE].table_id = TABLE_DPMCLOCKS; + + return 0; + +err1: + amdgpu_bo_free_kernel(&priv->smu_tables.entry[SMU10_WMTABLE].handle, + &priv->smu_tables.entry[SMU10_WMTABLE].mc_addr, + &priv->smu_tables.entry[SMU10_WMTABLE].table); +err0: + kfree(priv); + return -EINVAL; +} + +static int smu10_smc_table_manager(struct pp_hwmgr *hwmgr, uint8_t *table, uint16_t table_id, bool rw) +{ + int ret; + + if (rw) + ret = smu10_copy_table_from_smc(hwmgr, table, table_id); + else + ret = smu10_copy_table_to_smc(hwmgr, table, table_id); + + return ret; +} + + +const struct pp_smumgr_func smu10_smu_funcs = { + .smu_init = &smu10_smu_init, + .smu_fini = &smu10_smu_fini, + .start_smu = &smu10_start_smu, + .request_smu_load_specific_fw = NULL, + .send_msg_to_smc = &smu10_send_msg_to_smc, + .send_msg_to_smc_with_parameter = &smu10_send_msg_to_smc_with_parameter, + .download_pptable_settings = NULL, + .upload_pptable_settings = NULL, + .get_argument = smu10_read_arg_from_smc, + .smc_table_manager = smu10_smc_table_manager, +}; + + diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/rv_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.h index caebdbebdcd8..9c2be74a2b2f 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/rv_smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.h @@ -21,42 +21,30 @@ * */ -#ifndef PP_RAVEN_SMUMANAGER_H -#define PP_RAVEN_SMUMANAGER_H +#ifndef PP_SMU10_SMUMANAGER_H +#define PP_SMU10_SMUMANAGER_H #include "rv_ppsmc.h" #include "smu10_driver_if.h" -enum SMU_TABLE_ID { - WMTABLE = 0, - CLOCKTABLE, - MAX_SMU_TABLE, -}; +#define MAX_SMU_TABLE 2 struct smu_table_entry { uint32_t version; uint32_t size; uint32_t table_id; - uint32_t table_addr_high; - uint32_t table_addr_low; - uint8_t *table; - unsigned long handle; + uint64_t mc_addr; + void *table; + struct amdgpu_bo *handle; }; struct smu_table_array { struct smu_table_entry entry[MAX_SMU_TABLE]; }; -struct rv_smumgr { +struct smu10_smumgr { struct smu_table_array smu_tables; }; -int rv_read_arg_from_smc(struct pp_hwmgr *hwmgr, uint32_t *arg); -bool rv_is_smc_ram_running(struct pp_hwmgr *hwmgr); -int rv_copy_table_from_smc(struct pp_hwmgr *hwmgr, - uint8_t *table, int16_t table_id); -int rv_copy_table_to_smc(struct pp_hwmgr *hwmgr, - uint8_t *table, int16_t table_id); - #endif diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c index 311ff3718618..0399c10d2be0 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.c @@ -369,8 +369,8 @@ static int smu7_populate_single_firmware_entry(struct pp_hwmgr *hwmgr, if (!result) { entry->version = info.fw_version; entry->id = (uint16_t)fw_type; - entry->image_addr_high = smu_upper_32_bits(info.mc_addr); - entry->image_addr_low = smu_lower_32_bits(info.mc_addr); + entry->image_addr_high = upper_32_bits(info.mc_addr); + entry->image_addr_low = lower_32_bits(info.mc_addr); entry->meta_data_addr_high = 0; entry->meta_data_addr_low = 0; @@ -412,10 +412,10 @@ int smu7_request_smu_load_fw(struct pp_hwmgr *hwmgr) if (!cgs_is_virtualization_enabled(hwmgr->device)) { smu7_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SMU_DRAM_ADDR_HI, - smu_data->smu_buffer.mc_addr_high); + upper_32_bits(smu_data->smu_buffer.mc_addr)); smu7_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SMU_DRAM_ADDR_LO, - smu_data->smu_buffer.mc_addr_low); + lower_32_bits(smu_data->smu_buffer.mc_addr)); } fw_to_load = UCODE_ID_RLC_G_MASK + UCODE_ID_SDMA0_MASK @@ -472,8 +472,8 @@ int smu7_request_smu_load_fw(struct pp_hwmgr *hwmgr) UCODE_ID_MEC_STORAGE, &toc->entry[toc->num_entries++]), "Failed to Get Firmware Entry.", return -EINVAL); - smu7_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_DRV_DRAM_ADDR_HI, smu_data->header_buffer.mc_addr_high); - smu7_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_DRV_DRAM_ADDR_LO, smu_data->header_buffer.mc_addr_low); + smu7_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_DRV_DRAM_ADDR_HI, upper_32_bits(smu_data->header_buffer.mc_addr)); + smu7_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_DRV_DRAM_ADDR_LO, lower_32_bits(smu_data->header_buffer.mc_addr)); if (smu7_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_LoadUcodes, fw_to_load)) pr_err("Fail to Request SMU Load uCode"); @@ -585,9 +585,8 @@ int smu7_setup_pwr_virus(struct pp_hwmgr *hwmgr) int smu7_init(struct pp_hwmgr *hwmgr) { struct smu7_smumgr *smu_data; - uint8_t *internal_buf; uint64_t mc_addr = 0; - + int r; /* Allocate memory for backend private data */ smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend); smu_data->header_buffer.data_size = @@ -595,52 +594,42 @@ int smu7_init(struct pp_hwmgr *hwmgr) /* Allocate FW image data structure and header buffer and * send the header buffer address to SMU */ - smu_allocate_memory(hwmgr->device, + r = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, smu_data->header_buffer.data_size, - CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, + &smu_data->header_buffer.handle, &mc_addr, - &smu_data->header_buffer.kaddr, - &smu_data->header_buffer.handle); + &smu_data->header_buffer.kaddr); - smu_data->header = smu_data->header_buffer.kaddr; - smu_data->header_buffer.mc_addr_high = smu_upper_32_bits(mc_addr); - smu_data->header_buffer.mc_addr_low = smu_lower_32_bits(mc_addr); + if (r) + return -EINVAL; - PP_ASSERT_WITH_CODE((NULL != smu_data->header), - "Out of memory.", - kfree(hwmgr->smu_backend); - cgs_free_gpu_mem(hwmgr->device, - (cgs_handle_t)smu_data->header_buffer.handle); - return -EINVAL); + smu_data->header = smu_data->header_buffer.kaddr; + smu_data->header_buffer.mc_addr = mc_addr; if (cgs_is_virtualization_enabled(hwmgr->device)) return 0; smu_data->smu_buffer.data_size = 200*4096; - smu_allocate_memory(hwmgr->device, + r = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, smu_data->smu_buffer.data_size, - CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, + &smu_data->smu_buffer.handle, &mc_addr, - &smu_data->smu_buffer.kaddr, - &smu_data->smu_buffer.handle); - - internal_buf = smu_data->smu_buffer.kaddr; - smu_data->smu_buffer.mc_addr_high = smu_upper_32_bits(mc_addr); - smu_data->smu_buffer.mc_addr_low = smu_lower_32_bits(mc_addr); + &smu_data->smu_buffer.kaddr); - PP_ASSERT_WITH_CODE((NULL != internal_buf), - "Out of memory.", - kfree(hwmgr->smu_backend); - cgs_free_gpu_mem(hwmgr->device, - (cgs_handle_t)smu_data->smu_buffer.handle); - return -EINVAL); + if (r) { + amdgpu_bo_free_kernel(&smu_data->header_buffer.handle, + &smu_data->header_buffer.mc_addr, + &smu_data->header_buffer.kaddr); + return -EINVAL; + } + smu_data->smu_buffer.mc_addr = mc_addr; if (smum_is_hw_avfs_present(hwmgr)) - smu_data->avfs.avfs_btc_status = AVFS_BTC_BOOT; - else - smu_data->avfs.avfs_btc_status = AVFS_BTC_NOTSUPPORTED; + hwmgr->avfs_supported = true; return 0; } @@ -650,9 +639,14 @@ int smu7_smu_fini(struct pp_hwmgr *hwmgr) { struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend); - smu_free_memory(hwmgr->device, (void *) smu_data->header_buffer.handle); + amdgpu_bo_free_kernel(&smu_data->header_buffer.handle, + &smu_data->header_buffer.mc_addr, + &smu_data->header_buffer.kaddr); + if (!cgs_is_virtualization_enabled(hwmgr->device)) - smu_free_memory(hwmgr->device, (void *) smu_data->smu_buffer.handle); + amdgpu_bo_free_kernel(&smu_data->smu_buffer.handle, + &smu_data->smu_buffer.mc_addr, + &smu_data->smu_buffer.kaddr); kfree(hwmgr->smu_backend); hwmgr->smu_backend = NULL; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.h index c87263bc0caa..126d300259ba 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu7_smumgr.h @@ -31,15 +31,9 @@ struct smu7_buffer_entry { uint32_t data_size; - uint32_t mc_addr_low; - uint32_t mc_addr_high; + uint64_t mc_addr; void *kaddr; - unsigned long handle; -}; - -struct smu7_avfs { - enum AVFS_BTC_STATUS avfs_btc_status; - uint32_t avfs_btc_param; + struct amdgpu_bo *handle; }; struct smu7_smumgr { @@ -56,7 +50,7 @@ struct smu7_smumgr { uint32_t ulv_setting_starts; uint8_t security_hard_key; uint32_t acpi_optimization; - struct smu7_avfs avfs; + uint32_t avfs_btc_param; }; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c new file mode 100644 index 000000000000..c861d3023474 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c @@ -0,0 +1,891 @@ +/* + * 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 <linux/delay.h> +#include <linux/gfp.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/types.h> + +#include "cgs_common.h" +#include "smu/smu_8_0_d.h" +#include "smu/smu_8_0_sh_mask.h" +#include "smu8.h" +#include "smu8_fusion.h" +#include "smu8_smumgr.h" +#include "cz_ppsmc.h" +#include "smu_ucode_xfer_cz.h" +#include "gca/gfx_8_0_d.h" +#include "gca/gfx_8_0_sh_mask.h" +#include "smumgr.h" + +#define SIZE_ALIGN_32(x) (((x) + 31) / 32 * 32) + +static const enum smu8_scratch_entry firmware_list[] = { + SMU8_SCRATCH_ENTRY_UCODE_ID_SDMA0, + SMU8_SCRATCH_ENTRY_UCODE_ID_SDMA1, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_CE, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_PFP, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_ME, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_G, +}; + +static int smu8_get_argument(struct pp_hwmgr *hwmgr) +{ + if (hwmgr == NULL || hwmgr->device == NULL) + return -EINVAL; + + return cgs_read_register(hwmgr->device, + mmSMU_MP1_SRBM2P_ARG_0); +} + +static int smu8_send_msg_to_smc_async(struct pp_hwmgr *hwmgr, uint16_t msg) +{ + int result = 0; + + if (hwmgr == NULL || hwmgr->device == NULL) + return -EINVAL; + + result = PHM_WAIT_FIELD_UNEQUAL(hwmgr, + SMU_MP1_SRBM2P_RESP_0, CONTENT, 0); + if (result != 0) { + pr_err("smu8_send_msg_to_smc_async (0x%04x) failed\n", msg); + return result; + } + + cgs_write_register(hwmgr->device, mmSMU_MP1_SRBM2P_RESP_0, 0); + cgs_write_register(hwmgr->device, mmSMU_MP1_SRBM2P_MSG_0, msg); + + return 0; +} + +/* Send a message to the SMC, and wait for its response.*/ +static int smu8_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg) +{ + int result = 0; + + result = smu8_send_msg_to_smc_async(hwmgr, msg); + if (result != 0) + return result; + + return PHM_WAIT_FIELD_UNEQUAL(hwmgr, + SMU_MP1_SRBM2P_RESP_0, CONTENT, 0); +} + +static int smu8_set_smc_sram_address(struct pp_hwmgr *hwmgr, + uint32_t smc_address, uint32_t limit) +{ + if (hwmgr == NULL || hwmgr->device == NULL) + return -EINVAL; + + if (0 != (3 & smc_address)) { + pr_err("SMC address must be 4 byte aligned\n"); + return -EINVAL; + } + + if (limit <= (smc_address + 3)) { + pr_err("SMC address beyond the SMC RAM area\n"); + return -EINVAL; + } + + cgs_write_register(hwmgr->device, mmMP0PUB_IND_INDEX_0, + SMN_MP1_SRAM_START_ADDR + smc_address); + + return 0; +} + +static int smu8_write_smc_sram_dword(struct pp_hwmgr *hwmgr, + uint32_t smc_address, uint32_t value, uint32_t limit) +{ + int result; + + if (hwmgr == NULL || hwmgr->device == NULL) + return -EINVAL; + + result = smu8_set_smc_sram_address(hwmgr, smc_address, limit); + if (!result) + cgs_write_register(hwmgr->device, mmMP0PUB_IND_DATA_0, value); + + return result; +} + +static int smu8_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, + uint16_t msg, uint32_t parameter) +{ + if (hwmgr == NULL || hwmgr->device == NULL) + return -EINVAL; + + cgs_write_register(hwmgr->device, mmSMU_MP1_SRBM2P_ARG_0, parameter); + + return smu8_send_msg_to_smc(hwmgr, msg); +} + +static int smu8_check_fw_load_finish(struct pp_hwmgr *hwmgr, + uint32_t firmware) +{ + int i; + uint32_t index = SMN_MP1_SRAM_START_ADDR + + SMU8_FIRMWARE_HEADER_LOCATION + + offsetof(struct SMU8_Firmware_Header, UcodeLoadStatus); + + if (hwmgr == NULL || hwmgr->device == NULL) + return -EINVAL; + + cgs_write_register(hwmgr->device, mmMP0PUB_IND_INDEX, index); + + for (i = 0; i < hwmgr->usec_timeout; i++) { + if (firmware == + (cgs_read_register(hwmgr->device, mmMP0PUB_IND_DATA) & firmware)) + break; + udelay(1); + } + + if (i >= hwmgr->usec_timeout) { + pr_err("SMU check loaded firmware failed.\n"); + return -EINVAL; + } + + return 0; +} + +static int smu8_load_mec_firmware(struct pp_hwmgr *hwmgr) +{ + uint32_t reg_data; + uint32_t tmp; + int ret = 0; + struct cgs_firmware_info info = {0}; + struct smu8_smumgr *smu8_smu; + + if (hwmgr == NULL || hwmgr->device == NULL) + return -EINVAL; + + smu8_smu = hwmgr->smu_backend; + ret = cgs_get_firmware_info(hwmgr->device, + CGS_UCODE_ID_CP_MEC, &info); + + if (ret) + return -EINVAL; + + /* Disable MEC parsing/prefetching */ + tmp = cgs_read_register(hwmgr->device, + mmCP_MEC_CNTL); + tmp = PHM_SET_FIELD(tmp, CP_MEC_CNTL, MEC_ME1_HALT, 1); + tmp = PHM_SET_FIELD(tmp, CP_MEC_CNTL, MEC_ME2_HALT, 1); + cgs_write_register(hwmgr->device, mmCP_MEC_CNTL, tmp); + + tmp = cgs_read_register(hwmgr->device, + mmCP_CPC_IC_BASE_CNTL); + + tmp = PHM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, VMID, 0); + tmp = PHM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, ATC, 0); + tmp = PHM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, CACHE_POLICY, 0); + tmp = PHM_SET_FIELD(tmp, CP_CPC_IC_BASE_CNTL, MTYPE, 1); + cgs_write_register(hwmgr->device, mmCP_CPC_IC_BASE_CNTL, tmp); + + reg_data = lower_32_bits(info.mc_addr) & + PHM_FIELD_MASK(CP_CPC_IC_BASE_LO, IC_BASE_LO); + cgs_write_register(hwmgr->device, mmCP_CPC_IC_BASE_LO, reg_data); + + reg_data = upper_32_bits(info.mc_addr) & + PHM_FIELD_MASK(CP_CPC_IC_BASE_HI, IC_BASE_HI); + cgs_write_register(hwmgr->device, mmCP_CPC_IC_BASE_HI, reg_data); + + return 0; +} + +static uint8_t smu8_translate_firmware_enum_to_arg(struct pp_hwmgr *hwmgr, + enum smu8_scratch_entry firmware_enum) +{ + uint8_t ret = 0; + + switch (firmware_enum) { + case SMU8_SCRATCH_ENTRY_UCODE_ID_SDMA0: + ret = UCODE_ID_SDMA0; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_SDMA1: + if (hwmgr->chip_id == CHIP_STONEY) + ret = UCODE_ID_SDMA0; + else + ret = UCODE_ID_SDMA1; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_CP_CE: + ret = UCODE_ID_CP_CE; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_CP_PFP: + ret = UCODE_ID_CP_PFP; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_CP_ME: + ret = UCODE_ID_CP_ME; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1: + ret = UCODE_ID_CP_MEC_JT1; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2: + if (hwmgr->chip_id == CHIP_STONEY) + ret = UCODE_ID_CP_MEC_JT1; + else + ret = UCODE_ID_CP_MEC_JT2; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_GMCON_RENG: + ret = UCODE_ID_GMCON_RENG; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_G: + ret = UCODE_ID_RLC_G; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH: + ret = UCODE_ID_RLC_SCRATCH; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM: + ret = UCODE_ID_RLC_SRM_ARAM; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM: + ret = UCODE_ID_RLC_SRM_DRAM; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_DMCU_ERAM: + ret = UCODE_ID_DMCU_ERAM; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_DMCU_IRAM: + ret = UCODE_ID_DMCU_IRAM; + break; + case SMU8_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING: + ret = TASK_ARG_INIT_MM_PWR_LOG; + break; + case SMU8_SCRATCH_ENTRY_DATA_ID_SDMA_HALT: + case SMU8_SCRATCH_ENTRY_DATA_ID_SYS_CLOCKGATING: + case SMU8_SCRATCH_ENTRY_DATA_ID_SDMA_RING_REGS: + case SMU8_SCRATCH_ENTRY_DATA_ID_NONGFX_REINIT: + case SMU8_SCRATCH_ENTRY_DATA_ID_SDMA_START: + case SMU8_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS: + ret = TASK_ARG_REG_MMIO; + break; + case SMU8_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE: + ret = TASK_ARG_INIT_CLK_TABLE; + break; + } + + return ret; +} + +static enum cgs_ucode_id smu8_convert_fw_type_to_cgs(uint32_t fw_type) +{ + enum cgs_ucode_id result = CGS_UCODE_ID_MAXIMUM; + + switch (fw_type) { + case UCODE_ID_SDMA0: + result = CGS_UCODE_ID_SDMA0; + break; + case UCODE_ID_SDMA1: + result = CGS_UCODE_ID_SDMA1; + break; + case UCODE_ID_CP_CE: + result = CGS_UCODE_ID_CP_CE; + break; + case UCODE_ID_CP_PFP: + result = CGS_UCODE_ID_CP_PFP; + break; + case UCODE_ID_CP_ME: + result = CGS_UCODE_ID_CP_ME; + break; + case UCODE_ID_CP_MEC_JT1: + result = CGS_UCODE_ID_CP_MEC_JT1; + break; + case UCODE_ID_CP_MEC_JT2: + result = CGS_UCODE_ID_CP_MEC_JT2; + break; + case UCODE_ID_RLC_G: + result = CGS_UCODE_ID_RLC_G; + break; + default: + break; + } + + return result; +} + +static int smu8_smu_populate_single_scratch_task( + struct pp_hwmgr *hwmgr, + enum smu8_scratch_entry fw_enum, + uint8_t type, bool is_last) +{ + uint8_t i; + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + struct TOC *toc = (struct TOC *)smu8_smu->toc_buffer.kaddr; + struct SMU_Task *task = &toc->tasks[smu8_smu->toc_entry_used_count++]; + + task->type = type; + task->arg = smu8_translate_firmware_enum_to_arg(hwmgr, fw_enum); + task->next = is_last ? END_OF_TASK_LIST : smu8_smu->toc_entry_used_count; + + for (i = 0; i < smu8_smu->scratch_buffer_length; i++) + if (smu8_smu->scratch_buffer[i].firmware_ID == fw_enum) + break; + + if (i >= smu8_smu->scratch_buffer_length) { + pr_err("Invalid Firmware Type\n"); + return -EINVAL; + } + + task->addr.low = lower_32_bits(smu8_smu->scratch_buffer[i].mc_addr); + task->addr.high = upper_32_bits(smu8_smu->scratch_buffer[i].mc_addr); + task->size_bytes = smu8_smu->scratch_buffer[i].data_size; + + if (SMU8_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS == fw_enum) { + struct smu8_ih_meta_data *pIHReg_restore = + (struct smu8_ih_meta_data *)smu8_smu->scratch_buffer[i].kaddr; + pIHReg_restore->command = + METADATA_CMD_MODE0 | METADATA_PERFORM_ON_LOAD; + } + + return 0; +} + +static int smu8_smu_populate_single_ucode_load_task( + struct pp_hwmgr *hwmgr, + enum smu8_scratch_entry fw_enum, + bool is_last) +{ + uint8_t i; + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + struct TOC *toc = (struct TOC *)smu8_smu->toc_buffer.kaddr; + struct SMU_Task *task = &toc->tasks[smu8_smu->toc_entry_used_count++]; + + task->type = TASK_TYPE_UCODE_LOAD; + task->arg = smu8_translate_firmware_enum_to_arg(hwmgr, fw_enum); + task->next = is_last ? END_OF_TASK_LIST : smu8_smu->toc_entry_used_count; + + for (i = 0; i < smu8_smu->driver_buffer_length; i++) + if (smu8_smu->driver_buffer[i].firmware_ID == fw_enum) + break; + + if (i >= smu8_smu->driver_buffer_length) { + pr_err("Invalid Firmware Type\n"); + return -EINVAL; + } + + task->addr.low = lower_32_bits(smu8_smu->driver_buffer[i].mc_addr); + task->addr.high = upper_32_bits(smu8_smu->driver_buffer[i].mc_addr); + task->size_bytes = smu8_smu->driver_buffer[i].data_size; + + return 0; +} + +static int smu8_smu_construct_toc_for_rlc_aram_save(struct pp_hwmgr *hwmgr) +{ + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + + smu8_smu->toc_entry_aram = smu8_smu->toc_entry_used_count; + smu8_smu_populate_single_scratch_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM, + TASK_TYPE_UCODE_SAVE, true); + + return 0; +} + +static int smu8_smu_initialize_toc_empty_job_list(struct pp_hwmgr *hwmgr) +{ + int i; + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + struct TOC *toc = (struct TOC *)smu8_smu->toc_buffer.kaddr; + + for (i = 0; i < NUM_JOBLIST_ENTRIES; i++) + toc->JobList[i] = (uint8_t)IGNORE_JOB; + + return 0; +} + +static int smu8_smu_construct_toc_for_vddgfx_enter(struct pp_hwmgr *hwmgr) +{ + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + struct TOC *toc = (struct TOC *)smu8_smu->toc_buffer.kaddr; + + toc->JobList[JOB_GFX_SAVE] = (uint8_t)smu8_smu->toc_entry_used_count; + smu8_smu_populate_single_scratch_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH, + TASK_TYPE_UCODE_SAVE, false); + + smu8_smu_populate_single_scratch_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM, + TASK_TYPE_UCODE_SAVE, true); + + return 0; +} + + +static int smu8_smu_construct_toc_for_vddgfx_exit(struct pp_hwmgr *hwmgr) +{ + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + struct TOC *toc = (struct TOC *)smu8_smu->toc_buffer.kaddr; + + toc->JobList[JOB_GFX_RESTORE] = (uint8_t)smu8_smu->toc_entry_used_count; + + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_CE, false); + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_PFP, false); + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_ME, false); + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false); + + if (hwmgr->chip_id == CHIP_STONEY) + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false); + else + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, false); + + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_G, false); + + /* populate scratch */ + smu8_smu_populate_single_scratch_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH, + TASK_TYPE_UCODE_LOAD, false); + + smu8_smu_populate_single_scratch_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM, + TASK_TYPE_UCODE_LOAD, false); + + smu8_smu_populate_single_scratch_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM, + TASK_TYPE_UCODE_LOAD, true); + + return 0; +} + +static int smu8_smu_construct_toc_for_power_profiling(struct pp_hwmgr *hwmgr) +{ + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + + smu8_smu->toc_entry_power_profiling_index = smu8_smu->toc_entry_used_count; + + smu8_smu_populate_single_scratch_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING, + TASK_TYPE_INITIALIZE, true); + return 0; +} + +static int smu8_smu_construct_toc_for_bootup(struct pp_hwmgr *hwmgr) +{ + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + + smu8_smu->toc_entry_initialize_index = smu8_smu->toc_entry_used_count; + + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_SDMA0, false); + if (hwmgr->chip_id != CHIP_STONEY) + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_SDMA1, false); + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_CE, false); + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_PFP, false); + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_ME, false); + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, false); + if (hwmgr->chip_id != CHIP_STONEY) + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, false); + smu8_smu_populate_single_ucode_load_task(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_G, true); + + return 0; +} + +static int smu8_smu_construct_toc_for_clock_table(struct pp_hwmgr *hwmgr) +{ + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + + smu8_smu->toc_entry_clock_table = smu8_smu->toc_entry_used_count; + + smu8_smu_populate_single_scratch_task(hwmgr, + SMU8_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE, + TASK_TYPE_INITIALIZE, true); + + return 0; +} + +static int smu8_smu_construct_toc(struct pp_hwmgr *hwmgr) +{ + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + + smu8_smu->toc_entry_used_count = 0; + smu8_smu_initialize_toc_empty_job_list(hwmgr); + smu8_smu_construct_toc_for_rlc_aram_save(hwmgr); + smu8_smu_construct_toc_for_vddgfx_enter(hwmgr); + smu8_smu_construct_toc_for_vddgfx_exit(hwmgr); + smu8_smu_construct_toc_for_power_profiling(hwmgr); + smu8_smu_construct_toc_for_bootup(hwmgr); + smu8_smu_construct_toc_for_clock_table(hwmgr); + + return 0; +} + +static int smu8_smu_populate_firmware_entries(struct pp_hwmgr *hwmgr) +{ + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + uint32_t firmware_type; + uint32_t i; + int ret; + enum cgs_ucode_id ucode_id; + struct cgs_firmware_info info = {0}; + + smu8_smu->driver_buffer_length = 0; + + for (i = 0; i < ARRAY_SIZE(firmware_list); i++) { + + firmware_type = smu8_translate_firmware_enum_to_arg(hwmgr, + firmware_list[i]); + + ucode_id = smu8_convert_fw_type_to_cgs(firmware_type); + + ret = cgs_get_firmware_info(hwmgr->device, + ucode_id, &info); + + if (ret == 0) { + smu8_smu->driver_buffer[i].mc_addr = info.mc_addr; + + smu8_smu->driver_buffer[i].data_size = info.image_size; + + smu8_smu->driver_buffer[i].firmware_ID = firmware_list[i]; + smu8_smu->driver_buffer_length++; + } + } + + return 0; +} + +static int smu8_smu_populate_single_scratch_entry( + struct pp_hwmgr *hwmgr, + enum smu8_scratch_entry scratch_type, + uint32_t ulsize_byte, + struct smu8_buffer_entry *entry) +{ + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + uint32_t ulsize_aligned = SIZE_ALIGN_32(ulsize_byte); + + entry->data_size = ulsize_byte; + entry->kaddr = (char *) smu8_smu->smu_buffer.kaddr + + smu8_smu->smu_buffer_used_bytes; + entry->mc_addr = smu8_smu->smu_buffer.mc_addr + smu8_smu->smu_buffer_used_bytes; + entry->firmware_ID = scratch_type; + + smu8_smu->smu_buffer_used_bytes += ulsize_aligned; + + return 0; +} + +static int smu8_download_pptable_settings(struct pp_hwmgr *hwmgr, void **table) +{ + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + unsigned long i; + + for (i = 0; i < smu8_smu->scratch_buffer_length; i++) { + if (smu8_smu->scratch_buffer[i].firmware_ID + == SMU8_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE) + break; + } + + *table = (struct SMU8_Fusion_ClkTable *)smu8_smu->scratch_buffer[i].kaddr; + + smu8_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetClkTableAddrHi, + upper_32_bits(smu8_smu->scratch_buffer[i].mc_addr)); + + smu8_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetClkTableAddrLo, + lower_32_bits(smu8_smu->scratch_buffer[i].mc_addr)); + + smu8_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_ExecuteJob, + smu8_smu->toc_entry_clock_table); + + smu8_send_msg_to_smc(hwmgr, PPSMC_MSG_ClkTableXferToDram); + + return 0; +} + +static int smu8_upload_pptable_settings(struct pp_hwmgr *hwmgr) +{ + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + unsigned long i; + + for (i = 0; i < smu8_smu->scratch_buffer_length; i++) { + if (smu8_smu->scratch_buffer[i].firmware_ID + == SMU8_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE) + break; + } + + smu8_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetClkTableAddrHi, + upper_32_bits(smu8_smu->scratch_buffer[i].mc_addr)); + + smu8_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetClkTableAddrLo, + lower_32_bits(smu8_smu->scratch_buffer[i].mc_addr)); + + smu8_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_ExecuteJob, + smu8_smu->toc_entry_clock_table); + + smu8_send_msg_to_smc(hwmgr, PPSMC_MSG_ClkTableXferToSmu); + + return 0; +} + +static int smu8_request_smu_load_fw(struct pp_hwmgr *hwmgr) +{ + struct smu8_smumgr *smu8_smu = hwmgr->smu_backend; + uint32_t smc_address; + + if (!hwmgr->reload_fw) { + pr_info("skip reloading...\n"); + return 0; + } + + smu8_smu_populate_firmware_entries(hwmgr); + + smu8_smu_construct_toc(hwmgr); + + smc_address = SMU8_FIRMWARE_HEADER_LOCATION + + offsetof(struct SMU8_Firmware_Header, UcodeLoadStatus); + + smu8_write_smc_sram_dword(hwmgr, smc_address, 0, smc_address+4); + + smu8_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_DriverDramAddrHi, + upper_32_bits(smu8_smu->toc_buffer.mc_addr)); + + smu8_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_DriverDramAddrLo, + lower_32_bits(smu8_smu->toc_buffer.mc_addr)); + + smu8_send_msg_to_smc(hwmgr, PPSMC_MSG_InitJobs); + + smu8_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_ExecuteJob, + smu8_smu->toc_entry_aram); + smu8_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_ExecuteJob, + smu8_smu->toc_entry_power_profiling_index); + + return smu8_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_ExecuteJob, + smu8_smu->toc_entry_initialize_index); +} + +static int smu8_start_smu(struct pp_hwmgr *hwmgr) +{ + int ret = 0; + uint32_t fw_to_check = 0; + struct amdgpu_device *adev = hwmgr->adev; + + uint32_t index = SMN_MP1_SRAM_START_ADDR + + SMU8_FIRMWARE_HEADER_LOCATION + + offsetof(struct SMU8_Firmware_Header, Version); + + + if (hwmgr == NULL || hwmgr->device == NULL) + return -EINVAL; + + cgs_write_register(hwmgr->device, mmMP0PUB_IND_INDEX, index); + hwmgr->smu_version = cgs_read_register(hwmgr->device, mmMP0PUB_IND_DATA); + adev->pm.fw_version = hwmgr->smu_version >> 8; + + fw_to_check = UCODE_ID_RLC_G_MASK | + UCODE_ID_SDMA0_MASK | + UCODE_ID_SDMA1_MASK | + UCODE_ID_CP_CE_MASK | + UCODE_ID_CP_ME_MASK | + UCODE_ID_CP_PFP_MASK | + UCODE_ID_CP_MEC_JT1_MASK | + UCODE_ID_CP_MEC_JT2_MASK; + + if (hwmgr->chip_id == CHIP_STONEY) + fw_to_check &= ~(UCODE_ID_SDMA1_MASK | UCODE_ID_CP_MEC_JT2_MASK); + + ret = smu8_request_smu_load_fw(hwmgr); + if (ret) + pr_err("SMU firmware load failed\n"); + + smu8_check_fw_load_finish(hwmgr, fw_to_check); + + ret = smu8_load_mec_firmware(hwmgr); + if (ret) + pr_err("Mec Firmware load failed\n"); + + return ret; +} + +static int smu8_smu_init(struct pp_hwmgr *hwmgr) +{ + int ret = 0; + struct smu8_smumgr *smu8_smu; + + smu8_smu = kzalloc(sizeof(struct smu8_smumgr), GFP_KERNEL); + if (smu8_smu == NULL) + return -ENOMEM; + + hwmgr->smu_backend = smu8_smu; + + smu8_smu->toc_buffer.data_size = 4096; + smu8_smu->smu_buffer.data_size = + ALIGN(UCODE_ID_RLC_SCRATCH_SIZE_BYTE, 32) + + ALIGN(UCODE_ID_RLC_SRM_ARAM_SIZE_BYTE, 32) + + ALIGN(UCODE_ID_RLC_SRM_DRAM_SIZE_BYTE, 32) + + ALIGN(sizeof(struct SMU8_MultimediaPowerLogData), 32) + + ALIGN(sizeof(struct SMU8_Fusion_ClkTable), 32); + + ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, + smu8_smu->toc_buffer.data_size, + PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, + &smu8_smu->toc_buffer.handle, + &smu8_smu->toc_buffer.mc_addr, + &smu8_smu->toc_buffer.kaddr); + if (ret) + goto err2; + + ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, + smu8_smu->smu_buffer.data_size, + PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, + &smu8_smu->smu_buffer.handle, + &smu8_smu->smu_buffer.mc_addr, + &smu8_smu->smu_buffer.kaddr); + if (ret) + goto err1; + + if (0 != smu8_smu_populate_single_scratch_entry(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH, + UCODE_ID_RLC_SCRATCH_SIZE_BYTE, + &smu8_smu->scratch_buffer[smu8_smu->scratch_buffer_length++])) { + pr_err("Error when Populate Firmware Entry.\n"); + goto err0; + } + + if (0 != smu8_smu_populate_single_scratch_entry(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM, + UCODE_ID_RLC_SRM_ARAM_SIZE_BYTE, + &smu8_smu->scratch_buffer[smu8_smu->scratch_buffer_length++])) { + pr_err("Error when Populate Firmware Entry.\n"); + goto err0; + } + if (0 != smu8_smu_populate_single_scratch_entry(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM, + UCODE_ID_RLC_SRM_DRAM_SIZE_BYTE, + &smu8_smu->scratch_buffer[smu8_smu->scratch_buffer_length++])) { + pr_err("Error when Populate Firmware Entry.\n"); + goto err0; + } + + if (0 != smu8_smu_populate_single_scratch_entry(hwmgr, + SMU8_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING, + sizeof(struct SMU8_MultimediaPowerLogData), + &smu8_smu->scratch_buffer[smu8_smu->scratch_buffer_length++])) { + pr_err("Error when Populate Firmware Entry.\n"); + goto err0; + } + + if (0 != smu8_smu_populate_single_scratch_entry(hwmgr, + SMU8_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE, + sizeof(struct SMU8_Fusion_ClkTable), + &smu8_smu->scratch_buffer[smu8_smu->scratch_buffer_length++])) { + pr_err("Error when Populate Firmware Entry.\n"); + goto err0; + } + + return 0; + +err0: + amdgpu_bo_free_kernel(&smu8_smu->smu_buffer.handle, + &smu8_smu->smu_buffer.mc_addr, + &smu8_smu->smu_buffer.kaddr); +err1: + amdgpu_bo_free_kernel(&smu8_smu->toc_buffer.handle, + &smu8_smu->toc_buffer.mc_addr, + &smu8_smu->toc_buffer.kaddr); +err2: + kfree(smu8_smu); + return -EINVAL; +} + +static int smu8_smu_fini(struct pp_hwmgr *hwmgr) +{ + struct smu8_smumgr *smu8_smu; + + if (hwmgr == NULL || hwmgr->device == NULL) + return -EINVAL; + + smu8_smu = hwmgr->smu_backend; + if (smu8_smu) { + amdgpu_bo_free_kernel(&smu8_smu->toc_buffer.handle, + &smu8_smu->toc_buffer.mc_addr, + &smu8_smu->toc_buffer.kaddr); + amdgpu_bo_free_kernel(&smu8_smu->smu_buffer.handle, + &smu8_smu->smu_buffer.mc_addr, + &smu8_smu->smu_buffer.kaddr); + kfree(smu8_smu); + } + + return 0; +} + +static bool smu8_dpm_check_smu_features(struct pp_hwmgr *hwmgr, + unsigned long check_feature) +{ + int result; + unsigned long features; + + result = smu8_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetFeatureStatus, 0); + if (result == 0) { + features = smum_get_argument(hwmgr); + if (features & check_feature) + return true; + } + + return false; +} + +static bool smu8_is_dpm_running(struct pp_hwmgr *hwmgr) +{ + if (smu8_dpm_check_smu_features(hwmgr, SMU_EnabledFeatureScoreboard_SclkDpmOn)) + return true; + return false; +} + +const struct pp_smumgr_func smu8_smu_funcs = { + .smu_init = smu8_smu_init, + .smu_fini = smu8_smu_fini, + .start_smu = smu8_start_smu, + .check_fw_load_finish = smu8_check_fw_load_finish, + .request_smu_load_fw = NULL, + .request_smu_load_specific_fw = NULL, + .get_argument = smu8_get_argument, + .send_msg_to_smc = smu8_send_msg_to_smc, + .send_msg_to_smc_with_parameter = smu8_send_msg_to_smc_with_parameter, + .download_pptable_settings = smu8_download_pptable_settings, + .upload_pptable_settings = smu8_upload_pptable_settings, + .is_dpm_running = smu8_is_dpm_running, +}; + diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.h new file mode 100644 index 000000000000..c7b61222d258 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.h @@ -0,0 +1,99 @@ +/* + * 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. + * + */ +#ifndef _SMU8_SMUMGR_H_ +#define _SMU8_SMUMGR_H_ + + +#define MAX_NUM_FIRMWARE 8 +#define MAX_NUM_SCRATCH 11 +#define SMU8_SCRATCH_SIZE_NONGFX_CLOCKGATING 1024 +#define SMU8_SCRATCH_SIZE_NONGFX_GOLDENSETTING 2048 +#define SMU8_SCRATCH_SIZE_SDMA_METADATA 1024 +#define SMU8_SCRATCH_SIZE_IH ((2*256+1)*4) + +#define SMU_EnabledFeatureScoreboard_SclkDpmOn 0x00200000 + +enum smu8_scratch_entry { + SMU8_SCRATCH_ENTRY_UCODE_ID_SDMA0 = 0, + SMU8_SCRATCH_ENTRY_UCODE_ID_SDMA1, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_CE, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_PFP, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_ME, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT1, + SMU8_SCRATCH_ENTRY_UCODE_ID_CP_MEC_JT2, + SMU8_SCRATCH_ENTRY_UCODE_ID_GMCON_RENG, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_G, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SCRATCH, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_ARAM, + SMU8_SCRATCH_ENTRY_UCODE_ID_RLC_SRM_DRAM, + SMU8_SCRATCH_ENTRY_UCODE_ID_DMCU_ERAM, + SMU8_SCRATCH_ENTRY_UCODE_ID_DMCU_IRAM, + SMU8_SCRATCH_ENTRY_UCODE_ID_POWER_PROFILING, + SMU8_SCRATCH_ENTRY_DATA_ID_SDMA_HALT, + SMU8_SCRATCH_ENTRY_DATA_ID_SYS_CLOCKGATING, + SMU8_SCRATCH_ENTRY_DATA_ID_SDMA_RING_REGS, + SMU8_SCRATCH_ENTRY_DATA_ID_NONGFX_REINIT, + SMU8_SCRATCH_ENTRY_DATA_ID_SDMA_START, + SMU8_SCRATCH_ENTRY_DATA_ID_IH_REGISTERS, + SMU8_SCRATCH_ENTRY_SMU8_FUSION_CLKTABLE +}; + +struct smu8_buffer_entry { + uint32_t data_size; + uint64_t mc_addr; + void *kaddr; + enum smu8_scratch_entry firmware_ID; + struct amdgpu_bo *handle; /* as bo handle used when release bo */ +}; + +struct smu8_register_index_data_pair { + uint32_t offset; + uint32_t value; +}; + +struct smu8_ih_meta_data { + uint32_t command; + struct smu8_register_index_data_pair register_index_value_pair[1]; +}; + +struct smu8_smumgr { + uint8_t driver_buffer_length; + uint8_t scratch_buffer_length; + uint16_t toc_entry_used_count; + uint16_t toc_entry_initialize_index; + uint16_t toc_entry_power_profiling_index; + uint16_t toc_entry_aram; + uint16_t toc_entry_ih_register_restore_task_index; + uint16_t toc_entry_clock_table; + uint16_t ih_register_restore_task_size; + uint16_t smu_buffer_used_bytes; + + struct smu8_buffer_entry toc_buffer; + struct smu8_buffer_entry smu_buffer; + struct smu8_buffer_entry firmware_buffer; + struct smu8_buffer_entry driver_buffer[MAX_NUM_FIRMWARE]; + struct smu8_buffer_entry meta_data_buffer[MAX_NUM_FIRMWARE]; + struct smu8_buffer_entry scratch_buffer[MAX_NUM_SCRATCH]; +}; + +#endif diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c index 867388456530..c28b60aae5f8 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c @@ -28,7 +28,6 @@ #include <linux/types.h> #include <drm/amdgpu_drm.h> #include "smumgr.h" -#include "cgs_common.h" MODULE_FIRMWARE("amdgpu/topaz_smc.bin"); MODULE_FIRMWARE("amdgpu/topaz_k_smc.bin"); @@ -44,6 +43,7 @@ MODULE_FIRMWARE("amdgpu/polaris11_k_smc.bin"); MODULE_FIRMWARE("amdgpu/polaris12_smc.bin"); MODULE_FIRMWARE("amdgpu/vega10_smc.bin"); MODULE_FIRMWARE("amdgpu/vega10_acg_smc.bin"); +MODULE_FIRMWARE("amdgpu/vega12_smc.bin"); int smum_thermal_avfs_enable(struct pp_hwmgr *hwmgr) { @@ -144,57 +144,6 @@ int smum_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, hwmgr, msg, parameter); } -int smu_allocate_memory(void *device, uint32_t size, - enum cgs_gpu_mem_type type, - uint32_t byte_align, uint64_t *mc_addr, - void **kptr, void *handle) -{ - int ret = 0; - cgs_handle_t cgs_handle; - - if (device == NULL || handle == NULL || - mc_addr == NULL || kptr == NULL) - return -EINVAL; - - ret = cgs_alloc_gpu_mem(device, type, size, byte_align, - (cgs_handle_t *)handle); - if (ret) - return -ENOMEM; - - cgs_handle = *(cgs_handle_t *)handle; - - ret = cgs_gmap_gpu_mem(device, cgs_handle, mc_addr); - if (ret) - goto error_gmap; - - ret = cgs_kmap_gpu_mem(device, cgs_handle, kptr); - if (ret) - goto error_kmap; - - return 0; - -error_kmap: - cgs_gunmap_gpu_mem(device, cgs_handle); - -error_gmap: - cgs_free_gpu_mem(device, cgs_handle); - return ret; -} - -int smu_free_memory(void *device, void *handle) -{ - cgs_handle_t cgs_handle = (cgs_handle_t)handle; - - if (device == NULL || handle == NULL) - return -EINVAL; - - cgs_kunmap_gpu_mem(device, cgs_handle); - cgs_gunmap_gpu_mem(device, cgs_handle); - cgs_free_gpu_mem(device, cgs_handle); - - return 0; -} - int smum_init_smc_table(struct pp_hwmgr *hwmgr) { if (NULL != hwmgr->smumgr_funcs->init_smc_table) @@ -236,16 +185,6 @@ bool smum_is_dpm_running(struct pp_hwmgr *hwmgr) return true; } -int smum_populate_requested_graphic_levels(struct pp_hwmgr *hwmgr, - struct amd_pp_profile *request) -{ - if (hwmgr->smumgr_funcs->populate_requested_graphic_levels) - return hwmgr->smumgr_funcs->populate_requested_graphic_levels( - hwmgr, request); - - return 0; -} - bool smum_is_hw_avfs_present(struct pp_hwmgr *hwmgr) { if (hwmgr->smumgr_funcs->is_hw_avfs_present) @@ -253,3 +192,19 @@ bool smum_is_hw_avfs_present(struct pp_hwmgr *hwmgr) return false; } + +int smum_update_dpm_settings(struct pp_hwmgr *hwmgr, void *profile_setting) +{ + if (hwmgr->smumgr_funcs->update_dpm_settings) + return hwmgr->smumgr_funcs->update_dpm_settings(hwmgr, profile_setting); + + return -EINVAL; +} + +int smum_smc_table_manager(struct pp_hwmgr *hwmgr, uint8_t *table, uint16_t table_id, bool rw) +{ + if (hwmgr->smumgr_funcs->smc_table_manager) + return hwmgr->smumgr_funcs->smc_table_manager(hwmgr, table, table_id, rw); + + return -EINVAL; +} diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c index 79e5c05571bc..b51d7468c3e7 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c @@ -222,7 +222,6 @@ static int tonga_start_smu(struct pp_hwmgr *hwmgr) static int tonga_smu_init(struct pp_hwmgr *hwmgr) { struct tonga_smumgr *tonga_priv = NULL; - int i; tonga_priv = kzalloc(sizeof(struct tonga_smumgr), GFP_KERNEL); if (tonga_priv == NULL) @@ -230,11 +229,10 @@ static int tonga_smu_init(struct pp_hwmgr *hwmgr) hwmgr->smu_backend = tonga_priv; - if (smu7_init(hwmgr)) + if (smu7_init(hwmgr)) { + kfree(tonga_priv); return -EINVAL; - - for (i = 0; i < SMU72_MAX_LEVELS_GRAPHICS; i++) - tonga_priv->activity_target[i] = 30; + } return 0; } @@ -416,7 +414,7 @@ static int tonga_populate_cac_tables(struct pp_hwmgr *hwmgr, convert_to_vid(vddc_lookup_table->entries[index].us_cac_high); } - if ((data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2)) { + if (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) { /* We are populating vddgfx CAC data to BapmVddgfx table in split mode */ for (count = 0; count < vddgfx_level_count; count++) { index = phm_get_voltage_index(vddgfx_lookup_table, @@ -612,7 +610,6 @@ static int tonga_calculate_sclk_params(struct pp_hwmgr *hwmgr, static int tonga_populate_single_graphic_level(struct pp_hwmgr *hwmgr, uint32_t engine_clock, - uint16_t sclk_activity_level_threshold, SMU72_Discrete_GraphicsLevel *graphic_level) { int result; @@ -620,12 +617,18 @@ static int tonga_populate_single_graphic_level(struct pp_hwmgr *hwmgr, struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable); + phm_ppt_v1_clock_voltage_dependency_table *vdd_dep_table = NULL; result = tonga_calculate_sclk_params(hwmgr, engine_clock, graphic_level); + if (hwmgr->od_enabled) + vdd_dep_table = (phm_ppt_v1_clock_voltage_dependency_table *)&data->odn_dpm_table.vdd_dependency_on_sclk; + else + vdd_dep_table = pptable_info->vdd_dep_on_sclk; + /* populate graphics levels*/ result = tonga_get_dependency_volt_by_clk(hwmgr, - pptable_info->vdd_dep_on_sclk, engine_clock, + vdd_dep_table, engine_clock, &graphic_level->MinVoltage, &mvdd); PP_ASSERT_WITH_CODE((!result), "can not find VDDC voltage value for VDDC " @@ -634,7 +637,7 @@ static int tonga_populate_single_graphic_level(struct pp_hwmgr *hwmgr, /* SCLK frequency in units of 10KHz*/ graphic_level->SclkFrequency = engine_clock; /* Indicates maximum activity level for this performance level. 50% for now*/ - graphic_level->ActivityLevel = sclk_activity_level_threshold; + graphic_level->ActivityLevel = data->current_profile_setting.sclk_activity; graphic_level->CcPwrDynRm = 0; graphic_level->CcPwrDynRm1 = 0; @@ -642,8 +645,8 @@ static int tonga_populate_single_graphic_level(struct pp_hwmgr *hwmgr, graphic_level->EnabledForActivity = 0; /* this level can be used for throttling.*/ graphic_level->EnabledForThrottle = 1; - graphic_level->UpHyst = 0; - graphic_level->DownHyst = 0; + graphic_level->UpHyst = data->current_profile_setting.sclk_up_hyst; + graphic_level->DownHyst = data->current_profile_setting.sclk_down_hyst; graphic_level->VoltageDownHyst = 0; graphic_level->PowerThrottle = 0; @@ -702,7 +705,6 @@ static int tonga_populate_all_graphic_levels(struct pp_hwmgr *hwmgr) for (i = 0; i < dpm_table->sclk_table.count; i++) { result = tonga_populate_single_graphic_level(hwmgr, dpm_table->sclk_table.dpm_levels[i].value, - (uint16_t)smu_data->activity_target[i], &(smu_data->smc_state_table.GraphicsLevel[i])); if (result != 0) return result; @@ -966,10 +968,16 @@ static int tonga_populate_single_memory_level( uint32_t mclk_stutter_mode_threshold = 30000; uint32_t mclk_edc_enable_threshold = 40000; uint32_t mclk_strobe_mode_threshold = 40000; + phm_ppt_v1_clock_voltage_dependency_table *vdd_dep_table = NULL; - if (NULL != pptable_info->vdd_dep_on_mclk) { + if (hwmgr->od_enabled) + vdd_dep_table = (phm_ppt_v1_clock_voltage_dependency_table *)&data->odn_dpm_table.vdd_dependency_on_mclk; + else + vdd_dep_table = pptable_info->vdd_dep_on_mclk; + + if (NULL != vdd_dep_table) { result = tonga_get_dependency_volt_by_clk(hwmgr, - pptable_info->vdd_dep_on_mclk, + vdd_dep_table, memory_clock, &memory_level->MinVoltage, &mvdd); PP_ASSERT_WITH_CODE( @@ -986,12 +994,12 @@ static int tonga_populate_single_memory_level( memory_level->EnabledForThrottle = 1; memory_level->EnabledForActivity = 0; - memory_level->UpHyst = 0; - memory_level->DownHyst = 100; + memory_level->UpHyst = data->current_profile_setting.mclk_up_hyst; + memory_level->DownHyst = data->current_profile_setting.mclk_down_hyst; memory_level->VoltageDownHyst = 0; /* Indicates maximum activity level for this performance level.*/ - memory_level->ActivityLevel = (uint16_t)data->mclk_activity_target; + memory_level->ActivityLevel = data->current_profile_setting.mclk_activity; memory_level->StutterEnable = 0; memory_level->StrobeEnable = 0; memory_level->EdcReadEnable = 0; @@ -1281,7 +1289,7 @@ static int tonga_populate_smc_acpi_level(struct pp_hwmgr *hwmgr, table->MemoryACPILevel.VoltageDownHyst = 0; /* Indicates maximum activity level for this performance level.*/ table->MemoryACPILevel.ActivityLevel = - PP_HOST_TO_SMC_US((uint16_t)data->mclk_activity_target); + PP_HOST_TO_SMC_US(data->current_profile_setting.mclk_activity); table->MemoryACPILevel.StutterEnable = 0; table->MemoryACPILevel.StrobeEnable = 0; @@ -1617,19 +1625,12 @@ static int tonga_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr) struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table = table_info->vdd_dep_on_sclk; uint32_t hw_revision, dev_id; - struct cgs_system_info sys_info = {0}; + struct amdgpu_device *adev = hwmgr->adev; stretch_amount = (uint8_t)table_info->cac_dtp_table->usClockStretchAmount; - sys_info.size = sizeof(struct cgs_system_info); - - sys_info.info_id = CGS_SYSTEM_INFO_PCIE_REV; - cgs_query_system_info(hwmgr->device, &sys_info); - hw_revision = (uint32_t)sys_info.value; - - sys_info.info_id = CGS_SYSTEM_INFO_PCIE_DEV; - cgs_query_system_info(hwmgr->device, &sys_info); - dev_id = (uint32_t)sys_info.value; + hw_revision = adev->pdev->revision; + dev_id = adev->pdev->device; /* Read SMU_Eefuse to read and calculate RO and determine * if the part is SS or FF. if RO >= 1660MHz, part is FF. @@ -1699,7 +1700,7 @@ static int tonga_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr) phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_ClockStretcher); PP_ASSERT_WITH_CODE(false, - "Stretch Amount in PPTable not supported\n", + "Stretch Amount in PPTable not supported", return -EINVAL); } @@ -2257,42 +2258,6 @@ static void tonga_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr) smu_data->power_tune_defaults = &tonga_power_tune_data_set_array[0]; } -static void tonga_save_default_power_profile(struct pp_hwmgr *hwmgr) -{ - struct tonga_smumgr *data = (struct tonga_smumgr *)(hwmgr->smu_backend); - struct SMU72_Discrete_GraphicsLevel *levels = - data->smc_state_table.GraphicsLevel; - unsigned min_level = 1; - - hwmgr->default_gfx_power_profile.activity_threshold = - be16_to_cpu(levels[0].ActivityLevel); - hwmgr->default_gfx_power_profile.up_hyst = levels[0].UpHyst; - hwmgr->default_gfx_power_profile.down_hyst = levels[0].DownHyst; - hwmgr->default_gfx_power_profile.type = AMD_PP_GFX_PROFILE; - - hwmgr->default_compute_power_profile = hwmgr->default_gfx_power_profile; - hwmgr->default_compute_power_profile.type = AMD_PP_COMPUTE_PROFILE; - - /* Workaround compute SDMA instability: disable lowest SCLK - * DPM level. Optimize compute power profile: Use only highest - * 2 power levels (if more than 2 are available), Hysteresis: - * 0ms up, 5ms down - */ - if (data->smc_state_table.GraphicsDpmLevelCount > 2) - min_level = data->smc_state_table.GraphicsDpmLevelCount - 2; - else if (data->smc_state_table.GraphicsDpmLevelCount == 2) - min_level = 1; - else - min_level = 0; - hwmgr->default_compute_power_profile.min_sclk = - be32_to_cpu(levels[min_level].SclkFrequency); - hwmgr->default_compute_power_profile.up_hyst = 0; - hwmgr->default_compute_power_profile.down_hyst = 5; - - hwmgr->gfx_power_profile = hwmgr->default_gfx_power_profile; - hwmgr->compute_power_profile = hwmgr->default_compute_power_profile; -} - static int tonga_init_smc_table(struct pp_hwmgr *hwmgr) { int result; @@ -2434,7 +2399,7 @@ static int tonga_init_smc_table(struct pp_hwmgr *hwmgr) result = tonga_populate_vr_config(hwmgr, table); PP_ASSERT_WITH_CODE(!result, "Failed to populate VRConfig setting !", return result); - + data->vr_config = table->VRConfig; table->ThermGpio = 17; table->SclkStepSize = 0x4000; @@ -2501,7 +2466,6 @@ static int tonga_init_smc_table(struct pp_hwmgr *hwmgr) for (i = 0; i < SMU72_MAX_ENTRIES_SMIO; i++) table->Smio[i] = PP_HOST_TO_SMC_UL(table->Smio[i]); - CONVERT_FROM_HOST_TO_SMC_UL(table->SystemFlags); CONVERT_FROM_HOST_TO_SMC_UL(table->VRConfig); CONVERT_FROM_HOST_TO_SMC_UL(table->SmioMask1); @@ -2535,8 +2499,6 @@ static int tonga_init_smc_table(struct pp_hwmgr *hwmgr) PP_ASSERT_WITH_CODE((!result), "Failed to populate initialize MC Reg table !", return result); - tonga_save_default_power_profile(hwmgr); - return 0; } @@ -2612,7 +2574,7 @@ static int tonga_thermal_setup_fan_table(struct pp_hwmgr *hwmgr) fan_table.TempRespLim = cpu_to_be16(5); - reference_clock = smu7_get_xclk(hwmgr); + reference_clock = amdgpu_asic_get_xclk((struct amdgpu_device *)hwmgr->adev); fan_table.RefreshPeriod = cpu_to_be32((hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay * reference_clock) / 1600); @@ -3254,29 +3216,100 @@ static bool tonga_is_dpm_running(struct pp_hwmgr *hwmgr) ? true : false; } -static int tonga_populate_requested_graphic_levels(struct pp_hwmgr *hwmgr, - struct amd_pp_profile *request) +static int tonga_update_dpm_settings(struct pp_hwmgr *hwmgr, + void *profile_setting) { + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); struct tonga_smumgr *smu_data = (struct tonga_smumgr *) (hwmgr->smu_backend); + struct profile_mode_setting *setting; struct SMU72_Discrete_GraphicsLevel *levels = smu_data->smc_state_table.GraphicsLevel; uint32_t array = smu_data->smu7_data.dpm_table_start + offsetof(SMU72_Discrete_DpmTable, GraphicsLevel); - uint32_t array_size = sizeof(struct SMU72_Discrete_GraphicsLevel) * - SMU72_MAX_LEVELS_GRAPHICS; + + uint32_t mclk_array = smu_data->smu7_data.dpm_table_start + + offsetof(SMU72_Discrete_DpmTable, MemoryLevel); + struct SMU72_Discrete_MemoryLevel *mclk_levels = + smu_data->smc_state_table.MemoryLevel; uint32_t i; + uint32_t offset, up_hyst_offset, down_hyst_offset, clk_activity_offset, tmp; + + if (profile_setting == NULL) + return -EINVAL; + + setting = (struct profile_mode_setting *)profile_setting; - for (i = 0; i < smu_data->smc_state_table.GraphicsDpmLevelCount; i++) { - levels[i].ActivityLevel = - cpu_to_be16(request->activity_threshold); - levels[i].EnabledForActivity = 1; - levels[i].UpHyst = request->up_hyst; - levels[i].DownHyst = request->down_hyst; + if (setting->bupdate_sclk) { + if (!data->sclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_FreezeLevel); + for (i = 0; i < smu_data->smc_state_table.GraphicsDpmLevelCount; i++) { + if (levels[i].ActivityLevel != + cpu_to_be16(setting->sclk_activity)) { + levels[i].ActivityLevel = cpu_to_be16(setting->sclk_activity); + + clk_activity_offset = array + (sizeof(SMU72_Discrete_GraphicsLevel) * i) + + offsetof(SMU72_Discrete_GraphicsLevel, ActivityLevel); + offset = clk_activity_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(clk_activity_offset, tmp, levels[i].ActivityLevel, sizeof(uint16_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + + } + if (levels[i].UpHyst != setting->sclk_up_hyst || + levels[i].DownHyst != setting->sclk_down_hyst) { + levels[i].UpHyst = setting->sclk_up_hyst; + levels[i].DownHyst = setting->sclk_down_hyst; + up_hyst_offset = array + (sizeof(SMU72_Discrete_GraphicsLevel) * i) + + offsetof(SMU72_Discrete_GraphicsLevel, UpHyst); + down_hyst_offset = array + (sizeof(SMU72_Discrete_GraphicsLevel) * i) + + offsetof(SMU72_Discrete_GraphicsLevel, DownHyst); + offset = up_hyst_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(up_hyst_offset, tmp, levels[i].UpHyst, sizeof(uint8_t)); + tmp = phm_set_field_to_u32(down_hyst_offset, tmp, levels[i].DownHyst, sizeof(uint8_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + } + } + if (!data->sclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_SCLKDPM_UnfreezeLevel); } - return smu7_copy_bytes_to_smc(hwmgr, array, (uint8_t *)levels, - array_size, SMC_RAM_END); + if (setting->bupdate_mclk) { + if (!data->mclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_FreezeLevel); + for (i = 0; i < smu_data->smc_state_table.MemoryDpmLevelCount; i++) { + if (mclk_levels[i].ActivityLevel != + cpu_to_be16(setting->mclk_activity)) { + mclk_levels[i].ActivityLevel = cpu_to_be16(setting->mclk_activity); + + clk_activity_offset = mclk_array + (sizeof(SMU72_Discrete_MemoryLevel) * i) + + offsetof(SMU72_Discrete_MemoryLevel, ActivityLevel); + offset = clk_activity_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(clk_activity_offset, tmp, mclk_levels[i].ActivityLevel, sizeof(uint16_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + + } + if (mclk_levels[i].UpHyst != setting->mclk_up_hyst || + mclk_levels[i].DownHyst != setting->mclk_down_hyst) { + mclk_levels[i].UpHyst = setting->mclk_up_hyst; + mclk_levels[i].DownHyst = setting->mclk_down_hyst; + up_hyst_offset = mclk_array + (sizeof(SMU72_Discrete_MemoryLevel) * i) + + offsetof(SMU72_Discrete_MemoryLevel, UpHyst); + down_hyst_offset = mclk_array + (sizeof(SMU72_Discrete_MemoryLevel) * i) + + offsetof(SMU72_Discrete_MemoryLevel, DownHyst); + offset = up_hyst_offset & ~0x3; + tmp = PP_HOST_TO_SMC_UL(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset)); + tmp = phm_set_field_to_u32(up_hyst_offset, tmp, mclk_levels[i].UpHyst, sizeof(uint8_t)); + tmp = phm_set_field_to_u32(down_hyst_offset, tmp, mclk_levels[i].DownHyst, sizeof(uint8_t)); + cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset, PP_HOST_TO_SMC_UL(tmp)); + } + } + if (!data->mclk_dpm_key_disabled) + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_UnfreezeLevel); + } + return 0; } const struct pp_smumgr_func tonga_smu_funcs = { @@ -3301,5 +3334,5 @@ const struct pp_smumgr_func tonga_smu_funcs = { .get_mac_definition = tonga_get_mac_definition, .initialize_mc_reg_table = tonga_initialize_mc_reg_table, .is_dpm_running = tonga_is_dpm_running, - .populate_requested_graphic_levels = tonga_populate_requested_graphic_levels, + .update_dpm_settings = tonga_update_dpm_settings, }; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.h index 5d70a00348e2..d664fedd3d85 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.h @@ -69,9 +69,6 @@ struct tonga_smumgr { const struct tonga_pt_defaults *power_tune_defaults; SMU72_Discrete_MCRegisters mc_regs; struct tonga_mc_reg_table mc_reg_table; - - uint32_t activity_target[SMU72_MAX_LEVELS_GRAPHICS]; - }; #endif diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c index f6f39d01d227..4aafb043bcb0 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c @@ -25,13 +25,12 @@ #include "vega10_inc.h" #include "pp_soc15.h" #include "vega10_smumgr.h" +#include "vega10_hwmgr.h" #include "vega10_ppsmc.h" #include "smu9_driver_if.h" - #include "ppatomctrl.h" #include "pp_debug.h" -#include "smu_ucode_xfer_vi.h" -#include "smu7_smumgr.h" + #define AVFS_EN_MSB 1568 #define AVFS_EN_LSB 1568 @@ -83,16 +82,17 @@ static bool vega10_is_smc_ram_running(struct pp_hwmgr *hwmgr) static uint32_t vega10_wait_for_response(struct pp_hwmgr *hwmgr) { uint32_t reg; - - if (!vega10_is_smc_ram_running(hwmgr)) - return -EINVAL; + uint32_t ret; reg = soc15_get_register_offset(MP1_HWID, 0, mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90); - phm_wait_for_register_unequal(hwmgr, reg, + ret = phm_wait_for_register_unequal(hwmgr, reg, 0, MP1_C2PMSG_90__CONTENT_MASK); + if (ret) + pr_err("No response from smu\n"); + return cgs_read_register(hwmgr->device, reg); } @@ -102,14 +102,11 @@ static uint32_t vega10_wait_for_response(struct pp_hwmgr *hwmgr) * @param msg the message to send. * @return Always return 0. */ -int vega10_send_msg_to_smc_without_waiting(struct pp_hwmgr *hwmgr, +static int vega10_send_msg_to_smc_without_waiting(struct pp_hwmgr *hwmgr, uint16_t msg) { uint32_t reg; - if (!vega10_is_smc_ram_running(hwmgr)) - return -EINVAL; - reg = soc15_get_register_offset(MP1_HWID, 0, mmMP1_SMN_C2PMSG_66_BASE_IDX, mmMP1_SMN_C2PMSG_66); cgs_write_register(hwmgr->device, reg, msg); @@ -123,12 +120,10 @@ int vega10_send_msg_to_smc_without_waiting(struct pp_hwmgr *hwmgr, * @param msg the message to send. * @return Always return 0. */ -int vega10_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg) +static int vega10_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg) { uint32_t reg; - - if (!vega10_is_smc_ram_running(hwmgr)) - return -EINVAL; + uint32_t ret; vega10_wait_for_response(hwmgr); @@ -138,8 +133,9 @@ int vega10_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg) vega10_send_msg_to_smc_without_waiting(hwmgr, msg); - if (vega10_wait_for_response(hwmgr) != 1) - pr_err("Failed to send message: 0x%x\n", msg); + ret = vega10_wait_for_response(hwmgr); + if (ret != 1) + pr_err("Failed to send message: 0x%x, ret value: 0x%x\n", msg, ret); return 0; } @@ -151,13 +147,11 @@ int vega10_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg) * @param parameter: the parameter to send * @return Always return 0. */ -int vega10_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, +static int vega10_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, uint16_t msg, uint32_t parameter) { uint32_t reg; - - if (!vega10_is_smc_ram_running(hwmgr)) - return -EINVAL; + uint32_t ret; vega10_wait_for_response(hwmgr); @@ -171,60 +165,27 @@ int vega10_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, vega10_send_msg_to_smc_without_waiting(hwmgr, msg); - if (vega10_wait_for_response(hwmgr) != 1) - pr_err("Failed to send message: 0x%x\n", msg); + ret = vega10_wait_for_response(hwmgr); + if (ret != 1) + pr_err("Failed message: 0x%x, input parameter: 0x%x, error code: 0x%x\n", msg, parameter, ret); return 0; } - -/* - * Send a message to the SMC with parameter, do not wait for response - * @param hwmgr: the address of the powerplay hardware manager. - * @param msg: the message to send. - * @param parameter: the parameter to send - * @return The response that came from the SMC. - */ -int vega10_send_msg_to_smc_with_parameter_without_waiting( - struct pp_hwmgr *hwmgr, uint16_t msg, uint32_t parameter) +static int vega10_get_argument(struct pp_hwmgr *hwmgr) { uint32_t reg; reg = soc15_get_register_offset(MP1_HWID, 0, mmMP1_SMN_C2PMSG_82_BASE_IDX, mmMP1_SMN_C2PMSG_82); - cgs_write_register(hwmgr->device, reg, parameter); - return vega10_send_msg_to_smc_without_waiting(hwmgr, msg); -} - -/* - * Retrieve an argument from SMC. - * @param hwmgr the address of the powerplay hardware manager. - * @param arg pointer to store the argument from SMC. - * @return Always return 0. - */ -int vega10_read_arg_from_smc(struct pp_hwmgr *hwmgr, uint32_t *arg) -{ - uint32_t reg; - - reg = soc15_get_register_offset(MP1_HWID, 0, - mmMP1_SMN_C2PMSG_82_BASE_IDX, mmMP1_SMN_C2PMSG_82); - - *arg = cgs_read_register(hwmgr->device, reg); - - return 0; + return cgs_read_register(hwmgr->device, reg); } -/* - * Copy table from SMC into driver FB - * @param hwmgr the address of the HW manager - * @param table_id the driver's table ID to copy from - */ -int vega10_copy_table_from_smc(struct pp_hwmgr *hwmgr, +static int vega10_copy_table_from_smc(struct pp_hwmgr *hwmgr, uint8_t *table, int16_t table_id) { - struct vega10_smumgr *priv = - (struct vega10_smumgr *)(hwmgr->smu_backend); + struct vega10_smumgr *priv = hwmgr->smu_backend; PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE, "Invalid SMU Table ID!", return -EINVAL); @@ -232,20 +193,15 @@ int vega10_copy_table_from_smc(struct pp_hwmgr *hwmgr, "Invalid SMU Table version!", return -EINVAL); PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0, "Invalid SMU Table Length!", return -EINVAL); - PP_ASSERT_WITH_CODE(vega10_send_msg_to_smc_with_parameter(hwmgr, + vega10_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetDriverDramAddrHigh, - priv->smu_tables.entry[table_id].table_addr_high) == 0, - "[CopyTableFromSMC] Attempt to Set Dram Addr High Failed!", return -EINVAL); - PP_ASSERT_WITH_CODE(vega10_send_msg_to_smc_with_parameter(hwmgr, + upper_32_bits(priv->smu_tables.entry[table_id].mc_addr)); + vega10_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetDriverDramAddrLow, - priv->smu_tables.entry[table_id].table_addr_low) == 0, - "[CopyTableFromSMC] Attempt to Set Dram Addr Low Failed!", - return -EINVAL); - PP_ASSERT_WITH_CODE(vega10_send_msg_to_smc_with_parameter(hwmgr, + lower_32_bits(priv->smu_tables.entry[table_id].mc_addr)); + vega10_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_TransferTableSmu2Dram, - priv->smu_tables.entry[table_id].table_id) == 0, - "[CopyTableFromSMC] Attempt to Transfer Table From SMU Failed!", - return -EINVAL); + priv->smu_tables.entry[table_id].table_id); memcpy(table, priv->smu_tables.entry[table_id].table, priv->smu_tables.entry[table_id].size); @@ -253,16 +209,10 @@ int vega10_copy_table_from_smc(struct pp_hwmgr *hwmgr, return 0; } -/* - * Copy table from Driver FB into SMC - * @param hwmgr the address of the HW manager - * @param table_id the table to copy from - */ -int vega10_copy_table_to_smc(struct pp_hwmgr *hwmgr, +static int vega10_copy_table_to_smc(struct pp_hwmgr *hwmgr, uint8_t *table, int16_t table_id) { - struct vega10_smumgr *priv = - (struct vega10_smumgr *)(hwmgr->smu_backend); + struct vega10_smumgr *priv = hwmgr->smu_backend; PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE, "Invalid SMU Table ID!", return -EINVAL); @@ -274,81 +224,54 @@ int vega10_copy_table_to_smc(struct pp_hwmgr *hwmgr, memcpy(priv->smu_tables.entry[table_id].table, table, priv->smu_tables.entry[table_id].size); - PP_ASSERT_WITH_CODE(vega10_send_msg_to_smc_with_parameter(hwmgr, + vega10_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetDriverDramAddrHigh, - priv->smu_tables.entry[table_id].table_addr_high) == 0, - "[CopyTableToSMC] Attempt to Set Dram Addr High Failed!", - return -EINVAL;); - PP_ASSERT_WITH_CODE(vega10_send_msg_to_smc_with_parameter(hwmgr, + upper_32_bits(priv->smu_tables.entry[table_id].mc_addr)); + vega10_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetDriverDramAddrLow, - priv->smu_tables.entry[table_id].table_addr_low) == 0, - "[CopyTableToSMC] Attempt to Set Dram Addr Low Failed!", - return -EINVAL); - PP_ASSERT_WITH_CODE(vega10_send_msg_to_smc_with_parameter(hwmgr, + lower_32_bits(priv->smu_tables.entry[table_id].mc_addr)); + vega10_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_TransferTableDram2Smu, - priv->smu_tables.entry[table_id].table_id) == 0, - "[CopyTableToSMC] Attempt to Transfer Table To SMU Failed!", - return -EINVAL); + priv->smu_tables.entry[table_id].table_id); return 0; } -int vega10_save_vft_table(struct pp_hwmgr *hwmgr, uint8_t *avfs_table) -{ - PP_ASSERT_WITH_CODE(avfs_table, - "No access to SMC AVFS Table", - return -EINVAL); - - return vega10_copy_table_from_smc(hwmgr, avfs_table, AVFSTABLE); -} - -int vega10_restore_vft_table(struct pp_hwmgr *hwmgr, uint8_t *avfs_table) +static int vega10_get_smc_features(struct pp_hwmgr *hwmgr, + uint32_t *features_enabled) { - PP_ASSERT_WITH_CODE(avfs_table, - "No access to SMC AVFS Table", - return -EINVAL); - - return vega10_copy_table_to_smc(hwmgr, avfs_table, AVFSTABLE); -} + if (features_enabled == NULL) + return -EINVAL; -int vega10_enable_smc_features(struct pp_hwmgr *hwmgr, - bool enable, uint32_t feature_mask) -{ - int msg = enable ? PPSMC_MSG_EnableSmuFeatures : - PPSMC_MSG_DisableSmuFeatures; + vega10_send_msg_to_smc(hwmgr, PPSMC_MSG_GetEnabledSmuFeatures); + *features_enabled = vega10_get_argument(hwmgr); - return vega10_send_msg_to_smc_with_parameter(hwmgr, - msg, feature_mask); + return 0; } -int vega10_get_smc_features(struct pp_hwmgr *hwmgr, - uint32_t *features_enabled) +static bool vega10_is_dpm_running(struct pp_hwmgr *hwmgr) { - if (features_enabled == NULL) - return -EINVAL; + uint32_t features_enabled = 0; - if (!vega10_send_msg_to_smc(hwmgr, - PPSMC_MSG_GetEnabledSmuFeatures)) { - vega10_read_arg_from_smc(hwmgr, features_enabled); - return 0; - } + vega10_get_smc_features(hwmgr, &features_enabled); - return -EINVAL; + if (features_enabled & SMC_DPM_FEATURES) + return true; + else + return false; } -int vega10_set_tools_address(struct pp_hwmgr *hwmgr) +static int vega10_set_tools_address(struct pp_hwmgr *hwmgr) { - struct vega10_smumgr *priv = - (struct vega10_smumgr *)(hwmgr->smu_backend); + struct vega10_smumgr *priv = hwmgr->smu_backend; - if (priv->smu_tables.entry[TOOLSTABLE].table_addr_high || - priv->smu_tables.entry[TOOLSTABLE].table_addr_low) { - if (!vega10_send_msg_to_smc_with_parameter(hwmgr, + if (priv->smu_tables.entry[TOOLSTABLE].mc_addr) { + vega10_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetToolsDramAddrHigh, - priv->smu_tables.entry[TOOLSTABLE].table_addr_high)) - vega10_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_SetToolsDramAddrLow, - priv->smu_tables.entry[TOOLSTABLE].table_addr_low); + upper_32_bits(priv->smu_tables.entry[TOOLSTABLE].mc_addr)); + vega10_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetToolsDramAddrLow, + lower_32_bits(priv->smu_tables.entry[TOOLSTABLE].mc_addr)); } return 0; } @@ -356,7 +279,7 @@ int vega10_set_tools_address(struct pp_hwmgr *hwmgr) static int vega10_verify_smc_interface(struct pp_hwmgr *hwmgr) { uint32_t smc_driver_if_version; - struct cgs_system_info sys_info = {0}; + struct amdgpu_device *adev = hwmgr->adev; uint32_t dev_id; uint32_t rev_id; @@ -364,17 +287,10 @@ static int vega10_verify_smc_interface(struct pp_hwmgr *hwmgr) PPSMC_MSG_GetDriverIfVersion), "Attempt to get SMC IF Version Number Failed!", return -EINVAL); - vega10_read_arg_from_smc(hwmgr, &smc_driver_if_version); + smc_driver_if_version = vega10_get_argument(hwmgr); - sys_info.size = sizeof(struct cgs_system_info); - sys_info.info_id = CGS_SYSTEM_INFO_PCIE_DEV; - cgs_query_system_info(hwmgr->device, &sys_info); - dev_id = (uint32_t)sys_info.value; - - sys_info.size = sizeof(struct cgs_system_info); - sys_info.info_id = CGS_SYSTEM_INFO_PCIE_REV; - cgs_query_system_info(hwmgr->device, &sys_info); - rev_id = (uint32_t)sys_info.value; + dev_id = adev->pdev->device; + rev_id = adev->pdev->revision; if (!((dev_id == 0x687f) && ((rev_id == 0xc0) || @@ -393,14 +309,12 @@ static int vega10_verify_smc_interface(struct pp_hwmgr *hwmgr) static int vega10_smu_init(struct pp_hwmgr *hwmgr) { struct vega10_smumgr *priv; - uint64_t mc_addr; - void *kaddr = NULL; - unsigned long handle, tools_size; + unsigned long tools_size; int ret; struct cgs_firmware_info info = {0}; ret = cgs_get_firmware_info(hwmgr->device, - smu7_convert_fw_type_to_cgs(UCODE_ID_SMU), + CGS_UCODE_ID_SMU, &info); if (ret || !info.kptr) return -EINVAL; @@ -413,166 +327,130 @@ static int vega10_smu_init(struct pp_hwmgr *hwmgr) hwmgr->smu_backend = priv; /* allocate space for pptable */ - smu_allocate_memory(hwmgr->device, + ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, sizeof(PPTable_t), - CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB, PAGE_SIZE, - &mc_addr, - &kaddr, - &handle); - - PP_ASSERT_WITH_CODE(kaddr, - "[vega10_smu_init] Out of memory for pptable.", - kfree(hwmgr->smu_backend); - cgs_free_gpu_mem(hwmgr->device, - (cgs_handle_t)handle); - return -EINVAL); + AMDGPU_GEM_DOMAIN_VRAM, + &priv->smu_tables.entry[PPTABLE].handle, + &priv->smu_tables.entry[PPTABLE].mc_addr, + &priv->smu_tables.entry[PPTABLE].table); + if (ret) + goto free_backend; priv->smu_tables.entry[PPTABLE].version = 0x01; priv->smu_tables.entry[PPTABLE].size = sizeof(PPTable_t); priv->smu_tables.entry[PPTABLE].table_id = TABLE_PPTABLE; - priv->smu_tables.entry[PPTABLE].table_addr_high = - smu_upper_32_bits(mc_addr); - priv->smu_tables.entry[PPTABLE].table_addr_low = - smu_lower_32_bits(mc_addr); - priv->smu_tables.entry[PPTABLE].table = kaddr; - priv->smu_tables.entry[PPTABLE].handle = handle; /* allocate space for watermarks table */ - smu_allocate_memory(hwmgr->device, + ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, sizeof(Watermarks_t), - CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB, PAGE_SIZE, - &mc_addr, - &kaddr, - &handle); - - PP_ASSERT_WITH_CODE(kaddr, - "[vega10_smu_init] Out of memory for wmtable.", - kfree(hwmgr->smu_backend); - cgs_free_gpu_mem(hwmgr->device, - (cgs_handle_t)priv->smu_tables.entry[PPTABLE].handle); - cgs_free_gpu_mem(hwmgr->device, - (cgs_handle_t)handle); - return -EINVAL); + AMDGPU_GEM_DOMAIN_VRAM, + &priv->smu_tables.entry[WMTABLE].handle, + &priv->smu_tables.entry[WMTABLE].mc_addr, + &priv->smu_tables.entry[WMTABLE].table); + + if (ret) + goto err0; priv->smu_tables.entry[WMTABLE].version = 0x01; priv->smu_tables.entry[WMTABLE].size = sizeof(Watermarks_t); priv->smu_tables.entry[WMTABLE].table_id = TABLE_WATERMARKS; - priv->smu_tables.entry[WMTABLE].table_addr_high = - smu_upper_32_bits(mc_addr); - priv->smu_tables.entry[WMTABLE].table_addr_low = - smu_lower_32_bits(mc_addr); - priv->smu_tables.entry[WMTABLE].table = kaddr; - priv->smu_tables.entry[WMTABLE].handle = handle; /* allocate space for AVFS table */ - smu_allocate_memory(hwmgr->device, + ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, sizeof(AvfsTable_t), - CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB, PAGE_SIZE, - &mc_addr, - &kaddr, - &handle); - - PP_ASSERT_WITH_CODE(kaddr, - "[vega10_smu_init] Out of memory for avfs table.", - kfree(hwmgr->smu_backend); - cgs_free_gpu_mem(hwmgr->device, - (cgs_handle_t)priv->smu_tables.entry[PPTABLE].handle); - cgs_free_gpu_mem(hwmgr->device, - (cgs_handle_t)priv->smu_tables.entry[WMTABLE].handle); - cgs_free_gpu_mem(hwmgr->device, - (cgs_handle_t)handle); - return -EINVAL); + AMDGPU_GEM_DOMAIN_VRAM, + &priv->smu_tables.entry[AVFSTABLE].handle, + &priv->smu_tables.entry[AVFSTABLE].mc_addr, + &priv->smu_tables.entry[AVFSTABLE].table); + + if (ret) + goto err1; priv->smu_tables.entry[AVFSTABLE].version = 0x01; priv->smu_tables.entry[AVFSTABLE].size = sizeof(AvfsTable_t); priv->smu_tables.entry[AVFSTABLE].table_id = TABLE_AVFS; - priv->smu_tables.entry[AVFSTABLE].table_addr_high = - smu_upper_32_bits(mc_addr); - priv->smu_tables.entry[AVFSTABLE].table_addr_low = - smu_lower_32_bits(mc_addr); - priv->smu_tables.entry[AVFSTABLE].table = kaddr; - priv->smu_tables.entry[AVFSTABLE].handle = handle; tools_size = 0x19000; if (tools_size) { - smu_allocate_memory(hwmgr->device, + ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, tools_size, - CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB, PAGE_SIZE, - &mc_addr, - &kaddr, - &handle); - - if (kaddr) { - priv->smu_tables.entry[TOOLSTABLE].version = 0x01; - priv->smu_tables.entry[TOOLSTABLE].size = tools_size; - priv->smu_tables.entry[TOOLSTABLE].table_id = TABLE_PMSTATUSLOG; - priv->smu_tables.entry[TOOLSTABLE].table_addr_high = - smu_upper_32_bits(mc_addr); - priv->smu_tables.entry[TOOLSTABLE].table_addr_low = - smu_lower_32_bits(mc_addr); - priv->smu_tables.entry[TOOLSTABLE].table = kaddr; - priv->smu_tables.entry[TOOLSTABLE].handle = handle; - } + AMDGPU_GEM_DOMAIN_VRAM, + &priv->smu_tables.entry[TOOLSTABLE].handle, + &priv->smu_tables.entry[TOOLSTABLE].mc_addr, + &priv->smu_tables.entry[TOOLSTABLE].table); + if (ret) + goto err2; + priv->smu_tables.entry[TOOLSTABLE].version = 0x01; + priv->smu_tables.entry[TOOLSTABLE].size = tools_size; + priv->smu_tables.entry[TOOLSTABLE].table_id = TABLE_PMSTATUSLOG; } /* allocate space for AVFS Fuse table */ - smu_allocate_memory(hwmgr->device, + ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, sizeof(AvfsFuseOverride_t), - CGS_GPU_MEM_TYPE__VISIBLE_CONTIG_FB, PAGE_SIZE, - &mc_addr, - &kaddr, - &handle); - - PP_ASSERT_WITH_CODE(kaddr, - "[vega10_smu_init] Out of memory for avfs fuse table.", - kfree(hwmgr->smu_backend); - cgs_free_gpu_mem(hwmgr->device, - (cgs_handle_t)priv->smu_tables.entry[PPTABLE].handle); - cgs_free_gpu_mem(hwmgr->device, - (cgs_handle_t)priv->smu_tables.entry[WMTABLE].handle); - cgs_free_gpu_mem(hwmgr->device, - (cgs_handle_t)priv->smu_tables.entry[AVFSTABLE].handle); - cgs_free_gpu_mem(hwmgr->device, - (cgs_handle_t)priv->smu_tables.entry[TOOLSTABLE].handle); - cgs_free_gpu_mem(hwmgr->device, - (cgs_handle_t)handle); - return -EINVAL); + AMDGPU_GEM_DOMAIN_VRAM, + &priv->smu_tables.entry[AVFSFUSETABLE].handle, + &priv->smu_tables.entry[AVFSFUSETABLE].mc_addr, + &priv->smu_tables.entry[AVFSFUSETABLE].table); + if (ret) + goto err3; priv->smu_tables.entry[AVFSFUSETABLE].version = 0x01; priv->smu_tables.entry[AVFSFUSETABLE].size = sizeof(AvfsFuseOverride_t); priv->smu_tables.entry[AVFSFUSETABLE].table_id = TABLE_AVFS_FUSE_OVERRIDE; - priv->smu_tables.entry[AVFSFUSETABLE].table_addr_high = - smu_upper_32_bits(mc_addr); - priv->smu_tables.entry[AVFSFUSETABLE].table_addr_low = - smu_lower_32_bits(mc_addr); - priv->smu_tables.entry[AVFSFUSETABLE].table = kaddr; - priv->smu_tables.entry[AVFSFUSETABLE].handle = handle; + return 0; + +err3: + if (priv->smu_tables.entry[TOOLSTABLE].table) + amdgpu_bo_free_kernel(&priv->smu_tables.entry[TOOLSTABLE].handle, + &priv->smu_tables.entry[TOOLSTABLE].mc_addr, + &priv->smu_tables.entry[TOOLSTABLE].table); +err2: + amdgpu_bo_free_kernel(&priv->smu_tables.entry[AVFSTABLE].handle, + &priv->smu_tables.entry[AVFSTABLE].mc_addr, + &priv->smu_tables.entry[AVFSTABLE].table); +err1: + amdgpu_bo_free_kernel(&priv->smu_tables.entry[WMTABLE].handle, + &priv->smu_tables.entry[WMTABLE].mc_addr, + &priv->smu_tables.entry[WMTABLE].table); +err0: + amdgpu_bo_free_kernel(&priv->smu_tables.entry[PPTABLE].handle, + &priv->smu_tables.entry[PPTABLE].mc_addr, + &priv->smu_tables.entry[PPTABLE].table); +free_backend: + kfree(hwmgr->smu_backend); + + return -EINVAL; } static int vega10_smu_fini(struct pp_hwmgr *hwmgr) { - struct vega10_smumgr *priv = - (struct vega10_smumgr *)(hwmgr->smu_backend); + struct vega10_smumgr *priv = hwmgr->smu_backend; if (priv) { - cgs_free_gpu_mem(hwmgr->device, - (cgs_handle_t)priv->smu_tables.entry[PPTABLE].handle); - cgs_free_gpu_mem(hwmgr->device, - (cgs_handle_t)priv->smu_tables.entry[WMTABLE].handle); - cgs_free_gpu_mem(hwmgr->device, - (cgs_handle_t)priv->smu_tables.entry[AVFSTABLE].handle); + amdgpu_bo_free_kernel(&priv->smu_tables.entry[PPTABLE].handle, + &priv->smu_tables.entry[PPTABLE].mc_addr, + &priv->smu_tables.entry[PPTABLE].table); + amdgpu_bo_free_kernel(&priv->smu_tables.entry[WMTABLE].handle, + &priv->smu_tables.entry[WMTABLE].mc_addr, + &priv->smu_tables.entry[WMTABLE].table); + amdgpu_bo_free_kernel(&priv->smu_tables.entry[AVFSTABLE].handle, + &priv->smu_tables.entry[AVFSTABLE].mc_addr, + &priv->smu_tables.entry[AVFSTABLE].table); if (priv->smu_tables.entry[TOOLSTABLE].table) - cgs_free_gpu_mem(hwmgr->device, - (cgs_handle_t)priv->smu_tables.entry[TOOLSTABLE].handle); - cgs_free_gpu_mem(hwmgr->device, - (cgs_handle_t)priv->smu_tables.entry[AVFSFUSETABLE].handle); + amdgpu_bo_free_kernel(&priv->smu_tables.entry[TOOLSTABLE].handle, + &priv->smu_tables.entry[TOOLSTABLE].mc_addr, + &priv->smu_tables.entry[TOOLSTABLE].table); + amdgpu_bo_free_kernel(&priv->smu_tables.entry[AVFSFUSETABLE].handle, + &priv->smu_tables.entry[AVFSFUSETABLE].mc_addr, + &priv->smu_tables.entry[AVFSFUSETABLE].table); kfree(hwmgr->smu_backend); hwmgr->smu_backend = NULL; } @@ -581,6 +459,9 @@ static int vega10_smu_fini(struct pp_hwmgr *hwmgr) static int vega10_start_smu(struct pp_hwmgr *hwmgr) { + if (!vega10_is_smc_ram_running(hwmgr)) + return -EINVAL; + PP_ASSERT_WITH_CODE(!vega10_verify_smc_interface(hwmgr), "Failed to verify SMC interface!", return -EINVAL); @@ -590,6 +471,18 @@ static int vega10_start_smu(struct pp_hwmgr *hwmgr) return 0; } +static int vega10_smc_table_manager(struct pp_hwmgr *hwmgr, uint8_t *table, uint16_t table_id, bool rw) +{ + int ret; + + if (rw) + ret = vega10_copy_table_from_smc(hwmgr, table, table_id); + else + ret = vega10_copy_table_to_smc(hwmgr, table, table_id); + + return ret; +} + const struct pp_smumgr_func vega10_smu_funcs = { .smu_init = &vega10_smu_init, .smu_fini = &vega10_smu_fini, @@ -599,4 +492,7 @@ const struct pp_smumgr_func vega10_smu_funcs = { .send_msg_to_smc_with_parameter = &vega10_send_msg_to_smc_with_parameter, .download_pptable_settings = NULL, .upload_pptable_settings = NULL, + .is_dpm_running = vega10_is_dpm_running, + .get_argument = vega10_get_argument, + .smc_table_manager = vega10_smc_table_manager, }; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.h index 0695455b21b2..424e868bc768 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.h @@ -23,25 +23,15 @@ #ifndef _VEGA10_SMUMANAGER_H_ #define _VEGA10_SMUMANAGER_H_ -#include "vega10_hwmgr.h" - -enum smu_table_id { - PPTABLE = 0, - WMTABLE, - AVFSTABLE, - TOOLSTABLE, - AVFSFUSETABLE, - MAX_SMU_TABLE, -}; +#define MAX_SMU_TABLE 5 struct smu_table_entry { uint32_t version; uint32_t size; uint32_t table_id; - uint32_t table_addr_high; - uint32_t table_addr_low; - uint8_t *table; - unsigned long handle; + uint64_t mc_addr; + void *table; + struct amdgpu_bo *handle; }; struct smu_table_array { @@ -52,19 +42,6 @@ struct vega10_smumgr { struct smu_table_array smu_tables; }; -int vega10_read_arg_from_smc(struct pp_hwmgr *hwmgr, uint32_t *arg); -int vega10_copy_table_from_smc(struct pp_hwmgr *hwmgr, - uint8_t *table, int16_t table_id); -int vega10_copy_table_to_smc(struct pp_hwmgr *hwmgr, - uint8_t *table, int16_t table_id); -int vega10_enable_smc_features(struct pp_hwmgr *hwmgr, - bool enable, uint32_t feature_mask); -int vega10_get_smc_features(struct pp_hwmgr *hwmgr, - uint32_t *features_enabled); -int vega10_save_vft_table(struct pp_hwmgr *hwmgr, uint8_t *avfs_table); -int vega10_restore_vft_table(struct pp_hwmgr *hwmgr, uint8_t *avfs_table); - -int vega10_set_tools_address(struct pp_hwmgr *hwmgr); #endif diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega12_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/vega12_smumgr.c new file mode 100644 index 000000000000..55cd204c1789 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/smumgr/vega12_smumgr.c @@ -0,0 +1,561 @@ +/* + * Copyright 2017 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 "smumgr.h" +#include "vega12_inc.h" +#include "pp_soc15.h" +#include "vega12_smumgr.h" +#include "vega12_ppsmc.h" +#include "vega12/smu9_driver_if.h" + +#include "ppatomctrl.h" +#include "pp_debug.h" +#include "smu_ucode_xfer_vi.h" +#include "smu7_smumgr.h" + +/* MP Apertures */ +#define MP0_Public 0x03800000 +#define MP0_SRAM 0x03900000 +#define MP1_Public 0x03b00000 +#define MP1_SRAM 0x03c00004 + +#define smnMP1_FIRMWARE_FLAGS 0x3010028 +#define smnMP0_FW_INTF 0x3010104 +#define smnMP1_PUB_CTRL 0x3010b14 + +static bool vega12_is_smc_ram_running(struct pp_hwmgr *hwmgr) +{ + uint32_t mp1_fw_flags, reg; + + reg = soc15_get_register_offset(NBIF_HWID, 0, + mmPCIE_INDEX2_BASE_IDX, mmPCIE_INDEX2); + + cgs_write_register(hwmgr->device, reg, + (MP1_Public | (smnMP1_FIRMWARE_FLAGS & 0xffffffff))); + + reg = soc15_get_register_offset(NBIF_HWID, 0, + mmPCIE_DATA2_BASE_IDX, mmPCIE_DATA2); + + mp1_fw_flags = cgs_read_register(hwmgr->device, reg); + + if ((mp1_fw_flags & MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK) >> + MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED__SHIFT) + return true; + + return false; +} + +/* + * Check if SMC has responded to previous message. + * + * @param smumgr the address of the powerplay hardware manager. + * @return TRUE SMC has responded, FALSE otherwise. + */ +static uint32_t vega12_wait_for_response(struct pp_hwmgr *hwmgr) +{ + uint32_t reg; + + reg = soc15_get_register_offset(MP1_HWID, 0, + mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90); + + phm_wait_for_register_unequal(hwmgr, reg, + 0, MP1_C2PMSG_90__CONTENT_MASK); + + return cgs_read_register(hwmgr->device, reg); +} + +/* + * Send a message to the SMC, and do not wait for its response. + * @param smumgr the address of the powerplay hardware manager. + * @param msg the message to send. + * @return Always return 0. + */ +int vega12_send_msg_to_smc_without_waiting(struct pp_hwmgr *hwmgr, + uint16_t msg) +{ + uint32_t reg; + + reg = soc15_get_register_offset(MP1_HWID, 0, + mmMP1_SMN_C2PMSG_66_BASE_IDX, mmMP1_SMN_C2PMSG_66); + cgs_write_register(hwmgr->device, reg, msg); + + return 0; +} + +/* + * Send a message to the SMC, and wait for its response. + * @param hwmgr the address of the powerplay hardware manager. + * @param msg the message to send. + * @return Always return 0. + */ +int vega12_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg) +{ + uint32_t reg; + + vega12_wait_for_response(hwmgr); + + reg = soc15_get_register_offset(MP1_HWID, 0, + mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90); + cgs_write_register(hwmgr->device, reg, 0); + + vega12_send_msg_to_smc_without_waiting(hwmgr, msg); + + if (vega12_wait_for_response(hwmgr) != 1) + pr_err("Failed to send message: 0x%x\n", msg); + + return 0; +} + +/* + * Send a message to the SMC with parameter + * @param hwmgr: the address of the powerplay hardware manager. + * @param msg: the message to send. + * @param parameter: the parameter to send + * @return Always return 0. + */ +int vega12_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, + uint16_t msg, uint32_t parameter) +{ + uint32_t reg; + + vega12_wait_for_response(hwmgr); + + reg = soc15_get_register_offset(MP1_HWID, 0, + mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90); + cgs_write_register(hwmgr->device, reg, 0); + + reg = soc15_get_register_offset(MP1_HWID, 0, + mmMP1_SMN_C2PMSG_82_BASE_IDX, mmMP1_SMN_C2PMSG_82); + cgs_write_register(hwmgr->device, reg, parameter); + + vega12_send_msg_to_smc_without_waiting(hwmgr, msg); + + if (vega12_wait_for_response(hwmgr) != 1) + pr_err("Failed to send message: 0x%x\n", msg); + + return 0; +} + + +/* + * Send a message to the SMC with parameter, do not wait for response + * @param hwmgr: the address of the powerplay hardware manager. + * @param msg: the message to send. + * @param parameter: the parameter to send + * @return The response that came from the SMC. + */ +int vega12_send_msg_to_smc_with_parameter_without_waiting( + struct pp_hwmgr *hwmgr, uint16_t msg, uint32_t parameter) +{ + uint32_t reg; + + reg = soc15_get_register_offset(MP1_HWID, 0, + mmMP1_SMN_C2PMSG_66_BASE_IDX, mmMP1_SMN_C2PMSG_66); + cgs_write_register(hwmgr->device, reg, parameter); + + return vega12_send_msg_to_smc_without_waiting(hwmgr, msg); +} + +/* + * Retrieve an argument from SMC. + * @param hwmgr the address of the powerplay hardware manager. + * @param arg pointer to store the argument from SMC. + * @return Always return 0. + */ +int vega12_read_arg_from_smc(struct pp_hwmgr *hwmgr, uint32_t *arg) +{ + uint32_t reg; + + reg = soc15_get_register_offset(MP1_HWID, 0, + mmMP1_SMN_C2PMSG_82_BASE_IDX, mmMP1_SMN_C2PMSG_82); + + *arg = cgs_read_register(hwmgr->device, reg); + + return 0; +} + +/* + * Copy table from SMC into driver FB + * @param hwmgr the address of the HW manager + * @param table_id the driver's table ID to copy from + */ +int vega12_copy_table_from_smc(struct pp_hwmgr *hwmgr, + uint8_t *table, int16_t table_id) +{ + struct vega12_smumgr *priv = + (struct vega12_smumgr *)(hwmgr->smu_backend); + + PP_ASSERT_WITH_CODE(table_id < TABLE_COUNT, + "Invalid SMU Table ID!", return -EINVAL); + PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0, + "Invalid SMU Table version!", return -EINVAL); + PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0, + "Invalid SMU Table Length!", return -EINVAL); + PP_ASSERT_WITH_CODE(vega12_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetDriverDramAddrHigh, + upper_32_bits(priv->smu_tables.entry[table_id].mc_addr)) == 0, + "[CopyTableFromSMC] Attempt to Set Dram Addr High Failed!", return -EINVAL); + PP_ASSERT_WITH_CODE(vega12_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetDriverDramAddrLow, + lower_32_bits(priv->smu_tables.entry[table_id].mc_addr)) == 0, + "[CopyTableFromSMC] Attempt to Set Dram Addr Low Failed!", + return -EINVAL); + PP_ASSERT_WITH_CODE(vega12_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_TransferTableSmu2Dram, + table_id) == 0, + "[CopyTableFromSMC] Attempt to Transfer Table From SMU Failed!", + return -EINVAL); + + memcpy(table, priv->smu_tables.entry[table_id].table, + priv->smu_tables.entry[table_id].size); + + return 0; +} + +/* + * Copy table from Driver FB into SMC + * @param hwmgr the address of the HW manager + * @param table_id the table to copy from + */ +int vega12_copy_table_to_smc(struct pp_hwmgr *hwmgr, + uint8_t *table, int16_t table_id) +{ + struct vega12_smumgr *priv = + (struct vega12_smumgr *)(hwmgr->smu_backend); + + PP_ASSERT_WITH_CODE(table_id < TABLE_COUNT, + "Invalid SMU Table ID!", return -EINVAL); + PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0, + "Invalid SMU Table version!", return -EINVAL); + PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0, + "Invalid SMU Table Length!", return -EINVAL); + + memcpy(priv->smu_tables.entry[table_id].table, table, + priv->smu_tables.entry[table_id].size); + + PP_ASSERT_WITH_CODE(vega12_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetDriverDramAddrHigh, + upper_32_bits(priv->smu_tables.entry[table_id].mc_addr)) == 0, + "[CopyTableToSMC] Attempt to Set Dram Addr High Failed!", + return -EINVAL;); + PP_ASSERT_WITH_CODE(vega12_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetDriverDramAddrLow, + lower_32_bits(priv->smu_tables.entry[table_id].mc_addr)) == 0, + "[CopyTableToSMC] Attempt to Set Dram Addr Low Failed!", + return -EINVAL); + PP_ASSERT_WITH_CODE(vega12_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_TransferTableDram2Smu, + table_id) == 0, + "[CopyTableToSMC] Attempt to Transfer Table To SMU Failed!", + return -EINVAL); + + return 0; +} + +int vega12_enable_smc_features(struct pp_hwmgr *hwmgr, + bool enable, uint64_t feature_mask) +{ + uint32_t smu_features_low, smu_features_high; + + smu_features_low = (uint32_t)((feature_mask & SMU_FEATURES_LOW_MASK) >> SMU_FEATURES_LOW_SHIFT); + smu_features_high = (uint32_t)((feature_mask & SMU_FEATURES_HIGH_MASK) >> SMU_FEATURES_HIGH_SHIFT); + + if (enable) { + PP_ASSERT_WITH_CODE(vega12_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_EnableSmuFeaturesLow, smu_features_low) == 0, + "[EnableDisableSMCFeatures] Attemp to enable SMU features Low failed!", + return -EINVAL); + PP_ASSERT_WITH_CODE(vega12_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_EnableSmuFeaturesHigh, smu_features_high) == 0, + "[EnableDisableSMCFeatures] Attemp to enable SMU features High failed!", + return -EINVAL); + } else { + PP_ASSERT_WITH_CODE(vega12_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_DisableSmuFeaturesLow, smu_features_low) == 0, + "[EnableDisableSMCFeatures] Attemp to disable SMU features Low failed!", + return -EINVAL); + PP_ASSERT_WITH_CODE(vega12_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_DisableSmuFeaturesHigh, smu_features_high) == 0, + "[EnableDisableSMCFeatures] Attemp to disable SMU features High failed!", + return -EINVAL); + } + + return 0; +} + +int vega12_get_enabled_smc_features(struct pp_hwmgr *hwmgr, + uint64_t *features_enabled) +{ + uint32_t smc_features_low, smc_features_high; + + if (features_enabled == NULL) + return -EINVAL; + + PP_ASSERT_WITH_CODE(vega12_send_msg_to_smc(hwmgr, + PPSMC_MSG_GetEnabledSmuFeaturesLow) == 0, + "[GetEnabledSMCFeatures] Attemp to get SMU features Low failed!", + return -EINVAL); + PP_ASSERT_WITH_CODE(vega12_read_arg_from_smc(hwmgr, + &smc_features_low) == 0, + "[GetEnabledSMCFeatures] Attemp to read SMU features Low argument failed!", + return -EINVAL); + PP_ASSERT_WITH_CODE(vega12_send_msg_to_smc(hwmgr, + PPSMC_MSG_GetEnabledSmuFeaturesHigh) == 0, + "[GetEnabledSMCFeatures] Attemp to get SMU features High failed!", + return -EINVAL); + PP_ASSERT_WITH_CODE(vega12_read_arg_from_smc(hwmgr, + &smc_features_high) == 0, + "[GetEnabledSMCFeatures] Attemp to read SMU features High argument failed!", + return -EINVAL); + + *features_enabled = ((((uint64_t)smc_features_low << SMU_FEATURES_LOW_SHIFT) & SMU_FEATURES_LOW_MASK) | + (((uint64_t)smc_features_high << SMU_FEATURES_HIGH_SHIFT) & SMU_FEATURES_HIGH_MASK)); + + return 0; +} + +static bool vega12_is_dpm_running(struct pp_hwmgr *hwmgr) +{ + uint64_t features_enabled = 0; + + vega12_get_enabled_smc_features(hwmgr, &features_enabled); + + if (features_enabled & SMC_DPM_FEATURES) + return true; + else + return false; +} + +static int vega12_set_tools_address(struct pp_hwmgr *hwmgr) +{ + struct vega12_smumgr *priv = + (struct vega12_smumgr *)(hwmgr->smu_backend); + + if (priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr) { + if (!vega12_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetToolsDramAddrHigh, + upper_32_bits(priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr))) + vega12_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetToolsDramAddrLow, + lower_32_bits(priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr)); + } + return 0; +} + +#if 0 /* tentatively remove */ +static int vega12_verify_smc_interface(struct pp_hwmgr *hwmgr) +{ + uint32_t smc_driver_if_version; + + PP_ASSERT_WITH_CODE(!vega12_send_msg_to_smc(hwmgr, + PPSMC_MSG_GetDriverIfVersion), + "Attempt to get SMC IF Version Number Failed!", + return -EINVAL); + vega12_read_arg_from_smc(hwmgr, &smc_driver_if_version); + + if (smc_driver_if_version != SMU9_DRIVER_IF_VERSION) { + pr_err("Your firmware(0x%x) doesn't match \ + SMU9_DRIVER_IF_VERSION(0x%x). \ + Please update your firmware!\n", + smc_driver_if_version, SMU9_DRIVER_IF_VERSION); + return -EINVAL; + } + + return 0; +} +#endif + +static int vega12_smu_init(struct pp_hwmgr *hwmgr) +{ + struct vega12_smumgr *priv; + unsigned long tools_size; + struct cgs_firmware_info info = {0}; + int ret; + + ret = cgs_get_firmware_info(hwmgr->device, + smu7_convert_fw_type_to_cgs(UCODE_ID_SMU), + &info); + if (ret || !info.kptr) + return -EINVAL; + + priv = kzalloc(sizeof(struct vega12_smumgr), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + hwmgr->smu_backend = priv; + + /* allocate space for pptable */ + ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, + sizeof(PPTable_t), + PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, + &priv->smu_tables.entry[TABLE_PPTABLE].handle, + &priv->smu_tables.entry[TABLE_PPTABLE].mc_addr, + &priv->smu_tables.entry[TABLE_PPTABLE].table); + if (ret) + goto free_backend; + + priv->smu_tables.entry[TABLE_PPTABLE].version = 0x01; + priv->smu_tables.entry[TABLE_PPTABLE].size = sizeof(PPTable_t); + + /* allocate space for watermarks table */ + ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, + sizeof(Watermarks_t), + PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, + &priv->smu_tables.entry[TABLE_WATERMARKS].handle, + &priv->smu_tables.entry[TABLE_WATERMARKS].mc_addr, + &priv->smu_tables.entry[TABLE_WATERMARKS].table); + + if (ret) + goto err0; + + priv->smu_tables.entry[TABLE_WATERMARKS].version = 0x01; + priv->smu_tables.entry[TABLE_WATERMARKS].size = sizeof(Watermarks_t); + + tools_size = 0x19000; + if (tools_size) { + ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, + tools_size, + PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, + &priv->smu_tables.entry[TABLE_PMSTATUSLOG].handle, + &priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr, + &priv->smu_tables.entry[TABLE_PMSTATUSLOG].table); + if (ret) + goto err1; + + priv->smu_tables.entry[TABLE_PMSTATUSLOG].version = 0x01; + priv->smu_tables.entry[TABLE_PMSTATUSLOG].size = tools_size; + } + + /* allocate space for AVFS Fuse table */ + ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, + sizeof(AvfsFuseOverride_t), + PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, + &priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].handle, + &priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].mc_addr, + &priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].table); + + if (ret) + goto err2; + + priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].version = 0x01; + priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].size = sizeof(AvfsFuseOverride_t); + + /* allocate space for OverDrive table */ + ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, + sizeof(OverDriveTable_t), + PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, + &priv->smu_tables.entry[TABLE_OVERDRIVE].handle, + &priv->smu_tables.entry[TABLE_OVERDRIVE].mc_addr, + &priv->smu_tables.entry[TABLE_OVERDRIVE].table); + if (ret) + goto err3; + + priv->smu_tables.entry[TABLE_OVERDRIVE].version = 0x01; + priv->smu_tables.entry[TABLE_OVERDRIVE].size = sizeof(OverDriveTable_t); + + return 0; + +err3: + amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].handle, + &priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].mc_addr, + &priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].table); +err2: + if (priv->smu_tables.entry[TABLE_PMSTATUSLOG].table) + amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_PMSTATUSLOG].handle, + &priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr, + &priv->smu_tables.entry[TABLE_PMSTATUSLOG].table); +err1: + amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_WATERMARKS].handle, + &priv->smu_tables.entry[TABLE_WATERMARKS].mc_addr, + &priv->smu_tables.entry[TABLE_WATERMARKS].table); +err0: + amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_PPTABLE].handle, + &priv->smu_tables.entry[TABLE_PPTABLE].mc_addr, + &priv->smu_tables.entry[TABLE_PPTABLE].table); +free_backend: + kfree(hwmgr->smu_backend); + + return -EINVAL; +} + +static int vega12_smu_fini(struct pp_hwmgr *hwmgr) +{ + struct vega12_smumgr *priv = + (struct vega12_smumgr *)(hwmgr->smu_backend); + + if (priv) { + amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_PPTABLE].handle, + &priv->smu_tables.entry[TABLE_PPTABLE].mc_addr, + &priv->smu_tables.entry[TABLE_PPTABLE].table); + amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_WATERMARKS].handle, + &priv->smu_tables.entry[TABLE_WATERMARKS].mc_addr, + &priv->smu_tables.entry[TABLE_WATERMARKS].table); + if (priv->smu_tables.entry[TABLE_PMSTATUSLOG].table) + amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_PMSTATUSLOG].handle, + &priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr, + &priv->smu_tables.entry[TABLE_PMSTATUSLOG].table); + amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].handle, + &priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].mc_addr, + &priv->smu_tables.entry[TABLE_AVFS_FUSE_OVERRIDE].table); + amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_OVERDRIVE].handle, + &priv->smu_tables.entry[TABLE_OVERDRIVE].mc_addr, + &priv->smu_tables.entry[TABLE_OVERDRIVE].table); + kfree(hwmgr->smu_backend); + hwmgr->smu_backend = NULL; + } + return 0; +} + +static int vega12_start_smu(struct pp_hwmgr *hwmgr) +{ + PP_ASSERT_WITH_CODE(vega12_is_smc_ram_running(hwmgr), + "SMC is not running!", + return -EINVAL); + +#if 0 /* tentatively remove */ + PP_ASSERT_WITH_CODE(!vega12_verify_smc_interface(hwmgr), + "Failed to verify SMC interface!", + return -EINVAL); +#endif + + vega12_set_tools_address(hwmgr); + + return 0; +} + +const struct pp_smumgr_func vega12_smu_funcs = { + .smu_init = &vega12_smu_init, + .smu_fini = &vega12_smu_fini, + .start_smu = &vega12_start_smu, + .request_smu_load_specific_fw = NULL, + .send_msg_to_smc = &vega12_send_msg_to_smc, + .send_msg_to_smc_with_parameter = &vega12_send_msg_to_smc_with_parameter, + .download_pptable_settings = NULL, + .upload_pptable_settings = NULL, + .is_dpm_running = vega12_is_dpm_running, +}; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega12_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/vega12_smumgr.h new file mode 100644 index 000000000000..2810d387b611 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/smumgr/vega12_smumgr.h @@ -0,0 +1,62 @@ +/* + * Copyright 2017 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. + * + */ +#ifndef _VEGA12_SMUMANAGER_H_ +#define _VEGA12_SMUMANAGER_H_ + +#include "hwmgr.h" +#include "vega12/smu9_driver_if.h" +#include "vega12_hwmgr.h" + +struct smu_table_entry { + uint32_t version; + uint32_t size; + uint64_t mc_addr; + void *table; + struct amdgpu_bo *handle; +}; + +struct smu_table_array { + struct smu_table_entry entry[TABLE_COUNT]; +}; + +struct vega12_smumgr { + struct smu_table_array smu_tables; +}; + +#define SMU_FEATURES_LOW_MASK 0x00000000FFFFFFFF +#define SMU_FEATURES_LOW_SHIFT 0 +#define SMU_FEATURES_HIGH_MASK 0xFFFFFFFF00000000 +#define SMU_FEATURES_HIGH_SHIFT 32 + +int vega12_read_arg_from_smc(struct pp_hwmgr *hwmgr, uint32_t *arg); +int vega12_copy_table_from_smc(struct pp_hwmgr *hwmgr, + uint8_t *table, int16_t table_id); +int vega12_copy_table_to_smc(struct pp_hwmgr *hwmgr, + uint8_t *table, int16_t table_id); +int vega12_enable_smc_features(struct pp_hwmgr *hwmgr, + bool enable, uint64_t feature_mask); +int vega12_get_enabled_smc_features(struct pp_hwmgr *hwmgr, + uint64_t *features_enabled); + +#endif + |