Change-Id: Ib7414e1afc49d7b313188349b396aeac3a5054b7 Signed-off-by: Rex Zhu <Rex.Zhu at amd.com> --- drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 121 ++++++++++++++++++++++- 1 file changed, 120 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index 4ccc910..0d14299 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -4808,6 +4808,125 @@ static int smu7_get_thermal_temperature_range(struct pp_hwmgr *hwmgr, return 0; } +static bool smu7_check_clk_voltage_valid(struct pp_hwmgr *hwmgr, + enum PP_ODN_DPM_TABLE_TYPE type, + uint32_t clk, + uint32_t voltage) +{ + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + + if (hwmgr->dyn_state.max_clock_voltage_on_ac.vddc * 120 / 100 < voltage) + return false; + + if (type == PP_ODN_SCLK_VDDC_TABLE) { + if (data->vbios_boot_state.sclk_bootup_value > clk || + hwmgr->dyn_state.max_clock_voltage_on_ac.sclk * 120 / 100 < clk) + return false; + } else if (type == PP_ODN_MCLK_VDDC_TABLE) { + if (data->vbios_boot_state.mclk_bootup_value > clk || + hwmgr->dyn_state.max_clock_voltage_on_ac.mclk * 120 / 100 < clk) + return false; + } else { + return false; + } + + return true; +} + +static void smu7_check_vddc_updated(struct pp_hwmgr *hwmgr, + struct phm_ppt_v1_clock_voltage_dependency_table *dep_table, + struct smu7_odn_clock_voltage_dependency_table *odn_vdd_dep) +{ + int i; + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + + if (dep_table->count == 0) + return; + + for (i = 0; i < dep_table->count; i++) { + if (dep_table->entries[i].vddc != odn_vdd_dep->entries[i].vddc) { + data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_VDDC; + return; + } + } +} + +static int smu7_odn_edit_dpm_table(struct pp_hwmgr *hwmgr, + enum PP_ODN_DPM_TABLE_TYPE type, + long *input, uint32_t size) +{ + uint32_t i; + phm_ppt_v1_clock_voltage_dependency_table *pgolden_vdd_dep_table = NULL; + struct phm_odn_clock_levels *podn_dpm_table_in_backend = NULL; + struct smu7_odn_clock_voltage_dependency_table *podn_vdd_dep_in_backend = NULL; + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + struct phm_ppt_v1_information *table_info = + (struct phm_ppt_v1_information *)hwmgr->pptable; + uint32_t input_clk; + uint32_t input_vol; + uint32_t input_level; + + PP_ASSERT_WITH_CODE(input, "NULL user input for clock and voltage", + return -EINVAL); + + if (PP_ODN_SCLK_VDDC_TABLE == type) { + podn_dpm_table_in_backend = &data->odn_dpm_table.odn_core_clock_dpm_levels; + podn_vdd_dep_in_backend = &data->odn_dpm_table.vdd_dependency_on_sclk; + PP_ASSERT_WITH_CODE((podn_dpm_table_in_backend && podn_vdd_dep_in_backend), + "Failed to get ODN SCLK and Voltage tables", + return -EINVAL); + data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_SCLK; + } else if (PP_ODN_MCLK_VDDC_TABLE == type) { + podn_dpm_table_in_backend = &data->odn_dpm_table.odn_memory_clock_dpm_levels; + podn_vdd_dep_in_backend = &data->odn_dpm_table.vdd_dependency_on_mclk; + + PP_ASSERT_WITH_CODE((podn_dpm_table_in_backend && podn_vdd_dep_in_backend), + "Failed to get ODN MCLK and Voltage tables", + return -EINVAL); + data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_MCLK; + } else if (PP_ODN_RESET_DEFAULT_TABLE == type) { + smu7_odn_initial_default_setting(hwmgr); + data->need_update_smu7_dpm_table = DPMTABLE_OD_UPDATE_SCLK | DPMTABLE_OD_UPDATE_MCLK; + return 0; + } else { + return -EINVAL; + } + + for (i = 0; i < size; i += 3) { + if (i + 3 > size || input[i] >= podn_dpm_table_in_backend->num_of_pl) { + pr_info("invalid clock voltage input \n"); + return 0; + } + input_level = input[i]; + input_clk = input[i+1] * 100; + input_vol = input[i+2]; + + if (smu7_check_clk_voltage_valid(hwmgr, type, input_clk, input_vol)) { + podn_dpm_table_in_backend->entries[input_level].clock = input_clk; + podn_vdd_dep_in_backend->entries[input_level].clk = input_clk; + podn_dpm_table_in_backend->entries[input_level].vddc = input_vol; + podn_vdd_dep_in_backend->entries[input_level].vddc = input_vol; + } else { + pr_info("invaid input clk/voltage"); + } + } + + if (hwmgr->pp_table_version == PP_TABLE_V1) + pgolden_vdd_dep_table = PP_ODN_MCLK_VDDC_TABLE == type ? + table_info->vdd_dep_on_mclk: + table_info->vdd_dep_on_sclk; + + PP_ASSERT_WITH_CODE(pgolden_vdd_dep_table + && pgolden_vdd_dep_table->count > 0, + "Invalid golden_vdd_dep_table", + return -EINVAL); + + smu7_check_vddc_updated(hwmgr, pgolden_vdd_dep_table, podn_vdd_dep_in_backend); + + return 0; +} + + static const struct pp_hwmgr_func smu7_hwmgr_funcs = { .backend_init = &smu7_hwmgr_backend_init, .backend_fini = &smu7_hwmgr_backend_fini, @@ -4862,6 +4981,7 @@ static int smu7_get_thermal_temperature_range(struct pp_hwmgr *hwmgr, .notify_cac_buffer_info = smu7_notify_cac_buffer_info, .get_max_high_clocks = smu7_get_max_high_clocks, .get_thermal_temperature_range = smu7_get_thermal_temperature_range, + .odn_edit_dpm_table = smu7_odn_edit_dpm_table, }; uint8_t smu7_get_sleep_divider_id_from_clock(uint32_t clock, @@ -4893,4 +5013,3 @@ int smu7_init_function_pointers(struct pp_hwmgr *hwmgr) return ret; } - -- 1.9.1