|
@@ -28,12 +28,23 @@
|
|
|
#include "processpptables.h"
|
|
|
#include "cgs_common.h"
|
|
|
#include "smu/smu_8_0_d.h"
|
|
|
+#include "smu8_fusion.h"
|
|
|
+#include "smu/smu_8_0_sh_mask.h"
|
|
|
#include "smumgr.h"
|
|
|
#include "hwmgr.h"
|
|
|
#include "hardwaremanager.h"
|
|
|
#include "cz_ppsmc.h"
|
|
|
#include "cz_hwmgr.h"
|
|
|
#include "power_state.h"
|
|
|
+#include "cz_clockpowergating.h"
|
|
|
+
|
|
|
+
|
|
|
+#define ixSMUSVI_NB_CURRENTVID 0xD8230044
|
|
|
+#define CURRENT_NB_VID_MASK 0xff000000
|
|
|
+#define CURRENT_NB_VID__SHIFT 24
|
|
|
+#define ixSMUSVI_GFX_CURRENTVID 0xD8230048
|
|
|
+#define CURRENT_GFX_VID_MASK 0xff000000
|
|
|
+#define CURRENT_GFX_VID__SHIFT 24
|
|
|
|
|
|
static const unsigned long PhwCz_Magic = (unsigned long) PHM_Cz_Magic;
|
|
|
|
|
@@ -45,6 +56,46 @@ static struct cz_power_state *cast_PhwCzPowerState(struct pp_hw_power_state *hw_
|
|
|
return (struct cz_power_state *)hw_ps;
|
|
|
}
|
|
|
|
|
|
+static const struct cz_power_state *cast_const_PhwCzPowerState(
|
|
|
+ const struct pp_hw_power_state *hw_ps)
|
|
|
+{
|
|
|
+ if (PhwCz_Magic != hw_ps->magic)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ return (struct cz_power_state *)hw_ps;
|
|
|
+}
|
|
|
+
|
|
|
+uint32_t cz_get_eclk_level(struct pp_hwmgr *hwmgr,
|
|
|
+ uint32_t clock, uint32_t msg)
|
|
|
+{
|
|
|
+ int i = 0;
|
|
|
+ struct phm_vce_clock_voltage_dependency_table *ptable =
|
|
|
+ hwmgr->dyn_state.vce_clocl_voltage_dependency_table;
|
|
|
+
|
|
|
+ switch (msg) {
|
|
|
+ case PPSMC_MSG_SetEclkSoftMin:
|
|
|
+ case PPSMC_MSG_SetEclkHardMin:
|
|
|
+ for (i = 0; i < (int)ptable->count; i++) {
|
|
|
+ if (clock <= ptable->entries[i].ecclk)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case PPSMC_MSG_SetEclkSoftMax:
|
|
|
+ case PPSMC_MSG_SetEclkHardMax:
|
|
|
+ for (i = ptable->count - 1; i >= 0; i--) {
|
|
|
+ if (clock >= ptable->entries[i].ecclk)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return i;
|
|
|
+}
|
|
|
+
|
|
|
static uint32_t cz_get_sclk_level(struct pp_hwmgr *hwmgr,
|
|
|
uint32_t clock, uint32_t msg)
|
|
|
{
|
|
@@ -75,6 +126,37 @@ static uint32_t cz_get_sclk_level(struct pp_hwmgr *hwmgr,
|
|
|
return i;
|
|
|
}
|
|
|
|
|
|
+static uint32_t cz_get_uvd_level(struct pp_hwmgr *hwmgr,
|
|
|
+ uint32_t clock, uint32_t msg)
|
|
|
+{
|
|
|
+ int i = 0;
|
|
|
+ struct phm_uvd_clock_voltage_dependency_table *ptable =
|
|
|
+ hwmgr->dyn_state.uvd_clocl_voltage_dependency_table;
|
|
|
+
|
|
|
+ switch (msg) {
|
|
|
+ case PPSMC_MSG_SetUvdSoftMin:
|
|
|
+ case PPSMC_MSG_SetUvdHardMin:
|
|
|
+ for (i = 0; i < (int)ptable->count; i++) {
|
|
|
+ if (clock <= ptable->entries[i].vclk)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case PPSMC_MSG_SetUvdSoftMax:
|
|
|
+ case PPSMC_MSG_SetUvdHardMax:
|
|
|
+ for (i = ptable->count - 1; i >= 0; i--) {
|
|
|
+ if (clock >= ptable->entries[i].vclk)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return i;
|
|
|
+}
|
|
|
+
|
|
|
static uint32_t cz_get_max_sclk_level(struct pp_hwmgr *hwmgr)
|
|
|
{
|
|
|
struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
|
|
@@ -504,6 +586,175 @@ static int cz_tf_init_sclk_threshold(struct pp_hwmgr *hwmgr, void *input,
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
+static int cz_tf_update_sclk_limit(struct pp_hwmgr *hwmgr,
|
|
|
+ void *input, void *output,
|
|
|
+ void *storage, int result)
|
|
|
+{
|
|
|
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
|
|
|
+ struct phm_clock_voltage_dependency_table *table =
|
|
|
+ hwmgr->dyn_state.vddc_dependency_on_sclk;
|
|
|
+
|
|
|
+ unsigned long clock = 0;
|
|
|
+ unsigned long level;
|
|
|
+ unsigned long stable_pstate_sclk;
|
|
|
+ struct PP_Clocks clocks;
|
|
|
+ unsigned long percentage;
|
|
|
+
|
|
|
+ cz_hwmgr->sclk_dpm.soft_min_clk = table->entries[0].clk;
|
|
|
+ level = cz_get_max_sclk_level(hwmgr) - 1;
|
|
|
+
|
|
|
+ if (level < table->count)
|
|
|
+ cz_hwmgr->sclk_dpm.soft_max_clk = table->entries[level].clk;
|
|
|
+ else
|
|
|
+ cz_hwmgr->sclk_dpm.soft_max_clk = table->entries[table->count - 1].clk;
|
|
|
+
|
|
|
+ /*PECI_GetMinClockSettings(pHwMgr->pPECI, &clocks);*/
|
|
|
+ clock = clocks.engineClock;
|
|
|
+
|
|
|
+ if (cz_hwmgr->sclk_dpm.hard_min_clk != clock) {
|
|
|
+ cz_hwmgr->sclk_dpm.hard_min_clk = clock;
|
|
|
+
|
|
|
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
|
|
+ PPSMC_MSG_SetSclkHardMin,
|
|
|
+ cz_get_sclk_level(hwmgr,
|
|
|
+ cz_hwmgr->sclk_dpm.hard_min_clk,
|
|
|
+ PPSMC_MSG_SetSclkHardMin));
|
|
|
+ }
|
|
|
+
|
|
|
+ clock = cz_hwmgr->sclk_dpm.soft_min_clk;
|
|
|
+
|
|
|
+ /* update minimum clocks for Stable P-State feature */
|
|
|
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
|
|
+ PHM_PlatformCaps_StablePState)) {
|
|
|
+ percentage = 75;
|
|
|
+ /*Sclk - calculate sclk value based on percentage and find FLOOR sclk from VddcDependencyOnSCLK table */
|
|
|
+ stable_pstate_sclk = (hwmgr->dyn_state.max_clock_voltage_on_ac.mclk *
|
|
|
+ percentage) / 100;
|
|
|
+
|
|
|
+ if (clock < stable_pstate_sclk)
|
|
|
+ clock = stable_pstate_sclk;
|
|
|
+ } else {
|
|
|
+ if (clock < hwmgr->gfx_arbiter.sclk)
|
|
|
+ clock = hwmgr->gfx_arbiter.sclk;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (cz_hwmgr->sclk_dpm.soft_min_clk != clock) {
|
|
|
+ cz_hwmgr->sclk_dpm.soft_min_clk = clock;
|
|
|
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
|
|
+ PPSMC_MSG_SetSclkSoftMin,
|
|
|
+ cz_get_sclk_level(hwmgr,
|
|
|
+ cz_hwmgr->sclk_dpm.soft_min_clk,
|
|
|
+ PPSMC_MSG_SetSclkSoftMin));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
|
|
+ PHM_PlatformCaps_StablePState) &&
|
|
|
+ cz_hwmgr->sclk_dpm.soft_max_clk != clock) {
|
|
|
+ cz_hwmgr->sclk_dpm.soft_max_clk = clock;
|
|
|
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
|
|
+ PPSMC_MSG_SetSclkSoftMax,
|
|
|
+ cz_get_sclk_level(hwmgr,
|
|
|
+ cz_hwmgr->sclk_dpm.soft_max_clk,
|
|
|
+ PPSMC_MSG_SetSclkSoftMax));
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int cz_tf_set_deep_sleep_sclk_threshold(struct pp_hwmgr *hwmgr,
|
|
|
+ void *input, void *output,
|
|
|
+ void *storage, int result)
|
|
|
+{
|
|
|
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
|
|
+ PHM_PlatformCaps_SclkDeepSleep)) {
|
|
|
+ /* TO DO get from dal PECI_GetMinClockSettings(pHwMgr->pPECI, &clocks); */
|
|
|
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
|
|
+ PPSMC_MSG_SetMinDeepSleepSclk,
|
|
|
+ CZ_MIN_DEEP_SLEEP_SCLK);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int cz_tf_set_watermark_threshold(struct pp_hwmgr *hwmgr,
|
|
|
+ void *input, void *output,
|
|
|
+ void *storage, int result)
|
|
|
+{
|
|
|
+ struct cz_hwmgr *cz_hwmgr =
|
|
|
+ (struct cz_hwmgr *)(hwmgr->backend);
|
|
|
+
|
|
|
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
|
|
+ PPSMC_MSG_SetWatermarkFrequency,
|
|
|
+ cz_hwmgr->sclk_dpm.soft_max_clk);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int cz_tf_set_enabled_levels(struct pp_hwmgr *hwmgr,
|
|
|
+ void *input, void *output,
|
|
|
+ void *storage, int result)
|
|
|
+{
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int cz_tf_enable_nb_dpm(struct pp_hwmgr *hwmgr,
|
|
|
+ void *input, void *output,
|
|
|
+ void *storage, int result)
|
|
|
+{
|
|
|
+ int ret = 0;
|
|
|
+ struct cz_hwmgr *cz_hwmgr =
|
|
|
+ (struct cz_hwmgr *)(hwmgr->backend);
|
|
|
+ unsigned long dpm_features = 0;
|
|
|
+
|
|
|
+ if (!cz_hwmgr->is_nb_dpm_enabled &&
|
|
|
+ cz_hwmgr->is_nb_dpm_enabled_by_driver) { /* also depend on dal NBPStateDisableRequired */
|
|
|
+ dpm_features |= NB_DPM_MASK;
|
|
|
+ ret = smum_send_msg_to_smc_with_parameter(
|
|
|
+ hwmgr->smumgr,
|
|
|
+ PPSMC_MSG_EnableAllSmuFeatures,
|
|
|
+ dpm_features);
|
|
|
+ if (ret == 0)
|
|
|
+ cz_hwmgr->is_nb_dpm_enabled = true;
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int cz_tf_update_low_mem_pstate(struct pp_hwmgr *hwmgr,
|
|
|
+ void *input, void *output,
|
|
|
+ void *storage, int result)
|
|
|
+{
|
|
|
+
|
|
|
+ struct cz_hwmgr *cz_hwmgr =
|
|
|
+ (struct cz_hwmgr *)(hwmgr->backend);
|
|
|
+ const struct phm_set_power_state_input *states = (struct phm_set_power_state_input *)input;
|
|
|
+ const struct cz_power_state *pnew_state = cast_const_PhwCzPowerState(states->pnew_state);
|
|
|
+
|
|
|
+ if (cz_hwmgr->sys_info.nb_dpm_enable) {
|
|
|
+ if (pnew_state->action == FORCE_HIGH)
|
|
|
+ smum_send_msg_to_smc(hwmgr->smumgr,
|
|
|
+ PPSMC_MSG_DisableLowMemoryPstate);
|
|
|
+ else
|
|
|
+ smum_send_msg_to_smc(hwmgr->smumgr,
|
|
|
+ PPSMC_MSG_EnableLowMemoryPstate);
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static struct phm_master_table_item cz_set_power_state_list[] = {
|
|
|
+ {NULL, cz_tf_update_sclk_limit},
|
|
|
+ {NULL, cz_tf_set_deep_sleep_sclk_threshold},
|
|
|
+ {NULL, cz_tf_set_watermark_threshold},
|
|
|
+ {NULL, cz_tf_set_enabled_levels},
|
|
|
+ {NULL, cz_tf_enable_nb_dpm},
|
|
|
+ {NULL, cz_tf_update_low_mem_pstate},
|
|
|
+ {NULL, NULL}
|
|
|
+};
|
|
|
+
|
|
|
+static struct phm_master_table_header cz_set_power_state_master = {
|
|
|
+ 0,
|
|
|
+ PHM_MasterTableFlag_None,
|
|
|
+ cz_set_power_state_list
|
|
|
+};
|
|
|
|
|
|
static struct phm_master_table_item cz_setup_asic_list[] = {
|
|
|
{NULL, cz_tf_reset_active_process_mask},
|
|
@@ -649,6 +900,56 @@ static struct phm_master_table_header cz_enable_dpm_master = {
|
|
|
cz_enable_dpm_list
|
|
|
};
|
|
|
|
|
|
+static int cz_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
|
|
|
+ struct pp_power_state *prequest_ps,
|
|
|
+ const struct pp_power_state *pcurrent_ps)
|
|
|
+{
|
|
|
+ struct cz_power_state *cz_ps =
|
|
|
+ cast_PhwCzPowerState(&prequest_ps->hardware);
|
|
|
+
|
|
|
+ const struct cz_power_state *cz_current_ps =
|
|
|
+ cast_const_PhwCzPowerState(&pcurrent_ps->hardware);
|
|
|
+
|
|
|
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
|
|
|
+ struct PP_Clocks clocks;
|
|
|
+ bool force_high;
|
|
|
+ unsigned long num_of_active_displays = 4;
|
|
|
+
|
|
|
+ cz_ps->evclk = hwmgr->vce_arbiter.evclk;
|
|
|
+ cz_ps->ecclk = hwmgr->vce_arbiter.ecclk;
|
|
|
+
|
|
|
+ cz_ps->need_dfs_bypass = true;
|
|
|
+
|
|
|
+ cz_hwmgr->video_start = (hwmgr->uvd_arbiter.vclk != 0 || hwmgr->uvd_arbiter.dclk != 0 ||
|
|
|
+ hwmgr->vce_arbiter.evclk != 0 || hwmgr->vce_arbiter.ecclk != 0);
|
|
|
+
|
|
|
+ cz_hwmgr->battery_state = (PP_StateUILabel_Battery == prequest_ps->classification.ui_label);
|
|
|
+
|
|
|
+ /* to do PECI_GetMinClockSettings(pHwMgr->pPECI, &clocks); */
|
|
|
+ /* PECI_GetNumberOfActiveDisplays(pHwMgr->pPECI, &numOfActiveDisplays); */
|
|
|
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_StablePState))
|
|
|
+ clocks.memoryClock = hwmgr->dyn_state.max_clock_voltage_on_ac.mclk;
|
|
|
+ else
|
|
|
+ clocks.memoryClock = 0;
|
|
|
+
|
|
|
+ if (clocks.memoryClock < hwmgr->gfx_arbiter.mclk)
|
|
|
+ clocks.memoryClock = hwmgr->gfx_arbiter.mclk;
|
|
|
+
|
|
|
+ force_high = (clocks.memoryClock > cz_hwmgr->sys_info.nbp_memory_clock[CZ_NUM_NBPMEMORYCLOCK - 1])
|
|
|
+ || (num_of_active_displays >= 3);
|
|
|
+
|
|
|
+ cz_ps->action = cz_current_ps->action;
|
|
|
+
|
|
|
+ if ((force_high == false) && (cz_ps->action == FORCE_HIGH))
|
|
|
+ cz_ps->action = CANCEL_FORCE_HIGH;
|
|
|
+ else if ((force_high == true) && (cz_ps->action != FORCE_HIGH))
|
|
|
+ cz_ps->action = FORCE_HIGH;
|
|
|
+ else
|
|
|
+ cz_ps->action = DO_NOTHING;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int cz_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
|
|
|
{
|
|
|
int result = 0;
|
|
@@ -676,10 +977,28 @@ static int cz_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
|
|
|
|
|
|
result = phm_construct_table(hwmgr, &cz_disable_dpm_master,
|
|
|
&(hwmgr->disable_dynamic_state_management));
|
|
|
-
|
|
|
+ if (result != 0) {
|
|
|
+ printk(KERN_ERR "[ powerplay ] Fail to disable_dynamic_state\n");
|
|
|
+ return result;
|
|
|
+ }
|
|
|
result = phm_construct_table(hwmgr, &cz_enable_dpm_master,
|
|
|
&(hwmgr->enable_dynamic_state_management));
|
|
|
+ if (result != 0) {
|
|
|
+ printk(KERN_ERR "[ powerplay ] Fail to enable_dynamic_state\n");
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ result = phm_construct_table(hwmgr, &cz_set_power_state_master,
|
|
|
+ &(hwmgr->set_power_state));
|
|
|
+ if (result != 0) {
|
|
|
+ printk(KERN_ERR "[ powerplay ] Fail to construct set_power_state\n");
|
|
|
+ return result;
|
|
|
+ }
|
|
|
|
|
|
+ result = phm_construct_table(hwmgr, &cz_phm_enable_clock_power_gatings_master, &(hwmgr->enable_clock_power_gatings));
|
|
|
+ if (result != 0) {
|
|
|
+ printk(KERN_ERR "[ powerplay ] Fail to construct enable_clock_power_gatings\n");
|
|
|
+ return result;
|
|
|
+ }
|
|
|
return result;
|
|
|
}
|
|
|
|
|
@@ -793,6 +1112,138 @@ static int cz_dpm_force_dpm_level(struct pp_hwmgr *hwmgr,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+int cz_dpm_powerdown_uvd(struct pp_hwmgr *hwmgr)
|
|
|
+{
|
|
|
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
|
|
+ PHM_PlatformCaps_UVDPowerGating))
|
|
|
+ return smum_send_msg_to_smc(hwmgr->smumgr,
|
|
|
+ PPSMC_MSG_UVDPowerOFF);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int cz_dpm_powerup_uvd(struct pp_hwmgr *hwmgr)
|
|
|
+{
|
|
|
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
|
|
+ PHM_PlatformCaps_UVDPowerGating)) {
|
|
|
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
|
|
+ PHM_PlatformCaps_UVDDynamicPowerGating)) {
|
|
|
+ return smum_send_msg_to_smc_with_parameter(
|
|
|
+ hwmgr->smumgr,
|
|
|
+ PPSMC_MSG_UVDPowerON, 1);
|
|
|
+ } else {
|
|
|
+ return smum_send_msg_to_smc_with_parameter(
|
|
|
+ hwmgr->smumgr,
|
|
|
+ PPSMC_MSG_UVDPowerON, 0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int cz_dpm_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate)
|
|
|
+{
|
|
|
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
|
|
|
+ struct phm_uvd_clock_voltage_dependency_table *ptable =
|
|
|
+ hwmgr->dyn_state.uvd_clocl_voltage_dependency_table;
|
|
|
+
|
|
|
+ if (!bgate) {
|
|
|
+ /* Stable Pstate is enabled and we need to set the UVD DPM to highest level */
|
|
|
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
|
|
+ PHM_PlatformCaps_StablePState)) {
|
|
|
+ cz_hwmgr->uvd_dpm.hard_min_clk =
|
|
|
+ ptable->entries[ptable->count - 1].vclk;
|
|
|
+
|
|
|
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
|
|
+ PPSMC_MSG_SetUvdHardMin,
|
|
|
+ cz_get_uvd_level(hwmgr,
|
|
|
+ cz_hwmgr->uvd_dpm.hard_min_clk,
|
|
|
+ PPSMC_MSG_SetUvdHardMin));
|
|
|
+
|
|
|
+ cz_enable_disable_uvd_dpm(hwmgr, true);
|
|
|
+ } else
|
|
|
+ cz_enable_disable_uvd_dpm(hwmgr, true);
|
|
|
+ } else
|
|
|
+ cz_enable_disable_uvd_dpm(hwmgr, false);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int cz_dpm_update_vce_dpm(struct pp_hwmgr *hwmgr)
|
|
|
+{
|
|
|
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
|
|
|
+ struct phm_vce_clock_voltage_dependency_table *ptable =
|
|
|
+ hwmgr->dyn_state.vce_clocl_voltage_dependency_table;
|
|
|
+
|
|
|
+ /* Stable Pstate is enabled and we need to set the VCE DPM to highest level */
|
|
|
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
|
|
+ PHM_PlatformCaps_StablePState)) {
|
|
|
+ cz_hwmgr->vce_dpm.hard_min_clk =
|
|
|
+ ptable->entries[ptable->count - 1].ecclk;
|
|
|
+
|
|
|
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
|
|
+ PPSMC_MSG_SetEclkHardMin,
|
|
|
+ cz_get_eclk_level(hwmgr,
|
|
|
+ cz_hwmgr->vce_dpm.hard_min_clk,
|
|
|
+ PPSMC_MSG_SetEclkHardMin));
|
|
|
+ } else {
|
|
|
+ /*EPR# 419220 -HW limitation to to */
|
|
|
+ cz_hwmgr->vce_dpm.hard_min_clk = hwmgr->vce_arbiter.ecclk;
|
|
|
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
|
|
|
+ PPSMC_MSG_SetEclkHardMin,
|
|
|
+ cz_get_eclk_level(hwmgr,
|
|
|
+ cz_hwmgr->vce_dpm.hard_min_clk,
|
|
|
+ PPSMC_MSG_SetEclkHardMin));
|
|
|
+
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int cz_dpm_powerdown_vce(struct pp_hwmgr *hwmgr)
|
|
|
+{
|
|
|
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
|
|
+ PHM_PlatformCaps_VCEPowerGating))
|
|
|
+ return smum_send_msg_to_smc(hwmgr->smumgr,
|
|
|
+ PPSMC_MSG_VCEPowerOFF);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int cz_dpm_powerup_vce(struct pp_hwmgr *hwmgr)
|
|
|
+{
|
|
|
+ if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
|
|
|
+ PHM_PlatformCaps_VCEPowerGating))
|
|
|
+ return smum_send_msg_to_smc(hwmgr->smumgr,
|
|
|
+ PPSMC_MSG_VCEPowerON);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int cz_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
|
|
|
+{
|
|
|
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
|
|
|
+
|
|
|
+ return cz_hwmgr->sys_info.bootup_uma_clock;
|
|
|
+}
|
|
|
+
|
|
|
+static int cz_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low)
|
|
|
+{
|
|
|
+ struct pp_power_state *ps;
|
|
|
+ struct cz_power_state *cz_ps;
|
|
|
+
|
|
|
+ if (hwmgr == NULL)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ ps = hwmgr->request_ps;
|
|
|
+
|
|
|
+ if (ps == NULL)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ cz_ps = cast_PhwCzPowerState(&ps->hardware);
|
|
|
+
|
|
|
+ if (low)
|
|
|
+ return cz_ps->levels[0].engineClock;
|
|
|
+ else
|
|
|
+ return cz_ps->levels[cz_ps->level-1].engineClock;
|
|
|
+}
|
|
|
+
|
|
|
static int cz_dpm_patch_boot_state(struct pp_hwmgr *hwmgr,
|
|
|
struct pp_hw_power_state *hw_ps)
|
|
|
{
|
|
@@ -871,15 +1322,83 @@ int cz_get_power_state_size(struct pp_hwmgr *hwmgr)
|
|
|
return sizeof(struct cz_power_state);
|
|
|
}
|
|
|
|
|
|
+static void
|
|
|
+cz_print_current_perforce_level(struct pp_hwmgr *hwmgr, struct seq_file *m)
|
|
|
+{
|
|
|
+ struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
|
|
|
+
|
|
|
+ struct phm_clock_voltage_dependency_table *table =
|
|
|
+ hwmgr->dyn_state.vddc_dependency_on_sclk;
|
|
|
+
|
|
|
+ struct phm_vce_clock_voltage_dependency_table *vce_table =
|
|
|
+ hwmgr->dyn_state.vce_clocl_voltage_dependency_table;
|
|
|
+
|
|
|
+ struct phm_uvd_clock_voltage_dependency_table *uvd_table =
|
|
|
+ hwmgr->dyn_state.uvd_clocl_voltage_dependency_table;
|
|
|
+
|
|
|
+ uint32_t sclk_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX),
|
|
|
+ TARGET_AND_CURRENT_PROFILE_INDEX, CURR_SCLK_INDEX);
|
|
|
+ uint32_t uvd_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX_2),
|
|
|
+ TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_UVD_INDEX);
|
|
|
+ uint32_t vce_index = PHM_GET_FIELD(cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixTARGET_AND_CURRENT_PROFILE_INDEX_2),
|
|
|
+ TARGET_AND_CURRENT_PROFILE_INDEX_2, CURR_VCE_INDEX);
|
|
|
+
|
|
|
+ uint32_t sclk, vclk, dclk, ecclk, tmp;
|
|
|
+ uint16_t vddnb, vddgfx;
|
|
|
+
|
|
|
+ if (sclk_index >= NUM_SCLK_LEVELS) {
|
|
|
+ seq_printf(m, "\n invalid sclk dpm profile %d\n", sclk_index);
|
|
|
+ } else {
|
|
|
+ sclk = table->entries[sclk_index].clk;
|
|
|
+ seq_printf(m, "\n index: %u sclk: %u MHz\n", sclk_index, sclk/100);
|
|
|
+ }
|
|
|
+
|
|
|
+ tmp = (cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixSMUSVI_NB_CURRENTVID) &
|
|
|
+ CURRENT_NB_VID_MASK) >> CURRENT_NB_VID__SHIFT;
|
|
|
+ vddnb = cz_convert_8Bit_index_to_voltage(hwmgr, tmp);
|
|
|
+ tmp = (cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixSMUSVI_GFX_CURRENTVID) &
|
|
|
+ CURRENT_GFX_VID_MASK) >> CURRENT_GFX_VID__SHIFT;
|
|
|
+ vddgfx = cz_convert_8Bit_index_to_voltage(hwmgr, (u16)tmp);
|
|
|
+ seq_printf(m, "\n vddnb: %u vddgfx: %u\n", vddnb, vddgfx);
|
|
|
+
|
|
|
+ seq_printf(m, "\n uvd %sabled\n", cz_hwmgr->uvd_power_gated ? "dis" : "en");
|
|
|
+ if (!cz_hwmgr->uvd_power_gated) {
|
|
|
+ if (uvd_index >= CZ_MAX_HARDWARE_POWERLEVELS) {
|
|
|
+ seq_printf(m, "\n invalid uvd dpm level %d\n", uvd_index);
|
|
|
+ } else {
|
|
|
+ vclk = uvd_table->entries[uvd_index].vclk;
|
|
|
+ dclk = uvd_table->entries[uvd_index].dclk;
|
|
|
+ seq_printf(m, "\n index: %u uvd vclk: %u MHz dclk: %u MHz\n", uvd_index, vclk/100, dclk/100);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ seq_printf(m, "\n vce %sabled\n", cz_hwmgr->vce_power_gated ? "dis" : "en");
|
|
|
+ if (!cz_hwmgr->vce_power_gated) {
|
|
|
+ if (vce_index >= CZ_MAX_HARDWARE_POWERLEVELS) {
|
|
|
+ seq_printf(m, "\n invalid vce dpm level %d\n", vce_index);
|
|
|
+ } else {
|
|
|
+ ecclk = vce_table->entries[vce_index].ecclk;
|
|
|
+ seq_printf(m, "\n index: %u vce ecclk: %u MHz\n", vce_index, ecclk/100);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static const struct pp_hwmgr_func cz_hwmgr_funcs = {
|
|
|
.backend_init = cz_hwmgr_backend_init,
|
|
|
.backend_fini = cz_hwmgr_backend_fini,
|
|
|
.asic_setup = NULL,
|
|
|
+ .apply_state_adjust_rules = cz_apply_state_adjust_rules,
|
|
|
.force_dpm_level = cz_dpm_force_dpm_level,
|
|
|
.get_power_state_size = cz_get_power_state_size,
|
|
|
+ .powerdown_uvd = cz_dpm_powerdown_uvd,
|
|
|
+ .powergate_uvd = cz_dpm_powergate_uvd,
|
|
|
+ .powergate_vce = cz_dpm_powergate_vce,
|
|
|
+ .get_mclk = cz_dpm_get_mclk,
|
|
|
+ .get_sclk = cz_dpm_get_sclk,
|
|
|
.patch_boot_state = cz_dpm_patch_boot_state,
|
|
|
.get_pp_table_entry = cz_dpm_get_pp_table_entry,
|
|
|
.get_num_of_pp_table_entries = cz_dpm_get_num_of_pp_table_entries,
|
|
|
+ .print_current_perforce_level = cz_print_current_perforce_level,
|
|
|
};
|
|
|
|
|
|
int cz_hwmgr_init(struct pp_hwmgr *hwmgr)
|