Merge branch 'drm-vbl-timestamp' of git://gitorious.org/vsyrjala/linux into drm-next
Here's the vblank timestamp pull request you wanted. I addressed the few bugs that Mario pointed out and added the r-bs. As it has been a while since I made the changes, I gave it a quick spin on a few different i915 machines. Fortunately everything still seems to be fine. * 'drm-vbl-timestamp' of git://gitorious.org/vsyrjala/linux: drm/i915: Add a kludge for DSL incrementing too late and ISR not working drm/radeon: Move the early vblank IRQ fixup to radeon_get_crtc_scanoutpos() drm: Pass 'flags' from the caller to .get_scanout_position() drm: Fix vblank timestamping constants for interlaced modes drm/i915: Fix scanoutpos calculations for interlaced modes drm: Change {pixel,line,frame}dur_ns from s64 to int drm: Use crtc_clock in drm_calc_timestamping_constants() drm/radeon: Populate crtc_clock in radeon_atom_get_tv_timings() drm: Simplify the math in drm_calc_timestamping_constants() drm: Improve drm_calc_timestamping_constants() documentation drm/i915: Call drm_calc_timestamping_constants() earlier drm/i915: Kill hwmode save/restore drm: Pass the display mode to drm_calc_vbltimestamp_from_scanoutpos() drm: Pass the display mode to drm_calc_timestamping_constants()
This commit is contained in:
commit
f5395ba35f
|
@ -536,7 +536,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
|
|||
* are later needed by vblank and swap-completion
|
||||
* timestamping. They are derived from true hwmode.
|
||||
*/
|
||||
drm_calc_timestamping_constants(crtc);
|
||||
drm_calc_timestamping_constants(crtc, &crtc->hwmode);
|
||||
|
||||
/* FIXME: add subpixel order */
|
||||
done:
|
||||
|
|
|
@ -436,45 +436,41 @@ int drm_control(struct drm_device *dev, void *data,
|
|||
}
|
||||
|
||||
/**
|
||||
* drm_calc_timestamping_constants - Calculate and
|
||||
* store various constants which are later needed by
|
||||
* vblank and swap-completion timestamping, e.g, by
|
||||
* drm_calc_vbltimestamp_from_scanoutpos().
|
||||
* They are derived from crtc's true scanout timing,
|
||||
* so they take things like panel scaling or other
|
||||
* adjustments into account.
|
||||
* drm_calc_timestamping_constants - Calculate vblank timestamp constants
|
||||
*
|
||||
* @crtc drm_crtc whose timestamp constants should be updated.
|
||||
* @mode display mode containing the scanout timings
|
||||
*
|
||||
* Calculate and store various constants which are later
|
||||
* needed by vblank and swap-completion timestamping, e.g,
|
||||
* by drm_calc_vbltimestamp_from_scanoutpos(). They are
|
||||
* derived from crtc's true scanout timing, so they take
|
||||
* things like panel scaling or other adjustments into account.
|
||||
*/
|
||||
void drm_calc_timestamping_constants(struct drm_crtc *crtc)
|
||||
void drm_calc_timestamping_constants(struct drm_crtc *crtc,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
s64 linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0;
|
||||
u64 dotclock;
|
||||
|
||||
/* Dot clock in Hz: */
|
||||
dotclock = (u64) crtc->hwmode.clock * 1000;
|
||||
|
||||
/* Fields of interlaced scanout modes are only half a frame duration.
|
||||
* Double the dotclock to get half the frame-/line-/pixelduration.
|
||||
*/
|
||||
if (crtc->hwmode.flags & DRM_MODE_FLAG_INTERLACE)
|
||||
dotclock *= 2;
|
||||
int linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0;
|
||||
int dotclock = mode->crtc_clock;
|
||||
|
||||
/* Valid dotclock? */
|
||||
if (dotclock > 0) {
|
||||
int frame_size;
|
||||
/* Convert scanline length in pixels and video dot clock to
|
||||
* line duration, frame duration and pixel duration in
|
||||
* nanoseconds:
|
||||
int frame_size = mode->crtc_htotal * mode->crtc_vtotal;
|
||||
|
||||
/*
|
||||
* Convert scanline length in pixels and video
|
||||
* dot clock to line duration, frame duration
|
||||
* and pixel duration in nanoseconds:
|
||||
*/
|
||||
pixeldur_ns = (s64) div64_u64(1000000000, dotclock);
|
||||
linedur_ns = (s64) div64_u64(((u64) crtc->hwmode.crtc_htotal *
|
||||
1000000000), dotclock);
|
||||
frame_size = crtc->hwmode.crtc_htotal *
|
||||
crtc->hwmode.crtc_vtotal;
|
||||
framedur_ns = (s64) div64_u64((u64) frame_size * 1000000000,
|
||||
dotclock);
|
||||
pixeldur_ns = 1000000 / dotclock;
|
||||
linedur_ns = div_u64((u64) mode->crtc_htotal * 1000000, dotclock);
|
||||
framedur_ns = div_u64((u64) frame_size * 1000000, dotclock);
|
||||
|
||||
/*
|
||||
* Fields of interlaced scanout modes are only half a frame duration.
|
||||
*/
|
||||
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||
framedur_ns /= 2;
|
||||
} else
|
||||
DRM_ERROR("crtc %d: Can't calculate constants, dotclock = 0!\n",
|
||||
crtc->base.id);
|
||||
|
@ -484,11 +480,11 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc)
|
|||
crtc->framedur_ns = framedur_ns;
|
||||
|
||||
DRM_DEBUG("crtc %d: hwmode: htotal %d, vtotal %d, vdisplay %d\n",
|
||||
crtc->base.id, crtc->hwmode.crtc_htotal,
|
||||
crtc->hwmode.crtc_vtotal, crtc->hwmode.crtc_vdisplay);
|
||||
crtc->base.id, mode->crtc_htotal,
|
||||
mode->crtc_vtotal, mode->crtc_vdisplay);
|
||||
DRM_DEBUG("crtc %d: clock %d kHz framedur %d linedur %d, pixeldur %d\n",
|
||||
crtc->base.id, (int) dotclock/1000, (int) framedur_ns,
|
||||
(int) linedur_ns, (int) pixeldur_ns);
|
||||
crtc->base.id, dotclock, framedur_ns,
|
||||
linedur_ns, pixeldur_ns);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_calc_timestamping_constants);
|
||||
|
||||
|
@ -521,6 +517,7 @@ EXPORT_SYMBOL(drm_calc_timestamping_constants);
|
|||
* 0 = Default.
|
||||
* DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler.
|
||||
* @refcrtc: drm_crtc* of crtc which defines scanout timing.
|
||||
* @mode: mode which defines the scanout timings
|
||||
*
|
||||
* Returns negative value on error, failure or if not supported in current
|
||||
* video mode:
|
||||
|
@ -540,14 +537,14 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
|
|||
int *max_error,
|
||||
struct timeval *vblank_time,
|
||||
unsigned flags,
|
||||
struct drm_crtc *refcrtc)
|
||||
const struct drm_crtc *refcrtc,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
ktime_t stime, etime, mono_time_offset;
|
||||
struct timeval tv_etime;
|
||||
struct drm_display_mode *mode;
|
||||
int vbl_status, vtotal, vdisplay;
|
||||
int vbl_status;
|
||||
int vpos, hpos, i;
|
||||
s64 framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns;
|
||||
int framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns;
|
||||
bool invbl;
|
||||
|
||||
if (crtc < 0 || crtc >= dev->num_crtcs) {
|
||||
|
@ -561,10 +558,6 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
mode = &refcrtc->hwmode;
|
||||
vtotal = mode->crtc_vtotal;
|
||||
vdisplay = mode->crtc_vdisplay;
|
||||
|
||||
/* Durations of frames, lines, pixels in nanoseconds. */
|
||||
framedur_ns = refcrtc->framedur_ns;
|
||||
linedur_ns = refcrtc->linedur_ns;
|
||||
|
@ -573,7 +566,7 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
|
|||
/* If mode timing undefined, just return as no-op:
|
||||
* Happens during initial modesetting of a crtc.
|
||||
*/
|
||||
if (vtotal <= 0 || vdisplay <= 0 || framedur_ns == 0) {
|
||||
if (framedur_ns == 0) {
|
||||
DRM_DEBUG("crtc %d: Noop due to uninitialized mode.\n", crtc);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
@ -590,7 +583,7 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
|
|||
* Get vertical and horizontal scanout position vpos, hpos,
|
||||
* and bounding timestamps stime, etime, pre/post query.
|
||||
*/
|
||||
vbl_status = dev->driver->get_scanout_position(dev, crtc, &vpos,
|
||||
vbl_status = dev->driver->get_scanout_position(dev, crtc, flags, &vpos,
|
||||
&hpos, &stime, &etime);
|
||||
|
||||
/*
|
||||
|
@ -611,18 +604,18 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
|
|||
duration_ns = ktime_to_ns(etime) - ktime_to_ns(stime);
|
||||
|
||||
/* Accept result with < max_error nsecs timing uncertainty. */
|
||||
if (duration_ns <= (s64) *max_error)
|
||||
if (duration_ns <= *max_error)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Noisy system timing? */
|
||||
if (i == DRM_TIMESTAMP_MAXRETRIES) {
|
||||
DRM_DEBUG("crtc %d: Noisy timestamp %d us > %d us [%d reps].\n",
|
||||
crtc, (int) duration_ns/1000, *max_error/1000, i);
|
||||
crtc, duration_ns/1000, *max_error/1000, i);
|
||||
}
|
||||
|
||||
/* Return upper bound of timestamp precision error. */
|
||||
*max_error = (int) duration_ns;
|
||||
*max_error = duration_ns;
|
||||
|
||||
/* Check if in vblank area:
|
||||
* vpos is >=0 in video scanout area, but negative
|
||||
|
@ -635,25 +628,7 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
|
|||
* since start of scanout at first display scanline. delta_ns
|
||||
* can be negative if start of scanout hasn't happened yet.
|
||||
*/
|
||||
delta_ns = (s64) vpos * linedur_ns + (s64) hpos * pixeldur_ns;
|
||||
|
||||
/* Is vpos outside nominal vblank area, but less than
|
||||
* 1/100 of a frame height away from start of vblank?
|
||||
* If so, assume this isn't a massively delayed vblank
|
||||
* interrupt, but a vblank interrupt that fired a few
|
||||
* microseconds before true start of vblank. Compensate
|
||||
* by adding a full frame duration to the final timestamp.
|
||||
* Happens, e.g., on ATI R500, R600.
|
||||
*
|
||||
* We only do this if DRM_CALLED_FROM_VBLIRQ.
|
||||
*/
|
||||
if ((flags & DRM_CALLED_FROM_VBLIRQ) && !invbl &&
|
||||
((vdisplay - vpos) < vtotal / 100)) {
|
||||
delta_ns = delta_ns - framedur_ns;
|
||||
|
||||
/* Signal this correction as "applied". */
|
||||
vbl_status |= 0x8;
|
||||
}
|
||||
delta_ns = vpos * linedur_ns + hpos * pixeldur_ns;
|
||||
|
||||
if (!drm_timestamp_monotonic)
|
||||
etime = ktime_sub(etime, mono_time_offset);
|
||||
|
@ -673,7 +648,7 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
|
|||
crtc, (int)vbl_status, hpos, vpos,
|
||||
(long)tv_etime.tv_sec, (long)tv_etime.tv_usec,
|
||||
(long)vblank_time->tv_sec, (long)vblank_time->tv_usec,
|
||||
(int)duration_ns/1000, i);
|
||||
duration_ns/1000, i);
|
||||
|
||||
vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD;
|
||||
if (invbl)
|
||||
|
|
|
@ -621,36 +621,15 @@ static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
|
|||
#define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__))
|
||||
#define __raw_i915_read16(dev_priv__, reg__) readw((dev_priv__)->regs + (reg__))
|
||||
|
||||
static bool intel_pipe_in_vblank_locked(struct drm_device *dev, enum pipe pipe)
|
||||
static bool ilk_pipe_in_vblank_locked(struct drm_device *dev, enum pipe pipe)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
uint32_t status;
|
||||
int reg;
|
||||
|
||||
if (IS_VALLEYVIEW(dev)) {
|
||||
status = pipe == PIPE_A ?
|
||||
I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT :
|
||||
I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
|
||||
|
||||
reg = VLV_ISR;
|
||||
} else if (IS_GEN2(dev)) {
|
||||
status = pipe == PIPE_A ?
|
||||
I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT :
|
||||
I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
|
||||
|
||||
reg = ISR;
|
||||
} else if (INTEL_INFO(dev)->gen < 5) {
|
||||
status = pipe == PIPE_A ?
|
||||
I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT :
|
||||
I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
|
||||
|
||||
reg = ISR;
|
||||
} else if (INTEL_INFO(dev)->gen < 7) {
|
||||
if (INTEL_INFO(dev)->gen < 7) {
|
||||
status = pipe == PIPE_A ?
|
||||
DE_PIPEA_VBLANK :
|
||||
DE_PIPEB_VBLANK;
|
||||
|
||||
reg = DEISR;
|
||||
} else {
|
||||
switch (pipe) {
|
||||
default:
|
||||
|
@ -664,18 +643,14 @@ static bool intel_pipe_in_vblank_locked(struct drm_device *dev, enum pipe pipe)
|
|||
status = DE_PIPEC_VBLANK_IVB;
|
||||
break;
|
||||
}
|
||||
|
||||
reg = DEISR;
|
||||
}
|
||||
|
||||
if (IS_GEN2(dev))
|
||||
return __raw_i915_read16(dev_priv, reg) & status;
|
||||
else
|
||||
return __raw_i915_read32(dev_priv, reg) & status;
|
||||
return __raw_i915_read32(dev_priv, DEISR) & status;
|
||||
}
|
||||
|
||||
static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
|
||||
int *vpos, int *hpos, ktime_t *stime, ktime_t *etime)
|
||||
unsigned int flags, int *vpos, int *hpos,
|
||||
ktime_t *stime, ktime_t *etime)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
|
||||
|
@ -698,6 +673,12 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
|
|||
vbl_start = mode->crtc_vblank_start;
|
||||
vbl_end = mode->crtc_vblank_end;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
|
||||
vbl_start = DIV_ROUND_UP(vbl_start, 2);
|
||||
vbl_end /= 2;
|
||||
vtotal /= 2;
|
||||
}
|
||||
|
||||
ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
|
||||
|
||||
/*
|
||||
|
@ -722,17 +703,42 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
|
|||
else
|
||||
position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
|
||||
|
||||
/*
|
||||
* The scanline counter increments at the leading edge
|
||||
* of hsync, ie. it completely misses the active portion
|
||||
* of the line. Fix up the counter at both edges of vblank
|
||||
* to get a more accurate picture whether we're in vblank
|
||||
* or not.
|
||||
*/
|
||||
in_vbl = intel_pipe_in_vblank_locked(dev, pipe);
|
||||
if ((in_vbl && position == vbl_start - 1) ||
|
||||
(!in_vbl && position == vbl_end - 1))
|
||||
position = (position + 1) % vtotal;
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
/*
|
||||
* The scanline counter increments at the leading edge
|
||||
* of hsync, ie. it completely misses the active portion
|
||||
* of the line. Fix up the counter at both edges of vblank
|
||||
* to get a more accurate picture whether we're in vblank
|
||||
* or not.
|
||||
*/
|
||||
in_vbl = ilk_pipe_in_vblank_locked(dev, pipe);
|
||||
if ((in_vbl && position == vbl_start - 1) ||
|
||||
(!in_vbl && position == vbl_end - 1))
|
||||
position = (position + 1) % vtotal;
|
||||
} else {
|
||||
/*
|
||||
* ISR vblank status bits don't work the way we'd want
|
||||
* them to work on non-PCH platforms (for
|
||||
* ilk_pipe_in_vblank_locked()), and there doesn't
|
||||
* appear any other way to determine if we're currently
|
||||
* in vblank.
|
||||
*
|
||||
* Instead let's assume that we're already in vblank if
|
||||
* we got called from the vblank interrupt and the
|
||||
* scanline counter value indicates that we're on the
|
||||
* line just prior to vblank start. This should result
|
||||
* in the correct answer, unless the vblank interrupt
|
||||
* delivery really got delayed for almost exactly one
|
||||
* full frame/field.
|
||||
*/
|
||||
if (flags & DRM_CALLED_FROM_VBLIRQ &&
|
||||
position == vbl_start - 1) {
|
||||
position = (position + 1) % vtotal;
|
||||
|
||||
/* Signal this correction as "applied". */
|
||||
ret |= 0x8;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Have access to pixelcount since start of frame.
|
||||
* We can split this into vertical and horizontal
|
||||
|
@ -809,7 +815,8 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe,
|
|||
/* Helper routine in DRM core does all the work: */
|
||||
return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error,
|
||||
vblank_time, flags,
|
||||
crtc);
|
||||
crtc,
|
||||
&to_intel_crtc(crtc)->config.adjusted_mode);
|
||||
}
|
||||
|
||||
static bool intel_hpd_irq_event(struct drm_device *dev,
|
||||
|
|
|
@ -9597,21 +9597,19 @@ static int __intel_set_mode(struct drm_crtc *crtc,
|
|||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct drm_display_mode *saved_mode, *saved_hwmode;
|
||||
struct drm_display_mode *saved_mode;
|
||||
struct intel_crtc_config *pipe_config = NULL;
|
||||
struct intel_crtc *intel_crtc;
|
||||
unsigned disable_pipes, prepare_pipes, modeset_pipes;
|
||||
int ret = 0;
|
||||
|
||||
saved_mode = kcalloc(2, sizeof(*saved_mode), GFP_KERNEL);
|
||||
saved_mode = kmalloc(sizeof(*saved_mode), GFP_KERNEL);
|
||||
if (!saved_mode)
|
||||
return -ENOMEM;
|
||||
saved_hwmode = saved_mode + 1;
|
||||
|
||||
intel_modeset_affected_pipes(crtc, &modeset_pipes,
|
||||
&prepare_pipes, &disable_pipes);
|
||||
|
||||
*saved_hwmode = crtc->hwmode;
|
||||
*saved_mode = crtc->mode;
|
||||
|
||||
/* Hack: Because we don't (yet) support global modeset on multiple
|
||||
|
@ -9662,6 +9660,14 @@ static int __intel_set_mode(struct drm_crtc *crtc,
|
|||
/* mode_set/enable/disable functions rely on a correct pipe
|
||||
* config. */
|
||||
to_intel_crtc(crtc)->config = *pipe_config;
|
||||
|
||||
/*
|
||||
* Calculate and store various constants which
|
||||
* are later needed by vblank and swap-completion
|
||||
* timestamping. They are derived from true hwmode.
|
||||
*/
|
||||
drm_calc_timestamping_constants(crtc,
|
||||
&pipe_config->adjusted_mode);
|
||||
}
|
||||
|
||||
/* Only after disabling all output pipelines that will be changed can we
|
||||
|
@ -9685,23 +9691,10 @@ static int __intel_set_mode(struct drm_crtc *crtc,
|
|||
for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc)
|
||||
dev_priv->display.crtc_enable(&intel_crtc->base);
|
||||
|
||||
if (modeset_pipes) {
|
||||
/* Store real post-adjustment hardware mode. */
|
||||
crtc->hwmode = pipe_config->adjusted_mode;
|
||||
|
||||
/* Calculate and store various constants which
|
||||
* are later needed by vblank and swap-completion
|
||||
* timestamping. They are derived from true hwmode.
|
||||
*/
|
||||
drm_calc_timestamping_constants(crtc);
|
||||
}
|
||||
|
||||
/* FIXME: add subpixel order */
|
||||
done:
|
||||
if (ret && crtc->enabled) {
|
||||
crtc->hwmode = *saved_hwmode;
|
||||
if (ret && crtc->enabled)
|
||||
crtc->mode = *saved_mode;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(pipe_config);
|
||||
|
|
|
@ -1799,7 +1799,8 @@ bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index,
|
|||
if (misc & ATOM_DOUBLE_CLOCK_MODE)
|
||||
mode->flags |= DRM_MODE_FLAG_DBLSCAN;
|
||||
|
||||
mode->clock = le16_to_cpu(tv_info->aModeTimings[index].usPixelClock) * 10;
|
||||
mode->crtc_clock = mode->clock =
|
||||
le16_to_cpu(tv_info->aModeTimings[index].usPixelClock) * 10;
|
||||
|
||||
if (index == 1) {
|
||||
/* PAL timings appear to have wrong values for totals */
|
||||
|
@ -1842,7 +1843,8 @@ bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index,
|
|||
if (misc & ATOM_DOUBLE_CLOCK_MODE)
|
||||
mode->flags |= DRM_MODE_FLAG_DBLSCAN;
|
||||
|
||||
mode->clock = le16_to_cpu(dtd_timings->usPixClk) * 10;
|
||||
mode->crtc_clock = mode->clock =
|
||||
le16_to_cpu(dtd_timings->usPixClk) * 10;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -306,7 +306,7 @@ void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id)
|
|||
* to complete in this vblank?
|
||||
*/
|
||||
if (update_pending &&
|
||||
(DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, crtc_id,
|
||||
(DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, crtc_id, 0,
|
||||
&vpos, &hpos, NULL, NULL)) &&
|
||||
((vpos >= (99 * rdev->mode_info.crtcs[crtc_id]->base.hwmode.crtc_vdisplay)/100) ||
|
||||
(vpos < 0 && !ASIC_IS_AVIVO(rdev)))) {
|
||||
|
@ -1610,6 +1610,7 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
|
|||
*
|
||||
* \param dev Device to query.
|
||||
* \param crtc Crtc to query.
|
||||
* \param flags Flags from caller (DRM_CALLED_FROM_VBLIRQ or 0).
|
||||
* \param *vpos Location where vertical scanout position should be stored.
|
||||
* \param *hpos Location where horizontal scanout position should go.
|
||||
* \param *stime Target location for timestamp taken immediately before
|
||||
|
@ -1631,8 +1632,8 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
|
|||
* unknown small number of scanlines wrt. real scanout position.
|
||||
*
|
||||
*/
|
||||
int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int *hpos,
|
||||
ktime_t *stime, ktime_t *etime)
|
||||
int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int flags,
|
||||
int *vpos, int *hpos, ktime_t *stime, ktime_t *etime)
|
||||
{
|
||||
u32 stat_crtc = 0, vbl = 0, position = 0;
|
||||
int vbl_start, vbl_end, vtotal, ret = 0;
|
||||
|
@ -1774,5 +1775,27 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int
|
|||
if (in_vbl)
|
||||
ret |= DRM_SCANOUTPOS_INVBL;
|
||||
|
||||
/* Is vpos outside nominal vblank area, but less than
|
||||
* 1/100 of a frame height away from start of vblank?
|
||||
* If so, assume this isn't a massively delayed vblank
|
||||
* interrupt, but a vblank interrupt that fired a few
|
||||
* microseconds before true start of vblank. Compensate
|
||||
* by adding a full frame duration to the final timestamp.
|
||||
* Happens, e.g., on ATI R500, R600.
|
||||
*
|
||||
* We only do this if DRM_CALLED_FROM_VBLIRQ.
|
||||
*/
|
||||
if ((flags & DRM_CALLED_FROM_VBLIRQ) && !in_vbl) {
|
||||
vbl_start = rdev->mode_info.crtcs[crtc]->base.hwmode.crtc_vdisplay;
|
||||
vtotal = rdev->mode_info.crtcs[crtc]->base.hwmode.crtc_vtotal;
|
||||
|
||||
if (vbl_start - *vpos < vtotal / 100) {
|
||||
*vpos -= vtotal;
|
||||
|
||||
/* Signal this correction as "applied". */
|
||||
ret |= 0x8;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -109,6 +109,7 @@ int radeon_gem_object_open(struct drm_gem_object *obj,
|
|||
void radeon_gem_object_close(struct drm_gem_object *obj,
|
||||
struct drm_file *file_priv);
|
||||
extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc,
|
||||
unsigned int flags,
|
||||
int *vpos, int *hpos, ktime_t *stime,
|
||||
ktime_t *etime);
|
||||
extern const struct drm_ioctl_desc radeon_ioctls_kms[];
|
||||
|
|
|
@ -719,7 +719,7 @@ int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc,
|
|||
/* Helper routine in DRM core does all the work: */
|
||||
return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error,
|
||||
vblank_time, flags,
|
||||
drmcrtc);
|
||||
drmcrtc, &drmcrtc->hwmode);
|
||||
}
|
||||
|
||||
#define KMS_INVALID_IOCTL(name) \
|
||||
|
|
|
@ -801,6 +801,7 @@ extern int radeon_crtc_cursor_move(struct drm_crtc *crtc,
|
|||
int x, int y);
|
||||
|
||||
extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc,
|
||||
unsigned int flags,
|
||||
int *vpos, int *hpos, ktime_t *stime,
|
||||
ktime_t *etime);
|
||||
|
||||
|
|
|
@ -1486,7 +1486,7 @@ static bool radeon_pm_in_vbl(struct radeon_device *rdev)
|
|||
*/
|
||||
for (crtc = 0; (crtc < rdev->num_crtc) && in_vbl; crtc++) {
|
||||
if (rdev->pm.active_crtcs & (1 << crtc)) {
|
||||
vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, &vpos, &hpos, NULL, NULL);
|
||||
vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, 0, &vpos, &hpos, NULL, NULL);
|
||||
if ((vbl_status & DRM_SCANOUTPOS_VALID) &&
|
||||
!(vbl_status & DRM_SCANOUTPOS_INVBL))
|
||||
in_vbl = false;
|
||||
|
|
|
@ -845,6 +845,7 @@ struct drm_driver {
|
|||
*
|
||||
* \param dev DRM device.
|
||||
* \param crtc Id of the crtc to query.
|
||||
* \param flags Flags from the caller (DRM_CALLED_FROM_VBLIRQ or 0).
|
||||
* \param *vpos Target location for current vertical scanout position.
|
||||
* \param *hpos Target location for current horizontal scanout position.
|
||||
* \param *stime Target location for timestamp taken immediately before
|
||||
|
@ -867,6 +868,7 @@ struct drm_driver {
|
|||
*
|
||||
*/
|
||||
int (*get_scanout_position) (struct drm_device *dev, int crtc,
|
||||
unsigned int flags,
|
||||
int *vpos, int *hpos, ktime_t *stime,
|
||||
ktime_t *etime);
|
||||
|
||||
|
@ -1401,8 +1403,10 @@ extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
|
|||
int crtc, int *max_error,
|
||||
struct timeval *vblank_time,
|
||||
unsigned flags,
|
||||
struct drm_crtc *refcrtc);
|
||||
extern void drm_calc_timestamping_constants(struct drm_crtc *crtc);
|
||||
const struct drm_crtc *refcrtc,
|
||||
const struct drm_display_mode *mode);
|
||||
extern void drm_calc_timestamping_constants(struct drm_crtc *crtc,
|
||||
const struct drm_display_mode *mode);
|
||||
|
||||
extern bool
|
||||
drm_mode_parse_command_line_for_connector(const char *mode_option,
|
||||
|
|
|
@ -449,7 +449,7 @@ struct drm_crtc {
|
|||
uint16_t *gamma_store;
|
||||
|
||||
/* Constants needed for precise vblank and swap timestamping. */
|
||||
s64 framedur_ns, linedur_ns, pixeldur_ns;
|
||||
int framedur_ns, linedur_ns, pixeldur_ns;
|
||||
|
||||
/* if you are using the helper */
|
||||
void *helper_private;
|
||||
|
|
Loading…
Reference in New Issue