diff options
Diffstat (limited to 'drivers/gpu/drm/amd/powerplay')
17 files changed, 926 insertions, 106 deletions
diff --git a/drivers/gpu/drm/amd/powerplay/Makefile b/drivers/gpu/drm/amd/powerplay/Makefile index e195bf59da86..043e6ebab575 100644 --- a/drivers/gpu/drm/amd/powerplay/Makefile +++ b/drivers/gpu/drm/amd/powerplay/Makefile @@ -1,17 +1,17 @@ subdir-ccflags-y += -Iinclude/drm \ - -Idrivers/gpu/drm/amd/powerplay/inc/ \ - -Idrivers/gpu/drm/amd/include/asic_reg \ - -Idrivers/gpu/drm/amd/include \ - -Idrivers/gpu/drm/amd/powerplay/smumgr\ - -Idrivers/gpu/drm/amd/powerplay/hwmgr \ - -Idrivers/gpu/drm/amd/powerplay/eventmgr + -I$(FULL_AMD_PATH)/powerplay/inc/ \ + -I$(FULL_AMD_PATH)/include/asic_reg \ + -I$(FULL_AMD_PATH)/include \ + -I$(FULL_AMD_PATH)/powerplay/smumgr\ + -I$(FULL_AMD_PATH)/powerplay/hwmgr \ + -I$(FULL_AMD_PATH)/powerplay/eventmgr AMD_PP_PATH = ../powerplay PP_LIBS = smumgr hwmgr eventmgr -AMD_POWERPLAY = $(addsuffix /Makefile,$(addprefix drivers/gpu/drm/amd/powerplay/,$(PP_LIBS))) +AMD_POWERPLAY = $(addsuffix /Makefile,$(addprefix $(FULL_AMD_PATH)/powerplay/,$(PP_LIBS))) include $(AMD_POWERPLAY) diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c index 589599f66fcc..9d2290044708 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c @@ -29,6 +29,7 @@ #include "pp_instance.h" #include "power_state.h" #include "eventmanager.h" +#include "pp_debug.h" #define PP_CHECK(handle) \ do { \ @@ -436,7 +437,10 @@ enum amd_pm_state_type pp_dpm_get_current_power_state(void *handle) case PP_StateUILabel_Performance: return POWER_STATE_TYPE_PERFORMANCE; default: - return POWER_STATE_TYPE_DEFAULT; + if (state->classification.flags & PP_StateClassificationFlag_Boot) + return POWER_STATE_TYPE_INTERNAL_BOOT; + else + return POWER_STATE_TYPE_DEFAULT; } } @@ -538,6 +542,112 @@ static int pp_dpm_get_temperature(void *handle) return hwmgr->hwmgr_func->get_temperature(hwmgr); } +static int pp_dpm_get_pp_num_states(void *handle, + struct pp_states_info *data) +{ + struct pp_hwmgr *hwmgr; + int i; + + if (!handle) + return -EINVAL; + + hwmgr = ((struct pp_instance *)handle)->hwmgr; + + if (hwmgr == NULL || hwmgr->ps == NULL) + return -EINVAL; + + data->nums = hwmgr->num_ps; + + for (i = 0; i < hwmgr->num_ps; i++) { + struct pp_power_state *state = (struct pp_power_state *) + ((unsigned long)hwmgr->ps + i * hwmgr->ps_size); + switch (state->classification.ui_label) { + case PP_StateUILabel_Battery: + data->states[i] = POWER_STATE_TYPE_BATTERY; + break; + case PP_StateUILabel_Balanced: + data->states[i] = POWER_STATE_TYPE_BALANCED; + break; + case PP_StateUILabel_Performance: + data->states[i] = POWER_STATE_TYPE_PERFORMANCE; + break; + default: + if (state->classification.flags & PP_StateClassificationFlag_Boot) + data->states[i] = POWER_STATE_TYPE_INTERNAL_BOOT; + else + data->states[i] = POWER_STATE_TYPE_DEFAULT; + } + } + + return 0; +} + +static int pp_dpm_get_pp_table(void *handle, char **table) +{ + struct pp_hwmgr *hwmgr; + + if (!handle) + return -EINVAL; + + hwmgr = ((struct pp_instance *)handle)->hwmgr; + + if (hwmgr == NULL || hwmgr->hwmgr_func == NULL || + hwmgr->hwmgr_func->get_pp_table == NULL) + return -EINVAL; + + return hwmgr->hwmgr_func->get_pp_table(hwmgr, table); +} + +static int pp_dpm_set_pp_table(void *handle, const char *buf, size_t size) +{ + struct pp_hwmgr *hwmgr; + + if (!handle) + return -EINVAL; + + hwmgr = ((struct pp_instance *)handle)->hwmgr; + + if (hwmgr == NULL || hwmgr->hwmgr_func == NULL || + hwmgr->hwmgr_func->set_pp_table == NULL) + return -EINVAL; + + return hwmgr->hwmgr_func->set_pp_table(hwmgr, buf, size); +} + +static int pp_dpm_force_clock_level(void *handle, + enum pp_clock_type type, int level) +{ + struct pp_hwmgr *hwmgr; + + if (!handle) + return -EINVAL; + + hwmgr = ((struct pp_instance *)handle)->hwmgr; + + if (hwmgr == NULL || hwmgr->hwmgr_func == NULL || + hwmgr->hwmgr_func->force_clock_level == NULL) + return -EINVAL; + + return hwmgr->hwmgr_func->force_clock_level(hwmgr, type, level); +} + +static int pp_dpm_print_clock_levels(void *handle, + enum pp_clock_type type, char *buf) +{ + struct pp_hwmgr *hwmgr; + + if (!handle) + return -EINVAL; + + hwmgr = ((struct pp_instance *)handle)->hwmgr; + + if (hwmgr == NULL || hwmgr->hwmgr_func == NULL || + hwmgr->hwmgr_func->print_clock_levels == NULL) + return -EINVAL; + + return hwmgr->hwmgr_func->print_clock_levels(hwmgr, type, buf); +} + const struct amd_powerplay_funcs pp_dpm_funcs = { .get_temperature = pp_dpm_get_temperature, .load_firmware = pp_dpm_load_fw, @@ -555,6 +665,11 @@ const struct amd_powerplay_funcs pp_dpm_funcs = { .get_fan_control_mode = pp_dpm_get_fan_control_mode, .set_fan_speed_percent = pp_dpm_set_fan_speed_percent, .get_fan_speed_percent = pp_dpm_get_fan_speed_percent, + .get_pp_num_states = pp_dpm_get_pp_num_states, + .get_pp_table = pp_dpm_get_pp_table, + .set_pp_table = pp_dpm_set_pp_table, + .force_clock_level = pp_dpm_force_clock_level, + .print_clock_levels = pp_dpm_print_clock_levels, }; static int amd_pp_instance_init(struct amd_pp_init *pp_init, @@ -638,10 +753,10 @@ int amd_powerplay_fini(void *handle) /* export this function to DAL */ -int amd_powerplay_display_configuration_change(void *handle, const void *input) +int amd_powerplay_display_configuration_change(void *handle, + const struct amd_pp_display_configuration *display_config) { struct pp_hwmgr *hwmgr; - const struct amd_pp_display_configuration *display_config = input; PP_CHECK((struct pp_instance *)handle); @@ -653,7 +768,7 @@ int amd_powerplay_display_configuration_change(void *handle, const void *input) } int amd_powerplay_get_display_power_level(void *handle, - struct amd_pp_dal_clock_info *output) + struct amd_pp_simple_clock_info *output) { struct pp_hwmgr *hwmgr; @@ -666,3 +781,86 @@ int amd_powerplay_get_display_power_level(void *handle, return phm_get_dal_power_level(hwmgr, output); } + +int amd_powerplay_get_current_clocks(void *handle, + struct amd_pp_clock_info *clocks) +{ + struct pp_hwmgr *hwmgr; + struct amd_pp_simple_clock_info simple_clocks; + struct pp_clock_info hw_clocks; + + PP_CHECK((struct pp_instance *)handle); + + if (clocks == NULL) + return -EINVAL; + + hwmgr = ((struct pp_instance *)handle)->hwmgr; + + phm_get_dal_power_level(hwmgr, &simple_clocks); + + if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PowerContainment)) { + if (0 != phm_get_clock_info(hwmgr, &hwmgr->current_ps->hardware, &hw_clocks, PHM_PerformanceLevelDesignation_PowerContainment)) + PP_ASSERT_WITH_CODE(0, "Error in PHM_GetPowerContainmentClockInfo", return -1); + } else { + if (0 != phm_get_clock_info(hwmgr, &hwmgr->current_ps->hardware, &hw_clocks, PHM_PerformanceLevelDesignation_Activity)) + PP_ASSERT_WITH_CODE(0, "Error in PHM_GetClockInfo", return -1); + } + + clocks->min_engine_clock = hw_clocks.min_eng_clk; + clocks->max_engine_clock = hw_clocks.max_eng_clk; + clocks->min_memory_clock = hw_clocks.min_mem_clk; + clocks->max_memory_clock = hw_clocks.max_mem_clk; + clocks->min_bus_bandwidth = hw_clocks.min_bus_bandwidth; + clocks->max_bus_bandwidth = hw_clocks.max_bus_bandwidth; + + clocks->max_engine_clock_in_sr = hw_clocks.max_eng_clk; + clocks->min_engine_clock_in_sr = hw_clocks.min_eng_clk; + + clocks->max_clocks_state = simple_clocks.level; + + if (0 == phm_get_current_shallow_sleep_clocks(hwmgr, &hwmgr->current_ps->hardware, &hw_clocks)) { + clocks->max_engine_clock_in_sr = hw_clocks.max_eng_clk; + clocks->min_engine_clock_in_sr = hw_clocks.min_eng_clk; + } + + return 0; + +} + +int amd_powerplay_get_clock_by_type(void *handle, enum amd_pp_clock_type type, struct amd_pp_clocks *clocks) +{ + int result = -1; + + struct pp_hwmgr *hwmgr; + + PP_CHECK((struct pp_instance *)handle); + + if (clocks == NULL) + return -EINVAL; + + hwmgr = ((struct pp_instance *)handle)->hwmgr; + + result = phm_get_clock_by_type(hwmgr, type, clocks); + + return result; +} + +int amd_powerplay_get_display_mode_validation_clocks(void *handle, + struct amd_pp_simple_clock_info *clocks) +{ + int result = -1; + struct pp_hwmgr *hwmgr; + + PP_CHECK((struct pp_instance *)handle); + + if (clocks == NULL) + return -EINVAL; + + hwmgr = ((struct pp_instance *)handle)->hwmgr; + + if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DynamicPatchPowerState)) + result = phm_get_max_high_clocks(hwmgr, clocks); + + return result; +} + diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c index cf01177ca3b5..5682490337e3 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c @@ -241,6 +241,11 @@ static int cz_initialize_dpm_defaults(struct pp_hwmgr *hwmgr) phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DynamicUVDState); + phm_cap_set(hwmgr->platform_descriptor.platformCaps, + PHM_PlatformCaps_UVDDPM); + phm_cap_set(hwmgr->platform_descriptor.platformCaps, + PHM_PlatformCaps_VCEDPM); + cz_hwmgr->cc6_settings.cpu_cc6_disable = false; cz_hwmgr->cc6_settings.cpu_pstate_disable = false; cz_hwmgr->cc6_settings.nb_pstate_switch_disable = false; @@ -733,7 +738,6 @@ static int cz_tf_update_sclk_limit(struct pp_hwmgr *hwmgr, unsigned long clock = 0; unsigned long level; unsigned long stable_pstate_sclk; - struct PP_Clocks clocks; unsigned long percentage; cz_hwmgr->sclk_dpm.soft_min_clk = table->entries[0].clk; @@ -744,8 +748,10 @@ static int cz_tf_update_sclk_limit(struct pp_hwmgr *hwmgr, else cz_hwmgr->sclk_dpm.soft_max_clk = table->entries[table->count - 1].clk; - /*PECI_GetMinClockSettings(pHwMgr->pPECI, &clocks);*/ - clock = clocks.engineClock; + clock = hwmgr->display_config.min_core_set_clock; +; + if (clock == 0) + printk(KERN_INFO "[ powerplay ] min_core_set_clock not set\n"); if (cz_hwmgr->sclk_dpm.hard_min_clk != clock) { cz_hwmgr->sclk_dpm.hard_min_clk = clock; @@ -901,9 +907,9 @@ static int cz_tf_update_low_mem_pstate(struct pp_hwmgr *hwmgr, if (pnew_state->action == FORCE_HIGH) cz_nbdpm_pstate_enable_disable(hwmgr, false, disable_switch); - else if(pnew_state->action == CANCEL_FORCE_HIGH) - cz_nbdpm_pstate_enable_disable(hwmgr, false, disable_switch); - else + else if (pnew_state->action == CANCEL_FORCE_HIGH) + cz_nbdpm_pstate_enable_disable(hwmgr, true, disable_switch); + else cz_nbdpm_pstate_enable_disable(hwmgr, enable_low_mem_state, disable_switch); } return 0; @@ -1128,9 +1134,10 @@ static int cz_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, cast_const_PhwCzPowerState(&pcurrent_ps->hardware); struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend); - struct PP_Clocks clocks; + struct PP_Clocks clocks = {0, 0, 0, 0}; bool force_high; - unsigned long num_of_active_displays = 4; + uint32_t num_of_active_displays = 0; + struct cgs_display_info info = {0}; cz_ps->evclk = hwmgr->vce_arbiter.evclk; cz_ps->ecclk = hwmgr->vce_arbiter.ecclk; @@ -1142,12 +1149,15 @@ static int cz_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, cz_hwmgr->battery_state = (PP_StateUILabel_Battery == prequest_ps->classification.ui_label); - /* to do PECI_GetMinClockSettings(pHwMgr->pPECI, &clocks); */ - /* PECI_GetNumberOfActiveDisplays(pHwMgr->pPECI, &numOfActiveDisplays); */ + clocks.memoryClock = hwmgr->display_config.min_mem_set_clock != 0 ? + hwmgr->display_config.min_mem_set_clock : + cz_hwmgr->sys_info.nbp_memory_clock[1]; + + cgs_get_active_displays_info(hwmgr->device, &info); + num_of_active_displays = info.display_count; + if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState)) clocks.memoryClock = hwmgr->dyn_state.max_clock_voltage_on_ac.mclk; - else - clocks.memoryClock = 0; if (clocks.memoryClock < hwmgr->gfx_arbiter.mclk) clocks.memoryClock = hwmgr->gfx_arbiter.mclk; @@ -1217,6 +1227,7 @@ static int cz_hwmgr_backend_init(struct pp_hwmgr *hwmgr) printk(KERN_ERR "[ powerplay ] Fail to construct set_power_state\n"); return result; } + hwmgr->platform_descriptor.hardwareActivityPerformanceLevels = CZ_MAX_HARDWARE_POWERLEVELS; result = phm_construct_table(hwmgr, &cz_phm_enable_clock_power_gatings_master, &(hwmgr->enable_clock_power_gatings)); if (result != 0) { @@ -1648,10 +1659,10 @@ static void cz_hw_print_display_cfg( & PWRMGT_SEPARATION_TIME_MASK) << PWRMGT_SEPARATION_TIME_SHIFT; - data|= (hw_data->cc6_settings.cpu_cc6_disable ? 0x1 : 0x0) + data |= (hw_data->cc6_settings.cpu_cc6_disable ? 0x1 : 0x0) << PWRMGT_DISABLE_CPU_CSTATES_SHIFT; - data|= (hw_data->cc6_settings.cpu_pstate_disable ? 0x1 : 0x0) + data |= (hw_data->cc6_settings.cpu_pstate_disable ? 0x1 : 0x0) << PWRMGT_DISABLE_CPU_PSTATES_SHIFT; PP_DBG_LOG("SetDisplaySizePowerParams data: 0x%X\n", @@ -1666,9 +1677,9 @@ static void cz_hw_print_display_cfg( } - static int cz_store_cc6_data(struct pp_hwmgr *hwmgr, uint32_t separation_time, +static int cz_store_cc6_data(struct pp_hwmgr *hwmgr, uint32_t separation_time, bool cc6_disable, bool pstate_disable, bool pstate_switch_disable) - { +{ struct cz_hwmgr *hw_data = (struct cz_hwmgr *)(hwmgr->backend); if (separation_time != @@ -1696,20 +1707,19 @@ static void cz_hw_print_display_cfg( return 0; } - static int cz_get_dal_power_level(struct pp_hwmgr *hwmgr, - struct amd_pp_dal_clock_info*info) +static int cz_get_dal_power_level(struct pp_hwmgr *hwmgr, + struct amd_pp_simple_clock_info *info) { uint32_t i; - const struct phm_clock_voltage_dependency_table * table = + const struct phm_clock_voltage_dependency_table *table = hwmgr->dyn_state.vddc_dep_on_dal_pwrl; - const struct phm_clock_and_voltage_limits* limits = + const struct phm_clock_and_voltage_limits *limits = &hwmgr->dyn_state.max_clock_voltage_on_ac; info->engine_max_clock = limits->sclk; info->memory_max_clock = limits->mclk; for (i = table->count - 1; i > 0; i--) { - if (limits->vddc >= table->entries[i].v) { info->level = table->entries[i].clk; return 0; @@ -1718,6 +1728,158 @@ static void cz_hw_print_display_cfg( return -EINVAL; } +static int cz_force_clock_level(struct pp_hwmgr *hwmgr, + enum pp_clock_type type, int level) +{ + if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) + return -EINVAL; + + switch (type) { + case PP_SCLK: + smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, + PPSMC_MSG_SetSclkSoftMin, + (1 << level)); + smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, + PPSMC_MSG_SetSclkSoftMax, + (1 << level)); + break; + default: + break; + } + + return 0; +} + +static int cz_print_clock_levels(struct pp_hwmgr *hwmgr, + enum pp_clock_type type, char *buf) +{ + struct phm_clock_voltage_dependency_table *sclk_table = + hwmgr->dyn_state.vddc_dependency_on_sclk; + int i, now, size = 0; + + switch (type) { + case PP_SCLK: + now = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, + CGS_IND_REG__SMC, + ixTARGET_AND_CURRENT_PROFILE_INDEX), + TARGET_AND_CURRENT_PROFILE_INDEX, + CURR_SCLK_INDEX); + + for (i = 0; i < sclk_table->count; i++) + size += sprintf(buf + size, "%d: %uMhz %s\n", + i, sclk_table->entries[i].clk / 100, + (i == now) ? "*" : ""); + break; + default: + break; + } + return size; +} + +static int cz_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state, + PHM_PerformanceLevelDesignation designation, uint32_t index, + PHM_PerformanceLevel *level) +{ + const struct cz_power_state *ps; + struct cz_hwmgr *data; + uint32_t level_index; + uint32_t i; + + if (level == NULL || hwmgr == NULL || state == NULL) + return -EINVAL; + + data = (struct cz_hwmgr *)(hwmgr->backend); + ps = cast_const_PhwCzPowerState(state); + + level_index = index > ps->level - 1 ? ps->level - 1 : index; + + level->coreClock = ps->levels[level_index].engineClock; + + if (designation == PHM_PerformanceLevelDesignation_PowerContainment) { + for (i = 1; i < ps->level; i++) { + if (ps->levels[i].engineClock > data->dce_slow_sclk_threshold) { + level->coreClock = ps->levels[i].engineClock; + break; + } + } + } + + if (level_index == 0) + level->memory_clock = data->sys_info.nbp_memory_clock[CZ_NUM_NBPMEMORYCLOCK - 1]; + else + level->memory_clock = data->sys_info.nbp_memory_clock[0]; + + level->vddc = (cz_convert_8Bit_index_to_voltage(hwmgr, ps->levels[level_index].vddcIndex) + 2) / 4; + level->nonLocalMemoryFreq = 0; + level->nonLocalMemoryWidth = 0; + + return 0; +} + +static int cz_get_current_shallow_sleep_clocks(struct pp_hwmgr *hwmgr, + const struct pp_hw_power_state *state, struct pp_clock_info *clock_info) +{ + const struct cz_power_state *ps = cast_const_PhwCzPowerState(state); + + clock_info->min_eng_clk = ps->levels[0].engineClock / (1 << (ps->levels[0].ssDividerIndex)); + clock_info->max_eng_clk = ps->levels[ps->level - 1].engineClock / (1 << (ps->levels[ps->level - 1].ssDividerIndex)); + + return 0; +} + +static int cz_get_clock_by_type(struct pp_hwmgr *hwmgr, enum amd_pp_clock_type type, + struct amd_pp_clocks *clocks) +{ + struct cz_hwmgr *data = (struct cz_hwmgr *)(hwmgr->backend); + int i; + struct phm_clock_voltage_dependency_table *table; + + clocks->count = cz_get_max_sclk_level(hwmgr); + switch (type) { + case amd_pp_disp_clock: + for (i = 0; i < clocks->count; i++) + clocks->clock[i] = data->sys_info.display_clock[i]; + break; + case amd_pp_sys_clock: + table = hwmgr->dyn_state.vddc_dependency_on_sclk; + for (i = 0; i < clocks->count; i++) + clocks->clock[i] = table->entries[i].clk; + break; + case amd_pp_mem_clock: + clocks->count = CZ_NUM_NBPMEMORYCLOCK; + for (i = 0; i < clocks->count; i++) + clocks->clock[i] = data->sys_info.nbp_memory_clock[clocks->count - 1 - i]; + break; + default: + return -1; + } + + return 0; +} + +static int cz_get_max_high_clocks(struct pp_hwmgr *hwmgr, struct amd_pp_simple_clock_info *clocks) +{ + struct phm_clock_voltage_dependency_table *table = + hwmgr->dyn_state.vddc_dependency_on_sclk; + unsigned long level; + const struct phm_clock_and_voltage_limits *limits = + &hwmgr->dyn_state.max_clock_voltage_on_ac; + + if ((NULL == table) || (table->count <= 0) || (clocks == NULL)) + return -EINVAL; + + level = cz_get_max_sclk_level(hwmgr) - 1; + + if (level < table->count) + clocks->engine_max_clock = table->entries[level].clk; + else + clocks->engine_max_clock = table->entries[table->count - 1].clk; + + clocks->memory_max_clock = limits->mclk; + + return 0; +} + static const struct pp_hwmgr_func cz_hwmgr_funcs = { .backend_init = cz_hwmgr_backend_init, .backend_fini = cz_hwmgr_backend_fini, @@ -1736,7 +1898,13 @@ static const struct pp_hwmgr_func cz_hwmgr_funcs = { .print_current_perforce_level = cz_print_current_perforce_level, .set_cpu_power_state = cz_set_cpu_power_state, .store_cc6_data = cz_store_cc6_data, - .get_dal_power_level= cz_get_dal_power_level, + .force_clock_level = cz_force_clock_level, + .print_clock_levels = cz_print_clock_levels, + .get_dal_power_level = cz_get_dal_power_level, + .get_performance_level = cz_get_performance_level, + .get_current_shallow_sleep_clocks = cz_get_current_shallow_sleep_clocks, + .get_clock_by_type = cz_get_clock_by_type, + .get_max_high_clocks = cz_get_max_high_clocks, }; int cz_hwmgr_init(struct pp_hwmgr *hwmgr) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c index 28031a7eddba..51dedf84623c 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c @@ -4275,7 +4275,6 @@ static int fiji_populate_and_upload_sclk_mclk_dpm_levels( if (data->need_update_smu7_dpm_table & DPMTABLE_OD_UPDATE_MCLK) { dpm_table->mclk_table.dpm_levels [dpm_table->mclk_table.count - 1].value = mclk; - if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_OD6PlusinACSupport) || phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, @@ -4886,6 +4885,10 @@ static void fiji_print_current_perforce_level( activity_percent >>= 8; seq_printf(m, "\n [GPU load]: %u%%\n\n", activity_percent > 100 ? 100 : activity_percent); + + seq_printf(m, "uvd %sabled\n", data->uvd_power_gated ? "dis" : "en"); + + seq_printf(m, "vce %sabled\n", data->vce_power_gated ? "dis" : "en"); } static int fiji_program_display_gap(struct pp_hwmgr *hwmgr) @@ -5073,6 +5076,125 @@ static int fiji_get_fan_control_mode(struct pp_hwmgr *hwmgr) CG_FDO_CTRL2, FDO_PWM_MODE); } +static int fiji_get_pp_table(struct pp_hwmgr *hwmgr, char **table) +{ + struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend); + + *table = (char *)&data->smc_state_table; + + return sizeof(struct SMU73_Discrete_DpmTable); +} + +static int fiji_set_pp_table(struct pp_hwmgr *hwmgr, const char *buf, size_t size) +{ + struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend); + + void *table = (void *)&data->smc_state_table; + + memcpy(table, buf, size); + + return 0; +} + +static int fiji_force_clock_level(struct pp_hwmgr *hwmgr, + enum pp_clock_type type, int level) +{ + struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend); + + if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) + return -EINVAL; + + switch (type) { + case PP_SCLK: + if (!data->sclk_dpm_key_disabled) + smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, + PPSMC_MSG_SCLKDPM_SetEnabledMask, + (1 << level)); + break; + case PP_MCLK: + if (!data->mclk_dpm_key_disabled) + smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, + PPSMC_MSG_MCLKDPM_SetEnabledMask, + (1 << level)); + break; + case PP_PCIE: + if (!data->pcie_dpm_key_disabled) + smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, + PPSMC_MSG_PCIeDPM_ForceLevel, + (1 << level)); + break; + default: + break; + } + + return 0; +} + +static int fiji_print_clock_levels(struct pp_hwmgr *hwmgr, + enum pp_clock_type type, char *buf) +{ + struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend); + struct fiji_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table); + struct fiji_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table); + struct fiji_single_dpm_table *pcie_table = &(data->dpm_table.pcie_speed_table); + int i, now, size = 0; + uint32_t clock, pcie_speed; + + switch (type) { + case PP_SCLK: + smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetSclkFrequency); + clock = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0); + + for (i = 0; i < sclk_table->count; i++) { + if (clock > sclk_table->dpm_levels[i].value) + continue; + break; + } + now = i; + + for (i = 0; i < sclk_table->count; i++) + size += sprintf(buf + size, "%d: %uMhz %s\n", + i, sclk_table->dpm_levels[i].value / 100, + (i == now) ? "*" : ""); + break; + case PP_MCLK: + smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetMclkFrequency); + clock = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0); + + for (i = 0; i < mclk_table->count; i++) { + if (clock > mclk_table->dpm_levels[i].value) + continue; + break; + } + now = i; + + for (i = 0; i < mclk_table->count; i++) + size += sprintf(buf + size, "%d: %uMhz %s\n", + i, mclk_table->dpm_levels[i].value / 100, + (i == now) ? "*" : ""); + break; + case PP_PCIE: + pcie_speed = fiji_get_current_pcie_speed(hwmgr); + for (i = 0; i < pcie_table->count; i++) { + if (pcie_speed != pcie_table->dpm_levels[i].value) + continue; + break; + } + now = i; + + for (i = 0; i < pcie_table->count; i++) + size += sprintf(buf + size, "%d: %s %s\n", i, + (pcie_table->dpm_levels[i].value == 0) ? "2.5GB, x1" : + (pcie_table->dpm_levels[i].value == 1) ? "5.0GB, x16" : + (pcie_table->dpm_levels[i].value == 2) ? "8.0GB, x16" : "", + (i == now) ? "*" : ""); + break; + default: + break; + } + return size; +} + static const struct pp_hwmgr_func fiji_hwmgr_funcs = { .backend_init = &fiji_hwmgr_backend_init, .backend_fini = &tonga_hwmgr_backend_fini, @@ -5108,6 +5230,10 @@ static const struct pp_hwmgr_func fiji_hwmgr_funcs = { .register_internal_thermal_interrupt = fiji_register_internal_thermal_interrupt, .set_fan_control_mode = fiji_set_fan_control_mode, .get_fan_control_mode = fiji_get_fan_control_mode, + .get_pp_table = fiji_get_pp_table, + .set_pp_table = fiji_set_pp_table, + .force_clock_level = fiji_force_clock_level, + .print_clock_levels = fiji_print_clock_levels, }; int fiji_hwmgr_init(struct pp_hwmgr *hwmgr) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.h index 22e273b1c1c5..a16f7cd4c238 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.h @@ -29,6 +29,7 @@ #include "smu73_discrete.h" #include "ppatomctrl.h" #include "fiji_ppsmc.h" +#include "pp_endian.h" #define FIJI_MAX_HARDWARE_POWERLEVELS 2 #define FIJI_AT_DFLT 30 @@ -347,15 +348,4 @@ int fiji_update_samu_dpm(struct pp_hwmgr *hwmgr, bool bgate); int fiji_update_acp_dpm(struct pp_hwmgr *hwmgr, bool bgate); int fiji_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable); -#define PP_HOST_TO_SMC_UL(X) cpu_to_be32(X) -#define PP_SMC_TO_HOST_UL(X) be32_to_cpu(X) - -#define PP_HOST_TO_SMC_US(X) cpu_to_be16(X) -#define PP_SMC_TO_HOST_US(X) be16_to_cpu(X) - -#define CONVERT_FROM_HOST_TO_SMC_UL(X) ((X) = PP_HOST_TO_SMC_UL(X)) -#define CONVERT_FROM_SMC_TO_HOST_UL(X) ((X) = PP_SMC_TO_HOST_UL(X)) - -#define CONVERT_FROM_HOST_TO_SMC_US(X) ((X) = PP_HOST_TO_SMC_US(X)) - #endif /* _FIJI_HWMGR_H_ */ diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/functiontables.c b/drivers/gpu/drm/amd/powerplay/hwmgr/functiontables.c index 9deadabbc81c..72cfecc4f9f7 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/functiontables.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/functiontables.c @@ -34,6 +34,11 @@ static int phm_run_table(struct pp_hwmgr *hwmgr, int result = 0; phm_table_function *function; + if (rt_table->function_list == NULL) { + printk(KERN_INFO "[ powerplay ] this function not implement!\n"); + return 0; + } + for (function = rt_table->function_list; NULL != *function; function++) { int tmp = (*function)(hwmgr, input, output, temp_storage, result); @@ -57,9 +62,9 @@ int phm_dispatch_table(struct pp_hwmgr *hwmgr, int result = 0; void *temp_storage = NULL; - if (hwmgr == NULL || rt_table == NULL || rt_table->function_list == NULL) { + if (hwmgr == NULL || rt_table == NULL) { printk(KERN_ERR "[ powerplay ] Invalid Parameter!\n"); - return 0; /*temp return ture because some function not implement on some asic */ + return -EINVAL; } if (0 != rt_table->storage_size) { diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c index 0f2d5e4bc241..be31bed2538a 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c @@ -26,7 +26,7 @@ #include "power_state.h" #include "pp_acpi.h" #include "amd_acpi.h" -#include "amd_powerplay.h" +#include "pp_debug.h" #define PHM_FUNC_CHECK(hw) \ do { \ @@ -313,13 +313,12 @@ int phm_store_dal_configuration_data(struct pp_hwmgr *hwmgr, } int phm_get_dal_power_level(struct pp_hwmgr *hwmgr, - struct amd_pp_dal_clock_info *info) + struct amd_pp_simple_clock_info *info) { PHM_FUNC_CHECK(hwmgr); if (info == NULL || hwmgr->hwmgr_func->get_dal_power_level == NULL) return -EINVAL; - return hwmgr->hwmgr_func->get_dal_power_level(hwmgr, info); } @@ -332,3 +331,91 @@ int phm_set_cpu_power_state(struct pp_hwmgr *hwmgr) return 0; } + + +int phm_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state, + PHM_PerformanceLevelDesignation designation, uint32_t index, + PHM_PerformanceLevel *level) +{ + PHM_FUNC_CHECK(hwmgr); + if (hwmgr->hwmgr_func->get_performance_level == NULL) + return -EINVAL; + + return hwmgr->hwmgr_func->get_performance_level(hwmgr, state, designation, index, level); + + +} + + +/** +* Gets Clock Info. +* +* @param pHwMgr the address of the powerplay hardware manager. +* @param pPowerState the address of the Power State structure. +* @param pClockInfo the address of PP_ClockInfo structure where the result will be returned. +* @exception PP_Result_Failed if any of the paramters is NULL, otherwise the return value from the back-end. +*/ +int phm_get_clock_info(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state, struct pp_clock_info *pclock_info, + PHM_PerformanceLevelDesignation designation) +{ + int result; + PHM_PerformanceLevel performance_level; + + PHM_FUNC_CHECK(hwmgr); + + PP_ASSERT_WITH_CODE((NULL != state), "Invalid Input!", return -EINVAL); + PP_ASSERT_WITH_CODE((NULL != pclock_info), "Invalid Input!", return -EINVAL); + + result = phm_get_performance_level(hwmgr, state, PHM_PerformanceLevelDesignation_Activity, 0, &performance_level); + + PP_ASSERT_WITH_CODE((0 == result), "Failed to retrieve minimum clocks.", return result); + + + pclock_info->min_mem_clk = performance_level.memory_clock; + pclock_info->min_eng_clk = performance_level.coreClock; + pclock_info->min_bus_bandwidth = performance_level.nonLocalMemoryFreq * performance_level.nonLocalMemoryWidth; + + + result = phm_get_performance_level(hwmgr, state, designation, + (hwmgr->platform_descriptor.hardwareActivityPerformanceLevels - 1), &performance_level); + + PP_ASSERT_WITH_CODE((0 == result), "Failed to retrieve maximum clocks.", return result); + + pclock_info->max_mem_clk = performance_level.memory_clock; + pclock_info->max_eng_clk = performance_level.coreClock; + pclock_info->max_bus_bandwidth = performance_level.nonLocalMemoryFreq * performance_level.nonLocalMemoryWidth; + + return 0; +} + +int phm_get_current_shallow_sleep_clocks(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state, struct pp_clock_info *clock_info) +{ + PHM_FUNC_CHECK(hwmgr); + + if (hwmgr->hwmgr_func->get_current_shallow_sleep_clocks == NULL) + return -EINVAL; + + return hwmgr->hwmgr_func->get_current_shallow_sleep_clocks(hwmgr, state, clock_info); + +} + +int phm_get_clock_by_type(struct pp_hwmgr *hwmgr, enum amd_pp_clock_type type, struct amd_pp_clocks *clocks) +{ + PHM_FUNC_CHECK(hwmgr); + + if (hwmgr->hwmgr_func->get_clock_by_type == NULL) + return -EINVAL; + + return hwmgr->hwmgr_func->get_clock_by_type(hwmgr, type, clocks); + +} + +int phm_get_max_high_clocks(struct pp_hwmgr *hwmgr, struct amd_pp_simple_clock_info *clocks) +{ + PHM_FUNC_CHECK(hwmgr); + + if (hwmgr->hwmgr_func->get_max_high_clocks == NULL) + return -EINVAL; + + return hwmgr->hwmgr_func->get_max_high_clocks(hwmgr, clocks); +} diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/ppevvmath.h b/drivers/gpu/drm/amd/powerplay/hwmgr/ppevvmath.h index b7429a527828..b10df328d58c 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/ppevvmath.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/ppevvmath.h @@ -293,7 +293,7 @@ fInt GetScaledFraction(int X, int factor) } if (factor == 1) - return (ConvertToFraction(X)); + return ConvertToFraction(X); fValue = fDivide(ConvertToFraction(X * uPow(-1, bNEGATED)), ConvertToFraction(factor)); @@ -371,7 +371,7 @@ fInt fDivide (fInt X, fInt Y) fZERO = ConvertToFraction(0); if (Equal(Y, fZERO)) - return fZERO; + return fZERO; longlongX = (int64_t)X.full; longlongY = (int64_t)Y.full; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c index 980d3bf8ea76..0d5d8372953e 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c @@ -5185,7 +5185,6 @@ tonga_print_current_perforce_level(struct pp_hwmgr *hwmgr, struct seq_file *m) mclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0); seq_printf(m, "\n [ mclk ]: %u MHz\n\n [ sclk ]: %u MHz\n", mclk/100, sclk/100); - offset = data->soft_regs_start + offsetof(SMU72_SoftRegisters, AverageGraphicsActivity); activity_percent = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, offset); activity_percent += 0x80; @@ -5193,6 +5192,9 @@ tonga_print_current_perforce_level(struct pp_hwmgr *hwmgr, struct seq_file *m) seq_printf(m, "\n [GPU load]: %u%%\n\n", activity_percent > 100 ? 100 : activity_percent); + seq_printf(m, "uvd %sabled\n", data->uvd_power_gated ? "dis" : "en"); + + seq_printf(m, "vce %sabled\n", data->vce_power_gated ? "dis" : "en"); } static int tonga_find_dpm_states_clocks_in_dpm_table(struct pp_hwmgr *hwmgr, const void *input) @@ -6033,6 +6035,125 @@ static int tonga_get_fan_control_mode(struct pp_hwmgr *hwmgr) CG_FDO_CTRL2, FDO_PWM_MODE); } +static int tonga_get_pp_table(struct pp_hwmgr *hwmgr, char **table) +{ + struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend); + + *table = (char *)&data->smc_state_table; + + return sizeof(struct SMU72_Discrete_DpmTable); +} + +static int tonga_set_pp_table(struct pp_hwmgr *hwmgr, const char *buf, size_t size) +{ + struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend); + + void *table = (void *)&data->smc_state_table; + + memcpy(table, buf, size); + + return 0; +} + +static int tonga_force_clock_level(struct pp_hwmgr *hwmgr, + enum pp_clock_type type, int level) +{ + struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend); + + if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) + return -EINVAL; + + switch (type) { + case PP_SCLK: + if (!data->sclk_dpm_key_disabled) + smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, + PPSMC_MSG_SCLKDPM_SetEnabledMask, + (1 << level)); + break; + case PP_MCLK: + if (!data->mclk_dpm_key_disabled) + smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, + PPSMC_MSG_MCLKDPM_SetEnabledMask, + (1 << level)); + break; + case PP_PCIE: + if (!data->pcie_dpm_key_disabled) + smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, + PPSMC_MSG_PCIeDPM_ForceLevel, + (1 << level)); + break; + default: + break; + } + + return 0; +} + +static int tonga_print_clock_levels(struct pp_hwmgr *hwmgr, + enum pp_clock_type type, char *buf) +{ + struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend); + struct tonga_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table); + struct tonga_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table); + struct tonga_single_dpm_table *pcie_table = &(data->dpm_table.pcie_speed_table); + int i, now, size = 0; + uint32_t clock, pcie_speed; + + switch (type) { + case PP_SCLK: + smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetSclkFrequency); + clock = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0); + + for (i = 0; i < sclk_table->count; i++) { + if (clock > sclk_table->dpm_levels[i].value) + continue; + break; + } + now = i; + + for (i = 0; i < sclk_table->count; i++) + size += sprintf(buf + size, "%d: %uMhz %s\n", + i, sclk_table->dpm_levels[i].value / 100, + (i == now) ? "*" : ""); + break; + case PP_MCLK: + smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetMclkFrequency); + clock = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0); + + for (i = 0; i < mclk_table->count; i++) { + if (clock > mclk_table->dpm_levels[i].value) + continue; + break; + } + now = i; + + for (i = 0; i < mclk_table->count; i++) + size += sprintf(buf + size, "%d: %uMhz %s\n", + i, mclk_table->dpm_levels[i].value / 100, + (i == now) ? "*" : ""); + break; + case PP_PCIE: + pcie_speed = tonga_get_current_pcie_speed(hwmgr); + for (i = 0; i < pcie_table->count; i++) { + if (pcie_speed != pcie_table->dpm_levels[i].value) + continue; + break; + } + now = i; + + for (i = 0; i < pcie_table->count; i++) + size += sprintf(buf + size, "%d: %s %s\n", i, + (pcie_table->dpm_levels[i].value == 0) ? "2.5GB, x8" : + (pcie_table->dpm_levels[i].value == 1) ? "5.0GB, x16" : + (pcie_table->dpm_levels[i].value == 2) ? "8.0GB, x16" : "", + (i == now) ? "*" : ""); + break; + default: + break; + } + return size; +} + static const struct pp_hwmgr_func tonga_hwmgr_funcs = { .backend_init = &tonga_hwmgr_backend_init, .backend_fini = &tonga_hwmgr_backend_fini, @@ -6070,6 +6191,10 @@ static const struct pp_hwmgr_func tonga_hwmgr_funcs = { .check_states_equal = tonga_check_states_equal, .set_fan_control_mode = tonga_set_fan_control_mode, .get_fan_control_mode = tonga_get_fan_control_mode, + .get_pp_table = tonga_get_pp_table, + .set_pp_table = tonga_set_pp_table, + .force_clock_level = tonga_force_clock_level, + .print_clock_levels = tonga_print_clock_levels, }; int tonga_hwmgr_init(struct pp_hwmgr *hwmgr) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.h index 49168d262ccc..f88d3bbe6671 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.h @@ -28,6 +28,7 @@ #include "ppatomctrl.h" #include "ppinterrupt.h" #include "tonga_powertune.h" +#include "pp_endian.h" #define TONGA_MAX_HARDWARE_POWERLEVELS 2 #define TONGA_DYNCLK_NUMBER_OF_TREND_COEFFICIENTS 15 @@ -386,17 +387,6 @@ typedef struct tonga_hwmgr tonga_hwmgr; #define TONGA_UNUSED_GPIO_PIN 0x7F -#define PP_HOST_TO_SMC_UL(X) cpu_to_be32(X) -#define PP_SMC_TO_HOST_UL(X) be32_to_cpu(X) - -#define PP_HOST_TO_SMC_US(X) cpu_to_be16(X) -#define PP_SMC_TO_HOST_US(X) be16_to_cpu(X) - -#define CONVERT_FROM_HOST_TO_SMC_UL(X) ((X) = PP_HOST_TO_SMC_UL(X)) -#define CONVERT_FROM_SMC_TO_HOST_UL(X) ((X) = PP_SMC_TO_HOST_UL(X)) - -#define CONVERT_FROM_HOST_TO_SMC_US(X) ((X) = PP_HOST_TO_SMC_US(X)) - int tonga_hwmgr_init(struct pp_hwmgr *hwmgr); int tonga_update_vce_dpm(struct pp_hwmgr *hwmgr, const void *input); int tonga_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate); diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_processpptables.c b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_processpptables.c index 34f4bef3691f..b156481b50e8 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_processpptables.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_processpptables.c @@ -512,8 +512,10 @@ static int get_cac_tdp_table( hwmgr->dyn_state.cac_dtp_table = kzalloc(table_size, GFP_KERNEL); - if (NULL == hwmgr->dyn_state.cac_dtp_table) + if (NULL == hwmgr->dyn_state.cac_dtp_table) { + kfree(tdp_table); return -ENOMEM; + } memset(hwmgr->dyn_state.cac_dtp_table, 0x00, table_size); diff --git a/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h b/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h index e61a3e67852e..7255f7ddf93a 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h +++ b/drivers/gpu/drm/amd/powerplay/inc/amd_powerplay.h @@ -29,6 +29,7 @@ #include "amd_shared.h" #include "cgs_common.h" + enum amd_pp_event { AMD_PP_EVENT_INITIALIZE = 0, AMD_PP_EVENT_UNINITIALIZE, @@ -123,6 +124,7 @@ enum amd_dpm_forced_level { AMD_DPM_FORCED_LEVEL_AUTO = 0, AMD_DPM_FORCED_LEVEL_LOW = 1, AMD_DPM_FORCED_LEVEL_HIGH = 2, + AMD_DPM_FORCED_LEVEL_MANUAL = 3, }; struct amd_pp_init { @@ -212,12 +214,55 @@ struct amd_pp_display_configuration { uint32_t dce_tolerable_mclk_in_active_latency; }; -struct amd_pp_dal_clock_info { +struct amd_pp_simple_clock_info { uint32_t engine_max_clock; uint32_t memory_max_clock; uint32_t level; }; +enum PP_DAL_POWERLEVEL { + PP_DAL_POWERLEVEL_INVALID = 0, + PP_DAL_POWERLEVEL_ULTRALOW, + PP_DAL_POWERLEVEL_LOW, + PP_DAL_POWERLEVEL_NOMINAL, + PP_DAL_POWERLEVEL_PERFORMANCE, + + PP_DAL_POWERLEVEL_0 = PP_DAL_POWERLEVEL_ULTRALOW, + PP_DAL_POWERLEVEL_1 = PP_DAL_POWERLEVEL_LOW, + PP_DAL_POWERLEVEL_2 = PP_DAL_POWERLEVEL_NOMINAL, + PP_DAL_POWERLEVEL_3 = PP_DAL_POWERLEVEL_PERFORMANCE, + PP_DAL_POWERLEVEL_4 = PP_DAL_POWERLEVEL_3+1, + PP_DAL_POWERLEVEL_5 = PP_DAL_POWERLEVEL_4+1, + PP_DAL_POWERLEVEL_6 = PP_DAL_POWERLEVEL_5+1, + PP_DAL_POWERLEVEL_7 = PP_DAL_POWERLEVEL_6+1, +}; + +struct amd_pp_clock_info { + uint32_t min_engine_clock; + uint32_t max_engine_clock; + uint32_t min_memory_clock; + uint32_t max_memory_clock; + uint32_t min_bus_bandwidth; + uint32_t max_bus_bandwidth; + uint32_t max_engine_clock_in_sr; + uint32_t min_engine_clock_in_sr; + enum PP_DAL_POWERLEVEL max_clocks_state; +}; + +enum amd_pp_clock_type { + amd_pp_disp_clock = 1, + amd_pp_sys_clock, + amd_pp_mem_clock +}; + +#define MAX_NUM_CLOCKS 16 + +struct amd_pp_clocks { + uint32_t count; + uint32_t clock[MAX_NUM_CLOCKS]; +}; + + enum { PP_GROUP_UNKNOWN = 0, PP_GROUP_GFX = 1, @@ -225,6 +270,17 @@ enum { PP_GROUP_MAX }; +enum pp_clock_type { + PP_SCLK, + PP_MCLK, + PP_PCIE, +}; + +struct pp_states_info { + uint32_t nums; + uint32_t states[16]; +}; + #define PP_GROUP_MASK 0xF0000000 #define PP_GROUP_SHIFT 28 @@ -278,6 +334,11 @@ struct amd_powerplay_funcs { int (*get_fan_control_mode)(void *handle); int (*set_fan_speed_percent)(void *handle, uint32_t percent); int (*get_fan_speed_percent)(void *handle, uint32_t *speed); + int (*get_pp_num_states)(void *handle, struct pp_states_info *data); + int (*get_pp_table)(void *handle, char **table); + int (*set_pp_table)(void *handle, const char *buf, size_t size); + int (*force_clock_level)(void *handle, enum pp_clock_type type, int level); + int (*print_clock_levels)(void *handle, enum pp_clock_type type, char *buf); }; struct amd_powerplay { @@ -288,12 +349,23 @@ struct amd_powerplay { int amd_powerplay_init(struct amd_pp_init *pp_init, struct amd_powerplay *amd_pp); + int amd_powerplay_fini(void *handle); -int amd_powerplay_display_configuration_change(void *handle, const void *input); +int amd_powerplay_display_configuration_change(void *handle, + const struct amd_pp_display_configuration *input); int amd_powerplay_get_display_power_level(void *handle, - struct amd_pp_dal_clock_info *output); + struct amd_pp_simple_clock_info *output); + +int amd_powerplay_get_current_clocks(void *handle, + struct amd_pp_clock_info *output); + +int amd_powerplay_get_clock_by_type(void *handle, + enum amd_pp_clock_type type, + struct amd_pp_clocks *clocks); +int amd_powerplay_get_display_mode_validation_clocks(void *handle, + struct amd_pp_simple_clock_info *output); #endif /* _AMD_POWERPLAY_H_ */ diff --git a/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h b/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h index 91795efe1336..040d3f7cbf49 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hardwaremanager.h @@ -31,6 +31,7 @@ struct pp_power_state; enum amd_dpm_forced_level; struct PP_TemperatureRange; + struct phm_fan_speed_info { uint32_t min_percent; uint32_t max_percent; @@ -290,6 +291,15 @@ struct PP_Clocks { uint32_t engineClockInSR; }; +struct pp_clock_info { + uint32_t min_mem_clk; + uint32_t max_mem_clk; + uint32_t min_eng_clk; + uint32_t max_eng_clk; + uint32_t min_bus_bandwidth; + uint32_t max_bus_bandwidth; +}; + struct phm_platform_descriptor { uint32_t platformCaps[PHM_MAX_NUM_CAPS_ULONG_ENTRIES]; uint32_t vbiosInterruptId; @@ -323,24 +333,6 @@ struct phm_clocks { uint32_t clock[MAX_NUM_CLOCKS]; }; -enum PP_DAL_POWERLEVEL { - PP_DAL_POWERLEVEL_INVALID = 0, - PP_DAL_POWERLEVEL_ULTRALOW, - PP_DAL_POWERLEVEL_LOW, - PP_DAL_POWERLEVEL_NOMINAL, - PP_DAL_POWERLEVEL_PERFORMANCE, - - PP_DAL_POWERLEVEL_0 = PP_DAL_POWERLEVEL_ULTRALOW, - PP_DAL_POWERLEVEL_1 = PP_DAL_POWERLEVEL_LOW, - PP_DAL_POWERLEVEL_2 = PP_DAL_POWERLEVEL_NOMINAL, - PP_DAL_POWERLEVEL_3 = PP_DAL_POWERLEVEL_PERFORMANCE, - PP_DAL_POWERLEVEL_4 = PP_DAL_POWERLEVEL_3+1, - PP_DAL_POWERLEVEL_5 = PP_DAL_POWERLEVEL_4+1, - PP_DAL_POWERLEVEL_6 = PP_DAL_POWERLEVEL_5+1, - PP_DAL_POWERLEVEL_7 = PP_DAL_POWERLEVEL_6+1, -}; - - extern int phm_enable_clock_power_gatings(struct pp_hwmgr *hwmgr); extern int phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool gate); extern int phm_powergate_vce(struct pp_hwmgr *hwmgr, bool gate); @@ -375,11 +367,25 @@ extern int phm_store_dal_configuration_data(struct pp_hwmgr *hwmgr, const struct amd_pp_display_configuration *display_config); extern int phm_get_dal_power_level(struct pp_hwmgr *hwmgr, - struct amd_pp_dal_clock_info*info); + struct amd_pp_simple_clock_info *info); extern int phm_set_cpu_power_state(struct pp_hwmgr *hwmgr); extern int phm_power_down_asic(struct pp_hwmgr *hwmgr); +extern int phm_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state, + PHM_PerformanceLevelDesignation designation, uint32_t index, + PHM_PerformanceLevel *level); + +extern int phm_get_clock_info(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state, + struct pp_clock_info *pclock_info, + PHM_PerformanceLevelDesignation designation); + +extern int phm_get_current_shallow_sleep_clocks(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state, struct pp_clock_info *clock_info); + +extern int phm_get_clock_by_type(struct pp_hwmgr *hwmgr, enum amd_pp_clock_type type, struct amd_pp_clocks *clocks); + +extern int phm_get_max_high_clocks(struct pp_hwmgr *hwmgr, struct amd_pp_simple_clock_info *clocks); + #endif /* _HARDWARE_MANAGER_H_ */ diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h index aeaa3dbba525..928f5a740cba 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h @@ -325,8 +325,18 @@ struct pp_hwmgr_func { bool cc6_disable, bool pstate_disable, bool pstate_switch_disable); int (*get_dal_power_level)(struct pp_hwmgr *hwmgr, - struct amd_pp_dal_clock_info *info); + struct amd_pp_simple_clock_info *info); + int (*get_performance_level)(struct pp_hwmgr *, const struct pp_hw_power_state *, + PHM_PerformanceLevelDesignation, uint32_t, PHM_PerformanceLevel *); + int (*get_current_shallow_sleep_clocks)(struct pp_hwmgr *hwmgr, + const struct pp_hw_power_state *state, struct pp_clock_info *clock_info); + int (*get_clock_by_type)(struct pp_hwmgr *hwmgr, enum amd_pp_clock_type type, struct amd_pp_clocks *clocks); + int (*get_max_high_clocks)(struct pp_hwmgr *hwmgr, struct amd_pp_simple_clock_info *clocks); int (*power_off_asic)(struct pp_hwmgr *hwmgr); + int (*get_pp_table)(struct pp_hwmgr *hwmgr, char **table); + int (*set_pp_table)(struct pp_hwmgr *hwmgr, const char *buf, size_t size); + int (*force_clock_level)(struct pp_hwmgr *hwmgr, enum pp_clock_type type, int level); + int (*print_clock_levels)(struct pp_hwmgr *hwmgr, enum pp_clock_type type, char *buf); }; struct pp_table_func { diff --git a/drivers/gpu/drm/amd/powerplay/inc/pp_endian.h b/drivers/gpu/drm/amd/powerplay/inc/pp_endian.h new file mode 100644 index 000000000000..f49d1963fe85 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/inc/pp_endian.h @@ -0,0 +1,38 @@ +/* + * 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. + * + */ + +#ifndef _PP_ENDIAN_H_ +#define _PP_ENDIAN_H_ + +#define PP_HOST_TO_SMC_UL(X) cpu_to_be32(X) +#define PP_SMC_TO_HOST_UL(X) be32_to_cpu(X) + +#define PP_HOST_TO_SMC_US(X) cpu_to_be16(X) +#define PP_SMC_TO_HOST_US(X) be16_to_cpu(X) + +#define CONVERT_FROM_HOST_TO_SMC_UL(X) ((X) = PP_HOST_TO_SMC_UL(X)) +#define CONVERT_FROM_SMC_TO_HOST_UL(X) ((X) = PP_SMC_TO_HOST_UL(X)) + +#define CONVERT_FROM_HOST_TO_SMC_US(X) ((X) = PP_HOST_TO_SMC_US(X)) + +#endif /* _PP_ENDIAN_H_ */ diff --git a/drivers/gpu/drm/amd/powerplay/inc/smumgr.h b/drivers/gpu/drm/amd/powerplay/inc/smumgr.h index 504f035d1843..fc9e3d1dd409 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/smumgr.h @@ -32,6 +32,27 @@ struct pp_instance; #define smu_lower_32_bits(n) ((uint32_t)(n)) #define smu_upper_32_bits(n) ((uint32_t)(((n)>>16)>>16)) +enum AVFS_BTC_STATUS { + AVFS_BTC_BOOT = 0, + AVFS_BTC_BOOT_STARTEDSMU, + AVFS_LOAD_VIRUS, + AVFS_BTC_VIRUS_LOADED, + AVFS_BTC_VIRUS_FAIL, + AVFS_BTC_COMPLETED_PREVIOUSLY, + AVFS_BTC_ENABLEAVFS, + AVFS_BTC_STARTED, + AVFS_BTC_FAILED, + AVFS_BTC_RESTOREVFT_FAILED, + AVFS_BTC_SAVEVFT_FAILED, + AVFS_BTC_DPMTABLESETUP_FAILED, + AVFS_BTC_COMPLETED_UNSAVED, + AVFS_BTC_COMPLETED_SAVED, + AVFS_BTC_COMPLETED_RESTORED, + AVFS_BTC_DISABLED, + AVFS_BTC_NOTSUPPORTED, + AVFS_BTC_SMUMSG_ERROR +}; + struct pp_smumgr_func { int (*smu_init)(struct pp_smumgr *smumgr); int (*smu_fini)(struct pp_smumgr *smumgr); diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.h index 8cd22d9c9140..b4eb483215b1 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.h @@ -23,24 +23,6 @@ #ifndef _FIJI_SMUMANAGER_H_ #define _FIJI_SMUMANAGER_H_ -enum AVFS_BTC_STATUS { - AVFS_BTC_BOOT = 0, - AVFS_BTC_BOOT_STARTEDSMU, - AVFS_LOAD_VIRUS, - AVFS_BTC_VIRUS_LOADED, - AVFS_BTC_VIRUS_FAIL, - AVFS_BTC_STARTED, - AVFS_BTC_FAILED, - AVFS_BTC_RESTOREVFT_FAILED, - AVFS_BTC_SAVEVFT_FAILED, - AVFS_BTC_DPMTABLESETUP_FAILED, - AVFS_BTC_COMPLETED_UNSAVED, - AVFS_BTC_COMPLETED_SAVED, - AVFS_BTC_COMPLETED_RESTORED, - AVFS_BTC_DISABLED, - AVFS_BTC_NOTSUPPORTED, - AVFS_BTC_SMUMSG_ERROR -}; struct fiji_smu_avfs { enum AVFS_BTC_STATUS AvfsBtcStatus; |