aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMario Kleiner <mario.kleiner@tuebingen.mpg.de>2010-10-22 22:42:17 -0400
committerDave Airlie <airlied@redhat.com>2010-11-21 20:48:26 -0500
commitf5a8020903932624cf020dc72455a10a3e005087 (patch)
treefed9a5a2acadf001d5866d42dad8b308f864ac75 /drivers
parent27641c3f003e7f3b6585c01d8a788883603eb262 (diff)
drm/kms/radeon: Add support for precise vblank timestamping.
This patch adds new functions for use by the drm core: .get_vblank_timestamp() provides a precise timestamp for the end of the most recent (or current) vblank interval of a given crtc, as needed for the DRI2 implementation of the OML_sync_control extension. It is a thin wrapper around the drm function drm_calc_vbltimestamp_from_scanoutpos() which does almost all the work and is shared across drivers. .get_scanout_position() provides the current horizontal and vertical video scanout position and "in vblank" status of a given crtc, as needed by the drm for use by drm_calc_vbltimestamp_from_scanoutpos(). The function is also used by the dynamic gpu reclocking code to determine when it is safe to reclock inside vblank. For that purpose radeon_pm_in_vbl() is modified to accomodate a small change in the function prototype of the radeon_get_crtc_scanoutpos() which is hooked up to .get_scanout_position(). This code has been tested on AVIVO hardware, a RV530 (ATI Mobility Radeon X1600) in a Intel Core-2 Duo MacBookPro and some R600 variant (FireGL V7600) in a single cpu AMD Athlon 64 PC. Signed-off-by: Mario Kleiner <mario.kleiner@tuebingen.mpg.de> Reviewed-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.c40
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c8
-rw-r--r--drivers/gpu/drm/radeon/radeon_kms.c21
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h7
-rw-r--r--drivers/gpu/drm/radeon/radeon_pm.c6
5 files changed, 55 insertions, 27 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 1df4dc6c063c..eeea7cbb9517 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -1019,7 +1019,7 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
1019/* 1019/*
1020 * Retrieve current video scanout position of crtc on a given gpu. 1020 * Retrieve current video scanout position of crtc on a given gpu.
1021 * 1021 *
1022 * \param rdev Device to query. 1022 * \param dev Device to query.
1023 * \param crtc Crtc to query. 1023 * \param crtc Crtc to query.
1024 * \param *vpos Location where vertical scanout position should be stored. 1024 * \param *vpos Location where vertical scanout position should be stored.
1025 * \param *hpos Location where horizontal scanout position should go. 1025 * \param *hpos Location where horizontal scanout position should go.
@@ -1031,72 +1031,74 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
1031 * 1031 *
1032 * \return Flags, or'ed together as follows: 1032 * \return Flags, or'ed together as follows:
1033 * 1033 *
1034 * RADEON_SCANOUTPOS_VALID = Query successfull. 1034 * DRM_SCANOUTPOS_VALID = Query successfull.
1035 * RADEON_SCANOUTPOS_INVBL = Inside vblank. 1035 * DRM_SCANOUTPOS_INVBL = Inside vblank.
1036 * RADEON_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of 1036 * DRM_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of
1037 * this flag means that returned position may be offset by a constant but 1037 * this flag means that returned position may be offset by a constant but
1038 * unknown small number of scanlines wrt. real scanout position. 1038 * unknown small number of scanlines wrt. real scanout position.
1039 * 1039 *
1040 */ 1040 */
1041int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos, int *hpos) 1041int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int *hpos)
1042{ 1042{
1043 u32 stat_crtc = 0, vbl = 0, position = 0; 1043 u32 stat_crtc = 0, vbl = 0, position = 0;
1044 int vbl_start, vbl_end, vtotal, ret = 0; 1044 int vbl_start, vbl_end, vtotal, ret = 0;
1045 bool in_vbl = true; 1045 bool in_vbl = true;
1046 1046
1047 struct radeon_device *rdev = dev->dev_private;
1048
1047 if (ASIC_IS_DCE4(rdev)) { 1049 if (ASIC_IS_DCE4(rdev)) {
1048 if (crtc == 0) { 1050 if (crtc == 0) {
1049 vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + 1051 vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
1050 EVERGREEN_CRTC0_REGISTER_OFFSET); 1052 EVERGREEN_CRTC0_REGISTER_OFFSET);
1051 position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + 1053 position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
1052 EVERGREEN_CRTC0_REGISTER_OFFSET); 1054 EVERGREEN_CRTC0_REGISTER_OFFSET);
1053 ret |= RADEON_SCANOUTPOS_VALID; 1055 ret |= DRM_SCANOUTPOS_VALID;
1054 } 1056 }
1055 if (crtc == 1) { 1057 if (crtc == 1) {
1056 vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + 1058 vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
1057 EVERGREEN_CRTC1_REGISTER_OFFSET); 1059 EVERGREEN_CRTC1_REGISTER_OFFSET);
1058 position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + 1060 position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
1059 EVERGREEN_CRTC1_REGISTER_OFFSET); 1061 EVERGREEN_CRTC1_REGISTER_OFFSET);
1060 ret |= RADEON_SCANOUTPOS_VALID; 1062 ret |= DRM_SCANOUTPOS_VALID;
1061 } 1063 }
1062 if (crtc == 2) { 1064 if (crtc == 2) {
1063 vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + 1065 vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
1064 EVERGREEN_CRTC2_REGISTER_OFFSET); 1066 EVERGREEN_CRTC2_REGISTER_OFFSET);
1065 position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + 1067 position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
1066 EVERGREEN_CRTC2_REGISTER_OFFSET); 1068 EVERGREEN_CRTC2_REGISTER_OFFSET);
1067 ret |= RADEON_SCANOUTPOS_VALID; 1069 ret |= DRM_SCANOUTPOS_VALID;
1068 } 1070 }
1069 if (crtc == 3) { 1071 if (crtc == 3) {
1070 vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + 1072 vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
1071 EVERGREEN_CRTC3_REGISTER_OFFSET); 1073 EVERGREEN_CRTC3_REGISTER_OFFSET);
1072 position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + 1074 position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
1073 EVERGREEN_CRTC3_REGISTER_OFFSET); 1075 EVERGREEN_CRTC3_REGISTER_OFFSET);
1074 ret |= RADEON_SCANOUTPOS_VALID; 1076 ret |= DRM_SCANOUTPOS_VALID;
1075 } 1077 }
1076 if (crtc == 4) { 1078 if (crtc == 4) {
1077 vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + 1079 vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
1078 EVERGREEN_CRTC4_REGISTER_OFFSET); 1080 EVERGREEN_CRTC4_REGISTER_OFFSET);
1079 position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + 1081 position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
1080 EVERGREEN_CRTC4_REGISTER_OFFSET); 1082 EVERGREEN_CRTC4_REGISTER_OFFSET);
1081 ret |= RADEON_SCANOUTPOS_VALID; 1083 ret |= DRM_SCANOUTPOS_VALID;
1082 } 1084 }
1083 if (crtc == 5) { 1085 if (crtc == 5) {
1084 vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + 1086 vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
1085 EVERGREEN_CRTC5_REGISTER_OFFSET); 1087 EVERGREEN_CRTC5_REGISTER_OFFSET);
1086 position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + 1088 position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
1087 EVERGREEN_CRTC5_REGISTER_OFFSET); 1089 EVERGREEN_CRTC5_REGISTER_OFFSET);
1088 ret |= RADEON_SCANOUTPOS_VALID; 1090 ret |= DRM_SCANOUTPOS_VALID;
1089 } 1091 }
1090 } else if (ASIC_IS_AVIVO(rdev)) { 1092 } else if (ASIC_IS_AVIVO(rdev)) {
1091 if (crtc == 0) { 1093 if (crtc == 0) {
1092 vbl = RREG32(AVIVO_D1CRTC_V_BLANK_START_END); 1094 vbl = RREG32(AVIVO_D1CRTC_V_BLANK_START_END);
1093 position = RREG32(AVIVO_D1CRTC_STATUS_POSITION); 1095 position = RREG32(AVIVO_D1CRTC_STATUS_POSITION);
1094 ret |= RADEON_SCANOUTPOS_VALID; 1096 ret |= DRM_SCANOUTPOS_VALID;
1095 } 1097 }
1096 if (crtc == 1) { 1098 if (crtc == 1) {
1097 vbl = RREG32(AVIVO_D2CRTC_V_BLANK_START_END); 1099 vbl = RREG32(AVIVO_D2CRTC_V_BLANK_START_END);
1098 position = RREG32(AVIVO_D2CRTC_STATUS_POSITION); 1100 position = RREG32(AVIVO_D2CRTC_STATUS_POSITION);
1099 ret |= RADEON_SCANOUTPOS_VALID; 1101 ret |= DRM_SCANOUTPOS_VALID;
1100 } 1102 }
1101 } else { 1103 } else {
1102 /* Pre-AVIVO: Different encoding of scanout pos and vblank interval. */ 1104 /* Pre-AVIVO: Different encoding of scanout pos and vblank interval. */
@@ -1112,7 +1114,7 @@ int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos,
1112 if (!(stat_crtc & 1)) 1114 if (!(stat_crtc & 1))
1113 in_vbl = false; 1115 in_vbl = false;
1114 1116
1115 ret |= RADEON_SCANOUTPOS_VALID; 1117 ret |= DRM_SCANOUTPOS_VALID;
1116 } 1118 }
1117 if (crtc == 1) { 1119 if (crtc == 1) {
1118 vbl = (RREG32(RADEON_CRTC2_V_TOTAL_DISP) & 1120 vbl = (RREG32(RADEON_CRTC2_V_TOTAL_DISP) &
@@ -1122,7 +1124,7 @@ int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos,
1122 if (!(stat_crtc & 1)) 1124 if (!(stat_crtc & 1))
1123 in_vbl = false; 1125 in_vbl = false;
1124 1126
1125 ret |= RADEON_SCANOUTPOS_VALID; 1127 ret |= DRM_SCANOUTPOS_VALID;
1126 } 1128 }
1127 } 1129 }
1128 1130
@@ -1133,13 +1135,13 @@ int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos,
1133 /* Valid vblank area boundaries from gpu retrieved? */ 1135 /* Valid vblank area boundaries from gpu retrieved? */
1134 if (vbl > 0) { 1136 if (vbl > 0) {
1135 /* Yes: Decode. */ 1137 /* Yes: Decode. */
1136 ret |= RADEON_SCANOUTPOS_ACCURATE; 1138 ret |= DRM_SCANOUTPOS_ACCURATE;
1137 vbl_start = vbl & 0x1fff; 1139 vbl_start = vbl & 0x1fff;
1138 vbl_end = (vbl >> 16) & 0x1fff; 1140 vbl_end = (vbl >> 16) & 0x1fff;
1139 } 1141 }
1140 else { 1142 else {
1141 /* No: Fake something reasonable which gives at least ok results. */ 1143 /* No: Fake something reasonable which gives at least ok results. */
1142 vbl_start = rdev->mode_info.crtcs[crtc]->base.mode.crtc_vdisplay; 1144 vbl_start = rdev->mode_info.crtcs[crtc]->base.hwmode.crtc_vdisplay;
1143 vbl_end = 0; 1145 vbl_end = 0;
1144 } 1146 }
1145 1147
@@ -1155,7 +1157,7 @@ int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos,
1155 1157
1156 /* Inside "upper part" of vblank area? Apply corrective offset if so: */ 1158 /* Inside "upper part" of vblank area? Apply corrective offset if so: */
1157 if (in_vbl && (*vpos >= vbl_start)) { 1159 if (in_vbl && (*vpos >= vbl_start)) {
1158 vtotal = rdev->mode_info.crtcs[crtc]->base.mode.crtc_vtotal; 1160 vtotal = rdev->mode_info.crtcs[crtc]->base.hwmode.crtc_vtotal;
1159 *vpos = *vpos - vtotal; 1161 *vpos = *vpos - vtotal;
1160 } 1162 }
1161 1163
@@ -1164,7 +1166,7 @@ int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos,
1164 1166
1165 /* In vblank? */ 1167 /* In vblank? */
1166 if (in_vbl) 1168 if (in_vbl)
1167 ret |= RADEON_SCANOUTPOS_INVBL; 1169 ret |= DRM_SCANOUTPOS_INVBL;
1168 1170
1169 return ret; 1171 return ret;
1170} 1172}
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 88e4ea925900..32ec0cc6be92 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -66,6 +66,10 @@ int radeon_resume_kms(struct drm_device *dev);
66u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc); 66u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc);
67int radeon_enable_vblank_kms(struct drm_device *dev, int crtc); 67int radeon_enable_vblank_kms(struct drm_device *dev, int crtc);
68void radeon_disable_vblank_kms(struct drm_device *dev, int crtc); 68void radeon_disable_vblank_kms(struct drm_device *dev, int crtc);
69int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc,
70 int *max_error,
71 struct timeval *vblank_time,
72 unsigned flags);
69void radeon_driver_irq_preinstall_kms(struct drm_device *dev); 73void radeon_driver_irq_preinstall_kms(struct drm_device *dev);
70int radeon_driver_irq_postinstall_kms(struct drm_device *dev); 74int radeon_driver_irq_postinstall_kms(struct drm_device *dev);
71void radeon_driver_irq_uninstall_kms(struct drm_device *dev); 75void radeon_driver_irq_uninstall_kms(struct drm_device *dev);
@@ -74,6 +78,8 @@ int radeon_dma_ioctl_kms(struct drm_device *dev, void *data,
74 struct drm_file *file_priv); 78 struct drm_file *file_priv);
75int radeon_gem_object_init(struct drm_gem_object *obj); 79int radeon_gem_object_init(struct drm_gem_object *obj);
76void radeon_gem_object_free(struct drm_gem_object *obj); 80void radeon_gem_object_free(struct drm_gem_object *obj);
81extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc,
82 int *vpos, int *hpos);
77extern struct drm_ioctl_desc radeon_ioctls_kms[]; 83extern struct drm_ioctl_desc radeon_ioctls_kms[];
78extern int radeon_max_kms_ioctl; 84extern int radeon_max_kms_ioctl;
79int radeon_mmap(struct file *filp, struct vm_area_struct *vma); 85int radeon_mmap(struct file *filp, struct vm_area_struct *vma);
@@ -277,6 +283,8 @@ static struct drm_driver kms_driver = {
277 .get_vblank_counter = radeon_get_vblank_counter_kms, 283 .get_vblank_counter = radeon_get_vblank_counter_kms,
278 .enable_vblank = radeon_enable_vblank_kms, 284 .enable_vblank = radeon_enable_vblank_kms,
279 .disable_vblank = radeon_disable_vblank_kms, 285 .disable_vblank = radeon_disable_vblank_kms,
286 .get_vblank_timestamp = radeon_get_vblank_timestamp_kms,
287 .get_scanout_position = radeon_get_crtc_scanoutpos,
280#if defined(CONFIG_DEBUG_FS) 288#if defined(CONFIG_DEBUG_FS)
281 .debugfs_init = radeon_debugfs_init, 289 .debugfs_init = radeon_debugfs_init,
282 .debugfs_cleanup = radeon_debugfs_cleanup, 290 .debugfs_cleanup = radeon_debugfs_cleanup,
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index 8fbbe1c6ebbd..4bf423ca4c12 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -277,6 +277,27 @@ void radeon_disable_vblank_kms(struct drm_device *dev, int crtc)
277 radeon_irq_set(rdev); 277 radeon_irq_set(rdev);
278} 278}
279 279
280int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc,
281 int *max_error,
282 struct timeval *vblank_time,
283 unsigned flags)
284{
285 struct drm_crtc *drmcrtc;
286 struct radeon_device *rdev = dev->dev_private;
287
288 if (crtc < 0 || crtc >= dev->num_crtcs) {
289 DRM_ERROR("Invalid crtc %d\n", crtc);
290 return -EINVAL;
291 }
292
293 /* Get associated drm_crtc: */
294 drmcrtc = &rdev->mode_info.crtcs[crtc]->base;
295
296 /* Helper routine in DRM core does all the work: */
297 return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error,
298 vblank_time, flags,
299 drmcrtc);
300}
280 301
281/* 302/*
282 * IOCTL. 303 * IOCTL.
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index e301c6f9e059..55856ad0ac41 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -442,10 +442,6 @@ struct radeon_framebuffer {
442 struct drm_gem_object *obj; 442 struct drm_gem_object *obj;
443}; 443};
444 444
445/* radeon_get_crtc_scanoutpos() return flags */
446#define RADEON_SCANOUTPOS_VALID (1 << 0)
447#define RADEON_SCANOUTPOS_INVBL (1 << 1)
448#define RADEON_SCANOUTPOS_ACCURATE (1 << 2)
449 445
450extern enum radeon_tv_std 446extern enum radeon_tv_std
451radeon_combios_get_tv_info(struct radeon_device *rdev); 447radeon_combios_get_tv_info(struct radeon_device *rdev);
@@ -562,7 +558,8 @@ extern int radeon_crtc_cursor_set(struct drm_crtc *crtc,
562extern int radeon_crtc_cursor_move(struct drm_crtc *crtc, 558extern int radeon_crtc_cursor_move(struct drm_crtc *crtc,
563 int x, int y); 559 int x, int y);
564 560
565extern int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos, int *hpos); 561extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc,
562 int *vpos, int *hpos);
566 563
567extern bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev); 564extern bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev);
568extern struct edid * 565extern struct edid *
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 8c9b2ef32c68..5eda5e471980 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -720,9 +720,9 @@ static bool radeon_pm_in_vbl(struct radeon_device *rdev)
720 */ 720 */
721 for (crtc = 0; (crtc < rdev->num_crtc) && in_vbl; crtc++) { 721 for (crtc = 0; (crtc < rdev->num_crtc) && in_vbl; crtc++) {
722 if (rdev->pm.active_crtcs & (1 << crtc)) { 722 if (rdev->pm.active_crtcs & (1 << crtc)) {
723 vbl_status = radeon_get_crtc_scanoutpos(rdev, crtc, &vpos, &hpos); 723 vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, &vpos, &hpos);
724 if ((vbl_status & RADEON_SCANOUTPOS_VALID) && 724 if ((vbl_status & DRM_SCANOUTPOS_VALID) &&
725 !(vbl_status & RADEON_SCANOUTPOS_INVBL)) 725 !(vbl_status & DRM_SCANOUTPOS_INVBL))
726 in_vbl = false; 726 in_vbl = false;
727 } 727 }
728 } 728 }