diff options
Diffstat (limited to 'drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c')
-rw-r--r-- | drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 242 |
1 files changed, 194 insertions, 48 deletions
diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index f75ee33ec5bb..102eb6d029fa 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -89,6 +89,7 @@ enum DPM_EVENT_SRC { DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL = 4 }; +static int smu7_avfs_control(struct pp_hwmgr *hwmgr, bool enable); static const unsigned long PhwVIslands_Magic = (unsigned long)(PHM_VIslands_Magic); static int smu7_force_clock_level(struct pp_hwmgr *hwmgr, enum pp_clock_type type, uint32_t mask); @@ -1309,11 +1310,9 @@ int smu7_disable_dpm_tasks(struct pp_hwmgr *hwmgr) PP_ASSERT_WITH_CODE((tmp_result == 0), "Failed to disable thermal auto throttle!", result = tmp_result); - if (1 == PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, FEATURE_STATUS, AVS_ON)) { - PP_ASSERT_WITH_CODE((0 == smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_DisableAvfs)), - "Failed to disable AVFS!", - return -EINVAL); - } + tmp_result = smu7_avfs_control(hwmgr, false); + PP_ASSERT_WITH_CODE((tmp_result == 0), + "Failed to disable AVFS!", result = tmp_result); tmp_result = smu7_stop_dpm(hwmgr); PP_ASSERT_WITH_CODE((tmp_result == 0), @@ -1544,7 +1543,7 @@ static int smu7_get_evv_voltages(struct pp_hwmgr *hwmgr) if (vddc >= 2000 || vddc == 0) return -EINVAL; } else { - pr_warning("failed to retrieving EVV voltage!\n"); + pr_warn("failed to retrieving EVV voltage!\n"); continue; } @@ -2656,6 +2655,28 @@ static int smu7_get_power_state_size(struct pp_hwmgr *hwmgr) return sizeof(struct smu7_power_state); } +static int smu7_vblank_too_short(struct pp_hwmgr *hwmgr, + uint32_t vblank_time_us) +{ + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + uint32_t switch_limit_us; + + switch (hwmgr->chip_id) { + case CHIP_POLARIS10: + case CHIP_POLARIS11: + case CHIP_POLARIS12: + switch_limit_us = data->is_memory_gddr5 ? 190 : 150; + break; + default: + switch_limit_us = data->is_memory_gddr5 ? 450 : 150; + break; + } + + if (vblank_time_us < switch_limit_us) + return true; + else + return false; +} static int smu7_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, struct pp_power_state *request_ps, @@ -2670,6 +2691,7 @@ static int smu7_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, bool disable_mclk_switching; bool disable_mclk_switching_for_frame_lock; struct cgs_display_info info = {0}; + struct cgs_mode_info mode_info = {0}; const struct phm_clock_and_voltage_limits *max_limits; uint32_t i; struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); @@ -2678,6 +2700,7 @@ static int smu7_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, int32_t count; int32_t stable_pstate_sclk = 0, stable_pstate_mclk = 0; + info.mode_info = &mode_info; data->battery_state = (PP_StateUILabel_Battery == request_ps->classification.ui_label); @@ -2704,8 +2727,6 @@ static int smu7_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, cgs_get_active_displays_info(hwmgr->device, &info); - /*TO DO result = PHM_CheckVBlankTime(hwmgr, &vblankTooShort);*/ - minimum_clocks.engineClock = hwmgr->display_config.min_core_set_clock; minimum_clocks.memoryClock = hwmgr->display_config.min_mem_set_clock; @@ -2770,8 +2791,10 @@ static int smu7_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, PHM_PlatformCaps_DisableMclkSwitchingForFrameLock); - disable_mclk_switching = (1 < info.display_count) || - disable_mclk_switching_for_frame_lock; + disable_mclk_switching = ((1 < info.display_count) || + disable_mclk_switching_for_frame_lock || + smu7_vblank_too_short(hwmgr, mode_info.vblank_time_us) || + (mode_info.refresh_rate > 120)); sclk = smu7_ps->performance_levels[0].engine_clock; mclk = smu7_ps->performance_levels[0].memory_clock; @@ -3289,22 +3312,60 @@ static int smu7_get_pp_table_entry(struct pp_hwmgr *hwmgr, return 0; } -static int smu7_read_sensor(struct pp_hwmgr *hwmgr, int idx, int32_t *value) +static int smu7_get_gpu_power(struct pp_hwmgr *hwmgr, + struct pp_gpu_power *query) +{ + PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(hwmgr->smumgr, + PPSMC_MSG_PmStatusLogStart), + "Failed to start pm status log!", + return -1); + + msleep_interruptible(20); + + PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(hwmgr->smumgr, + PPSMC_MSG_PmStatusLogSample), + "Failed to sample pm status log!", + return -1); + + query->vddc_power = cgs_read_ind_register(hwmgr->device, + CGS_IND_REG__SMC, + ixSMU_PM_STATUS_40); + query->vddci_power = cgs_read_ind_register(hwmgr->device, + CGS_IND_REG__SMC, + ixSMU_PM_STATUS_49); + query->max_gpu_power = cgs_read_ind_register(hwmgr->device, + CGS_IND_REG__SMC, + ixSMU_PM_STATUS_94); + query->average_gpu_power = cgs_read_ind_register(hwmgr->device, + CGS_IND_REG__SMC, + ixSMU_PM_STATUS_95); + + return 0; +} + +static int smu7_read_sensor(struct pp_hwmgr *hwmgr, int idx, + void *value, int *size) { uint32_t sclk, mclk, activity_percent; uint32_t offset; struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + /* size must be at least 4 bytes for all sensors */ + if (*size < 4) + return -EINVAL; + switch (idx) { case AMDGPU_PP_SENSOR_GFX_SCLK: smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetSclkFrequency); sclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0); - *value = sclk; + *((uint32_t *)value) = sclk; + *size = 4; return 0; case AMDGPU_PP_SENSOR_GFX_MCLK: smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetMclkFrequency); mclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0); - *value = mclk; + *((uint32_t *)value) = mclk; + *size = 4; return 0; case AMDGPU_PP_SENSOR_GPU_LOAD: offset = data->soft_regs_start + smum_get_offsetof(hwmgr->smumgr, @@ -3314,17 +3375,26 @@ static int smu7_read_sensor(struct pp_hwmgr *hwmgr, int idx, int32_t *value) activity_percent = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset); activity_percent += 0x80; activity_percent >>= 8; - *value = activity_percent > 100 ? 100 : activity_percent; + *((uint32_t *)value) = activity_percent > 100 ? 100 : activity_percent; + *size = 4; return 0; case AMDGPU_PP_SENSOR_GPU_TEMP: - *value = smu7_thermal_get_temperature(hwmgr); + *((uint32_t *)value) = smu7_thermal_get_temperature(hwmgr); + *size = 4; return 0; case AMDGPU_PP_SENSOR_UVD_POWER: - *value = data->uvd_power_gated ? 0 : 1; + *((uint32_t *)value) = data->uvd_power_gated ? 0 : 1; + *size = 4; return 0; case AMDGPU_PP_SENSOR_VCE_POWER: - *value = data->vce_power_gated ? 0 : 1; + *((uint32_t *)value) = data->vce_power_gated ? 0 : 1; + *size = 4; return 0; + case AMDGPU_PP_SENSOR_GPU_POWER: + if (*size < sizeof(struct pp_gpu_power)) + return -EINVAL; + *size = sizeof(struct pp_gpu_power); + return smu7_get_gpu_power(hwmgr, (struct pp_gpu_power *)value); default: return -EINVAL; } @@ -4288,26 +4358,31 @@ static int smu7_print_clock_levels(struct pp_hwmgr *hwmgr, static int smu7_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode) { - if (mode) { - /* stop auto-manage */ - if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, - PHM_PlatformCaps_MicrocodeFanControl)) - smu7_fan_ctrl_stop_smc_fan_control(hwmgr); - smu7_fan_ctrl_set_static_mode(hwmgr, mode); - } else - /* restart auto-manage */ - smu7_fan_ctrl_reset_fan_speed_to_default(hwmgr); + int result = 0; - return 0; + switch (mode) { + case AMD_FAN_CTRL_NONE: + result = smu7_fan_ctrl_set_fan_speed_percent(hwmgr, 100); + break; + case AMD_FAN_CTRL_MANUAL: + if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, + PHM_PlatformCaps_MicrocodeFanControl)) + result = smu7_fan_ctrl_stop_smc_fan_control(hwmgr); + break; + case AMD_FAN_CTRL_AUTO: + result = smu7_fan_ctrl_set_static_mode(hwmgr, mode); + if (!result) + result = smu7_fan_ctrl_start_smc_fan_control(hwmgr); + break; + default: + break; + } + return result; } static int smu7_get_fan_control_mode(struct pp_hwmgr *hwmgr) { - if (hwmgr->fan_ctrl_is_in_default_mode) - return hwmgr->fan_ctrl_default_mode; - else - return PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, - CG_FDO_CTRL2, FDO_PWM_MODE); + return hwmgr->fan_ctrl_enabled ? AMD_FAN_CTRL_AUTO : AMD_FAN_CTRL_MANUAL; } static int smu7_get_sclk_od(struct pp_hwmgr *hwmgr) @@ -4476,29 +4551,99 @@ static int smu7_get_clock_by_type(struct pp_hwmgr *hwmgr, enum amd_pp_clock_type return 0; } -static int smu7_request_firmware(struct pp_hwmgr *hwmgr) +static void smu7_find_min_clock_masks(struct pp_hwmgr *hwmgr, + uint32_t *sclk_mask, uint32_t *mclk_mask, + uint32_t min_sclk, uint32_t min_mclk) { - int ret; - struct cgs_firmware_info info = {0}; + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + struct smu7_dpm_table *dpm_table = &(data->dpm_table); + uint32_t i; - ret = cgs_get_firmware_info(hwmgr->device, - smu7_convert_fw_type_to_cgs(UCODE_ID_SMU), - &info); - if (ret || !info.kptr) - return -EINVAL; + for (i = 0; i < dpm_table->sclk_table.count; i++) { + if (dpm_table->sclk_table.dpm_levels[i].enabled && + dpm_table->sclk_table.dpm_levels[i].value >= min_sclk) + *sclk_mask |= 1 << i; + } - return 0; + for (i = 0; i < dpm_table->mclk_table.count; i++) { + if (dpm_table->mclk_table.dpm_levels[i].enabled && + dpm_table->mclk_table.dpm_levels[i].value >= min_mclk) + *mclk_mask |= 1 << i; + } } -static int smu7_release_firmware(struct pp_hwmgr *hwmgr) +static int smu7_set_power_profile_state(struct pp_hwmgr *hwmgr, + struct amd_pp_profile *request) { - int ret; + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + int tmp_result, result = 0; + uint32_t sclk_mask = 0, mclk_mask = 0; + + if (hwmgr->chip_id == CHIP_FIJI) { + if (request->type == AMD_PP_GFX_PROFILE) + smu7_enable_power_containment(hwmgr); + else if (request->type == AMD_PP_COMPUTE_PROFILE) + smu7_disable_power_containment(hwmgr); + } - ret = cgs_rel_firmware(hwmgr->device, - smu7_convert_fw_type_to_cgs(UCODE_ID_SMU)); - if (ret) + if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_AUTO) return -EINVAL; + tmp_result = smu7_freeze_sclk_mclk_dpm(hwmgr); + PP_ASSERT_WITH_CODE(!tmp_result, + "Failed to freeze SCLK MCLK DPM!", + result = tmp_result); + + tmp_result = smum_populate_requested_graphic_levels(hwmgr, request); + PP_ASSERT_WITH_CODE(!tmp_result, + "Failed to populate requested graphic levels!", + result = tmp_result); + + tmp_result = smu7_unfreeze_sclk_mclk_dpm(hwmgr); + PP_ASSERT_WITH_CODE(!tmp_result, + "Failed to unfreeze SCLK MCLK DPM!", + result = tmp_result); + + smu7_find_min_clock_masks(hwmgr, &sclk_mask, &mclk_mask, + request->min_sclk, request->min_mclk); + + if (sclk_mask) { + if (!data->sclk_dpm_key_disabled) + smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, + PPSMC_MSG_SCLKDPM_SetEnabledMask, + data->dpm_level_enable_mask. + sclk_dpm_enable_mask & + sclk_mask); + } + + if (mclk_mask) { + if (!data->mclk_dpm_key_disabled) + smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, + PPSMC_MSG_MCLKDPM_SetEnabledMask, + data->dpm_level_enable_mask. + mclk_dpm_enable_mask & + mclk_mask); + } + + return result; +} + +static int smu7_avfs_control(struct pp_hwmgr *hwmgr, bool enable) +{ + if (enable) { + if (!PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, + CGS_IND_REG__SMC, FEATURE_STATUS, AVS_ON)) + PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc( + hwmgr->smumgr, PPSMC_MSG_EnableAvfs), + "Failed to enable AVFS!", + return -EINVAL); + } else if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, + CGS_IND_REG__SMC, FEATURE_STATUS, AVS_ON)) + PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc( + hwmgr->smumgr, PPSMC_MSG_DisableAvfs), + "Failed to disable AVFS!", + return -EINVAL); + return 0; } @@ -4549,8 +4694,9 @@ static const struct pp_hwmgr_func smu7_hwmgr_funcs = { .get_clock_by_type = smu7_get_clock_by_type, .read_sensor = smu7_read_sensor, .dynamic_state_management_disable = smu7_disable_dpm_tasks, - .request_firmware = smu7_request_firmware, - .release_firmware = smu7_release_firmware, + .set_power_profile_state = smu7_set_power_profile_state, + .avfs_control = smu7_avfs_control, + .disable_smc_firmware_ctf = smu7_thermal_disable_alert, }; uint8_t smu7_get_sleep_divider_id_from_clock(uint32_t clock, |