Merge airlied/drm-next into drm-misc-next
[linux-2.6-microblaze.git] / drivers / gpu / drm / amd / amdgpu / amdgpu_pm.c
index 723ae68..346e80a 100644 (file)
 
 static int amdgpu_debugfs_pm_init(struct amdgpu_device *adev);
 
+static const struct cg_flag_name clocks[] = {
+       {AMD_CG_SUPPORT_GFX_MGCG, "Graphics Medium Grain Clock Gating"},
+       {AMD_CG_SUPPORT_GFX_MGLS, "Graphics Medium Grain memory Light Sleep"},
+       {AMD_CG_SUPPORT_GFX_CGCG, "Graphics Coarse Grain Clock Gating"},
+       {AMD_CG_SUPPORT_GFX_CGLS, "Graphics Coarse Grain memory Light Sleep"},
+       {AMD_CG_SUPPORT_GFX_CGTS, "Graphics Coarse Grain Tree Shader Clock Gating"},
+       {AMD_CG_SUPPORT_GFX_CGTS_LS, "Graphics Coarse Grain Tree Shader Light Sleep"},
+       {AMD_CG_SUPPORT_GFX_CP_LS, "Graphics Command Processor Light Sleep"},
+       {AMD_CG_SUPPORT_GFX_RLC_LS, "Graphics Run List Controller Light Sleep"},
+       {AMD_CG_SUPPORT_MC_LS, "Memory Controller Light Sleep"},
+       {AMD_CG_SUPPORT_MC_MGCG, "Memory Controller Medium Grain Clock Gating"},
+       {AMD_CG_SUPPORT_SDMA_LS, "System Direct Memory Access Light Sleep"},
+       {AMD_CG_SUPPORT_SDMA_MGCG, "System Direct Memory Access Medium Grain Clock Gating"},
+       {AMD_CG_SUPPORT_BIF_LS, "Bus Interface Light Sleep"},
+       {AMD_CG_SUPPORT_UVD_MGCG, "Unified Video Decoder Medium Grain Clock Gating"},
+       {AMD_CG_SUPPORT_VCE_MGCG, "Video Compression Engine Medium Grain Clock Gating"},
+       {AMD_CG_SUPPORT_HDP_LS, "Host Data Path Light Sleep"},
+       {AMD_CG_SUPPORT_HDP_MGCG, "Host Data Path Medium Grain Clock Gating"},
+       {AMD_CG_SUPPORT_ROM_MGCG, "Rom Medium Grain Clock Gating"},
+       {0, NULL},
+};
+
 void amdgpu_pm_acpi_event_handler(struct amdgpu_device *adev)
 {
        if (adev->pp_enabled)
@@ -112,28 +134,23 @@ static ssize_t amdgpu_get_dpm_forced_performance_level(struct device *dev,
 {
        struct drm_device *ddev = dev_get_drvdata(dev);
        struct amdgpu_device *adev = ddev->dev_private;
+       enum amd_dpm_forced_level level;
 
        if  ((adev->flags & AMD_IS_PX) &&
             (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
                return snprintf(buf, PAGE_SIZE, "off\n");
 
-       if (adev->pp_enabled) {
-               enum amd_dpm_forced_level level;
-
-               level = amdgpu_dpm_get_performance_level(adev);
-               return snprintf(buf, PAGE_SIZE, "%s\n",
-                               (level == AMD_DPM_FORCED_LEVEL_AUTO) ? "auto" :
-                               (level == AMD_DPM_FORCED_LEVEL_LOW) ? "low" :
-                               (level == AMD_DPM_FORCED_LEVEL_HIGH) ? "high" :
-                               (level == AMD_DPM_FORCED_LEVEL_MANUAL) ? "manual" : "unknown");
-       } else {
-               enum amdgpu_dpm_forced_level level;
-
-               level = adev->pm.dpm.forced_level;
-               return snprintf(buf, PAGE_SIZE, "%s\n",
-                               (level == AMDGPU_DPM_FORCED_LEVEL_AUTO) ? "auto" :
-                               (level == AMDGPU_DPM_FORCED_LEVEL_LOW) ? "low" : "high");
-       }
+       level = amdgpu_dpm_get_performance_level(adev);
+       return snprintf(buf, PAGE_SIZE, "%s\n",
+                       (level == AMD_DPM_FORCED_LEVEL_AUTO) ? "auto" :
+                       (level == AMD_DPM_FORCED_LEVEL_LOW) ? "low" :
+                       (level == AMD_DPM_FORCED_LEVEL_HIGH) ? "high" :
+                       (level == AMD_DPM_FORCED_LEVEL_MANUAL) ? "manual" :
+                       (level == AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD) ? "profile_standard" :
+                       (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) ? "profile_min_sclk" :
+                       (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) ? "profile_min_mclk" :
+                       (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) ? "profile_peak" :
+                       "unknown");
 }
 
 static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
@@ -143,7 +160,8 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
 {
        struct drm_device *ddev = dev_get_drvdata(dev);
        struct amdgpu_device *adev = ddev->dev_private;
-       enum amdgpu_dpm_forced_level level;
+       enum amd_dpm_forced_level level;
+       enum amd_dpm_forced_level current_level;
        int ret = 0;
 
        /* Can't force performance level when the card is off */
@@ -151,19 +169,34 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
             (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
                return -EINVAL;
 
+       current_level = amdgpu_dpm_get_performance_level(adev);
+
        if (strncmp("low", buf, strlen("low")) == 0) {
-               level = AMDGPU_DPM_FORCED_LEVEL_LOW;
+               level = AMD_DPM_FORCED_LEVEL_LOW;
        } else if (strncmp("high", buf, strlen("high")) == 0) {
-               level = AMDGPU_DPM_FORCED_LEVEL_HIGH;
+               level = AMD_DPM_FORCED_LEVEL_HIGH;
        } else if (strncmp("auto", buf, strlen("auto")) == 0) {
-               level = AMDGPU_DPM_FORCED_LEVEL_AUTO;
+               level = AMD_DPM_FORCED_LEVEL_AUTO;
        } else if (strncmp("manual", buf, strlen("manual")) == 0) {
-               level = AMDGPU_DPM_FORCED_LEVEL_MANUAL;
-       } else {
+               level = AMD_DPM_FORCED_LEVEL_MANUAL;
+       } else if (strncmp("profile_exit", buf, strlen("profile_exit")) == 0) {
+               level = AMD_DPM_FORCED_LEVEL_PROFILE_EXIT;
+       } else if (strncmp("profile_standard", buf, strlen("profile_standard")) == 0) {
+               level = AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD;
+       } else if (strncmp("profile_min_sclk", buf, strlen("profile_min_sclk")) == 0) {
+               level = AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK;
+       } else if (strncmp("profile_min_mclk", buf, strlen("profile_min_mclk")) == 0) {
+               level = AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK;
+       } else if (strncmp("profile_peak", buf, strlen("profile_peak")) == 0) {
+               level = AMD_DPM_FORCED_LEVEL_PROFILE_PEAK;
+       }  else {
                count = -EINVAL;
                goto fail;
        }
 
+       if (current_level == level)
+               return count;
+
        if (adev->pp_enabled)
                amdgpu_dpm_force_performance_level(adev, level);
        else {
@@ -180,6 +213,7 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
                        adev->pm.dpm.forced_level = level;
                mutex_unlock(&adev->pm.mutex);
        }
+
 fail:
        return count;
 }
@@ -1060,9 +1094,9 @@ static void amdgpu_dpm_change_power_state_locked(struct amdgpu_device *adev)
 
        if (adev->pm.funcs->force_performance_level) {
                if (adev->pm.dpm.thermal_active) {
-                       enum amdgpu_dpm_forced_level level = adev->pm.dpm.forced_level;
+                       enum amd_dpm_forced_level level = adev->pm.dpm.forced_level;
                        /* force low perf level for thermal */
-                       amdgpu_dpm_force_performance_level(adev, AMDGPU_DPM_FORCED_LEVEL_LOW);
+                       amdgpu_dpm_force_performance_level(adev, AMD_DPM_FORCED_LEVEL_LOW);
                        /* save the user's level */
                        adev->pm.dpm.forced_level = level;
                } else {
@@ -1108,12 +1142,22 @@ void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable)
                        /* XXX select vce level based on ring/task */
                        adev->pm.dpm.vce_level = AMD_VCE_LEVEL_AC_ALL;
                        mutex_unlock(&adev->pm.mutex);
+                       amdgpu_pm_compute_clocks(adev);
+                       amdgpu_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
+                                                       AMD_PG_STATE_UNGATE);
+                       amdgpu_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
+                                                       AMD_CG_STATE_UNGATE);
                } else {
+                       amdgpu_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
+                                                       AMD_PG_STATE_GATE);
+                       amdgpu_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
+                                                       AMD_CG_STATE_GATE);
                        mutex_lock(&adev->pm.mutex);
                        adev->pm.dpm.vce_active = false;
                        mutex_unlock(&adev->pm.mutex);
+                       amdgpu_pm_compute_clocks(adev);
                }
-               amdgpu_pm_compute_clocks(adev);
+
        }
 }
 
@@ -1252,7 +1296,8 @@ void amdgpu_pm_compute_clocks(struct amdgpu_device *adev)
        if (!adev->pm.dpm_enabled)
                return;
 
-       amdgpu_display_bandwidth_update(adev);
+       if (adev->mode_info.num_crtc)
+               amdgpu_display_bandwidth_update(adev);
 
        for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
                struct amdgpu_ring *ring = adev->rings[i];
@@ -1351,12 +1396,27 @@ static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *a
        return 0;
 }
 
+static void amdgpu_parse_cg_state(struct seq_file *m, u32 flags)
+{
+       int i;
+
+       for (i = 0; clocks[i].flag; i++)
+               seq_printf(m, "\t%s: %s\n", clocks[i].name,
+                          (flags & clocks[i].flag) ? "On" : "Off");
+}
+
 static int amdgpu_debugfs_pm_info(struct seq_file *m, void *data)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
        struct amdgpu_device *adev = dev->dev_private;
        struct drm_device *ddev = adev->ddev;
+       u32 flags = 0;
+
+       amdgpu_get_clockgating_state(adev, &flags);
+       seq_printf(m, "Clock Gating Flags Mask: 0x%x\n", flags);
+       amdgpu_parse_cg_state(m, flags);
+       seq_printf(m, "\n");
 
        if (!adev->pm.dpm_enabled) {
                seq_printf(m, "dpm not enabled\n");