mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-20 02:34:23 +08:00
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>
This commit is contained in:
parent
ba032a58d1
commit
6383cf7d78
@ -989,3 +989,156 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve current video scanout position of crtc on a given gpu.
|
||||
*
|
||||
* \param rdev Device to query.
|
||||
* \param crtc Crtc to query.
|
||||
* \param *vpos Location where vertical scanout position should be stored.
|
||||
* \param *hpos Location where horizontal scanout position should go.
|
||||
*
|
||||
* Returns vpos as a positive number while in active scanout area.
|
||||
* Returns vpos as a negative number inside vblank, counting the number
|
||||
* of scanlines to go until end of vblank, e.g., -1 means "one scanline
|
||||
* until start of active scanout / end of vblank."
|
||||
*
|
||||
* \return Flags, or'ed together as follows:
|
||||
*
|
||||
* RADEON_SCANOUTPOS_VALID = Query successfull.
|
||||
* RADEON_SCANOUTPOS_INVBL = Inside vblank.
|
||||
* RADEON_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of
|
||||
* this flag means that returned position may be offset by a constant but
|
||||
* unknown small number of scanlines wrt. real scanout position.
|
||||
*
|
||||
*/
|
||||
int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos, int *hpos)
|
||||
{
|
||||
u32 stat_crtc = 0, vbl = 0, position = 0;
|
||||
int vbl_start, vbl_end, vtotal, ret = 0;
|
||||
bool in_vbl = true;
|
||||
|
||||
if (ASIC_IS_DCE4(rdev)) {
|
||||
if (crtc == 0) {
|
||||
vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
|
||||
EVERGREEN_CRTC0_REGISTER_OFFSET);
|
||||
position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
|
||||
EVERGREEN_CRTC0_REGISTER_OFFSET);
|
||||
ret |= RADEON_SCANOUTPOS_VALID;
|
||||
}
|
||||
if (crtc == 1) {
|
||||
vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
|
||||
EVERGREEN_CRTC1_REGISTER_OFFSET);
|
||||
position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
|
||||
EVERGREEN_CRTC1_REGISTER_OFFSET);
|
||||
ret |= RADEON_SCANOUTPOS_VALID;
|
||||
}
|
||||
if (crtc == 2) {
|
||||
vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
|
||||
EVERGREEN_CRTC2_REGISTER_OFFSET);
|
||||
position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
|
||||
EVERGREEN_CRTC2_REGISTER_OFFSET);
|
||||
ret |= RADEON_SCANOUTPOS_VALID;
|
||||
}
|
||||
if (crtc == 3) {
|
||||
vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
|
||||
EVERGREEN_CRTC3_REGISTER_OFFSET);
|
||||
position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
|
||||
EVERGREEN_CRTC3_REGISTER_OFFSET);
|
||||
ret |= RADEON_SCANOUTPOS_VALID;
|
||||
}
|
||||
if (crtc == 4) {
|
||||
vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
|
||||
EVERGREEN_CRTC4_REGISTER_OFFSET);
|
||||
position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
|
||||
EVERGREEN_CRTC4_REGISTER_OFFSET);
|
||||
ret |= RADEON_SCANOUTPOS_VALID;
|
||||
}
|
||||
if (crtc == 5) {
|
||||
vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
|
||||
EVERGREEN_CRTC5_REGISTER_OFFSET);
|
||||
position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
|
||||
EVERGREEN_CRTC5_REGISTER_OFFSET);
|
||||
ret |= RADEON_SCANOUTPOS_VALID;
|
||||
}
|
||||
} else if (ASIC_IS_AVIVO(rdev)) {
|
||||
if (crtc == 0) {
|
||||
vbl = RREG32(AVIVO_D1CRTC_V_BLANK_START_END);
|
||||
position = RREG32(AVIVO_D1CRTC_STATUS_POSITION);
|
||||
ret |= RADEON_SCANOUTPOS_VALID;
|
||||
}
|
||||
if (crtc == 1) {
|
||||
vbl = RREG32(AVIVO_D2CRTC_V_BLANK_START_END);
|
||||
position = RREG32(AVIVO_D2CRTC_STATUS_POSITION);
|
||||
ret |= RADEON_SCANOUTPOS_VALID;
|
||||
}
|
||||
} else {
|
||||
/* Pre-AVIVO: Different encoding of scanout pos and vblank interval. */
|
||||
if (crtc == 0) {
|
||||
/* Assume vbl_end == 0, get vbl_start from
|
||||
* upper 16 bits.
|
||||
*/
|
||||
vbl = (RREG32(RADEON_CRTC_V_TOTAL_DISP) &
|
||||
RADEON_CRTC_V_DISP) >> RADEON_CRTC_V_DISP_SHIFT;
|
||||
/* Only retrieve vpos from upper 16 bits, set hpos == 0. */
|
||||
position = (RREG32(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL;
|
||||
stat_crtc = RREG32(RADEON_CRTC_STATUS);
|
||||
if (!(stat_crtc & 1))
|
||||
in_vbl = false;
|
||||
|
||||
ret |= RADEON_SCANOUTPOS_VALID;
|
||||
}
|
||||
if (crtc == 1) {
|
||||
vbl = (RREG32(RADEON_CRTC2_V_TOTAL_DISP) &
|
||||
RADEON_CRTC_V_DISP) >> RADEON_CRTC_V_DISP_SHIFT;
|
||||
position = (RREG32(RADEON_CRTC2_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL;
|
||||
stat_crtc = RREG32(RADEON_CRTC2_STATUS);
|
||||
if (!(stat_crtc & 1))
|
||||
in_vbl = false;
|
||||
|
||||
ret |= RADEON_SCANOUTPOS_VALID;
|
||||
}
|
||||
}
|
||||
|
||||
/* Decode into vertical and horizontal scanout position. */
|
||||
*vpos = position & 0x1fff;
|
||||
*hpos = (position >> 16) & 0x1fff;
|
||||
|
||||
/* Valid vblank area boundaries from gpu retrieved? */
|
||||
if (vbl > 0) {
|
||||
/* Yes: Decode. */
|
||||
ret |= RADEON_SCANOUTPOS_ACCURATE;
|
||||
vbl_start = vbl & 0x1fff;
|
||||
vbl_end = (vbl >> 16) & 0x1fff;
|
||||
}
|
||||
else {
|
||||
/* No: Fake something reasonable which gives at least ok results. */
|
||||
vbl_start = rdev->mode_info.crtcs[crtc]->base.mode.crtc_vdisplay;
|
||||
vbl_end = 0;
|
||||
}
|
||||
|
||||
/* Test scanout position against vblank region. */
|
||||
if ((*vpos < vbl_start) && (*vpos >= vbl_end))
|
||||
in_vbl = false;
|
||||
|
||||
/* Check if inside vblank area and apply corrective offsets:
|
||||
* vpos will then be >=0 in video scanout area, but negative
|
||||
* within vblank area, counting down the number of lines until
|
||||
* start of scanout.
|
||||
*/
|
||||
|
||||
/* Inside "upper part" of vblank area? Apply corrective offset if so: */
|
||||
if (in_vbl && (*vpos >= vbl_start)) {
|
||||
vtotal = rdev->mode_info.crtcs[crtc]->base.mode.crtc_vtotal;
|
||||
*vpos = *vpos - vtotal;
|
||||
}
|
||||
|
||||
/* Correct for shifted end of vbl at vbl_end. */
|
||||
*vpos = *vpos - vbl_end;
|
||||
|
||||
/* In vblank? */
|
||||
if (in_vbl)
|
||||
ret |= RADEON_SCANOUTPOS_INVBL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -428,6 +428,11 @@ struct radeon_framebuffer {
|
||||
struct drm_gem_object *obj;
|
||||
};
|
||||
|
||||
/* radeon_get_crtc_scanoutpos() return flags */
|
||||
#define RADEON_SCANOUTPOS_VALID (1 << 0)
|
||||
#define RADEON_SCANOUTPOS_INVBL (1 << 1)
|
||||
#define RADEON_SCANOUTPOS_ACCURATE (1 << 2)
|
||||
|
||||
extern enum radeon_tv_std
|
||||
radeon_combios_get_tv_info(struct radeon_device *rdev);
|
||||
extern enum radeon_tv_std
|
||||
@ -531,6 +536,8 @@ extern int radeon_crtc_cursor_set(struct drm_crtc *crtc,
|
||||
extern int radeon_crtc_cursor_move(struct drm_crtc *crtc,
|
||||
int x, int y);
|
||||
|
||||
extern int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos, int *hpos);
|
||||
|
||||
extern bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev);
|
||||
extern struct edid *
|
||||
radeon_combios_get_hardcoded_edid(struct radeon_device *rdev);
|
||||
|
Loading…
Reference in New Issue
Block a user