summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Deucher <alexander.deucher@amd.com>2015-12-18 19:06:42 +0300
committerAlex Deucher <alexander.deucher@amd.com>2016-01-13 20:11:30 +0300
commitd83b1e8132f91ba9e038b5206dc81d32ecac1f75 (patch)
treeec747b7c51cc8fb123f0cde32120d0a122d4007d
parent888c9e33e4c5a503285921046c621f7c73199d2f (diff)
downloadlinux-d83b1e8132f91ba9e038b5206dc81d32ecac1f75.tar.xz
drm/amdgpu/cz: add code to enable forcing UVD clocks
UVD DPM works similarly to SCLK DPM. Add a similar interface for UVD for forcing the UVD clocks. Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cz_dpm.c129
-rw-r--r--drivers/gpu/drm/amd/amdgpu/cz_dpm.h1
2 files changed, 130 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/cz_dpm.c b/drivers/gpu/drm/amd/amdgpu/cz_dpm.c
index 8035d4d6a4f5..5ccea9f9c634 100644
--- a/drivers/gpu/drm/amd/amdgpu/cz_dpm.c
+++ b/drivers/gpu/drm/amd/amdgpu/cz_dpm.c
@@ -1078,6 +1078,37 @@ static uint32_t cz_get_eclk_level(struct amdgpu_device *adev,
return i;
}
+static uint32_t cz_get_uvd_level(struct amdgpu_device *adev,
+ uint32_t clock, uint16_t msg)
+{
+ int i = 0;
+ struct amdgpu_uvd_clock_voltage_dependency_table *table =
+ &adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table;
+
+ switch (msg) {
+ case PPSMC_MSG_SetUvdSoftMin:
+ case PPSMC_MSG_SetUvdHardMin:
+ for (i = 0; i < table->count; i++)
+ if (clock <= table->entries[i].vclk)
+ break;
+ if (i == table->count)
+ i = table->count - 1;
+ break;
+ case PPSMC_MSG_SetUvdSoftMax:
+ case PPSMC_MSG_SetUvdHardMax:
+ for (i = table->count - 1; i >= 0; i--)
+ if (clock >= table->entries[i].vclk)
+ break;
+ if (i < 0)
+ i = 0;
+ break;
+ default:
+ break;
+ }
+
+ return i;
+}
+
static int cz_program_bootup_state(struct amdgpu_device *adev)
{
struct cz_power_info *pi = cz_get_pi(adev);
@@ -1739,6 +1770,104 @@ static int cz_dpm_unforce_dpm_levels(struct amdgpu_device *adev)
return 0;
}
+
+static int cz_dpm_uvd_force_highest(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ int ret = 0;
+
+ if (pi->uvd_dpm.soft_min_clk != pi->uvd_dpm.soft_max_clk) {
+ pi->uvd_dpm.soft_min_clk =
+ pi->uvd_dpm.soft_max_clk;
+ ret = cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetUvdSoftMin,
+ cz_get_uvd_level(adev,
+ pi->uvd_dpm.soft_min_clk,
+ PPSMC_MSG_SetUvdSoftMin));
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+static int cz_dpm_uvd_force_lowest(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ int ret = 0;
+
+ if (pi->uvd_dpm.soft_max_clk != pi->uvd_dpm.soft_min_clk) {
+ pi->uvd_dpm.soft_max_clk = pi->uvd_dpm.soft_min_clk;
+ ret = cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetUvdSoftMax,
+ cz_get_uvd_level(adev,
+ pi->uvd_dpm.soft_max_clk,
+ PPSMC_MSG_SetUvdSoftMax));
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+static uint32_t cz_dpm_get_max_uvd_level(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+
+ if (!pi->max_uvd_level) {
+ cz_send_msg_to_smc(adev, PPSMC_MSG_GetMaxUvdLevel);
+ pi->max_uvd_level = cz_get_argument(adev) + 1;
+ }
+
+ if (pi->max_uvd_level > CZ_MAX_HARDWARE_POWERLEVELS) {
+ DRM_ERROR("Invalid max uvd level!\n");
+ return -EINVAL;
+ }
+
+ return pi->max_uvd_level;
+}
+
+static int cz_dpm_unforce_uvd_dpm_levels(struct amdgpu_device *adev)
+{
+ struct cz_power_info *pi = cz_get_pi(adev);
+ struct amdgpu_uvd_clock_voltage_dependency_table *dep_table =
+ &adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table;
+ uint32_t level = 0;
+ int ret = 0;
+
+ pi->uvd_dpm.soft_min_clk = dep_table->entries[0].vclk;
+ level = cz_dpm_get_max_uvd_level(adev) - 1;
+ if (level < dep_table->count)
+ pi->uvd_dpm.soft_max_clk = dep_table->entries[level].vclk;
+ else
+ pi->uvd_dpm.soft_max_clk =
+ dep_table->entries[dep_table->count - 1].vclk;
+
+ /* get min/max sclk soft value
+ * notify SMU to execute */
+ ret = cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetUvdSoftMin,
+ cz_get_uvd_level(adev,
+ pi->uvd_dpm.soft_min_clk,
+ PPSMC_MSG_SetUvdSoftMin));
+ if (ret)
+ return ret;
+
+ ret = cz_send_msg_to_smc_with_parameter(adev,
+ PPSMC_MSG_SetUvdSoftMax,
+ cz_get_uvd_level(adev,
+ pi->uvd_dpm.soft_max_clk,
+ PPSMC_MSG_SetUvdSoftMax));
+ if (ret)
+ return ret;
+
+ DRM_DEBUG("DPM uvd unforce state min=%d, max=%d.\n",
+ pi->uvd_dpm.soft_min_clk,
+ pi->uvd_dpm.soft_max_clk);
+
+ return 0;
+}
+
static int cz_dpm_force_dpm_level(struct amdgpu_device *adev,
enum amdgpu_dpm_forced_level level)
{
diff --git a/drivers/gpu/drm/amd/amdgpu/cz_dpm.h b/drivers/gpu/drm/amd/amdgpu/cz_dpm.h
index 99e1afc89629..6a6a6fe7967f 100644
--- a/drivers/gpu/drm/amd/amdgpu/cz_dpm.h
+++ b/drivers/gpu/drm/amd/amdgpu/cz_dpm.h
@@ -183,6 +183,7 @@ struct cz_power_info {
uint32_t voltage_drop_threshold;
uint32_t gfx_pg_threshold;
uint32_t max_sclk_level;
+ uint32_t max_uvd_level;
/* flags */
bool didt_enabled;
bool video_start;