diff options
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/3797-drm-amd-pp-Replace-rv_-with-smu10_.patch')
-rw-r--r-- | meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/3797-drm-amd-pp-Replace-rv_-with-smu10_.patch | 3770 |
1 files changed, 3770 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/3797-drm-amd-pp-Replace-rv_-with-smu10_.patch b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/3797-drm-amd-pp-Replace-rv_-with-smu10_.patch new file mode 100644 index 00000000..169741c1 --- /dev/null +++ b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/3797-drm-amd-pp-Replace-rv_-with-smu10_.patch @@ -0,0 +1,3770 @@ +From 92c3fc499b8caa2bd1a8a5322d8edc4d8dce6cd6 Mon Sep 17 00:00:00 2001 +From: Rex Zhu <Rex.Zhu@amd.com> +Date: Tue, 6 Mar 2018 17:28:38 +0800 +Subject: [PATCH 3797/4131] drm/amd/pp: Replace rv_* with smu10_* + +Powerplay is for the hw ip smu, for RV, smu10 is used, +so use smu10 as the prefix of the files name/function name. + +Change-Id: Ib47ab34a7e7870a61ebde2e18105b4222fc91e49 +Reviewed-by: Alex Deucher <alexander.deucher@amd.com> +Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> +Signed-off-by: Kalyan Alle <kalyan.alle@amd.com> +--- + drivers/gpu/drm/amd/powerplay/hwmgr/Makefile | 2 +- + drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c | 6 +- + drivers/gpu/drm/amd/powerplay/hwmgr/rv_hwmgr.c | 1043 -------------------- + drivers/gpu/drm/amd/powerplay/hwmgr/rv_hwmgr.h | 320 ------ + drivers/gpu/drm/amd/powerplay/hwmgr/rv_inc.h | 43 - + drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c | 1042 +++++++++++++++++++ + drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.h | 322 ++++++ + drivers/gpu/drm/amd/powerplay/hwmgr/smu10_inc.h | 43 + + drivers/gpu/drm/amd/powerplay/inc/hwmgr.h | 2 +- + drivers/gpu/drm/amd/powerplay/smumgr/Makefile | 2 +- + drivers/gpu/drm/amd/powerplay/smumgr/rv_smumgr.c | 346 ------- + drivers/gpu/drm/amd/powerplay/smumgr/rv_smumgr.h | 50 - + .../gpu/drm/amd/powerplay/smumgr/smu10_smumgr.c | 346 +++++++ + .../gpu/drm/amd/powerplay/smumgr/smu10_smumgr.h | 50 + + 14 files changed, 1809 insertions(+), 1808 deletions(-) + delete mode 100644 drivers/gpu/drm/amd/powerplay/hwmgr/rv_hwmgr.c + delete mode 100644 drivers/gpu/drm/amd/powerplay/hwmgr/rv_hwmgr.h + delete mode 100644 drivers/gpu/drm/amd/powerplay/hwmgr/rv_inc.h + create mode 100644 drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c + create mode 100644 drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.h + create mode 100644 drivers/gpu/drm/amd/powerplay/hwmgr/smu10_inc.h + delete mode 100644 drivers/gpu/drm/amd/powerplay/smumgr/rv_smumgr.c + delete mode 100644 drivers/gpu/drm/amd/powerplay/smumgr/rv_smumgr.h + create mode 100644 drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.c + create mode 100644 drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.h + +diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile b/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile +index aa150c9..efbdd3e 100644 +--- a/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile ++++ b/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile +@@ -10,7 +10,7 @@ HARDWARE_MGR = hwmgr.o processpptables.o \ + smu7_hwmgr.o smu7_powertune.o smu7_thermal.o \ + smu7_clockpowergating.o \ + vega10_processpptables.o vega10_hwmgr.o vega10_powertune.o \ +- vega10_thermal.o rv_hwmgr.o pp_psm.o\ ++ vega10_thermal.o smu10_hwmgr.o pp_psm.o\ + pp_overdriver.o + + AMD_PP_HWMGR = $(addprefix $(AMD_PP_PATH)/hwmgr/,$(HARDWARE_MGR)) +diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c +index af1b22d..3432dc0 100644 +--- a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c ++++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c +@@ -43,7 +43,7 @@ extern const struct pp_smumgr_func tonga_smu_funcs; + extern const struct pp_smumgr_func fiji_smu_funcs; + extern const struct pp_smumgr_func polaris10_smu_funcs; + extern const struct pp_smumgr_func vega10_smu_funcs; +-extern const struct pp_smumgr_func rv_smu_funcs; ++extern const struct pp_smumgr_func smu10_smu_funcs; + + extern int cz_init_function_pointers(struct pp_hwmgr *hwmgr); + static int polaris_set_asic_special_caps(struct pp_hwmgr *hwmgr); +@@ -230,8 +230,8 @@ int hwmgr_early_init(struct pp_instance *handle) + switch (hwmgr->chip_id) { + case CHIP_RAVEN: + hwmgr->od_enabled = false; +- hwmgr->smumgr_funcs = &rv_smu_funcs; +- rv_init_function_pointers(hwmgr); ++ hwmgr->smumgr_funcs = &smu10_smu_funcs; ++ smu10_init_function_pointers(hwmgr); + break; + default: + return -EINVAL; +diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/rv_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/rv_hwmgr.c +deleted file mode 100644 +index f314591..0000000 +--- a/drivers/gpu/drm/amd/powerplay/hwmgr/rv_hwmgr.c ++++ /dev/null +@@ -1,1043 +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 "pp_debug.h" +-#include <linux/types.h> +-#include <linux/kernel.h> +-#include <linux/slab.h> +-#include "atom-types.h" +-#include "atombios.h" +-#include "processpptables.h" +-#include "cgs_common.h" +-#include "smumgr.h" +-#include "hwmgr.h" +-#include "hardwaremanager.h" +-#include "rv_ppsmc.h" +-#include "rv_hwmgr.h" +-#include "power_state.h" +-#include "pp_soc15.h" +- +-#define RAVEN_MAX_DEEPSLEEP_DIVIDER_ID 5 +-#define RAVEN_MINIMUM_ENGINE_CLOCK 800 /* 8Mhz, the low boundary of engine clock allowed on this chip */ +-#define SCLK_MIN_DIV_INTV_SHIFT 12 +-#define RAVEN_DISPCLK_BYPASS_THRESHOLD 10000 /* 100Mhz */ +-#define SMC_RAM_END 0x40000 +- +-static const unsigned long PhwRaven_Magic = (unsigned long) PHM_Rv_Magic; +- +- +-int rv_display_clock_voltage_request(struct pp_hwmgr *hwmgr, +- struct pp_display_clock_request *clock_req); +- +- +-static struct rv_power_state *cast_rv_ps(struct pp_hw_power_state *hw_ps) +-{ +- if (PhwRaven_Magic != hw_ps->magic) +- return NULL; +- +- return (struct rv_power_state *)hw_ps; +-} +- +-static const struct rv_power_state *cast_const_rv_ps( +- const struct pp_hw_power_state *hw_ps) +-{ +- if (PhwRaven_Magic != hw_ps->magic) +- return NULL; +- +- return (struct rv_power_state *)hw_ps; +-} +- +-static int rv_initialize_dpm_defaults(struct pp_hwmgr *hwmgr) +-{ +- struct rv_hwmgr *rv_hwmgr = (struct rv_hwmgr *)(hwmgr->backend); +- +- rv_hwmgr->dce_slow_sclk_threshold = 30000; +- rv_hwmgr->thermal_auto_throttling_treshold = 0; +- rv_hwmgr->is_nb_dpm_enabled = 1; +- rv_hwmgr->dpm_flags = 1; +- rv_hwmgr->gfx_off_controled_by_driver = false; +- rv_hwmgr->need_min_deep_sleep_dcefclk = true; +- rv_hwmgr->num_active_display = 0; +- rv_hwmgr->deep_sleep_dcefclk = 0; +- +- phm_cap_unset(hwmgr->platform_descriptor.platformCaps, +- PHM_PlatformCaps_SclkDeepSleep); +- +- phm_cap_unset(hwmgr->platform_descriptor.platformCaps, +- PHM_PlatformCaps_SclkThrottleLowNotification); +- +- phm_cap_set(hwmgr->platform_descriptor.platformCaps, +- PHM_PlatformCaps_PowerPlaySupport); +- return 0; +-} +- +-static int rv_construct_max_power_limits_table(struct pp_hwmgr *hwmgr, +- struct phm_clock_and_voltage_limits *table) +-{ +- return 0; +-} +- +-static int rv_init_dynamic_state_adjustment_rule_settings( +- struct pp_hwmgr *hwmgr) +-{ +- uint32_t table_size = +- sizeof(struct phm_clock_voltage_dependency_table) + +- (7 * sizeof(struct phm_clock_voltage_dependency_record)); +- +- struct phm_clock_voltage_dependency_table *table_clk_vlt = +- kzalloc(table_size, GFP_KERNEL); +- +- if (NULL == table_clk_vlt) { +- pr_err("Can not allocate memory!\n"); +- return -ENOMEM; +- } +- +- table_clk_vlt->count = 8; +- table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_0; +- table_clk_vlt->entries[0].v = 0; +- table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_1; +- table_clk_vlt->entries[1].v = 1; +- table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_2; +- table_clk_vlt->entries[2].v = 2; +- table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_3; +- table_clk_vlt->entries[3].v = 3; +- table_clk_vlt->entries[4].clk = PP_DAL_POWERLEVEL_4; +- table_clk_vlt->entries[4].v = 4; +- table_clk_vlt->entries[5].clk = PP_DAL_POWERLEVEL_5; +- table_clk_vlt->entries[5].v = 5; +- table_clk_vlt->entries[6].clk = PP_DAL_POWERLEVEL_6; +- table_clk_vlt->entries[6].v = 6; +- table_clk_vlt->entries[7].clk = PP_DAL_POWERLEVEL_7; +- table_clk_vlt->entries[7].v = 7; +- hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt; +- +- return 0; +-} +- +-static int rv_get_system_info_data(struct pp_hwmgr *hwmgr) +-{ +- struct rv_hwmgr *rv_data = (struct rv_hwmgr *)hwmgr->backend; +- +- rv_data->sys_info.htc_hyst_lmt = 5; +- rv_data->sys_info.htc_tmp_lmt = 203; +- +- if (rv_data->thermal_auto_throttling_treshold == 0) +- rv_data->thermal_auto_throttling_treshold = 203; +- +- rv_construct_max_power_limits_table (hwmgr, +- &hwmgr->dyn_state.max_clock_voltage_on_ac); +- +- rv_init_dynamic_state_adjustment_rule_settings(hwmgr); +- +- return 0; +-} +- +-static int rv_construct_boot_state(struct pp_hwmgr *hwmgr) +-{ +- return 0; +-} +- +-static int rv_set_clock_limit(struct pp_hwmgr *hwmgr, const void *input) +-{ +- struct PP_Clocks clocks = {0}; +- struct pp_display_clock_request clock_req; +- +- clocks.dcefClock = hwmgr->display_config.min_dcef_set_clk; +- clock_req.clock_type = amd_pp_dcf_clock; +- clock_req.clock_freq_in_khz = clocks.dcefClock * 10; +- +- PP_ASSERT_WITH_CODE(!rv_display_clock_voltage_request(hwmgr, &clock_req), +- "Attempt to set DCF Clock Failed!", return -EINVAL); +- +- return 0; +-} +- +-static int rv_set_deep_sleep_dcefclk(struct pp_hwmgr *hwmgr, uint32_t clock) +-{ +- struct rv_hwmgr *rv_data = (struct rv_hwmgr *)(hwmgr->backend); +- +- if (rv_data->need_min_deep_sleep_dcefclk && rv_data->deep_sleep_dcefclk != clock/100) { +- rv_data->deep_sleep_dcefclk = clock/100; +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetMinDeepSleepDcefclk, +- rv_data->deep_sleep_dcefclk); +- } +- +- return 0; +-} +- +-static int rv_set_active_display_count(struct pp_hwmgr *hwmgr, uint32_t count) +-{ +- struct rv_hwmgr *rv_data = (struct rv_hwmgr *)(hwmgr->backend); +- +- if (rv_data->num_active_display != count) { +- rv_data->num_active_display = count; +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetDisplayCount, +- rv_data->num_active_display); +- } +- +- return 0; +-} +- +-static int rv_set_power_state_tasks(struct pp_hwmgr *hwmgr, const void *input) +-{ +- return rv_set_clock_limit(hwmgr, input); +-} +- +-static int rv_init_power_gate_state(struct pp_hwmgr *hwmgr) +-{ +- struct rv_hwmgr *rv_data = (struct rv_hwmgr *)(hwmgr->backend); +- +- rv_data->vcn_power_gated = true; +- rv_data->isp_tileA_power_gated = true; +- rv_data->isp_tileB_power_gated = true; +- +- return 0; +-} +- +- +-static int rv_setup_asic_task(struct pp_hwmgr *hwmgr) +-{ +- return rv_init_power_gate_state(hwmgr); +-} +- +-static int rv_reset_cc6_data(struct pp_hwmgr *hwmgr) +-{ +- struct rv_hwmgr *rv_data = (struct rv_hwmgr *)(hwmgr->backend); +- +- rv_data->separation_time = 0; +- rv_data->cc6_disable = false; +- rv_data->pstate_disable = false; +- rv_data->cc6_setting_changed = false; +- +- return 0; +-} +- +-static int rv_power_off_asic(struct pp_hwmgr *hwmgr) +-{ +- return rv_reset_cc6_data(hwmgr); +-} +- +-static int rv_disable_gfx_off(struct pp_hwmgr *hwmgr) +-{ +- struct rv_hwmgr *rv_data = (struct rv_hwmgr *)(hwmgr->backend); +- +- if (rv_data->gfx_off_controled_by_driver) +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_DisableGfxOff); +- +- return 0; +-} +- +-static int rv_disable_dpm_tasks(struct pp_hwmgr *hwmgr) +-{ +- return rv_disable_gfx_off(hwmgr); +-} +- +-static int rv_enable_gfx_off(struct pp_hwmgr *hwmgr) +-{ +- struct rv_hwmgr *rv_data = (struct rv_hwmgr *)(hwmgr->backend); +- +- if (rv_data->gfx_off_controled_by_driver) +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_EnableGfxOff); +- +- return 0; +-} +- +-static int rv_enable_dpm_tasks(struct pp_hwmgr *hwmgr) +-{ +- return rv_enable_gfx_off(hwmgr); +-} +- +-static int rv_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, +- struct pp_power_state *prequest_ps, +- const struct pp_power_state *pcurrent_ps) +-{ +- return 0; +-} +- +-/* temporary hardcoded clock voltage breakdown tables */ +-static const DpmClock_t VddDcfClk[]= { +- { 300, 2600}, +- { 600, 3200}, +- { 600, 3600}, +-}; +- +-static const DpmClock_t VddSocClk[]= { +- { 478, 2600}, +- { 722, 3200}, +- { 722, 3600}, +-}; +- +-static const DpmClock_t VddFClk[]= { +- { 400, 2600}, +- {1200, 3200}, +- {1200, 3600}, +-}; +- +-static const DpmClock_t VddDispClk[]= { +- { 435, 2600}, +- { 661, 3200}, +- {1086, 3600}, +-}; +- +-static const DpmClock_t VddDppClk[]= { +- { 435, 2600}, +- { 661, 3200}, +- { 661, 3600}, +-}; +- +-static const DpmClock_t VddPhyClk[]= { +- { 540, 2600}, +- { 810, 3200}, +- { 810, 3600}, +-}; +- +-static int rv_get_clock_voltage_dependency_table(struct pp_hwmgr *hwmgr, +- struct rv_voltage_dependency_table **pptable, +- uint32_t num_entry, const DpmClock_t *pclk_dependency_table) +-{ +- uint32_t table_size, i; +- struct rv_voltage_dependency_table *ptable; +- +- table_size = sizeof(uint32_t) + sizeof(struct rv_voltage_dependency_table) * num_entry; +- ptable = kzalloc(table_size, GFP_KERNEL); +- +- if (NULL == ptable) +- return -ENOMEM; +- +- ptable->count = num_entry; +- +- for (i = 0; i < ptable->count; i++) { +- ptable->entries[i].clk = pclk_dependency_table->Freq * 100; +- ptable->entries[i].vol = pclk_dependency_table->Vol; +- pclk_dependency_table++; +- } +- +- *pptable = ptable; +- +- return 0; +-} +- +-static int rv_populate_clock_table(struct pp_hwmgr *hwmgr) +-{ +- int result; +- +- struct rv_hwmgr *rv_data = (struct rv_hwmgr *)(hwmgr->backend); +- DpmClocks_t *table = &(rv_data->clock_table); +- struct rv_clock_voltage_information *pinfo = &(rv_data->clock_vol_info); +- +- result = smum_smc_table_manager(hwmgr, (uint8_t *)table, SMU10_CLOCKTABLE, true); +- +- PP_ASSERT_WITH_CODE((0 == result), +- "Attempt to copy clock table from smc failed", +- return result); +- +- if (0 == result && table->DcefClocks[0].Freq != 0) { +- rv_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_dcefclk, +- NUM_DCEFCLK_DPM_LEVELS, +- &rv_data->clock_table.DcefClocks[0]); +- rv_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_socclk, +- NUM_SOCCLK_DPM_LEVELS, +- &rv_data->clock_table.SocClocks[0]); +- rv_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_fclk, +- NUM_FCLK_DPM_LEVELS, +- &rv_data->clock_table.FClocks[0]); +- rv_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_mclk, +- NUM_MEMCLK_DPM_LEVELS, +- &rv_data->clock_table.MemClocks[0]); +- } else { +- rv_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_dcefclk, +- ARRAY_SIZE(VddDcfClk), +- &VddDcfClk[0]); +- rv_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_socclk, +- ARRAY_SIZE(VddSocClk), +- &VddSocClk[0]); +- rv_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_fclk, +- ARRAY_SIZE(VddFClk), +- &VddFClk[0]); +- } +- rv_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_dispclk, +- ARRAY_SIZE(VddDispClk), +- &VddDispClk[0]); +- rv_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_dppclk, +- ARRAY_SIZE(VddDppClk), &VddDppClk[0]); +- rv_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_phyclk, +- ARRAY_SIZE(VddPhyClk), &VddPhyClk[0]); +- +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMinGfxclkFrequency); +- result = smum_get_argument(hwmgr); +- rv_data->gfx_min_freq_limit = result * 100; +- +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxGfxclkFrequency); +- result = smum_get_argument(hwmgr); +- rv_data->gfx_max_freq_limit = result * 100; +- +- return 0; +-} +- +-static int rv_hwmgr_backend_init(struct pp_hwmgr *hwmgr) +-{ +- int result = 0; +- struct rv_hwmgr *data; +- +- data = kzalloc(sizeof(struct rv_hwmgr), GFP_KERNEL); +- if (data == NULL) +- return -ENOMEM; +- +- hwmgr->backend = data; +- +- result = rv_initialize_dpm_defaults(hwmgr); +- if (result != 0) { +- pr_err("rv_initialize_dpm_defaults failed\n"); +- return result; +- } +- +- rv_populate_clock_table(hwmgr); +- +- result = rv_get_system_info_data(hwmgr); +- if (result != 0) { +- pr_err("rv_get_system_info_data failed\n"); +- return result; +- } +- +- rv_construct_boot_state(hwmgr); +- +- hwmgr->platform_descriptor.hardwareActivityPerformanceLevels = +- RAVEN_MAX_HARDWARE_POWERLEVELS; +- +- hwmgr->platform_descriptor.hardwarePerformanceLevels = +- RAVEN_MAX_HARDWARE_POWERLEVELS; +- +- hwmgr->platform_descriptor.vbiosInterruptId = 0; +- +- hwmgr->platform_descriptor.clockStep.engineClock = 500; +- +- hwmgr->platform_descriptor.clockStep.memoryClock = 500; +- +- hwmgr->platform_descriptor.minimumClocksReductionPercentage = 50; +- +- hwmgr->pstate_sclk = RAVEN_UMD_PSTATE_GFXCLK * 100; +- hwmgr->pstate_mclk = RAVEN_UMD_PSTATE_FCLK * 100; +- +- return result; +-} +- +-static int rv_hwmgr_backend_fini(struct pp_hwmgr *hwmgr) +-{ +- struct rv_hwmgr *rv_data = (struct rv_hwmgr *)(hwmgr->backend); +- struct rv_clock_voltage_information *pinfo = &(rv_data->clock_vol_info); +- +- kfree(pinfo->vdd_dep_on_dcefclk); +- pinfo->vdd_dep_on_dcefclk = NULL; +- kfree(pinfo->vdd_dep_on_socclk); +- pinfo->vdd_dep_on_socclk = NULL; +- kfree(pinfo->vdd_dep_on_fclk); +- pinfo->vdd_dep_on_fclk = NULL; +- kfree(pinfo->vdd_dep_on_dispclk); +- pinfo->vdd_dep_on_dispclk = NULL; +- kfree(pinfo->vdd_dep_on_dppclk); +- pinfo->vdd_dep_on_dppclk = NULL; +- kfree(pinfo->vdd_dep_on_phyclk); +- pinfo->vdd_dep_on_phyclk = NULL; +- +- kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl); +- hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL; +- +- kfree(hwmgr->backend); +- hwmgr->backend = NULL; +- +- return 0; +-} +- +-static int rv_dpm_force_dpm_level(struct pp_hwmgr *hwmgr, +- enum amd_dpm_forced_level level) +-{ +- struct rv_hwmgr *data = hwmgr->backend; +- if (hwmgr->smu_version < 0x1E3700) { +- pr_info("smu firmware version too old, can not set dpm level\n"); +- return 0; +- } +- +- switch (level) { +- case AMD_DPM_FORCED_LEVEL_HIGH: +- case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetHardMinGfxClk, +- data->gfx_max_freq_limit/100); +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetHardMinFclkByFreq, +- RAVEN_UMD_PSTATE_PEAK_FCLK); +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetHardMinSocclkByFreq, +- RAVEN_UMD_PSTATE_PEAK_SOCCLK); +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetHardMinVcn, +- RAVEN_UMD_PSTATE_VCE); +- +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetSoftMaxGfxClk, +- data->gfx_max_freq_limit/100); +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetSoftMaxFclkByFreq, +- RAVEN_UMD_PSTATE_PEAK_FCLK); +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetSoftMaxSocclkByFreq, +- RAVEN_UMD_PSTATE_PEAK_SOCCLK); +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetSoftMaxVcn, +- RAVEN_UMD_PSTATE_VCE); +- break; +- case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetHardMinGfxClk, +- data->gfx_min_freq_limit/100); +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetSoftMaxGfxClk, +- data->gfx_min_freq_limit/100); +- break; +- case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetHardMinFclkByFreq, +- RAVEN_UMD_PSTATE_MIN_FCLK); +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetSoftMaxFclkByFreq, +- RAVEN_UMD_PSTATE_MIN_FCLK); +- break; +- case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetHardMinGfxClk, +- RAVEN_UMD_PSTATE_GFXCLK); +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetHardMinFclkByFreq, +- RAVEN_UMD_PSTATE_FCLK); +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetHardMinSocclkByFreq, +- RAVEN_UMD_PSTATE_SOCCLK); +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetHardMinVcn, +- RAVEN_UMD_PSTATE_VCE); +- +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetSoftMaxGfxClk, +- RAVEN_UMD_PSTATE_GFXCLK); +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetSoftMaxFclkByFreq, +- RAVEN_UMD_PSTATE_FCLK); +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetSoftMaxSocclkByFreq, +- RAVEN_UMD_PSTATE_SOCCLK); +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetSoftMaxVcn, +- RAVEN_UMD_PSTATE_VCE); +- break; +- case AMD_DPM_FORCED_LEVEL_AUTO: +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetHardMinGfxClk, +- data->gfx_min_freq_limit/100); +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetHardMinFclkByFreq, +- RAVEN_UMD_PSTATE_MIN_FCLK); +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetHardMinSocclkByFreq, +- RAVEN_UMD_PSTATE_MIN_SOCCLK); +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetHardMinVcn, +- RAVEN_UMD_PSTATE_MIN_VCE); +- +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetSoftMaxGfxClk, +- data->gfx_max_freq_limit/100); +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetSoftMaxFclkByFreq, +- RAVEN_UMD_PSTATE_PEAK_FCLK); +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetSoftMaxSocclkByFreq, +- RAVEN_UMD_PSTATE_PEAK_SOCCLK); +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetSoftMaxVcn, +- RAVEN_UMD_PSTATE_VCE); +- break; +- case AMD_DPM_FORCED_LEVEL_LOW: +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetHardMinGfxClk, +- data->gfx_min_freq_limit/100); +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetSoftMaxGfxClk, +- data->gfx_min_freq_limit/100); +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetHardMinFclkByFreq, +- RAVEN_UMD_PSTATE_MIN_FCLK); +- smum_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetSoftMaxFclkByFreq, +- RAVEN_UMD_PSTATE_MIN_FCLK); +- break; +- case AMD_DPM_FORCED_LEVEL_MANUAL: +- case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT: +- default: +- break; +- } +- return 0; +-} +- +-static uint32_t rv_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low) +-{ +- struct rv_hwmgr *data; +- +- if (hwmgr == NULL) +- return -EINVAL; +- +- data = (struct rv_hwmgr *)(hwmgr->backend); +- +- if (low) +- return data->clock_vol_info.vdd_dep_on_fclk->entries[0].clk; +- else +- return data->clock_vol_info.vdd_dep_on_fclk->entries[ +- data->clock_vol_info.vdd_dep_on_fclk->count - 1].clk; +-} +- +-static uint32_t rv_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low) +-{ +- struct rv_hwmgr *data; +- +- if (hwmgr == NULL) +- return -EINVAL; +- +- data = (struct rv_hwmgr *)(hwmgr->backend); +- +- if (low) +- return data->gfx_min_freq_limit; +- else +- return data->gfx_max_freq_limit; +-} +- +-static int rv_dpm_patch_boot_state(struct pp_hwmgr *hwmgr, +- struct pp_hw_power_state *hw_ps) +-{ +- return 0; +-} +- +-static int rv_dpm_get_pp_table_entry_callback( +- struct pp_hwmgr *hwmgr, +- struct pp_hw_power_state *hw_ps, +- unsigned int index, +- const void *clock_info) +-{ +- struct rv_power_state *rv_ps = cast_rv_ps(hw_ps); +- +- rv_ps->levels[index].engine_clock = 0; +- +- rv_ps->levels[index].vddc_index = 0; +- rv_ps->level = index + 1; +- +- if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) { +- rv_ps->levels[index].ds_divider_index = 5; +- rv_ps->levels[index].ss_divider_index = 5; +- } +- +- return 0; +-} +- +-static int rv_dpm_get_num_of_pp_table_entries(struct pp_hwmgr *hwmgr) +-{ +- int result; +- unsigned long ret = 0; +- +- result = pp_tables_get_num_of_entries(hwmgr, &ret); +- +- return result ? 0 : ret; +-} +- +-static int rv_dpm_get_pp_table_entry(struct pp_hwmgr *hwmgr, +- unsigned long entry, struct pp_power_state *ps) +-{ +- int result; +- struct rv_power_state *rv_ps; +- +- ps->hardware.magic = PhwRaven_Magic; +- +- rv_ps = cast_rv_ps(&(ps->hardware)); +- +- result = pp_tables_get_entry(hwmgr, entry, ps, +- rv_dpm_get_pp_table_entry_callback); +- +- rv_ps->uvd_clocks.vclk = ps->uvd_clocks.VCLK; +- rv_ps->uvd_clocks.dclk = ps->uvd_clocks.DCLK; +- +- return result; +-} +- +-static int rv_get_power_state_size(struct pp_hwmgr *hwmgr) +-{ +- return sizeof(struct rv_power_state); +-} +- +-static int rv_set_cpu_power_state(struct pp_hwmgr *hwmgr) +-{ +- return 0; +-} +- +- +-static int rv_store_cc6_data(struct pp_hwmgr *hwmgr, uint32_t separation_time, +- bool cc6_disable, bool pstate_disable, bool pstate_switch_disable) +-{ +- return 0; +-} +- +-static int rv_get_dal_power_level(struct pp_hwmgr *hwmgr, +- struct amd_pp_simple_clock_info *info) +-{ +- return -EINVAL; +-} +- +-static int rv_force_clock_level(struct pp_hwmgr *hwmgr, +- enum pp_clock_type type, uint32_t mask) +-{ +- return 0; +-} +- +-static int rv_print_clock_levels(struct pp_hwmgr *hwmgr, +- enum pp_clock_type type, char *buf) +-{ +- struct rv_hwmgr *data = (struct rv_hwmgr *)(hwmgr->backend); +- struct rv_voltage_dependency_table *mclk_table = +- data->clock_vol_info.vdd_dep_on_fclk; +- uint32_t i, now, size = 0; +- +- switch (type) { +- case PP_SCLK: +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetGfxclkFrequency); +- now = smum_get_argument(hwmgr); +- +- size += sprintf(buf + size, "0: %uMhz %s\n", +- data->gfx_min_freq_limit / 100, +- ((data->gfx_min_freq_limit / 100) +- == now) ? "*" : ""); +- size += sprintf(buf + size, "1: %uMhz %s\n", +- data->gfx_max_freq_limit / 100, +- ((data->gfx_max_freq_limit / 100) +- == now) ? "*" : ""); +- break; +- case PP_MCLK: +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetFclkFrequency); +- now = smum_get_argument(hwmgr); +- +- for (i = 0; i < mclk_table->count; i++) +- size += sprintf(buf + size, "%d: %uMhz %s\n", +- i, +- mclk_table->entries[i].clk / 100, +- ((mclk_table->entries[i].clk / 100) +- == now) ? "*" : ""); +- break; +- default: +- break; +- } +- +- return size; +-} +- +-static int rv_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state, +- PHM_PerformanceLevelDesignation designation, uint32_t index, +- PHM_PerformanceLevel *level) +-{ +- struct rv_hwmgr *data; +- +- if (level == NULL || hwmgr == NULL || state == NULL) +- return -EINVAL; +- +- data = (struct rv_hwmgr *)(hwmgr->backend); +- +- if (index == 0) { +- level->memory_clock = data->clock_vol_info.vdd_dep_on_fclk->entries[0].clk; +- level->coreClock = data->gfx_min_freq_limit; +- } else { +- level->memory_clock = data->clock_vol_info.vdd_dep_on_fclk->entries[ +- data->clock_vol_info.vdd_dep_on_fclk->count - 1].clk; +- level->coreClock = data->gfx_max_freq_limit; +- } +- +- level->nonLocalMemoryFreq = 0; +- level->nonLocalMemoryWidth = 0; +- +- return 0; +-} +- +-static int rv_get_current_shallow_sleep_clocks(struct pp_hwmgr *hwmgr, +- const struct pp_hw_power_state *state, struct pp_clock_info *clock_info) +-{ +- const struct rv_power_state *ps = cast_const_rv_ps(state); +- +- clock_info->min_eng_clk = ps->levels[0].engine_clock / (1 << (ps->levels[0].ss_divider_index)); +- clock_info->max_eng_clk = ps->levels[ps->level - 1].engine_clock / (1 << (ps->levels[ps->level - 1].ss_divider_index)); +- +- return 0; +-} +- +-#define MEM_FREQ_LOW_LATENCY 25000 +-#define MEM_FREQ_HIGH_LATENCY 80000 +-#define MEM_LATENCY_HIGH 245 +-#define MEM_LATENCY_LOW 35 +-#define MEM_LATENCY_ERR 0xFFFF +- +- +-static uint32_t rv_get_mem_latency(struct pp_hwmgr *hwmgr, +- uint32_t clock) +-{ +- if (clock >= MEM_FREQ_LOW_LATENCY && +- clock < MEM_FREQ_HIGH_LATENCY) +- return MEM_LATENCY_HIGH; +- else if (clock >= MEM_FREQ_HIGH_LATENCY) +- return MEM_LATENCY_LOW; +- else +- return MEM_LATENCY_ERR; +-} +- +-static int rv_get_clock_by_type_with_latency(struct pp_hwmgr *hwmgr, +- enum amd_pp_clock_type type, +- struct pp_clock_levels_with_latency *clocks) +-{ +- uint32_t i; +- struct rv_hwmgr *rv_data = (struct rv_hwmgr *)(hwmgr->backend); +- struct rv_clock_voltage_information *pinfo = &(rv_data->clock_vol_info); +- struct rv_voltage_dependency_table *pclk_vol_table; +- bool latency_required = false; +- +- if (pinfo == NULL) +- return -EINVAL; +- +- switch (type) { +- case amd_pp_mem_clock: +- pclk_vol_table = pinfo->vdd_dep_on_mclk; +- latency_required = true; +- break; +- case amd_pp_f_clock: +- pclk_vol_table = pinfo->vdd_dep_on_fclk; +- latency_required = true; +- break; +- case amd_pp_dcf_clock: +- pclk_vol_table = pinfo->vdd_dep_on_dcefclk; +- break; +- case amd_pp_disp_clock: +- pclk_vol_table = pinfo->vdd_dep_on_dispclk; +- break; +- case amd_pp_phy_clock: +- pclk_vol_table = pinfo->vdd_dep_on_phyclk; +- break; +- case amd_pp_dpp_clock: +- pclk_vol_table = pinfo->vdd_dep_on_dppclk; +- default: +- return -EINVAL; +- } +- +- if (pclk_vol_table == NULL || pclk_vol_table->count == 0) +- return -EINVAL; +- +- clocks->num_levels = 0; +- for (i = 0; i < pclk_vol_table->count; i++) { +- clocks->data[i].clocks_in_khz = pclk_vol_table->entries[i].clk; +- clocks->data[i].latency_in_us = latency_required ? +- rv_get_mem_latency(hwmgr, +- pclk_vol_table->entries[i].clk) : +- 0; +- clocks->num_levels++; +- } +- +- return 0; +-} +- +-static int rv_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr, +- enum amd_pp_clock_type type, +- struct pp_clock_levels_with_voltage *clocks) +-{ +- uint32_t i; +- struct rv_hwmgr *rv_data = (struct rv_hwmgr *)(hwmgr->backend); +- struct rv_clock_voltage_information *pinfo = &(rv_data->clock_vol_info); +- struct rv_voltage_dependency_table *pclk_vol_table = NULL; +- +- if (pinfo == NULL) +- return -EINVAL; +- +- switch (type) { +- case amd_pp_mem_clock: +- pclk_vol_table = pinfo->vdd_dep_on_mclk; +- break; +- case amd_pp_f_clock: +- pclk_vol_table = pinfo->vdd_dep_on_fclk; +- break; +- case amd_pp_dcf_clock: +- pclk_vol_table = pinfo->vdd_dep_on_dcefclk; +- break; +- case amd_pp_soc_clock: +- pclk_vol_table = pinfo->vdd_dep_on_socclk; +- break; +- default: +- return -EINVAL; +- } +- +- if (pclk_vol_table == NULL || pclk_vol_table->count == 0) +- return -EINVAL; +- +- clocks->num_levels = 0; +- for (i = 0; i < pclk_vol_table->count; i++) { +- clocks->data[i].clocks_in_khz = pclk_vol_table->entries[i].clk; +- clocks->data[i].voltage_in_mv = pclk_vol_table->entries[i].vol; +- clocks->num_levels++; +- } +- +- return 0; +-} +- +-int rv_display_clock_voltage_request(struct pp_hwmgr *hwmgr, +- struct pp_display_clock_request *clock_req) +-{ +- struct rv_hwmgr *rv_data = (struct rv_hwmgr *)(hwmgr->backend); +- enum amd_pp_clock_type clk_type = clock_req->clock_type; +- uint32_t clk_freq = clock_req->clock_freq_in_khz / 1000; +- PPSMC_Msg msg; +- +- switch (clk_type) { +- case amd_pp_dcf_clock: +- if (clk_freq == rv_data->dcf_actual_hard_min_freq) +- return 0; +- msg = PPSMC_MSG_SetHardMinDcefclkByFreq; +- rv_data->dcf_actual_hard_min_freq = clk_freq; +- break; +- case amd_pp_soc_clock: +- msg = PPSMC_MSG_SetHardMinSocclkByFreq; +- break; +- case amd_pp_f_clock: +- if (clk_freq == rv_data->f_actual_hard_min_freq) +- return 0; +- rv_data->f_actual_hard_min_freq = clk_freq; +- msg = PPSMC_MSG_SetHardMinFclkByFreq; +- break; +- default: +- pr_info("[DisplayClockVoltageRequest]Invalid Clock Type!"); +- return -EINVAL; +- } +- +- smum_send_msg_to_smc_with_parameter(hwmgr, msg, clk_freq); +- +- return 0; +-} +- +-static int rv_get_max_high_clocks(struct pp_hwmgr *hwmgr, struct amd_pp_simple_clock_info *clocks) +-{ +- clocks->engine_max_clock = 80000; /* driver can't get engine clock, temp hard code to 800MHz */ +- return 0; +-} +- +-static int rv_thermal_get_temperature(struct pp_hwmgr *hwmgr) +-{ +- uint32_t reg_offset = soc15_get_register_offset(THM_HWID, 0, +- mmTHM_TCON_CUR_TMP_BASE_IDX, mmTHM_TCON_CUR_TMP); +- uint32_t reg_value = cgs_read_register(hwmgr->device, reg_offset); +- int cur_temp = +- (reg_value & THM_TCON_CUR_TMP__CUR_TEMP_MASK) >> THM_TCON_CUR_TMP__CUR_TEMP__SHIFT; +- +- if (cur_temp & THM_TCON_CUR_TMP__CUR_TEMP_RANGE_SEL_MASK) +- cur_temp = ((cur_temp / 8) - 49) * PP_TEMPERATURE_UNITS_PER_CENTIGRADES; +- else +- cur_temp = (cur_temp / 8) * PP_TEMPERATURE_UNITS_PER_CENTIGRADES; +- +- return cur_temp; +-} +- +-static int rv_read_sensor(struct pp_hwmgr *hwmgr, int idx, +- void *value, int *size) +-{ +- uint32_t sclk, mclk; +- int ret = 0; +- +- switch (idx) { +- case AMDGPU_PP_SENSOR_GFX_SCLK: +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetGfxclkFrequency); +- sclk = smum_get_argument(hwmgr); +- /* in units of 10KHZ */ +- *((uint32_t *)value) = sclk * 100; +- *size = 4; +- break; +- case AMDGPU_PP_SENSOR_GFX_MCLK: +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetFclkFrequency); +- mclk = smum_get_argument(hwmgr); +- /* in units of 10KHZ */ +- *((uint32_t *)value) = mclk * 100; +- *size = 4; +- break; +- case AMDGPU_PP_SENSOR_GPU_TEMP: +- *((uint32_t *)value) = rv_thermal_get_temperature(hwmgr); +- break; +- default: +- ret = -EINVAL; +- break; +- } +- +- return ret; +-} +- +-static int rv_set_mmhub_powergating_by_smu(struct pp_hwmgr *hwmgr) +-{ +- return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_PowerGateMmHub); +-} +- +-static const struct pp_hwmgr_func rv_hwmgr_funcs = { +- .backend_init = rv_hwmgr_backend_init, +- .backend_fini = rv_hwmgr_backend_fini, +- .asic_setup = NULL, +- .apply_state_adjust_rules = rv_apply_state_adjust_rules, +- .force_dpm_level = rv_dpm_force_dpm_level, +- .get_power_state_size = rv_get_power_state_size, +- .powerdown_uvd = NULL, +- .powergate_uvd = NULL, +- .powergate_vce = NULL, +- .get_mclk = rv_dpm_get_mclk, +- .get_sclk = rv_dpm_get_sclk, +- .patch_boot_state = rv_dpm_patch_boot_state, +- .get_pp_table_entry = rv_dpm_get_pp_table_entry, +- .get_num_of_pp_table_entries = rv_dpm_get_num_of_pp_table_entries, +- .set_cpu_power_state = rv_set_cpu_power_state, +- .store_cc6_data = rv_store_cc6_data, +- .force_clock_level = rv_force_clock_level, +- .print_clock_levels = rv_print_clock_levels, +- .get_dal_power_level = rv_get_dal_power_level, +- .get_performance_level = rv_get_performance_level, +- .get_current_shallow_sleep_clocks = rv_get_current_shallow_sleep_clocks, +- .get_clock_by_type_with_latency = rv_get_clock_by_type_with_latency, +- .get_clock_by_type_with_voltage = rv_get_clock_by_type_with_voltage, +- .get_max_high_clocks = rv_get_max_high_clocks, +- .read_sensor = rv_read_sensor, +- .set_active_display_count = rv_set_active_display_count, +- .set_deep_sleep_dcefclk = rv_set_deep_sleep_dcefclk, +- .dynamic_state_management_enable = rv_enable_dpm_tasks, +- .power_off_asic = rv_power_off_asic, +- .asic_setup = rv_setup_asic_task, +- .power_state_set = rv_set_power_state_tasks, +- .dynamic_state_management_disable = rv_disable_dpm_tasks, +- .set_mmhub_powergating_by_smu = rv_set_mmhub_powergating_by_smu, +-}; +- +-int rv_init_function_pointers(struct pp_hwmgr *hwmgr) +-{ +- hwmgr->hwmgr_func = &rv_hwmgr_funcs; +- hwmgr->pptable_func = &pptable_funcs; +- return 0; +-} +diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/rv_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/rv_hwmgr.h +deleted file mode 100644 +index 29afa5c..0000000 +--- a/drivers/gpu/drm/amd/powerplay/hwmgr/rv_hwmgr.h ++++ /dev/null +@@ -1,320 +0,0 @@ +-/* +- * 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 RAVEN_HWMGR_H +-#define RAVEN_HWMGR_H +- +-#include "hwmgr.h" +-#include "rv_inc.h" +-#include "smu10_driver_if.h" +-#include "rv_ppsmc.h" +- +- +-#define RAVEN_MAX_HARDWARE_POWERLEVELS 8 +-#define PHMRAVEN_DYNCLK_NUMBER_OF_TREND_COEFFICIENTS 15 +- +-#define DPMFlags_SCLK_Enabled 0x00000001 +-#define DPMFlags_UVD_Enabled 0x00000002 +-#define DPMFlags_VCE_Enabled 0x00000004 +-#define DPMFlags_ACP_Enabled 0x00000008 +-#define DPMFlags_ForceHighestValid 0x40000000 +- +-/* Do not change the following, it is also defined in SMU8.h */ +-#define SMU_EnabledFeatureScoreboard_AcpDpmOn 0x00000001 +-#define SMU_EnabledFeatureScoreboard_SclkDpmOn 0x00200000 +-#define SMU_EnabledFeatureScoreboard_UvdDpmOn 0x01000000 +-#define SMU_EnabledFeatureScoreboard_VceDpmOn 0x02000000 +- +-#define SMU_PHYID_SHIFT 8 +- +-#define RAVEN_PCIE_POWERGATING_TARGET_GFX 0 +-#define RAVEN_PCIE_POWERGATING_TARGET_DDI 1 +-#define RAVEN_PCIE_POWERGATING_TARGET_PLLCASCADE 2 +-#define RAVEN_PCIE_POWERGATING_TARGET_PHY 3 +- +-enum VQ_TYPE { +- CLOCK_TYPE_DCLK = 0L, +- CLOCK_TYPE_ECLK, +- CLOCK_TYPE_SCLK, +- CLOCK_TYPE_CCLK, +- VQ_GFX_CU +-}; +- +-#define SUSTAINABLE_SCLK_MASK 0x00ffffff +-#define SUSTAINABLE_SCLK_SHIFT 0 +-#define SUSTAINABLE_CU_MASK 0xff000000 +-#define SUSTAINABLE_CU_SHIFT 24 +- +-struct rv_dpm_entry { +- uint32_t soft_min_clk; +- uint32_t hard_min_clk; +- uint32_t soft_max_clk; +- uint32_t hard_max_clk; +-}; +- +-struct rv_power_level { +- uint32_t engine_clock; +- uint8_t vddc_index; +- uint8_t ds_divider_index; +- uint8_t ss_divider_index; +- uint8_t allow_gnb_slow; +- uint8_t force_nbp_state; +- uint8_t display_wm; +- uint8_t vce_wm; +- uint8_t num_simd_to_powerdown; +- uint8_t hysteresis_up; +- uint8_t rsv[3]; +-}; +- +-/*used for the nbpsFlags field in rv_power state*/ +-#define RAVEN_POWERSTATE_FLAGS_NBPS_FORCEHIGH (1<<0) +-#define RAVEN_POWERSTATE_FLAGS_NBPS_LOCKTOHIGH (1<<1) +-#define RAVEN_POWERSTATE_FLAGS_NBPS_LOCKTOLOW (1<<2) +- +-#define RAVEN_POWERSTATE_FLAGS_BAPM_DISABLE (1<<0) +- +-struct rv_uvd_clocks { +- uint32_t vclk; +- uint32_t dclk; +- uint32_t vclk_low_divider; +- uint32_t vclk_high_divider; +- uint32_t dclk_low_divider; +- uint32_t dclk_high_divider; +-}; +- +-struct pp_disable_nbpslo_flags { +- union { +- struct { +- uint32_t entry : 1; +- uint32_t display : 1; +- uint32_t driver: 1; +- uint32_t vce : 1; +- uint32_t uvd : 1; +- uint32_t acp : 1; +- uint32_t reserved: 26; +- } bits; +- uint32_t u32All; +- }; +-}; +- +- +-enum rv_pstate_previous_action { +- DO_NOTHING = 1, +- FORCE_HIGH, +- CANCEL_FORCE_HIGH +-}; +- +-struct rv_power_state { +- unsigned int magic; +- uint32_t level; +- struct rv_uvd_clocks uvd_clocks; +- uint32_t evclk; +- uint32_t ecclk; +- uint32_t samclk; +- uint32_t acpclk; +- bool need_dfs_bypass; +- +- uint32_t nbps_flags; +- uint32_t bapm_flags; +- uint8_t dpm0_pg_nbps_low; +- uint8_t dpm0_pg_nbps_high; +- uint8_t dpm_x_nbps_low; +- uint8_t dpm_x_nbps_high; +- +- enum rv_pstate_previous_action action; +- +- struct rv_power_level levels[RAVEN_MAX_HARDWARE_POWERLEVELS]; +- struct pp_disable_nbpslo_flags nbpslo_flags; +-}; +- +-#define RAVEN_NUM_NBPSTATES 4 +-#define RAVEN_NUM_NBPMEMORYCLOCK 2 +- +- +-struct rv_display_phy_info_entry { +- uint8_t phy_present; +- uint8_t active_lane_mapping; +- uint8_t display_config_type; +- uint8_t active_num_of_lanes; +-}; +- +-#define RAVEN_MAX_DISPLAYPHY_IDS 10 +- +-struct rv_display_phy_info { +- bool display_phy_access_initialized; +- struct rv_display_phy_info_entry entries[RAVEN_MAX_DISPLAYPHY_IDS]; +-}; +- +-#define MAX_DISPLAY_CLOCK_LEVEL 8 +- +-struct rv_system_info{ +- uint8_t htc_tmp_lmt; +- uint8_t htc_hyst_lmt; +-}; +- +-#define MAX_REGULAR_DPM_NUMBER 8 +- +-struct rv_mclk_latency_entries { +- uint32_t frequency; +- uint32_t latency; +-}; +- +-struct rv_mclk_latency_table { +- uint32_t count; +- struct rv_mclk_latency_entries entries[MAX_REGULAR_DPM_NUMBER]; +-}; +- +-struct rv_clock_voltage_dependency_record { +- uint32_t clk; +- uint32_t vol; +-}; +- +- +-struct rv_voltage_dependency_table { +- uint32_t count; +- struct rv_clock_voltage_dependency_record entries[1]; +-}; +- +-struct rv_clock_voltage_information { +- struct rv_voltage_dependency_table *vdd_dep_on_dcefclk; +- struct rv_voltage_dependency_table *vdd_dep_on_socclk; +- struct rv_voltage_dependency_table *vdd_dep_on_fclk; +- struct rv_voltage_dependency_table *vdd_dep_on_mclk; +- struct rv_voltage_dependency_table *vdd_dep_on_dispclk; +- struct rv_voltage_dependency_table *vdd_dep_on_dppclk; +- struct rv_voltage_dependency_table *vdd_dep_on_phyclk; +-}; +- +-struct rv_hwmgr { +- uint32_t disable_driver_thermal_policy; +- uint32_t thermal_auto_throttling_treshold; +- struct rv_system_info sys_info; +- struct rv_mclk_latency_table mclk_latency_table; +- +- uint32_t ddi_power_gating_disabled; +- +- struct rv_display_phy_info_entry display_phy_info; +- uint32_t dce_slow_sclk_threshold; +- +- bool disp_clk_bypass; +- bool disp_clk_bypass_pending; +- uint32_t bapm_enabled; +- +- bool video_start; +- bool battery_state; +- +- uint32_t is_nb_dpm_enabled; +- uint32_t is_voltage_island_enabled; +- uint32_t disable_smu_acp_s3_handshake; +- uint32_t disable_notify_smu_vpu_recovery; +- bool in_vpu_recovery; +- bool pg_acp_init; +- uint8_t disp_config; +- +- /* PowerTune */ +- uint32_t power_containment_features; +- bool cac_enabled; +- bool disable_uvd_power_tune_feature; +- bool enable_bapm_feature; +- bool enable_tdc_limit_feature; +- +- +- /* SMC SRAM Address of firmware header tables */ +- uint32_t sram_end; +- uint32_t dpm_table_start; +- uint32_t soft_regs_start; +- +- /* start of SMU7_Fusion_DpmTable */ +- +- uint8_t uvd_level_count; +- uint8_t vce_level_count; +- uint8_t acp_level_count; +- uint8_t samu_level_count; +- +- uint32_t fps_high_threshold; +- uint32_t fps_low_threshold; +- +- uint32_t dpm_flags; +- struct rv_dpm_entry sclk_dpm; +- struct rv_dpm_entry uvd_dpm; +- struct rv_dpm_entry vce_dpm; +- struct rv_dpm_entry acp_dpm; +- bool acp_power_up_no_dsp; +- +- uint32_t max_sclk_level; +- uint32_t num_of_clk_entries; +- +- /* CPU Power State */ +- uint32_t separation_time; +- bool cc6_disable; +- bool pstate_disable; +- bool cc6_setting_changed; +- +- uint32_t ulTotalActiveCUs; +- +- bool isp_tileA_power_gated; +- bool isp_tileB_power_gated; +- uint32_t isp_actual_hard_min_freq; +- uint32_t soc_actual_hard_min_freq; +- uint32_t dcf_actual_hard_min_freq; +- +- uint32_t f_actual_hard_min_freq; +- uint32_t fabric_actual_soft_min_freq; +- uint32_t vclk_soft_min; +- uint32_t dclk_soft_min; +- uint32_t gfx_actual_soft_min_freq; +- uint32_t gfx_min_freq_limit; +- uint32_t gfx_max_freq_limit; +- +- bool vcn_power_gated; +- bool vcn_dpg_mode; +- +- bool gfx_off_controled_by_driver; +- Watermarks_t water_marks_table; +- struct rv_clock_voltage_information clock_vol_info; +- DpmClocks_t clock_table; +- +- uint32_t active_process_mask; +- bool need_min_deep_sleep_dcefclk; +- uint32_t deep_sleep_dcefclk; +- uint32_t num_active_display; +-}; +- +-struct pp_hwmgr; +- +-int rv_init_function_pointers(struct pp_hwmgr *hwmgr); +- +-/* UMD PState Raven Msg Parameters in MHz */ +-#define RAVEN_UMD_PSTATE_GFXCLK 700 +-#define RAVEN_UMD_PSTATE_SOCCLK 626 +-#define RAVEN_UMD_PSTATE_FCLK 933 +-#define RAVEN_UMD_PSTATE_VCE 0x03C00320 +- +-#define RAVEN_UMD_PSTATE_PEAK_SOCCLK 757 +-#define RAVEN_UMD_PSTATE_PEAK_FCLK 1200 +- +-#define RAVEN_UMD_PSTATE_MIN_FCLK 400 +-#define RAVEN_UMD_PSTATE_MIN_SOCCLK 200 +-#define RAVEN_UMD_PSTATE_MIN_VCE 0x0190012C +- +-#endif +diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/rv_inc.h b/drivers/gpu/drm/amd/powerplay/hwmgr/rv_inc.h +deleted file mode 100644 +index ae59a3f..0000000 +--- a/drivers/gpu/drm/amd/powerplay/hwmgr/rv_inc.h ++++ /dev/null +@@ -1,43 +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. +- * +- */ +- +-#ifndef RAVEN_INC_H +-#define RAVEN_INC_H +- +- +-#include "asic_reg/mp/mp_10_0_default.h" +-#include "asic_reg/mp/mp_10_0_offset.h" +-#include "asic_reg/mp/mp_10_0_sh_mask.h" +- +-#include "asic_reg/nbio/nbio_7_0_default.h" +-#include "asic_reg/nbio/nbio_7_0_offset.h" +-#include "asic_reg/nbio/nbio_7_0_sh_mask.h" +- +-#include "asic_reg/thm/thm_10_0_default.h" +-#include "asic_reg/thm/thm_10_0_offset.h" +-#include "asic_reg/thm/thm_10_0_sh_mask.h" +- +- +-#define ixDDI_PHY_GEN_STATUS 0x3FCE8 +- +-#endif +diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c +new file mode 100644 +index 0000000..10253b8 +--- /dev/null ++++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c +@@ -0,0 +1,1042 @@ ++/* ++ * 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 "pp_debug.h" ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include "atom-types.h" ++#include "atombios.h" ++#include "processpptables.h" ++#include "cgs_common.h" ++#include "smumgr.h" ++#include "hwmgr.h" ++#include "hardwaremanager.h" ++#include "rv_ppsmc.h" ++#include "smu10_hwmgr.h" ++#include "power_state.h" ++#include "pp_soc15.h" ++ ++#define SMU10_MAX_DEEPSLEEP_DIVIDER_ID 5 ++#define SMU10_MINIMUM_ENGINE_CLOCK 800 /* 8Mhz, the low boundary of engine clock allowed on this chip */ ++#define SCLK_MIN_DIV_INTV_SHIFT 12 ++#define SMU10_DISPCLK_BYPASS_THRESHOLD 10000 /* 100Mhz */ ++#define SMC_RAM_END 0x40000 ++ ++static const unsigned long SMU10_Magic = (unsigned long) PHM_Rv_Magic; ++ ++ ++static int smu10_display_clock_voltage_request(struct pp_hwmgr *hwmgr, ++ struct pp_display_clock_request *clock_req); ++ ++ ++static struct smu10_power_state *cast_smu10_ps(struct pp_hw_power_state *hw_ps) ++{ ++ if (SMU10_Magic != hw_ps->magic) ++ return NULL; ++ ++ return (struct smu10_power_state *)hw_ps; ++} ++ ++static const struct smu10_power_state *cast_const_smu10_ps( ++ const struct pp_hw_power_state *hw_ps) ++{ ++ if (SMU10_Magic != hw_ps->magic) ++ return NULL; ++ ++ return (struct smu10_power_state *)hw_ps; ++} ++ ++static int smu10_initialize_dpm_defaults(struct pp_hwmgr *hwmgr) ++{ ++ struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); ++ ++ smu10_data->dce_slow_sclk_threshold = 30000; ++ smu10_data->thermal_auto_throttling_treshold = 0; ++ smu10_data->is_nb_dpm_enabled = 1; ++ smu10_data->dpm_flags = 1; ++ smu10_data->gfx_off_controled_by_driver = false; ++ smu10_data->need_min_deep_sleep_dcefclk = true; ++ smu10_data->num_active_display = 0; ++ smu10_data->deep_sleep_dcefclk = 0; ++ ++ phm_cap_unset(hwmgr->platform_descriptor.platformCaps, ++ PHM_PlatformCaps_SclkDeepSleep); ++ ++ phm_cap_unset(hwmgr->platform_descriptor.platformCaps, ++ PHM_PlatformCaps_SclkThrottleLowNotification); ++ ++ phm_cap_set(hwmgr->platform_descriptor.platformCaps, ++ PHM_PlatformCaps_PowerPlaySupport); ++ return 0; ++} ++ ++static int smu10_construct_max_power_limits_table(struct pp_hwmgr *hwmgr, ++ struct phm_clock_and_voltage_limits *table) ++{ ++ return 0; ++} ++ ++static int smu10_init_dynamic_state_adjustment_rule_settings( ++ struct pp_hwmgr *hwmgr) ++{ ++ uint32_t table_size = ++ sizeof(struct phm_clock_voltage_dependency_table) + ++ (7 * sizeof(struct phm_clock_voltage_dependency_record)); ++ ++ struct phm_clock_voltage_dependency_table *table_clk_vlt = ++ kzalloc(table_size, GFP_KERNEL); ++ ++ if (NULL == table_clk_vlt) { ++ pr_err("Can not allocate memory!\n"); ++ return -ENOMEM; ++ } ++ ++ table_clk_vlt->count = 8; ++ table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_0; ++ table_clk_vlt->entries[0].v = 0; ++ table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_1; ++ table_clk_vlt->entries[1].v = 1; ++ table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_2; ++ table_clk_vlt->entries[2].v = 2; ++ table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_3; ++ table_clk_vlt->entries[3].v = 3; ++ table_clk_vlt->entries[4].clk = PP_DAL_POWERLEVEL_4; ++ table_clk_vlt->entries[4].v = 4; ++ table_clk_vlt->entries[5].clk = PP_DAL_POWERLEVEL_5; ++ table_clk_vlt->entries[5].v = 5; ++ table_clk_vlt->entries[6].clk = PP_DAL_POWERLEVEL_6; ++ table_clk_vlt->entries[6].v = 6; ++ table_clk_vlt->entries[7].clk = PP_DAL_POWERLEVEL_7; ++ table_clk_vlt->entries[7].v = 7; ++ hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt; ++ ++ return 0; ++} ++ ++static int smu10_get_system_info_data(struct pp_hwmgr *hwmgr) ++{ ++ struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)hwmgr->backend; ++ ++ smu10_data->sys_info.htc_hyst_lmt = 5; ++ smu10_data->sys_info.htc_tmp_lmt = 203; ++ ++ if (smu10_data->thermal_auto_throttling_treshold == 0) ++ smu10_data->thermal_auto_throttling_treshold = 203; ++ ++ smu10_construct_max_power_limits_table (hwmgr, ++ &hwmgr->dyn_state.max_clock_voltage_on_ac); ++ ++ smu10_init_dynamic_state_adjustment_rule_settings(hwmgr); ++ ++ return 0; ++} ++ ++static int smu10_construct_boot_state(struct pp_hwmgr *hwmgr) ++{ ++ return 0; ++} ++ ++static int smu10_set_clock_limit(struct pp_hwmgr *hwmgr, const void *input) ++{ ++ struct PP_Clocks clocks = {0}; ++ struct pp_display_clock_request clock_req; ++ ++ clocks.dcefClock = hwmgr->display_config.min_dcef_set_clk; ++ clock_req.clock_type = amd_pp_dcf_clock; ++ clock_req.clock_freq_in_khz = clocks.dcefClock * 10; ++ ++ PP_ASSERT_WITH_CODE(!smu10_display_clock_voltage_request(hwmgr, &clock_req), ++ "Attempt to set DCF Clock Failed!", return -EINVAL); ++ ++ return 0; ++} ++ ++static int smu10_set_deep_sleep_dcefclk(struct pp_hwmgr *hwmgr, uint32_t clock) ++{ ++ struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); ++ ++ if (smu10_data->need_min_deep_sleep_dcefclk && smu10_data->deep_sleep_dcefclk != clock/100) { ++ smu10_data->deep_sleep_dcefclk = clock/100; ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetMinDeepSleepDcefclk, ++ smu10_data->deep_sleep_dcefclk); ++ } ++ return 0; ++} ++ ++static int smu10_set_active_display_count(struct pp_hwmgr *hwmgr, uint32_t count) ++{ ++ struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); ++ ++ if (smu10_data->num_active_display != count) { ++ smu10_data->num_active_display = count; ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetDisplayCount, ++ smu10_data->num_active_display); ++ } ++ ++ return 0; ++} ++ ++static int smu10_set_power_state_tasks(struct pp_hwmgr *hwmgr, const void *input) ++{ ++ return smu10_set_clock_limit(hwmgr, input); ++} ++ ++static int smu10_init_power_gate_state(struct pp_hwmgr *hwmgr) ++{ ++ struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); ++ ++ smu10_data->vcn_power_gated = true; ++ smu10_data->isp_tileA_power_gated = true; ++ smu10_data->isp_tileB_power_gated = true; ++ ++ return 0; ++} ++ ++ ++static int smu10_setup_asic_task(struct pp_hwmgr *hwmgr) ++{ ++ return smu10_init_power_gate_state(hwmgr); ++} ++ ++static int smu10_reset_cc6_data(struct pp_hwmgr *hwmgr) ++{ ++ struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); ++ ++ smu10_data->separation_time = 0; ++ smu10_data->cc6_disable = false; ++ smu10_data->pstate_disable = false; ++ smu10_data->cc6_setting_changed = false; ++ ++ return 0; ++} ++ ++static int smu10_power_off_asic(struct pp_hwmgr *hwmgr) ++{ ++ return smu10_reset_cc6_data(hwmgr); ++} ++ ++static int smu10_disable_gfx_off(struct pp_hwmgr *hwmgr) ++{ ++ struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); ++ ++ if (smu10_data->gfx_off_controled_by_driver) ++ smum_send_msg_to_smc(hwmgr, PPSMC_MSG_DisableGfxOff); ++ ++ return 0; ++} ++ ++static int smu10_disable_dpm_tasks(struct pp_hwmgr *hwmgr) ++{ ++ return smu10_disable_gfx_off(hwmgr); ++} ++ ++static int smu10_enable_gfx_off(struct pp_hwmgr *hwmgr) ++{ ++ struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); ++ ++ if (smu10_data->gfx_off_controled_by_driver) ++ smum_send_msg_to_smc(hwmgr, PPSMC_MSG_EnableGfxOff); ++ ++ return 0; ++} ++ ++static int smu10_enable_dpm_tasks(struct pp_hwmgr *hwmgr) ++{ ++ return smu10_enable_gfx_off(hwmgr); ++} ++ ++static int smu10_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, ++ struct pp_power_state *prequest_ps, ++ const struct pp_power_state *pcurrent_ps) ++{ ++ return 0; ++} ++ ++/* temporary hardcoded clock voltage breakdown tables */ ++static const DpmClock_t VddDcfClk[]= { ++ { 300, 2600}, ++ { 600, 3200}, ++ { 600, 3600}, ++}; ++ ++static const DpmClock_t VddSocClk[]= { ++ { 478, 2600}, ++ { 722, 3200}, ++ { 722, 3600}, ++}; ++ ++static const DpmClock_t VddFClk[]= { ++ { 400, 2600}, ++ {1200, 3200}, ++ {1200, 3600}, ++}; ++ ++static const DpmClock_t VddDispClk[]= { ++ { 435, 2600}, ++ { 661, 3200}, ++ {1086, 3600}, ++}; ++ ++static const DpmClock_t VddDppClk[]= { ++ { 435, 2600}, ++ { 661, 3200}, ++ { 661, 3600}, ++}; ++ ++static const DpmClock_t VddPhyClk[]= { ++ { 540, 2600}, ++ { 810, 3200}, ++ { 810, 3600}, ++}; ++ ++static int smu10_get_clock_voltage_dependency_table(struct pp_hwmgr *hwmgr, ++ struct smu10_voltage_dependency_table **pptable, ++ uint32_t num_entry, const DpmClock_t *pclk_dependency_table) ++{ ++ uint32_t table_size, i; ++ struct smu10_voltage_dependency_table *ptable; ++ ++ table_size = sizeof(uint32_t) + sizeof(struct smu10_voltage_dependency_table) * num_entry; ++ ptable = kzalloc(table_size, GFP_KERNEL); ++ ++ if (NULL == ptable) ++ return -ENOMEM; ++ ++ ptable->count = num_entry; ++ ++ for (i = 0; i < ptable->count; i++) { ++ ptable->entries[i].clk = pclk_dependency_table->Freq * 100; ++ ptable->entries[i].vol = pclk_dependency_table->Vol; ++ pclk_dependency_table++; ++ } ++ ++ *pptable = ptable; ++ ++ return 0; ++} ++ ++ ++static int smu10_populate_clock_table(struct pp_hwmgr *hwmgr) ++{ ++ int result; ++ ++ struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); ++ DpmClocks_t *table = &(smu10_data->clock_table); ++ struct smu10_clock_voltage_information *pinfo = &(smu10_data->clock_vol_info); ++ ++ result = smum_smc_table_manager(hwmgr, (uint8_t *)table, SMU10_CLOCKTABLE, true); ++ ++ PP_ASSERT_WITH_CODE((0 == result), ++ "Attempt to copy clock table from smc failed", ++ return result); ++ ++ if (0 == result && table->DcefClocks[0].Freq != 0) { ++ smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_dcefclk, ++ NUM_DCEFCLK_DPM_LEVELS, ++ &smu10_data->clock_table.DcefClocks[0]); ++ smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_socclk, ++ NUM_SOCCLK_DPM_LEVELS, ++ &smu10_data->clock_table.SocClocks[0]); ++ smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_fclk, ++ NUM_FCLK_DPM_LEVELS, ++ &smu10_data->clock_table.FClocks[0]); ++ smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_mclk, ++ NUM_MEMCLK_DPM_LEVELS, ++ &smu10_data->clock_table.MemClocks[0]); ++ } else { ++ smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_dcefclk, ++ ARRAY_SIZE(VddDcfClk), ++ &VddDcfClk[0]); ++ smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_socclk, ++ ARRAY_SIZE(VddSocClk), ++ &VddSocClk[0]); ++ smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_fclk, ++ ARRAY_SIZE(VddFClk), ++ &VddFClk[0]); ++ } ++ smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_dispclk, ++ ARRAY_SIZE(VddDispClk), ++ &VddDispClk[0]); ++ smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_dppclk, ++ ARRAY_SIZE(VddDppClk), &VddDppClk[0]); ++ smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_phyclk, ++ ARRAY_SIZE(VddPhyClk), &VddPhyClk[0]); ++ ++ smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMinGfxclkFrequency); ++ result = smum_get_argument(hwmgr); ++ smu10_data->gfx_min_freq_limit = result * 100; ++ ++ smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetMaxGfxclkFrequency); ++ result = smum_get_argument(hwmgr); ++ smu10_data->gfx_max_freq_limit = result * 100; ++ ++ return 0; ++} ++ ++static int smu10_hwmgr_backend_init(struct pp_hwmgr *hwmgr) ++{ ++ int result = 0; ++ struct smu10_hwmgr *data; ++ ++ data = kzalloc(sizeof(struct smu10_hwmgr), GFP_KERNEL); ++ if (data == NULL) ++ return -ENOMEM; ++ ++ hwmgr->backend = data; ++ ++ result = smu10_initialize_dpm_defaults(hwmgr); ++ if (result != 0) { ++ pr_err("smu10_initialize_dpm_defaults failed\n"); ++ return result; ++ } ++ ++ smu10_populate_clock_table(hwmgr); ++ ++ result = smu10_get_system_info_data(hwmgr); ++ if (result != 0) { ++ pr_err("smu10_get_system_info_data failed\n"); ++ return result; ++ } ++ ++ smu10_construct_boot_state(hwmgr); ++ ++ hwmgr->platform_descriptor.hardwareActivityPerformanceLevels = ++ SMU10_MAX_HARDWARE_POWERLEVELS; ++ ++ hwmgr->platform_descriptor.hardwarePerformanceLevels = ++ SMU10_MAX_HARDWARE_POWERLEVELS; ++ ++ hwmgr->platform_descriptor.vbiosInterruptId = 0; ++ ++ hwmgr->platform_descriptor.clockStep.engineClock = 500; ++ ++ hwmgr->platform_descriptor.clockStep.memoryClock = 500; ++ ++ hwmgr->platform_descriptor.minimumClocksReductionPercentage = 50; ++ ++ hwmgr->pstate_sclk = SMU10_UMD_PSTATE_GFXCLK; ++ hwmgr->pstate_mclk = SMU10_UMD_PSTATE_FCLK; ++ ++ return result; ++} ++ ++static int smu10_hwmgr_backend_fini(struct pp_hwmgr *hwmgr) ++{ ++ struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); ++ struct smu10_clock_voltage_information *pinfo = &(smu10_data->clock_vol_info); ++ ++ kfree(pinfo->vdd_dep_on_dcefclk); ++ pinfo->vdd_dep_on_dcefclk = NULL; ++ kfree(pinfo->vdd_dep_on_socclk); ++ pinfo->vdd_dep_on_socclk = NULL; ++ kfree(pinfo->vdd_dep_on_fclk); ++ pinfo->vdd_dep_on_fclk = NULL; ++ kfree(pinfo->vdd_dep_on_dispclk); ++ pinfo->vdd_dep_on_dispclk = NULL; ++ kfree(pinfo->vdd_dep_on_dppclk); ++ pinfo->vdd_dep_on_dppclk = NULL; ++ kfree(pinfo->vdd_dep_on_phyclk); ++ pinfo->vdd_dep_on_phyclk = NULL; ++ ++ kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl); ++ hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL; ++ ++ kfree(hwmgr->backend); ++ hwmgr->backend = NULL; ++ ++ return 0; ++} ++ ++static int smu10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr, ++ enum amd_dpm_forced_level level) ++{ ++ if (hwmgr->smu_version < 0x1E3700) { ++ pr_info("smu firmware version too old, can not set dpm level\n"); ++ return 0; ++ } ++ ++ switch (level) { ++ case AMD_DPM_FORCED_LEVEL_HIGH: ++ case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetHardMinGfxClk, ++ SMU10_UMD_PSTATE_PEAK_GFXCLK); ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetHardMinFclkByFreq, ++ SMU10_UMD_PSTATE_PEAK_FCLK); ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetHardMinSocclkByFreq, ++ SMU10_UMD_PSTATE_PEAK_SOCCLK); ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetHardMinVcn, ++ SMU10_UMD_PSTATE_VCE); ++ ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetSoftMaxGfxClk, ++ SMU10_UMD_PSTATE_PEAK_GFXCLK); ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetSoftMaxFclkByFreq, ++ SMU10_UMD_PSTATE_PEAK_FCLK); ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetSoftMaxSocclkByFreq, ++ SMU10_UMD_PSTATE_PEAK_SOCCLK); ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetSoftMaxVcn, ++ SMU10_UMD_PSTATE_VCE); ++ break; ++ case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetHardMinGfxClk, ++ SMU10_UMD_PSTATE_MIN_GFXCLK); ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetSoftMaxGfxClk, ++ SMU10_UMD_PSTATE_MIN_GFXCLK); ++ break; ++ case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetHardMinFclkByFreq, ++ SMU10_UMD_PSTATE_MIN_FCLK); ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetSoftMaxFclkByFreq, ++ SMU10_UMD_PSTATE_MIN_FCLK); ++ break; ++ case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetHardMinGfxClk, ++ SMU10_UMD_PSTATE_GFXCLK); ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetHardMinFclkByFreq, ++ SMU10_UMD_PSTATE_FCLK); ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetHardMinSocclkByFreq, ++ SMU10_UMD_PSTATE_SOCCLK); ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetHardMinVcn, ++ SMU10_UMD_PSTATE_VCE); ++ ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetSoftMaxGfxClk, ++ SMU10_UMD_PSTATE_GFXCLK); ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetSoftMaxFclkByFreq, ++ SMU10_UMD_PSTATE_FCLK); ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetSoftMaxSocclkByFreq, ++ SMU10_UMD_PSTATE_SOCCLK); ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetSoftMaxVcn, ++ SMU10_UMD_PSTATE_VCE); ++ break; ++ case AMD_DPM_FORCED_LEVEL_AUTO: ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetHardMinGfxClk, ++ SMU10_UMD_PSTATE_MIN_GFXCLK); ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetHardMinFclkByFreq, ++ SMU10_UMD_PSTATE_MIN_FCLK); ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetHardMinSocclkByFreq, ++ SMU10_UMD_PSTATE_MIN_SOCCLK); ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetHardMinVcn, ++ SMU10_UMD_PSTATE_MIN_VCE); ++ ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetSoftMaxGfxClk, ++ SMU10_UMD_PSTATE_PEAK_GFXCLK); ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetSoftMaxFclkByFreq, ++ SMU10_UMD_PSTATE_PEAK_FCLK); ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetSoftMaxSocclkByFreq, ++ SMU10_UMD_PSTATE_PEAK_SOCCLK); ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetSoftMaxVcn, ++ SMU10_UMD_PSTATE_VCE); ++ break; ++ case AMD_DPM_FORCED_LEVEL_LOW: ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetHardMinGfxClk, ++ SMU10_UMD_PSTATE_MIN_GFXCLK); ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetSoftMaxGfxClk, ++ SMU10_UMD_PSTATE_MIN_GFXCLK); ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetHardMinFclkByFreq, ++ SMU10_UMD_PSTATE_MIN_FCLK); ++ smum_send_msg_to_smc_with_parameter(hwmgr, ++ PPSMC_MSG_SetSoftMaxFclkByFreq, ++ SMU10_UMD_PSTATE_MIN_FCLK); ++ break; ++ case AMD_DPM_FORCED_LEVEL_MANUAL: ++ case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT: ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static uint32_t smu10_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low) ++{ ++ struct smu10_hwmgr *data; ++ ++ if (hwmgr == NULL) ++ return -EINVAL; ++ ++ data = (struct smu10_hwmgr *)(hwmgr->backend); ++ ++ if (low) ++ return data->clock_vol_info.vdd_dep_on_fclk->entries[0].clk; ++ else ++ return data->clock_vol_info.vdd_dep_on_fclk->entries[ ++ data->clock_vol_info.vdd_dep_on_fclk->count - 1].clk; ++} ++ ++static uint32_t smu10_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low) ++{ ++ struct smu10_hwmgr *data; ++ ++ if (hwmgr == NULL) ++ return -EINVAL; ++ ++ data = (struct smu10_hwmgr *)(hwmgr->backend); ++ ++ if (low) ++ return data->gfx_min_freq_limit; ++ else ++ return data->gfx_max_freq_limit; ++} ++ ++static int smu10_dpm_patch_boot_state(struct pp_hwmgr *hwmgr, ++ struct pp_hw_power_state *hw_ps) ++{ ++ return 0; ++} ++ ++static int smu10_dpm_get_pp_table_entry_callback( ++ struct pp_hwmgr *hwmgr, ++ struct pp_hw_power_state *hw_ps, ++ unsigned int index, ++ const void *clock_info) ++{ ++ struct smu10_power_state *smu10_ps = cast_smu10_ps(hw_ps); ++ ++ smu10_ps->levels[index].engine_clock = 0; ++ ++ smu10_ps->levels[index].vddc_index = 0; ++ smu10_ps->level = index + 1; ++ ++ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) { ++ smu10_ps->levels[index].ds_divider_index = 5; ++ smu10_ps->levels[index].ss_divider_index = 5; ++ } ++ ++ return 0; ++} ++ ++static int smu10_dpm_get_num_of_pp_table_entries(struct pp_hwmgr *hwmgr) ++{ ++ int result; ++ unsigned long ret = 0; ++ ++ result = pp_tables_get_num_of_entries(hwmgr, &ret); ++ ++ return result ? 0 : ret; ++} ++ ++static int smu10_dpm_get_pp_table_entry(struct pp_hwmgr *hwmgr, ++ unsigned long entry, struct pp_power_state *ps) ++{ ++ int result; ++ struct smu10_power_state *smu10_ps; ++ ++ ps->hardware.magic = SMU10_Magic; ++ ++ smu10_ps = cast_smu10_ps(&(ps->hardware)); ++ ++ result = pp_tables_get_entry(hwmgr, entry, ps, ++ smu10_dpm_get_pp_table_entry_callback); ++ ++ smu10_ps->uvd_clocks.vclk = ps->uvd_clocks.VCLK; ++ smu10_ps->uvd_clocks.dclk = ps->uvd_clocks.DCLK; ++ ++ return result; ++} ++ ++static int smu10_get_power_state_size(struct pp_hwmgr *hwmgr) ++{ ++ return sizeof(struct smu10_power_state); ++} ++ ++static int smu10_set_cpu_power_state(struct pp_hwmgr *hwmgr) ++{ ++ return 0; ++} ++ ++ ++static int smu10_store_cc6_data(struct pp_hwmgr *hwmgr, uint32_t separation_time, ++ bool cc6_disable, bool pstate_disable, bool pstate_switch_disable) ++{ ++ return 0; ++} ++ ++static int smu10_get_dal_power_level(struct pp_hwmgr *hwmgr, ++ struct amd_pp_simple_clock_info *info) ++{ ++ return -EINVAL; ++} ++ ++static int smu10_force_clock_level(struct pp_hwmgr *hwmgr, ++ enum pp_clock_type type, uint32_t mask) ++{ ++ return 0; ++} ++ ++static int smu10_print_clock_levels(struct pp_hwmgr *hwmgr, ++ enum pp_clock_type type, char *buf) ++{ ++ struct smu10_hwmgr *data = (struct smu10_hwmgr *)(hwmgr->backend); ++ struct smu10_voltage_dependency_table *mclk_table = ++ data->clock_vol_info.vdd_dep_on_fclk; ++ int i, now, size = 0; ++ ++ switch (type) { ++ case PP_SCLK: ++ smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetGfxclkFrequency); ++ now = smum_get_argument(hwmgr); ++ ++ size += sprintf(buf + size, "0: %uMhz %s\n", ++ data->gfx_min_freq_limit / 100, ++ ((data->gfx_min_freq_limit / 100) ++ == now) ? "*" : ""); ++ size += sprintf(buf + size, "1: %uMhz %s\n", ++ data->gfx_max_freq_limit / 100, ++ ((data->gfx_max_freq_limit / 100) ++ == now) ? "*" : ""); ++ break; ++ case PP_MCLK: ++ smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetFclkFrequency); ++ now = smum_get_argument(hwmgr); ++ ++ for (i = 0; i < mclk_table->count; i++) ++ size += sprintf(buf + size, "%d: %uMhz %s\n", ++ i, ++ mclk_table->entries[i].clk / 100, ++ ((mclk_table->entries[i].clk / 100) ++ == now) ? "*" : ""); ++ break; ++ default: ++ break; ++ } ++ ++ return size; ++} ++ ++static int smu10_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state, ++ PHM_PerformanceLevelDesignation designation, uint32_t index, ++ PHM_PerformanceLevel *level) ++{ ++ struct smu10_hwmgr *data; ++ ++ if (level == NULL || hwmgr == NULL || state == NULL) ++ return -EINVAL; ++ ++ data = (struct smu10_hwmgr *)(hwmgr->backend); ++ ++ if (index == 0) { ++ level->memory_clock = data->clock_vol_info.vdd_dep_on_fclk->entries[0].clk; ++ level->coreClock = data->gfx_min_freq_limit; ++ } else { ++ level->memory_clock = data->clock_vol_info.vdd_dep_on_fclk->entries[ ++ data->clock_vol_info.vdd_dep_on_fclk->count - 1].clk; ++ level->coreClock = data->gfx_max_freq_limit; ++ } ++ ++ level->nonLocalMemoryFreq = 0; ++ level->nonLocalMemoryWidth = 0; ++ ++ return 0; ++} ++ ++static int smu10_get_current_shallow_sleep_clocks(struct pp_hwmgr *hwmgr, ++ const struct pp_hw_power_state *state, struct pp_clock_info *clock_info) ++{ ++ const struct smu10_power_state *ps = cast_const_smu10_ps(state); ++ ++ clock_info->min_eng_clk = ps->levels[0].engine_clock / (1 << (ps->levels[0].ss_divider_index)); ++ clock_info->max_eng_clk = ps->levels[ps->level - 1].engine_clock / (1 << (ps->levels[ps->level - 1].ss_divider_index)); ++ ++ return 0; ++} ++ ++#define MEM_FREQ_LOW_LATENCY 25000 ++#define MEM_FREQ_HIGH_LATENCY 80000 ++#define MEM_LATENCY_HIGH 245 ++#define MEM_LATENCY_LOW 35 ++#define MEM_LATENCY_ERR 0xFFFF ++ ++ ++static uint32_t smu10_get_mem_latency(struct pp_hwmgr *hwmgr, ++ uint32_t clock) ++{ ++ if (clock >= MEM_FREQ_LOW_LATENCY && ++ clock < MEM_FREQ_HIGH_LATENCY) ++ return MEM_LATENCY_HIGH; ++ else if (clock >= MEM_FREQ_HIGH_LATENCY) ++ return MEM_LATENCY_LOW; ++ else ++ return MEM_LATENCY_ERR; ++} ++ ++static int smu10_get_clock_by_type_with_latency(struct pp_hwmgr *hwmgr, ++ enum amd_pp_clock_type type, ++ struct pp_clock_levels_with_latency *clocks) ++{ ++ uint32_t i; ++ struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); ++ struct smu10_clock_voltage_information *pinfo = &(smu10_data->clock_vol_info); ++ struct smu10_voltage_dependency_table *pclk_vol_table; ++ bool latency_required = false; ++ ++ if (pinfo == NULL) ++ return -EINVAL; ++ ++ switch (type) { ++ case amd_pp_mem_clock: ++ pclk_vol_table = pinfo->vdd_dep_on_mclk; ++ latency_required = true; ++ break; ++ case amd_pp_f_clock: ++ pclk_vol_table = pinfo->vdd_dep_on_fclk; ++ latency_required = true; ++ break; ++ case amd_pp_dcf_clock: ++ pclk_vol_table = pinfo->vdd_dep_on_dcefclk; ++ break; ++ case amd_pp_disp_clock: ++ pclk_vol_table = pinfo->vdd_dep_on_dispclk; ++ break; ++ case amd_pp_phy_clock: ++ pclk_vol_table = pinfo->vdd_dep_on_phyclk; ++ break; ++ case amd_pp_dpp_clock: ++ pclk_vol_table = pinfo->vdd_dep_on_dppclk; ++ default: ++ return -EINVAL; ++ } ++ ++ if (pclk_vol_table == NULL || pclk_vol_table->count == 0) ++ return -EINVAL; ++ ++ clocks->num_levels = 0; ++ for (i = 0; i < pclk_vol_table->count; i++) { ++ clocks->data[i].clocks_in_khz = pclk_vol_table->entries[i].clk; ++ clocks->data[i].latency_in_us = latency_required ? ++ smu10_get_mem_latency(hwmgr, ++ pclk_vol_table->entries[i].clk) : ++ 0; ++ clocks->num_levels++; ++ } ++ ++ return 0; ++} ++ ++static int smu10_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr, ++ enum amd_pp_clock_type type, ++ struct pp_clock_levels_with_voltage *clocks) ++{ ++ uint32_t i; ++ struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); ++ struct smu10_clock_voltage_information *pinfo = &(smu10_data->clock_vol_info); ++ struct smu10_voltage_dependency_table *pclk_vol_table = NULL; ++ ++ if (pinfo == NULL) ++ return -EINVAL; ++ ++ switch (type) { ++ case amd_pp_mem_clock: ++ pclk_vol_table = pinfo->vdd_dep_on_mclk; ++ break; ++ case amd_pp_f_clock: ++ pclk_vol_table = pinfo->vdd_dep_on_fclk; ++ break; ++ case amd_pp_dcf_clock: ++ pclk_vol_table = pinfo->vdd_dep_on_dcefclk; ++ break; ++ case amd_pp_soc_clock: ++ pclk_vol_table = pinfo->vdd_dep_on_socclk; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (pclk_vol_table == NULL || pclk_vol_table->count == 0) ++ return -EINVAL; ++ ++ clocks->num_levels = 0; ++ for (i = 0; i < pclk_vol_table->count; i++) { ++ clocks->data[i].clocks_in_khz = pclk_vol_table->entries[i].clk; ++ clocks->data[i].voltage_in_mv = pclk_vol_table->entries[i].vol; ++ clocks->num_levels++; ++ } ++ ++ return 0; ++} ++ ++static int smu10_display_clock_voltage_request(struct pp_hwmgr *hwmgr, ++ struct pp_display_clock_request *clock_req) ++{ ++ struct smu10_hwmgr *smu10_data = (struct smu10_hwmgr *)(hwmgr->backend); ++ enum amd_pp_clock_type clk_type = clock_req->clock_type; ++ uint32_t clk_freq = clock_req->clock_freq_in_khz / 1000; ++ PPSMC_Msg msg; ++ ++ switch (clk_type) { ++ case amd_pp_dcf_clock: ++ if (clk_freq == smu10_data->dcf_actual_hard_min_freq) ++ return 0; ++ msg = PPSMC_MSG_SetHardMinDcefclkByFreq; ++ smu10_data->dcf_actual_hard_min_freq = clk_freq; ++ break; ++ case amd_pp_soc_clock: ++ msg = PPSMC_MSG_SetHardMinSocclkByFreq; ++ break; ++ case amd_pp_f_clock: ++ if (clk_freq == smu10_data->f_actual_hard_min_freq) ++ return 0; ++ smu10_data->f_actual_hard_min_freq = clk_freq; ++ msg = PPSMC_MSG_SetHardMinFclkByFreq; ++ break; ++ default: ++ pr_info("[DisplayClockVoltageRequest]Invalid Clock Type!"); ++ return -EINVAL; ++ } ++ ++ smum_send_msg_to_smc_with_parameter(hwmgr, msg, clk_freq); ++ ++ return 0; ++} ++ ++static int smu10_get_max_high_clocks(struct pp_hwmgr *hwmgr, struct amd_pp_simple_clock_info *clocks) ++{ ++ clocks->engine_max_clock = 80000; /* driver can't get engine clock, temp hard code to 800MHz */ ++ return 0; ++} ++ ++static int smu10_thermal_get_temperature(struct pp_hwmgr *hwmgr) ++{ ++ uint32_t reg_offset = soc15_get_register_offset(THM_HWID, 0, ++ mmTHM_TCON_CUR_TMP_BASE_IDX, mmTHM_TCON_CUR_TMP); ++ uint32_t reg_value = cgs_read_register(hwmgr->device, reg_offset); ++ int cur_temp = ++ (reg_value & THM_TCON_CUR_TMP__CUR_TEMP_MASK) >> THM_TCON_CUR_TMP__CUR_TEMP__SHIFT; ++ ++ if (cur_temp & THM_TCON_CUR_TMP__CUR_TEMP_RANGE_SEL_MASK) ++ cur_temp = ((cur_temp / 8) - 49) * PP_TEMPERATURE_UNITS_PER_CENTIGRADES; ++ else ++ cur_temp = (cur_temp / 8) * PP_TEMPERATURE_UNITS_PER_CENTIGRADES; ++ ++ return cur_temp; ++} ++ ++static int smu10_read_sensor(struct pp_hwmgr *hwmgr, int idx, ++ void *value, int *size) ++{ ++ uint32_t sclk, mclk; ++ int ret = 0; ++ ++ switch (idx) { ++ case AMDGPU_PP_SENSOR_GFX_SCLK: ++ smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetGfxclkFrequency); ++ sclk = smum_get_argument(hwmgr); ++ /* in units of 10KHZ */ ++ *((uint32_t *)value) = sclk * 100; ++ *size = 4; ++ break; ++ case AMDGPU_PP_SENSOR_GFX_MCLK: ++ smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetFclkFrequency); ++ mclk = smum_get_argument(hwmgr); ++ /* in units of 10KHZ */ ++ *((uint32_t *)value) = mclk * 100; ++ *size = 4; ++ break; ++ case AMDGPU_PP_SENSOR_GPU_TEMP: ++ *((uint32_t *)value) = smu10_thermal_get_temperature(hwmgr); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++static int smu10_set_mmhub_powergating_by_smu(struct pp_hwmgr *hwmgr) ++{ ++ return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_PowerGateMmHub); ++} ++ ++static const struct pp_hwmgr_func smu10_hwmgr_funcs = { ++ .backend_init = smu10_hwmgr_backend_init, ++ .backend_fini = smu10_hwmgr_backend_fini, ++ .asic_setup = NULL, ++ .apply_state_adjust_rules = smu10_apply_state_adjust_rules, ++ .force_dpm_level = smu10_dpm_force_dpm_level, ++ .get_power_state_size = smu10_get_power_state_size, ++ .powerdown_uvd = NULL, ++ .powergate_uvd = NULL, ++ .powergate_vce = NULL, ++ .get_mclk = smu10_dpm_get_mclk, ++ .get_sclk = smu10_dpm_get_sclk, ++ .patch_boot_state = smu10_dpm_patch_boot_state, ++ .get_pp_table_entry = smu10_dpm_get_pp_table_entry, ++ .get_num_of_pp_table_entries = smu10_dpm_get_num_of_pp_table_entries, ++ .set_cpu_power_state = smu10_set_cpu_power_state, ++ .store_cc6_data = smu10_store_cc6_data, ++ .force_clock_level = smu10_force_clock_level, ++ .print_clock_levels = smu10_print_clock_levels, ++ .get_dal_power_level = smu10_get_dal_power_level, ++ .get_performance_level = smu10_get_performance_level, ++ .get_current_shallow_sleep_clocks = smu10_get_current_shallow_sleep_clocks, ++ .get_clock_by_type_with_latency = smu10_get_clock_by_type_with_latency, ++ .get_clock_by_type_with_voltage = smu10_get_clock_by_type_with_voltage, ++ .get_max_high_clocks = smu10_get_max_high_clocks, ++ .read_sensor = smu10_read_sensor, ++ .set_active_display_count = smu10_set_active_display_count, ++ .set_deep_sleep_dcefclk = smu10_set_deep_sleep_dcefclk, ++ .dynamic_state_management_enable = smu10_enable_dpm_tasks, ++ .power_off_asic = smu10_power_off_asic, ++ .asic_setup = smu10_setup_asic_task, ++ .power_state_set = smu10_set_power_state_tasks, ++ .dynamic_state_management_disable = smu10_disable_dpm_tasks, ++ .set_mmhub_powergating_by_smu = smu10_set_mmhub_powergating_by_smu, ++}; ++ ++int smu10_init_function_pointers(struct pp_hwmgr *hwmgr) ++{ ++ hwmgr->hwmgr_func = &smu10_hwmgr_funcs; ++ hwmgr->pptable_func = &pptable_funcs; ++ return 0; ++} +diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.h +new file mode 100644 +index 0000000..175c3a5 +--- /dev/null ++++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.h +@@ -0,0 +1,322 @@ ++/* ++ * 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 SMU10_HWMGR_H ++#define SMU10_HWMGR_H ++ ++#include "hwmgr.h" ++#include "smu10_inc.h" ++#include "smu10_driver_if.h" ++#include "rv_ppsmc.h" ++ ++ ++#define SMU10_MAX_HARDWARE_POWERLEVELS 8 ++#define SMU10_DYNCLK_NUMBER_OF_TREND_COEFFICIENTS 15 ++ ++#define DPMFlags_SCLK_Enabled 0x00000001 ++#define DPMFlags_UVD_Enabled 0x00000002 ++#define DPMFlags_VCE_Enabled 0x00000004 ++#define DPMFlags_ACP_Enabled 0x00000008 ++#define DPMFlags_ForceHighestValid 0x40000000 ++ ++/* Do not change the following, it is also defined in SMU8.h */ ++#define SMU_EnabledFeatureScoreboard_AcpDpmOn 0x00000001 ++#define SMU_EnabledFeatureScoreboard_SclkDpmOn 0x00200000 ++#define SMU_EnabledFeatureScoreboard_UvdDpmOn 0x01000000 ++#define SMU_EnabledFeatureScoreboard_VceDpmOn 0x02000000 ++ ++#define SMU_PHYID_SHIFT 8 ++ ++#define SMU10_PCIE_POWERGATING_TARGET_GFX 0 ++#define SMU10_PCIE_POWERGATING_TARGET_DDI 1 ++#define SMU10_PCIE_POWERGATING_TARGET_PLLCASCADE 2 ++#define SMU10_PCIE_POWERGATING_TARGET_PHY 3 ++ ++enum VQ_TYPE { ++ CLOCK_TYPE_DCLK = 0L, ++ CLOCK_TYPE_ECLK, ++ CLOCK_TYPE_SCLK, ++ CLOCK_TYPE_CCLK, ++ VQ_GFX_CU ++}; ++ ++#define SUSTAINABLE_SCLK_MASK 0x00ffffff ++#define SUSTAINABLE_SCLK_SHIFT 0 ++#define SUSTAINABLE_CU_MASK 0xff000000 ++#define SUSTAINABLE_CU_SHIFT 24 ++ ++struct smu10_dpm_entry { ++ uint32_t soft_min_clk; ++ uint32_t hard_min_clk; ++ uint32_t soft_max_clk; ++ uint32_t hard_max_clk; ++}; ++ ++struct smu10_power_level { ++ uint32_t engine_clock; ++ uint8_t vddc_index; ++ uint8_t ds_divider_index; ++ uint8_t ss_divider_index; ++ uint8_t allow_gnb_slow; ++ uint8_t force_nbp_state; ++ uint8_t display_wm; ++ uint8_t vce_wm; ++ uint8_t num_simd_to_powerdown; ++ uint8_t hysteresis_up; ++ uint8_t rsv[3]; ++}; ++ ++/*used for the nbpsFlags field in smu10_power state*/ ++#define SMU10_POWERSTATE_FLAGS_NBPS_FORCEHIGH (1<<0) ++#define SMU10_POWERSTATE_FLAGS_NBPS_LOCKTOHIGH (1<<1) ++#define SMU10_POWERSTATE_FLAGS_NBPS_LOCKTOLOW (1<<2) ++ ++#define SMU10_POWERSTATE_FLAGS_BAPM_DISABLE (1<<0) ++ ++struct smu10_uvd_clocks { ++ uint32_t vclk; ++ uint32_t dclk; ++ uint32_t vclk_low_divider; ++ uint32_t vclk_high_divider; ++ uint32_t dclk_low_divider; ++ uint32_t dclk_high_divider; ++}; ++ ++struct pp_disable_nbpslo_flags { ++ union { ++ struct { ++ uint32_t entry : 1; ++ uint32_t display : 1; ++ uint32_t driver: 1; ++ uint32_t vce : 1; ++ uint32_t uvd : 1; ++ uint32_t acp : 1; ++ uint32_t reserved: 26; ++ } bits; ++ uint32_t u32All; ++ }; ++}; ++ ++ ++enum smu10_pstate_previous_action { ++ DO_NOTHING = 1, ++ FORCE_HIGH, ++ CANCEL_FORCE_HIGH ++}; ++ ++struct smu10_power_state { ++ unsigned int magic; ++ uint32_t level; ++ struct smu10_uvd_clocks uvd_clocks; ++ uint32_t evclk; ++ uint32_t ecclk; ++ uint32_t samclk; ++ uint32_t acpclk; ++ bool need_dfs_bypass; ++ ++ uint32_t nbps_flags; ++ uint32_t bapm_flags; ++ uint8_t dpm0_pg_nbps_low; ++ uint8_t dpm0_pg_nbps_high; ++ uint8_t dpm_x_nbps_low; ++ uint8_t dpm_x_nbps_high; ++ ++ enum smu10_pstate_previous_action action; ++ ++ struct smu10_power_level levels[SMU10_MAX_HARDWARE_POWERLEVELS]; ++ struct pp_disable_nbpslo_flags nbpslo_flags; ++}; ++ ++#define SMU10_NUM_NBPSTATES 4 ++#define SMU10_NUM_NBPMEMORYCLOCK 2 ++ ++ ++struct smu10_display_phy_info_entry { ++ uint8_t phy_present; ++ uint8_t active_lane_mapping; ++ uint8_t display_config_type; ++ uint8_t active_num_of_lanes; ++}; ++ ++#define SMU10_MAX_DISPLAYPHY_IDS 10 ++ ++struct smu10_display_phy_info { ++ bool display_phy_access_initialized; ++ struct smu10_display_phy_info_entry entries[SMU10_MAX_DISPLAYPHY_IDS]; ++}; ++ ++#define MAX_DISPLAY_CLOCK_LEVEL 8 ++ ++struct smu10_system_info{ ++ uint8_t htc_tmp_lmt; ++ uint8_t htc_hyst_lmt; ++}; ++ ++#define MAX_REGULAR_DPM_NUMBER 8 ++ ++struct smu10_mclk_latency_entries { ++ uint32_t frequency; ++ uint32_t latency; ++}; ++ ++struct smu10_mclk_latency_table { ++ uint32_t count; ++ struct smu10_mclk_latency_entries entries[MAX_REGULAR_DPM_NUMBER]; ++}; ++ ++struct smu10_clock_voltage_dependency_record { ++ uint32_t clk; ++ uint32_t vol; ++}; ++ ++ ++struct smu10_voltage_dependency_table { ++ uint32_t count; ++ struct smu10_clock_voltage_dependency_record entries[1]; ++}; ++ ++struct smu10_clock_voltage_information { ++ struct smu10_voltage_dependency_table *vdd_dep_on_dcefclk; ++ struct smu10_voltage_dependency_table *vdd_dep_on_socclk; ++ struct smu10_voltage_dependency_table *vdd_dep_on_fclk; ++ struct smu10_voltage_dependency_table *vdd_dep_on_mclk; ++ struct smu10_voltage_dependency_table *vdd_dep_on_dispclk; ++ struct smu10_voltage_dependency_table *vdd_dep_on_dppclk; ++ struct smu10_voltage_dependency_table *vdd_dep_on_phyclk; ++}; ++ ++struct smu10_hwmgr { ++ uint32_t disable_driver_thermal_policy; ++ uint32_t thermal_auto_throttling_treshold; ++ struct smu10_system_info sys_info; ++ struct smu10_mclk_latency_table mclk_latency_table; ++ ++ uint32_t ddi_power_gating_disabled; ++ ++ struct smu10_display_phy_info_entry display_phy_info; ++ uint32_t dce_slow_sclk_threshold; ++ ++ bool disp_clk_bypass; ++ bool disp_clk_bypass_pending; ++ uint32_t bapm_enabled; ++ ++ bool video_start; ++ bool battery_state; ++ ++ uint32_t is_nb_dpm_enabled; ++ uint32_t is_voltage_island_enabled; ++ uint32_t disable_smu_acp_s3_handshake; ++ uint32_t disable_notify_smu_vpu_recovery; ++ bool in_vpu_recovery; ++ bool pg_acp_init; ++ uint8_t disp_config; ++ ++ /* PowerTune */ ++ uint32_t power_containment_features; ++ bool cac_enabled; ++ bool disable_uvd_power_tune_feature; ++ bool enable_bapm_feature; ++ bool enable_tdc_limit_feature; ++ ++ ++ /* SMC SRAM Address of firmware header tables */ ++ uint32_t sram_end; ++ uint32_t dpm_table_start; ++ uint32_t soft_regs_start; ++ ++ /* start of SMU7_Fusion_DpmTable */ ++ ++ uint8_t uvd_level_count; ++ uint8_t vce_level_count; ++ uint8_t acp_level_count; ++ uint8_t samu_level_count; ++ ++ uint32_t fps_high_threshold; ++ uint32_t fps_low_threshold; ++ ++ uint32_t dpm_flags; ++ struct smu10_dpm_entry sclk_dpm; ++ struct smu10_dpm_entry uvd_dpm; ++ struct smu10_dpm_entry vce_dpm; ++ struct smu10_dpm_entry acp_dpm; ++ bool acp_power_up_no_dsp; ++ ++ uint32_t max_sclk_level; ++ uint32_t num_of_clk_entries; ++ ++ /* CPU Power State */ ++ uint32_t separation_time; ++ bool cc6_disable; ++ bool pstate_disable; ++ bool cc6_setting_changed; ++ ++ uint32_t ulTotalActiveCUs; ++ ++ bool isp_tileA_power_gated; ++ bool isp_tileB_power_gated; ++ uint32_t isp_actual_hard_min_freq; ++ uint32_t soc_actual_hard_min_freq; ++ uint32_t dcf_actual_hard_min_freq; ++ ++ uint32_t f_actual_hard_min_freq; ++ uint32_t fabric_actual_soft_min_freq; ++ uint32_t vclk_soft_min; ++ uint32_t dclk_soft_min; ++ uint32_t gfx_actual_soft_min_freq; ++ uint32_t gfx_min_freq_limit; ++ uint32_t gfx_max_freq_limit; ++ ++ bool vcn_power_gated; ++ bool vcn_dpg_mode; ++ ++ bool gfx_off_controled_by_driver; ++ Watermarks_t water_marks_table; ++ struct smu10_clock_voltage_information clock_vol_info; ++ DpmClocks_t clock_table; ++ ++ uint32_t active_process_mask; ++ bool need_min_deep_sleep_dcefclk; ++ uint32_t deep_sleep_dcefclk; ++ uint32_t num_active_display; ++}; ++ ++struct pp_hwmgr; ++ ++int smu10_init_function_pointers(struct pp_hwmgr *hwmgr); ++ ++/* UMD PState SMU10 Msg Parameters in MHz */ ++#define SMU10_UMD_PSTATE_GFXCLK 700 ++#define SMU10_UMD_PSTATE_SOCCLK 626 ++#define SMU10_UMD_PSTATE_FCLK 933 ++#define SMU10_UMD_PSTATE_VCE 0x03C00320 ++ ++#define SMU10_UMD_PSTATE_PEAK_GFXCLK 1100 ++#define SMU10_UMD_PSTATE_PEAK_SOCCLK 757 ++#define SMU10_UMD_PSTATE_PEAK_FCLK 1200 ++ ++#define SMU10_UMD_PSTATE_MIN_GFXCLK 200 ++#define SMU10_UMD_PSTATE_MIN_FCLK 400 ++#define SMU10_UMD_PSTATE_MIN_SOCCLK 200 ++#define SMU10_UMD_PSTATE_MIN_VCE 0x0190012C ++ ++#endif +diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_inc.h b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_inc.h +new file mode 100644 +index 0000000..edb68e3 +--- /dev/null ++++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_inc.h +@@ -0,0 +1,43 @@ ++/* ++ * 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 SMU10_INC_H ++#define SMU10_INC_H ++ ++ ++#include "asic_reg/mp/mp_10_0_default.h" ++#include "asic_reg/mp/mp_10_0_offset.h" ++#include "asic_reg/mp/mp_10_0_sh_mask.h" ++ ++#include "asic_reg/nbio/nbio_7_0_default.h" ++#include "asic_reg/nbio/nbio_7_0_offset.h" ++#include "asic_reg/nbio/nbio_7_0_sh_mask.h" ++ ++#include "asic_reg/thm/thm_10_0_default.h" ++#include "asic_reg/thm/thm_10_0_offset.h" ++#include "asic_reg/thm/thm_10_0_sh_mask.h" ++ ++ ++#define ixDDI_PHY_GEN_STATUS 0x3FCE8 ++ ++#endif +diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +index 494f891..9bdad48 100644 +--- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h ++++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +@@ -820,7 +820,7 @@ extern void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr); + + extern int smu7_init_function_pointers(struct pp_hwmgr *hwmgr); + extern int vega10_hwmgr_init(struct pp_hwmgr *hwmgr); +-extern int rv_init_function_pointers(struct pp_hwmgr *hwmgr); ++extern int smu10_init_function_pointers(struct pp_hwmgr *hwmgr); + + extern int phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type, + uint32_t sclk, uint16_t id, uint16_t *voltage); +diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/Makefile b/drivers/gpu/drm/amd/powerplay/smumgr/Makefile +index 30d3089..c44d792 100644 +--- a/drivers/gpu/drm/amd/powerplay/smumgr/Makefile ++++ b/drivers/gpu/drm/amd/powerplay/smumgr/Makefile +@@ -5,7 +5,7 @@ + + SMU_MGR = smumgr.o cz_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 + + AMD_PP_SMUMGR = $(addprefix $(AMD_PP_PATH)/smumgr/,$(SMU_MGR)) + +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 3dec481..0000000 +--- a/drivers/gpu/drm/amd/powerplay/smumgr/rv_smumgr.c ++++ /dev/null +@@ -1,346 +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" +- +- +-#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 rv_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 rv_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 rv_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 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; +-} +- +- +-static 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; +-} +- +-static 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;); +- rv_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetDriverDramAddrHigh, +- upper_32_bits(priv->smu_tables.entry[table_id].mc_addr)); +- rv_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetDriverDramAddrLow, +- lower_32_bits(priv->smu_tables.entry[table_id].mc_addr)); +- rv_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 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); +- +- rv_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetDriverDramAddrHigh, +- upper_32_bits(priv->smu_tables.entry[table_id].mc_addr)); +- rv_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_SetDriverDramAddrLow, +- lower_32_bits(priv->smu_tables.entry[table_id].mc_addr)); +- rv_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_TransferTableDram2Smu, +- priv->smu_tables.entry[table_id].table_id); +- +- return 0; +-} +- +-static int rv_verify_smc_interface(struct pp_hwmgr *hwmgr) +-{ +- uint32_t smc_driver_if_version; +- +- rv_send_msg_to_smc(hwmgr, +- PPSMC_MSG_GetDriverIfVersion); +- smc_driver_if_version = rv_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 rv_smc_enable_sdma(struct pp_hwmgr *hwmgr) +-{ +- rv_send_msg_to_smc(hwmgr, +- PPSMC_MSG_PowerUpSdma); +-} +- +-static void rv_smc_disable_sdma(struct pp_hwmgr *hwmgr) +-{ +- rv_send_msg_to_smc(hwmgr, +- PPSMC_MSG_PowerDownSdma); +-} +- +-/* vcn is disabled by default in vbios, need to re-enable in driver */ +-static void rv_smc_enable_vcn(struct pp_hwmgr *hwmgr) +-{ +- rv_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_PowerUpVcn, 0); +-} +- +-static void rv_smc_disable_vcn(struct pp_hwmgr *hwmgr) +-{ +- rv_send_msg_to_smc_with_parameter(hwmgr, +- PPSMC_MSG_PowerDownVcn, 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); +- 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 rv_start_smu(struct pp_hwmgr *hwmgr) +-{ +- struct cgs_firmware_info info = {0}; +- +- smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetSmuVersion); +- hwmgr->smu_version = rv_read_arg_from_smc(hwmgr); +- 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; +- rv_smc_enable_sdma(hwmgr); +- rv_smc_enable_vcn(hwmgr); +- return 0; +-} +- +-static int rv_smu_init(struct pp_hwmgr *hwmgr) +-{ +- struct rv_smumgr *priv; +- int r; +- +- priv = kzalloc(sizeof(struct rv_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 rv_smc_table_manager(struct pp_hwmgr *hwmgr, uint8_t *table, uint16_t table_id, bool rw) +-{ +- int ret; +- +- if (rw) +- ret = rv_copy_table_from_smc(hwmgr, table, table_id); +- else +- ret = rv_copy_table_to_smc(hwmgr, table, table_id); +- +- return ret; +-} +- +- +-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, +- .get_argument = rv_read_arg_from_smc, +- .smc_table_manager = rv_smc_table_manager, +-}; +- +- +diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/rv_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/rv_smumgr.h +deleted file mode 100644 +index 7b53798..0000000 +--- a/drivers/gpu/drm/amd/powerplay/smumgr/rv_smumgr.h ++++ /dev/null +@@ -1,50 +0,0 @@ +-/* +- * 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 PP_RAVEN_SMUMANAGER_H +-#define PP_RAVEN_SMUMANAGER_H +- +-#include "rv_ppsmc.h" +-#include "smu10_driver_if.h" +- +-#define MAX_SMU_TABLE 2 +- +-struct smu_table_entry { +- uint32_t version; +- uint32_t size; +- uint32_t table_id; +- 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 smu_table_array smu_tables; +-}; +- +- +-#endif +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 0000000..bef0b2d +--- /dev/null ++++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.c +@@ -0,0 +1,346 @@ ++/* ++ * 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 cgs_firmware_info info = {0}; ++ ++ smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetSmuVersion); ++ hwmgr->smu_version = smu10_read_arg_from_smc(hwmgr); ++ info.version = hwmgr->smu_version >> 8; ++ ++ cgs_get_firmware_info(hwmgr->device, CGS_UCODE_ID_SMU, &info); ++ ++ 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/smu10_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.h +new file mode 100644 +index 0000000..9c2be74 +--- /dev/null ++++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.h +@@ -0,0 +1,50 @@ ++/* ++ * 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 PP_SMU10_SMUMANAGER_H ++#define PP_SMU10_SMUMANAGER_H ++ ++#include "rv_ppsmc.h" ++#include "smu10_driver_if.h" ++ ++#define MAX_SMU_TABLE 2 ++ ++struct smu_table_entry { ++ uint32_t version; ++ uint32_t size; ++ uint32_t table_id; ++ uint64_t mc_addr; ++ void *table; ++ struct amdgpu_bo *handle; ++}; ++ ++struct smu_table_array { ++ struct smu_table_entry entry[MAX_SMU_TABLE]; ++}; ++ ++struct smu10_smumgr { ++ struct smu_table_array smu_tables; ++}; ++ ++ ++#endif +-- +2.7.4 + |