*
*/
+#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"
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,
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:
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;
}
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;
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;
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);
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);
return ci_enable_uvd_dpm(rdev, !gate);
}
-#if 0
static u8 ci_get_vce_boot_level(struct radeon_device *rdev)
{
u8 i;
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);
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);
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");
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;
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;
}
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;
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;
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);