diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/trinity_dpm.c')
| -rw-r--r-- | drivers/gpu/drm/radeon/trinity_dpm.c | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/drivers/gpu/drm/radeon/trinity_dpm.c b/drivers/gpu/drm/radeon/trinity_dpm.c index a5b02c575d77..d34bfcdab9be 100644 --- a/drivers/gpu/drm/radeon/trinity_dpm.c +++ b/drivers/gpu/drm/radeon/trinity_dpm.c | |||
| @@ -336,6 +336,7 @@ static const u32 trinity_override_mgpg_sequences[] = | |||
| 336 | 0x00000204, 0x00000000, | 336 | 0x00000204, 0x00000000, |
| 337 | }; | 337 | }; |
| 338 | 338 | ||
| 339 | extern void vce_v1_0_enable_mgcg(struct radeon_device *rdev, bool enable); | ||
| 339 | static void trinity_program_clk_gating_hw_sequence(struct radeon_device *rdev, | 340 | static void trinity_program_clk_gating_hw_sequence(struct radeon_device *rdev, |
| 340 | const u32 *seq, u32 count); | 341 | const u32 *seq, u32 count); |
| 341 | static void trinity_override_dynamic_mg_powergating(struct radeon_device *rdev); | 342 | static void trinity_override_dynamic_mg_powergating(struct radeon_device *rdev); |
| @@ -985,6 +986,21 @@ static void trinity_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev | |||
| 985 | trinity_setup_uvd_clocks(rdev, new_rps, old_rps); | 986 | trinity_setup_uvd_clocks(rdev, new_rps, old_rps); |
| 986 | } | 987 | } |
| 987 | 988 | ||
| 989 | static void trinity_set_vce_clock(struct radeon_device *rdev, | ||
| 990 | struct radeon_ps *new_rps, | ||
| 991 | struct radeon_ps *old_rps) | ||
| 992 | { | ||
| 993 | if ((old_rps->evclk != new_rps->evclk) || | ||
| 994 | (old_rps->ecclk != new_rps->ecclk)) { | ||
| 995 | /* turn the clocks on when encoding, off otherwise */ | ||
| 996 | if (new_rps->evclk || new_rps->ecclk) | ||
| 997 | vce_v1_0_enable_mgcg(rdev, false); | ||
| 998 | else | ||
| 999 | vce_v1_0_enable_mgcg(rdev, true); | ||
| 1000 | radeon_set_vce_clocks(rdev, new_rps->evclk, new_rps->ecclk); | ||
| 1001 | } | ||
| 1002 | } | ||
| 1003 | |||
| 988 | static void trinity_program_ttt(struct radeon_device *rdev) | 1004 | static void trinity_program_ttt(struct radeon_device *rdev) |
| 989 | { | 1005 | { |
| 990 | struct trinity_power_info *pi = trinity_get_pi(rdev); | 1006 | struct trinity_power_info *pi = trinity_get_pi(rdev); |
| @@ -1246,6 +1262,7 @@ int trinity_dpm_set_power_state(struct radeon_device *rdev) | |||
| 1246 | trinity_force_level_0(rdev); | 1262 | trinity_force_level_0(rdev); |
| 1247 | trinity_unforce_levels(rdev); | 1263 | trinity_unforce_levels(rdev); |
| 1248 | trinity_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps); | 1264 | trinity_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps); |
| 1265 | trinity_set_vce_clock(rdev, new_ps, old_ps); | ||
| 1249 | } | 1266 | } |
| 1250 | trinity_release_mutex(rdev); | 1267 | trinity_release_mutex(rdev); |
| 1251 | 1268 | ||
| @@ -1483,7 +1500,35 @@ static void trinity_adjust_uvd_state(struct radeon_device *rdev, | |||
| 1483 | } | 1500 | } |
| 1484 | } | 1501 | } |
| 1485 | 1502 | ||
| 1503 | static int trinity_get_vce_clock_voltage(struct radeon_device *rdev, | ||
| 1504 | u32 evclk, u32 ecclk, u16 *voltage) | ||
| 1505 | { | ||
| 1506 | u32 i; | ||
| 1507 | int ret = -EINVAL; | ||
| 1508 | struct radeon_vce_clock_voltage_dependency_table *table = | ||
| 1509 | &rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table; | ||
| 1510 | |||
| 1511 | if (((evclk == 0) && (ecclk == 0)) || | ||
| 1512 | (table && (table->count == 0))) { | ||
| 1513 | *voltage = 0; | ||
| 1514 | return 0; | ||
| 1515 | } | ||
| 1516 | |||
| 1517 | for (i = 0; i < table->count; i++) { | ||
| 1518 | if ((evclk <= table->entries[i].evclk) && | ||
| 1519 | (ecclk <= table->entries[i].ecclk)) { | ||
| 1520 | *voltage = table->entries[i].v; | ||
| 1521 | ret = 0; | ||
| 1522 | break; | ||
| 1523 | } | ||
| 1524 | } | ||
| 1525 | |||
| 1526 | /* if no match return the highest voltage */ | ||
| 1527 | if (ret) | ||
| 1528 | *voltage = table->entries[table->count - 1].v; | ||
| 1486 | 1529 | ||
| 1530 | return ret; | ||
| 1531 | } | ||
| 1487 | 1532 | ||
| 1488 | static void trinity_apply_state_adjust_rules(struct radeon_device *rdev, | 1533 | static void trinity_apply_state_adjust_rules(struct radeon_device *rdev, |
| 1489 | struct radeon_ps *new_rps, | 1534 | struct radeon_ps *new_rps, |
| @@ -1496,6 +1541,7 @@ static void trinity_apply_state_adjust_rules(struct radeon_device *rdev, | |||
| 1496 | u32 min_sclk = pi->sys_info.min_sclk; /* XXX check against disp reqs */ | 1541 | u32 min_sclk = pi->sys_info.min_sclk; /* XXX check against disp reqs */ |
| 1497 | u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */ | 1542 | u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */ |
| 1498 | u32 i; | 1543 | u32 i; |
| 1544 | u16 min_vce_voltage; | ||
| 1499 | bool force_high; | 1545 | bool force_high; |
| 1500 | u32 num_active_displays = rdev->pm.dpm.new_active_crtc_count; | 1546 | u32 num_active_displays = rdev->pm.dpm.new_active_crtc_count; |
| 1501 | 1547 | ||
| @@ -1504,6 +1550,14 @@ static void trinity_apply_state_adjust_rules(struct radeon_device *rdev, | |||
| 1504 | 1550 | ||
| 1505 | trinity_adjust_uvd_state(rdev, new_rps); | 1551 | trinity_adjust_uvd_state(rdev, new_rps); |
| 1506 | 1552 | ||
| 1553 | if (new_rps->vce_active) { | ||
| 1554 | new_rps->evclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].evclk; | ||
| 1555 | new_rps->ecclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].ecclk; | ||
| 1556 | } else { | ||
| 1557 | new_rps->evclk = 0; | ||
| 1558 | new_rps->ecclk = 0; | ||
| 1559 | } | ||
| 1560 | |||
| 1507 | for (i = 0; i < ps->num_levels; i++) { | 1561 | for (i = 0; i < ps->num_levels; i++) { |
| 1508 | if (ps->levels[i].vddc_index < min_voltage) | 1562 | if (ps->levels[i].vddc_index < min_voltage) |
| 1509 | ps->levels[i].vddc_index = min_voltage; | 1563 | ps->levels[i].vddc_index = min_voltage; |
| @@ -1512,6 +1566,17 @@ static void trinity_apply_state_adjust_rules(struct radeon_device *rdev, | |||
| 1512 | ps->levels[i].sclk = | 1566 | ps->levels[i].sclk = |
| 1513 | trinity_get_valid_engine_clock(rdev, min_sclk); | 1567 | trinity_get_valid_engine_clock(rdev, min_sclk); |
| 1514 | 1568 | ||
| 1569 | /* patch in vce limits */ | ||
| 1570 | if (new_rps->vce_active) { | ||
| 1571 | /* sclk */ | ||
| 1572 | if (ps->levels[i].sclk < rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk) | ||
| 1573 | ps->levels[i].sclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk; | ||
| 1574 | /* vddc */ | ||
| 1575 | trinity_get_vce_clock_voltage(rdev, new_rps->evclk, new_rps->ecclk, &min_vce_voltage); | ||
| 1576 | if (ps->levels[i].vddc_index < min_vce_voltage) | ||
| 1577 | ps->levels[i].vddc_index = min_vce_voltage; | ||
| 1578 | } | ||
| 1579 | |||
| 1515 | ps->levels[i].ds_divider_index = | 1580 | ps->levels[i].ds_divider_index = |
| 1516 | sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[i].sclk, sclk_in_sr); | 1581 | sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[i].sclk, sclk_in_sr); |
| 1517 | 1582 | ||
| @@ -1733,6 +1798,19 @@ static int trinity_parse_power_table(struct radeon_device *rdev) | |||
| 1733 | power_state_offset += 2 + power_state->v2.ucNumDPMLevels; | 1798 | power_state_offset += 2 + power_state->v2.ucNumDPMLevels; |
| 1734 | } | 1799 | } |
| 1735 | rdev->pm.dpm.num_ps = state_array->ucNumEntries; | 1800 | rdev->pm.dpm.num_ps = state_array->ucNumEntries; |
| 1801 | |||
| 1802 | /* fill in the vce power states */ | ||
| 1803 | for (i = 0; i < RADEON_MAX_VCE_LEVELS; i++) { | ||
| 1804 | u32 sclk; | ||
| 1805 | clock_array_index = rdev->pm.dpm.vce_states[i].clk_idx; | ||
| 1806 | clock_info = (union pplib_clock_info *) | ||
| 1807 | &clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize]; | ||
| 1808 | sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow); | ||
| 1809 | sclk |= clock_info->sumo.ucEngineClockHigh << 16; | ||
| 1810 | rdev->pm.dpm.vce_states[i].sclk = sclk; | ||
| 1811 | rdev->pm.dpm.vce_states[i].mclk = 0; | ||
| 1812 | } | ||
| 1813 | |||
| 1736 | return 0; | 1814 | return 0; |
| 1737 | } | 1815 | } |
| 1738 | 1816 | ||
| @@ -1914,6 +1992,10 @@ int trinity_dpm_init(struct radeon_device *rdev) | |||
| 1914 | if (ret) | 1992 | if (ret) |
| 1915 | return ret; | 1993 | return ret; |
| 1916 | 1994 | ||
| 1995 | ret = r600_parse_extended_power_table(rdev); | ||
| 1996 | if (ret) | ||
| 1997 | return ret; | ||
| 1998 | |||
| 1917 | ret = trinity_parse_power_table(rdev); | 1999 | ret = trinity_parse_power_table(rdev); |
| 1918 | if (ret) | 2000 | if (ret) |
| 1919 | return ret; | 2001 | return ret; |
| @@ -2000,6 +2082,7 @@ void trinity_dpm_fini(struct radeon_device *rdev) | |||
| 2000 | } | 2082 | } |
| 2001 | kfree(rdev->pm.dpm.ps); | 2083 | kfree(rdev->pm.dpm.ps); |
| 2002 | kfree(rdev->pm.dpm.priv); | 2084 | kfree(rdev->pm.dpm.priv); |
| 2085 | r600_free_extended_power_table(rdev); | ||
| 2003 | } | 2086 | } |
| 2004 | 2087 | ||
| 2005 | u32 trinity_dpm_get_sclk(struct radeon_device *rdev, bool low) | 2088 | u32 trinity_dpm_get_sclk(struct radeon_device *rdev, bool low) |
