drm/radeon: re-enable mclk dpm on R7 260X asics
[pandora-kernel.git] / drivers / gpu / drm / radeon / ci_dpm.c
index 8d49104..10dae41 100644 (file)
  *
  */
 
+#include <linux/firmware.h>
 #include "drmP.h"
 #include "radeon.h"
+#include "radeon_ucode.h"
 #include "cikd.h"
 #include "r600_dpm.h"
 #include "ci_dpm.h"
@@ -172,6 +174,8 @@ extern void si_trim_voltage_table_to_fit_state_table(struct radeon_device *rdev,
 extern void cik_enter_rlc_safe_mode(struct radeon_device *rdev);
 extern void cik_exit_rlc_safe_mode(struct radeon_device *rdev);
 extern int ci_mc_load_microcode(struct radeon_device *rdev);
+extern void cik_update_cg(struct radeon_device *rdev,
+                         u32 block, bool enable);
 
 static int ci_get_std_voltage_value_sidd(struct radeon_device *rdev,
                                         struct atom_voltage_table_entry *voltage_table,
@@ -200,24 +204,29 @@ static void ci_initialize_powertune_defaults(struct radeon_device *rdev)
        struct ci_power_info *pi = ci_get_pi(rdev);
 
        switch (rdev->pdev->device) {
+       case 0x6649:
        case 0x6650:
+       case 0x6651:
        case 0x6658:
        case 0x665C:
+       case 0x665D:
        default:
                pi->powertune_defaults = &defaults_bonaire_xt;
                break;
-       case 0x6651:
-       case 0x665D:
-               pi->powertune_defaults = &defaults_bonaire_pro;
-               break;
        case 0x6640:
-               pi->powertune_defaults = &defaults_saturn_xt;
-               break;
        case 0x6641:
-               pi->powertune_defaults = &defaults_saturn_pro;
+       case 0x6646:
+       case 0x6647:
+               pi->powertune_defaults = &defaults_saturn_xt;
                break;
        case 0x67B8:
        case 0x67B0:
+               pi->powertune_defaults = &defaults_hawaii_xt;
+               break;
+       case 0x67BA:
+       case 0x67B1:
+               pi->powertune_defaults = &defaults_hawaii_pro;
+               break;
        case 0x67A0:
        case 0x67A1:
        case 0x67A2:
@@ -226,11 +235,7 @@ static void ci_initialize_powertune_defaults(struct radeon_device *rdev)
        case 0x67AA:
        case 0x67B9:
        case 0x67BE:
-               pi->powertune_defaults = &defaults_hawaii_xt;
-               break;
-       case 0x67BA:
-       case 0x67B1:
-               pi->powertune_defaults = &defaults_hawaii_pro;
+               pi->powertune_defaults = &defaults_bonaire_xt;
                break;
        }
 
@@ -746,6 +751,14 @@ static void ci_apply_state_adjust_rules(struct radeon_device *rdev,
        u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc;
        int i;
 
+       if (rps->vce_active) {
+               rps->evclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].evclk;
+               rps->ecclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].ecclk;
+       } else {
+               rps->evclk = 0;
+               rps->ecclk = 0;
+       }
+
        if ((rdev->pm.dpm.new_active_crtc_count > 1) ||
            ci_dpm_vblank_too_short(rdev))
                disable_mclk_switching = true;
@@ -804,6 +817,13 @@ static void ci_apply_state_adjust_rules(struct radeon_device *rdev,
                sclk = ps->performance_levels[0].sclk;
        }
 
+       if (rps->vce_active) {
+               if (sclk < rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk)
+                       sclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk;
+               if (mclk < rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].mclk)
+                       mclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].mclk;
+       }
+
        ps->performance_levels[0].sclk = sclk;
        ps->performance_levels[0].mclk = mclk;
 
@@ -3468,7 +3488,6 @@ static int ci_enable_uvd_dpm(struct radeon_device *rdev, bool enable)
                0 : -EINVAL;
 }
 
-#if 0
 static int ci_enable_vce_dpm(struct radeon_device *rdev, bool enable)
 {
        struct ci_power_info *pi = ci_get_pi(rdev);
@@ -3501,6 +3520,7 @@ static int ci_enable_vce_dpm(struct radeon_device *rdev, bool enable)
                0 : -EINVAL;
 }
 
+#if 0
 static int ci_enable_samu_dpm(struct radeon_device *rdev, bool enable)
 {
        struct ci_power_info *pi = ci_get_pi(rdev);
@@ -3587,7 +3607,6 @@ static int ci_update_uvd_dpm(struct radeon_device *rdev, bool gate)
        return ci_enable_uvd_dpm(rdev, !gate);
 }
 
-#if 0
 static u8 ci_get_vce_boot_level(struct radeon_device *rdev)
 {
        u8 i;
@@ -3608,15 +3627,15 @@ static int ci_update_vce_dpm(struct radeon_device *rdev,
                             struct radeon_ps *radeon_current_state)
 {
        struct ci_power_info *pi = ci_get_pi(rdev);
-       bool new_vce_clock_non_zero = (radeon_new_state->evclk != 0);
-       bool old_vce_clock_non_zero = (radeon_current_state->evclk != 0);
        int ret = 0;
        u32 tmp;
 
-       if (new_vce_clock_non_zero != old_vce_clock_non_zero) {
-               if (new_vce_clock_non_zero) {
-                       pi->smc_state_table.VceBootLevel = ci_get_vce_boot_level(rdev);
+       if (radeon_current_state->evclk != radeon_new_state->evclk) {
+               if (radeon_new_state->evclk) {
+                       /* turn the clocks on when encoding */
+                       cik_update_cg(rdev, RADEON_CG_BLOCK_VCE, false);
 
+                       pi->smc_state_table.VceBootLevel = ci_get_vce_boot_level(rdev);
                        tmp = RREG32_SMC(DPM_TABLE_475);
                        tmp &= ~VceBootLevel_MASK;
                        tmp |= VceBootLevel(pi->smc_state_table.VceBootLevel);
@@ -3624,12 +3643,16 @@ static int ci_update_vce_dpm(struct radeon_device *rdev,
 
                        ret = ci_enable_vce_dpm(rdev, true);
                } else {
+                       /* turn the clocks off when not encoding */
+                       cik_update_cg(rdev, RADEON_CG_BLOCK_VCE, true);
+
                        ret = ci_enable_vce_dpm(rdev, false);
                }
        }
        return ret;
 }
 
+#if 0
 static int ci_update_samu_dpm(struct radeon_device *rdev, bool gate)
 {
        return ci_enable_samu_dpm(rdev, gate);
@@ -4752,13 +4775,13 @@ int ci_dpm_set_power_state(struct radeon_device *rdev)
                DRM_ERROR("ci_generate_dpm_level_enable_mask failed\n");
                return ret;
        }
-#if 0
+
        ret = ci_update_vce_dpm(rdev, new_ps, old_ps);
        if (ret) {
                DRM_ERROR("ci_update_vce_dpm failed\n");
                return ret;
        }
-#endif
+
        ret = ci_update_sclk_t(rdev);
        if (ret) {
                DRM_ERROR("ci_update_sclk_t failed\n");
@@ -4959,9 +4982,6 @@ static int ci_parse_power_table(struct radeon_device *rdev)
        if (!rdev->pm.dpm.ps)
                return -ENOMEM;
        power_state_offset = (u8 *)state_array->states;
-       rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
-       rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
-       rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
        for (i = 0; i < state_array->ucNumEntries; i++) {
                u8 *idx;
                power_state = (union pplib_power_state *)power_state_offset;
@@ -4998,6 +5018,21 @@ static int ci_parse_power_table(struct radeon_device *rdev)
                power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
        }
        rdev->pm.dpm.num_ps = state_array->ucNumEntries;
+
+       /* fill in the vce power states */
+       for (i = 0; i < RADEON_MAX_VCE_LEVELS; i++) {
+               u32 sclk, mclk;
+               clock_array_index = rdev->pm.dpm.vce_states[i].clk_idx;
+               clock_info = (union pplib_clock_info *)
+                       &clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
+               sclk = le16_to_cpu(clock_info->ci.usEngineClockLow);
+               sclk |= clock_info->ci.ucEngineClockHigh << 16;
+               mclk = le16_to_cpu(clock_info->ci.usMemoryClockLow);
+               mclk |= clock_info->ci.ucMemoryClockHigh << 16;
+               rdev->pm.dpm.vce_states[i].sclk = sclk;
+               rdev->pm.dpm.vce_states[i].mclk = mclk;
+       }
+
        return 0;
 }
 
@@ -5077,17 +5112,25 @@ int ci_dpm_init(struct radeon_device *rdev)
                ci_dpm_fini(rdev);
                return ret;
        }
-       ret = ci_parse_power_table(rdev);
+
+       ret = r600_get_platform_caps(rdev);
        if (ret) {
                ci_dpm_fini(rdev);
                return ret;
        }
+
        ret = r600_parse_extended_power_table(rdev);
        if (ret) {
                ci_dpm_fini(rdev);
                return ret;
        }
 
+       ret = ci_parse_power_table(rdev);
+       if (ret) {
+               ci_dpm_fini(rdev);
+               return ret;
+       }
+
         pi->dll_default_on = false;
         pi->sram_end = SMC_RAM_END;
 
@@ -5106,6 +5149,12 @@ int ci_dpm_init(struct radeon_device *rdev)
        pi->mclk_dpm_key_disabled = 0;
        pi->pcie_dpm_key_disabled = 0;
 
+       /* mclk dpm is unstable on some R7 260X cards with the old mc ucode */
+       if ((rdev->pdev->device == 0x6658) &&
+           (rdev->mc_fw->size == (BONAIRE_MC_UCODE_SIZE * 4))) {
+               pi->mclk_dpm_key_disabled = 1;
+       }
+
        pi->caps_sclk_ds = true;
 
        pi->mclk_strobe_mode_threshold = 40000;
@@ -5120,6 +5169,7 @@ int ci_dpm_init(struct radeon_device *rdev)
        pi->caps_sclk_throttle_low_notification = false;
 
        pi->caps_uvd_dpm = true;
+       pi->caps_vce_dpm = true;
 
         ci_get_leakage_voltages(rdev);
         ci_patch_dependency_tables_with_leakage(rdev);