diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/rv6xx_dpm.c')
| -rw-r--r-- | drivers/gpu/drm/radeon/rv6xx_dpm.c | 103 |
1 files changed, 65 insertions, 38 deletions
diff --git a/drivers/gpu/drm/radeon/rv6xx_dpm.c b/drivers/gpu/drm/radeon/rv6xx_dpm.c index 8303de267ee..e7045b08571 100644 --- a/drivers/gpu/drm/radeon/rv6xx_dpm.c +++ b/drivers/gpu/drm/radeon/rv6xx_dpm.c @@ -407,9 +407,9 @@ static void rv6xx_enable_engine_feedback_and_reference_sync(struct radeon_device WREG32_P(SPLL_CNTL_MODE, SPLL_DIV_SYNC, ~SPLL_DIV_SYNC); } -static u64 rv6xx_clocks_per_unit(u32 unit) +static u32 rv6xx_clocks_per_unit(u32 unit) { - u64 tmp = 1 << (2 * unit); + u32 tmp = 1 << (2 * unit); return tmp; } @@ -417,7 +417,7 @@ static u64 rv6xx_clocks_per_unit(u32 unit) static u32 rv6xx_scale_count_given_unit(struct radeon_device *rdev, u32 unscaled_count, u32 unit) { - u32 count_per_unit = (u32)rv6xx_clocks_per_unit(unit); + u32 count_per_unit = rv6xx_clocks_per_unit(unit); return (unscaled_count + count_per_unit - 1) / count_per_unit; } @@ -819,7 +819,7 @@ static void rv6xx_program_memory_timing_parameters(struct radeon_device *rdev) POWERMODE1(calculate_memory_refresh_rate(rdev, pi->hw.sclks[R600_POWER_LEVEL_MEDIUM])) | POWERMODE2(calculate_memory_refresh_rate(rdev, - pi->hw.sclks[R600_POWER_LEVEL_MEDIUM])) | + pi->hw.sclks[R600_POWER_LEVEL_HIGH])) | POWERMODE3(calculate_memory_refresh_rate(rdev, pi->hw.sclks[R600_POWER_LEVEL_HIGH]))); WREG32(ARB_RFSH_RATE, arb_refresh_rate); @@ -1182,10 +1182,10 @@ static void rv6xx_program_display_gap(struct radeon_device *rdev) u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL); tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK); - if (RREG32(AVIVO_D1CRTC_CONTROL) & AVIVO_CRTC_EN) { + if (rdev->pm.dpm.new_active_crtcs & 1) { tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK); tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); - } else if (RREG32(AVIVO_D2CRTC_CONTROL) & AVIVO_CRTC_EN) { + } else if (rdev->pm.dpm.new_active_crtcs & 2) { tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE); tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK); } else { @@ -1546,7 +1546,6 @@ int rv6xx_dpm_enable(struct radeon_device *rdev) { struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps; - int ret; if (r600_dynamicpm_enabled(rdev)) return -EINVAL; @@ -1594,15 +1593,6 @@ int rv6xx_dpm_enable(struct radeon_device *rdev) r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true); r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, true); - if (rdev->irq.installed && - r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { - ret = r600_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); - if (ret) - return ret; - rdev->irq.dpm_thermal = true; - radeon_irq_set(rdev); - } - rv6xx_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); r600_start_dpm(rdev); @@ -1670,6 +1660,8 @@ int rv6xx_dpm_set_power_state(struct radeon_device *rdev) struct radeon_ps *old_ps = rdev->pm.dpm.current_ps; int ret; + pi->restricted_levels = 0; + rv6xx_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps); rv6xx_clear_vc(rdev); @@ -1763,12 +1755,14 @@ void rv6xx_setup_asic(struct radeon_device *rdev) { r600_enable_acpi_pm(rdev); - if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s) - rv6xx_enable_l0s(rdev); - if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1) - rv6xx_enable_l1(rdev); - if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1) - rv6xx_enable_pll_sleep_in_l1(rdev); + if (radeon_aspm != 0) { + if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s) + rv6xx_enable_l0s(rdev); + if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1) + rv6xx_enable_l1(rdev); + if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1) + rv6xx_enable_pll_sleep_in_l1(rdev); + } } void rv6xx_dpm_display_configuration_changed(struct radeon_device *rdev) @@ -1897,9 +1891,6 @@ static int rv6xx_parse_power_table(struct radeon_device *rdev) power_info->pplib.ucNumStates, GFP_KERNEL); if (!rdev->pm.dpm.ps) return -ENOMEM; - 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 < power_info->pplib.ucNumStates; i++) { power_state = (union pplib_power_state *) @@ -1912,6 +1903,7 @@ static int rv6xx_parse_power_table(struct radeon_device *rdev) (power_state->v1.ucNonClockStateIndex * power_info->pplib.ucNonClockSize)); if (power_info->pplib.ucStateEntrySize - 1) { + u8 *idx; ps = kzalloc(sizeof(struct rv6xx_ps), GFP_KERNEL); if (ps == NULL) { kfree(rdev->pm.dpm.ps); @@ -1920,12 +1912,12 @@ static int rv6xx_parse_power_table(struct radeon_device *rdev) rdev->pm.dpm.ps[i].ps_priv = ps; rv6xx_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i], non_clock_info); + idx = (u8 *)&power_state->v1.ucClockStateIndices[0]; for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) { clock_info = (union pplib_clock_info *) (mode_info->atom_context->bios + data_offset + le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) + - (power_state->v1.ucClockStateIndices[j] * - power_info->pplib.ucClockInfoSize)); + (idx[j] * power_info->pplib.ucClockInfoSize)); rv6xx_parse_pplib_clock_info(rdev, &rdev->pm.dpm.ps[i], j, clock_info); @@ -1938,9 +1930,7 @@ static int rv6xx_parse_power_table(struct radeon_device *rdev) int rv6xx_dpm_init(struct radeon_device *rdev) { - int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info); - uint16_t data_offset, size; - uint8_t frev, crev; + struct radeon_atom_ss ss; struct atom_clock_dividers dividers; struct rv6xx_power_info *pi; int ret; @@ -1950,6 +1940,10 @@ int rv6xx_dpm_init(struct radeon_device *rdev) return -ENOMEM; rdev->pm.dpm.priv = pi; + ret = r600_get_platform_caps(rdev); + if (ret) + return ret; + ret = rv6xx_parse_power_table(rdev); if (ret) return ret; @@ -1983,16 +1977,18 @@ int rv6xx_dpm_init(struct radeon_device *rdev) pi->gfx_clock_gating = true; - if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size, - &frev, &crev, &data_offset)) { - pi->sclk_ss = true; - pi->mclk_ss = true; + pi->sclk_ss = radeon_atombios_get_asic_ss_info(rdev, &ss, + ASIC_INTERNAL_ENGINE_SS, 0); + pi->mclk_ss = radeon_atombios_get_asic_ss_info(rdev, &ss, + ASIC_INTERNAL_MEMORY_SS, 0); + + /* Disable sclk ss, causes hangs on a lot of systems */ + pi->sclk_ss = false; + + if (pi->sclk_ss || pi->mclk_ss) pi->dynamic_ss = true; - } else { - pi->sclk_ss = false; - pi->mclk_ss = false; + else pi->dynamic_ss = false; - } pi->dynamic_pcie_gen2 = true; @@ -2083,3 +2079,34 @@ u32 rv6xx_dpm_get_mclk(struct radeon_device *rdev, bool low) else return requested_state->high.mclk; } + +int rv6xx_dpm_force_performance_level(struct radeon_device *rdev, + enum radeon_dpm_forced_level level) +{ + struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); + + if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { + pi->restricted_levels = 3; + } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) { + pi->restricted_levels = 2; + } else { + pi->restricted_levels = 0; + } + + rv6xx_clear_vc(rdev); + r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true); + r600_set_at(rdev, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF); + r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW); + r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false); + r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false); + rv6xx_enable_medium(rdev); + rv6xx_enable_high(rdev); + if (pi->restricted_levels == 3) + r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, false); + rv6xx_program_vc(rdev); + rv6xx_program_at(rdev); + + rdev->pm.dpm.forced_level = level; + + return 0; +} |
