diff options
author | Mario Kleiner <mario.kleiner@tuebingen.mpg.de> | 2010-10-05 19:57:36 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2010-10-05 21:46:27 -0400 |
commit | 6383cf7d7839bf52aa4efa20cc921773126797f4 (patch) | |
tree | 963fa5cff40af73656442ccc1b7fdaf2097332ea /drivers | |
parent | ba032a58d1f320039e7850fb6e8651695c1aa571 (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')
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_display.c | 153 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_mode.h | 7 |
2 files changed, 160 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 | */ | ||
1015 | int 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 | } | ||
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index d25cf093c84d..f4396d71b417 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h | |||
@@ -428,6 +428,11 @@ struct radeon_framebuffer { | |||
428 | struct drm_gem_object *obj; | 428 | struct drm_gem_object *obj; |
429 | }; | 429 | }; |
430 | 430 | ||
431 | /* radeon_get_crtc_scanoutpos() return flags */ | ||
432 | #define RADEON_SCANOUTPOS_VALID (1 << 0) | ||
433 | #define RADEON_SCANOUTPOS_INVBL (1 << 1) | ||
434 | #define RADEON_SCANOUTPOS_ACCURATE (1 << 2) | ||
435 | |||
431 | extern enum radeon_tv_std | 436 | extern enum radeon_tv_std |
432 | radeon_combios_get_tv_info(struct radeon_device *rdev); | 437 | radeon_combios_get_tv_info(struct radeon_device *rdev); |
433 | extern enum radeon_tv_std | 438 | extern enum radeon_tv_std |
@@ -531,6 +536,8 @@ extern int radeon_crtc_cursor_set(struct drm_crtc *crtc, | |||
531 | extern int radeon_crtc_cursor_move(struct drm_crtc *crtc, | 536 | extern int radeon_crtc_cursor_move(struct drm_crtc *crtc, |
532 | int x, int y); | 537 | int x, int y); |
533 | 538 | ||
539 | extern int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos, int *hpos); | ||
540 | |||
534 | extern bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev); | 541 | extern bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev); |
535 | extern struct edid * | 542 | extern struct edid * |
536 | radeon_combios_get_hardcoded_edid(struct radeon_device *rdev); | 543 | radeon_combios_get_hardcoded_edid(struct radeon_device *rdev); |