drm: Stop using linedur_ns and pixeldur_ns for vblank timestamps

linedur_ns, and especially pixeldur_ns are becoming rather inaccurate
to be used for the vblank timestamp correction. With 4k@60 the pixel
duration is already below 2ns, so the amount of error due to the
truncation to nanoseconds is introducing quite a bit of error.

We can avoid such problems if we instead calculate the timestamp
delta_ns directly from the dislay timings, avoiding the use of
these intermediate truncated values.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
[danvet: Squash in fixup from Thierry Reding for amdgpu.]
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 6b2fefd..9fab333 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -694,12 +694,11 @@
 					  unsigned flags,
 					  const struct drm_display_mode *mode)
 {
-	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
 	struct timeval tv_etime;
 	ktime_t stime, etime;
 	int vbl_status;
 	int vpos, hpos, i;
-	int framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns;
+	int delta_ns, duration_ns;
 	bool invbl;
 
 	if (pipe >= dev->num_crtcs) {
@@ -713,15 +712,10 @@
 		return -EIO;
 	}
 
-	/* Durations of frames, lines, pixels in nanoseconds. */
-	framedur_ns = vblank->framedur_ns;
-	linedur_ns  = vblank->linedur_ns;
-	pixeldur_ns = vblank->pixeldur_ns;
-
 	/* If mode timing undefined, just return as no-op:
 	 * Happens during initial modesetting of a crtc.
 	 */
-	if (framedur_ns == 0) {
+	if (mode->crtc_clock == 0) {
 		DRM_DEBUG("crtc %u: Noop due to uninitialized mode.\n", pipe);
 		return -EAGAIN;
 	}
@@ -738,8 +732,10 @@
 		 * Get vertical and horizontal scanout position vpos, hpos,
 		 * and bounding timestamps stime, etime, pre/post query.
 		 */
-		vbl_status = dev->driver->get_scanout_position(dev, pipe, flags, &vpos,
-							       &hpos, &stime, &etime);
+		vbl_status = dev->driver->get_scanout_position(dev, pipe, flags,
+							       &vpos, &hpos,
+							       &stime, &etime,
+							       mode);
 
 		/* Return as no-op if scanout query unsupported or failed. */
 		if (!(vbl_status & DRM_SCANOUTPOS_VALID)) {
@@ -776,7 +772,8 @@
 	 * since start of scanout at first display scanline. delta_ns
 	 * can be negative if start of scanout hasn't happened yet.
 	 */
-	delta_ns = vpos * linedur_ns + hpos * pixeldur_ns;
+	delta_ns = div_s64(1000000LL * (vpos * mode->crtc_htotal + hpos),
+			   mode->crtc_clock);
 
 	if (!drm_timestamp_monotonic)
 		etime = ktime_mono_to_real(etime);