diff options
Diffstat (limited to 'drivers/gpu/drm/amd/powerplay/amd_powerplay.c')
| -rw-r--r-- | drivers/gpu/drm/amd/powerplay/amd_powerplay.c | 419 |
1 files changed, 355 insertions, 64 deletions
diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c index 9d2290044708..abbb658bdc1e 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c @@ -37,6 +37,12 @@ return -EINVAL; \ } while (0) +#define PP_CHECK_HW(hwmgr) \ + do { \ + if ((hwmgr) == NULL || (hwmgr)->hwmgr_func == NULL) \ + return -EINVAL; \ + } while (0) + static int pp_early_init(void *handle) { return 0; @@ -54,22 +60,29 @@ static int pp_sw_init(void *handle) pp_handle = (struct pp_instance *)handle; hwmgr = pp_handle->hwmgr; - if (hwmgr == NULL || hwmgr->pptable_func == NULL || - hwmgr->hwmgr_func == NULL || + PP_CHECK_HW(hwmgr); + + if (hwmgr->pptable_func == NULL || hwmgr->pptable_func->pptable_init == NULL || hwmgr->hwmgr_func->backend_init == NULL) return -EINVAL; ret = hwmgr->pptable_func->pptable_init(hwmgr); + if (ret) + goto err; - if (ret == 0) - ret = hwmgr->hwmgr_func->backend_init(hwmgr); - + ret = hwmgr->hwmgr_func->backend_init(hwmgr); if (ret) - printk("amdgpu: powerplay initialization failed\n"); - else - printk("amdgpu: powerplay initialized\n"); + goto err1; + + pr_info("amdgpu: powerplay initialized\n"); + return 0; +err1: + if (hwmgr->pptable_func->pptable_fini) + hwmgr->pptable_func->pptable_fini(hwmgr); +err: + pr_err("amdgpu: powerplay initialization failed\n"); return ret; } @@ -85,10 +98,14 @@ static int pp_sw_fini(void *handle) pp_handle = (struct pp_instance *)handle; hwmgr = pp_handle->hwmgr; - if (hwmgr != NULL || hwmgr->hwmgr_func != NULL || - hwmgr->hwmgr_func->backend_fini != NULL) + PP_CHECK_HW(hwmgr); + + if (hwmgr->hwmgr_func->backend_fini != NULL) ret = hwmgr->hwmgr_func->backend_fini(hwmgr); + if (hwmgr->pptable_func->pptable_fini) + hwmgr->pptable_func->pptable_fini(hwmgr); + return ret; } @@ -159,7 +176,7 @@ static int pp_hw_fini(void *handle) static bool pp_is_idle(void *handle) { - return 0; + return false; } static int pp_wait_for_idle(void *handle) @@ -172,21 +189,117 @@ static int pp_sw_reset(void *handle) return 0; } -static void pp_print_status(void *handle) -{ - -} static int pp_set_clockgating_state(void *handle, enum amd_clockgating_state state) { + struct pp_hwmgr *hwmgr; + uint32_t msg_id, pp_state; + + if (handle == NULL) + return -EINVAL; + + hwmgr = ((struct pp_instance *)handle)->hwmgr; + + PP_CHECK_HW(hwmgr); + + if (hwmgr->hwmgr_func->update_clock_gatings == NULL) { + printk(KERN_INFO "%s was not implemented.\n", __func__); + return 0; + } + + if (state == AMD_CG_STATE_UNGATE) + pp_state = 0; + else + pp_state = PP_STATE_CG | PP_STATE_LS; + + /* Enable/disable GFX blocks clock gating through SMU */ + msg_id = PP_CG_MSG_ID(PP_GROUP_GFX, + PP_BLOCK_GFX_CG, + PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS, + pp_state); + hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id); + msg_id = PP_CG_MSG_ID(PP_GROUP_GFX, + PP_BLOCK_GFX_3D, + PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS, + pp_state); + hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id); + msg_id = PP_CG_MSG_ID(PP_GROUP_GFX, + PP_BLOCK_GFX_RLC, + PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS, + pp_state); + hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id); + msg_id = PP_CG_MSG_ID(PP_GROUP_GFX, + PP_BLOCK_GFX_CP, + PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS, + pp_state); + hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id); + msg_id = PP_CG_MSG_ID(PP_GROUP_GFX, + PP_BLOCK_GFX_MG, + PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS, + pp_state); + hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id); + + /* Enable/disable System blocks clock gating through SMU */ + msg_id = PP_CG_MSG_ID(PP_GROUP_SYS, + PP_BLOCK_SYS_BIF, + PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS, + pp_state); + hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id); + msg_id = PP_CG_MSG_ID(PP_GROUP_SYS, + PP_BLOCK_SYS_BIF, + PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS, + pp_state); + hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id); + msg_id = PP_CG_MSG_ID(PP_GROUP_SYS, + PP_BLOCK_SYS_MC, + PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS, + pp_state); + hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id); + msg_id = PP_CG_MSG_ID(PP_GROUP_SYS, + PP_BLOCK_SYS_ROM, + PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS, + pp_state); + hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id); + msg_id = PP_CG_MSG_ID(PP_GROUP_SYS, + PP_BLOCK_SYS_DRM, + PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS, + pp_state); + hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id); + msg_id = PP_CG_MSG_ID(PP_GROUP_SYS, + PP_BLOCK_SYS_HDP, + PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS, + pp_state); + hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id); + msg_id = PP_CG_MSG_ID(PP_GROUP_SYS, + PP_BLOCK_SYS_SDMA, + PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS, + pp_state); + hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id); + return 0; } static int pp_set_powergating_state(void *handle, enum amd_powergating_state state) { - return 0; + struct pp_hwmgr *hwmgr; + + if (handle == NULL) + return -EINVAL; + + hwmgr = ((struct pp_instance *)handle)->hwmgr; + + PP_CHECK_HW(hwmgr); + + if (hwmgr->hwmgr_func->enable_per_cu_power_gating == NULL) { + printk(KERN_INFO "%s was not implemented.\n", __func__); + return 0; + } + + /* Enable/disable GFX per cu powergating through SMU */ + return hwmgr->hwmgr_func->enable_per_cu_power_gating(hwmgr, + state == AMD_PG_STATE_GATE ? true : false); } static int pp_suspend(void *handle) @@ -236,6 +349,7 @@ static int pp_resume(void *handle) } const struct amd_ip_funcs pp_ip_funcs = { + .name = "powerplay", .early_init = pp_early_init, .late_init = NULL, .sw_init = pp_sw_init, @@ -247,7 +361,6 @@ const struct amd_ip_funcs pp_ip_funcs = { .is_idle = pp_is_idle, .wait_for_idle = pp_wait_for_idle, .soft_reset = pp_sw_reset, - .print_status = pp_print_status, .set_clockgating_state = pp_set_clockgating_state, .set_powergating_state = pp_set_powergating_state, }; @@ -275,9 +388,12 @@ static int pp_dpm_force_performance_level(void *handle, hwmgr = pp_handle->hwmgr; - if (hwmgr == NULL || hwmgr->hwmgr_func == NULL || - hwmgr->hwmgr_func->force_dpm_level == NULL) - return -EINVAL; + PP_CHECK_HW(hwmgr); + + if (hwmgr->hwmgr_func->force_dpm_level == NULL) { + printk(KERN_INFO "%s was not implemented.\n", __func__); + return 0; + } hwmgr->hwmgr_func->force_dpm_level(hwmgr, level); @@ -309,9 +425,12 @@ static int pp_dpm_get_sclk(void *handle, bool low) hwmgr = ((struct pp_instance *)handle)->hwmgr; - if (hwmgr == NULL || hwmgr->hwmgr_func == NULL || - hwmgr->hwmgr_func->get_sclk == NULL) - return -EINVAL; + PP_CHECK_HW(hwmgr); + + if (hwmgr->hwmgr_func->get_sclk == NULL) { + printk(KERN_INFO "%s was not implemented.\n", __func__); + return 0; + } return hwmgr->hwmgr_func->get_sclk(hwmgr, low); } @@ -325,9 +444,12 @@ static int pp_dpm_get_mclk(void *handle, bool low) hwmgr = ((struct pp_instance *)handle)->hwmgr; - if (hwmgr == NULL || hwmgr->hwmgr_func == NULL || - hwmgr->hwmgr_func->get_mclk == NULL) - return -EINVAL; + PP_CHECK_HW(hwmgr); + + if (hwmgr->hwmgr_func->get_mclk == NULL) { + printk(KERN_INFO "%s was not implemented.\n", __func__); + return 0; + } return hwmgr->hwmgr_func->get_mclk(hwmgr, low); } @@ -341,9 +463,12 @@ static int pp_dpm_powergate_vce(void *handle, bool gate) hwmgr = ((struct pp_instance *)handle)->hwmgr; - if (hwmgr == NULL || hwmgr->hwmgr_func == NULL || - hwmgr->hwmgr_func->powergate_vce == NULL) - return -EINVAL; + PP_CHECK_HW(hwmgr); + + if (hwmgr->hwmgr_func->powergate_vce == NULL) { + printk(KERN_INFO "%s was not implemented.\n", __func__); + return 0; + } return hwmgr->hwmgr_func->powergate_vce(hwmgr, gate); } @@ -357,9 +482,12 @@ static int pp_dpm_powergate_uvd(void *handle, bool gate) hwmgr = ((struct pp_instance *)handle)->hwmgr; - if (hwmgr == NULL || hwmgr->hwmgr_func == NULL || - hwmgr->hwmgr_func->powergate_uvd == NULL) - return -EINVAL; + PP_CHECK_HW(hwmgr); + + if (hwmgr->hwmgr_func->powergate_uvd == NULL) { + printk(KERN_INFO "%s was not implemented.\n", __func__); + return 0; + } return hwmgr->hwmgr_func->powergate_uvd(hwmgr, gate); } @@ -408,6 +536,10 @@ int pp_dpm_dispatch_tasks(void *handle, enum amd_pp_event event_id, void *input, case AMD_PP_EVENT_COMPLETE_INIT: ret = pem_handle_event(pp_handle->eventmgr, event_id, &data); break; + case AMD_PP_EVENT_READJUST_POWER_STATE: + pp_handle->hwmgr->current_ps = pp_handle->hwmgr->boot_ps; + ret = pem_handle_event(pp_handle->eventmgr, event_id, &data); + break; default: break; } @@ -455,10 +587,14 @@ pp_debugfs_print_current_performance_level(void *handle, hwmgr = ((struct pp_instance *)handle)->hwmgr; - if (hwmgr == NULL || hwmgr->hwmgr_func == NULL || - hwmgr->hwmgr_func->print_current_perforce_level == NULL) + if (hwmgr == NULL || hwmgr->hwmgr_func == NULL) return; + if (hwmgr->hwmgr_func->print_current_perforce_level == NULL) { + printk(KERN_INFO "%s was not implemented.\n", __func__); + return; + } + hwmgr->hwmgr_func->print_current_perforce_level(hwmgr, m); } @@ -471,9 +607,12 @@ static int pp_dpm_set_fan_control_mode(void *handle, uint32_t mode) hwmgr = ((struct pp_instance *)handle)->hwmgr; - if (hwmgr == NULL || hwmgr->hwmgr_func == NULL || - hwmgr->hwmgr_func->set_fan_control_mode == NULL) - return -EINVAL; + PP_CHECK_HW(hwmgr); + + if (hwmgr->hwmgr_func->set_fan_control_mode == NULL) { + printk(KERN_INFO "%s was not implemented.\n", __func__); + return 0; + } return hwmgr->hwmgr_func->set_fan_control_mode(hwmgr, mode); } @@ -487,9 +626,12 @@ static int pp_dpm_get_fan_control_mode(void *handle) hwmgr = ((struct pp_instance *)handle)->hwmgr; - if (hwmgr == NULL || hwmgr->hwmgr_func == NULL || - hwmgr->hwmgr_func->get_fan_control_mode == NULL) - return -EINVAL; + PP_CHECK_HW(hwmgr); + + if (hwmgr->hwmgr_func->get_fan_control_mode == NULL) { + printk(KERN_INFO "%s was not implemented.\n", __func__); + return 0; + } return hwmgr->hwmgr_func->get_fan_control_mode(hwmgr); } @@ -503,9 +645,12 @@ static int pp_dpm_set_fan_speed_percent(void *handle, uint32_t percent) hwmgr = ((struct pp_instance *)handle)->hwmgr; - if (hwmgr == NULL || hwmgr->hwmgr_func == NULL || - hwmgr->hwmgr_func->set_fan_speed_percent == NULL) - return -EINVAL; + PP_CHECK_HW(hwmgr); + + if (hwmgr->hwmgr_func->set_fan_speed_percent == NULL) { + printk(KERN_INFO "%s was not implemented.\n", __func__); + return 0; + } return hwmgr->hwmgr_func->set_fan_speed_percent(hwmgr, percent); } @@ -519,9 +664,12 @@ static int pp_dpm_get_fan_speed_percent(void *handle, uint32_t *speed) hwmgr = ((struct pp_instance *)handle)->hwmgr; - if (hwmgr == NULL || hwmgr->hwmgr_func == NULL || - hwmgr->hwmgr_func->get_fan_speed_percent == NULL) - return -EINVAL; + PP_CHECK_HW(hwmgr); + + if (hwmgr->hwmgr_func->get_fan_speed_percent == NULL) { + printk(KERN_INFO "%s was not implemented.\n", __func__); + return 0; + } return hwmgr->hwmgr_func->get_fan_speed_percent(hwmgr, speed); } @@ -535,9 +683,12 @@ static int pp_dpm_get_temperature(void *handle) hwmgr = ((struct pp_instance *)handle)->hwmgr; - if (hwmgr == NULL || hwmgr->hwmgr_func == NULL || - hwmgr->hwmgr_func->get_temperature == NULL) - return -EINVAL; + PP_CHECK_HW(hwmgr); + + if (hwmgr->hwmgr_func->get_temperature == NULL) { + printk(KERN_INFO "%s was not implemented.\n", __func__); + return 0; + } return hwmgr->hwmgr_func->get_temperature(hwmgr); } @@ -591,11 +742,14 @@ static int pp_dpm_get_pp_table(void *handle, char **table) hwmgr = ((struct pp_instance *)handle)->hwmgr; - if (hwmgr == NULL || hwmgr->hwmgr_func == NULL || - hwmgr->hwmgr_func->get_pp_table == NULL) + PP_CHECK_HW(hwmgr); + + if (!hwmgr->soft_pp_table) return -EINVAL; - return hwmgr->hwmgr_func->get_pp_table(hwmgr, table); + *table = (char *)hwmgr->soft_pp_table; + + return hwmgr->soft_pp_table_size; } static int pp_dpm_set_pp_table(void *handle, const char *buf, size_t size) @@ -607,15 +761,29 @@ static int pp_dpm_set_pp_table(void *handle, const char *buf, size_t size) hwmgr = ((struct pp_instance *)handle)->hwmgr; - if (hwmgr == NULL || hwmgr->hwmgr_func == NULL || - hwmgr->hwmgr_func->set_pp_table == NULL) - return -EINVAL; + PP_CHECK_HW(hwmgr); + + if (!hwmgr->hardcode_pp_table) { + hwmgr->hardcode_pp_table = + kzalloc(hwmgr->soft_pp_table_size, GFP_KERNEL); + + if (!hwmgr->hardcode_pp_table) + return -ENOMEM; + + /* to avoid powerplay crash when hardcode pptable is empty */ + memcpy(hwmgr->hardcode_pp_table, hwmgr->soft_pp_table, + hwmgr->soft_pp_table_size); + } + + memcpy(hwmgr->hardcode_pp_table, buf, size); + + hwmgr->soft_pp_table = hwmgr->hardcode_pp_table; - return hwmgr->hwmgr_func->set_pp_table(hwmgr, buf, size); + return amd_powerplay_reset(handle); } static int pp_dpm_force_clock_level(void *handle, - enum pp_clock_type type, int level) + enum pp_clock_type type, uint32_t mask) { struct pp_hwmgr *hwmgr; @@ -624,11 +792,14 @@ static int pp_dpm_force_clock_level(void *handle, hwmgr = ((struct pp_instance *)handle)->hwmgr; - if (hwmgr == NULL || hwmgr->hwmgr_func == NULL || - hwmgr->hwmgr_func->force_clock_level == NULL) - return -EINVAL; + PP_CHECK_HW(hwmgr); - return hwmgr->hwmgr_func->force_clock_level(hwmgr, type, level); + if (hwmgr->hwmgr_func->force_clock_level == NULL) { + printk(KERN_INFO "%s was not implemented.\n", __func__); + return 0; + } + + return hwmgr->hwmgr_func->force_clock_level(hwmgr, type, mask); } static int pp_dpm_print_clock_levels(void *handle, @@ -641,13 +812,91 @@ static int pp_dpm_print_clock_levels(void *handle, hwmgr = ((struct pp_instance *)handle)->hwmgr; - if (hwmgr == NULL || hwmgr->hwmgr_func == NULL || - hwmgr->hwmgr_func->print_clock_levels == NULL) - return -EINVAL; + PP_CHECK_HW(hwmgr); + if (hwmgr->hwmgr_func->print_clock_levels == NULL) { + printk(KERN_INFO "%s was not implemented.\n", __func__); + return 0; + } return hwmgr->hwmgr_func->print_clock_levels(hwmgr, type, buf); } +static int pp_dpm_get_sclk_od(void *handle) +{ + struct pp_hwmgr *hwmgr; + + if (!handle) + return -EINVAL; + + hwmgr = ((struct pp_instance *)handle)->hwmgr; + + PP_CHECK_HW(hwmgr); + + if (hwmgr->hwmgr_func->get_sclk_od == NULL) { + printk(KERN_INFO "%s was not implemented.\n", __func__); + return 0; + } + + return hwmgr->hwmgr_func->get_sclk_od(hwmgr); +} + +static int pp_dpm_set_sclk_od(void *handle, uint32_t value) +{ + struct pp_hwmgr *hwmgr; + + if (!handle) + return -EINVAL; + + hwmgr = ((struct pp_instance *)handle)->hwmgr; + + PP_CHECK_HW(hwmgr); + + if (hwmgr->hwmgr_func->set_sclk_od == NULL) { + printk(KERN_INFO "%s was not implemented.\n", __func__); + return 0; + } + + return hwmgr->hwmgr_func->set_sclk_od(hwmgr, value); +} + +static int pp_dpm_get_mclk_od(void *handle) +{ + struct pp_hwmgr *hwmgr; + + if (!handle) + return -EINVAL; + + hwmgr = ((struct pp_instance *)handle)->hwmgr; + + PP_CHECK_HW(hwmgr); + + if (hwmgr->hwmgr_func->get_mclk_od == NULL) { + printk(KERN_INFO "%s was not implemented.\n", __func__); + return 0; + } + + return hwmgr->hwmgr_func->get_mclk_od(hwmgr); +} + +static int pp_dpm_set_mclk_od(void *handle, uint32_t value) +{ + struct pp_hwmgr *hwmgr; + + if (!handle) + return -EINVAL; + + hwmgr = ((struct pp_instance *)handle)->hwmgr; + + PP_CHECK_HW(hwmgr); + + if (hwmgr->hwmgr_func->set_mclk_od == NULL) { + printk(KERN_INFO "%s was not implemented.\n", __func__); + return 0; + } + + return hwmgr->hwmgr_func->set_mclk_od(hwmgr, value); +} + const struct amd_powerplay_funcs pp_dpm_funcs = { .get_temperature = pp_dpm_get_temperature, .load_firmware = pp_dpm_load_fw, @@ -670,6 +919,10 @@ const struct amd_powerplay_funcs pp_dpm_funcs = { .set_pp_table = pp_dpm_set_pp_table, .force_clock_level = pp_dpm_force_clock_level, .print_clock_levels = pp_dpm_print_clock_levels, + .get_sclk_od = pp_dpm_get_sclk_od, + .set_sclk_od = pp_dpm_set_sclk_od, + .get_mclk_od = pp_dpm_get_mclk_od, + .set_mclk_od = pp_dpm_set_mclk_od, }; static int amd_pp_instance_init(struct amd_pp_init *pp_init, @@ -751,6 +1004,44 @@ int amd_powerplay_fini(void *handle) return 0; } +int amd_powerplay_reset(void *handle) +{ + struct pp_instance *instance = (struct pp_instance *)handle; + struct pp_eventmgr *eventmgr; + struct pem_event_data event_data = { {0} }; + int ret; + + if (instance == NULL) + return -EINVAL; + + eventmgr = instance->eventmgr; + if (!eventmgr || !eventmgr->pp_eventmgr_fini) + return -EINVAL; + + eventmgr->pp_eventmgr_fini(eventmgr); + + ret = pp_sw_fini(handle); + if (ret) + return ret; + + kfree(instance->hwmgr->ps); + + ret = pp_sw_init(handle); + if (ret) + return ret; + + hw_init_power_state_table(instance->hwmgr); + + if (eventmgr == NULL || eventmgr->pp_eventmgr_init == NULL) + return -EINVAL; + + ret = eventmgr->pp_eventmgr_init(eventmgr); + if (ret) + return ret; + + return pem_handle_event(eventmgr, AMD_PP_EVENT_COMPLETE_INIT, &event_data); +} + /* export this function to DAL */ int amd_powerplay_display_configuration_change(void *handle, |

