aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorAlex Deucher <alexander.deucher@amd.com>2012-11-07 20:05:07 -0500
committerAlex Deucher <alexander.deucher@amd.com>2013-06-27 19:15:48 -0400
commit0c4aaeae441495b21b9c7d306098ee4911bfa16a (patch)
tree6865baac28f703c024262ba1feb0ef8b63d57c69 /drivers/gpu/drm
parent06793dfba2215f3d31a7a12e5fd8901f18ee035a (diff)
drm/radeon: add dpm UVD handling for TN asics (v2)
v2: fix typo noticed by Dan Carpenter Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/radeon/ppsmc.h1
-rw-r--r--drivers/gpu/drm/radeon/trinity_dpm.c220
-rw-r--r--drivers/gpu/drm/radeon/trinity_dpm.h18
-rw-r--r--drivers/gpu/drm/radeon/trinity_smc.c5
-rw-r--r--drivers/gpu/drm/radeon/trinityd.h5
5 files changed, 249 insertions, 0 deletions
diff --git a/drivers/gpu/drm/radeon/ppsmc.h b/drivers/gpu/drm/radeon/ppsmc.h
index 88838083448b..66c4bedba0dc 100644
--- a/drivers/gpu/drm/radeon/ppsmc.h
+++ b/drivers/gpu/drm/radeon/ppsmc.h
@@ -77,6 +77,7 @@ typedef uint8_t PPSMC_Result;
77#define PPSMC_MSG_PG_SIMD_Config ((uint32_t) 0x108) 77#define PPSMC_MSG_PG_SIMD_Config ((uint32_t) 0x108)
78#define PPSMC_MSG_DCE_RemoveVoltageAdjustment ((uint32_t) 0x11d) 78#define PPSMC_MSG_DCE_RemoveVoltageAdjustment ((uint32_t) 0x11d)
79#define PPSMC_MSG_DCE_AllowVoltageAdjustment ((uint32_t) 0x11e) 79#define PPSMC_MSG_DCE_AllowVoltageAdjustment ((uint32_t) 0x11e)
80#define PPSMC_MSG_UVD_DPM_Config ((uint32_t) 0x124)
80 81
81 82
82typedef uint16_t PPSMC_Msg; 83typedef uint16_t PPSMC_Msg;
diff --git a/drivers/gpu/drm/radeon/trinity_dpm.c b/drivers/gpu/drm/radeon/trinity_dpm.c
index c4779a6ef48f..1b3822ff6083 100644
--- a/drivers/gpu/drm/radeon/trinity_dpm.c
+++ b/drivers/gpu/drm/radeon/trinity_dpm.c
@@ -866,6 +866,117 @@ static void trinity_program_bootup_state(struct radeon_device *rdev)
866 trinity_power_level_enable_disable(rdev, i, false); 866 trinity_power_level_enable_disable(rdev, i, false);
867} 867}
868 868
869static void trinity_setup_uvd_clock_table(struct radeon_device *rdev,
870 struct radeon_ps *rps)
871{
872 struct trinity_ps *ps = trinity_get_ps(rps);
873 u32 uvdstates = (ps->vclk_low_divider |
874 ps->vclk_high_divider << 8 |
875 ps->dclk_low_divider << 16 |
876 ps->dclk_high_divider << 24);
877
878 WREG32_SMC(SMU_UVD_DPM_STATES, uvdstates);
879}
880
881static void trinity_setup_uvd_dpm_interval(struct radeon_device *rdev,
882 u32 interval)
883{
884 u32 p, u;
885 u32 tp = RREG32_SMC(PM_TP);
886 u32 val;
887 u32 xclk = sumo_get_xclk(rdev);
888
889 r600_calculate_u_and_p(interval, xclk, 16, &p, &u);
890
891 val = (p + tp - 1) / tp;
892
893 WREG32_SMC(SMU_UVD_DPM_CNTL, val);
894}
895
896static bool trinity_uvd_clocks_zero(struct radeon_ps *rps)
897{
898 if ((rps->vclk == 0) && (rps->dclk == 0))
899 return true;
900 else
901 return false;
902}
903
904static bool trinity_uvd_clocks_equal(struct radeon_ps *rps1,
905 struct radeon_ps *rps2)
906{
907 struct trinity_ps *ps1 = trinity_get_ps(rps1);
908 struct trinity_ps *ps2 = trinity_get_ps(rps2);
909
910 if ((rps1->vclk == rps2->vclk) &&
911 (rps1->dclk == rps2->dclk) &&
912 (ps1->vclk_low_divider == ps2->vclk_low_divider) &&
913 (ps1->vclk_high_divider == ps2->vclk_high_divider) &&
914 (ps1->dclk_low_divider == ps2->dclk_low_divider) &&
915 (ps1->dclk_high_divider == ps2->dclk_high_divider))
916 return true;
917 else
918 return false;
919}
920
921static void trinity_setup_uvd_clocks(struct radeon_device *rdev,
922 struct radeon_ps *current_rps,
923 struct radeon_ps *new_rps)
924{
925 struct trinity_power_info *pi = trinity_get_pi(rdev);
926
927 if (pi->uvd_dpm) {
928 if (trinity_uvd_clocks_zero(new_rps) &&
929 !trinity_uvd_clocks_zero(current_rps)) {
930 trinity_setup_uvd_dpm_interval(rdev, 0);
931 } else if (!trinity_uvd_clocks_zero(new_rps)) {
932 trinity_setup_uvd_clock_table(rdev, new_rps);
933
934 if (trinity_uvd_clocks_zero(current_rps)) {
935 u32 tmp = RREG32(CG_MISC_REG);
936 tmp &= 0xfffffffd;
937 WREG32(CG_MISC_REG, tmp);
938
939 radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
940
941 trinity_setup_uvd_dpm_interval(rdev, 3000);
942 }
943 }
944 trinity_uvd_dpm_config(rdev);
945 } else {
946 if (trinity_uvd_clocks_zero(new_rps) ||
947 trinity_uvd_clocks_equal(new_rps, current_rps))
948 return;
949
950 radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
951 }
952}
953
954static void trinity_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev)
955{
956 struct trinity_ps *new_ps = trinity_get_ps(rdev->pm.dpm.requested_ps);
957 struct trinity_ps *current_ps = trinity_get_ps(rdev->pm.dpm.current_ps);
958
959 if (new_ps->levels[new_ps->num_levels - 1].sclk >=
960 current_ps->levels[current_ps->num_levels - 1].sclk)
961 return;
962
963 trinity_setup_uvd_clocks(rdev, rdev->pm.dpm.current_ps,
964 rdev->pm.dpm.requested_ps);
965}
966
967static void trinity_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev)
968{
969 struct trinity_ps *new_ps = trinity_get_ps(rdev->pm.dpm.requested_ps);
970 struct trinity_ps *current_ps = trinity_get_ps(rdev->pm.dpm.current_ps);
971
972 if (new_ps->levels[new_ps->num_levels - 1].sclk <
973 current_ps->levels[current_ps->num_levels - 1].sclk)
974 return;
975
976 trinity_setup_uvd_clocks(rdev, rdev->pm.dpm.current_ps,
977 rdev->pm.dpm.requested_ps);
978}
979
869static void trinity_program_ttt(struct radeon_device *rdev) 980static void trinity_program_ttt(struct radeon_device *rdev)
870{ 981{
871 struct trinity_power_info *pi = trinity_get_pi(rdev); 982 struct trinity_power_info *pi = trinity_get_pi(rdev);
@@ -1017,6 +1128,7 @@ int trinity_dpm_set_power_state(struct radeon_device *rdev)
1017 1128
1018 trinity_acquire_mutex(rdev); 1129 trinity_acquire_mutex(rdev);
1019 if (pi->enable_dpm) { 1130 if (pi->enable_dpm) {
1131 trinity_set_uvd_clock_before_set_eng_clock(rdev);
1020 trinity_enable_power_level_0(rdev); 1132 trinity_enable_power_level_0(rdev);
1021 trinity_force_level_0(rdev); 1133 trinity_force_level_0(rdev);
1022 trinity_wait_for_level_0(rdev); 1134 trinity_wait_for_level_0(rdev);
@@ -1024,6 +1136,7 @@ int trinity_dpm_set_power_state(struct radeon_device *rdev)
1024 trinity_program_power_levels_0_to_n(rdev); 1136 trinity_program_power_levels_0_to_n(rdev);
1025 trinity_force_level_0(rdev); 1137 trinity_force_level_0(rdev);
1026 trinity_unforce_levels(rdev); 1138 trinity_unforce_levels(rdev);
1139 trinity_set_uvd_clock_after_set_eng_clock(rdev);
1027 } 1140 }
1028 trinity_release_mutex(rdev); 1141 trinity_release_mutex(rdev);
1029 1142
@@ -1198,6 +1311,61 @@ static u8 trinity_calculate_display_wm(struct radeon_device *rdev,
1198 } 1311 }
1199} 1312}
1200 1313
1314static u32 trinity_get_uvd_clock_index(struct radeon_device *rdev,
1315 struct radeon_ps *rps)
1316{
1317 struct trinity_power_info *pi = trinity_get_pi(rdev);
1318 u32 i = 0;
1319
1320 for (i = 0; i < 4; i++) {
1321 if ((rps->vclk == pi->sys_info.uvd_clock_table_entries[i].vclk) &&
1322 (rps->dclk == pi->sys_info.uvd_clock_table_entries[i].dclk))
1323 break;
1324 }
1325
1326 if (i >= 4) {
1327 DRM_ERROR("UVD clock index not found!\n");
1328 i = 3;
1329 }
1330 return i;
1331}
1332
1333static void trinity_adjust_uvd_state(struct radeon_device *rdev,
1334 struct radeon_ps *rps)
1335{
1336 struct trinity_ps *ps = trinity_get_ps(rps);
1337 struct trinity_power_info *pi = trinity_get_pi(rdev);
1338 u32 high_index = 0;
1339 u32 low_index = 0;
1340
1341 if (pi->uvd_dpm && r600_is_uvd_state(rps->class, rps->class2)) {
1342 high_index = trinity_get_uvd_clock_index(rdev, rps);
1343
1344 switch(high_index) {
1345 case 3:
1346 case 2:
1347 low_index = 1;
1348 break;
1349 case 1:
1350 case 0:
1351 default:
1352 low_index = 0;
1353 break;
1354 }
1355
1356 ps->vclk_low_divider =
1357 pi->sys_info.uvd_clock_table_entries[high_index].vclk_did;
1358 ps->dclk_low_divider =
1359 pi->sys_info.uvd_clock_table_entries[high_index].dclk_did;
1360 ps->vclk_high_divider =
1361 pi->sys_info.uvd_clock_table_entries[low_index].vclk_did;
1362 ps->dclk_high_divider =
1363 pi->sys_info.uvd_clock_table_entries[low_index].dclk_did;
1364 }
1365}
1366
1367
1368
1201static void trinity_apply_state_adjust_rules(struct radeon_device *rdev) 1369static void trinity_apply_state_adjust_rules(struct radeon_device *rdev)
1202{ 1370{
1203 struct radeon_ps *rps = rdev->pm.dpm.requested_ps; 1371 struct radeon_ps *rps = rdev->pm.dpm.requested_ps;
@@ -1214,6 +1382,8 @@ static void trinity_apply_state_adjust_rules(struct radeon_device *rdev)
1214 if (rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL) 1382 if (rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
1215 return trinity_patch_thermal_state(rdev, ps, current_ps); 1383 return trinity_patch_thermal_state(rdev, ps, current_ps);
1216 1384
1385 trinity_adjust_uvd_state(rdev, rps);
1386
1217 for (i = 0; i < ps->num_levels; i++) { 1387 for (i = 0; i < ps->num_levels; i++) {
1218 if (ps->levels[i].vddc_index < min_voltage) 1388 if (ps->levels[i].vddc_index < min_voltage)
1219 ps->levels[i].vddc_index = min_voltage; 1389 ps->levels[i].vddc_index = min_voltage;
@@ -1454,6 +1624,25 @@ union igp_info {
1454 struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7; 1624 struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;
1455}; 1625};
1456 1626
1627static u32 trinity_convert_did_to_freq(struct radeon_device *rdev, u8 did)
1628{
1629 struct trinity_power_info *pi = trinity_get_pi(rdev);
1630 u32 divider;
1631
1632 if (did >= 8 && did <= 0x3f)
1633 divider = did * 25;
1634 else if (did > 0x3f && did <= 0x5f)
1635 divider = (did - 64) * 50 + 1600;
1636 else if (did > 0x5f && did <= 0x7e)
1637 divider = (did - 96) * 100 + 3200;
1638 else if (did == 0x7f)
1639 divider = 128 * 100;
1640 else
1641 return 10000;
1642
1643 return ((pi->sys_info.dentist_vco_freq * 100) + (divider - 1)) / divider;
1644}
1645
1457static int trinity_parse_sys_info_table(struct radeon_device *rdev) 1646static int trinity_parse_sys_info_table(struct radeon_device *rdev)
1458{ 1647{
1459 struct trinity_power_info *pi = trinity_get_pi(rdev); 1648 struct trinity_power_info *pi = trinity_get_pi(rdev);
@@ -1476,6 +1665,7 @@ static int trinity_parse_sys_info_table(struct radeon_device *rdev)
1476 pi->sys_info.bootup_sclk = le32_to_cpu(igp_info->info_7.ulBootUpEngineClock); 1665 pi->sys_info.bootup_sclk = le32_to_cpu(igp_info->info_7.ulBootUpEngineClock);
1477 pi->sys_info.min_sclk = le32_to_cpu(igp_info->info_7.ulMinEngineClock); 1666 pi->sys_info.min_sclk = le32_to_cpu(igp_info->info_7.ulMinEngineClock);
1478 pi->sys_info.bootup_uma_clk = le32_to_cpu(igp_info->info_7.ulBootUpUMAClock); 1667 pi->sys_info.bootup_uma_clk = le32_to_cpu(igp_info->info_7.ulBootUpUMAClock);
1668 pi->sys_info.dentist_vco_freq = le32_to_cpu(igp_info->info_7.ulDentistVCOFreq);
1479 pi->sys_info.bootup_nb_voltage_index = 1669 pi->sys_info.bootup_nb_voltage_index =
1480 le16_to_cpu(igp_info->info_7.usBootUpNBVoltage); 1670 le16_to_cpu(igp_info->info_7.usBootUpNBVoltage);
1481 if (igp_info->info_7.ucHtcTmpLmt == 0) 1671 if (igp_info->info_7.ucHtcTmpLmt == 0)
@@ -1521,6 +1711,35 @@ static int trinity_parse_sys_info_table(struct radeon_device *rdev)
1521 sumo_construct_vid_mapping_table(rdev, &pi->sys_info.vid_mapping_table, 1711 sumo_construct_vid_mapping_table(rdev, &pi->sys_info.vid_mapping_table,
1522 igp_info->info_7.sAvail_SCLK); 1712 igp_info->info_7.sAvail_SCLK);
1523 1713
1714 pi->sys_info.uvd_clock_table_entries[0].vclk_did =
1715 igp_info->info_7.ucDPMState0VclkFid;
1716 pi->sys_info.uvd_clock_table_entries[1].vclk_did =
1717 igp_info->info_7.ucDPMState1VclkFid;
1718 pi->sys_info.uvd_clock_table_entries[2].vclk_did =
1719 igp_info->info_7.ucDPMState2VclkFid;
1720 pi->sys_info.uvd_clock_table_entries[3].vclk_did =
1721 igp_info->info_7.ucDPMState3VclkFid;
1722
1723 pi->sys_info.uvd_clock_table_entries[0].dclk_did =
1724 igp_info->info_7.ucDPMState0DclkFid;
1725 pi->sys_info.uvd_clock_table_entries[1].dclk_did =
1726 igp_info->info_7.ucDPMState1DclkFid;
1727 pi->sys_info.uvd_clock_table_entries[2].dclk_did =
1728 igp_info->info_7.ucDPMState2DclkFid;
1729 pi->sys_info.uvd_clock_table_entries[3].dclk_did =
1730 igp_info->info_7.ucDPMState3DclkFid;
1731
1732 for (i = 0; i < 4; i++) {
1733 pi->sys_info.uvd_clock_table_entries[i].vclk =
1734 trinity_convert_did_to_freq(rdev,
1735 pi->sys_info.uvd_clock_table_entries[i].vclk_did);
1736 pi->sys_info.uvd_clock_table_entries[i].dclk =
1737 trinity_convert_did_to_freq(rdev,
1738 pi->sys_info.uvd_clock_table_entries[i].dclk_did);
1739 }
1740
1741
1742
1524 } 1743 }
1525 return 0; 1744 return 0;
1526} 1745}
@@ -1547,6 +1766,7 @@ int trinity_dpm_init(struct radeon_device *rdev)
1547 pi->override_dynamic_mgpg = true; 1766 pi->override_dynamic_mgpg = true;
1548 pi->enable_auto_thermal_throttling = true; 1767 pi->enable_auto_thermal_throttling = true;
1549 pi->voltage_drop_in_dce = false; /* need to restructure dpm/modeset interaction */ 1768 pi->voltage_drop_in_dce = false; /* need to restructure dpm/modeset interaction */
1769 pi->uvd_dpm = true; /* ??? */
1550 1770
1551 ret = trinity_parse_sys_info_table(rdev); 1771 ret = trinity_parse_sys_info_table(rdev);
1552 if (ret) 1772 if (ret)
diff --git a/drivers/gpu/drm/radeon/trinity_dpm.h b/drivers/gpu/drm/radeon/trinity_dpm.h
index 15e050fd5446..31100ac64245 100644
--- a/drivers/gpu/drm/radeon/trinity_dpm.h
+++ b/drivers/gpu/drm/radeon/trinity_dpm.h
@@ -55,14 +55,29 @@ struct trinity_ps {
55 u8 Dpm0PgNbPsHi; 55 u8 Dpm0PgNbPsHi;
56 u8 DpmXNbPsLo; 56 u8 DpmXNbPsLo;
57 u8 DpmXNbPsHi; 57 u8 DpmXNbPsHi;
58
59 u32 vclk_low_divider;
60 u32 vclk_high_divider;
61 u32 dclk_low_divider;
62 u32 dclk_high_divider;
58}; 63};
59 64
60#define TRINITY_NUM_NBPSTATES 4 65#define TRINITY_NUM_NBPSTATES 4
61 66
67struct trinity_uvd_clock_table_entry
68{
69 u32 vclk;
70 u32 dclk;
71 u8 vclk_did;
72 u8 dclk_did;
73 u8 rsv[2];
74};
75
62struct trinity_sys_info { 76struct trinity_sys_info {
63 u32 bootup_uma_clk; 77 u32 bootup_uma_clk;
64 u32 bootup_sclk; 78 u32 bootup_sclk;
65 u32 min_sclk; 79 u32 min_sclk;
80 u32 dentist_vco_freq;
66 u32 nb_dpm_enable; 81 u32 nb_dpm_enable;
67 u32 nbp_mclk[TRINITY_NUM_NBPSTATES]; 82 u32 nbp_mclk[TRINITY_NUM_NBPSTATES];
68 u32 nbp_nclk[TRINITY_NUM_NBPSTATES]; 83 u32 nbp_nclk[TRINITY_NUM_NBPSTATES];
@@ -73,6 +88,7 @@ struct trinity_sys_info {
73 struct sumo_sclk_voltage_mapping_table sclk_voltage_mapping_table; 88 struct sumo_sclk_voltage_mapping_table sclk_voltage_mapping_table;
74 struct sumo_vid_mapping_table vid_mapping_table; 89 struct sumo_vid_mapping_table vid_mapping_table;
75 u32 uma_channel_number; 90 u32 uma_channel_number;
91 struct trinity_uvd_clock_table_entry uvd_clock_table_entries[4];
76}; 92};
77 93
78struct trinity_power_info { 94struct trinity_power_info {
@@ -93,12 +109,14 @@ struct trinity_power_info {
93 bool enable_auto_thermal_throttling; 109 bool enable_auto_thermal_throttling;
94 bool enable_dpm; 110 bool enable_dpm;
95 bool enable_sclk_ds; 111 bool enable_sclk_ds;
112 bool uvd_dpm;
96}; 113};
97 114
98#define TRINITY_AT_DFLT 30 115#define TRINITY_AT_DFLT 30
99 116
100/* trinity_smc.c */ 117/* trinity_smc.c */
101int trinity_dpm_config(struct radeon_device *rdev, bool enable); 118int trinity_dpm_config(struct radeon_device *rdev, bool enable);
119int trinity_uvd_dpm_config(struct radeon_device *rdev);
102int trinity_dpm_force_state(struct radeon_device *rdev, u32 n); 120int trinity_dpm_force_state(struct radeon_device *rdev, u32 n);
103int trinity_dpm_no_forced_level(struct radeon_device *rdev); 121int trinity_dpm_no_forced_level(struct radeon_device *rdev);
104int trinity_dce_enable_voltage_adjustment(struct radeon_device *rdev, 122int trinity_dce_enable_voltage_adjustment(struct radeon_device *rdev,
diff --git a/drivers/gpu/drm/radeon/trinity_smc.c b/drivers/gpu/drm/radeon/trinity_smc.c
index 60ffc1e6f21b..85f86a29513c 100644
--- a/drivers/gpu/drm/radeon/trinity_smc.c
+++ b/drivers/gpu/drm/radeon/trinity_smc.c
@@ -73,6 +73,11 @@ int trinity_dpm_force_state(struct radeon_device *rdev, u32 n)
73 return trinity_notify_message_to_smu(rdev, PPSMC_MSG_DPM_ForceState); 73 return trinity_notify_message_to_smu(rdev, PPSMC_MSG_DPM_ForceState);
74} 74}
75 75
76int trinity_uvd_dpm_config(struct radeon_device *rdev)
77{
78 return trinity_notify_message_to_smu(rdev, PPSMC_MSG_UVD_DPM_Config);
79}
80
76int trinity_dpm_no_forced_level(struct radeon_device *rdev) 81int trinity_dpm_no_forced_level(struct radeon_device *rdev)
77{ 82{
78 return trinity_notify_message_to_smu(rdev, PPSMC_MSG_NoForcedLevel); 83 return trinity_notify_message_to_smu(rdev, PPSMC_MSG_NoForcedLevel);
diff --git a/drivers/gpu/drm/radeon/trinityd.h b/drivers/gpu/drm/radeon/trinityd.h
index b234d36ddce0..fd32e2771755 100644
--- a/drivers/gpu/drm/radeon/trinityd.h
+++ b/drivers/gpu/drm/radeon/trinityd.h
@@ -100,6 +100,9 @@
100# define HT_MASK (0xffff << 16) 100# define HT_MASK (0xffff << 16)
101# define HT_SHIFT 16 101# define HT_SHIFT 16
102 102
103#define SMU_UVD_DPM_STATES 0x1f1a0
104#define SMU_UVD_DPM_CNTL 0x1f1a4
105
103#define SMU_S_PG_CNTL 0x1f118 106#define SMU_S_PG_CNTL 0x1f118
104# define DS_PG_EN(x) ((x) << 16) 107# define DS_PG_EN(x) ((x) << 16)
105# define DS_PG_EN_MASK (0xff << 16) 108# define DS_PG_EN_MASK (0xff << 16)
@@ -198,6 +201,8 @@
198# define SU_MASK (0xffff << 16) 201# define SU_MASK (0xffff << 16)
199# define SU_SHIFT 16 202# define SU_SHIFT 16
200 203
204#define CG_MISC_REG 0x708
205
201#define CG_THERMAL_INT_CTRL 0x738 206#define CG_THERMAL_INT_CTRL 0x738
202# define DIG_THERM_INTH(x) ((x) << 0) 207# define DIG_THERM_INTH(x) ((x) << 0)
203# define DIG_THERM_INTH_MASK (0xff << 0) 208# define DIG_THERM_INTH_MASK (0xff << 0)