Skip to content

Commit

Permalink
drm/amdgpu: enable uvd dpm and powergating
Browse files Browse the repository at this point in the history
Enable UVD dpm (dynamic power management) and powergating.  UVD dpm dynamically scales the UVD
clocks on demand.  Powergating turns off the power to the block when it's not in use.

Signed-off-by: Sonny Jiang <sonny.jiang@amd.com>
Acked-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
  • Loading branch information
Sonny Jiang authored and Alex Deucher committed Jun 4, 2015
1 parent 5bbc553 commit 564ea79
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 3 deletions.
90 changes: 88 additions & 2 deletions drivers/gpu/drm/amd/amdgpu/cz_dpm.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
#include "bif/bif_5_1_d.h"
#include "gfx_v8_0.h"

static void cz_dpm_powergate_uvd(struct amdgpu_device *adev, bool gate);

static struct cz_ps *cz_get_ps(struct amdgpu_ps *rps)
{
struct cz_ps *ps = rps->ps_priv;
Expand Down Expand Up @@ -474,6 +476,7 @@ static int cz_dpm_init(struct amdgpu_device *adev)
return ret;

pi->dpm_enabled = true;
pi->uvd_dynamic_pg = false;

return 0;
}
Expand Down Expand Up @@ -546,6 +549,15 @@ static int cz_dpm_early_init(struct amdgpu_device *adev)
return 0;
}


static int cz_dpm_late_init(struct amdgpu_device *adev)
{
/* powerdown unused blocks for now */
cz_dpm_powergate_uvd(adev, true);

return 0;
}

static int cz_dpm_sw_init(struct amdgpu_device *adev)
{
int ret = 0;
Expand Down Expand Up @@ -1260,6 +1272,9 @@ static int cz_dpm_disable(struct amdgpu_device *adev)
return -EINVAL;
}

/* powerup blocks */
cz_dpm_powergate_uvd(adev, false);

cz_clear_voting_clients(adev);
cz_stop_dpm(adev);
cz_update_current_ps(adev, adev->pm.dpm.boot_ps);
Expand Down Expand Up @@ -1677,9 +1692,80 @@ static uint32_t cz_dpm_get_mclk(struct amdgpu_device *adev, bool low)
return pi->sys_info.bootup_uma_clk;
}

static int cz_enable_uvd_dpm(struct amdgpu_device *adev, bool enable)
{
struct cz_power_info *pi = cz_get_pi(adev);
int ret = 0;

if (enable && pi->caps_uvd_dpm ) {
pi->dpm_flags |= DPMFlags_UVD_Enabled;
DRM_DEBUG("UVD DPM Enabled.\n");

ret = cz_send_msg_to_smc_with_parameter(adev,
PPSMC_MSG_EnableAllSmuFeatures, UVD_DPM_MASK);
} else {
pi->dpm_flags &= ~DPMFlags_UVD_Enabled;
DRM_DEBUG("UVD DPM Stopped\n");

ret = cz_send_msg_to_smc_with_parameter(adev,
PPSMC_MSG_DisableAllSmuFeatures, UVD_DPM_MASK);
}

return ret;
}

static int cz_update_uvd_dpm(struct amdgpu_device *adev, bool gate)
{
return cz_enable_uvd_dpm(adev, !gate);
}


static void cz_dpm_powergate_uvd(struct amdgpu_device *adev, bool gate)
{
struct cz_power_info *pi = cz_get_pi(adev);
int ret;

if (pi->uvd_power_gated == gate)
return;

pi->uvd_power_gated = gate;

if (gate) {
if (pi->caps_uvd_pg) {
/* disable clockgating so we can properly shut down the block */
ret = amdgpu_set_clockgating_state(adev, AMDGPU_IP_BLOCK_TYPE_UVD,
AMDGPU_CG_STATE_UNGATE);
/* shutdown the UVD block */
ret = amdgpu_set_powergating_state(adev, AMDGPU_IP_BLOCK_TYPE_UVD,
AMDGPU_PG_STATE_GATE);
/* XXX: check for errors */
}
cz_update_uvd_dpm(adev, gate);
if (pi->caps_uvd_pg)
/* power off the UVD block */
cz_send_msg_to_smc(adev, PPSMC_MSG_UVDPowerOFF);
} else {
if (pi->caps_uvd_pg) {
/* power on the UVD block */
if (pi->uvd_dynamic_pg)
cz_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_UVDPowerON, 1);
else
cz_send_msg_to_smc_with_parameter(adev, PPSMC_MSG_UVDPowerON, 0);
/* re-init the UVD block */
ret = amdgpu_set_powergating_state(adev, AMDGPU_IP_BLOCK_TYPE_UVD,
AMDGPU_PG_STATE_UNGATE);
/* enable clockgating. hw will dynamically gate/ungate clocks on the fly */
ret = amdgpu_set_clockgating_state(adev, AMDGPU_IP_BLOCK_TYPE_UVD,
AMDGPU_CG_STATE_GATE);
/* XXX: check for errors */
}
cz_update_uvd_dpm(adev, gate);
}
}

const struct amdgpu_ip_funcs cz_dpm_ip_funcs = {
.early_init = cz_dpm_early_init,
.late_init = NULL,
.late_init = cz_dpm_late_init,
.sw_init = cz_dpm_sw_init,
.sw_fini = cz_dpm_sw_fini,
.hw_init = cz_dpm_hw_init,
Expand Down Expand Up @@ -1707,7 +1793,7 @@ static const struct amdgpu_dpm_funcs cz_dpm_funcs = {
cz_dpm_debugfs_print_current_performance_level,
.force_performance_level = cz_dpm_force_dpm_level,
.vblank_too_short = NULL,
.powergate_uvd = NULL,
.powergate_uvd = cz_dpm_powergate_uvd,
};

static void cz_dpm_set_funcs(struct amdgpu_device *adev)
Expand Down
2 changes: 2 additions & 0 deletions drivers/gpu/drm/amd/amdgpu/cz_dpm.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ struct cz_power_info {
bool uvd_power_down;
bool vce_power_down;
bool acp_power_down;

bool uvd_dynamic_pg;
};

/* cz_smc.c */
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/amd/amdgpu/vi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1266,7 +1266,7 @@ static int vi_common_early_init(struct amdgpu_device *adev)
case CHIP_CARRIZO:
adev->has_uvd = true;
adev->cg_flags = 0;
adev->pg_flags = 0;
adev->pg_flags = AMDGPU_PG_SUPPORT_UVD;
adev->external_rev_id = adev->rev_id + 0x1;
if (amdgpu_smc_load_fw && smc_enabled)
adev->firmware.smu_load = true;
Expand Down

0 comments on commit 564ea79

Please sign in to comment.