aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/radeon_display.c
diff options
context:
space:
mode:
authorMario Kleiner <mario.kleiner@tuebingen.mpg.de>2010-10-05 19:57:36 -0400
committerDave Airlie <airlied@redhat.com>2010-10-05 21:46:27 -0400
commit6383cf7d7839bf52aa4efa20cc921773126797f4 (patch)
tree963fa5cff40af73656442ccc1b7fdaf2097332ea /drivers/gpu/drm/radeon/radeon_display.c
parentba032a58d1f320039e7850fb6e8651695c1aa571 (diff)
drm/radeon: Add function for display scanout position query.
radeon_get_crtc_scanoutpos() returns the current horizontal and vertical scanout position of a crtc. It also reports if the display scanout is currently inside the vblank area. hpos reports current horizontal pixel scanout position. vpos reports the current scanned out line as a value >= 0 in active scanout. If the scanout is inside vblank area, it reports a negative value, the number of scanlines until end of vblank aka start of active scanout, e.g., -3 == "At most 3 scanlines until end of vblank". This code is derived from radeon_pm_in_vbl(), tested on R500 and R600. Signed-off-by: Mario Kleiner <mario.kleiner@tuebingen.mpg.de> Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_display.c')
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c153
1 files changed, 153 insertions, 0 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 325a07391b3c..fd70b8428f39 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -989,3 +989,156 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
989 } 989 }
990 return true; 990 return true;
991} 991}
992
993/*
994 * Retrieve current video scanout position of crtc on a given gpu.
995 *
996 * \param rdev Device to query.
997 * \param crtc Crtc to query.
998 * \param *vpos Location where vertical scanout position should be stored.
999 * \param *hpos Location where horizontal scanout position should go.
1000 *
1001 * Returns vpos as a positive number while in active scanout area.
1002 * Returns vpos as a negative number inside vblank, counting the number
1003 * of scanlines to go until end of vblank, e.g., -1 means "one scanline
1004 * until start of active scanout / end of vblank."
1005 *
1006 * \return Flags, or'ed together as follows:
1007 *
1008 * RADEON_SCANOUTPOS_VALID = Query successfull.
1009 * RADEON_SCANOUTPOS_INVBL = Inside vblank.
1010 * RADEON_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of
1011 * this flag means that returned position may be offset by a constant but
1012 * unknown small number of scanlines wrt. real scanout position.
1013 *
1014 */
1015int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos, int *hpos)
1016{
1017 u32 stat_crtc = 0, vbl = 0, position = 0;
1018 int vbl_start, vbl_end, vtotal, ret = 0;
1019 bool in_vbl = true;
1020
1021 if (ASIC_IS_DCE4(rdev)) {
1022 if (crtc == 0) {
1023 vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
1024 EVERGREEN_CRTC0_REGISTER_OFFSET);
1025 position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
1026 EVERGREEN_CRTC0_REGISTER_OFFSET);
1027 ret |= RADEON_SCANOUTPOS_VALID;
1028 }
1029 if (crtc == 1) {
1030 vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
1031 EVERGREEN_CRTC1_REGISTER_OFFSET);
1032 position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
1033 EVERGREEN_CRTC1_REGISTER_OFFSET);
1034 ret |= RADEON_SCANOUTPOS_VALID;
1035 }
1036 if (crtc == 2) {
1037 vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
1038 EVERGREEN_CRTC2_REGISTER_OFFSET);
1039 position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
1040 EVERGREEN_CRTC2_REGISTER_OFFSET);
1041 ret |= RADEON_SCANOUTPOS_VALID;
1042 }
1043 if (crtc == 3) {
1044 vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
1045 EVERGREEN_CRTC3_REGISTER_OFFSET);
1046 position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
1047 EVERGREEN_CRTC3_REGISTER_OFFSET);
1048 ret |= RADEON_SCANOUTPOS_VALID;
1049 }
1050 if (crtc == 4) {
1051 vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
1052 EVERGREEN_CRTC4_REGISTER_OFFSET);
1053 position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
1054 EVERGREEN_CRTC4_REGISTER_OFFSET);
1055 ret |= RADEON_SCANOUTPOS_VALID;
1056 }
1057 if (crtc == 5) {
1058 vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
1059 EVERGREEN_CRTC5_REGISTER_OFFSET);
1060 position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
1061 EVERGREEN_CRTC5_REGISTER_OFFSET);
1062 ret |= RADEON_SCANOUTPOS_VALID;
1063 }
1064 } else if (ASIC_IS_AVIVO(rdev)) {
1065 if (crtc == 0) {
1066 vbl = RREG32(AVIVO_D1CRTC_V_BLANK_START_END);
1067 position = RREG32(AVIVO_D1CRTC_STATUS_POSITION);
1068 ret |= RADEON_SCANOUTPOS_VALID;
1069 }
1070 if (crtc == 1) {
1071 vbl = RREG32(AVIVO_D2CRTC_V_BLANK_START_END);
1072 position = RREG32(AVIVO_D2CRTC_STATUS_POSITION);
1073 ret |= RADEON_SCANOUTPOS_VALID;
1074 }
1075 } else {
1076 /* Pre-AVIVO: Different encoding of scanout pos and vblank interval. */
1077 if (crtc == 0) {
1078 /* Assume vbl_end == 0, get vbl_start from
1079 * upper 16 bits.
1080 */
1081 vbl = (RREG32(RADEON_CRTC_V_TOTAL_DISP) &
1082 RADEON_CRTC_V_DISP) >> RADEON_CRTC_V_DISP_SHIFT;
1083 /* Only retrieve vpos from upper 16 bits, set hpos == 0. */
1084 position = (RREG32(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL;
1085 stat_crtc = RREG32(RADEON_CRTC_STATUS);
1086 if (!(stat_crtc & 1))
1087 in_vbl = false;
1088
1089 ret |= RADEON_SCANOUTPOS_VALID;
1090 }
1091 if (crtc == 1) {
1092 vbl = (RREG32(RADEON_CRTC2_V_TOTAL_DISP) &
1093 RADEON_CRTC_V_DISP) >> RADEON_CRTC_V_DISP_SHIFT;
1094 position = (RREG32(RADEON_CRTC2_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL;
1095 stat_crtc = RREG32(RADEON_CRTC2_STATUS);
1096 if (!(stat_crtc & 1))
1097 in_vbl = false;
1098
1099 ret |= RADEON_SCANOUTPOS_VALID;
1100 }
1101 }
1102
1103 /* Decode into vertical and horizontal scanout position. */
1104 *vpos = position & 0x1fff;
1105 *hpos = (position >> 16) & 0x1fff;
1106
1107 /* Valid vblank area boundaries from gpu retrieved? */
1108 if (vbl > 0) {
1109 /* Yes: Decode. */
1110 ret |= RADEON_SCANOUTPOS_ACCURATE;
1111 vbl_start = vbl & 0x1fff;
1112 vbl_end = (vbl >> 16) & 0x1fff;
1113 }
1114 else {
1115 /* No: Fake something reasonable which gives at least ok results. */
1116 vbl_start = rdev->mode_info.crtcs[crtc]->base.mode.crtc_vdisplay;
1117 vbl_end = 0;
1118 }
1119
1120 /* Test scanout position against vblank region. */
1121 if ((*vpos < vbl_start) && (*vpos >= vbl_end))
1122 in_vbl = false;
1123
1124 /* Check if inside vblank area and apply corrective offsets:
1125 * vpos will then be >=0 in video scanout area, but negative
1126 * within vblank area, counting down the number of lines until
1127 * start of scanout.
1128 */
1129
1130 /* Inside "upper part" of vblank area? Apply corrective offset if so: */
1131 if (in_vbl && (*vpos >= vbl_start)) {
1132 vtotal = rdev->mode_info.crtcs[crtc]->base.mode.crtc_vtotal;
1133 *vpos = *vpos - vtotal;
1134 }
1135
1136 /* Correct for shifted end of vbl at vbl_end. */
1137 *vpos = *vpos - vbl_end;
1138
1139 /* In vblank? */
1140 if (in_vbl)
1141 ret |= RADEON_SCANOUTPOS_INVBL;
1142
1143 return ret;
1144}