All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/15] drm/i915: Fix TV encoder support
@ 2018-11-12 16:59 Ville Syrjala
  2018-11-12 16:59 ` [PATCH 01/15] drm/vblank: Allow dynamic per-crtc max_vblank_count Ville Syrjala
                   ` (24 more replies)
  0 siblings, 25 replies; 66+ messages in thread
From: Ville Syrjala @ 2018-11-12 16:59 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Our TV encoder support isn't in the best shape. This series fixes
it up quite a bit.

The most important part is fixing the issues resulting from the
lack of frame counter on i965gm which causes nasty flip_done
timeouts when we attempt to do anything with the TV encoder 
(including load detection).

Dust off those component cables people! ;)

Entire series is available here:
git://github.com/vsyrjala/linux.git tvout_fixes

Ville Syrjälä (15):
  drm/vblank: Allow dynamic per-crtc max_vblank_count
  drm/i915: Don't try to use the hardware frame counter with i965gm TV
    output
  drm/i915/tv: Fix interlaced ysize calculation
  drm/i915/tv: Fix tv mode clocks
  drm/i915/tv: Store the TV oversampling factor in the TV mode
  drm/i915/tv: Use bools where appropriate
  drm/i915/tv: Nuke silly 0 inittialization of xpos/ypos
  drm/i915/tv: Deobfuscate preferred mode selection
  drm/i915/tv: Use drm_mode_set_name() to name TV modes
  drm/i915/tv: Make TV mode autoselection actually useable
  drm/i915/tv: Nuke reported_modes[]
  drm/i915/tv: Add 1080p30/50/60 TV modes
  drm/i915/tv: Generate better pipe timings for TV encoder
  drm/i915/tv: Fix >1024 modes on gen3
  drm/i915/tv: Filter out >1024 wide modes that would need vertical
    scaling on gen3

 drivers/gpu/drm/drm_vblank.c         |  39 +-
 drivers/gpu/drm/i915/i915_irq.c      |  10 +-
 drivers/gpu/drm/i915/i915_reg.h      |   1 +
 drivers/gpu/drm/i915/intel_display.c |  40 +-
 drivers/gpu/drm/i915/intel_tv.c      | 695 +++++++++++++++++++++------
 include/drm/drm_vblank.h             |   8 +
 6 files changed, 640 insertions(+), 153 deletions(-)

-- 
2.18.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 66+ messages in thread

* [PATCH 01/15] drm/vblank: Allow dynamic per-crtc max_vblank_count
  2018-11-12 16:59 [PATCH 00/15] drm/i915: Fix TV encoder support Ville Syrjala
@ 2018-11-12 16:59 ` Ville Syrjala
  2018-11-21  9:27     ` Daniel Vetter
  2018-11-27 18:20     ` Ville Syrjala
  2018-11-12 16:59 ` [PATCH 02/15] drm/i915: Don't try to use the hardware frame counter with i965gm TV output Ville Syrjala
                   ` (23 subsequent siblings)
  24 siblings, 2 replies; 66+ messages in thread
From: Ville Syrjala @ 2018-11-12 16:59 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel, stable, Inki Dae, Daniel Vetter

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

On i965gm we need to adjust max_vblank_count dynamically
depending on whether the TV encoder is used or not. To
that end add a per-crtc max_vblank_count that takes
precedence over its device wide counterpart. The driver
can now call drm_crtc_set_max_vblank_count() to configure
the per-crtc value before calling drm_vblank_on().

Also looks like there was some discussion about exynos needing
similar treatment.

Cc: stable@vger.kernel.org
Cc: Inki Dae <inki.dae@samsung.com>
Cc: Daniel Vetter <daniel@ffwll.ch>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/drm_vblank.c | 39 ++++++++++++++++++++++++++++++++----
 include/drm/drm_vblank.h     |  8 ++++++++
 2 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
index 98e091175921..c3abbdca8aba 100644
--- a/drivers/gpu/drm/drm_vblank.c
+++ b/drivers/gpu/drm/drm_vblank.c
@@ -105,13 +105,20 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe,
 	write_sequnlock(&vblank->seqlock);
 }
 
+static u32 drm_max_vblank_count(struct drm_device *dev, unsigned int pipe)
+{
+	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
+
+	return vblank->max_vblank_count ?: dev->max_vblank_count;
+}
+
 /*
  * "No hw counter" fallback implementation of .get_vblank_counter() hook,
  * if there is no useable hardware frame counter available.
  */
 static u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe)
 {
-	WARN_ON_ONCE(dev->max_vblank_count != 0);
+	WARN_ON_ONCE(drm_max_vblank_count(dev, pipe) != 0);
 	return 0;
 }
 
@@ -198,6 +205,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
 	ktime_t t_vblank;
 	int count = DRM_TIMESTAMP_MAXRETRIES;
 	int framedur_ns = vblank->framedur_ns;
+	u32 max_vblank_count = drm_max_vblank_count(dev, pipe);
 
 	/*
 	 * Interrupts were disabled prior to this call, so deal with counter
@@ -216,9 +224,9 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
 		rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq);
 	} while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0);
 
-	if (dev->max_vblank_count != 0) {
+	if (max_vblank_count) {
 		/* trust the hw counter when it's around */
-		diff = (cur_vblank - vblank->last) & dev->max_vblank_count;
+		diff = (cur_vblank - vblank->last) & max_vblank_count;
 	} else if (rc && framedur_ns) {
 		u64 diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time));
 
@@ -258,7 +266,8 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
 		      pipe, vblank->count, diff, cur_vblank, vblank->last);
 
 	if (diff == 0) {
-		WARN_ON_ONCE(cur_vblank != vblank->last);
+		WARN_ON_ONCE(max_vblank_count &&
+			     cur_vblank != vblank->last);
 		return;
 	}
 
@@ -1204,6 +1213,28 @@ void drm_crtc_vblank_reset(struct drm_crtc *crtc)
 }
 EXPORT_SYMBOL(drm_crtc_vblank_reset);
 
+/**
+ * drm_crtc_set_max_vblank_count - configure the hw max vblank counter value
+ * @crtc: CRTC in question
+ * @max_vblank_count: max hardware vblank counter value
+ *
+ * Update the maximum hardware vblank counter value for @crtc. Useful
+ * for hardware where the operation of the hardware vblank counter
+ * depends on the active display configuration.
+ *
+ * If used, must be called before drm_vblank_on().
+ */
+void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc,
+				   u32 max_vblank_count)
+{
+	struct drm_device *dev = crtc->dev;
+	unsigned int pipe = drm_crtc_index(crtc);
+	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
+
+	vblank->max_vblank_count = max_vblank_count;
+}
+EXPORT_SYMBOL(drm_crtc_set_max_vblank_count);
+
 /**
  * drm_crtc_vblank_on - enable vblank events on a CRTC
  * @crtc: CRTC in question
diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h
index 6ad9630d4f48..ecb2cf9913e2 100644
--- a/include/drm/drm_vblank.h
+++ b/include/drm/drm_vblank.h
@@ -128,6 +128,12 @@ struct drm_vblank_crtc {
 	 * @last: Protected by &drm_device.vbl_lock, used for wraparound handling.
 	 */
 	u32 last;
+	/**
+	 * @max_vblank_count: Maximum value of the hardware vblank counter.
+	 * If non-zero this takes precedence over &drm_device.max_vblank_count
+	 * for this crtc. Otherwise &drm_device.max_vblank_count is used.
+	 */
+	u32 max_vblank_count;
 	/**
 	 * @inmodeset: Tracks whether the vblank is disabled due to a modeset.
 	 * For legacy driver bit 2 additionally tracks whether an additional
@@ -206,4 +212,6 @@ bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
 void drm_calc_timestamping_constants(struct drm_crtc *crtc,
 				     const struct drm_display_mode *mode);
 wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc);
+void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc,
+				   u32 max_vblank_count);
 #endif
-- 
2.18.1

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 02/15] drm/i915: Don't try to use the hardware frame counter with i965gm TV output
  2018-11-12 16:59 [PATCH 00/15] drm/i915: Fix TV encoder support Ville Syrjala
  2018-11-12 16:59 ` [PATCH 01/15] drm/vblank: Allow dynamic per-crtc max_vblank_count Ville Syrjala
@ 2018-11-12 16:59 ` Ville Syrjala
  2018-11-27 18:21   ` [PATCH v2 " Ville Syrjala
  2018-11-27 20:05   ` [PATCH v3 " Ville Syrjala
  2018-11-12 16:59 ` [PATCH 03/15] drm/i915/tv: Fix interlaced ysize calculation Ville Syrjala
                   ` (22 subsequent siblings)
  24 siblings, 2 replies; 66+ messages in thread
From: Ville Syrjala @ 2018-11-12 16:59 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel, stable

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

On i965gm the hardware frame counter does not work when
the TV encoder is active. So let's not try to consult
the hardware frame counter in that case. Instead we'll
fall back to the timestamp based guesstimation method
used on gen2.

Note that the pipe timings generated by the TV encoder
are also rather peculiar. Apparently the pipe wants to
run at a much higher speed (related to the oversample
clock somehow it seems) but during the vertical active
period the TV encoder stalls the pipe every few lines
to keep its speed in check. But once the vertical
blanking period is reached the pipe gets to run at full
speed. This means our vblank timestamp estimates are
suspect. Fixing all that would require quite a bit
more work. This simple fix at least avoids the nasty
vblank timeouts that are happening currently.

Curiously the frame counter works just fine on i945gm
and gm45. I don't really understand what kind of mishap
occurred with the hardware design on i965gm. Sadly
I wasn't able to find any chicken bits etc. that would
fix the frame counter :(

Cc: stable@vger.kernel.org
Fixes: 51e31d49c890 ("drm/i915: Use generic vblank wait")
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=93782
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_irq.c      | 10 ++++++-
 drivers/gpu/drm/i915/intel_display.c | 40 +++++++++++++++++++++++-----
 2 files changed, 43 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index d447d7d508f4..019cb685986c 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -4843,8 +4843,16 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
 		dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
 		dev->driver->get_vblank_counter = g4x_get_vblank_counter;
 	} else {
+		/*
+		 * On i965gm the hardware frame counter reads zero
+		 * when the TV encoder is used. Hence we configure
+		 * max_vblank_count dynamically for each crtc.
+		 */
+		if (IS_I965GM(dev_priv))
+			dev->max_vblank_count = 0;
+		else
+			dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
 		dev->driver->get_vblank_counter = i915_get_vblank_counter;
-		dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
 	}
 
 	/*
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 940577f8c041..2dccb3310ad2 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -5504,6 +5504,32 @@ static void intel_encoders_post_pll_disable(struct drm_crtc *crtc,
 	}
 }
 
+static u32 intel_crtc_max_vblank_count(const struct intel_crtc_state *crtc_state)
+{
+	struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
+	u32 max_vblank_count = dev_priv->drm.max_vblank_count;
+
+	/*
+	 * On i965gm the hardware frame counter always
+	 * reads zero when the TV encoder is used :(
+	 * Otherwise we get the 24 bit frame counter.
+	 */
+	if (IS_I965GM(dev_priv) &&
+	    (crtc_state->output_types & BIT(INTEL_OUTPUT_TVOUT)) == 0)
+		max_vblank_count = 0xffffff; /* only 24 bits of frame count */
+
+	return max_vblank_count;
+}
+
+static void intel_crtc_vblank_on(const struct intel_crtc_state *crtc_state)
+{
+	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+
+	drm_crtc_set_max_vblank_count(&crtc->base,
+				      intel_crtc_max_vblank_count(crtc_state));
+	drm_crtc_vblank_on(&crtc->base);
+}
+
 static void ironlake_crtc_enable(struct intel_crtc_state *pipe_config,
 				 struct drm_atomic_state *old_state)
 {
@@ -5577,7 +5603,7 @@ static void ironlake_crtc_enable(struct intel_crtc_state *pipe_config,
 		ironlake_pch_enable(old_intel_state, pipe_config);
 
 	assert_vblank_disabled(crtc);
-	drm_crtc_vblank_on(crtc);
+	intel_crtc_vblank_on(pipe_config);
 
 	intel_encoders_enable(crtc, pipe_config, old_state);
 
@@ -5734,7 +5760,7 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
 		intel_ddi_set_vc_payload_alloc(pipe_config, true);
 
 	assert_vblank_disabled(crtc);
-	drm_crtc_vblank_on(crtc);
+	intel_crtc_vblank_on(pipe_config);
 
 	intel_encoders_enable(crtc, pipe_config, old_state);
 
@@ -6074,7 +6100,7 @@ static void valleyview_crtc_enable(struct intel_crtc_state *pipe_config,
 	intel_enable_pipe(pipe_config);
 
 	assert_vblank_disabled(crtc);
-	drm_crtc_vblank_on(crtc);
+	intel_crtc_vblank_on(pipe_config);
 
 	intel_encoders_enable(crtc, pipe_config, old_state);
 }
@@ -6133,7 +6159,7 @@ static void i9xx_crtc_enable(struct intel_crtc_state *pipe_config,
 	intel_enable_pipe(pipe_config);
 
 	assert_vblank_disabled(crtc);
-	drm_crtc_vblank_on(crtc);
+	intel_crtc_vblank_on(pipe_config);
 
 	intel_encoders_enable(crtc, pipe_config, old_state);
 }
@@ -15752,10 +15778,12 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
 	 * waits, so we need vblank interrupts restored beforehand.
 	 */
 	for_each_intel_crtc(&dev_priv->drm, crtc) {
+		crtc_state = to_intel_crtc_state(crtc->base.state);
+
 		drm_crtc_vblank_reset(&crtc->base);
 
-		if (crtc->base.state->active)
-			drm_crtc_vblank_on(&crtc->base);
+		if (crtc_state->base.active)
+			intel_crtc_vblank_on(crtc_state);
 	}
 
 	intel_sanitize_plane_mapping(dev_priv);
-- 
2.18.1

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 03/15] drm/i915/tv: Fix interlaced ysize calculation
  2018-11-12 16:59 [PATCH 00/15] drm/i915: Fix TV encoder support Ville Syrjala
  2018-11-12 16:59 ` [PATCH 01/15] drm/vblank: Allow dynamic per-crtc max_vblank_count Ville Syrjala
  2018-11-12 16:59 ` [PATCH 02/15] drm/i915: Don't try to use the hardware frame counter with i965gm TV output Ville Syrjala
@ 2018-11-12 16:59 ` Ville Syrjala
  2019-01-22 12:54   ` Imre Deak
  2018-11-12 16:59 ` [PATCH 04/15] drm/i915/tv: Fix tv mode clocks Ville Syrjala
                   ` (21 subsequent siblings)
  24 siblings, 1 reply; 66+ messages in thread
From: Ville Syrjala @ 2018-11-12 16:59 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Fix the calculation of the vertical active period for interlaced
TV modes.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_tv.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 860f306a23ba..219a16d6dcc2 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1087,7 +1087,7 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder,
 	if (tv_mode->progressive)
 		ysize = tv_mode->nbr_end + 1;
 	else
-		ysize = 2*tv_mode->nbr_end + 1;
+		ysize = 2 * (tv_mode->nbr_end + 1);
 
 	xpos += conn_state->tv.margins.left;
 	ypos += conn_state->tv.margins.top;
-- 
2.18.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 04/15] drm/i915/tv: Fix tv mode clocks
  2018-11-12 16:59 [PATCH 00/15] drm/i915: Fix TV encoder support Ville Syrjala
                   ` (2 preceding siblings ...)
  2018-11-12 16:59 ` [PATCH 03/15] drm/i915/tv: Fix interlaced ysize calculation Ville Syrjala
@ 2018-11-12 16:59 ` Ville Syrjala
  2019-01-22 12:56   ` Imre Deak
  2018-11-12 16:59 ` [PATCH 05/15] drm/i915/tv: Store the TV oversampling factor in the TV mode Ville Syrjala
                   ` (20 subsequent siblings)
  24 siblings, 1 reply; 66+ messages in thread
From: Ville Syrjala @ 2018-11-12 16:59 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

The oversample clock is always supposed to be either 108 MHz
or 148.5 MHz. Make it so.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_tv.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 219a16d6dcc2..dea24ef88763 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -636,7 +636,7 @@ static const struct tv_mode tv_modes[] = {
 	},
 	{
 		.name       = "480p",
-		.clock		= 107520,
+		.clock		= 108000,
 		.refresh	= 59940,
 		.oversample     = TV_OVERSAMPLE_4X,
 		.component_only = 1,
@@ -660,7 +660,7 @@ static const struct tv_mode tv_modes[] = {
 	},
 	{
 		.name       = "576p",
-		.clock		= 107520,
+		.clock		= 108000,
 		.refresh	= 50000,
 		.oversample     = TV_OVERSAMPLE_4X,
 		.component_only = 1,
@@ -684,7 +684,7 @@ static const struct tv_mode tv_modes[] = {
 	},
 	{
 		.name       = "720p@60Hz",
-		.clock		= 148800,
+		.clock		= 148500,
 		.refresh	= 60000,
 		.oversample     = TV_OVERSAMPLE_2X,
 		.component_only = 1,
@@ -708,7 +708,7 @@ static const struct tv_mode tv_modes[] = {
 	},
 	{
 		.name       = "720p@50Hz",
-		.clock		= 148800,
+		.clock		= 148500,
 		.refresh	= 50000,
 		.oversample     = TV_OVERSAMPLE_2X,
 		.component_only = 1,
@@ -733,7 +733,7 @@ static const struct tv_mode tv_modes[] = {
 	},
 	{
 		.name       = "1080i@50Hz",
-		.clock		= 148800,
+		.clock		= 148500,
 		.refresh	= 50000,
 		.oversample     = TV_OVERSAMPLE_2X,
 		.component_only = 1,
@@ -759,7 +759,7 @@ static const struct tv_mode tv_modes[] = {
 	},
 	{
 		.name       = "1080i@60Hz",
-		.clock		= 148800,
+		.clock		= 148500,
 		.refresh	= 60000,
 		.oversample     = TV_OVERSAMPLE_2X,
 		.component_only = 1,
@@ -1114,7 +1114,7 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder,
 static const struct drm_display_mode reported_modes[] = {
 	{
 		.name = "NTSC 480i",
-		.clock = 107520,
+		.clock = 108000,
 		.hdisplay = 1280,
 		.hsync_start = 1368,
 		.hsync_end = 1496,
-- 
2.18.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 05/15] drm/i915/tv: Store the TV oversampling factor in the TV mode
  2018-11-12 16:59 [PATCH 00/15] drm/i915: Fix TV encoder support Ville Syrjala
                   ` (3 preceding siblings ...)
  2018-11-12 16:59 ` [PATCH 04/15] drm/i915/tv: Fix tv mode clocks Ville Syrjala
@ 2018-11-12 16:59 ` Ville Syrjala
  2019-01-22 13:03   ` Imre Deak
  2018-11-12 16:59 ` [PATCH 06/15] drm/i915/tv: Use bools where appropriate Ville Syrjala
                   ` (19 subsequent siblings)
  24 siblings, 1 reply; 66+ messages in thread
From: Ville Syrjala @ 2018-11-12 16:59 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Store the oversampling factor as a number in the TV modes. We
shall want to arithmetic with this which is easier if it's
a number we can use directly.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_tv.c | 42 ++++++++++++++++++++++-----------
 1 file changed, 28 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index dea24ef88763..96257b29d07c 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -307,7 +307,7 @@ struct tv_mode {
 
 	u32 clock;
 	u16 refresh; /* in millihertz (for precision) */
-	u32 oversample;
+	u8 oversample;
 	u8 hsync_end;
 	u16 hblank_start, hblank_end, htotal;
 	bool progressive : 1, trilevel_sync : 1, component_only : 1;
@@ -379,7 +379,7 @@ static const struct tv_mode tv_modes[] = {
 		.name		= "NTSC-M",
 		.clock		= 108000,
 		.refresh	= 59940,
-		.oversample	= TV_OVERSAMPLE_8X,
+		.oversample	= 8,
 		.component_only = 0,
 		/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
 
@@ -422,7 +422,7 @@ static const struct tv_mode tv_modes[] = {
 		.name		= "NTSC-443",
 		.clock		= 108000,
 		.refresh	= 59940,
-		.oversample	= TV_OVERSAMPLE_8X,
+		.oversample	= 8,
 		.component_only = 0,
 		/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 4.43MHz */
 		.hsync_end	= 64,		    .hblank_end		= 124,
@@ -464,7 +464,7 @@ static const struct tv_mode tv_modes[] = {
 		.name		= "NTSC-J",
 		.clock		= 108000,
 		.refresh	= 59940,
-		.oversample	= TV_OVERSAMPLE_8X,
+		.oversample	= 8,
 		.component_only = 0,
 
 		/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
@@ -507,7 +507,7 @@ static const struct tv_mode tv_modes[] = {
 		.name		= "PAL-M",
 		.clock		= 108000,
 		.refresh	= 59940,
-		.oversample	= TV_OVERSAMPLE_8X,
+		.oversample	= 8,
 		.component_only = 0,
 
 		/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
@@ -551,7 +551,7 @@ static const struct tv_mode tv_modes[] = {
 		.name	    = "PAL-N",
 		.clock		= 108000,
 		.refresh	= 50000,
-		.oversample	= TV_OVERSAMPLE_8X,
+		.oversample	= 8,
 		.component_only = 0,
 
 		.hsync_end	= 64,		    .hblank_end		= 128,
@@ -596,7 +596,7 @@ static const struct tv_mode tv_modes[] = {
 		.name	    = "PAL",
 		.clock		= 108000,
 		.refresh	= 50000,
-		.oversample	= TV_OVERSAMPLE_8X,
+		.oversample	= 8,
 		.component_only = 0,
 
 		.hsync_end	= 64,		    .hblank_end		= 142,
@@ -638,7 +638,7 @@ static const struct tv_mode tv_modes[] = {
 		.name       = "480p",
 		.clock		= 108000,
 		.refresh	= 59940,
-		.oversample     = TV_OVERSAMPLE_4X,
+		.oversample     = 4,
 		.component_only = 1,
 
 		.hsync_end      = 64,               .hblank_end         = 122,
@@ -662,7 +662,7 @@ static const struct tv_mode tv_modes[] = {
 		.name       = "576p",
 		.clock		= 108000,
 		.refresh	= 50000,
-		.oversample     = TV_OVERSAMPLE_4X,
+		.oversample     = 4,
 		.component_only = 1,
 
 		.hsync_end      = 64,               .hblank_end         = 139,
@@ -686,7 +686,7 @@ static const struct tv_mode tv_modes[] = {
 		.name       = "720p@60Hz",
 		.clock		= 148500,
 		.refresh	= 60000,
-		.oversample     = TV_OVERSAMPLE_2X,
+		.oversample     = 2,
 		.component_only = 1,
 
 		.hsync_end      = 80,               .hblank_end         = 300,
@@ -710,7 +710,7 @@ static const struct tv_mode tv_modes[] = {
 		.name       = "720p@50Hz",
 		.clock		= 148500,
 		.refresh	= 50000,
-		.oversample     = TV_OVERSAMPLE_2X,
+		.oversample     = 2,
 		.component_only = 1,
 
 		.hsync_end      = 80,               .hblank_end         = 300,
@@ -735,7 +735,7 @@ static const struct tv_mode tv_modes[] = {
 		.name       = "1080i@50Hz",
 		.clock		= 148500,
 		.refresh	= 50000,
-		.oversample     = TV_OVERSAMPLE_2X,
+		.oversample     = 2,
 		.component_only = 1,
 
 		.hsync_end      = 88,               .hblank_end         = 235,
@@ -761,7 +761,7 @@ static const struct tv_mode tv_modes[] = {
 		.name       = "1080i@60Hz",
 		.clock		= 148500,
 		.refresh	= 60000,
-		.oversample     = TV_OVERSAMPLE_2X,
+		.oversample     = 2,
 		.component_only = 1,
 
 		.hsync_end      = 88,               .hblank_end         = 235,
@@ -1030,7 +1030,21 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder,
 	}
 
 	tv_ctl |= TV_ENC_PIPE_SEL(intel_crtc->pipe);
-	tv_ctl |= tv_mode->oversample;
+
+	switch (tv_mode->oversample) {
+	case 8:
+		tv_ctl |= TV_OVERSAMPLE_8X;
+		break;
+	case 4:
+		tv_ctl |= TV_OVERSAMPLE_4X;
+		break;
+	case 2:
+		tv_ctl |= TV_OVERSAMPLE_2X;
+		break;
+	default:
+		tv_ctl |= TV_OVERSAMPLE_NONE;
+		break;
+	}
 
 	if (tv_mode->progressive)
 		tv_ctl |= TV_PROGRESSIVE;
-- 
2.18.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 06/15] drm/i915/tv: Use bools where appropriate
  2018-11-12 16:59 [PATCH 00/15] drm/i915: Fix TV encoder support Ville Syrjala
                   ` (4 preceding siblings ...)
  2018-11-12 16:59 ` [PATCH 05/15] drm/i915/tv: Store the TV oversampling factor in the TV mode Ville Syrjala
@ 2018-11-12 16:59 ` Ville Syrjala
  2019-01-22 13:07   ` Imre Deak
  2018-11-12 16:59 ` [PATCH 07/15] drm/i915/tv: Nuke silly 0 initialzation of xpos/ypos Ville Syrjala
                   ` (18 subsequent siblings)
  24 siblings, 1 reply; 66+ messages in thread
From: Ville Syrjala @ 2018-11-12 16:59 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

'component_only' is a bool. Initialize it like a bool.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_tv.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 96257b29d07c..72de154b8627 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -380,7 +380,7 @@ static const struct tv_mode tv_modes[] = {
 		.clock		= 108000,
 		.refresh	= 59940,
 		.oversample	= 8,
-		.component_only = 0,
+		.component_only = false,
 		/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
 
 		.hsync_end	= 64,		    .hblank_end		= 124,
@@ -423,7 +423,7 @@ static const struct tv_mode tv_modes[] = {
 		.clock		= 108000,
 		.refresh	= 59940,
 		.oversample	= 8,
-		.component_only = 0,
+		.component_only = false,
 		/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 4.43MHz */
 		.hsync_end	= 64,		    .hblank_end		= 124,
 		.hblank_start	= 836,		    .htotal		= 857,
@@ -465,7 +465,7 @@ static const struct tv_mode tv_modes[] = {
 		.clock		= 108000,
 		.refresh	= 59940,
 		.oversample	= 8,
-		.component_only = 0,
+		.component_only = false,
 
 		/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
 		.hsync_end	= 64,		    .hblank_end		= 124,
@@ -508,7 +508,7 @@ static const struct tv_mode tv_modes[] = {
 		.clock		= 108000,
 		.refresh	= 59940,
 		.oversample	= 8,
-		.component_only = 0,
+		.component_only = false,
 
 		/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
 		.hsync_end	= 64,		  .hblank_end		= 124,
@@ -552,7 +552,7 @@ static const struct tv_mode tv_modes[] = {
 		.clock		= 108000,
 		.refresh	= 50000,
 		.oversample	= 8,
-		.component_only = 0,
+		.component_only = false,
 
 		.hsync_end	= 64,		    .hblank_end		= 128,
 		.hblank_start = 844,	    .htotal		= 863,
@@ -597,7 +597,7 @@ static const struct tv_mode tv_modes[] = {
 		.clock		= 108000,
 		.refresh	= 50000,
 		.oversample	= 8,
-		.component_only = 0,
+		.component_only = false,
 
 		.hsync_end	= 64,		    .hblank_end		= 142,
 		.hblank_start	= 844,	    .htotal		= 863,
@@ -639,7 +639,7 @@ static const struct tv_mode tv_modes[] = {
 		.clock		= 108000,
 		.refresh	= 59940,
 		.oversample     = 4,
-		.component_only = 1,
+		.component_only = true,
 
 		.hsync_end      = 64,               .hblank_end         = 122,
 		.hblank_start   = 842,              .htotal             = 857,
@@ -663,7 +663,7 @@ static const struct tv_mode tv_modes[] = {
 		.clock		= 108000,
 		.refresh	= 50000,
 		.oversample     = 4,
-		.component_only = 1,
+		.component_only = true,
 
 		.hsync_end      = 64,               .hblank_end         = 139,
 		.hblank_start   = 859,              .htotal             = 863,
@@ -687,7 +687,7 @@ static const struct tv_mode tv_modes[] = {
 		.clock		= 148500,
 		.refresh	= 60000,
 		.oversample     = 2,
-		.component_only = 1,
+		.component_only = true,
 
 		.hsync_end      = 80,               .hblank_end         = 300,
 		.hblank_start   = 1580,             .htotal             = 1649,
@@ -711,7 +711,7 @@ static const struct tv_mode tv_modes[] = {
 		.clock		= 148500,
 		.refresh	= 50000,
 		.oversample     = 2,
-		.component_only = 1,
+		.component_only = true,
 
 		.hsync_end      = 80,               .hblank_end         = 300,
 		.hblank_start   = 1580,             .htotal             = 1979,
@@ -736,7 +736,7 @@ static const struct tv_mode tv_modes[] = {
 		.clock		= 148500,
 		.refresh	= 50000,
 		.oversample     = 2,
-		.component_only = 1,
+		.component_only = true,
 
 		.hsync_end      = 88,               .hblank_end         = 235,
 		.hblank_start   = 2155,             .htotal             = 2639,
@@ -762,7 +762,7 @@ static const struct tv_mode tv_modes[] = {
 		.clock		= 148500,
 		.refresh	= 60000,
 		.oversample     = 2,
-		.component_only = 1,
+		.component_only = true,
 
 		.hsync_end      = 88,               .hblank_end         = 235,
 		.hblank_start   = 2155,             .htotal             = 2199,
-- 
2.18.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 07/15] drm/i915/tv: Nuke silly 0 initialzation of xpos/ypos
  2018-11-12 16:59 [PATCH 00/15] drm/i915: Fix TV encoder support Ville Syrjala
                   ` (5 preceding siblings ...)
  2018-11-12 16:59 ` [PATCH 06/15] drm/i915/tv: Use bools where appropriate Ville Syrjala
@ 2018-11-12 16:59 ` Ville Syrjala
  2019-01-22 13:09   ` Imre Deak
  2018-11-12 16:59 ` [PATCH 07/15] drm/i915/tv: Nuke silly 0 inittialization " Ville Syrjala
                   ` (17 subsequent siblings)
  24 siblings, 1 reply; 66+ messages in thread
From: Ville Syrjala @ 2018-11-12 16:59 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Just assign the margin values directly to xpos/ypos instead
of first initializing to zero and then adding the values.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_tv.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 72de154b8627..97a82878359f 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -994,7 +994,7 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder,
 	const struct video_levels *video_levels;
 	const struct color_conversion *color_conversion;
 	bool burst_ena;
-	int xpos = 0x0, ypos = 0x0;
+	int xpos, ypos;
 	unsigned int xsize, ysize;
 
 	if (!tv_mode)
@@ -1103,8 +1103,8 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder,
 	else
 		ysize = 2 * (tv_mode->nbr_end + 1);
 
-	xpos += conn_state->tv.margins.left;
-	ypos += conn_state->tv.margins.top;
+	xpos = conn_state->tv.margins.left;
+	ypos = conn_state->tv.margins.top;
 	xsize -= (conn_state->tv.margins.left +
 		  conn_state->tv.margins.right);
 	ysize -= (conn_state->tv.margins.top +
-- 
2.18.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 07/15] drm/i915/tv: Nuke silly 0 inittialization of xpos/ypos
  2018-11-12 16:59 [PATCH 00/15] drm/i915: Fix TV encoder support Ville Syrjala
                   ` (6 preceding siblings ...)
  2018-11-12 16:59 ` [PATCH 07/15] drm/i915/tv: Nuke silly 0 initialzation of xpos/ypos Ville Syrjala
@ 2018-11-12 16:59 ` Ville Syrjala
  2018-11-12 16:59 ` [PATCH 08/15] drm/i915/tv: Deobfuscate preferred mode selection Ville Syrjala
                   ` (16 subsequent siblings)
  24 siblings, 0 replies; 66+ messages in thread
From: Ville Syrjala @ 2018-11-12 16:59 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Just assign the margin values directly to xpos/ypos instead
of first initializing to zero and then adding the values.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_tv.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 72de154b8627..97a82878359f 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -994,7 +994,7 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder,
 	const struct video_levels *video_levels;
 	const struct color_conversion *color_conversion;
 	bool burst_ena;
-	int xpos = 0x0, ypos = 0x0;
+	int xpos, ypos;
 	unsigned int xsize, ysize;
 
 	if (!tv_mode)
@@ -1103,8 +1103,8 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder,
 	else
 		ysize = 2 * (tv_mode->nbr_end + 1);
 
-	xpos += conn_state->tv.margins.left;
-	ypos += conn_state->tv.margins.top;
+	xpos = conn_state->tv.margins.left;
+	ypos = conn_state->tv.margins.top;
 	xsize -= (conn_state->tv.margins.left +
 		  conn_state->tv.margins.right);
 	ysize -= (conn_state->tv.margins.top +
-- 
2.18.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 08/15] drm/i915/tv: Deobfuscate preferred mode selection
  2018-11-12 16:59 [PATCH 00/15] drm/i915: Fix TV encoder support Ville Syrjala
                   ` (7 preceding siblings ...)
  2018-11-12 16:59 ` [PATCH 07/15] drm/i915/tv: Nuke silly 0 inittialization " Ville Syrjala
@ 2018-11-12 16:59 ` Ville Syrjala
  2019-01-22 14:43   ` [Intel-gfx] " Imre Deak
  2018-11-12 16:59 ` [PATCH 09/15] drm/i915/tv: Use drm_mode_set_name() to name TV modes Ville Syrjala
                   ` (15 subsequent siblings)
  24 siblings, 1 reply; 66+ messages in thread
From: Ville Syrjala @ 2018-11-12 16:59 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Rewrite the preferred mode selection to just check
whether the TV modes is HD or SD. For SD TV modes we
favor 480 line modes, for 720p we prefer 720 line modes,
and for 1080i/p we prefer 1080 line modes.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_tv.c | 50 ++++++++++++++++++++-------------
 1 file changed, 30 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 97a82878359f..54189080cfb1 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -860,6 +860,14 @@ intel_tv_mode_valid(struct drm_connector *connector,
 	return MODE_CLOCK_RANGE;
 }
 
+static int
+intel_tv_mode_vdisplay(const struct tv_mode *tv_mode)
+{
+	if (tv_mode->progressive)
+		return tv_mode->nbr_end + 1;
+	else
+		return 2 * (tv_mode->nbr_end + 1);
+}
 
 static void
 intel_tv_get_config(struct intel_encoder *encoder,
@@ -1098,10 +1106,7 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder,
 	/* Filter ctl must be set before TV_WIN_SIZE */
 	I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);
 	xsize = tv_mode->hblank_start - tv_mode->hblank_end;
-	if (tv_mode->progressive)
-		ysize = tv_mode->nbr_end + 1;
-	else
-		ysize = 2 * (tv_mode->nbr_end + 1);
+	ysize = intel_tv_mode_vdisplay(tv_mode);
 
 	xpos = conn_state->tv.margins.left;
 	ypos = conn_state->tv.margins.top;
@@ -1320,22 +1325,28 @@ static const struct input_res {
 	{"1920x1080", 1920, 1080},
 };
 
-/*
- * Chose preferred mode  according to line number of TV format
- */
+/* Choose preferred mode according to line number of TV format */
+static bool
+intel_tv_is_preferred_mode(const struct drm_display_mode *mode,
+			   const struct tv_mode *tv_mode)
+{
+	int vdisplay = intel_tv_mode_vdisplay(tv_mode);
+
+	/* prefer 480 line modes for all SD TV modes */
+	if (vdisplay <= 576)
+		vdisplay = 480;
+
+	return vdisplay == mode->vdisplay;
+}
+
 static void
-intel_tv_choose_preferred_modes(const struct tv_mode *tv_mode,
-			       struct drm_display_mode *mode_ptr)
+intel_tv_set_mode_type(struct drm_display_mode *mode,
+		       const struct tv_mode *tv_mode)
 {
-	if (tv_mode->nbr_end < 480 && mode_ptr->vdisplay == 480)
-		mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
-	else if (tv_mode->nbr_end > 480) {
-		if (tv_mode->progressive == true && tv_mode->nbr_end < 720) {
-			if (mode_ptr->vdisplay == 720)
-				mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
-		} else if (mode_ptr->vdisplay == 1080)
-				mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
-	}
+	mode->type = DRM_MODE_TYPE_DRIVER;
+
+	if (intel_tv_is_preferred_mode(mode, tv_mode))
+		mode->type |= DRM_MODE_TYPE_PREFERRED;
 }
 
 static int
@@ -1383,8 +1394,7 @@ intel_tv_get_modes(struct drm_connector *connector)
 		tmp = div_u64(tmp, 1000000);
 		mode_ptr->clock = (int) tmp;
 
-		mode_ptr->type = DRM_MODE_TYPE_DRIVER;
-		intel_tv_choose_preferred_modes(tv_mode, mode_ptr);
+		intel_tv_set_mode_type(mode_ptr, tv_mode);
 		drm_mode_probed_add(connector, mode_ptr);
 		count++;
 	}
-- 
2.18.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 09/15] drm/i915/tv: Use drm_mode_set_name() to name TV modes
  2018-11-12 16:59 [PATCH 00/15] drm/i915: Fix TV encoder support Ville Syrjala
                   ` (8 preceding siblings ...)
  2018-11-12 16:59 ` [PATCH 08/15] drm/i915/tv: Deobfuscate preferred mode selection Ville Syrjala
@ 2018-11-12 16:59 ` Ville Syrjala
  2019-01-22 14:45   ` Imre Deak
  2018-11-12 16:59 ` [PATCH 10/15] drm/i915/tv: Make TV mode autoselection actually useable Ville Syrjala
                   ` (14 subsequent siblings)
  24 siblings, 1 reply; 66+ messages in thread
From: Ville Syrjala @ 2018-11-12 16:59 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

No point in storing the mode names in the array. drm_mode_set_name()
will give us the same names without wasting space for these string
constants.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_tv.c | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 54189080cfb1..433f538261c1 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1313,16 +1313,15 @@ intel_tv_detect(struct drm_connector *connector,
 }
 
 static const struct input_res {
-	const char *name;
-	int w, h;
+	u16 w, h;
 } input_res_table[] = {
-	{"640x480", 640, 480},
-	{"800x600", 800, 600},
-	{"1024x768", 1024, 768},
-	{"1280x1024", 1280, 1024},
-	{"848x480", 848, 480},
-	{"1280x720", 1280, 720},
-	{"1920x1080", 1920, 1080},
+	{ 640, 480 },
+	{ 800, 600 },
+	{ 1024, 768 },
+	{ 1280, 1024 },
+	{ 848, 480 },
+	{ 1280, 720 },
+	{ 1920, 1080 },
 };
 
 /* Choose preferred mode according to line number of TV format */
@@ -1373,7 +1372,6 @@ intel_tv_get_modes(struct drm_connector *connector)
 		mode_ptr = drm_mode_create(connector->dev);
 		if (!mode_ptr)
 			continue;
-		strlcpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN);
 
 		mode_ptr->hdisplay = hactive_s;
 		mode_ptr->hsync_start = hactive_s + 1;
@@ -1395,6 +1393,9 @@ intel_tv_get_modes(struct drm_connector *connector)
 		mode_ptr->clock = (int) tmp;
 
 		intel_tv_set_mode_type(mode_ptr, tv_mode);
+
+		drm_mode_set_name(mode_ptr);
+
 		drm_mode_probed_add(connector, mode_ptr);
 		count++;
 	}
-- 
2.18.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 10/15] drm/i915/tv: Make TV mode autoselection actually useable
  2018-11-12 16:59 [PATCH 00/15] drm/i915: Fix TV encoder support Ville Syrjala
                   ` (9 preceding siblings ...)
  2018-11-12 16:59 ` [PATCH 09/15] drm/i915/tv: Use drm_mode_set_name() to name TV modes Ville Syrjala
@ 2018-11-12 16:59 ` Ville Syrjala
  2019-01-22 14:54   ` Imre Deak
  2018-11-12 16:59 ` [PATCH 11/15] drm/i915/tv: Nuke reported_modes[] Ville Syrjala
                   ` (13 subsequent siblings)
  24 siblings, 1 reply; 66+ messages in thread
From: Ville Syrjala @ 2018-11-12 16:59 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

The current code insists on picking a new TV mode when
switching between component and non-component cables.
That's super annoying. Let's just keep the current TV
mode unless the new cable type actually disagrees with it.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_tv.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 433f538261c1..32a8786fe0da 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1253,16 +1253,18 @@ static void intel_tv_find_better_format(struct drm_connector *connector)
 	const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
 	int i;
 
-	if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) ==
-		tv_mode->component_only)
+	/* Component supports everything so we can keep the current mode */
+	if (intel_tv->type == DRM_MODE_CONNECTOR_Component)
 		return;
 
+	/* If the current mode is fine don't change it */
+	if (!tv_mode->component_only)
+		return;
 
 	for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
-		tv_mode = tv_modes + i;
+		tv_mode = &tv_modes[i];
 
-		if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) ==
-			tv_mode->component_only)
+		if (!tv_mode->component_only)
 			break;
 	}
 
-- 
2.18.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 11/15] drm/i915/tv: Nuke reported_modes[]
  2018-11-12 16:59 [PATCH 00/15] drm/i915: Fix TV encoder support Ville Syrjala
                   ` (10 preceding siblings ...)
  2018-11-12 16:59 ` [PATCH 10/15] drm/i915/tv: Make TV mode autoselection actually useable Ville Syrjala
@ 2018-11-12 16:59 ` Ville Syrjala
  2019-01-22 15:08   ` Imre Deak
  2018-11-12 16:59 ` [PATCH 12/15] drm/i915/tv: Add 1080p30/50/60 TV modes Ville Syrjala
                   ` (12 subsequent siblings)
  24 siblings, 1 reply; 66+ messages in thread
From: Ville Syrjala @ 2018-11-12 16:59 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Remove the silly reported_modes[] array. I suppse once upon a time
this actually had something to do with modes we reported to userspace.
Now it is just the placeholder for the mode we use for load detection.
We don't need it even for that, and instead we can just rely on
the fallback mode in intel_get_load_detect_pipe().

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_tv.c | 22 +---------------------
 1 file changed, 1 insertion(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 32a8786fe0da..c39e9a5b43db 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1130,23 +1130,6 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder,
 	I915_WRITE(TV_CTL, tv_ctl);
 }
 
-static const struct drm_display_mode reported_modes[] = {
-	{
-		.name = "NTSC 480i",
-		.clock = 108000,
-		.hdisplay = 1280,
-		.hsync_start = 1368,
-		.hsync_end = 1496,
-		.htotal = 1712,
-
-		.vdisplay = 1024,
-		.vsync_start = 1027,
-		.vsync_end = 1034,
-		.vtotal = 1104,
-		.type = DRM_MODE_TYPE_DRIVER,
-	},
-};
-
 static int
 intel_tv_detect_type(struct intel_tv *intel_tv,
 		      struct drm_connector *connector)
@@ -1276,7 +1259,6 @@ intel_tv_detect(struct drm_connector *connector,
 		struct drm_modeset_acquire_ctx *ctx,
 		bool force)
 {
-	struct drm_display_mode mode;
 	struct intel_tv *intel_tv = intel_attached_tv(connector);
 	enum drm_connector_status status;
 	int type;
@@ -1285,13 +1267,11 @@ intel_tv_detect(struct drm_connector *connector,
 		      connector->base.id, connector->name,
 		      force);
 
-	mode = reported_modes[0];
-
 	if (force) {
 		struct intel_load_detect_pipe tmp;
 		int ret;
 
-		ret = intel_get_load_detect_pipe(connector, &mode, &tmp, ctx);
+		ret = intel_get_load_detect_pipe(connector, NULL, &tmp, ctx);
 		if (ret < 0)
 			return ret;
 
-- 
2.18.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 12/15] drm/i915/tv: Add 1080p30/50/60 TV modes
  2018-11-12 16:59 [PATCH 00/15] drm/i915: Fix TV encoder support Ville Syrjala
                   ` (11 preceding siblings ...)
  2018-11-12 16:59 ` [PATCH 11/15] drm/i915/tv: Nuke reported_modes[] Ville Syrjala
@ 2018-11-12 16:59 ` Ville Syrjala
  2019-01-22 15:09   ` [Intel-gfx] " Imre Deak
  2018-11-12 16:59 ` [PATCH 13/15] drm/i915/tv: Generate better pipe timings for TV encoder Ville Syrjala
                   ` (11 subsequent siblings)
  24 siblings, 1 reply; 66+ messages in thread
From: Ville Syrjala @ 2018-11-12 16:59 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Add the missing 1080p TV modes. On gen4 all of them work just fine,
whereas on gen3 only the 30Hz mode actually works correctly.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_tv.c | 90 +++++++++++++++++++++++++++++++--
 1 file changed, 86 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index c39e9a5b43db..216525dd144a 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -783,6 +783,84 @@ static const struct tv_mode tv_modes[] = {
 
 		.filter_table = filter_table,
 	},
+
+	{
+		.name       = "1080p@30Hz",
+		.clock		= 148500,
+		.refresh	= 30000,
+		.oversample     = 2,
+		.component_only = true,
+
+		.hsync_end      = 88,               .hblank_end         = 235,
+		.hblank_start   = 2155,             .htotal             = 2199,
+
+		.progressive	= true,		    .trilevel_sync = true,
+
+		.vsync_start_f1 = 8,               .vsync_start_f2     = 8,
+		.vsync_len      = 10,
+
+		.veq_ena	= false,	.veq_start_f1	= 0,
+		.veq_start_f2	= 0,		    .veq_len		= 0,
+
+		.vi_end_f1      = 44,               .vi_end_f2          = 44,
+		.nbr_end        = 1079,
+
+		.burst_ena      = false,
+
+		.filter_table = filter_table,
+	},
+
+	{
+		.name       = "1080p@50Hz",
+		.clock		= 148500,
+		.refresh	= 50000,
+		.oversample     = 1,
+		.component_only = true,
+
+		.hsync_end      = 88,               .hblank_end         = 235,
+		.hblank_start   = 2155,             .htotal             = 2639,
+
+		.progressive	= true,		    .trilevel_sync = true,
+
+		.vsync_start_f1 = 8,               .vsync_start_f2     = 8,
+		.vsync_len      = 10,
+
+		.veq_ena	= false,	.veq_start_f1	= 0,
+		.veq_start_f2	= 0,		    .veq_len		= 0,
+
+		.vi_end_f1      = 44,               .vi_end_f2          = 44,
+		.nbr_end        = 1079,
+
+		.burst_ena      = false,
+
+		.filter_table = filter_table,
+	},
+
+	{
+		.name       = "1080p@60Hz",
+		.clock		= 148500,
+		.refresh	= 60000,
+		.oversample     = 1,
+		.component_only = true,
+
+		.hsync_end      = 88,               .hblank_end         = 235,
+		.hblank_start   = 2155,             .htotal             = 2199,
+
+		.progressive	= true,		    .trilevel_sync = true,
+
+		.vsync_start_f1 = 8,               .vsync_start_f2     = 8,
+		.vsync_len      = 10,
+
+		.veq_ena	= false,		    .veq_start_f1	= 0,
+		.veq_start_f2	= 0,		    .veq_len		= 0,
+
+		.vi_end_f1      = 44,               .vi_end_f2          = 44,
+		.nbr_end        = 1079,
+
+		.burst_ena      = false,
+
+		.filter_table = filter_table,
+	},
 };
 
 static struct intel_tv *enc_to_tv(struct intel_encoder *encoder)
@@ -1538,11 +1616,15 @@ intel_tv_init(struct drm_i915_private *dev_priv)
 	connector->doublescan_allowed = false;
 
 	/* Create TV properties then attach current values */
-	for (i = 0; i < ARRAY_SIZE(tv_modes); i++)
+	for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
+		/* 1080p50/1080p60 not supported on gen3 */
+		if (IS_GEN3(dev_priv) &&
+		    tv_modes[i].oversample == 1)
+			break;
+
 		tv_format_names[i] = tv_modes[i].name;
-	drm_mode_create_tv_properties(dev,
-				      ARRAY_SIZE(tv_modes),
-				      tv_format_names);
+	}
+	drm_mode_create_tv_properties(dev, i, tv_format_names);
 
 	drm_object_attach_property(&connector->base, dev->mode_config.tv_mode_property,
 				   state->tv.mode);
-- 
2.18.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 13/15] drm/i915/tv: Generate better pipe timings for TV encoder
  2018-11-12 16:59 [PATCH 00/15] drm/i915: Fix TV encoder support Ville Syrjala
                   ` (12 preceding siblings ...)
  2018-11-12 16:59 ` [PATCH 12/15] drm/i915/tv: Add 1080p30/50/60 TV modes Ville Syrjala
@ 2018-11-12 16:59 ` Ville Syrjala
  2019-01-22 17:22   ` Imre Deak
  2018-11-12 16:59 ` [PATCH 14/15] drm/i915/tv: Fix >1024 modes on gen3 Ville Syrjala
                   ` (10 subsequent siblings)
  24 siblings, 1 reply; 66+ messages in thread
From: Ville Syrjala @ 2018-11-12 16:59 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

To make vblank timestamps work better with the TV encoder let's
scale the pipe timings such that the relationship between the
TV active and TV blanking periods is mirrored in the
corresponding pipe timings.

Note that in reality the pipe runs at a faster speed during the
TV vblank, and correspondigly there are periods when the pipe
is enitrely stopped. We pretend that this isn't the case and
as such we incur some error in the vblank timestamps during
the TV vblank. Further explanation of the issues in a big
comment in the code.

This makes the vblank timestamps good enough to make
i965gm (which doesn't have a working frame counter with
the TV encoder) report correct frame numbers. Previously
you could get all kinds of nonsense which resulted in
eg. glxgears reporting that it's running at twice the
actual framerate in most cases.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_reg.h |   1 +
 drivers/gpu/drm/i915/intel_tv.c | 322 +++++++++++++++++++++++++++-----
 2 files changed, 278 insertions(+), 45 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index fe4b913e46ac..10813ae7bee7 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -4848,6 +4848,7 @@ enum {
 # define TV_OVERSAMPLE_NONE		(2 << 18)
 /* Selects 8x oversampling */
 # define TV_OVERSAMPLE_8X		(3 << 18)
+# define TV_OVERSAMPLE_MASK		(3 << 18)
 /* Selects progressive mode rather than interlaced */
 # define TV_PROGRESSIVE			(1 << 17)
 /* Sets the colorburst to PAL mode.  Required for non-M PAL modes. */
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 216525dd144a..75126fce655d 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -340,7 +340,6 @@ struct tv_mode {
 	const struct video_levels *composite_levels, *svideo_levels;
 	const struct color_conversion *composite_color, *svideo_color;
 	const u32 *filter_table;
-	u16 max_srcw;
 };
 
 
@@ -729,7 +728,6 @@ static const struct tv_mode tv_modes[] = {
 		.burst_ena      = false,
 
 		.filter_table = filter_table,
-		.max_srcw = 800
 	},
 	{
 		.name       = "1080i@50Hz",
@@ -947,13 +945,183 @@ intel_tv_mode_vdisplay(const struct tv_mode *tv_mode)
 		return 2 * (tv_mode->nbr_end + 1);
 }
 
+static void
+intel_tv_mode_to_mode(struct drm_display_mode *mode,
+		      const struct tv_mode *tv_mode)
+{
+	mode->clock = tv_mode->clock /
+		(tv_mode->oversample >> !tv_mode->progressive);
+
+	/*
+	 * tv_mode horizontal timings:
+	 *
+	 * hsync_end
+	 *    | hblank_end
+	 *    |    | hblank_start
+	 *    |    |       | htotal
+	 *    |     _______    |
+	 *     ____/       \___
+	 * \__/                \
+	 */
+	mode->hdisplay =
+		tv_mode->hblank_start - tv_mode->hblank_end;
+	mode->hsync_start = mode->hdisplay +
+		tv_mode->htotal - tv_mode->hblank_start;
+	mode->hsync_end = mode->hsync_start +
+		tv_mode->hsync_end;
+	mode->htotal = tv_mode->htotal + 1;
+
+	/*
+	 * tv_mode vertical timings:
+	 *
+	 * vsync_start
+	 *    | vsync_end
+	 *    |  | vi_end nbr_end
+	 *    |  |    |       |
+	 *    |  |     _______
+	 * \__    ____/       \
+	 *    \__/
+	 */
+	mode->vdisplay = intel_tv_mode_vdisplay(tv_mode);
+	if (tv_mode->progressive) {
+		mode->vsync_start = mode->vdisplay +
+			tv_mode->vsync_start_f1 + 1;
+		mode->vsync_end = mode->vsync_start +
+			tv_mode->vsync_len;
+		mode->vtotal = mode->vdisplay +
+			tv_mode->vi_end_f1 + 1;
+	} else {
+		mode->vsync_start = mode->vdisplay +
+			tv_mode->vsync_start_f1 + 1 +
+			tv_mode->vsync_start_f2 + 1;
+		mode->vsync_end = mode->vsync_start +
+			2 * tv_mode->vsync_len;
+		mode->vtotal = mode->vdisplay +
+			tv_mode->vi_end_f1 + 1 +
+			tv_mode->vi_end_f2 + 1;
+	}
+
+	/* TV has it's own notion of sync and other mode flags, so clear them. */
+	mode->flags = 0;
+
+	mode->vrefresh = 0;
+	mode->vrefresh = drm_mode_vrefresh(mode);
+
+	snprintf(mode->name, sizeof(mode->name),
+		 "%dx%d%c (%s)",
+		 mode->hdisplay, mode->vdisplay,
+		 tv_mode->progressive ? 'p' : 'i',
+		 tv_mode->name);
+}
+
+static void intel_tv_scale_mode_horiz(struct drm_display_mode *mode,
+				      int hdisplay, int left_margin,
+				      int right_margin)
+{
+	int hsync_start = mode->hsync_start - mode->hdisplay + right_margin;
+	int hsync_end = mode->hsync_end - mode->hdisplay + right_margin;
+	int new_htotal = mode->htotal * hdisplay /
+		(mode->hdisplay - left_margin - right_margin);
+
+	mode->clock = mode->clock * new_htotal / mode->htotal;
+
+	mode->hdisplay = hdisplay;
+	mode->hsync_start = hdisplay + hsync_start * new_htotal / mode->htotal;
+	mode->hsync_end = hdisplay + hsync_end * new_htotal / mode->htotal;
+	mode->htotal = new_htotal;
+}
+
+static void intel_tv_scale_mode_vert(struct drm_display_mode *mode,
+				     int vdisplay, int top_margin,
+				     int bottom_margin)
+{
+	int vsync_start = mode->vsync_start - mode->vdisplay + bottom_margin;
+	int vsync_end = mode->vsync_end - mode->vdisplay + bottom_margin;
+	int new_vtotal = mode->vtotal * vdisplay /
+		(mode->vdisplay - top_margin - bottom_margin);
+
+	mode->clock = mode->clock * new_vtotal / mode->vtotal;
+
+	mode->vdisplay = vdisplay;
+	mode->vsync_start = vdisplay + vsync_start * new_vtotal / mode->vtotal;
+	mode->vsync_end = vdisplay + vsync_end * new_vtotal / mode->vtotal;
+	mode->vtotal = new_vtotal;
+}
+
 static void
 intel_tv_get_config(struct intel_encoder *encoder,
 		    struct intel_crtc_state *pipe_config)
 {
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct drm_display_mode *adjusted_mode =
+		&pipe_config->base.adjusted_mode;
+	struct drm_display_mode mode = {};
+	u32 tv_ctl, hctl1, hctl3, vctl1, vctl2, tmp;
+	struct tv_mode tv_mode = {};
+	int hdisplay = adjusted_mode->crtc_hdisplay;
+	int vdisplay = adjusted_mode->crtc_vdisplay;
+	int xsize, ysize, xpos, ypos;
+
 	pipe_config->output_types |= BIT(INTEL_OUTPUT_TVOUT);
 
-	pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
+	tv_ctl = I915_READ(TV_CTL);
+	hctl1 = I915_READ(TV_H_CTL_1);
+	hctl3 = I915_READ(TV_H_CTL_3);
+	vctl1 = I915_READ(TV_V_CTL_1);
+	vctl2 = I915_READ(TV_V_CTL_2);
+
+	tv_mode.htotal = (hctl1 & TV_HTOTAL_MASK) >> TV_HTOTAL_SHIFT;
+	tv_mode.hsync_end = (hctl1 & TV_HSYNC_END_MASK) >> TV_HSYNC_END_SHIFT;
+
+	tv_mode.hblank_start = (hctl3 & TV_HBLANK_START_MASK) >> TV_HBLANK_START_SHIFT;
+	tv_mode.hblank_end = (hctl3 & TV_HSYNC_END_MASK) >> TV_HBLANK_END_SHIFT;
+
+	tv_mode.nbr_end = (vctl1 & TV_NBR_END_MASK) >> TV_NBR_END_SHIFT;
+	tv_mode.vi_end_f1 = (vctl1 & TV_VI_END_F1_MASK) >> TV_VI_END_F1_SHIFT;
+	tv_mode.vi_end_f2 = (vctl1 & TV_VI_END_F2_MASK) >> TV_VI_END_F2_SHIFT;
+
+	tv_mode.vsync_len = (vctl2 & TV_VSYNC_LEN_MASK) >> TV_VSYNC_LEN_SHIFT;
+	tv_mode.vsync_start_f1 = (vctl2 & TV_VSYNC_START_F1_MASK) >> TV_VSYNC_START_F1_SHIFT;
+	tv_mode.vsync_start_f2 = (vctl2 & TV_VSYNC_START_F2_MASK) >> TV_VSYNC_START_F2_SHIFT;
+
+	tv_mode.clock = pipe_config->port_clock;
+
+	tv_mode.progressive = tv_ctl & TV_PROGRESSIVE;
+
+	switch (tv_ctl & TV_OVERSAMPLE_MASK) {
+	case TV_OVERSAMPLE_8X:
+		tv_mode.oversample = 8;
+		break;
+	case TV_OVERSAMPLE_4X:
+		tv_mode.oversample = 4;
+		break;
+	case TV_OVERSAMPLE_2X:
+		tv_mode.oversample = 2;
+		break;
+	default:
+		tv_mode.oversample = 1;
+		break;
+	}
+
+	tmp = I915_READ(TV_WIN_POS);
+	xpos = tmp >> 16;
+	ypos = tmp & 0xffff;
+
+	tmp = I915_READ(TV_WIN_SIZE);
+	xsize = tmp >> 16;
+	ysize = tmp & 0xffff;
+
+	intel_tv_mode_to_mode(&mode, &tv_mode);
+
+	DRM_DEBUG_KMS("TV mode:\n");
+	drm_mode_debug_printmodeline(&mode);
+
+	intel_tv_scale_mode_horiz(&mode, hdisplay,
+				  xpos, mode.hdisplay - xsize - xpos);
+	intel_tv_scale_mode_vert(&mode, vdisplay,
+				 ypos, mode.vdisplay - ysize - ypos);
+
+	adjusted_mode->crtc_clock = mode.clock;
 }
 
 static bool
@@ -964,6 +1132,8 @@ intel_tv_compute_config(struct intel_encoder *encoder,
 	const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
 	struct drm_display_mode *adjusted_mode =
 		&pipe_config->base.adjusted_mode;
+	int hdisplay = adjusted_mode->crtc_hdisplay;
+	int vdisplay = adjusted_mode->crtc_vdisplay;
 
 	if (!tv_mode)
 		return false;
@@ -972,17 +1142,90 @@ intel_tv_compute_config(struct intel_encoder *encoder,
 		return false;
 
 	pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
-	adjusted_mode->crtc_clock = tv_mode->clock;
+
 	DRM_DEBUG_KMS("forcing bpc to 8 for TV\n");
 	pipe_config->pipe_bpp = 8*3;
 
-	/* TV has it's own notion of sync and other mode flags, so clear them. */
-	adjusted_mode->flags = 0;
+	pipe_config->port_clock = tv_mode->clock;
+
+	intel_tv_mode_to_mode(adjusted_mode, tv_mode);
+
+	DRM_DEBUG_KMS("TV mode:\n");
+	drm_mode_debug_printmodeline(adjusted_mode);
 
 	/*
-	 * FIXME: We don't check whether the input mode is actually what we want
-	 * or whether userspace is doing something stupid.
+	 * The pipe scanline counter behaviour looks as follows when
+	 * using the TV encoder:
+	 *
+	 * time ->
+	 *
+	 * dsl=vtotal-1       |             |
+	 *                   ||            ||
+	 *               ___| |        ___| |
+	 *              /     |       /     |
+	 *             /      |      /      |
+	 * dsl=0   ___/       |_____/       |
+	 *        | | |  |  | |
+	 *         ^ ^ ^   ^ ^
+	 *         | | |   | pipe vblank/first part of tv vblank
+	 *         | | |   bottom margin
+	 *         | | active
+	 *         | top margin
+	 *         remainder of tv vblank
+	 *
+	 * When the TV encoder is used the pipe wants to run faster
+	 * than expected rate. During the active portion the TV
+	 * encoder stalls the pipe every few lines to keep it in
+	 * check. When the TV encoder reaches the bottom margin the
+	 * pipe simply stops. Once we reach the TV vblank the pipe is
+	 * no longer stalled and it runs at the max rate (apparently
+	 * oversample clock on gen3, cdclk on gen4). Once the pipe
+	 * reaches the pipe vtotal the pipe stops for the remainder
+	 * of the TV vblank/top margin. The pipe starts up again when
+	 * the TV encoder exits the top margin.
+	 *
+	 * To avoid huge hassles for vblank timestamping we scale
+	 * the pipe timings as if the pipe always runs at the average
+	 * rate it maintains during the active period. This also
+	 * gives us a reasonable guesstimate as to the pixel rate.
+	 * Due to the variation in the actual pipe speed the scanline
+	 * counter will give us slightly erroneous results during the
+	 * TV vblank/margins. But since vtotal was selected such that
+	 * it matches the average rate of the pipe during the active
+	 * portion the error shouldn't cause any serious grief to
+	 * vblank timestamps.
+	 *
+	 * For posterity here is the empirically derived formula
+	 * that gives us the maximum length of the pipe vblank
+	 * we can use without causing display corruption. Following
+	 * this would allow us to have a ticking scanline counter
+	 * everywhere except during the bottom margin (there the
+	 * pipe always stops). Ie. this would eliminate the second
+	 * flat portion of the above graph. However this would also
+	 * complicate vblank timestamping as the pipe vtotal would
+	 * no longer match the average rate the pipe runs at during
+	 * the active portion. Hence following this formula seems
+	 * more trouble that it's worth.
+	 *
+	 * if (IS_GEN4(dev_priv)) {
+	 *	num = cdclk * (tv_mode->oversample >> !tv_mode->progressive);
+	 *	den = tv_mode->clock;
+	 * } else {
+	 *	num = tv_mode->oversample >> !tv_mode->progressive;
+	 *	den = 1;
+	 * }
+	 * max_pipe_vblank_len ~=
+	 *	(num * tv_htotal * (tv_vblank_len + top_margin)) /
+	 *	(den * pipe_htotal);
 	 */
+	intel_tv_scale_mode_horiz(adjusted_mode, hdisplay,
+				  conn_state->tv.margins.left,
+				  conn_state->tv.margins.right);
+	intel_tv_scale_mode_vert(adjusted_mode, vdisplay,
+				 conn_state->tv.margins.top,
+				 conn_state->tv.margins.bottom);
+	drm_mode_set_crtcinfo(adjusted_mode, 0);
+	adjusted_mode->name[0] = '\0';
 
 	return true;
 }
@@ -1411,52 +1654,41 @@ intel_tv_set_mode_type(struct drm_display_mode *mode,
 static int
 intel_tv_get_modes(struct drm_connector *connector)
 {
-	struct drm_display_mode *mode_ptr;
 	const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
-	int j, count = 0;
-	u64 tmp;
+	int i, count = 0;
 
-	for (j = 0; j < ARRAY_SIZE(input_res_table);
-	     j++) {
-		const struct input_res *input = &input_res_table[j];
-		unsigned int hactive_s = input->w;
-		unsigned int vactive_s = input->h;
-
-		if (tv_mode->max_srcw && input->w > tv_mode->max_srcw)
-			continue;
+	for (i = 0; i < ARRAY_SIZE(input_res_table); i++) {
+		const struct input_res *input = &input_res_table[i];
+		struct drm_display_mode *mode;
 
-		if (input->w > 1024 && (!tv_mode->progressive
-					&& !tv_mode->component_only))
+		if (input->w > 1024 &&
+		    !tv_mode->progressive &&
+		    !tv_mode->component_only)
 			continue;
 
-		mode_ptr = drm_mode_create(connector->dev);
-		if (!mode_ptr)
+		mode = drm_mode_create(connector->dev);
+		if (!mode)
 			continue;
 
-		mode_ptr->hdisplay = hactive_s;
-		mode_ptr->hsync_start = hactive_s + 1;
-		mode_ptr->hsync_end = hactive_s + 64;
-		if (mode_ptr->hsync_end <= mode_ptr->hsync_start)
-			mode_ptr->hsync_end = mode_ptr->hsync_start + 1;
-		mode_ptr->htotal = hactive_s + 96;
-
-		mode_ptr->vdisplay = vactive_s;
-		mode_ptr->vsync_start = vactive_s + 1;
-		mode_ptr->vsync_end = vactive_s + 32;
-		if (mode_ptr->vsync_end <= mode_ptr->vsync_start)
-			mode_ptr->vsync_end = mode_ptr->vsync_start  + 1;
-		mode_ptr->vtotal = vactive_s + 33;
-
-		tmp = mul_u32_u32(tv_mode->refresh, mode_ptr->vtotal);
-		tmp *= mode_ptr->htotal;
-		tmp = div_u64(tmp, 1000000);
-		mode_ptr->clock = (int) tmp;
-
-		intel_tv_set_mode_type(mode_ptr, tv_mode);
+		/*
+		 * We take the TV mode and scale it to look
+		 * like it had the expected h/vdisplay. This
+		 * provides the most information to userspace
+		 * about the actual timings of the mode. We
+		 * do ignore the margins though.
+		 */
+		intel_tv_mode_to_mode(mode, tv_mode);
+		if (count == 0) {
+			DRM_DEBUG_KMS("TV mode:\n");
+			drm_mode_debug_printmodeline(mode);
+		}
+		intel_tv_scale_mode_horiz(mode, input->w, 0, 0);
+		intel_tv_scale_mode_vert(mode, input->h, 0, 0);
+		intel_tv_set_mode_type(mode, tv_mode);
 
-		drm_mode_set_name(mode_ptr);
+		drm_mode_set_name(mode);
 
-		drm_mode_probed_add(connector, mode_ptr);
+		drm_mode_probed_add(connector, mode);
 		count++;
 	}
 
-- 
2.18.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 14/15] drm/i915/tv: Fix >1024 modes on gen3
  2018-11-12 16:59 [PATCH 00/15] drm/i915: Fix TV encoder support Ville Syrjala
                   ` (13 preceding siblings ...)
  2018-11-12 16:59 ` [PATCH 13/15] drm/i915/tv: Generate better pipe timings for TV encoder Ville Syrjala
@ 2018-11-12 16:59 ` Ville Syrjala
  2019-01-23 13:49   ` Imre Deak
  2018-11-12 17:00 ` [PATCH 15/15] drm/i915/tv: Filter out >1024 wide modes that would need vertical scaling " Ville Syrjala
                   ` (9 subsequent siblings)
  24 siblings, 1 reply; 66+ messages in thread
From: Ville Syrjala @ 2018-11-12 16:59 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

On gen3 we must disable the TV encoder vertical filter for >1024
pixel wide sources. Once that's done all we can is try to center
the image on the screen. Naturally the TV mode vertical resolution
must be equal or larger than the user mode vertical resolution
or else we'd have to cut off part of the user mode.

And while we may not be able to respect the user's choice of
top and bottom borders exactly (or we'd have to reject he mode
most likely), we can try to maintain the relative sizes of the
top and bottom border with respect to each orher.

Additionally we must configure the pipe as interlaced if the
TV mode is interlaced.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_tv.c | 100 +++++++++++++++++++++++++++++---
 1 file changed, 92 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 75126fce655d..7099d837e31a 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -861,6 +861,44 @@ static const struct tv_mode tv_modes[] = {
 	},
 };
 
+struct intel_tv_connector_state {
+	struct drm_connector_state base;
+
+	/*
+	 * May need to override the user margins for
+	 * gen3 >1024 wide source vertical centering.
+	 */
+	struct {
+		u16 top, bottom;
+	} margins;
+
+	bool bypass_vfilter;
+};
+
+#define to_intel_tv_connector_state(x) container_of(x, struct intel_tv_connector_state, base)
+
+/**
+ * intel_digital_connector_duplicate_state - duplicate connector state
+ * @connector: digital connector
+ *
+ * Allocates and returns a copy of the connector state (both common and
+ * digital connector specific) for the specified connector.
+ *
+ * Returns: The newly allocated connector state, or NULL on failure.
+ */
+struct drm_connector_state *
+intel_tv_connector_duplicate_state(struct drm_connector *connector)
+{
+	struct intel_tv_connector_state *state;
+
+	state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	__drm_atomic_helper_connector_duplicate_state(connector, &state->base);
+	return &state->base;
+}
+
 static struct intel_tv *enc_to_tv(struct intel_encoder *encoder)
 {
 	return container_of(encoder, struct intel_tv, base);
@@ -1129,6 +1167,9 @@ intel_tv_compute_config(struct intel_encoder *encoder,
 			struct intel_crtc_state *pipe_config,
 			struct drm_connector_state *conn_state)
 {
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct intel_tv_connector_state *tv_conn_state =
+		to_intel_tv_connector_state(conn_state);
 	const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
 	struct drm_display_mode *adjusted_mode =
 		&pipe_config->base.adjusted_mode;
@@ -1149,6 +1190,43 @@ intel_tv_compute_config(struct intel_encoder *encoder,
 	pipe_config->port_clock = tv_mode->clock;
 
 	intel_tv_mode_to_mode(adjusted_mode, tv_mode);
+	drm_mode_set_crtcinfo(adjusted_mode, 0);
+
+	if (IS_GEN3(dev_priv) && hdisplay > 1024) {
+		int extra, top, bottom;
+
+		extra = adjusted_mode->crtc_vdisplay - vdisplay;
+
+		if (extra < 0) {
+			DRM_DEBUG_KMS("No vertical scaling for >1024 pixel wide modes\n");
+			return false;
+		}
+
+		/* Need to turn off the vertical filter and center the image */
+
+		/* Attempt to maintain the relative sizes of the margins */
+		top = conn_state->tv.margins.top;
+		bottom = conn_state->tv.margins.bottom;
+
+		if (top + bottom)
+			top = extra * top / (top + bottom);
+		else
+			top = extra / 2;
+		bottom = extra - top;
+
+		tv_conn_state->margins.top = top;
+		tv_conn_state->margins.bottom = bottom;
+
+		tv_conn_state->bypass_vfilter = true;
+
+		if (!tv_mode->progressive)
+			adjusted_mode->flags |= DRM_MODE_FLAG_INTERLACE;
+	} else {
+		tv_conn_state->margins.top = conn_state->tv.margins.top;
+		tv_conn_state->margins.bottom = conn_state->tv.margins.bottom;
+
+		tv_conn_state->bypass_vfilter = false;
+	}
 
 	DRM_DEBUG_KMS("TV mode:\n");
 	drm_mode_debug_printmodeline(adjusted_mode);
@@ -1222,8 +1300,8 @@ intel_tv_compute_config(struct intel_encoder *encoder,
 				  conn_state->tv.margins.left,
 				  conn_state->tv.margins.right);
 	intel_tv_scale_mode_vert(adjusted_mode, vdisplay,
-				 conn_state->tv.margins.top,
-				 conn_state->tv.margins.bottom);
+				 tv_conn_state->margins.top,
+				 tv_conn_state->margins.bottom);
 	drm_mode_set_crtcinfo(adjusted_mode, 0);
 	adjusted_mode->name[0] = '\0';
 
@@ -1316,8 +1394,10 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder,
 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
 	struct intel_tv *intel_tv = enc_to_tv(encoder);
+	const struct intel_tv_connector_state *tv_conn_state =
+		to_intel_tv_connector_state(conn_state);
 	const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
-	u32 tv_ctl;
+	u32 tv_ctl, tv_filter_ctl;
 	u32 scctl1, scctl2, scctl3;
 	int i, j;
 	const struct video_levels *video_levels;
@@ -1425,16 +1505,20 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder,
 	assert_pipe_disabled(dev_priv, intel_crtc->pipe);
 
 	/* Filter ctl must be set before TV_WIN_SIZE */
-	I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);
+	tv_filter_ctl = TV_AUTO_SCALE;
+	if (tv_conn_state->bypass_vfilter)
+		tv_filter_ctl |= TV_V_FILTER_BYPASS;
+	I915_WRITE(TV_FILTER_CTL_1, tv_filter_ctl);
+
 	xsize = tv_mode->hblank_start - tv_mode->hblank_end;
 	ysize = intel_tv_mode_vdisplay(tv_mode);
 
 	xpos = conn_state->tv.margins.left;
-	ypos = conn_state->tv.margins.top;
+	ypos = tv_conn_state->margins.top;
 	xsize -= (conn_state->tv.margins.left +
 		  conn_state->tv.margins.right);
-	ysize -= (conn_state->tv.margins.top +
-		  conn_state->tv.margins.bottom);
+	ysize -= (tv_conn_state->margins.top +
+		  tv_conn_state->margins.bottom);
 	I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos);
 	I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize);
 
@@ -1701,7 +1785,7 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = {
 	.destroy = intel_connector_destroy,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_duplicate_state = intel_tv_connector_duplicate_state,
 };
 
 static int intel_tv_atomic_check(struct drm_connector *connector,
-- 
2.18.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 15/15] drm/i915/tv: Filter out >1024 wide modes that would need vertical scaling on gen3
  2018-11-12 16:59 [PATCH 00/15] drm/i915: Fix TV encoder support Ville Syrjala
                   ` (14 preceding siblings ...)
  2018-11-12 16:59 ` [PATCH 14/15] drm/i915/tv: Fix >1024 modes on gen3 Ville Syrjala
@ 2018-11-12 17:00 ` Ville Syrjala
  2019-01-23 13:49   ` Imre Deak
  2018-11-12 17:16 ` ✗ Fi.CI.SPARSE: warning for drm/i915: Fix TV encoder support Patchwork
                   ` (8 subsequent siblings)
  24 siblings, 1 reply; 66+ messages in thread
From: Ville Syrjala @ 2018-11-12 17:00 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Since gen3 can't handle >1024 wide sources with vertical scaling
let's not advertize such modes in the mode list. Less tempetation
to the user to try out things that won't work.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_tv.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 7099d837e31a..89c537839273 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1738,6 +1738,7 @@ intel_tv_set_mode_type(struct drm_display_mode *mode,
 static int
 intel_tv_get_modes(struct drm_connector *connector)
 {
+	struct drm_i915_private *dev_priv = to_i915(connector->dev);
 	const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
 	int i, count = 0;
 
@@ -1750,6 +1751,11 @@ intel_tv_get_modes(struct drm_connector *connector)
 		    !tv_mode->component_only)
 			continue;
 
+		/* no vertical scaling with wide sources on gen3 */
+		if (IS_GEN3(dev_priv) && input->w > 1024 &&
+		    input->h > intel_tv_mode_vdisplay(tv_mode))
+			continue;
+
 		mode = drm_mode_create(connector->dev);
 		if (!mode)
 			continue;
-- 
2.18.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* ✗ Fi.CI.SPARSE: warning for drm/i915: Fix TV encoder support
  2018-11-12 16:59 [PATCH 00/15] drm/i915: Fix TV encoder support Ville Syrjala
                   ` (15 preceding siblings ...)
  2018-11-12 17:00 ` [PATCH 15/15] drm/i915/tv: Filter out >1024 wide modes that would need vertical scaling " Ville Syrjala
@ 2018-11-12 17:16 ` Patchwork
  2018-11-12 17:31 ` ✓ Fi.CI.BAT: success " Patchwork
                   ` (7 subsequent siblings)
  24 siblings, 0 replies; 66+ messages in thread
From: Patchwork @ 2018-11-12 17:16 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

== Series Details ==

Series: drm/i915: Fix TV encoder support
URL   : https://patchwork.freedesktop.org/series/52378/
State : warning

== Summary ==

$ dim sparse origin/drm-tip
Sparse version: v0.5.2
Commit: drm/vblank: Allow dynamic per-crtc max_vblank_count
Okay!

Commit: drm/i915: Don't try to use the hardware frame counter with i965gm TV output
Okay!

Commit: drm/i915/tv: Fix interlaced ysize calculation
Okay!

Commit: drm/i915/tv: Fix tv mode clocks
Okay!

Commit: drm/i915/tv: Store the TV oversampling factor in the TV mode
Okay!

Commit: drm/i915/tv: Use bools where appropriate
Okay!

Commit: drm/i915/tv: Nuke silly 0 initialzation of xpos/ypos
Okay!

Commit: drm/i915/tv: Deobfuscate preferred mode selection
Okay!

Commit: drm/i915/tv: Use drm_mode_set_name() to name TV modes
Okay!

Commit: drm/i915/tv: Make TV mode autoselection actually useable
Okay!

Commit: drm/i915/tv: Nuke reported_modes[]
Okay!

Commit: drm/i915/tv: Add 1080p30/50/60 TV modes
Okay!

Commit: drm/i915/tv: Generate better pipe timings for TV encoder
Okay!

Commit: drm/i915/tv: Fix >1024 modes on gen3
+drivers/gpu/drm/i915/intel_tv.c:889:28: warning: symbol 'intel_tv_connector_duplicate_state' was not declared. Should it be static?

Commit: drm/i915/tv: Filter out >1024 wide modes that would need vertical scaling on gen3
Okay!

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 66+ messages in thread

* ✓ Fi.CI.BAT: success for drm/i915: Fix TV encoder support
  2018-11-12 16:59 [PATCH 00/15] drm/i915: Fix TV encoder support Ville Syrjala
                   ` (16 preceding siblings ...)
  2018-11-12 17:16 ` ✗ Fi.CI.SPARSE: warning for drm/i915: Fix TV encoder support Patchwork
@ 2018-11-12 17:31 ` Patchwork
  2018-11-12 20:06 ` ✓ Fi.CI.IGT: " Patchwork
                   ` (6 subsequent siblings)
  24 siblings, 0 replies; 66+ messages in thread
From: Patchwork @ 2018-11-12 17:31 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

== Series Details ==

Series: drm/i915: Fix TV encoder support
URL   : https://patchwork.freedesktop.org/series/52378/
State : success

== Summary ==

= CI Bug Log - changes from CI_DRM_5126 -> Patchwork_10806 =

== Summary - SUCCESS ==

  No regressions found.

  External URL: https://patchwork.freedesktop.org/api/1.0/series/52378/revisions/1/mbox/

== Known issues ==

  Here are the changes found in Patchwork_10806 that come from known issues:

  === IGT changes ===

    ==== Issues hit ====

    igt@drv_selftest@live_hugepages:
      fi-skl-6700k2:      PASS -> INCOMPLETE (fdo#108716)

    igt@kms_chamelium@common-hpd-after-suspend:
      fi-skl-6700k2:      PASS -> TIMEOUT (fdo#108715)

    igt@kms_pipe_crc_basic@hang-read-crc-pipe-b:
      fi-skl-guc:         PASS -> FAIL (fdo#107362, fdo#103191)

    igt@kms_pipe_crc_basic@nonblocking-crc-pipe-a-frame-sequence:
      fi-byt-clapper:     PASS -> FAIL (fdo#107362, fdo#103191)

    
    ==== Possible fixes ====

    igt@kms_pipe_crc_basic@nonblocking-crc-pipe-b-frame-sequence:
      fi-byt-clapper:     FAIL (fdo#107362, fdo#103191) -> PASS

    
  fdo#103191 https://bugs.freedesktop.org/show_bug.cgi?id=103191
  fdo#107362 https://bugs.freedesktop.org/show_bug.cgi?id=107362
  fdo#108715 https://bugs.freedesktop.org/show_bug.cgi?id=108715
  fdo#108716 https://bugs.freedesktop.org/show_bug.cgi?id=108716


== Participating hosts (51 -> 45) ==

  Missing    (6): fi-kbl-soraka fi-ilk-m540 fi-byt-squawks fi-bsw-cyan fi-ctg-p8600 fi-icl-u 


== Build changes ==

    * Linux: CI_DRM_5126 -> Patchwork_10806

  CI_DRM_5126: 1465b00c43e237ca0064d75283ef305eea5549a4 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_4714: cab148ca3ec904a94d0cd43476cf7e1f8663f906 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  Patchwork_10806: 2864e57f2a77113596cb2fc7587599ceeabd84c6 @ git://anongit.freedesktop.org/gfx-ci/linux


== Linux commits ==

2864e57f2a77 drm/i915/tv: Filter out >1024 wide modes that would need vertical scaling on gen3
200b0f36ceeb drm/i915/tv: Fix >1024 modes on gen3
4f234aaaaad3 drm/i915/tv: Generate better pipe timings for TV encoder
d0e58280183f drm/i915/tv: Add 1080p30/50/60 TV modes
ca9f81153a5f drm/i915/tv: Nuke reported_modes[]
a8082ebc8b63 drm/i915/tv: Make TV mode autoselection actually useable
5e783b50de08 drm/i915/tv: Use drm_mode_set_name() to name TV modes
1f56a9e4b5d8 drm/i915/tv: Deobfuscate preferred mode selection
c2c301b2bb37 drm/i915/tv: Nuke silly 0 initialzation of xpos/ypos
bd508d96df3c drm/i915/tv: Use bools where appropriate
a6397daed382 drm/i915/tv: Store the TV oversampling factor in the TV mode
46d03afc55ce drm/i915/tv: Fix tv mode clocks
733a8c873db6 drm/i915/tv: Fix interlaced ysize calculation
905433c18486 drm/i915: Don't try to use the hardware frame counter with i965gm TV output
d5706da57c8c drm/vblank: Allow dynamic per-crtc max_vblank_count

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_10806/issues.html
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 66+ messages in thread

* ✓ Fi.CI.IGT: success for drm/i915: Fix TV encoder support
  2018-11-12 16:59 [PATCH 00/15] drm/i915: Fix TV encoder support Ville Syrjala
                   ` (17 preceding siblings ...)
  2018-11-12 17:31 ` ✓ Fi.CI.BAT: success " Patchwork
@ 2018-11-12 20:06 ` Patchwork
  2018-11-21 16:51 ` ✗ Fi.CI.BAT: failure for drm/i915: Fix TV encoder support (rev2) Patchwork
                   ` (5 subsequent siblings)
  24 siblings, 0 replies; 66+ messages in thread
From: Patchwork @ 2018-11-12 20:06 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

== Series Details ==

Series: drm/i915: Fix TV encoder support
URL   : https://patchwork.freedesktop.org/series/52378/
State : success

== Summary ==

= CI Bug Log - changes from CI_DRM_5126_full -> Patchwork_10806_full =

== Summary - WARNING ==

  Minor unknown changes coming with Patchwork_10806_full need to be verified
  manually.
  
  If you think the reported changes have nothing to do with the changes
  introduced in Patchwork_10806_full, please notify your bug team to allow them
  to document this new failure mode, which will reduce false positives in CI.

  

== Possible new issues ==

  Here are the unknown changes that may have been introduced in Patchwork_10806_full:

  === IGT changes ===

    ==== Warnings ====

    igt@kms_cursor_legacy@flip-vs-cursor-toggle:
      shard-snb:          SKIP -> PASS +1

    igt@tools_test@tools_test:
      shard-glk:          PASS -> SKIP

    
== Known issues ==

  Here are the changes found in Patchwork_10806_full that come from known issues:

  === IGT changes ===

    ==== Issues hit ====

    igt@gem_cpu_reloc@full:
      shard-skl:          PASS -> INCOMPLETE (fdo#108073)

    igt@gem_exec_schedule@pi-ringfull-bsd:
      shard-skl:          NOTRUN -> FAIL (fdo#103158)

    igt@gem_ppgtt@blt-vs-render-ctxn:
      shard-skl:          NOTRUN -> TIMEOUT (fdo#108039)

    igt@gem_userptr_blits@readonly-unsync:
      shard-skl:          NOTRUN -> INCOMPLETE (fdo#108074)

    igt@kms_busy@extended-modeset-hang-newfb-with-reset-render-c:
      shard-kbl:          NOTRUN -> DMESG-WARN (fdo#107956)

    igt@kms_color@pipe-c-degamma:
      shard-apl:          PASS -> FAIL (fdo#104782)

    igt@kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-move:
      shard-apl:          PASS -> FAIL (fdo#103167)

    igt@kms_frontbuffer_tracking@fbc-2p-primscrn-spr-indfb-draw-mmap-gtt:
      shard-glk:          PASS -> FAIL (fdo#103167)

    igt@kms_frontbuffer_tracking@fbc-stridechange:
      shard-skl:          NOTRUN -> FAIL (fdo#105683)

    igt@kms_frontbuffer_tracking@psr-1p-primscrn-spr-indfb-draw-pwrite:
      shard-skl:          NOTRUN -> FAIL (fdo#103167)

    igt@kms_plane@pixel-format-pipe-c-planes:
      shard-apl:          PASS -> FAIL (fdo#103166) +1

    igt@kms_plane_alpha_blend@pipe-a-alpha-transparant-fb:
      shard-apl:          NOTRUN -> FAIL (fdo#108145)

    igt@kms_setmode@basic:
      shard-apl:          PASS -> FAIL (fdo#99912)

    igt@pm_rpm@dpms-mode-unset-non-lpsp:
      shard-skl:          NOTRUN -> INCOMPLETE (fdo#107807)

    igt@pm_rpm@modeset-lpsp-stress-no-wait:
      shard-skl:          PASS -> INCOMPLETE (fdo#107807)

    
    ==== Possible fixes ====

    igt@drm_import_export@import-close-race-flink:
      shard-skl:          TIMEOUT (fdo#108667) -> PASS

    igt@gem_ppgtt@blt-vs-render-ctx0:
      shard-kbl:          INCOMPLETE (fdo#103665, fdo#106887, fdo#106023) -> PASS

    igt@kms_chv_cursor_fail@pipe-c-256x256-top-edge:
      shard-skl:          FAIL (fdo#104671) -> PASS

    igt@kms_color@pipe-c-ctm-blue-to-red:
      shard-skl:          FAIL (fdo#107201) -> PASS

    igt@kms_color@pipe-c-legacy-gamma:
      shard-apl:          FAIL (fdo#104782) -> PASS

    igt@kms_cursor_crc@cursor-128x128-random:
      shard-apl:          FAIL (fdo#103232) -> PASS +1

    igt@kms_cursor_crc@cursor-256x256-suspend:
      shard-skl:          INCOMPLETE (fdo#104108) -> PASS

    igt@kms_draw_crc@draw-method-xrgb2101010-mmap-gtt-xtiled:
      shard-skl:          FAIL (fdo#103184) -> PASS

    igt@kms_fbcon_fbt@fbc-suspend:
      shard-skl:          INCOMPLETE (fdo#104108, fdo#107773) -> PASS

    igt@kms_flip@flip-vs-expired-vblank-interruptible:
      shard-skl:          FAIL (fdo#105363) -> PASS

    igt@kms_frontbuffer_tracking@fbc-1p-primscrn-cur-indfb-draw-pwrite:
      shard-apl:          FAIL (fdo#103167) -> PASS

    igt@kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-fullscreen:
      shard-glk:          FAIL (fdo#103167) -> PASS

    igt@kms_frontbuffer_tracking@fbcpsr-1p-rte:
      shard-skl:          FAIL (fdo#105682, fdo#103167) -> PASS

    igt@kms_frontbuffer_tracking@psr-1p-primscrn-indfb-msflip-blt:
      shard-skl:          FAIL (fdo#103167) -> PASS +1

    igt@kms_plane@plane-position-covered-pipe-b-planes:
      shard-glk:          FAIL (fdo#103166) -> PASS +1

    igt@kms_plane_alpha_blend@pipe-a-coverage-7efc:
      shard-skl:          FAIL (fdo#108145, fdo#107815) -> PASS

    igt@kms_plane_multiple@atomic-pipe-b-tiling-y:
      shard-apl:          FAIL (fdo#103166) -> PASS

    igt@perf_pmu@busy-start-vcs0:
      shard-kbl:          DMESG-WARN (fdo#103558, fdo#105602) -> PASS

    igt@pm_rpm@drm-resources-equal:
      shard-skl:          INCOMPLETE (fdo#107807) -> PASS

    
    ==== Warnings ====

    igt@kms_busy@extended-pageflip-hang-newfb-render-b:
      shard-apl:          INCOMPLETE (fdo#103927) -> DMESG-WARN (fdo#107956)

    
  fdo#103158 https://bugs.freedesktop.org/show_bug.cgi?id=103158
  fdo#103166 https://bugs.freedesktop.org/show_bug.cgi?id=103166
  fdo#103167 https://bugs.freedesktop.org/show_bug.cgi?id=103167
  fdo#103184 https://bugs.freedesktop.org/show_bug.cgi?id=103184
  fdo#103232 https://bugs.freedesktop.org/show_bug.cgi?id=103232
  fdo#103558 https://bugs.freedesktop.org/show_bug.cgi?id=103558
  fdo#103665 https://bugs.freedesktop.org/show_bug.cgi?id=103665
  fdo#103927 https://bugs.freedesktop.org/show_bug.cgi?id=103927
  fdo#104108 https://bugs.freedesktop.org/show_bug.cgi?id=104108
  fdo#104671 https://bugs.freedesktop.org/show_bug.cgi?id=104671
  fdo#104782 https://bugs.freedesktop.org/show_bug.cgi?id=104782
  fdo#105363 https://bugs.freedesktop.org/show_bug.cgi?id=105363
  fdo#105602 https://bugs.freedesktop.org/show_bug.cgi?id=105602
  fdo#105682 https://bugs.freedesktop.org/show_bug.cgi?id=105682
  fdo#105683 https://bugs.freedesktop.org/show_bug.cgi?id=105683
  fdo#106023 https://bugs.freedesktop.org/show_bug.cgi?id=106023
  fdo#106887 https://bugs.freedesktop.org/show_bug.cgi?id=106887
  fdo#107201 https://bugs.freedesktop.org/show_bug.cgi?id=107201
  fdo#107773 https://bugs.freedesktop.org/show_bug.cgi?id=107773
  fdo#107807 https://bugs.freedesktop.org/show_bug.cgi?id=107807
  fdo#107815 https://bugs.freedesktop.org/show_bug.cgi?id=107815
  fdo#107956 https://bugs.freedesktop.org/show_bug.cgi?id=107956
  fdo#108039 https://bugs.freedesktop.org/show_bug.cgi?id=108039
  fdo#108073 https://bugs.freedesktop.org/show_bug.cgi?id=108073
  fdo#108074 https://bugs.freedesktop.org/show_bug.cgi?id=108074
  fdo#108145 https://bugs.freedesktop.org/show_bug.cgi?id=108145
  fdo#108667 https://bugs.freedesktop.org/show_bug.cgi?id=108667
  fdo#99912 https://bugs.freedesktop.org/show_bug.cgi?id=99912


== Participating hosts (6 -> 6) ==

  No changes in participating hosts


== Build changes ==

    * Linux: CI_DRM_5126 -> Patchwork_10806

  CI_DRM_5126: 1465b00c43e237ca0064d75283ef305eea5549a4 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_4714: cab148ca3ec904a94d0cd43476cf7e1f8663f906 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  Patchwork_10806: 2864e57f2a77113596cb2fc7587599ceeabd84c6 @ git://anongit.freedesktop.org/gfx-ci/linux
  piglit_4509: fdc5a4ca11124ab8413c7988896eec4c97336694 @ git://anongit.freedesktop.org/piglit

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_10806/shards.html
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 01/15] drm/vblank: Allow dynamic per-crtc max_vblank_count
  2018-11-12 16:59 ` [PATCH 01/15] drm/vblank: Allow dynamic per-crtc max_vblank_count Ville Syrjala
@ 2018-11-21  9:27     ` Daniel Vetter
  2018-11-27 18:20     ` Ville Syrjala
  1 sibling, 0 replies; 66+ messages in thread
From: Daniel Vetter @ 2018-11-21  9:27 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, dri-devel, stable, Inki Dae, Daniel Vetter

On Mon, Nov 12, 2018 at 06:59:45PM +0200, Ville Syrjala wrote:
> From: Ville Syrj�l� <ville.syrjala@linux.intel.com>
> 
> On i965gm we need to adjust max_vblank_count dynamically
> depending on whether the TV encoder is used or not. To
> that end add a per-crtc max_vblank_count that takes
> precedence over its device wide counterpart. The driver
> can now call drm_crtc_set_max_vblank_count() to configure
> the per-crtc value before calling drm_vblank_on().
> 
> Also looks like there was some discussion about exynos needing
> similar treatment.
> 
> Cc: stable@vger.kernel.org
> Cc: Inki Dae <inki.dae@samsung.com>
> Cc: Daniel Vetter <daniel@ffwll.ch>
> Signed-off-by: Ville Syrj�l� <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/drm_vblank.c | 39 ++++++++++++++++++++++++++++++++----
>  include/drm/drm_vblank.h     |  8 ++++++++
>  2 files changed, 43 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
> index 98e091175921..c3abbdca8aba 100644
> --- a/drivers/gpu/drm/drm_vblank.c
> +++ b/drivers/gpu/drm/drm_vblank.c
> @@ -105,13 +105,20 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe,
>  	write_sequnlock(&vblank->seqlock);
>  }
>  
> +static u32 drm_max_vblank_count(struct drm_device *dev, unsigned int pipe)
> +{
> +	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> +
> +	return vblank->max_vblank_count ?: dev->max_vblank_count;
> +}
> +
>  /*
>   * "No hw counter" fallback implementation of .get_vblank_counter() hook,
>   * if there is no useable hardware frame counter available.
>   */
>  static u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe)
>  {
> -	WARN_ON_ONCE(dev->max_vblank_count != 0);
> +	WARN_ON_ONCE(drm_max_vblank_count(dev, pipe) != 0);
>  	return 0;
>  }
>  
> @@ -198,6 +205,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
>  	ktime_t t_vblank;
>  	int count = DRM_TIMESTAMP_MAXRETRIES;
>  	int framedur_ns = vblank->framedur_ns;
> +	u32 max_vblank_count = drm_max_vblank_count(dev, pipe);
>  
>  	/*
>  	 * Interrupts were disabled prior to this call, so deal with counter
> @@ -216,9 +224,9 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
>  		rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq);
>  	} while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0);
>  
> -	if (dev->max_vblank_count != 0) {
> +	if (max_vblank_count) {
>  		/* trust the hw counter when it's around */
> -		diff = (cur_vblank - vblank->last) & dev->max_vblank_count;
> +		diff = (cur_vblank - vblank->last) & max_vblank_count;
>  	} else if (rc && framedur_ns) {
>  		u64 diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time));
>  
> @@ -258,7 +266,8 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
>  		      pipe, vblank->count, diff, cur_vblank, vblank->last);
>  
>  	if (diff == 0) {
> -		WARN_ON_ONCE(cur_vblank != vblank->last);
> +		WARN_ON_ONCE(max_vblank_count &&
> +			     cur_vblank != vblank->last);

Unrelated bugfix for this warning? Should be a separate patch I think, or
I'm missing something.

>  		return;
>  	}
>  
> @@ -1204,6 +1213,28 @@ void drm_crtc_vblank_reset(struct drm_crtc *crtc)
>  }
>  EXPORT_SYMBOL(drm_crtc_vblank_reset);
>  
> +/**
> + * drm_crtc_set_max_vblank_count - configure the hw max vblank counter value
> + * @crtc: CRTC in question
> + * @max_vblank_count: max hardware vblank counter value
> + *
> + * Update the maximum hardware vblank counter value for @crtc. Useful
> + * for hardware where the operation of the hardware vblank counter
> + * depends on the active display configuration.
> + *
> + * If used, must be called before drm_vblank_on().

I think we should check this at runtime with a WARN_ON. Plus make the
comment here a bit clearer that this is indeed for runtime adjusting of
the max_vblank_count, in cases where that depends upon the connected
outputs.

> + */
> +void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc,
> +				   u32 max_vblank_count)
> +{
> +	struct drm_device *dev = crtc->dev;
> +	unsigned int pipe = drm_crtc_index(crtc);
> +	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> +
> +	vblank->max_vblank_count = max_vblank_count;
> +}
> +EXPORT_SYMBOL(drm_crtc_set_max_vblank_count);
> +
>  /**
>   * drm_crtc_vblank_on - enable vblank events on a CRTC
>   * @crtc: CRTC in question
> diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h
> index 6ad9630d4f48..ecb2cf9913e2 100644
> --- a/include/drm/drm_vblank.h
> +++ b/include/drm/drm_vblank.h
> @@ -128,6 +128,12 @@ struct drm_vblank_crtc {
>  	 * @last: Protected by &drm_device.vbl_lock, used for wraparound handling.
>  	 */
>  	u32 last;
> +	/**
> +	 * @max_vblank_count: Maximum value of the hardware vblank counter.
> +	 * If non-zero this takes precedence over &drm_device.max_vblank_count
> +	 * for this crtc. Otherwise &drm_device.max_vblank_count is used.
> +	 */

I'd add "This should be set by calling drm_crtc_set_max_vblank_count()."

And please also add a note to the kerneldoc of drm_driver.max_vblank_count
pointing at &drm_vblank_crtc.max_vblank_count for per-crtc limits.

Aside from the nits lgtm. I think I'll skip looking at the TV out stuff
though ...

Cheers, Daniel

> +	u32 max_vblank_count;
>  	/**
>  	 * @inmodeset: Tracks whether the vblank is disabled due to a modeset.
>  	 * For legacy driver bit 2 additionally tracks whether an additional
> @@ -206,4 +212,6 @@ bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
>  void drm_calc_timestamping_constants(struct drm_crtc *crtc,
>  				     const struct drm_display_mode *mode);
>  wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc);
> +void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc,
> +				   u32 max_vblank_count);
>  #endif
> -- 
> 2.18.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 01/15] drm/vblank: Allow dynamic per-crtc max_vblank_count
@ 2018-11-21  9:27     ` Daniel Vetter
  0 siblings, 0 replies; 66+ messages in thread
From: Daniel Vetter @ 2018-11-21  9:27 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: Inki Dae, intel-gfx, stable, dri-devel

On Mon, Nov 12, 2018 at 06:59:45PM +0200, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> On i965gm we need to adjust max_vblank_count dynamically
> depending on whether the TV encoder is used or not. To
> that end add a per-crtc max_vblank_count that takes
> precedence over its device wide counterpart. The driver
> can now call drm_crtc_set_max_vblank_count() to configure
> the per-crtc value before calling drm_vblank_on().
> 
> Also looks like there was some discussion about exynos needing
> similar treatment.
> 
> Cc: stable@vger.kernel.org
> Cc: Inki Dae <inki.dae@samsung.com>
> Cc: Daniel Vetter <daniel@ffwll.ch>
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/drm_vblank.c | 39 ++++++++++++++++++++++++++++++++----
>  include/drm/drm_vblank.h     |  8 ++++++++
>  2 files changed, 43 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
> index 98e091175921..c3abbdca8aba 100644
> --- a/drivers/gpu/drm/drm_vblank.c
> +++ b/drivers/gpu/drm/drm_vblank.c
> @@ -105,13 +105,20 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe,
>  	write_sequnlock(&vblank->seqlock);
>  }
>  
> +static u32 drm_max_vblank_count(struct drm_device *dev, unsigned int pipe)
> +{
> +	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> +
> +	return vblank->max_vblank_count ?: dev->max_vblank_count;
> +}
> +
>  /*
>   * "No hw counter" fallback implementation of .get_vblank_counter() hook,
>   * if there is no useable hardware frame counter available.
>   */
>  static u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe)
>  {
> -	WARN_ON_ONCE(dev->max_vblank_count != 0);
> +	WARN_ON_ONCE(drm_max_vblank_count(dev, pipe) != 0);
>  	return 0;
>  }
>  
> @@ -198,6 +205,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
>  	ktime_t t_vblank;
>  	int count = DRM_TIMESTAMP_MAXRETRIES;
>  	int framedur_ns = vblank->framedur_ns;
> +	u32 max_vblank_count = drm_max_vblank_count(dev, pipe);
>  
>  	/*
>  	 * Interrupts were disabled prior to this call, so deal with counter
> @@ -216,9 +224,9 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
>  		rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq);
>  	} while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0);
>  
> -	if (dev->max_vblank_count != 0) {
> +	if (max_vblank_count) {
>  		/* trust the hw counter when it's around */
> -		diff = (cur_vblank - vblank->last) & dev->max_vblank_count;
> +		diff = (cur_vblank - vblank->last) & max_vblank_count;
>  	} else if (rc && framedur_ns) {
>  		u64 diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time));
>  
> @@ -258,7 +266,8 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
>  		      pipe, vblank->count, diff, cur_vblank, vblank->last);
>  
>  	if (diff == 0) {
> -		WARN_ON_ONCE(cur_vblank != vblank->last);
> +		WARN_ON_ONCE(max_vblank_count &&
> +			     cur_vblank != vblank->last);

Unrelated bugfix for this warning? Should be a separate patch I think, or
I'm missing something.

>  		return;
>  	}
>  
> @@ -1204,6 +1213,28 @@ void drm_crtc_vblank_reset(struct drm_crtc *crtc)
>  }
>  EXPORT_SYMBOL(drm_crtc_vblank_reset);
>  
> +/**
> + * drm_crtc_set_max_vblank_count - configure the hw max vblank counter value
> + * @crtc: CRTC in question
> + * @max_vblank_count: max hardware vblank counter value
> + *
> + * Update the maximum hardware vblank counter value for @crtc. Useful
> + * for hardware where the operation of the hardware vblank counter
> + * depends on the active display configuration.
> + *
> + * If used, must be called before drm_vblank_on().

I think we should check this at runtime with a WARN_ON. Plus make the
comment here a bit clearer that this is indeed for runtime adjusting of
the max_vblank_count, in cases where that depends upon the connected
outputs.

> + */
> +void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc,
> +				   u32 max_vblank_count)
> +{
> +	struct drm_device *dev = crtc->dev;
> +	unsigned int pipe = drm_crtc_index(crtc);
> +	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> +
> +	vblank->max_vblank_count = max_vblank_count;
> +}
> +EXPORT_SYMBOL(drm_crtc_set_max_vblank_count);
> +
>  /**
>   * drm_crtc_vblank_on - enable vblank events on a CRTC
>   * @crtc: CRTC in question
> diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h
> index 6ad9630d4f48..ecb2cf9913e2 100644
> --- a/include/drm/drm_vblank.h
> +++ b/include/drm/drm_vblank.h
> @@ -128,6 +128,12 @@ struct drm_vblank_crtc {
>  	 * @last: Protected by &drm_device.vbl_lock, used for wraparound handling.
>  	 */
>  	u32 last;
> +	/**
> +	 * @max_vblank_count: Maximum value of the hardware vblank counter.
> +	 * If non-zero this takes precedence over &drm_device.max_vblank_count
> +	 * for this crtc. Otherwise &drm_device.max_vblank_count is used.
> +	 */

I'd add "This should be set by calling drm_crtc_set_max_vblank_count()."

And please also add a note to the kerneldoc of drm_driver.max_vblank_count
pointing at &drm_vblank_crtc.max_vblank_count for per-crtc limits.

Aside from the nits lgtm. I think I'll skip looking at the TV out stuff
though ...

Cheers, Daniel

> +	u32 max_vblank_count;
>  	/**
>  	 * @inmodeset: Tracks whether the vblank is disabled due to a modeset.
>  	 * For legacy driver bit 2 additionally tracks whether an additional
> @@ -206,4 +212,6 @@ bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
>  void drm_calc_timestamping_constants(struct drm_crtc *crtc,
>  				     const struct drm_display_mode *mode);
>  wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc);
> +void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc,
> +				   u32 max_vblank_count);
>  #endif
> -- 
> 2.18.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 01/15] drm/vblank: Allow dynamic per-crtc max_vblank_count
  2018-11-21  9:27     ` Daniel Vetter
@ 2018-11-21 11:37       ` Ville Syrjälä
  -1 siblings, 0 replies; 66+ messages in thread
From: Ville Syrjälä @ 2018-11-21 11:37 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, dri-devel, stable, Inki Dae

On Wed, Nov 21, 2018 at 10:27:27AM +0100, Daniel Vetter wrote:
> On Mon, Nov 12, 2018 at 06:59:45PM +0200, Ville Syrjala wrote:
> > From: Ville Syrj�l� <ville.syrjala@linux.intel.com>
> > 
> > On i965gm we need to adjust max_vblank_count dynamically
> > depending on whether the TV encoder is used or not. To
> > that end add a per-crtc max_vblank_count that takes
> > precedence over its device wide counterpart. The driver
> > can now call drm_crtc_set_max_vblank_count() to configure
> > the per-crtc value before calling drm_vblank_on().
> > 
> > Also looks like there was some discussion about exynos needing
> > similar treatment.
> > 
> > Cc: stable@vger.kernel.org
> > Cc: Inki Dae <inki.dae@samsung.com>
> > Cc: Daniel Vetter <daniel@ffwll.ch>
> > Signed-off-by: Ville Syrj�l� <ville.syrjala@linux.intel.com>
> > ---
> >  drivers/gpu/drm/drm_vblank.c | 39 ++++++++++++++++++++++++++++++++----
> >  include/drm/drm_vblank.h     |  8 ++++++++
> >  2 files changed, 43 insertions(+), 4 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
> > index 98e091175921..c3abbdca8aba 100644
> > --- a/drivers/gpu/drm/drm_vblank.c
> > +++ b/drivers/gpu/drm/drm_vblank.c
> > @@ -105,13 +105,20 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe,
> >  	write_sequnlock(&vblank->seqlock);
> >  }
> >  
> > +static u32 drm_max_vblank_count(struct drm_device *dev, unsigned int pipe)
> > +{
> > +	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> > +
> > +	return vblank->max_vblank_count ?: dev->max_vblank_count;
> > +}
> > +
> >  /*
> >   * "No hw counter" fallback implementation of .get_vblank_counter() hook,
> >   * if there is no useable hardware frame counter available.
> >   */
> >  static u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe)
> >  {
> > -	WARN_ON_ONCE(dev->max_vblank_count != 0);
> > +	WARN_ON_ONCE(drm_max_vblank_count(dev, pipe) != 0);
> >  	return 0;
> >  }
> >  
> > @@ -198,6 +205,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> >  	ktime_t t_vblank;
> >  	int count = DRM_TIMESTAMP_MAXRETRIES;
> >  	int framedur_ns = vblank->framedur_ns;
> > +	u32 max_vblank_count = drm_max_vblank_count(dev, pipe);
> >  
> >  	/*
> >  	 * Interrupts were disabled prior to this call, so deal with counter
> > @@ -216,9 +224,9 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> >  		rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq);
> >  	} while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0);
> >  
> > -	if (dev->max_vblank_count != 0) {
> > +	if (max_vblank_count) {
> >  		/* trust the hw counter when it's around */
> > -		diff = (cur_vblank - vblank->last) & dev->max_vblank_count;
> > +		diff = (cur_vblank - vblank->last) & max_vblank_count;
> >  	} else if (rc && framedur_ns) {
> >  		u64 diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time));
> >  
> > @@ -258,7 +266,8 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> >  		      pipe, vblank->count, diff, cur_vblank, vblank->last);
> >  
> >  	if (diff == 0) {
> > -		WARN_ON_ONCE(cur_vblank != vblank->last);
> > +		WARN_ON_ONCE(max_vblank_count &&
> > +			     cur_vblank != vblank->last);
> 
> Unrelated bugfix for this warning? Should be a separate patch I think, or
> I'm missing something.

Ah, yeah this was due to a quirk of i965gm hardware. The hw counter
does work until the exact point when we enable TV encoder. Thus we
will get non-zero values up to that point, and since the TV encoder
isn't yet throttling the pipe it presumably runs at the oversample
clock so our timestamp based estimates can give us a diff==0 even
though the pipe did indeed pass a vblank already. I forgot to
note this in the commit message.

I think we can handle this three ways:
1. do what I do here and just let the mismatch slip through
2. force i915_get_vblank_counter() to return 0 always when the
   TV encoder is going to be used
3. don't call drm_crtc_set_max_vblank_count() before drm_vblank_on()
   and instead delay it until just before we enable the TV encoder

I think option 3 is overly complicated to consider seriously. So
option 1 or option 2 is what I think we should do. For whatever
reason I went with option 1 here, but maybe option 2 is better
since it would be all contained within i915...

> 
> >  		return;
> >  	}
> >  
> > @@ -1204,6 +1213,28 @@ void drm_crtc_vblank_reset(struct drm_crtc *crtc)
> >  }
> >  EXPORT_SYMBOL(drm_crtc_vblank_reset);
> >  
> > +/**
> > + * drm_crtc_set_max_vblank_count - configure the hw max vblank counter value
> > + * @crtc: CRTC in question
> > + * @max_vblank_count: max hardware vblank counter value
> > + *
> > + * Update the maximum hardware vblank counter value for @crtc. Useful
> > + * for hardware where the operation of the hardware vblank counter
> > + * depends on the active display configuration.
> > + *
> > + * If used, must be called before drm_vblank_on().
> 
> I think we should check this at runtime with a WARN_ON. Plus make the
> comment here a bit clearer that this is indeed for runtime adjusting of
> the max_vblank_count, in cases where that depends upon the connected
> outputs.

Sure. I'll try to pimp up the docs a bit.

> 
> > + */
> > +void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc,
> > +				   u32 max_vblank_count)
> > +{
> > +	struct drm_device *dev = crtc->dev;
> > +	unsigned int pipe = drm_crtc_index(crtc);
> > +	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> > +
> > +	vblank->max_vblank_count = max_vblank_count;
> > +}
> > +EXPORT_SYMBOL(drm_crtc_set_max_vblank_count);
> > +
> >  /**
> >   * drm_crtc_vblank_on - enable vblank events on a CRTC
> >   * @crtc: CRTC in question
> > diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h
> > index 6ad9630d4f48..ecb2cf9913e2 100644
> > --- a/include/drm/drm_vblank.h
> > +++ b/include/drm/drm_vblank.h
> > @@ -128,6 +128,12 @@ struct drm_vblank_crtc {
> >  	 * @last: Protected by &drm_device.vbl_lock, used for wraparound handling.
> >  	 */
> >  	u32 last;
> > +	/**
> > +	 * @max_vblank_count: Maximum value of the hardware vblank counter.
> > +	 * If non-zero this takes precedence over &drm_device.max_vblank_count
> > +	 * for this crtc. Otherwise &drm_device.max_vblank_count is used.
> > +	 */
> 
> I'd add "This should be set by calling drm_crtc_set_max_vblank_count()."
> 
> And please also add a note to the kerneldoc of drm_driver.max_vblank_count
> pointing at &drm_vblank_crtc.max_vblank_count for per-crtc limits.

Ack.

> 
> Aside from the nits lgtm. I think I'll skip looking at the TV out stuff
> though ...

:)

-- 
Ville Syrj�l�
Intel

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 01/15] drm/vblank: Allow dynamic per-crtc max_vblank_count
@ 2018-11-21 11:37       ` Ville Syrjälä
  0 siblings, 0 replies; 66+ messages in thread
From: Ville Syrjälä @ 2018-11-21 11:37 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, stable, dri-devel

On Wed, Nov 21, 2018 at 10:27:27AM +0100, Daniel Vetter wrote:
> On Mon, Nov 12, 2018 at 06:59:45PM +0200, Ville Syrjala wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > On i965gm we need to adjust max_vblank_count dynamically
> > depending on whether the TV encoder is used or not. To
> > that end add a per-crtc max_vblank_count that takes
> > precedence over its device wide counterpart. The driver
> > can now call drm_crtc_set_max_vblank_count() to configure
> > the per-crtc value before calling drm_vblank_on().
> > 
> > Also looks like there was some discussion about exynos needing
> > similar treatment.
> > 
> > Cc: stable@vger.kernel.org
> > Cc: Inki Dae <inki.dae@samsung.com>
> > Cc: Daniel Vetter <daniel@ffwll.ch>
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >  drivers/gpu/drm/drm_vblank.c | 39 ++++++++++++++++++++++++++++++++----
> >  include/drm/drm_vblank.h     |  8 ++++++++
> >  2 files changed, 43 insertions(+), 4 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
> > index 98e091175921..c3abbdca8aba 100644
> > --- a/drivers/gpu/drm/drm_vblank.c
> > +++ b/drivers/gpu/drm/drm_vblank.c
> > @@ -105,13 +105,20 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe,
> >  	write_sequnlock(&vblank->seqlock);
> >  }
> >  
> > +static u32 drm_max_vblank_count(struct drm_device *dev, unsigned int pipe)
> > +{
> > +	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> > +
> > +	return vblank->max_vblank_count ?: dev->max_vblank_count;
> > +}
> > +
> >  /*
> >   * "No hw counter" fallback implementation of .get_vblank_counter() hook,
> >   * if there is no useable hardware frame counter available.
> >   */
> >  static u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe)
> >  {
> > -	WARN_ON_ONCE(dev->max_vblank_count != 0);
> > +	WARN_ON_ONCE(drm_max_vblank_count(dev, pipe) != 0);
> >  	return 0;
> >  }
> >  
> > @@ -198,6 +205,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> >  	ktime_t t_vblank;
> >  	int count = DRM_TIMESTAMP_MAXRETRIES;
> >  	int framedur_ns = vblank->framedur_ns;
> > +	u32 max_vblank_count = drm_max_vblank_count(dev, pipe);
> >  
> >  	/*
> >  	 * Interrupts were disabled prior to this call, so deal with counter
> > @@ -216,9 +224,9 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> >  		rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq);
> >  	} while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0);
> >  
> > -	if (dev->max_vblank_count != 0) {
> > +	if (max_vblank_count) {
> >  		/* trust the hw counter when it's around */
> > -		diff = (cur_vblank - vblank->last) & dev->max_vblank_count;
> > +		diff = (cur_vblank - vblank->last) & max_vblank_count;
> >  	} else if (rc && framedur_ns) {
> >  		u64 diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time));
> >  
> > @@ -258,7 +266,8 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> >  		      pipe, vblank->count, diff, cur_vblank, vblank->last);
> >  
> >  	if (diff == 0) {
> > -		WARN_ON_ONCE(cur_vblank != vblank->last);
> > +		WARN_ON_ONCE(max_vblank_count &&
> > +			     cur_vblank != vblank->last);
> 
> Unrelated bugfix for this warning? Should be a separate patch I think, or
> I'm missing something.

Ah, yeah this was due to a quirk of i965gm hardware. The hw counter
does work until the exact point when we enable TV encoder. Thus we
will get non-zero values up to that point, and since the TV encoder
isn't yet throttling the pipe it presumably runs at the oversample
clock so our timestamp based estimates can give us a diff==0 even
though the pipe did indeed pass a vblank already. I forgot to
note this in the commit message.

I think we can handle this three ways:
1. do what I do here and just let the mismatch slip through
2. force i915_get_vblank_counter() to return 0 always when the
   TV encoder is going to be used
3. don't call drm_crtc_set_max_vblank_count() before drm_vblank_on()
   and instead delay it until just before we enable the TV encoder

I think option 3 is overly complicated to consider seriously. So
option 1 or option 2 is what I think we should do. For whatever
reason I went with option 1 here, but maybe option 2 is better
since it would be all contained within i915...

> 
> >  		return;
> >  	}
> >  
> > @@ -1204,6 +1213,28 @@ void drm_crtc_vblank_reset(struct drm_crtc *crtc)
> >  }
> >  EXPORT_SYMBOL(drm_crtc_vblank_reset);
> >  
> > +/**
> > + * drm_crtc_set_max_vblank_count - configure the hw max vblank counter value
> > + * @crtc: CRTC in question
> > + * @max_vblank_count: max hardware vblank counter value
> > + *
> > + * Update the maximum hardware vblank counter value for @crtc. Useful
> > + * for hardware where the operation of the hardware vblank counter
> > + * depends on the active display configuration.
> > + *
> > + * If used, must be called before drm_vblank_on().
> 
> I think we should check this at runtime with a WARN_ON. Plus make the
> comment here a bit clearer that this is indeed for runtime adjusting of
> the max_vblank_count, in cases where that depends upon the connected
> outputs.

Sure. I'll try to pimp up the docs a bit.

> 
> > + */
> > +void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc,
> > +				   u32 max_vblank_count)
> > +{
> > +	struct drm_device *dev = crtc->dev;
> > +	unsigned int pipe = drm_crtc_index(crtc);
> > +	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> > +
> > +	vblank->max_vblank_count = max_vblank_count;
> > +}
> > +EXPORT_SYMBOL(drm_crtc_set_max_vblank_count);
> > +
> >  /**
> >   * drm_crtc_vblank_on - enable vblank events on a CRTC
> >   * @crtc: CRTC in question
> > diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h
> > index 6ad9630d4f48..ecb2cf9913e2 100644
> > --- a/include/drm/drm_vblank.h
> > +++ b/include/drm/drm_vblank.h
> > @@ -128,6 +128,12 @@ struct drm_vblank_crtc {
> >  	 * @last: Protected by &drm_device.vbl_lock, used for wraparound handling.
> >  	 */
> >  	u32 last;
> > +	/**
> > +	 * @max_vblank_count: Maximum value of the hardware vblank counter.
> > +	 * If non-zero this takes precedence over &drm_device.max_vblank_count
> > +	 * for this crtc. Otherwise &drm_device.max_vblank_count is used.
> > +	 */
> 
> I'd add "This should be set by calling drm_crtc_set_max_vblank_count()."
> 
> And please also add a note to the kerneldoc of drm_driver.max_vblank_count
> pointing at &drm_vblank_crtc.max_vblank_count for per-crtc limits.

Ack.

> 
> Aside from the nits lgtm. I think I'll skip looking at the TV out stuff
> though ...

:)

-- 
Ville Syrjälä
Intel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 01/15] drm/vblank: Allow dynamic per-crtc max_vblank_count
  2018-11-21 11:37       ` Ville Syrjälä
@ 2018-11-21 15:19         ` Daniel Vetter
  -1 siblings, 0 replies; 66+ messages in thread
From: Daniel Vetter @ 2018-11-21 15:19 UTC (permalink / raw)
  To: Ville Syrjälä
  Cc: Daniel Vetter, intel-gfx, dri-devel, stable, Inki Dae

On Wed, Nov 21, 2018 at 01:37:51PM +0200, Ville Syrj�l� wrote:
> On Wed, Nov 21, 2018 at 10:27:27AM +0100, Daniel Vetter wrote:
> > On Mon, Nov 12, 2018 at 06:59:45PM +0200, Ville Syrjala wrote:
> > > From: Ville Syrj�l� <ville.syrjala@linux.intel.com>
> > > 
> > > On i965gm we need to adjust max_vblank_count dynamically
> > > depending on whether the TV encoder is used or not. To
> > > that end add a per-crtc max_vblank_count that takes
> > > precedence over its device wide counterpart. The driver
> > > can now call drm_crtc_set_max_vblank_count() to configure
> > > the per-crtc value before calling drm_vblank_on().
> > > 
> > > Also looks like there was some discussion about exynos needing
> > > similar treatment.
> > > 
> > > Cc: stable@vger.kernel.org
> > > Cc: Inki Dae <inki.dae@samsung.com>
> > > Cc: Daniel Vetter <daniel@ffwll.ch>
> > > Signed-off-by: Ville Syrj�l� <ville.syrjala@linux.intel.com>
> > > ---
> > >  drivers/gpu/drm/drm_vblank.c | 39 ++++++++++++++++++++++++++++++++----
> > >  include/drm/drm_vblank.h     |  8 ++++++++
> > >  2 files changed, 43 insertions(+), 4 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
> > > index 98e091175921..c3abbdca8aba 100644
> > > --- a/drivers/gpu/drm/drm_vblank.c
> > > +++ b/drivers/gpu/drm/drm_vblank.c
> > > @@ -105,13 +105,20 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe,
> > >  	write_sequnlock(&vblank->seqlock);
> > >  }
> > >  
> > > +static u32 drm_max_vblank_count(struct drm_device *dev, unsigned int pipe)
> > > +{
> > > +	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> > > +
> > > +	return vblank->max_vblank_count ?: dev->max_vblank_count;
> > > +}
> > > +
> > >  /*
> > >   * "No hw counter" fallback implementation of .get_vblank_counter() hook,
> > >   * if there is no useable hardware frame counter available.
> > >   */
> > >  static u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe)
> > >  {
> > > -	WARN_ON_ONCE(dev->max_vblank_count != 0);
> > > +	WARN_ON_ONCE(drm_max_vblank_count(dev, pipe) != 0);
> > >  	return 0;
> > >  }
> > >  
> > > @@ -198,6 +205,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > >  	ktime_t t_vblank;
> > >  	int count = DRM_TIMESTAMP_MAXRETRIES;
> > >  	int framedur_ns = vblank->framedur_ns;
> > > +	u32 max_vblank_count = drm_max_vblank_count(dev, pipe);
> > >  
> > >  	/*
> > >  	 * Interrupts were disabled prior to this call, so deal with counter
> > > @@ -216,9 +224,9 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > >  		rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq);
> > >  	} while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0);
> > >  
> > > -	if (dev->max_vblank_count != 0) {
> > > +	if (max_vblank_count) {
> > >  		/* trust the hw counter when it's around */
> > > -		diff = (cur_vblank - vblank->last) & dev->max_vblank_count;
> > > +		diff = (cur_vblank - vblank->last) & max_vblank_count;
> > >  	} else if (rc && framedur_ns) {
> > >  		u64 diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time));
> > >  
> > > @@ -258,7 +266,8 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > >  		      pipe, vblank->count, diff, cur_vblank, vblank->last);
> > >  
> > >  	if (diff == 0) {
> > > -		WARN_ON_ONCE(cur_vblank != vblank->last);
> > > +		WARN_ON_ONCE(max_vblank_count &&
> > > +			     cur_vblank != vblank->last);
> > 
> > Unrelated bugfix for this warning? Should be a separate patch I think, or
> > I'm missing something.
> 
> Ah, yeah this was due to a quirk of i965gm hardware. The hw counter
> does work until the exact point when we enable TV encoder. Thus we
> will get non-zero values up to that point, and since the TV encoder
> isn't yet throttling the pipe it presumably runs at the oversample
> clock so our timestamp based estimates can give us a diff==0 even
> though the pipe did indeed pass a vblank already. I forgot to
> note this in the commit message.
> 
> I think we can handle this three ways:
> 1. do what I do here and just let the mismatch slip through
> 2. force i915_get_vblank_counter() to return 0 always when the
>    TV encoder is going to be used
> 3. don't call drm_crtc_set_max_vblank_count() before drm_vblank_on()
>    and instead delay it until just before we enable the TV encoder
> 
> I think option 3 is overly complicated to consider seriously. So
> option 1 or option 2 is what I think we should do. For whatever
> reason I went with option 1 here, but maybe option 2 is better
> since it would be all contained within i915...

Delay drm_crtc_vblank_on until the vblank is stable? That seems like the
semantically clean solution to me, instead of hacking around in core code
when drivers leak garbage out ...

-Daniel


> > 
> > >  		return;
> > >  	}
> > >  
> > > @@ -1204,6 +1213,28 @@ void drm_crtc_vblank_reset(struct drm_crtc *crtc)
> > >  }
> > >  EXPORT_SYMBOL(drm_crtc_vblank_reset);
> > >  
> > > +/**
> > > + * drm_crtc_set_max_vblank_count - configure the hw max vblank counter value
> > > + * @crtc: CRTC in question
> > > + * @max_vblank_count: max hardware vblank counter value
> > > + *
> > > + * Update the maximum hardware vblank counter value for @crtc. Useful
> > > + * for hardware where the operation of the hardware vblank counter
> > > + * depends on the active display configuration.
> > > + *
> > > + * If used, must be called before drm_vblank_on().
> > 
> > I think we should check this at runtime with a WARN_ON. Plus make the
> > comment here a bit clearer that this is indeed for runtime adjusting of
> > the max_vblank_count, in cases where that depends upon the connected
> > outputs.
> 
> Sure. I'll try to pimp up the docs a bit.
> 
> > 
> > > + */
> > > +void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc,
> > > +				   u32 max_vblank_count)
> > > +{
> > > +	struct drm_device *dev = crtc->dev;
> > > +	unsigned int pipe = drm_crtc_index(crtc);
> > > +	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> > > +
> > > +	vblank->max_vblank_count = max_vblank_count;
> > > +}
> > > +EXPORT_SYMBOL(drm_crtc_set_max_vblank_count);
> > > +
> > >  /**
> > >   * drm_crtc_vblank_on - enable vblank events on a CRTC
> > >   * @crtc: CRTC in question
> > > diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h
> > > index 6ad9630d4f48..ecb2cf9913e2 100644
> > > --- a/include/drm/drm_vblank.h
> > > +++ b/include/drm/drm_vblank.h
> > > @@ -128,6 +128,12 @@ struct drm_vblank_crtc {
> > >  	 * @last: Protected by &drm_device.vbl_lock, used for wraparound handling.
> > >  	 */
> > >  	u32 last;
> > > +	/**
> > > +	 * @max_vblank_count: Maximum value of the hardware vblank counter.
> > > +	 * If non-zero this takes precedence over &drm_device.max_vblank_count
> > > +	 * for this crtc. Otherwise &drm_device.max_vblank_count is used.
> > > +	 */
> > 
> > I'd add "This should be set by calling drm_crtc_set_max_vblank_count()."
> > 
> > And please also add a note to the kerneldoc of drm_driver.max_vblank_count
> > pointing at &drm_vblank_crtc.max_vblank_count for per-crtc limits.
> 
> Ack.
> 
> > 
> > Aside from the nits lgtm. I think I'll skip looking at the TV out stuff
> > though ...
> 
> :)
> 
> -- 
> Ville Syrj�l�
> Intel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 01/15] drm/vblank: Allow dynamic per-crtc max_vblank_count
@ 2018-11-21 15:19         ` Daniel Vetter
  0 siblings, 0 replies; 66+ messages in thread
From: Daniel Vetter @ 2018-11-21 15:19 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: stable, intel-gfx, dri-devel

On Wed, Nov 21, 2018 at 01:37:51PM +0200, Ville Syrjälä wrote:
> On Wed, Nov 21, 2018 at 10:27:27AM +0100, Daniel Vetter wrote:
> > On Mon, Nov 12, 2018 at 06:59:45PM +0200, Ville Syrjala wrote:
> > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > 
> > > On i965gm we need to adjust max_vblank_count dynamically
> > > depending on whether the TV encoder is used or not. To
> > > that end add a per-crtc max_vblank_count that takes
> > > precedence over its device wide counterpart. The driver
> > > can now call drm_crtc_set_max_vblank_count() to configure
> > > the per-crtc value before calling drm_vblank_on().
> > > 
> > > Also looks like there was some discussion about exynos needing
> > > similar treatment.
> > > 
> > > Cc: stable@vger.kernel.org
> > > Cc: Inki Dae <inki.dae@samsung.com>
> > > Cc: Daniel Vetter <daniel@ffwll.ch>
> > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > ---
> > >  drivers/gpu/drm/drm_vblank.c | 39 ++++++++++++++++++++++++++++++++----
> > >  include/drm/drm_vblank.h     |  8 ++++++++
> > >  2 files changed, 43 insertions(+), 4 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
> > > index 98e091175921..c3abbdca8aba 100644
> > > --- a/drivers/gpu/drm/drm_vblank.c
> > > +++ b/drivers/gpu/drm/drm_vblank.c
> > > @@ -105,13 +105,20 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe,
> > >  	write_sequnlock(&vblank->seqlock);
> > >  }
> > >  
> > > +static u32 drm_max_vblank_count(struct drm_device *dev, unsigned int pipe)
> > > +{
> > > +	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> > > +
> > > +	return vblank->max_vblank_count ?: dev->max_vblank_count;
> > > +}
> > > +
> > >  /*
> > >   * "No hw counter" fallback implementation of .get_vblank_counter() hook,
> > >   * if there is no useable hardware frame counter available.
> > >   */
> > >  static u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe)
> > >  {
> > > -	WARN_ON_ONCE(dev->max_vblank_count != 0);
> > > +	WARN_ON_ONCE(drm_max_vblank_count(dev, pipe) != 0);
> > >  	return 0;
> > >  }
> > >  
> > > @@ -198,6 +205,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > >  	ktime_t t_vblank;
> > >  	int count = DRM_TIMESTAMP_MAXRETRIES;
> > >  	int framedur_ns = vblank->framedur_ns;
> > > +	u32 max_vblank_count = drm_max_vblank_count(dev, pipe);
> > >  
> > >  	/*
> > >  	 * Interrupts were disabled prior to this call, so deal with counter
> > > @@ -216,9 +224,9 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > >  		rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq);
> > >  	} while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0);
> > >  
> > > -	if (dev->max_vblank_count != 0) {
> > > +	if (max_vblank_count) {
> > >  		/* trust the hw counter when it's around */
> > > -		diff = (cur_vblank - vblank->last) & dev->max_vblank_count;
> > > +		diff = (cur_vblank - vblank->last) & max_vblank_count;
> > >  	} else if (rc && framedur_ns) {
> > >  		u64 diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time));
> > >  
> > > @@ -258,7 +266,8 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > >  		      pipe, vblank->count, diff, cur_vblank, vblank->last);
> > >  
> > >  	if (diff == 0) {
> > > -		WARN_ON_ONCE(cur_vblank != vblank->last);
> > > +		WARN_ON_ONCE(max_vblank_count &&
> > > +			     cur_vblank != vblank->last);
> > 
> > Unrelated bugfix for this warning? Should be a separate patch I think, or
> > I'm missing something.
> 
> Ah, yeah this was due to a quirk of i965gm hardware. The hw counter
> does work until the exact point when we enable TV encoder. Thus we
> will get non-zero values up to that point, and since the TV encoder
> isn't yet throttling the pipe it presumably runs at the oversample
> clock so our timestamp based estimates can give us a diff==0 even
> though the pipe did indeed pass a vblank already. I forgot to
> note this in the commit message.
> 
> I think we can handle this three ways:
> 1. do what I do here and just let the mismatch slip through
> 2. force i915_get_vblank_counter() to return 0 always when the
>    TV encoder is going to be used
> 3. don't call drm_crtc_set_max_vblank_count() before drm_vblank_on()
>    and instead delay it until just before we enable the TV encoder
> 
> I think option 3 is overly complicated to consider seriously. So
> option 1 or option 2 is what I think we should do. For whatever
> reason I went with option 1 here, but maybe option 2 is better
> since it would be all contained within i915...

Delay drm_crtc_vblank_on until the vblank is stable? That seems like the
semantically clean solution to me, instead of hacking around in core code
when drivers leak garbage out ...

-Daniel


> > 
> > >  		return;
> > >  	}
> > >  
> > > @@ -1204,6 +1213,28 @@ void drm_crtc_vblank_reset(struct drm_crtc *crtc)
> > >  }
> > >  EXPORT_SYMBOL(drm_crtc_vblank_reset);
> > >  
> > > +/**
> > > + * drm_crtc_set_max_vblank_count - configure the hw max vblank counter value
> > > + * @crtc: CRTC in question
> > > + * @max_vblank_count: max hardware vblank counter value
> > > + *
> > > + * Update the maximum hardware vblank counter value for @crtc. Useful
> > > + * for hardware where the operation of the hardware vblank counter
> > > + * depends on the active display configuration.
> > > + *
> > > + * If used, must be called before drm_vblank_on().
> > 
> > I think we should check this at runtime with a WARN_ON. Plus make the
> > comment here a bit clearer that this is indeed for runtime adjusting of
> > the max_vblank_count, in cases where that depends upon the connected
> > outputs.
> 
> Sure. I'll try to pimp up the docs a bit.
> 
> > 
> > > + */
> > > +void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc,
> > > +				   u32 max_vblank_count)
> > > +{
> > > +	struct drm_device *dev = crtc->dev;
> > > +	unsigned int pipe = drm_crtc_index(crtc);
> > > +	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> > > +
> > > +	vblank->max_vblank_count = max_vblank_count;
> > > +}
> > > +EXPORT_SYMBOL(drm_crtc_set_max_vblank_count);
> > > +
> > >  /**
> > >   * drm_crtc_vblank_on - enable vblank events on a CRTC
> > >   * @crtc: CRTC in question
> > > diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h
> > > index 6ad9630d4f48..ecb2cf9913e2 100644
> > > --- a/include/drm/drm_vblank.h
> > > +++ b/include/drm/drm_vblank.h
> > > @@ -128,6 +128,12 @@ struct drm_vblank_crtc {
> > >  	 * @last: Protected by &drm_device.vbl_lock, used for wraparound handling.
> > >  	 */
> > >  	u32 last;
> > > +	/**
> > > +	 * @max_vblank_count: Maximum value of the hardware vblank counter.
> > > +	 * If non-zero this takes precedence over &drm_device.max_vblank_count
> > > +	 * for this crtc. Otherwise &drm_device.max_vblank_count is used.
> > > +	 */
> > 
> > I'd add "This should be set by calling drm_crtc_set_max_vblank_count()."
> > 
> > And please also add a note to the kerneldoc of drm_driver.max_vblank_count
> > pointing at &drm_vblank_crtc.max_vblank_count for per-crtc limits.
> 
> Ack.
> 
> > 
> > Aside from the nits lgtm. I think I'll skip looking at the TV out stuff
> > though ...
> 
> :)
> 
> -- 
> Ville Syrjälä
> Intel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 01/15] drm/vblank: Allow dynamic per-crtc max_vblank_count
  2018-11-21 15:19         ` Daniel Vetter
@ 2018-11-21 16:16           ` Ville Syrjälä
  -1 siblings, 0 replies; 66+ messages in thread
From: Ville Syrjälä @ 2018-11-21 16:16 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, dri-devel, stable, Inki Dae

On Wed, Nov 21, 2018 at 04:19:36PM +0100, Daniel Vetter wrote:
> On Wed, Nov 21, 2018 at 01:37:51PM +0200, Ville Syrj�l� wrote:
> > On Wed, Nov 21, 2018 at 10:27:27AM +0100, Daniel Vetter wrote:
> > > On Mon, Nov 12, 2018 at 06:59:45PM +0200, Ville Syrjala wrote:
> > > > From: Ville Syrj�l� <ville.syrjala@linux.intel.com>
> > > > 
> > > > On i965gm we need to adjust max_vblank_count dynamically
> > > > depending on whether the TV encoder is used or not. To
> > > > that end add a per-crtc max_vblank_count that takes
> > > > precedence over its device wide counterpart. The driver
> > > > can now call drm_crtc_set_max_vblank_count() to configure
> > > > the per-crtc value before calling drm_vblank_on().
> > > > 
> > > > Also looks like there was some discussion about exynos needing
> > > > similar treatment.
> > > > 
> > > > Cc: stable@vger.kernel.org
> > > > Cc: Inki Dae <inki.dae@samsung.com>
> > > > Cc: Daniel Vetter <daniel@ffwll.ch>
> > > > Signed-off-by: Ville Syrj�l� <ville.syrjala@linux.intel.com>
> > > > ---
> > > >  drivers/gpu/drm/drm_vblank.c | 39 ++++++++++++++++++++++++++++++++----
> > > >  include/drm/drm_vblank.h     |  8 ++++++++
> > > >  2 files changed, 43 insertions(+), 4 deletions(-)
> > > > 
> > > > diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
> > > > index 98e091175921..c3abbdca8aba 100644
> > > > --- a/drivers/gpu/drm/drm_vblank.c
> > > > +++ b/drivers/gpu/drm/drm_vblank.c
> > > > @@ -105,13 +105,20 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe,
> > > >  	write_sequnlock(&vblank->seqlock);
> > > >  }
> > > >  
> > > > +static u32 drm_max_vblank_count(struct drm_device *dev, unsigned int pipe)
> > > > +{
> > > > +	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> > > > +
> > > > +	return vblank->max_vblank_count ?: dev->max_vblank_count;
> > > > +}
> > > > +
> > > >  /*
> > > >   * "No hw counter" fallback implementation of .get_vblank_counter() hook,
> > > >   * if there is no useable hardware frame counter available.
> > > >   */
> > > >  static u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe)
> > > >  {
> > > > -	WARN_ON_ONCE(dev->max_vblank_count != 0);
> > > > +	WARN_ON_ONCE(drm_max_vblank_count(dev, pipe) != 0);
> > > >  	return 0;
> > > >  }
> > > >  
> > > > @@ -198,6 +205,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > > >  	ktime_t t_vblank;
> > > >  	int count = DRM_TIMESTAMP_MAXRETRIES;
> > > >  	int framedur_ns = vblank->framedur_ns;
> > > > +	u32 max_vblank_count = drm_max_vblank_count(dev, pipe);
> > > >  
> > > >  	/*
> > > >  	 * Interrupts were disabled prior to this call, so deal with counter
> > > > @@ -216,9 +224,9 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > > >  		rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq);
> > > >  	} while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0);
> > > >  
> > > > -	if (dev->max_vblank_count != 0) {
> > > > +	if (max_vblank_count) {
> > > >  		/* trust the hw counter when it's around */
> > > > -		diff = (cur_vblank - vblank->last) & dev->max_vblank_count;
> > > > +		diff = (cur_vblank - vblank->last) & max_vblank_count;
> > > >  	} else if (rc && framedur_ns) {
> > > >  		u64 diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time));
> > > >  
> > > > @@ -258,7 +266,8 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > > >  		      pipe, vblank->count, diff, cur_vblank, vblank->last);
> > > >  
> > > >  	if (diff == 0) {
> > > > -		WARN_ON_ONCE(cur_vblank != vblank->last);
> > > > +		WARN_ON_ONCE(max_vblank_count &&
> > > > +			     cur_vblank != vblank->last);
> > > 
> > > Unrelated bugfix for this warning? Should be a separate patch I think, or
> > > I'm missing something.
> > 
> > Ah, yeah this was due to a quirk of i965gm hardware. The hw counter
> > does work until the exact point when we enable TV encoder. Thus we
> > will get non-zero values up to that point, and since the TV encoder
> > isn't yet throttling the pipe it presumably runs at the oversample
> > clock so our timestamp based estimates can give us a diff==0 even
> > though the pipe did indeed pass a vblank already. I forgot to
> > note this in the commit message.
> > 
> > I think we can handle this three ways:
> > 1. do what I do here and just let the mismatch slip through
> > 2. force i915_get_vblank_counter() to return 0 always when the
> >    TV encoder is going to be used
> > 3. don't call drm_crtc_set_max_vblank_count() before drm_vblank_on()
> >    and instead delay it until just before we enable the TV encoder
> > 
> > I think option 3 is overly complicated to consider seriously. So
> > option 1 or option 2 is what I think we should do. For whatever
> > reason I went with option 1 here, but maybe option 2 is better
> > since it would be all contained within i915...
> 
> Delay drm_crtc_vblank_on until the vblank is stable? That seems like the
> semantically clean solution to me, instead of hacking around in core code
> when drivers leak garbage out ...

We need a vblank wait before turning on the TV encoder. Chicken vs. egg.

-- 
Ville Syrj�l�
Intel

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 01/15] drm/vblank: Allow dynamic per-crtc max_vblank_count
@ 2018-11-21 16:16           ` Ville Syrjälä
  0 siblings, 0 replies; 66+ messages in thread
From: Ville Syrjälä @ 2018-11-21 16:16 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, dri-devel, stable, Inki Dae

On Wed, Nov 21, 2018 at 04:19:36PM +0100, Daniel Vetter wrote:
> On Wed, Nov 21, 2018 at 01:37:51PM +0200, Ville Syrjälä wrote:
> > On Wed, Nov 21, 2018 at 10:27:27AM +0100, Daniel Vetter wrote:
> > > On Mon, Nov 12, 2018 at 06:59:45PM +0200, Ville Syrjala wrote:
> > > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > 
> > > > On i965gm we need to adjust max_vblank_count dynamically
> > > > depending on whether the TV encoder is used or not. To
> > > > that end add a per-crtc max_vblank_count that takes
> > > > precedence over its device wide counterpart. The driver
> > > > can now call drm_crtc_set_max_vblank_count() to configure
> > > > the per-crtc value before calling drm_vblank_on().
> > > > 
> > > > Also looks like there was some discussion about exynos needing
> > > > similar treatment.
> > > > 
> > > > Cc: stable@vger.kernel.org
> > > > Cc: Inki Dae <inki.dae@samsung.com>
> > > > Cc: Daniel Vetter <daniel@ffwll.ch>
> > > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > ---
> > > >  drivers/gpu/drm/drm_vblank.c | 39 ++++++++++++++++++++++++++++++++----
> > > >  include/drm/drm_vblank.h     |  8 ++++++++
> > > >  2 files changed, 43 insertions(+), 4 deletions(-)
> > > > 
> > > > diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
> > > > index 98e091175921..c3abbdca8aba 100644
> > > > --- a/drivers/gpu/drm/drm_vblank.c
> > > > +++ b/drivers/gpu/drm/drm_vblank.c
> > > > @@ -105,13 +105,20 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe,
> > > >  	write_sequnlock(&vblank->seqlock);
> > > >  }
> > > >  
> > > > +static u32 drm_max_vblank_count(struct drm_device *dev, unsigned int pipe)
> > > > +{
> > > > +	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> > > > +
> > > > +	return vblank->max_vblank_count ?: dev->max_vblank_count;
> > > > +}
> > > > +
> > > >  /*
> > > >   * "No hw counter" fallback implementation of .get_vblank_counter() hook,
> > > >   * if there is no useable hardware frame counter available.
> > > >   */
> > > >  static u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe)
> > > >  {
> > > > -	WARN_ON_ONCE(dev->max_vblank_count != 0);
> > > > +	WARN_ON_ONCE(drm_max_vblank_count(dev, pipe) != 0);
> > > >  	return 0;
> > > >  }
> > > >  
> > > > @@ -198,6 +205,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > > >  	ktime_t t_vblank;
> > > >  	int count = DRM_TIMESTAMP_MAXRETRIES;
> > > >  	int framedur_ns = vblank->framedur_ns;
> > > > +	u32 max_vblank_count = drm_max_vblank_count(dev, pipe);
> > > >  
> > > >  	/*
> > > >  	 * Interrupts were disabled prior to this call, so deal with counter
> > > > @@ -216,9 +224,9 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > > >  		rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq);
> > > >  	} while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0);
> > > >  
> > > > -	if (dev->max_vblank_count != 0) {
> > > > +	if (max_vblank_count) {
> > > >  		/* trust the hw counter when it's around */
> > > > -		diff = (cur_vblank - vblank->last) & dev->max_vblank_count;
> > > > +		diff = (cur_vblank - vblank->last) & max_vblank_count;
> > > >  	} else if (rc && framedur_ns) {
> > > >  		u64 diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time));
> > > >  
> > > > @@ -258,7 +266,8 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > > >  		      pipe, vblank->count, diff, cur_vblank, vblank->last);
> > > >  
> > > >  	if (diff == 0) {
> > > > -		WARN_ON_ONCE(cur_vblank != vblank->last);
> > > > +		WARN_ON_ONCE(max_vblank_count &&
> > > > +			     cur_vblank != vblank->last);
> > > 
> > > Unrelated bugfix for this warning? Should be a separate patch I think, or
> > > I'm missing something.
> > 
> > Ah, yeah this was due to a quirk of i965gm hardware. The hw counter
> > does work until the exact point when we enable TV encoder. Thus we
> > will get non-zero values up to that point, and since the TV encoder
> > isn't yet throttling the pipe it presumably runs at the oversample
> > clock so our timestamp based estimates can give us a diff==0 even
> > though the pipe did indeed pass a vblank already. I forgot to
> > note this in the commit message.
> > 
> > I think we can handle this three ways:
> > 1. do what I do here and just let the mismatch slip through
> > 2. force i915_get_vblank_counter() to return 0 always when the
> >    TV encoder is going to be used
> > 3. don't call drm_crtc_set_max_vblank_count() before drm_vblank_on()
> >    and instead delay it until just before we enable the TV encoder
> > 
> > I think option 3 is overly complicated to consider seriously. So
> > option 1 or option 2 is what I think we should do. For whatever
> > reason I went with option 1 here, but maybe option 2 is better
> > since it would be all contained within i915...
> 
> Delay drm_crtc_vblank_on until the vblank is stable? That seems like the
> semantically clean solution to me, instead of hacking around in core code
> when drivers leak garbage out ...

We need a vblank wait before turning on the TV encoder. Chicken vs. egg.

-- 
Ville Syrjälä
Intel

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 01/15] drm/vblank: Allow dynamic per-crtc max_vblank_count
  2018-11-21 16:16           ` Ville Syrjälä
@ 2018-11-21 16:22             ` Daniel Vetter
  -1 siblings, 0 replies; 66+ messages in thread
From: Daniel Vetter @ 2018-11-21 16:22 UTC (permalink / raw)
  To: Syrjala, Ville; +Cc: intel-gfx, dri-devel, stable, Inki Dae

On Wed, Nov 21, 2018 at 5:16 PM Ville Syrjälä
<ville.syrjala@linux.intel.com> wrote:
>
> On Wed, Nov 21, 2018 at 04:19:36PM +0100, Daniel Vetter wrote:
> > On Wed, Nov 21, 2018 at 01:37:51PM +0200, Ville Syrjälä wrote:
> > > On Wed, Nov 21, 2018 at 10:27:27AM +0100, Daniel Vetter wrote:
> > > > On Mon, Nov 12, 2018 at 06:59:45PM +0200, Ville Syrjala wrote:
> > > > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > >
> > > > > On i965gm we need to adjust max_vblank_count dynamically
> > > > > depending on whether the TV encoder is used or not. To
> > > > > that end add a per-crtc max_vblank_count that takes
> > > > > precedence over its device wide counterpart. The driver
> > > > > can now call drm_crtc_set_max_vblank_count() to configure
> > > > > the per-crtc value before calling drm_vblank_on().
> > > > >
> > > > > Also looks like there was some discussion about exynos needing
> > > > > similar treatment.
> > > > >
> > > > > Cc: stable@vger.kernel.org
> > > > > Cc: Inki Dae <inki.dae@samsung.com>
> > > > > Cc: Daniel Vetter <daniel@ffwll.ch>
> > > > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > > ---
> > > > >  drivers/gpu/drm/drm_vblank.c | 39 ++++++++++++++++++++++++++++++++----
> > > > >  include/drm/drm_vblank.h     |  8 ++++++++
> > > > >  2 files changed, 43 insertions(+), 4 deletions(-)
> > > > >
> > > > > diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
> > > > > index 98e091175921..c3abbdca8aba 100644
> > > > > --- a/drivers/gpu/drm/drm_vblank.c
> > > > > +++ b/drivers/gpu/drm/drm_vblank.c
> > > > > @@ -105,13 +105,20 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe,
> > > > >         write_sequnlock(&vblank->seqlock);
> > > > >  }
> > > > >
> > > > > +static u32 drm_max_vblank_count(struct drm_device *dev, unsigned int pipe)
> > > > > +{
> > > > > +       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> > > > > +
> > > > > +       return vblank->max_vblank_count ?: dev->max_vblank_count;
> > > > > +}
> > > > > +
> > > > >  /*
> > > > >   * "No hw counter" fallback implementation of .get_vblank_counter() hook,
> > > > >   * if there is no useable hardware frame counter available.
> > > > >   */
> > > > >  static u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe)
> > > > >  {
> > > > > -       WARN_ON_ONCE(dev->max_vblank_count != 0);
> > > > > +       WARN_ON_ONCE(drm_max_vblank_count(dev, pipe) != 0);
> > > > >         return 0;
> > > > >  }
> > > > >
> > > > > @@ -198,6 +205,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > > > >         ktime_t t_vblank;
> > > > >         int count = DRM_TIMESTAMP_MAXRETRIES;
> > > > >         int framedur_ns = vblank->framedur_ns;
> > > > > +       u32 max_vblank_count = drm_max_vblank_count(dev, pipe);
> > > > >
> > > > >         /*
> > > > >          * Interrupts were disabled prior to this call, so deal with counter
> > > > > @@ -216,9 +224,9 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > > > >                 rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq);
> > > > >         } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0);
> > > > >
> > > > > -       if (dev->max_vblank_count != 0) {
> > > > > +       if (max_vblank_count) {
> > > > >                 /* trust the hw counter when it's around */
> > > > > -               diff = (cur_vblank - vblank->last) & dev->max_vblank_count;
> > > > > +               diff = (cur_vblank - vblank->last) & max_vblank_count;
> > > > >         } else if (rc && framedur_ns) {
> > > > >                 u64 diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time));
> > > > >
> > > > > @@ -258,7 +266,8 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > > > >                       pipe, vblank->count, diff, cur_vblank, vblank->last);
> > > > >
> > > > >         if (diff == 0) {
> > > > > -               WARN_ON_ONCE(cur_vblank != vblank->last);
> > > > > +               WARN_ON_ONCE(max_vblank_count &&
> > > > > +                            cur_vblank != vblank->last);
> > > >
> > > > Unrelated bugfix for this warning? Should be a separate patch I think, or
> > > > I'm missing something.
> > >
> > > Ah, yeah this was due to a quirk of i965gm hardware. The hw counter
> > > does work until the exact point when we enable TV encoder. Thus we
> > > will get non-zero values up to that point, and since the TV encoder
> > > isn't yet throttling the pipe it presumably runs at the oversample
> > > clock so our timestamp based estimates can give us a diff==0 even
> > > though the pipe did indeed pass a vblank already. I forgot to
> > > note this in the commit message.
> > >
> > > I think we can handle this three ways:
> > > 1. do what I do here and just let the mismatch slip through
> > > 2. force i915_get_vblank_counter() to return 0 always when the
> > >    TV encoder is going to be used
> > > 3. don't call drm_crtc_set_max_vblank_count() before drm_vblank_on()
> > >    and instead delay it until just before we enable the TV encoder
> > >
> > > I think option 3 is overly complicated to consider seriously. So
> > > option 1 or option 2 is what I think we should do. For whatever
> > > reason I went with option 1 here, but maybe option 2 is better
> > > since it would be all contained within i915...
> >
> > Delay drm_crtc_vblank_on until the vblank is stable? That seems like the
> > semantically clean solution to me, instead of hacking around in core code
> > when drivers leak garbage out ...
>
> We need a vblank wait before turning on the TV encoder. Chicken vs. egg.

Gah.

Ok I think I think having the hack here makes sense then, but split
out as a separate patch with separate justification. It's a bit a
tricky thing that deserves to be higlighted (and easier way to found
the explanation with git blame in case it's ever needed).
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 01/15] drm/vblank: Allow dynamic per-crtc max_vblank_count
@ 2018-11-21 16:22             ` Daniel Vetter
  0 siblings, 0 replies; 66+ messages in thread
From: Daniel Vetter @ 2018-11-21 16:22 UTC (permalink / raw)
  To: Syrjala, Ville; +Cc: intel-gfx, stable, dri-devel

On Wed, Nov 21, 2018 at 5:16 PM Ville Syrjälä
<ville.syrjala@linux.intel.com> wrote:
>
> On Wed, Nov 21, 2018 at 04:19:36PM +0100, Daniel Vetter wrote:
> > On Wed, Nov 21, 2018 at 01:37:51PM +0200, Ville Syrjälä wrote:
> > > On Wed, Nov 21, 2018 at 10:27:27AM +0100, Daniel Vetter wrote:
> > > > On Mon, Nov 12, 2018 at 06:59:45PM +0200, Ville Syrjala wrote:
> > > > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > >
> > > > > On i965gm we need to adjust max_vblank_count dynamically
> > > > > depending on whether the TV encoder is used or not. To
> > > > > that end add a per-crtc max_vblank_count that takes
> > > > > precedence over its device wide counterpart. The driver
> > > > > can now call drm_crtc_set_max_vblank_count() to configure
> > > > > the per-crtc value before calling drm_vblank_on().
> > > > >
> > > > > Also looks like there was some discussion about exynos needing
> > > > > similar treatment.
> > > > >
> > > > > Cc: stable@vger.kernel.org
> > > > > Cc: Inki Dae <inki.dae@samsung.com>
> > > > > Cc: Daniel Vetter <daniel@ffwll.ch>
> > > > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > > ---
> > > > >  drivers/gpu/drm/drm_vblank.c | 39 ++++++++++++++++++++++++++++++++----
> > > > >  include/drm/drm_vblank.h     |  8 ++++++++
> > > > >  2 files changed, 43 insertions(+), 4 deletions(-)
> > > > >
> > > > > diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
> > > > > index 98e091175921..c3abbdca8aba 100644
> > > > > --- a/drivers/gpu/drm/drm_vblank.c
> > > > > +++ b/drivers/gpu/drm/drm_vblank.c
> > > > > @@ -105,13 +105,20 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe,
> > > > >         write_sequnlock(&vblank->seqlock);
> > > > >  }
> > > > >
> > > > > +static u32 drm_max_vblank_count(struct drm_device *dev, unsigned int pipe)
> > > > > +{
> > > > > +       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> > > > > +
> > > > > +       return vblank->max_vblank_count ?: dev->max_vblank_count;
> > > > > +}
> > > > > +
> > > > >  /*
> > > > >   * "No hw counter" fallback implementation of .get_vblank_counter() hook,
> > > > >   * if there is no useable hardware frame counter available.
> > > > >   */
> > > > >  static u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe)
> > > > >  {
> > > > > -       WARN_ON_ONCE(dev->max_vblank_count != 0);
> > > > > +       WARN_ON_ONCE(drm_max_vblank_count(dev, pipe) != 0);
> > > > >         return 0;
> > > > >  }
> > > > >
> > > > > @@ -198,6 +205,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > > > >         ktime_t t_vblank;
> > > > >         int count = DRM_TIMESTAMP_MAXRETRIES;
> > > > >         int framedur_ns = vblank->framedur_ns;
> > > > > +       u32 max_vblank_count = drm_max_vblank_count(dev, pipe);
> > > > >
> > > > >         /*
> > > > >          * Interrupts were disabled prior to this call, so deal with counter
> > > > > @@ -216,9 +224,9 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > > > >                 rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq);
> > > > >         } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0);
> > > > >
> > > > > -       if (dev->max_vblank_count != 0) {
> > > > > +       if (max_vblank_count) {
> > > > >                 /* trust the hw counter when it's around */
> > > > > -               diff = (cur_vblank - vblank->last) & dev->max_vblank_count;
> > > > > +               diff = (cur_vblank - vblank->last) & max_vblank_count;
> > > > >         } else if (rc && framedur_ns) {
> > > > >                 u64 diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time));
> > > > >
> > > > > @@ -258,7 +266,8 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > > > >                       pipe, vblank->count, diff, cur_vblank, vblank->last);
> > > > >
> > > > >         if (diff == 0) {
> > > > > -               WARN_ON_ONCE(cur_vblank != vblank->last);
> > > > > +               WARN_ON_ONCE(max_vblank_count &&
> > > > > +                            cur_vblank != vblank->last);
> > > >
> > > > Unrelated bugfix for this warning? Should be a separate patch I think, or
> > > > I'm missing something.
> > >
> > > Ah, yeah this was due to a quirk of i965gm hardware. The hw counter
> > > does work until the exact point when we enable TV encoder. Thus we
> > > will get non-zero values up to that point, and since the TV encoder
> > > isn't yet throttling the pipe it presumably runs at the oversample
> > > clock so our timestamp based estimates can give us a diff==0 even
> > > though the pipe did indeed pass a vblank already. I forgot to
> > > note this in the commit message.
> > >
> > > I think we can handle this three ways:
> > > 1. do what I do here and just let the mismatch slip through
> > > 2. force i915_get_vblank_counter() to return 0 always when the
> > >    TV encoder is going to be used
> > > 3. don't call drm_crtc_set_max_vblank_count() before drm_vblank_on()
> > >    and instead delay it until just before we enable the TV encoder
> > >
> > > I think option 3 is overly complicated to consider seriously. So
> > > option 1 or option 2 is what I think we should do. For whatever
> > > reason I went with option 1 here, but maybe option 2 is better
> > > since it would be all contained within i915...
> >
> > Delay drm_crtc_vblank_on until the vblank is stable? That seems like the
> > semantically clean solution to me, instead of hacking around in core code
> > when drivers leak garbage out ...
>
> We need a vblank wait before turning on the TV encoder. Chicken vs. egg.

Gah.

Ok I think I think having the hack here makes sense then, but split
out as a separate patch with separate justification. It's a bit a
tricky thing that deserves to be higlighted (and easier way to found
the explanation with git blame in case it's ever needed).
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 01/15] drm/vblank: Allow dynamic per-crtc max_vblank_count
  2018-11-21 16:22             ` Daniel Vetter
@ 2018-11-21 16:46               ` Ville Syrjälä
  -1 siblings, 0 replies; 66+ messages in thread
From: Ville Syrjälä @ 2018-11-21 16:46 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, dri-devel, stable, Inki Dae

On Wed, Nov 21, 2018 at 05:22:49PM +0100, Daniel Vetter wrote:
> On Wed, Nov 21, 2018 at 5:16 PM Ville Syrj�l�
> <ville.syrjala@linux.intel.com> wrote:
> >
> > On Wed, Nov 21, 2018 at 04:19:36PM +0100, Daniel Vetter wrote:
> > > On Wed, Nov 21, 2018 at 01:37:51PM +0200, Ville Syrj�l� wrote:
> > > > On Wed, Nov 21, 2018 at 10:27:27AM +0100, Daniel Vetter wrote:
> > > > > On Mon, Nov 12, 2018 at 06:59:45PM +0200, Ville Syrjala wrote:
> > > > > > From: Ville Syrj�l� <ville.syrjala@linux.intel.com>
> > > > > >
> > > > > > On i965gm we need to adjust max_vblank_count dynamically
> > > > > > depending on whether the TV encoder is used or not. To
> > > > > > that end add a per-crtc max_vblank_count that takes
> > > > > > precedence over its device wide counterpart. The driver
> > > > > > can now call drm_crtc_set_max_vblank_count() to configure
> > > > > > the per-crtc value before calling drm_vblank_on().
> > > > > >
> > > > > > Also looks like there was some discussion about exynos needing
> > > > > > similar treatment.
> > > > > >
> > > > > > Cc: stable@vger.kernel.org
> > > > > > Cc: Inki Dae <inki.dae@samsung.com>
> > > > > > Cc: Daniel Vetter <daniel@ffwll.ch>
> > > > > > Signed-off-by: Ville Syrj�l� <ville.syrjala@linux.intel.com>
> > > > > > ---
> > > > > >  drivers/gpu/drm/drm_vblank.c | 39 ++++++++++++++++++++++++++++++++----
> > > > > >  include/drm/drm_vblank.h     |  8 ++++++++
> > > > > >  2 files changed, 43 insertions(+), 4 deletions(-)
> > > > > >
> > > > > > diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
> > > > > > index 98e091175921..c3abbdca8aba 100644
> > > > > > --- a/drivers/gpu/drm/drm_vblank.c
> > > > > > +++ b/drivers/gpu/drm/drm_vblank.c
> > > > > > @@ -105,13 +105,20 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe,
> > > > > >         write_sequnlock(&vblank->seqlock);
> > > > > >  }
> > > > > >
> > > > > > +static u32 drm_max_vblank_count(struct drm_device *dev, unsigned int pipe)
> > > > > > +{
> > > > > > +       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> > > > > > +
> > > > > > +       return vblank->max_vblank_count ?: dev->max_vblank_count;
> > > > > > +}
> > > > > > +
> > > > > >  /*
> > > > > >   * "No hw counter" fallback implementation of .get_vblank_counter() hook,
> > > > > >   * if there is no useable hardware frame counter available.
> > > > > >   */
> > > > > >  static u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe)
> > > > > >  {
> > > > > > -       WARN_ON_ONCE(dev->max_vblank_count != 0);
> > > > > > +       WARN_ON_ONCE(drm_max_vblank_count(dev, pipe) != 0);
> > > > > >         return 0;
> > > > > >  }
> > > > > >
> > > > > > @@ -198,6 +205,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > > > > >         ktime_t t_vblank;
> > > > > >         int count = DRM_TIMESTAMP_MAXRETRIES;
> > > > > >         int framedur_ns = vblank->framedur_ns;
> > > > > > +       u32 max_vblank_count = drm_max_vblank_count(dev, pipe);
> > > > > >
> > > > > >         /*
> > > > > >          * Interrupts were disabled prior to this call, so deal with counter
> > > > > > @@ -216,9 +224,9 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > > > > >                 rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq);
> > > > > >         } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0);
> > > > > >
> > > > > > -       if (dev->max_vblank_count != 0) {
> > > > > > +       if (max_vblank_count) {
> > > > > >                 /* trust the hw counter when it's around */
> > > > > > -               diff = (cur_vblank - vblank->last) & dev->max_vblank_count;
> > > > > > +               diff = (cur_vblank - vblank->last) & max_vblank_count;
> > > > > >         } else if (rc && framedur_ns) {
> > > > > >                 u64 diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time));
> > > > > >
> > > > > > @@ -258,7 +266,8 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > > > > >                       pipe, vblank->count, diff, cur_vblank, vblank->last);
> > > > > >
> > > > > >         if (diff == 0) {
> > > > > > -               WARN_ON_ONCE(cur_vblank != vblank->last);
> > > > > > +               WARN_ON_ONCE(max_vblank_count &&
> > > > > > +                            cur_vblank != vblank->last);
> > > > >
> > > > > Unrelated bugfix for this warning? Should be a separate patch I think, or
> > > > > I'm missing something.
> > > >
> > > > Ah, yeah this was due to a quirk of i965gm hardware. The hw counter
> > > > does work until the exact point when we enable TV encoder. Thus we
> > > > will get non-zero values up to that point, and since the TV encoder
> > > > isn't yet throttling the pipe it presumably runs at the oversample
> > > > clock so our timestamp based estimates can give us a diff==0 even
> > > > though the pipe did indeed pass a vblank already. I forgot to
> > > > note this in the commit message.
> > > >
> > > > I think we can handle this three ways:
> > > > 1. do what I do here and just let the mismatch slip through
> > > > 2. force i915_get_vblank_counter() to return 0 always when the
> > > >    TV encoder is going to be used
> > > > 3. don't call drm_crtc_set_max_vblank_count() before drm_vblank_on()
> > > >    and instead delay it until just before we enable the TV encoder
> > > >
> > > > I think option 3 is overly complicated to consider seriously. So
> > > > option 1 or option 2 is what I think we should do. For whatever
> > > > reason I went with option 1 here, but maybe option 2 is better
> > > > since it would be all contained within i915...
> > >
> > > Delay drm_crtc_vblank_on until the vblank is stable? That seems like the
> > > semantically clean solution to me, instead of hacking around in core code
> > > when drivers leak garbage out ...
> >
> > We need a vblank wait before turning on the TV encoder. Chicken vs. egg.
> 
> Gah.
> 
> Ok I think I think having the hack here makes sense then, but split
> out as a separate patch with separate justification. It's a bit a
> tricky thing that deserves to be higlighted (and easier way to found
> the explanation with git blame in case it's ever needed).

Or we go with option 2. It doesn't seem too bad actually.

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 019cb685986c..26d86aedc7ac 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -822,11 +822,26 @@ static void i915_enable_asle_pipestat(struct drm_i915_private *dev_priv)
 static u32 i915_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
+       const struct drm_display_mode *mode = vblank->hwmode;
        i915_reg_t high_frame, low_frame;
        u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal;
-       const struct drm_display_mode *mode = &dev->vblank[pipe].hwmode;
        unsigned long irqflags;
 
+       /*
+        * On i965gm TV output the frame counter works up to
+        * the point when we enable the TV encoder. After that the
+        * frame counter ceases to work and reads zero. We need a
+        * vblank wait before enabling the TV encoder and so we
+        * have to enable vblank interrupts while the frame counter
+        * is still in a working state. However the core vblank code
+        * does not like us returning non-zero frame counter values
+        * when we've told it that we don't have a working frame
+        * counter. Thus we must stop non-zero values leaking out.
+        */
+       if (!vblank->max_vblank_count)
+               return 0;
+
        htotal = mode->crtc_htotal;
        hsync_start = mode->crtc_hsync_start;
        vbl_start = mode->crtc_vblank_start;

-- 
Ville Syrj�l�
Intel

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* Re: [PATCH 01/15] drm/vblank: Allow dynamic per-crtc max_vblank_count
@ 2018-11-21 16:46               ` Ville Syrjälä
  0 siblings, 0 replies; 66+ messages in thread
From: Ville Syrjälä @ 2018-11-21 16:46 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, dri-devel, stable, Inki Dae

On Wed, Nov 21, 2018 at 05:22:49PM +0100, Daniel Vetter wrote:
> On Wed, Nov 21, 2018 at 5:16 PM Ville Syrjälä
> <ville.syrjala@linux.intel.com> wrote:
> >
> > On Wed, Nov 21, 2018 at 04:19:36PM +0100, Daniel Vetter wrote:
> > > On Wed, Nov 21, 2018 at 01:37:51PM +0200, Ville Syrjälä wrote:
> > > > On Wed, Nov 21, 2018 at 10:27:27AM +0100, Daniel Vetter wrote:
> > > > > On Mon, Nov 12, 2018 at 06:59:45PM +0200, Ville Syrjala wrote:
> > > > > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > > >
> > > > > > On i965gm we need to adjust max_vblank_count dynamically
> > > > > > depending on whether the TV encoder is used or not. To
> > > > > > that end add a per-crtc max_vblank_count that takes
> > > > > > precedence over its device wide counterpart. The driver
> > > > > > can now call drm_crtc_set_max_vblank_count() to configure
> > > > > > the per-crtc value before calling drm_vblank_on().
> > > > > >
> > > > > > Also looks like there was some discussion about exynos needing
> > > > > > similar treatment.
> > > > > >
> > > > > > Cc: stable@vger.kernel.org
> > > > > > Cc: Inki Dae <inki.dae@samsung.com>
> > > > > > Cc: Daniel Vetter <daniel@ffwll.ch>
> > > > > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > > > ---
> > > > > >  drivers/gpu/drm/drm_vblank.c | 39 ++++++++++++++++++++++++++++++++----
> > > > > >  include/drm/drm_vblank.h     |  8 ++++++++
> > > > > >  2 files changed, 43 insertions(+), 4 deletions(-)
> > > > > >
> > > > > > diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
> > > > > > index 98e091175921..c3abbdca8aba 100644
> > > > > > --- a/drivers/gpu/drm/drm_vblank.c
> > > > > > +++ b/drivers/gpu/drm/drm_vblank.c
> > > > > > @@ -105,13 +105,20 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe,
> > > > > >         write_sequnlock(&vblank->seqlock);
> > > > > >  }
> > > > > >
> > > > > > +static u32 drm_max_vblank_count(struct drm_device *dev, unsigned int pipe)
> > > > > > +{
> > > > > > +       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> > > > > > +
> > > > > > +       return vblank->max_vblank_count ?: dev->max_vblank_count;
> > > > > > +}
> > > > > > +
> > > > > >  /*
> > > > > >   * "No hw counter" fallback implementation of .get_vblank_counter() hook,
> > > > > >   * if there is no useable hardware frame counter available.
> > > > > >   */
> > > > > >  static u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe)
> > > > > >  {
> > > > > > -       WARN_ON_ONCE(dev->max_vblank_count != 0);
> > > > > > +       WARN_ON_ONCE(drm_max_vblank_count(dev, pipe) != 0);
> > > > > >         return 0;
> > > > > >  }
> > > > > >
> > > > > > @@ -198,6 +205,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > > > > >         ktime_t t_vblank;
> > > > > >         int count = DRM_TIMESTAMP_MAXRETRIES;
> > > > > >         int framedur_ns = vblank->framedur_ns;
> > > > > > +       u32 max_vblank_count = drm_max_vblank_count(dev, pipe);
> > > > > >
> > > > > >         /*
> > > > > >          * Interrupts were disabled prior to this call, so deal with counter
> > > > > > @@ -216,9 +224,9 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > > > > >                 rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq);
> > > > > >         } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0);
> > > > > >
> > > > > > -       if (dev->max_vblank_count != 0) {
> > > > > > +       if (max_vblank_count) {
> > > > > >                 /* trust the hw counter when it's around */
> > > > > > -               diff = (cur_vblank - vblank->last) & dev->max_vblank_count;
> > > > > > +               diff = (cur_vblank - vblank->last) & max_vblank_count;
> > > > > >         } else if (rc && framedur_ns) {
> > > > > >                 u64 diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time));
> > > > > >
> > > > > > @@ -258,7 +266,8 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > > > > >                       pipe, vblank->count, diff, cur_vblank, vblank->last);
> > > > > >
> > > > > >         if (diff == 0) {
> > > > > > -               WARN_ON_ONCE(cur_vblank != vblank->last);
> > > > > > +               WARN_ON_ONCE(max_vblank_count &&
> > > > > > +                            cur_vblank != vblank->last);
> > > > >
> > > > > Unrelated bugfix for this warning? Should be a separate patch I think, or
> > > > > I'm missing something.
> > > >
> > > > Ah, yeah this was due to a quirk of i965gm hardware. The hw counter
> > > > does work until the exact point when we enable TV encoder. Thus we
> > > > will get non-zero values up to that point, and since the TV encoder
> > > > isn't yet throttling the pipe it presumably runs at the oversample
> > > > clock so our timestamp based estimates can give us a diff==0 even
> > > > though the pipe did indeed pass a vblank already. I forgot to
> > > > note this in the commit message.
> > > >
> > > > I think we can handle this three ways:
> > > > 1. do what I do here and just let the mismatch slip through
> > > > 2. force i915_get_vblank_counter() to return 0 always when the
> > > >    TV encoder is going to be used
> > > > 3. don't call drm_crtc_set_max_vblank_count() before drm_vblank_on()
> > > >    and instead delay it until just before we enable the TV encoder
> > > >
> > > > I think option 3 is overly complicated to consider seriously. So
> > > > option 1 or option 2 is what I think we should do. For whatever
> > > > reason I went with option 1 here, but maybe option 2 is better
> > > > since it would be all contained within i915...
> > >
> > > Delay drm_crtc_vblank_on until the vblank is stable? That seems like the
> > > semantically clean solution to me, instead of hacking around in core code
> > > when drivers leak garbage out ...
> >
> > We need a vblank wait before turning on the TV encoder. Chicken vs. egg.
> 
> Gah.
> 
> Ok I think I think having the hack here makes sense then, but split
> out as a separate patch with separate justification. It's a bit a
> tricky thing that deserves to be higlighted (and easier way to found
> the explanation with git blame in case it's ever needed).

Or we go with option 2. It doesn't seem too bad actually.

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 019cb685986c..26d86aedc7ac 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -822,11 +822,26 @@ static void i915_enable_asle_pipestat(struct drm_i915_private *dev_priv)
 static u32 i915_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
+       const struct drm_display_mode *mode = vblank->hwmode;
        i915_reg_t high_frame, low_frame;
        u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal;
-       const struct drm_display_mode *mode = &dev->vblank[pipe].hwmode;
        unsigned long irqflags;
 
+       /*
+        * On i965gm TV output the frame counter works up to
+        * the point when we enable the TV encoder. After that the
+        * frame counter ceases to work and reads zero. We need a
+        * vblank wait before enabling the TV encoder and so we
+        * have to enable vblank interrupts while the frame counter
+        * is still in a working state. However the core vblank code
+        * does not like us returning non-zero frame counter values
+        * when we've told it that we don't have a working frame
+        * counter. Thus we must stop non-zero values leaking out.
+        */
+       if (!vblank->max_vblank_count)
+               return 0;
+
        htotal = mode->crtc_htotal;
        hsync_start = mode->crtc_hsync_start;
        vbl_start = mode->crtc_vblank_start;

-- 
Ville Syrjälä
Intel

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* ✗ Fi.CI.BAT: failure for drm/i915: Fix TV encoder support (rev2)
  2018-11-12 16:59 [PATCH 00/15] drm/i915: Fix TV encoder support Ville Syrjala
                   ` (18 preceding siblings ...)
  2018-11-12 20:06 ` ✓ Fi.CI.IGT: " Patchwork
@ 2018-11-21 16:51 ` Patchwork
  2018-11-27 19:11 ` ✗ Fi.CI.SPARSE: warning for drm/i915: Fix TV encoder support (rev4) Patchwork
                   ` (4 subsequent siblings)
  24 siblings, 0 replies; 66+ messages in thread
From: Patchwork @ 2018-11-21 16:51 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

== Series Details ==

Series: drm/i915: Fix TV encoder support (rev2)
URL   : https://patchwork.freedesktop.org/series/52378/
State : failure

== Summary ==

Applying: drm/vblank: Allow dynamic per-crtc max_vblank_count
error: patch failed: drivers/gpu/drm/i915/i915_irq.c:822
error: drivers/gpu/drm/i915/i915_irq.c: patch does not apply
error: Did you hand edit your patch?
It does not apply to blobs recorded in its index.
Using index info to reconstruct a base tree...
M	drivers/gpu/drm/i915/i915_irq.c
Patch failed at 0001 drm/vblank: Allow dynamic per-crtc max_vblank_count
Use 'git am --show-current-patch' to see the failed patch
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 01/15] drm/vblank: Allow dynamic per-crtc max_vblank_count
  2018-11-21 16:46               ` Ville Syrjälä
@ 2018-11-22  8:53                 ` Daniel Vetter
  -1 siblings, 0 replies; 66+ messages in thread
From: Daniel Vetter @ 2018-11-22  8:53 UTC (permalink / raw)
  To: Ville Syrjälä
  Cc: Daniel Vetter, intel-gfx, dri-devel, stable, Inki Dae

On Wed, Nov 21, 2018 at 06:46:57PM +0200, Ville Syrj�l� wrote:
> On Wed, Nov 21, 2018 at 05:22:49PM +0100, Daniel Vetter wrote:
> > On Wed, Nov 21, 2018 at 5:16 PM Ville Syrj�l�
> > <ville.syrjala@linux.intel.com> wrote:
> > >
> > > On Wed, Nov 21, 2018 at 04:19:36PM +0100, Daniel Vetter wrote:
> > > > On Wed, Nov 21, 2018 at 01:37:51PM +0200, Ville Syrj�l� wrote:
> > > > > On Wed, Nov 21, 2018 at 10:27:27AM +0100, Daniel Vetter wrote:
> > > > > > On Mon, Nov 12, 2018 at 06:59:45PM +0200, Ville Syrjala wrote:
> > > > > > > From: Ville Syrj�l� <ville.syrjala@linux.intel.com>
> > > > > > >
> > > > > > > On i965gm we need to adjust max_vblank_count dynamically
> > > > > > > depending on whether the TV encoder is used or not. To
> > > > > > > that end add a per-crtc max_vblank_count that takes
> > > > > > > precedence over its device wide counterpart. The driver
> > > > > > > can now call drm_crtc_set_max_vblank_count() to configure
> > > > > > > the per-crtc value before calling drm_vblank_on().
> > > > > > >
> > > > > > > Also looks like there was some discussion about exynos needing
> > > > > > > similar treatment.
> > > > > > >
> > > > > > > Cc: stable@vger.kernel.org
> > > > > > > Cc: Inki Dae <inki.dae@samsung.com>
> > > > > > > Cc: Daniel Vetter <daniel@ffwll.ch>
> > > > > > > Signed-off-by: Ville Syrj�l� <ville.syrjala@linux.intel.com>
> > > > > > > ---
> > > > > > >  drivers/gpu/drm/drm_vblank.c | 39 ++++++++++++++++++++++++++++++++----
> > > > > > >  include/drm/drm_vblank.h     |  8 ++++++++
> > > > > > >  2 files changed, 43 insertions(+), 4 deletions(-)
> > > > > > >
> > > > > > > diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
> > > > > > > index 98e091175921..c3abbdca8aba 100644
> > > > > > > --- a/drivers/gpu/drm/drm_vblank.c
> > > > > > > +++ b/drivers/gpu/drm/drm_vblank.c
> > > > > > > @@ -105,13 +105,20 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe,
> > > > > > >         write_sequnlock(&vblank->seqlock);
> > > > > > >  }
> > > > > > >
> > > > > > > +static u32 drm_max_vblank_count(struct drm_device *dev, unsigned int pipe)
> > > > > > > +{
> > > > > > > +       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> > > > > > > +
> > > > > > > +       return vblank->max_vblank_count ?: dev->max_vblank_count;
> > > > > > > +}
> > > > > > > +
> > > > > > >  /*
> > > > > > >   * "No hw counter" fallback implementation of .get_vblank_counter() hook,
> > > > > > >   * if there is no useable hardware frame counter available.
> > > > > > >   */
> > > > > > >  static u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe)
> > > > > > >  {
> > > > > > > -       WARN_ON_ONCE(dev->max_vblank_count != 0);
> > > > > > > +       WARN_ON_ONCE(drm_max_vblank_count(dev, pipe) != 0);
> > > > > > >         return 0;
> > > > > > >  }
> > > > > > >
> > > > > > > @@ -198,6 +205,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > > > > > >         ktime_t t_vblank;
> > > > > > >         int count = DRM_TIMESTAMP_MAXRETRIES;
> > > > > > >         int framedur_ns = vblank->framedur_ns;
> > > > > > > +       u32 max_vblank_count = drm_max_vblank_count(dev, pipe);
> > > > > > >
> > > > > > >         /*
> > > > > > >          * Interrupts were disabled prior to this call, so deal with counter
> > > > > > > @@ -216,9 +224,9 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > > > > > >                 rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq);
> > > > > > >         } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0);
> > > > > > >
> > > > > > > -       if (dev->max_vblank_count != 0) {
> > > > > > > +       if (max_vblank_count) {
> > > > > > >                 /* trust the hw counter when it's around */
> > > > > > > -               diff = (cur_vblank - vblank->last) & dev->max_vblank_count;
> > > > > > > +               diff = (cur_vblank - vblank->last) & max_vblank_count;
> > > > > > >         } else if (rc && framedur_ns) {
> > > > > > >                 u64 diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time));
> > > > > > >
> > > > > > > @@ -258,7 +266,8 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > > > > > >                       pipe, vblank->count, diff, cur_vblank, vblank->last);
> > > > > > >
> > > > > > >         if (diff == 0) {
> > > > > > > -               WARN_ON_ONCE(cur_vblank != vblank->last);
> > > > > > > +               WARN_ON_ONCE(max_vblank_count &&
> > > > > > > +                            cur_vblank != vblank->last);
> > > > > >
> > > > > > Unrelated bugfix for this warning? Should be a separate patch I think, or
> > > > > > I'm missing something.
> > > > >
> > > > > Ah, yeah this was due to a quirk of i965gm hardware. The hw counter
> > > > > does work until the exact point when we enable TV encoder. Thus we
> > > > > will get non-zero values up to that point, and since the TV encoder
> > > > > isn't yet throttling the pipe it presumably runs at the oversample
> > > > > clock so our timestamp based estimates can give us a diff==0 even
> > > > > though the pipe did indeed pass a vblank already. I forgot to
> > > > > note this in the commit message.
> > > > >
> > > > > I think we can handle this three ways:
> > > > > 1. do what I do here and just let the mismatch slip through
> > > > > 2. force i915_get_vblank_counter() to return 0 always when the
> > > > >    TV encoder is going to be used
> > > > > 3. don't call drm_crtc_set_max_vblank_count() before drm_vblank_on()
> > > > >    and instead delay it until just before we enable the TV encoder
> > > > >
> > > > > I think option 3 is overly complicated to consider seriously. So
> > > > > option 1 or option 2 is what I think we should do. For whatever
> > > > > reason I went with option 1 here, but maybe option 2 is better
> > > > > since it would be all contained within i915...
> > > >
> > > > Delay drm_crtc_vblank_on until the vblank is stable? That seems like the
> > > > semantically clean solution to me, instead of hacking around in core code
> > > > when drivers leak garbage out ...
> > >
> > > We need a vblank wait before turning on the TV encoder. Chicken vs. egg.
> > 
> > Gah.
> > 
> > Ok I think I think having the hack here makes sense then, but split
> > out as a separate patch with separate justification. It's a bit a
> > tricky thing that deserves to be higlighted (and easier way to found
> > the explanation with git blame in case it's ever needed).
> 
> Or we go with option 2. It doesn't seem too bad actually.
> 
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 019cb685986c..26d86aedc7ac 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -822,11 +822,26 @@ static void i915_enable_asle_pipestat(struct drm_i915_private *dev_priv)
>  static u32 i915_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
>  {
>         struct drm_i915_private *dev_priv = to_i915(dev);
> +       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> +       const struct drm_display_mode *mode = vblank->hwmode;
>         i915_reg_t high_frame, low_frame;
>         u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal;
> -       const struct drm_display_mode *mode = &dev->vblank[pipe].hwmode;
>         unsigned long irqflags;
>  
> +       /*
> +        * On i965gm TV output the frame counter works up to
> +        * the point when we enable the TV encoder. After that the
> +        * frame counter ceases to work and reads zero. We need a
> +        * vblank wait before enabling the TV encoder and so we
> +        * have to enable vblank interrupts while the frame counter
> +        * is still in a working state. However the core vblank code
> +        * does not like us returning non-zero frame counter values
> +        * when we've told it that we don't have a working frame
> +        * counter. Thus we must stop non-zero values leaking out.
> +        */
> +       if (!vblank->max_vblank_count)
> +               return 0;

Hm yeah, looks reasonable actually. And less hacks in the shared code.
-Daniel

> +
>         htotal = mode->crtc_htotal;
>         hsync_start = mode->crtc_hsync_start;
>         vbl_start = mode->crtc_vblank_start;
> 
> -- 
> Ville Syrj�l�
> Intel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 01/15] drm/vblank: Allow dynamic per-crtc max_vblank_count
@ 2018-11-22  8:53                 ` Daniel Vetter
  0 siblings, 0 replies; 66+ messages in thread
From: Daniel Vetter @ 2018-11-22  8:53 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: Inki Dae, stable, intel-gfx, dri-devel

On Wed, Nov 21, 2018 at 06:46:57PM +0200, Ville Syrjälä wrote:
> On Wed, Nov 21, 2018 at 05:22:49PM +0100, Daniel Vetter wrote:
> > On Wed, Nov 21, 2018 at 5:16 PM Ville Syrjälä
> > <ville.syrjala@linux.intel.com> wrote:
> > >
> > > On Wed, Nov 21, 2018 at 04:19:36PM +0100, Daniel Vetter wrote:
> > > > On Wed, Nov 21, 2018 at 01:37:51PM +0200, Ville Syrjälä wrote:
> > > > > On Wed, Nov 21, 2018 at 10:27:27AM +0100, Daniel Vetter wrote:
> > > > > > On Mon, Nov 12, 2018 at 06:59:45PM +0200, Ville Syrjala wrote:
> > > > > > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > > > >
> > > > > > > On i965gm we need to adjust max_vblank_count dynamically
> > > > > > > depending on whether the TV encoder is used or not. To
> > > > > > > that end add a per-crtc max_vblank_count that takes
> > > > > > > precedence over its device wide counterpart. The driver
> > > > > > > can now call drm_crtc_set_max_vblank_count() to configure
> > > > > > > the per-crtc value before calling drm_vblank_on().
> > > > > > >
> > > > > > > Also looks like there was some discussion about exynos needing
> > > > > > > similar treatment.
> > > > > > >
> > > > > > > Cc: stable@vger.kernel.org
> > > > > > > Cc: Inki Dae <inki.dae@samsung.com>
> > > > > > > Cc: Daniel Vetter <daniel@ffwll.ch>
> > > > > > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > > > > ---
> > > > > > >  drivers/gpu/drm/drm_vblank.c | 39 ++++++++++++++++++++++++++++++++----
> > > > > > >  include/drm/drm_vblank.h     |  8 ++++++++
> > > > > > >  2 files changed, 43 insertions(+), 4 deletions(-)
> > > > > > >
> > > > > > > diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
> > > > > > > index 98e091175921..c3abbdca8aba 100644
> > > > > > > --- a/drivers/gpu/drm/drm_vblank.c
> > > > > > > +++ b/drivers/gpu/drm/drm_vblank.c
> > > > > > > @@ -105,13 +105,20 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe,
> > > > > > >         write_sequnlock(&vblank->seqlock);
> > > > > > >  }
> > > > > > >
> > > > > > > +static u32 drm_max_vblank_count(struct drm_device *dev, unsigned int pipe)
> > > > > > > +{
> > > > > > > +       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> > > > > > > +
> > > > > > > +       return vblank->max_vblank_count ?: dev->max_vblank_count;
> > > > > > > +}
> > > > > > > +
> > > > > > >  /*
> > > > > > >   * "No hw counter" fallback implementation of .get_vblank_counter() hook,
> > > > > > >   * if there is no useable hardware frame counter available.
> > > > > > >   */
> > > > > > >  static u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe)
> > > > > > >  {
> > > > > > > -       WARN_ON_ONCE(dev->max_vblank_count != 0);
> > > > > > > +       WARN_ON_ONCE(drm_max_vblank_count(dev, pipe) != 0);
> > > > > > >         return 0;
> > > > > > >  }
> > > > > > >
> > > > > > > @@ -198,6 +205,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > > > > > >         ktime_t t_vblank;
> > > > > > >         int count = DRM_TIMESTAMP_MAXRETRIES;
> > > > > > >         int framedur_ns = vblank->framedur_ns;
> > > > > > > +       u32 max_vblank_count = drm_max_vblank_count(dev, pipe);
> > > > > > >
> > > > > > >         /*
> > > > > > >          * Interrupts were disabled prior to this call, so deal with counter
> > > > > > > @@ -216,9 +224,9 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > > > > > >                 rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq);
> > > > > > >         } while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0);
> > > > > > >
> > > > > > > -       if (dev->max_vblank_count != 0) {
> > > > > > > +       if (max_vblank_count) {
> > > > > > >                 /* trust the hw counter when it's around */
> > > > > > > -               diff = (cur_vblank - vblank->last) & dev->max_vblank_count;
> > > > > > > +               diff = (cur_vblank - vblank->last) & max_vblank_count;
> > > > > > >         } else if (rc && framedur_ns) {
> > > > > > >                 u64 diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time));
> > > > > > >
> > > > > > > @@ -258,7 +266,8 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
> > > > > > >                       pipe, vblank->count, diff, cur_vblank, vblank->last);
> > > > > > >
> > > > > > >         if (diff == 0) {
> > > > > > > -               WARN_ON_ONCE(cur_vblank != vblank->last);
> > > > > > > +               WARN_ON_ONCE(max_vblank_count &&
> > > > > > > +                            cur_vblank != vblank->last);
> > > > > >
> > > > > > Unrelated bugfix for this warning? Should be a separate patch I think, or
> > > > > > I'm missing something.
> > > > >
> > > > > Ah, yeah this was due to a quirk of i965gm hardware. The hw counter
> > > > > does work until the exact point when we enable TV encoder. Thus we
> > > > > will get non-zero values up to that point, and since the TV encoder
> > > > > isn't yet throttling the pipe it presumably runs at the oversample
> > > > > clock so our timestamp based estimates can give us a diff==0 even
> > > > > though the pipe did indeed pass a vblank already. I forgot to
> > > > > note this in the commit message.
> > > > >
> > > > > I think we can handle this three ways:
> > > > > 1. do what I do here and just let the mismatch slip through
> > > > > 2. force i915_get_vblank_counter() to return 0 always when the
> > > > >    TV encoder is going to be used
> > > > > 3. don't call drm_crtc_set_max_vblank_count() before drm_vblank_on()
> > > > >    and instead delay it until just before we enable the TV encoder
> > > > >
> > > > > I think option 3 is overly complicated to consider seriously. So
> > > > > option 1 or option 2 is what I think we should do. For whatever
> > > > > reason I went with option 1 here, but maybe option 2 is better
> > > > > since it would be all contained within i915...
> > > >
> > > > Delay drm_crtc_vblank_on until the vblank is stable? That seems like the
> > > > semantically clean solution to me, instead of hacking around in core code
> > > > when drivers leak garbage out ...
> > >
> > > We need a vblank wait before turning on the TV encoder. Chicken vs. egg.
> > 
> > Gah.
> > 
> > Ok I think I think having the hack here makes sense then, but split
> > out as a separate patch with separate justification. It's a bit a
> > tricky thing that deserves to be higlighted (and easier way to found
> > the explanation with git blame in case it's ever needed).
> 
> Or we go with option 2. It doesn't seem too bad actually.
> 
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 019cb685986c..26d86aedc7ac 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -822,11 +822,26 @@ static void i915_enable_asle_pipestat(struct drm_i915_private *dev_priv)
>  static u32 i915_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
>  {
>         struct drm_i915_private *dev_priv = to_i915(dev);
> +       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> +       const struct drm_display_mode *mode = vblank->hwmode;
>         i915_reg_t high_frame, low_frame;
>         u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal;
> -       const struct drm_display_mode *mode = &dev->vblank[pipe].hwmode;
>         unsigned long irqflags;
>  
> +       /*
> +        * On i965gm TV output the frame counter works up to
> +        * the point when we enable the TV encoder. After that the
> +        * frame counter ceases to work and reads zero. We need a
> +        * vblank wait before enabling the TV encoder and so we
> +        * have to enable vblank interrupts while the frame counter
> +        * is still in a working state. However the core vblank code
> +        * does not like us returning non-zero frame counter values
> +        * when we've told it that we don't have a working frame
> +        * counter. Thus we must stop non-zero values leaking out.
> +        */
> +       if (!vblank->max_vblank_count)
> +               return 0;

Hm yeah, looks reasonable actually. And less hacks in the shared code.
-Daniel

> +
>         htotal = mode->crtc_htotal;
>         hsync_start = mode->crtc_hsync_start;
>         vbl_start = mode->crtc_vblank_start;
> 
> -- 
> Ville Syrjälä
> Intel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 66+ messages in thread

* [PATCH v2 01/15] drm/vblank: Allow dynamic per-crtc max_vblank_count
  2018-11-12 16:59 ` [PATCH 01/15] drm/vblank: Allow dynamic per-crtc max_vblank_count Ville Syrjala
@ 2018-11-27 18:20     ` Ville Syrjala
  2018-11-27 18:20     ` Ville Syrjala
  1 sibling, 0 replies; 66+ messages in thread
From: Ville Syrjala @ 2018-11-27 18:20 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel, stable, Inki Dae, Daniel Vetter

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

On i965gm we need to adjust max_vblank_count dynamically
depending on whether the TV encoder is used or not. To
that end add a per-crtc max_vblank_count that takes
precedence over its device wide counterpart. The driver
can now call drm_crtc_set_max_vblank_count() to configure
the per-crtc value before calling drm_vblank_on().

Also looks like there was some discussion about exynos needing
similar treatment.

v2: Drop the extra max_vblank_count!=0 check for the
    WARN(last!=current), will take care of it in i915 code (Daniel)
    WARN_ON(!inmodeset) (Daniel)
    WARN_ON(dev->max_vblank_count)
    Pimp up the docs (Daniel)

Cc: stable@vger.kernel.org
Cc: Inki Dae <inki.dae@samsung.com>
Cc: Daniel Vetter <daniel@ffwll.ch>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/drm_vblank.c | 45 +++++++++++++++++++++++++++++++++---
 include/drm/drm_device.h     |  8 ++++++-
 include/drm/drm_vblank.h     | 22 ++++++++++++++++++
 3 files changed, 71 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
index 98e091175921..cde71ee95a8f 100644
--- a/drivers/gpu/drm/drm_vblank.c
+++ b/drivers/gpu/drm/drm_vblank.c
@@ -105,13 +105,20 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe,
 	write_sequnlock(&vblank->seqlock);
 }
 
+static u32 drm_max_vblank_count(struct drm_device *dev, unsigned int pipe)
+{
+	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
+
+	return vblank->max_vblank_count ?: dev->max_vblank_count;
+}
+
 /*
  * "No hw counter" fallback implementation of .get_vblank_counter() hook,
  * if there is no useable hardware frame counter available.
  */
 static u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe)
 {
-	WARN_ON_ONCE(dev->max_vblank_count != 0);
+	WARN_ON_ONCE(drm_max_vblank_count(dev, pipe) != 0);
 	return 0;
 }
 
@@ -198,6 +205,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
 	ktime_t t_vblank;
 	int count = DRM_TIMESTAMP_MAXRETRIES;
 	int framedur_ns = vblank->framedur_ns;
+	u32 max_vblank_count = drm_max_vblank_count(dev, pipe);
 
 	/*
 	 * Interrupts were disabled prior to this call, so deal with counter
@@ -216,9 +224,9 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
 		rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq);
 	} while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0);
 
-	if (dev->max_vblank_count != 0) {
+	if (max_vblank_count) {
 		/* trust the hw counter when it's around */
-		diff = (cur_vblank - vblank->last) & dev->max_vblank_count;
+		diff = (cur_vblank - vblank->last) & max_vblank_count;
 	} else if (rc && framedur_ns) {
 		u64 diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time));
 
@@ -1204,6 +1212,37 @@ void drm_crtc_vblank_reset(struct drm_crtc *crtc)
 }
 EXPORT_SYMBOL(drm_crtc_vblank_reset);
 
+/**
+ * drm_crtc_set_max_vblank_count - configure the hw max vblank counter value
+ * @crtc: CRTC in question
+ * @max_vblank_count: max hardware vblank counter value
+ *
+ * Update the maximum hardware vblank counter value for @crtc
+ * at runtime. Useful for hardware where the operation of the
+ * hardware vblank counter depends on the currently active
+ * display configuration.
+ *
+ * For example, if the hardware vblank counter does not work
+ * when a specific connector is active the maximum can be set
+ * to zero. And when that specific connector isn't active the
+ * maximum can again be set to the appropriate non-zero value.
+ *
+ * If used, must be called before drm_vblank_on().
+ */
+void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc,
+				   u32 max_vblank_count)
+{
+	struct drm_device *dev = crtc->dev;
+	unsigned int pipe = drm_crtc_index(crtc);
+	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
+
+	WARN_ON(dev->max_vblank_count);
+	WARN_ON(!READ_ONCE(vblank->inmodeset));
+
+	vblank->max_vblank_count = max_vblank_count;
+}
+EXPORT_SYMBOL(drm_crtc_set_max_vblank_count);
+
 /**
  * drm_crtc_vblank_on - enable vblank events on a CRTC
  * @crtc: CRTC in question
diff --git a/include/drm/drm_device.h b/include/drm/drm_device.h
index 42411b3ea0c8..45e43ce9652f 100644
--- a/include/drm/drm_device.h
+++ b/include/drm/drm_device.h
@@ -184,7 +184,13 @@ struct drm_device {
 	 * races and imprecision over longer time periods, hence exposing a
 	 * hardware vblank counter is always recommended.
 	 *
-	 * If non-zeor, &drm_crtc_funcs.get_vblank_counter must be set.
+	 * This is the statically configured device wide maximum. The driver
+	 * can instead choose to use a runtime configurable per-crtc value
+	 * &drm_vblank_crtc.max_vblank_count, in which case @max_vblank_count
+	 * must be left at zero. See drm_crtc_set_max_vblank_count() on how
+	 * to use the per-crtc value.
+	 *
+	 * If non-zero, &drm_crtc_funcs.get_vblank_counter must be set.
 	 */
 	u32 max_vblank_count;           /**< size of vblank counter register */
 
diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h
index 6ad9630d4f48..e528bb2f659d 100644
--- a/include/drm/drm_vblank.h
+++ b/include/drm/drm_vblank.h
@@ -128,6 +128,26 @@ struct drm_vblank_crtc {
 	 * @last: Protected by &drm_device.vbl_lock, used for wraparound handling.
 	 */
 	u32 last;
+	/**
+	 * @max_vblank_count:
+	 *
+	 * Maximum value of the vblank registers for this crtc. This value +1
+	 * will result in a wrap-around of the vblank register. It is used
+	 * by the vblank core to handle wrap-arounds.
+	 *
+	 * If set to zero the vblank core will try to guess the elapsed vblanks
+	 * between times when the vblank interrupt is disabled through
+	 * high-precision timestamps. That approach is suffering from small
+	 * races and imprecision over longer time periods, hence exposing a
+	 * hardware vblank counter is always recommended.
+	 *
+	 * This is the runtime configurable per-crtc maximum set through
+	 * drm_crtc_set_max_vblank_count(). If this is used the driver
+	 * must leave the device wide &drm_device.max_vblank_count at zero.
+	 *
+	 * If non-zero, &drm_crtc_funcs.get_vblank_counter must be set.
+	 */
+	u32 max_vblank_count;
 	/**
 	 * @inmodeset: Tracks whether the vblank is disabled due to a modeset.
 	 * For legacy driver bit 2 additionally tracks whether an additional
@@ -206,4 +226,6 @@ bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
 void drm_calc_timestamping_constants(struct drm_crtc *crtc,
 				     const struct drm_display_mode *mode);
 wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc);
+void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc,
+				   u32 max_vblank_count);
 #endif
-- 
2.18.1

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH v2 01/15] drm/vblank: Allow dynamic per-crtc max_vblank_count
@ 2018-11-27 18:20     ` Ville Syrjala
  0 siblings, 0 replies; 66+ messages in thread
From: Ville Syrjala @ 2018-11-27 18:20 UTC (permalink / raw)
  To: intel-gfx; +Cc: stable, dri-devel

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

On i965gm we need to adjust max_vblank_count dynamically
depending on whether the TV encoder is used or not. To
that end add a per-crtc max_vblank_count that takes
precedence over its device wide counterpart. The driver
can now call drm_crtc_set_max_vblank_count() to configure
the per-crtc value before calling drm_vblank_on().

Also looks like there was some discussion about exynos needing
similar treatment.

v2: Drop the extra max_vblank_count!=0 check for the
    WARN(last!=current), will take care of it in i915 code (Daniel)
    WARN_ON(!inmodeset) (Daniel)
    WARN_ON(dev->max_vblank_count)
    Pimp up the docs (Daniel)

Cc: stable@vger.kernel.org
Cc: Inki Dae <inki.dae@samsung.com>
Cc: Daniel Vetter <daniel@ffwll.ch>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/drm_vblank.c | 45 +++++++++++++++++++++++++++++++++---
 include/drm/drm_device.h     |  8 ++++++-
 include/drm/drm_vblank.h     | 22 ++++++++++++++++++
 3 files changed, 71 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
index 98e091175921..cde71ee95a8f 100644
--- a/drivers/gpu/drm/drm_vblank.c
+++ b/drivers/gpu/drm/drm_vblank.c
@@ -105,13 +105,20 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe,
 	write_sequnlock(&vblank->seqlock);
 }
 
+static u32 drm_max_vblank_count(struct drm_device *dev, unsigned int pipe)
+{
+	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
+
+	return vblank->max_vblank_count ?: dev->max_vblank_count;
+}
+
 /*
  * "No hw counter" fallback implementation of .get_vblank_counter() hook,
  * if there is no useable hardware frame counter available.
  */
 static u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe)
 {
-	WARN_ON_ONCE(dev->max_vblank_count != 0);
+	WARN_ON_ONCE(drm_max_vblank_count(dev, pipe) != 0);
 	return 0;
 }
 
@@ -198,6 +205,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
 	ktime_t t_vblank;
 	int count = DRM_TIMESTAMP_MAXRETRIES;
 	int framedur_ns = vblank->framedur_ns;
+	u32 max_vblank_count = drm_max_vblank_count(dev, pipe);
 
 	/*
 	 * Interrupts were disabled prior to this call, so deal with counter
@@ -216,9 +224,9 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
 		rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq);
 	} while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0);
 
-	if (dev->max_vblank_count != 0) {
+	if (max_vblank_count) {
 		/* trust the hw counter when it's around */
-		diff = (cur_vblank - vblank->last) & dev->max_vblank_count;
+		diff = (cur_vblank - vblank->last) & max_vblank_count;
 	} else if (rc && framedur_ns) {
 		u64 diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time));
 
@@ -1204,6 +1212,37 @@ void drm_crtc_vblank_reset(struct drm_crtc *crtc)
 }
 EXPORT_SYMBOL(drm_crtc_vblank_reset);
 
+/**
+ * drm_crtc_set_max_vblank_count - configure the hw max vblank counter value
+ * @crtc: CRTC in question
+ * @max_vblank_count: max hardware vblank counter value
+ *
+ * Update the maximum hardware vblank counter value for @crtc
+ * at runtime. Useful for hardware where the operation of the
+ * hardware vblank counter depends on the currently active
+ * display configuration.
+ *
+ * For example, if the hardware vblank counter does not work
+ * when a specific connector is active the maximum can be set
+ * to zero. And when that specific connector isn't active the
+ * maximum can again be set to the appropriate non-zero value.
+ *
+ * If used, must be called before drm_vblank_on().
+ */
+void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc,
+				   u32 max_vblank_count)
+{
+	struct drm_device *dev = crtc->dev;
+	unsigned int pipe = drm_crtc_index(crtc);
+	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
+
+	WARN_ON(dev->max_vblank_count);
+	WARN_ON(!READ_ONCE(vblank->inmodeset));
+
+	vblank->max_vblank_count = max_vblank_count;
+}
+EXPORT_SYMBOL(drm_crtc_set_max_vblank_count);
+
 /**
  * drm_crtc_vblank_on - enable vblank events on a CRTC
  * @crtc: CRTC in question
diff --git a/include/drm/drm_device.h b/include/drm/drm_device.h
index 42411b3ea0c8..45e43ce9652f 100644
--- a/include/drm/drm_device.h
+++ b/include/drm/drm_device.h
@@ -184,7 +184,13 @@ struct drm_device {
 	 * races and imprecision over longer time periods, hence exposing a
 	 * hardware vblank counter is always recommended.
 	 *
-	 * If non-zeor, &drm_crtc_funcs.get_vblank_counter must be set.
+	 * This is the statically configured device wide maximum. The driver
+	 * can instead choose to use a runtime configurable per-crtc value
+	 * &drm_vblank_crtc.max_vblank_count, in which case @max_vblank_count
+	 * must be left at zero. See drm_crtc_set_max_vblank_count() on how
+	 * to use the per-crtc value.
+	 *
+	 * If non-zero, &drm_crtc_funcs.get_vblank_counter must be set.
 	 */
 	u32 max_vblank_count;           /**< size of vblank counter register */
 
diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h
index 6ad9630d4f48..e528bb2f659d 100644
--- a/include/drm/drm_vblank.h
+++ b/include/drm/drm_vblank.h
@@ -128,6 +128,26 @@ struct drm_vblank_crtc {
 	 * @last: Protected by &drm_device.vbl_lock, used for wraparound handling.
 	 */
 	u32 last;
+	/**
+	 * @max_vblank_count:
+	 *
+	 * Maximum value of the vblank registers for this crtc. This value +1
+	 * will result in a wrap-around of the vblank register. It is used
+	 * by the vblank core to handle wrap-arounds.
+	 *
+	 * If set to zero the vblank core will try to guess the elapsed vblanks
+	 * between times when the vblank interrupt is disabled through
+	 * high-precision timestamps. That approach is suffering from small
+	 * races and imprecision over longer time periods, hence exposing a
+	 * hardware vblank counter is always recommended.
+	 *
+	 * This is the runtime configurable per-crtc maximum set through
+	 * drm_crtc_set_max_vblank_count(). If this is used the driver
+	 * must leave the device wide &drm_device.max_vblank_count at zero.
+	 *
+	 * If non-zero, &drm_crtc_funcs.get_vblank_counter must be set.
+	 */
+	u32 max_vblank_count;
 	/**
 	 * @inmodeset: Tracks whether the vblank is disabled due to a modeset.
 	 * For legacy driver bit 2 additionally tracks whether an additional
@@ -206,4 +226,6 @@ bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
 void drm_calc_timestamping_constants(struct drm_crtc *crtc,
 				     const struct drm_display_mode *mode);
 wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc);
+void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc,
+				   u32 max_vblank_count);
 #endif
-- 
2.18.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH v2 02/15] drm/i915: Don't try to use the hardware frame counter with i965gm TV output
  2018-11-12 16:59 ` [PATCH 02/15] drm/i915: Don't try to use the hardware frame counter with i965gm TV output Ville Syrjala
@ 2018-11-27 18:21   ` Ville Syrjala
  2018-11-27 20:05   ` [PATCH v3 " Ville Syrjala
  1 sibling, 0 replies; 66+ messages in thread
From: Ville Syrjala @ 2018-11-27 18:21 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel, stable, Daniel Vetter

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

On i965gm the hardware frame counter does not work when
the TV encoder is active. So let's not try to consult
the hardware frame counter in that case. Instead we'll
fall back to the timestamp based guesstimation method
used on gen2.

Note that the pipe timings generated by the TV encoder
are also rather peculiar. Apparently the pipe wants to
run at a much higher speed (related to the oversample
clock somehow it seems) but during the vertical active
period the TV encoder stalls the pipe every few lines
to keep its speed in check. But once the vertical
blanking period is reached the pipe gets to run at full
speed. This means our vblank timestamp estimates are
suspect. Fixing all that would require quite a bit
more work. This simple fix at least avoids the nasty
vblank timeouts that are happening currently.

Curiously the frame counter works just fine on i945gm
and gm45. I don't really understand what kind of mishap
occurred with the hardware design on i965gm. Sadly
I wasn't able to find any chicken bits etc. that would
fix the frame counter :(

v2: Move the zero vs. non-zero hw counter value handling
    into i915_get_vblank_counter() (Daniel)
    Use the per-crtc maximum exclusively, leaving the
    per-device maximum at zero

Cc: stable@vger.kernel.org
Cc: Daniel Vetter <daniel@ffwll.ch>
Fixes: 51e31d49c890 ("drm/i915: Use generic vblank wait")
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=93782
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_irq.c      | 27 ++++++++++-----
 drivers/gpu/drm/i915/intel_display.c | 49 +++++++++++++++++++++++-----
 2 files changed, 59 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index d447d7d508f4..ab2d4eefef18 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -822,11 +822,26 @@ static void i915_enable_asle_pipestat(struct drm_i915_private *dev_priv)
 static u32 i915_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
 {
 	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
+	const struct drm_display_mode *mode = &vblank->hwmode;
 	i915_reg_t high_frame, low_frame;
 	u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal;
-	const struct drm_display_mode *mode = &dev->vblank[pipe].hwmode;
 	unsigned long irqflags;
 
+	/*
+	 * On i965gm TV output the frame counter only works up to
+	 * the point when we enable the TV encoder. After that the
+	 * frame counter ceases to work and reads zero. We need a
+	 * vblank wait before enabling the TV encoder and so we
+	 * have to enable vblank interrupts while the frame counter
+	 * is still in a working state. However the core vblank code
+	 * does not like us returning non-zero frame counter values
+	 * when we've told it that we don't have a working frame
+	 * counter. Thus we must stop non-zero values leaking out.
+	 */
+	if (!vblank->max_vblank_count)
+		return 0;
+
 	htotal = mode->crtc_htotal;
 	hsync_start = mode->crtc_hsync_start;
 	vbl_start = mode->crtc_vblank_start;
@@ -4836,16 +4851,10 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
 	if (INTEL_GEN(dev_priv) >= 8)
 		rps->pm_intrmsk_mbz |= GEN8_PMINTR_DISABLE_REDIRECT_TO_GUC;
 
-	if (IS_GEN2(dev_priv)) {
-		/* Gen2 doesn't have a hardware frame counter */
-		dev->max_vblank_count = 0;
-	} else if (IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5) {
-		dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
+	if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
 		dev->driver->get_vblank_counter = g4x_get_vblank_counter;
-	} else {
+	else if (INTEL_GEN(dev_priv) >= 3)
 		dev->driver->get_vblank_counter = i915_get_vblank_counter;
-		dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
-	}
 
 	/*
 	 * Opt out of the vblank disable timer on everything except gen2.
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index e9f4e22b2a4e..3eafea4e598f 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1758,6 +1758,7 @@ static void intel_enable_pipe(const struct intel_crtc_state *new_crtc_state)
 {
 	struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc);
 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+	struct drm_vblank_crtc *vblank = &dev_priv->drm.vblank[drm_crtc_index(&crtc->base)];
 	enum transcoder cpu_transcoder = new_crtc_state->cpu_transcoder;
 	enum pipe pipe = crtc->pipe;
 	i915_reg_t reg;
@@ -1806,7 +1807,7 @@ static void intel_enable_pipe(const struct intel_crtc_state *new_crtc_state)
 	 * when it's derived from the timestamps. So let's wait for the
 	 * pipe to start properly before we call drm_crtc_vblank_on()
 	 */
-	if (dev_priv->drm.max_vblank_count == 0)
+	if (vblank->max_vblank_count == 0)
 		intel_wait_for_pipe_scanline_moving(crtc);
 }
 
@@ -5544,6 +5545,35 @@ static void intel_encoders_post_pll_disable(struct drm_crtc *crtc,
 	}
 }
 
+static u32 intel_crtc_max_vblank_count(const struct intel_crtc_state *crtc_state)
+{
+	struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
+
+	/*
+	 * On i965gm the hardware frame counter reads
+	 * zero when the TV encoder is enabled :(
+	 */
+	if (IS_I965GM(dev_priv) &&
+	    (crtc_state->output_types & BIT(INTEL_OUTPUT_TVOUT)))
+		return 0;
+
+	if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
+		return 0xffffffff; /* full 32 bit counter */
+	else if (INTEL_GEN(dev_priv) >= 3)
+		return 0xffffff; /* only 24 bits of frame count */
+	else
+		return 0; /* Gen2 doesn't have a hardware frame counter */
+}
+
+static void intel_crtc_vblank_on(const struct intel_crtc_state *crtc_state)
+{
+	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+
+	drm_crtc_set_max_vblank_count(&crtc->base,
+				      intel_crtc_max_vblank_count(crtc_state));
+	drm_crtc_vblank_on(&crtc->base);
+}
+
 static void ironlake_crtc_enable(struct intel_crtc_state *pipe_config,
 				 struct drm_atomic_state *old_state)
 {
@@ -5617,7 +5647,7 @@ static void ironlake_crtc_enable(struct intel_crtc_state *pipe_config,
 		ironlake_pch_enable(old_intel_state, pipe_config);
 
 	assert_vblank_disabled(crtc);
-	drm_crtc_vblank_on(crtc);
+	intel_crtc_vblank_on(pipe_config);
 
 	intel_encoders_enable(crtc, pipe_config, old_state);
 
@@ -5774,7 +5804,7 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
 		intel_ddi_set_vc_payload_alloc(pipe_config, true);
 
 	assert_vblank_disabled(crtc);
-	drm_crtc_vblank_on(crtc);
+	intel_crtc_vblank_on(pipe_config);
 
 	intel_encoders_enable(crtc, pipe_config, old_state);
 
@@ -6114,7 +6144,7 @@ static void valleyview_crtc_enable(struct intel_crtc_state *pipe_config,
 	intel_enable_pipe(pipe_config);
 
 	assert_vblank_disabled(crtc);
-	drm_crtc_vblank_on(crtc);
+	intel_crtc_vblank_on(pipe_config);
 
 	intel_encoders_enable(crtc, pipe_config, old_state);
 }
@@ -6173,7 +6203,7 @@ static void i9xx_crtc_enable(struct intel_crtc_state *pipe_config,
 	intel_enable_pipe(pipe_config);
 
 	assert_vblank_disabled(crtc);
-	drm_crtc_vblank_on(crtc);
+	intel_crtc_vblank_on(pipe_config);
 
 	intel_encoders_enable(crtc, pipe_config, old_state);
 }
@@ -12653,8 +12683,9 @@ static int intel_atomic_prepare_commit(struct drm_device *dev,
 u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc)
 {
 	struct drm_device *dev = crtc->base.dev;
+	struct drm_vblank_crtc *vblank = &dev->vblank[drm_crtc_index(&crtc->base)];
 
-	if (!dev->max_vblank_count)
+	if (!vblank->max_vblank_count)
 		return (u32)drm_crtc_accurate_vblank_count(&crtc->base);
 
 	return dev->driver->get_vblank_counter(dev, crtc->pipe);
@@ -15736,10 +15767,12 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
 	 * waits, so we need vblank interrupts restored beforehand.
 	 */
 	for_each_intel_crtc(&dev_priv->drm, crtc) {
+		crtc_state = to_intel_crtc_state(crtc->base.state);
+
 		drm_crtc_vblank_reset(&crtc->base);
 
-		if (crtc->base.state->active)
-			drm_crtc_vblank_on(&crtc->base);
+		if (crtc_state->base.active)
+			intel_crtc_vblank_on(crtc_state);
 	}
 
 	intel_sanitize_plane_mapping(dev_priv);
-- 
2.18.1

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* ✗ Fi.CI.SPARSE: warning for drm/i915: Fix TV encoder support (rev4)
  2018-11-12 16:59 [PATCH 00/15] drm/i915: Fix TV encoder support Ville Syrjala
                   ` (19 preceding siblings ...)
  2018-11-21 16:51 ` ✗ Fi.CI.BAT: failure for drm/i915: Fix TV encoder support (rev2) Patchwork
@ 2018-11-27 19:11 ` Patchwork
  2018-11-27 19:23 ` ✗ Fi.CI.BAT: failure " Patchwork
                   ` (3 subsequent siblings)
  24 siblings, 0 replies; 66+ messages in thread
From: Patchwork @ 2018-11-27 19:11 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

== Series Details ==

Series: drm/i915: Fix TV encoder support (rev4)
URL   : https://patchwork.freedesktop.org/series/52378/
State : warning

== Summary ==

$ dim sparse origin/drm-tip
Sparse version: v0.5.2
Commit: drm/vblank: Allow dynamic per-crtc max_vblank_count
Okay!

Commit: drm/i915: Don't try to use the hardware frame counter with i965gm TV output
Okay!

Commit: drm/i915/tv: Fix interlaced ysize calculation
Okay!

Commit: drm/i915/tv: Fix tv mode clocks
Okay!

Commit: drm/i915/tv: Store the TV oversampling factor in the TV mode
Okay!

Commit: drm/i915/tv: Use bools where appropriate
Okay!

Commit: drm/i915/tv: Nuke silly 0 initialzation of xpos/ypos
Okay!

Commit: drm/i915/tv: Deobfuscate preferred mode selection
Okay!

Commit: drm/i915/tv: Use drm_mode_set_name() to name TV modes
Okay!

Commit: drm/i915/tv: Make TV mode autoselection actually useable
Okay!

Commit: drm/i915/tv: Nuke reported_modes[]
Okay!

Commit: drm/i915/tv: Add 1080p30/50/60 TV modes
Okay!

Commit: drm/i915/tv: Generate better pipe timings for TV encoder
Okay!

Commit: drm/i915/tv: Fix >1024 modes on gen3
+drivers/gpu/drm/i915/intel_tv.c:889:28: warning: symbol 'intel_tv_connector_duplicate_state' was not declared. Should it be static?

Commit: drm/i915/tv: Filter out >1024 wide modes that would need vertical scaling on gen3
Okay!

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 66+ messages in thread

* ✗ Fi.CI.BAT: failure for drm/i915: Fix TV encoder support (rev4)
  2018-11-12 16:59 [PATCH 00/15] drm/i915: Fix TV encoder support Ville Syrjala
                   ` (20 preceding siblings ...)
  2018-11-27 19:11 ` ✗ Fi.CI.SPARSE: warning for drm/i915: Fix TV encoder support (rev4) Patchwork
@ 2018-11-27 19:23 ` Patchwork
  2018-11-27 20:37 ` ✗ Fi.CI.SPARSE: warning for drm/i915: Fix TV encoder support (rev5) Patchwork
                   ` (2 subsequent siblings)
  24 siblings, 0 replies; 66+ messages in thread
From: Patchwork @ 2018-11-27 19:23 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

== Series Details ==

Series: drm/i915: Fix TV encoder support (rev4)
URL   : https://patchwork.freedesktop.org/series/52378/
State : failure

== Summary ==

= CI Bug Log - changes from CI_DRM_5211 -> Patchwork_10919 =

== Summary - FAILURE ==

  Serious unknown changes coming with Patchwork_10919 absolutely need to be
  verified manually.
  
  If you think the reported changes have nothing to do with the changes
  introduced in Patchwork_10919, please notify your bug team to allow them
  to document this new failure mode, which will reduce false positives in CI.

  External URL: https://patchwork.freedesktop.org/api/1.0/series/52378/revisions/4/mbox/

== Possible new issues ==

  Here are the unknown changes that may have been introduced in Patchwork_10919:

  === IGT changes ===

    ==== Possible regressions ====

    igt@i915_module_load@reload:
      fi-glk-j4005:       PASS -> DMESG-WARN +4
      fi-skl-iommu:       PASS -> DMESG-WARN +4
      fi-bdw-gvtdvm:      PASS -> DMESG-WARN +3
      fi-snb-2520m:       PASS -> DMESG-WARN +2

    igt@i915_module_load@reload-with-fault-injection:
      fi-skl-gvtdvm:      PASS -> DMESG-WARN +3
      fi-cfl-guc:         PASS -> DMESG-WARN +4
      fi-skl-guc:         PASS -> DMESG-WARN +3
      fi-cfl-8700k:       PASS -> DMESG-WARN +4
      fi-skl-6700k2:      PASS -> DMESG-WARN +2
      fi-skl-6260u:       PASS -> DMESG-WARN +4
      fi-ivb-3520m:       PASS -> DMESG-WARN +3
      fi-ilk-650:         PASS -> DMESG-WARN +1

    igt@kms_busy@basic-flip-b:
      fi-bdw-5557u:       PASS -> DMESG-WARN +4

    igt@kms_busy@basic-flip-c:
      fi-hsw-peppy:       PASS -> DMESG-WARN +3
      fi-ivb-3770:        PASS -> DMESG-WARN +3
      fi-icl-u2:          PASS -> DMESG-WARN

    
== Known issues ==

  Here are the changes found in Patchwork_10919 that come from known issues:

  === IGT changes ===

    ==== Issues hit ====

    igt@gem_ctx_create@basic-files:
      fi-bsw-n3050:       PASS -> FAIL ([fdo#108656])

    igt@gem_exec_suspend@basic-s3:
      fi-blb-e6850:       PASS -> INCOMPLETE ([fdo#107718])

    igt@i915_module_load@reload-with-fault-injection:
      fi-hsw-4770:        PASS -> DMESG-WARN ([fdo#107924])
      fi-hsw-peppy:       PASS -> DMESG-WARN ([fdo#107924])

    igt@kms_pipe_crc_basic@nonblocking-crc-pipe-a-frame-sequence:
      fi-byt-clapper:     PASS -> FAIL ([fdo#103191], [fdo#107362]) +1

    
    ==== Possible fixes ====

    igt@i915_selftest@live_hangcheck:
      fi-cfl-8109u:       INCOMPLETE ([fdo#106070]) -> PASS

    igt@kms_frontbuffer_tracking@basic:
      fi-hsw-peppy:       DMESG-WARN ([fdo#102614]) -> PASS

    igt@kms_pipe_crc_basic@read-crc-pipe-a:
      fi-byt-clapper:     FAIL ([fdo#107362]) -> PASS

    igt@kms_pipe_crc_basic@suspend-read-crc-pipe-a:
      fi-byt-clapper:     FAIL ([fdo#103191], [fdo#107362]) -> PASS

    igt@kms_pipe_crc_basic@suspend-read-crc-pipe-b:
      fi-cfl-8109u:       DMESG-WARN ([fdo#106107]) -> PASS

    
  fdo#102614 https://bugs.freedesktop.org/show_bug.cgi?id=102614
  fdo#103191 https://bugs.freedesktop.org/show_bug.cgi?id=103191
  fdo#106070 https://bugs.freedesktop.org/show_bug.cgi?id=106070
  fdo#106107 https://bugs.freedesktop.org/show_bug.cgi?id=106107
  fdo#107362 https://bugs.freedesktop.org/show_bug.cgi?id=107362
  fdo#107718 https://bugs.freedesktop.org/show_bug.cgi?id=107718
  fdo#107924 https://bugs.freedesktop.org/show_bug.cgi?id=107924
  fdo#108656 https://bugs.freedesktop.org/show_bug.cgi?id=108656


== Participating hosts (51 -> 44) ==

  Missing    (7): fi-ilk-m540 fi-hsw-4200u fi-byt-j1900 fi-byt-squawks fi-bsw-cyan fi-ctg-p8600 fi-snb-2600 


== Build changes ==

    * Linux: CI_DRM_5211 -> Patchwork_10919

  CI_DRM_5211: b6ba4ad91b7c6c4341c40a05b0326470e0c293cb @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_4732: eae5c3587e56abc581af9b59060cd316df2caa08 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  Patchwork_10919: 39640710adab3f7f9c448d94542d9410222b4065 @ git://anongit.freedesktop.org/gfx-ci/linux


== Linux commits ==

39640710adab drm/i915/tv: Filter out >1024 wide modes that would need vertical scaling on gen3
07ccbfdd05af drm/i915/tv: Fix >1024 modes on gen3
7fdc0da96974 drm/i915/tv: Generate better pipe timings for TV encoder
53ac682f877e drm/i915/tv: Add 1080p30/50/60 TV modes
b59b4cdc04f9 drm/i915/tv: Nuke reported_modes[]
4f2cb6238ad3 drm/i915/tv: Make TV mode autoselection actually useable
0eb9da57f9dc drm/i915/tv: Use drm_mode_set_name() to name TV modes
287f7ac24759 drm/i915/tv: Deobfuscate preferred mode selection
c0f6c577fc7e drm/i915/tv: Nuke silly 0 initialzation of xpos/ypos
46e2ca9d9c6d drm/i915/tv: Use bools where appropriate
a1484e8e981a drm/i915/tv: Store the TV oversampling factor in the TV mode
80917f6b2693 drm/i915/tv: Fix tv mode clocks
055e572d3e07 drm/i915/tv: Fix interlaced ysize calculation
cb0be7c79c97 drm/i915: Don't try to use the hardware frame counter with i965gm TV output
d9864f1ce3a3 drm/vblank: Allow dynamic per-crtc max_vblank_count

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_10919/
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v2 01/15] drm/vblank: Allow dynamic per-crtc max_vblank_count
  2018-11-27 18:20     ` Ville Syrjala
@ 2018-11-27 19:42       ` Daniel Vetter
  -1 siblings, 0 replies; 66+ messages in thread
From: Daniel Vetter @ 2018-11-27 19:42 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, dri-devel, stable, Inki Dae, Daniel Vetter

On Tue, Nov 27, 2018 at 08:20:04PM +0200, Ville Syrjala wrote:
> From: Ville Syrj�l� <ville.syrjala@linux.intel.com>
> 
> On i965gm we need to adjust max_vblank_count dynamically
> depending on whether the TV encoder is used or not. To
> that end add a per-crtc max_vblank_count that takes
> precedence over its device wide counterpart. The driver
> can now call drm_crtc_set_max_vblank_count() to configure
> the per-crtc value before calling drm_vblank_on().
> 
> Also looks like there was some discussion about exynos needing
> similar treatment.
> 
> v2: Drop the extra max_vblank_count!=0 check for the
>     WARN(last!=current), will take care of it in i915 code (Daniel)
>     WARN_ON(!inmodeset) (Daniel)
>     WARN_ON(dev->max_vblank_count)
>     Pimp up the docs (Daniel)

Yeah I'm happy with the pile of WARN_ON here. And docs look great too.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> 
> Cc: stable@vger.kernel.org
> Cc: Inki Dae <inki.dae@samsung.com>
> Cc: Daniel Vetter <daniel@ffwll.ch>
> Signed-off-by: Ville Syrj�l� <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/drm_vblank.c | 45 +++++++++++++++++++++++++++++++++---
>  include/drm/drm_device.h     |  8 ++++++-
>  include/drm/drm_vblank.h     | 22 ++++++++++++++++++
>  3 files changed, 71 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
> index 98e091175921..cde71ee95a8f 100644
> --- a/drivers/gpu/drm/drm_vblank.c
> +++ b/drivers/gpu/drm/drm_vblank.c
> @@ -105,13 +105,20 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe,
>  	write_sequnlock(&vblank->seqlock);
>  }
>  
> +static u32 drm_max_vblank_count(struct drm_device *dev, unsigned int pipe)
> +{
> +	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> +
> +	return vblank->max_vblank_count ?: dev->max_vblank_count;
> +}
> +
>  /*
>   * "No hw counter" fallback implementation of .get_vblank_counter() hook,
>   * if there is no useable hardware frame counter available.
>   */
>  static u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe)
>  {
> -	WARN_ON_ONCE(dev->max_vblank_count != 0);
> +	WARN_ON_ONCE(drm_max_vblank_count(dev, pipe) != 0);
>  	return 0;
>  }
>  
> @@ -198,6 +205,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
>  	ktime_t t_vblank;
>  	int count = DRM_TIMESTAMP_MAXRETRIES;
>  	int framedur_ns = vblank->framedur_ns;
> +	u32 max_vblank_count = drm_max_vblank_count(dev, pipe);
>  
>  	/*
>  	 * Interrupts were disabled prior to this call, so deal with counter
> @@ -216,9 +224,9 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
>  		rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq);
>  	} while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0);
>  
> -	if (dev->max_vblank_count != 0) {
> +	if (max_vblank_count) {
>  		/* trust the hw counter when it's around */
> -		diff = (cur_vblank - vblank->last) & dev->max_vblank_count;
> +		diff = (cur_vblank - vblank->last) & max_vblank_count;
>  	} else if (rc && framedur_ns) {
>  		u64 diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time));
>  
> @@ -1204,6 +1212,37 @@ void drm_crtc_vblank_reset(struct drm_crtc *crtc)
>  }
>  EXPORT_SYMBOL(drm_crtc_vblank_reset);
>  
> +/**
> + * drm_crtc_set_max_vblank_count - configure the hw max vblank counter value
> + * @crtc: CRTC in question
> + * @max_vblank_count: max hardware vblank counter value
> + *
> + * Update the maximum hardware vblank counter value for @crtc
> + * at runtime. Useful for hardware where the operation of the
> + * hardware vblank counter depends on the currently active
> + * display configuration.
> + *
> + * For example, if the hardware vblank counter does not work
> + * when a specific connector is active the maximum can be set
> + * to zero. And when that specific connector isn't active the
> + * maximum can again be set to the appropriate non-zero value.
> + *
> + * If used, must be called before drm_vblank_on().
> + */
> +void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc,
> +				   u32 max_vblank_count)
> +{
> +	struct drm_device *dev = crtc->dev;
> +	unsigned int pipe = drm_crtc_index(crtc);
> +	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> +
> +	WARN_ON(dev->max_vblank_count);
> +	WARN_ON(!READ_ONCE(vblank->inmodeset));
> +
> +	vblank->max_vblank_count = max_vblank_count;
> +}
> +EXPORT_SYMBOL(drm_crtc_set_max_vblank_count);
> +
>  /**
>   * drm_crtc_vblank_on - enable vblank events on a CRTC
>   * @crtc: CRTC in question
> diff --git a/include/drm/drm_device.h b/include/drm/drm_device.h
> index 42411b3ea0c8..45e43ce9652f 100644
> --- a/include/drm/drm_device.h
> +++ b/include/drm/drm_device.h
> @@ -184,7 +184,13 @@ struct drm_device {
>  	 * races and imprecision over longer time periods, hence exposing a
>  	 * hardware vblank counter is always recommended.
>  	 *
> -	 * If non-zeor, &drm_crtc_funcs.get_vblank_counter must be set.
> +	 * This is the statically configured device wide maximum. The driver
> +	 * can instead choose to use a runtime configurable per-crtc value
> +	 * &drm_vblank_crtc.max_vblank_count, in which case @max_vblank_count
> +	 * must be left at zero. See drm_crtc_set_max_vblank_count() on how
> +	 * to use the per-crtc value.
> +	 *
> +	 * If non-zero, &drm_crtc_funcs.get_vblank_counter must be set.
>  	 */
>  	u32 max_vblank_count;           /**< size of vblank counter register */
>  
> diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h
> index 6ad9630d4f48..e528bb2f659d 100644
> --- a/include/drm/drm_vblank.h
> +++ b/include/drm/drm_vblank.h
> @@ -128,6 +128,26 @@ struct drm_vblank_crtc {
>  	 * @last: Protected by &drm_device.vbl_lock, used for wraparound handling.
>  	 */
>  	u32 last;
> +	/**
> +	 * @max_vblank_count:
> +	 *
> +	 * Maximum value of the vblank registers for this crtc. This value +1
> +	 * will result in a wrap-around of the vblank register. It is used
> +	 * by the vblank core to handle wrap-arounds.
> +	 *
> +	 * If set to zero the vblank core will try to guess the elapsed vblanks
> +	 * between times when the vblank interrupt is disabled through
> +	 * high-precision timestamps. That approach is suffering from small
> +	 * races and imprecision over longer time periods, hence exposing a
> +	 * hardware vblank counter is always recommended.
> +	 *
> +	 * This is the runtime configurable per-crtc maximum set through
> +	 * drm_crtc_set_max_vblank_count(). If this is used the driver
> +	 * must leave the device wide &drm_device.max_vblank_count at zero.
> +	 *
> +	 * If non-zero, &drm_crtc_funcs.get_vblank_counter must be set.
> +	 */
> +	u32 max_vblank_count;
>  	/**
>  	 * @inmodeset: Tracks whether the vblank is disabled due to a modeset.
>  	 * For legacy driver bit 2 additionally tracks whether an additional
> @@ -206,4 +226,6 @@ bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
>  void drm_calc_timestamping_constants(struct drm_crtc *crtc,
>  				     const struct drm_display_mode *mode);
>  wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc);
> +void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc,
> +				   u32 max_vblank_count);
>  #endif
> -- 
> 2.18.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v2 01/15] drm/vblank: Allow dynamic per-crtc max_vblank_count
@ 2018-11-27 19:42       ` Daniel Vetter
  0 siblings, 0 replies; 66+ messages in thread
From: Daniel Vetter @ 2018-11-27 19:42 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, dri-devel, stable, Inki Dae, Daniel Vetter

On Tue, Nov 27, 2018 at 08:20:04PM +0200, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> On i965gm we need to adjust max_vblank_count dynamically
> depending on whether the TV encoder is used or not. To
> that end add a per-crtc max_vblank_count that takes
> precedence over its device wide counterpart. The driver
> can now call drm_crtc_set_max_vblank_count() to configure
> the per-crtc value before calling drm_vblank_on().
> 
> Also looks like there was some discussion about exynos needing
> similar treatment.
> 
> v2: Drop the extra max_vblank_count!=0 check for the
>     WARN(last!=current), will take care of it in i915 code (Daniel)
>     WARN_ON(!inmodeset) (Daniel)
>     WARN_ON(dev->max_vblank_count)
>     Pimp up the docs (Daniel)

Yeah I'm happy with the pile of WARN_ON here. And docs look great too.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> 
> Cc: stable@vger.kernel.org
> Cc: Inki Dae <inki.dae@samsung.com>
> Cc: Daniel Vetter <daniel@ffwll.ch>
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/drm_vblank.c | 45 +++++++++++++++++++++++++++++++++---
>  include/drm/drm_device.h     |  8 ++++++-
>  include/drm/drm_vblank.h     | 22 ++++++++++++++++++
>  3 files changed, 71 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
> index 98e091175921..cde71ee95a8f 100644
> --- a/drivers/gpu/drm/drm_vblank.c
> +++ b/drivers/gpu/drm/drm_vblank.c
> @@ -105,13 +105,20 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe,
>  	write_sequnlock(&vblank->seqlock);
>  }
>  
> +static u32 drm_max_vblank_count(struct drm_device *dev, unsigned int pipe)
> +{
> +	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> +
> +	return vblank->max_vblank_count ?: dev->max_vblank_count;
> +}
> +
>  /*
>   * "No hw counter" fallback implementation of .get_vblank_counter() hook,
>   * if there is no useable hardware frame counter available.
>   */
>  static u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe)
>  {
> -	WARN_ON_ONCE(dev->max_vblank_count != 0);
> +	WARN_ON_ONCE(drm_max_vblank_count(dev, pipe) != 0);
>  	return 0;
>  }
>  
> @@ -198,6 +205,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
>  	ktime_t t_vblank;
>  	int count = DRM_TIMESTAMP_MAXRETRIES;
>  	int framedur_ns = vblank->framedur_ns;
> +	u32 max_vblank_count = drm_max_vblank_count(dev, pipe);
>  
>  	/*
>  	 * Interrupts were disabled prior to this call, so deal with counter
> @@ -216,9 +224,9 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
>  		rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, in_vblank_irq);
>  	} while (cur_vblank != __get_vblank_counter(dev, pipe) && --count > 0);
>  
> -	if (dev->max_vblank_count != 0) {
> +	if (max_vblank_count) {
>  		/* trust the hw counter when it's around */
> -		diff = (cur_vblank - vblank->last) & dev->max_vblank_count;
> +		diff = (cur_vblank - vblank->last) & max_vblank_count;
>  	} else if (rc && framedur_ns) {
>  		u64 diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time));
>  
> @@ -1204,6 +1212,37 @@ void drm_crtc_vblank_reset(struct drm_crtc *crtc)
>  }
>  EXPORT_SYMBOL(drm_crtc_vblank_reset);
>  
> +/**
> + * drm_crtc_set_max_vblank_count - configure the hw max vblank counter value
> + * @crtc: CRTC in question
> + * @max_vblank_count: max hardware vblank counter value
> + *
> + * Update the maximum hardware vblank counter value for @crtc
> + * at runtime. Useful for hardware where the operation of the
> + * hardware vblank counter depends on the currently active
> + * display configuration.
> + *
> + * For example, if the hardware vblank counter does not work
> + * when a specific connector is active the maximum can be set
> + * to zero. And when that specific connector isn't active the
> + * maximum can again be set to the appropriate non-zero value.
> + *
> + * If used, must be called before drm_vblank_on().
> + */
> +void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc,
> +				   u32 max_vblank_count)
> +{
> +	struct drm_device *dev = crtc->dev;
> +	unsigned int pipe = drm_crtc_index(crtc);
> +	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> +
> +	WARN_ON(dev->max_vblank_count);
> +	WARN_ON(!READ_ONCE(vblank->inmodeset));
> +
> +	vblank->max_vblank_count = max_vblank_count;
> +}
> +EXPORT_SYMBOL(drm_crtc_set_max_vblank_count);
> +
>  /**
>   * drm_crtc_vblank_on - enable vblank events on a CRTC
>   * @crtc: CRTC in question
> diff --git a/include/drm/drm_device.h b/include/drm/drm_device.h
> index 42411b3ea0c8..45e43ce9652f 100644
> --- a/include/drm/drm_device.h
> +++ b/include/drm/drm_device.h
> @@ -184,7 +184,13 @@ struct drm_device {
>  	 * races and imprecision over longer time periods, hence exposing a
>  	 * hardware vblank counter is always recommended.
>  	 *
> -	 * If non-zeor, &drm_crtc_funcs.get_vblank_counter must be set.
> +	 * This is the statically configured device wide maximum. The driver
> +	 * can instead choose to use a runtime configurable per-crtc value
> +	 * &drm_vblank_crtc.max_vblank_count, in which case @max_vblank_count
> +	 * must be left at zero. See drm_crtc_set_max_vblank_count() on how
> +	 * to use the per-crtc value.
> +	 *
> +	 * If non-zero, &drm_crtc_funcs.get_vblank_counter must be set.
>  	 */
>  	u32 max_vblank_count;           /**< size of vblank counter register */
>  
> diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h
> index 6ad9630d4f48..e528bb2f659d 100644
> --- a/include/drm/drm_vblank.h
> +++ b/include/drm/drm_vblank.h
> @@ -128,6 +128,26 @@ struct drm_vblank_crtc {
>  	 * @last: Protected by &drm_device.vbl_lock, used for wraparound handling.
>  	 */
>  	u32 last;
> +	/**
> +	 * @max_vblank_count:
> +	 *
> +	 * Maximum value of the vblank registers for this crtc. This value +1
> +	 * will result in a wrap-around of the vblank register. It is used
> +	 * by the vblank core to handle wrap-arounds.
> +	 *
> +	 * If set to zero the vblank core will try to guess the elapsed vblanks
> +	 * between times when the vblank interrupt is disabled through
> +	 * high-precision timestamps. That approach is suffering from small
> +	 * races and imprecision over longer time periods, hence exposing a
> +	 * hardware vblank counter is always recommended.
> +	 *
> +	 * This is the runtime configurable per-crtc maximum set through
> +	 * drm_crtc_set_max_vblank_count(). If this is used the driver
> +	 * must leave the device wide &drm_device.max_vblank_count at zero.
> +	 *
> +	 * If non-zero, &drm_crtc_funcs.get_vblank_counter must be set.
> +	 */
> +	u32 max_vblank_count;
>  	/**
>  	 * @inmodeset: Tracks whether the vblank is disabled due to a modeset.
>  	 * For legacy driver bit 2 additionally tracks whether an additional
> @@ -206,4 +226,6 @@ bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
>  void drm_calc_timestamping_constants(struct drm_crtc *crtc,
>  				     const struct drm_display_mode *mode);
>  wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc);
> +void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc,
> +				   u32 max_vblank_count);
>  #endif
> -- 
> 2.18.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 66+ messages in thread

* [PATCH v3 02/15] drm/i915: Don't try to use the hardware frame counter with i965gm TV output
  2018-11-12 16:59 ` [PATCH 02/15] drm/i915: Don't try to use the hardware frame counter with i965gm TV output Ville Syrjala
  2018-11-27 18:21   ` [PATCH v2 " Ville Syrjala
@ 2018-11-27 20:05   ` Ville Syrjala
  2019-01-22 12:51       ` Imre Deak
  1 sibling, 1 reply; 66+ messages in thread
From: Ville Syrjala @ 2018-11-27 20:05 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel, stable, Daniel Vetter

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

On i965gm the hardware frame counter does not work when
the TV encoder is active. So let's not try to consult
the hardware frame counter in that case. Instead we'll
fall back to the timestamp based guesstimation method
used on gen2.

Note that the pipe timings generated by the TV encoder
are also rather peculiar. Apparently the pipe wants to
run at a much higher speed (related to the oversample
clock somehow it seems) but during the vertical active
period the TV encoder stalls the pipe every few lines
to keep its speed in check. But once the vertical
blanking period is reached the pipe gets to run at full
speed. This means our vblank timestamp estimates are
suspect. Fixing all that would require quite a bit
more work. This simple fix at least avoids the nasty
vblank timeouts that are happening currently.

Curiously the frame counter works just fine on i945gm
and gm45. I don't really understand what kind of mishap
occurred with the hardware design on i965gm. Sadly
I wasn't able to find any chicken bits etc. that would
fix the frame counter :(

v2: Move the zero vs. non-zero hw counter value handling
    into i915_get_vblank_counter() (Daniel)
    Use the per-crtc maximum exclusively, leaving the
    per-device maximum at zero
v3: max_vblank_count not populated yet in intel_enable_pipe()
    use intel_crtc_max_vblank_count() instead

Cc: stable@vger.kernel.org
Cc: Daniel Vetter <daniel@ffwll.ch>
Fixes: 51e31d49c890 ("drm/i915: Use generic vblank wait")
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=93782
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

fix#	_slub_broken.S
---
 drivers/gpu/drm/i915/i915_irq.c      | 27 ++++++++++------
 drivers/gpu/drm/i915/intel_display.c | 48 +++++++++++++++++++++++-----
 2 files changed, 58 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index d447d7d508f4..ab2d4eefef18 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -822,11 +822,26 @@ static void i915_enable_asle_pipestat(struct drm_i915_private *dev_priv)
 static u32 i915_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
 {
 	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
+	const struct drm_display_mode *mode = &vblank->hwmode;
 	i915_reg_t high_frame, low_frame;
 	u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal;
-	const struct drm_display_mode *mode = &dev->vblank[pipe].hwmode;
 	unsigned long irqflags;
 
+	/*
+	 * On i965gm TV output the frame counter only works up to
+	 * the point when we enable the TV encoder. After that the
+	 * frame counter ceases to work and reads zero. We need a
+	 * vblank wait before enabling the TV encoder and so we
+	 * have to enable vblank interrupts while the frame counter
+	 * is still in a working state. However the core vblank code
+	 * does not like us returning non-zero frame counter values
+	 * when we've told it that we don't have a working frame
+	 * counter. Thus we must stop non-zero values leaking out.
+	 */
+	if (!vblank->max_vblank_count)
+		return 0;
+
 	htotal = mode->crtc_htotal;
 	hsync_start = mode->crtc_hsync_start;
 	vbl_start = mode->crtc_vblank_start;
@@ -4836,16 +4851,10 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
 	if (INTEL_GEN(dev_priv) >= 8)
 		rps->pm_intrmsk_mbz |= GEN8_PMINTR_DISABLE_REDIRECT_TO_GUC;
 
-	if (IS_GEN2(dev_priv)) {
-		/* Gen2 doesn't have a hardware frame counter */
-		dev->max_vblank_count = 0;
-	} else if (IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5) {
-		dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
+	if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
 		dev->driver->get_vblank_counter = g4x_get_vblank_counter;
-	} else {
+	else if (INTEL_GEN(dev_priv) >= 3)
 		dev->driver->get_vblank_counter = i915_get_vblank_counter;
-		dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
-	}
 
 	/*
 	 * Opt out of the vblank disable timer on everything except gen2.
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index e9f4e22b2a4e..cb13eff78ad9 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1754,6 +1754,35 @@ enum pipe intel_crtc_pch_transcoder(struct intel_crtc *crtc)
 		return crtc->pipe;
 }
 
+static u32 intel_crtc_max_vblank_count(const struct intel_crtc_state *crtc_state)
+{
+	struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
+
+	/*
+	 * On i965gm the hardware frame counter reads
+	 * zero when the TV encoder is enabled :(
+	 */
+	if (IS_I965GM(dev_priv) &&
+	    (crtc_state->output_types & BIT(INTEL_OUTPUT_TVOUT)))
+		return 0;
+
+	if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
+		return 0xffffffff; /* full 32 bit counter */
+	else if (INTEL_GEN(dev_priv) >= 3)
+		return 0xffffff; /* only 24 bits of frame count */
+	else
+		return 0; /* Gen2 doesn't have a hardware frame counter */
+}
+
+static void intel_crtc_vblank_on(const struct intel_crtc_state *crtc_state)
+{
+	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+
+	drm_crtc_set_max_vblank_count(&crtc->base,
+				      intel_crtc_max_vblank_count(crtc_state));
+	drm_crtc_vblank_on(&crtc->base);
+}
+
 static void intel_enable_pipe(const struct intel_crtc_state *new_crtc_state)
 {
 	struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc);
@@ -1806,7 +1835,7 @@ static void intel_enable_pipe(const struct intel_crtc_state *new_crtc_state)
 	 * when it's derived from the timestamps. So let's wait for the
 	 * pipe to start properly before we call drm_crtc_vblank_on()
 	 */
-	if (dev_priv->drm.max_vblank_count == 0)
+	if (intel_crtc_max_vblank_count(new_crtc_state) == 0)
 		intel_wait_for_pipe_scanline_moving(crtc);
 }
 
@@ -5617,7 +5646,7 @@ static void ironlake_crtc_enable(struct intel_crtc_state *pipe_config,
 		ironlake_pch_enable(old_intel_state, pipe_config);
 
 	assert_vblank_disabled(crtc);
-	drm_crtc_vblank_on(crtc);
+	intel_crtc_vblank_on(pipe_config);
 
 	intel_encoders_enable(crtc, pipe_config, old_state);
 
@@ -5774,7 +5803,7 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
 		intel_ddi_set_vc_payload_alloc(pipe_config, true);
 
 	assert_vblank_disabled(crtc);
-	drm_crtc_vblank_on(crtc);
+	intel_crtc_vblank_on(pipe_config);
 
 	intel_encoders_enable(crtc, pipe_config, old_state);
 
@@ -6114,7 +6143,7 @@ static void valleyview_crtc_enable(struct intel_crtc_state *pipe_config,
 	intel_enable_pipe(pipe_config);
 
 	assert_vblank_disabled(crtc);
-	drm_crtc_vblank_on(crtc);
+	intel_crtc_vblank_on(pipe_config);
 
 	intel_encoders_enable(crtc, pipe_config, old_state);
 }
@@ -6173,7 +6202,7 @@ static void i9xx_crtc_enable(struct intel_crtc_state *pipe_config,
 	intel_enable_pipe(pipe_config);
 
 	assert_vblank_disabled(crtc);
-	drm_crtc_vblank_on(crtc);
+	intel_crtc_vblank_on(pipe_config);
 
 	intel_encoders_enable(crtc, pipe_config, old_state);
 }
@@ -12653,8 +12682,9 @@ static int intel_atomic_prepare_commit(struct drm_device *dev,
 u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc)
 {
 	struct drm_device *dev = crtc->base.dev;
+	struct drm_vblank_crtc *vblank = &dev->vblank[drm_crtc_index(&crtc->base)];
 
-	if (!dev->max_vblank_count)
+	if (!vblank->max_vblank_count)
 		return (u32)drm_crtc_accurate_vblank_count(&crtc->base);
 
 	return dev->driver->get_vblank_counter(dev, crtc->pipe);
@@ -15736,10 +15766,12 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
 	 * waits, so we need vblank interrupts restored beforehand.
 	 */
 	for_each_intel_crtc(&dev_priv->drm, crtc) {
+		crtc_state = to_intel_crtc_state(crtc->base.state);
+
 		drm_crtc_vblank_reset(&crtc->base);
 
-		if (crtc->base.state->active)
-			drm_crtc_vblank_on(&crtc->base);
+		if (crtc_state->base.active)
+			intel_crtc_vblank_on(crtc_state);
 	}
 
 	intel_sanitize_plane_mapping(dev_priv);
-- 
2.18.1

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* ✗ Fi.CI.SPARSE: warning for drm/i915: Fix TV encoder support (rev5)
  2018-11-12 16:59 [PATCH 00/15] drm/i915: Fix TV encoder support Ville Syrjala
                   ` (21 preceding siblings ...)
  2018-11-27 19:23 ` ✗ Fi.CI.BAT: failure " Patchwork
@ 2018-11-27 20:37 ` Patchwork
  2018-11-27 20:48 ` ✓ Fi.CI.BAT: success " Patchwork
  2018-11-28  5:33 ` ✓ Fi.CI.IGT: " Patchwork
  24 siblings, 0 replies; 66+ messages in thread
From: Patchwork @ 2018-11-27 20:37 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx

== Series Details ==

Series: drm/i915: Fix TV encoder support (rev5)
URL   : https://patchwork.freedesktop.org/series/52378/
State : warning

== Summary ==

$ dim sparse origin/drm-tip
Sparse version: v0.5.2
Commit: drm/vblank: Allow dynamic per-crtc max_vblank_count
Okay!

Commit: drm/i915: Don't try to use the hardware frame counter with i965gm TV output
Okay!

Commit: drm/i915/tv: Fix interlaced ysize calculation
Okay!

Commit: drm/i915/tv: Fix tv mode clocks
Okay!

Commit: drm/i915/tv: Store the TV oversampling factor in the TV mode
Okay!

Commit: drm/i915/tv: Use bools where appropriate
Okay!

Commit: drm/i915/tv: Nuke silly 0 initialzation of xpos/ypos
Okay!

Commit: drm/i915/tv: Deobfuscate preferred mode selection
Okay!

Commit: drm/i915/tv: Use drm_mode_set_name() to name TV modes
Okay!

Commit: drm/i915/tv: Make TV mode autoselection actually useable
Okay!

Commit: drm/i915/tv: Nuke reported_modes[]
Okay!

Commit: drm/i915/tv: Add 1080p30/50/60 TV modes
Okay!

Commit: drm/i915/tv: Generate better pipe timings for TV encoder
Okay!

Commit: drm/i915/tv: Fix >1024 modes on gen3
+drivers/gpu/drm/i915/intel_tv.c:889:28: warning: symbol 'intel_tv_connector_duplicate_state' was not declared. Should it be static?

Commit: drm/i915/tv: Filter out >1024 wide modes that would need vertical scaling on gen3
Okay!

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 66+ messages in thread

* ✓ Fi.CI.BAT: success for drm/i915: Fix TV encoder support (rev5)
  2018-11-12 16:59 [PATCH 00/15] drm/i915: Fix TV encoder support Ville Syrjala
                   ` (22 preceding siblings ...)
  2018-11-27 20:37 ` ✗ Fi.CI.SPARSE: warning for drm/i915: Fix TV encoder support (rev5) Patchwork
@ 2018-11-27 20:48 ` Patchwork
  2018-11-28  5:33 ` ✓ Fi.CI.IGT: " Patchwork
  24 siblings, 0 replies; 66+ messages in thread
From: Patchwork @ 2018-11-27 20:48 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx

== Series Details ==

Series: drm/i915: Fix TV encoder support (rev5)
URL   : https://patchwork.freedesktop.org/series/52378/
State : success

== Summary ==

= CI Bug Log - changes from CI_DRM_5211 -> Patchwork_10920 =

== Summary - SUCCESS ==

  No regressions found.

  External URL: https://patchwork.freedesktop.org/api/1.0/series/52378/revisions/5/mbox/

== Known issues ==

  Here are the changes found in Patchwork_10920 that come from known issues:

  === IGT changes ===

    ==== Issues hit ====

    igt@gem_exec_suspend@basic-s4-devices:
      fi-ivb-3520m:       PASS -> FAIL ([fdo#108880])

    igt@kms_flip@basic-flip-vs-dpms:
      fi-skl-6700hq:      PASS -> DMESG-WARN ([fdo#105998])

    igt@kms_frontbuffer_tracking@basic:
      {fi-icl-u3}:        PASS -> FAIL ([fdo#103167])

    
    ==== Possible fixes ====

    igt@i915_module_load@reload:
      fi-blb-e6850:       INCOMPLETE ([fdo#107718]) -> PASS

    igt@i915_selftest@live_hangcheck:
      fi-cfl-8109u:       INCOMPLETE ([fdo#106070]) -> PASS

    igt@kms_frontbuffer_tracking@basic:
      fi-hsw-peppy:       DMESG-WARN ([fdo#102614]) -> PASS

    igt@kms_pipe_crc_basic@read-crc-pipe-a:
      fi-byt-clapper:     FAIL ([fdo#107362]) -> PASS

    igt@kms_pipe_crc_basic@suspend-read-crc-pipe-a:
      fi-byt-clapper:     FAIL ([fdo#103191], [fdo#107362]) -> PASS

    igt@kms_pipe_crc_basic@suspend-read-crc-pipe-b:
      fi-cfl-8109u:       DMESG-WARN ([fdo#106107]) -> PASS

    
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  fdo#102614 https://bugs.freedesktop.org/show_bug.cgi?id=102614
  fdo#103167 https://bugs.freedesktop.org/show_bug.cgi?id=103167
  fdo#103191 https://bugs.freedesktop.org/show_bug.cgi?id=103191
  fdo#105998 https://bugs.freedesktop.org/show_bug.cgi?id=105998
  fdo#106070 https://bugs.freedesktop.org/show_bug.cgi?id=106070
  fdo#106107 https://bugs.freedesktop.org/show_bug.cgi?id=106107
  fdo#107362 https://bugs.freedesktop.org/show_bug.cgi?id=107362
  fdo#107718 https://bugs.freedesktop.org/show_bug.cgi?id=107718
  fdo#108880 https://bugs.freedesktop.org/show_bug.cgi?id=108880


== Participating hosts (51 -> 45) ==

  Missing    (6): fi-ilk-m540 fi-hsw-4200u fi-byt-squawks fi-bsw-cyan fi-ctg-p8600 fi-snb-2600 


== Build changes ==

    * Linux: CI_DRM_5211 -> Patchwork_10920

  CI_DRM_5211: b6ba4ad91b7c6c4341c40a05b0326470e0c293cb @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_4732: eae5c3587e56abc581af9b59060cd316df2caa08 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  Patchwork_10920: c07c3bae1ed1cb76147b294d469eb6a59e241a87 @ git://anongit.freedesktop.org/gfx-ci/linux


== Linux commits ==

c07c3bae1ed1 drm/i915/tv: Filter out >1024 wide modes that would need vertical scaling on gen3
58f23f67a2d0 drm/i915/tv: Fix >1024 modes on gen3
9f80e4bca57d drm/i915/tv: Generate better pipe timings for TV encoder
090d9895cab2 drm/i915/tv: Add 1080p30/50/60 TV modes
3938af790529 drm/i915/tv: Nuke reported_modes[]
3843e6fbfd73 drm/i915/tv: Make TV mode autoselection actually useable
554460968989 drm/i915/tv: Use drm_mode_set_name() to name TV modes
9a0d12af09b2 drm/i915/tv: Deobfuscate preferred mode selection
dbcb06f0dbb5 drm/i915/tv: Nuke silly 0 initialzation of xpos/ypos
4198959702ba drm/i915/tv: Use bools where appropriate
57d0c552757f drm/i915/tv: Store the TV oversampling factor in the TV mode
0e2acc87b153 drm/i915/tv: Fix tv mode clocks
c2ee18a09a71 drm/i915/tv: Fix interlaced ysize calculation
18faa03a3c3e drm/i915: Don't try to use the hardware frame counter with i965gm TV output
af05bf07d808 drm/vblank: Allow dynamic per-crtc max_vblank_count

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_10920/
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 66+ messages in thread

* ✓ Fi.CI.IGT: success for drm/i915: Fix TV encoder support (rev5)
  2018-11-12 16:59 [PATCH 00/15] drm/i915: Fix TV encoder support Ville Syrjala
                   ` (23 preceding siblings ...)
  2018-11-27 20:48 ` ✓ Fi.CI.BAT: success " Patchwork
@ 2018-11-28  5:33 ` Patchwork
  24 siblings, 0 replies; 66+ messages in thread
From: Patchwork @ 2018-11-28  5:33 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

== Series Details ==

Series: drm/i915: Fix TV encoder support (rev5)
URL   : https://patchwork.freedesktop.org/series/52378/
State : success

== Summary ==

= CI Bug Log - changes from CI_DRM_5211_full -> Patchwork_10920_full =

== Summary - WARNING ==

  Minor unknown changes coming with Patchwork_10920_full need to be verified
  manually.
  
  If you think the reported changes have nothing to do with the changes
  introduced in Patchwork_10920_full, please notify your bug team to allow them
  to document this new failure mode, which will reduce false positives in CI.

  

== Possible new issues ==

  Here are the unknown changes that may have been introduced in Patchwork_10920_full:

  === IGT changes ===

    ==== Warnings ====

    igt@kms_chv_cursor_fail@pipe-b-64x64-top-edge:
      shard-snb:          SKIP -> PASS +1

    igt@pm_rc6_residency@rc6-accuracy:
      shard-kbl:          SKIP -> PASS

    
== Known issues ==

  Here are the changes found in Patchwork_10920_full that come from known issues:

  === IGT changes ===

    ==== Issues hit ====

    igt@debugfs_test@read_all_entries_display_off:
      shard-skl:          PASS -> INCOMPLETE ([fdo#104108])

    igt@gem_exec_schedule@pi-ringfull-blt:
      shard-skl:          NOTRUN -> FAIL ([fdo#103158])

    igt@gem_exec_schedule@pi-ringfull-vebox:
      {shard-iclb}:       NOTRUN -> FAIL ([fdo#103158])

    igt@gem_exec_suspend@basic-s3:
      shard-kbl:          PASS -> INCOMPLETE ([fdo#103665])

    igt@gem_ppgtt@blt-vs-render-ctxn:
      shard-skl:          PASS -> TIMEOUT ([fdo#108039])

    igt@i915_suspend@shrink:
      shard-skl:          NOTRUN -> INCOMPLETE ([fdo#106886])

    igt@kms_atomic_transition@1x-modeset-transitions-fencing:
      shard-kbl:          PASS -> DMESG-WARN ([fdo#103313], [fdo#105345])

    igt@kms_available_modes_crc@available_mode_test_crc:
      shard-apl:          PASS -> FAIL ([fdo#106641])

    igt@kms_busy@extended-modeset-hang-newfb-with-reset-render-c:
      shard-skl:          NOTRUN -> DMESG-WARN ([fdo#107956])

    igt@kms_chv_cursor_fail@pipe-c-128x128-right-edge:
      shard-skl:          NOTRUN -> FAIL ([fdo#104671])

    igt@kms_cursor_crc@cursor-256x85-onscreen:
      shard-apl:          PASS -> FAIL ([fdo#103232]) +3

    igt@kms_cursor_crc@cursor-64x21-random:
      {shard-iclb}:       NOTRUN -> FAIL ([fdo#103232])

    igt@kms_flip@dpms-vs-vblank-race:
      shard-apl:          PASS -> FAIL ([fdo#103060])

    igt@kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-draw-mmap-cpu:
      shard-apl:          PASS -> FAIL ([fdo#103167]) +3

    igt@kms_frontbuffer_tracking@fbc-2p-primscrn-spr-indfb-fullscreen:
      shard-glk:          PASS -> FAIL ([fdo#103167])

    igt@kms_frontbuffer_tracking@fbcpsr-1p-primscrn-spr-indfb-draw-mmap-wc:
      {shard-iclb}:       PASS -> FAIL ([fdo#103167])

    igt@kms_frontbuffer_tracking@fbcpsr-1p-primscrn-spr-indfb-draw-render:
      shard-skl:          NOTRUN -> FAIL ([fdo#103167]) +2

    igt@kms_plane_alpha_blend@pipe-a-alpha-transparant-fb:
      shard-skl:          NOTRUN -> FAIL ([fdo#108145]) +1

    igt@kms_plane_alpha_blend@pipe-c-coverage-7efc:
      shard-skl:          NOTRUN -> FAIL ([fdo#107815])

    igt@kms_plane_multiple@atomic-pipe-b-tiling-x:
      shard-glk:          PASS -> FAIL ([fdo#103166])

    igt@kms_plane_multiple@atomic-pipe-b-tiling-y:
      shard-apl:          PASS -> FAIL ([fdo#103166]) +3

    igt@kms_plane_multiple@atomic-pipe-c-tiling-y:
      {shard-iclb}:       PASS -> FAIL ([fdo#103166])

    igt@pm_rpm@reg-read-ioctl:
      {shard-iclb}:       PASS -> DMESG-WARN ([fdo#108654]) +1

    igt@pm_rpm@sysfs-read:
      {shard-iclb}:       PASS -> INCOMPLETE ([fdo#107713], [fdo#108840])

    
    ==== Possible fixes ====

    igt@kms_chv_cursor_fail@pipe-a-128x128-bottom-edge:
      shard-skl:          FAIL ([fdo#104671]) -> PASS

    igt@kms_color@pipe-a-legacy-gamma:
      shard-skl:          FAIL ([fdo#104782], [fdo#108145]) -> PASS

    igt@kms_cursor_crc@cursor-64x64-dpms:
      shard-apl:          FAIL ([fdo#103232]) -> PASS +1

    igt@kms_cursor_crc@cursor-64x64-offscreen:
      shard-skl:          FAIL ([fdo#103232]) -> PASS +1

    igt@kms_cursor_legacy@cursora-vs-flipa-toggle:
      shard-glk:          DMESG-WARN ([fdo#105763], [fdo#106538]) -> PASS

    igt@kms_draw_crc@draw-method-rgb565-mmap-gtt-xtiled:
      shard-glk:          FAIL ([fdo#103184]) -> PASS

    igt@kms_flip@flip-vs-expired-vblank:
      shard-skl:          FAIL ([fdo#105363]) -> PASS

    igt@kms_flip@flip-vs-expired-vblank-interruptible:
      shard-apl:          FAIL ([fdo#102887], [fdo#105363]) -> PASS

    igt@kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-move:
      {shard-iclb}:       FAIL ([fdo#103167]) -> PASS +7

    igt@kms_frontbuffer_tracking@fbcpsr-1p-primscrn-cur-indfb-draw-blt:
      shard-skl:          FAIL ([fdo#105682]) -> PASS

    igt@kms_frontbuffer_tracking@psr-1p-offscren-pri-indfb-draw-mmap-gtt:
      shard-skl:          FAIL ([fdo#103167]) -> PASS +3

    igt@kms_plane@plane-position-covered-pipe-c-planes:
      shard-apl:          FAIL ([fdo#103166]) -> PASS +1

    igt@kms_plane_alpha_blend@pipe-a-coverage-7efc:
      shard-skl:          FAIL ([fdo#107815], [fdo#108145]) -> PASS

    igt@kms_plane_multiple@atomic-pipe-b-tiling-yf:
      {shard-iclb}:       FAIL ([fdo#103166]) -> PASS +1

    igt@kms_setmode@basic:
      shard-kbl:          FAIL ([fdo#99912]) -> PASS

    igt@pm_rpm@fences-dpms:
      shard-skl:          INCOMPLETE ([fdo#107807]) -> PASS +2

    igt@pm_rpm@system-suspend-execbuf:
      shard-kbl:          INCOMPLETE ([fdo#103665], [fdo#107807]) -> PASS

    
    ==== Warnings ====

    igt@i915_suspend@shrink:
      shard-apl:          DMESG-WARN ([fdo#108784]) -> INCOMPLETE ([fdo#103927], [fdo#106886])

    
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  fdo#102887 https://bugs.freedesktop.org/show_bug.cgi?id=102887
  fdo#103060 https://bugs.freedesktop.org/show_bug.cgi?id=103060
  fdo#103158 https://bugs.freedesktop.org/show_bug.cgi?id=103158
  fdo#103166 https://bugs.freedesktop.org/show_bug.cgi?id=103166
  fdo#103167 https://bugs.freedesktop.org/show_bug.cgi?id=103167
  fdo#103184 https://bugs.freedesktop.org/show_bug.cgi?id=103184
  fdo#103232 https://bugs.freedesktop.org/show_bug.cgi?id=103232
  fdo#103313 https://bugs.freedesktop.org/show_bug.cgi?id=103313
  fdo#103665 https://bugs.freedesktop.org/show_bug.cgi?id=103665
  fdo#103927 https://bugs.freedesktop.org/show_bug.cgi?id=103927
  fdo#104108 https://bugs.freedesktop.org/show_bug.cgi?id=104108
  fdo#104671 https://bugs.freedesktop.org/show_bug.cgi?id=104671
  fdo#104782 https://bugs.freedesktop.org/show_bug.cgi?id=104782
  fdo#105345 https://bugs.freedesktop.org/show_bug.cgi?id=105345
  fdo#105363 https://bugs.freedesktop.org/show_bug.cgi?id=105363
  fdo#105682 https://bugs.freedesktop.org/show_bug.cgi?id=105682
  fdo#105763 https://bugs.freedesktop.org/show_bug.cgi?id=105763
  fdo#106538 https://bugs.freedesktop.org/show_bug.cgi?id=106538
  fdo#106641 https://bugs.freedesktop.org/show_bug.cgi?id=106641
  fdo#106886 https://bugs.freedesktop.org/show_bug.cgi?id=106886
  fdo#107713 https://bugs.freedesktop.org/show_bug.cgi?id=107713
  fdo#107807 https://bugs.freedesktop.org/show_bug.cgi?id=107807
  fdo#107815 https://bugs.freedesktop.org/show_bug.cgi?id=107815
  fdo#107956 https://bugs.freedesktop.org/show_bug.cgi?id=107956
  fdo#108039 https://bugs.freedesktop.org/show_bug.cgi?id=108039
  fdo#108145 https://bugs.freedesktop.org/show_bug.cgi?id=108145
  fdo#108654 https://bugs.freedesktop.org/show_bug.cgi?id=108654
  fdo#108784 https://bugs.freedesktop.org/show_bug.cgi?id=108784
  fdo#108840 https://bugs.freedesktop.org/show_bug.cgi?id=108840
  fdo#99912 https://bugs.freedesktop.org/show_bug.cgi?id=99912


== Participating hosts (7 -> 7) ==

  No changes in participating hosts


== Build changes ==

    * Linux: CI_DRM_5211 -> Patchwork_10920

  CI_DRM_5211: b6ba4ad91b7c6c4341c40a05b0326470e0c293cb @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_4732: eae5c3587e56abc581af9b59060cd316df2caa08 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  Patchwork_10920: c07c3bae1ed1cb76147b294d469eb6a59e241a87 @ git://anongit.freedesktop.org/gfx-ci/linux
  piglit_4509: fdc5a4ca11124ab8413c7988896eec4c97336694 @ git://anongit.freedesktop.org/piglit

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_10920/shards.html
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v3 02/15] drm/i915: Don't try to use the hardware frame counter with i965gm TV output
  2018-11-27 20:05   ` [PATCH v3 " Ville Syrjala
@ 2019-01-22 12:51       ` Imre Deak
  0 siblings, 0 replies; 66+ messages in thread
From: Imre Deak @ 2019-01-22 12:51 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, stable, dri-devel

On Tue, Nov 27, 2018 at 10:05:50PM +0200, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> On i965gm the hardware frame counter does not work when
> the TV encoder is active. So let's not try to consult
> the hardware frame counter in that case. Instead we'll
> fall back to the timestamp based guesstimation method
> used on gen2.
> 
> Note that the pipe timings generated by the TV encoder
> are also rather peculiar. Apparently the pipe wants to
> run at a much higher speed (related to the oversample
> clock somehow it seems) but during the vertical active
> period the TV encoder stalls the pipe every few lines
> to keep its speed in check. But once the vertical
> blanking period is reached the pipe gets to run at full
> speed. This means our vblank timestamp estimates are
> suspect. Fixing all that would require quite a bit
> more work. This simple fix at least avoids the nasty
> vblank timeouts that are happening currently.
> 
> Curiously the frame counter works just fine on i945gm
> and gm45. I don't really understand what kind of mishap
> occurred with the hardware design on i965gm. Sadly
> I wasn't able to find any chicken bits etc. that would
> fix the frame counter :(
> 
> v2: Move the zero vs. non-zero hw counter value handling
>     into i915_get_vblank_counter() (Daniel)
>     Use the per-crtc maximum exclusively, leaving the
>     per-device maximum at zero
> v3: max_vblank_count not populated yet in intel_enable_pipe()
>     use intel_crtc_max_vblank_count() instead
> 
> Cc: stable@vger.kernel.org
> Cc: Daniel Vetter <daniel@ffwll.ch>
> Fixes: 51e31d49c890 ("drm/i915: Use generic vblank wait")
> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=93782
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> fix#	_slub_broken.S
  ^ some remnant

Reviewed-by: Imre Deak <imre.deak@intel.com>

> ---
>  drivers/gpu/drm/i915/i915_irq.c      | 27 ++++++++++------
>  drivers/gpu/drm/i915/intel_display.c | 48 +++++++++++++++++++++++-----
>  2 files changed, 58 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index d447d7d508f4..ab2d4eefef18 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -822,11 +822,26 @@ static void i915_enable_asle_pipestat(struct drm_i915_private *dev_priv)
>  static u32 i915_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
>  {
>  	struct drm_i915_private *dev_priv = to_i915(dev);
> +	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> +	const struct drm_display_mode *mode = &vblank->hwmode;
>  	i915_reg_t high_frame, low_frame;
>  	u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal;
> -	const struct drm_display_mode *mode = &dev->vblank[pipe].hwmode;
>  	unsigned long irqflags;
>  
> +	/*
> +	 * On i965gm TV output the frame counter only works up to
> +	 * the point when we enable the TV encoder. After that the
> +	 * frame counter ceases to work and reads zero. We need a
> +	 * vblank wait before enabling the TV encoder and so we
> +	 * have to enable vblank interrupts while the frame counter
> +	 * is still in a working state. However the core vblank code
> +	 * does not like us returning non-zero frame counter values
> +	 * when we've told it that we don't have a working frame
> +	 * counter. Thus we must stop non-zero values leaking out.
> +	 */
> +	if (!vblank->max_vblank_count)
> +		return 0;
> +
>  	htotal = mode->crtc_htotal;
>  	hsync_start = mode->crtc_hsync_start;
>  	vbl_start = mode->crtc_vblank_start;
> @@ -4836,16 +4851,10 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
>  	if (INTEL_GEN(dev_priv) >= 8)
>  		rps->pm_intrmsk_mbz |= GEN8_PMINTR_DISABLE_REDIRECT_TO_GUC;
>  
> -	if (IS_GEN2(dev_priv)) {
> -		/* Gen2 doesn't have a hardware frame counter */
> -		dev->max_vblank_count = 0;
> -	} else if (IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5) {
> -		dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
> +	if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
>  		dev->driver->get_vblank_counter = g4x_get_vblank_counter;
> -	} else {
> +	else if (INTEL_GEN(dev_priv) >= 3)
>  		dev->driver->get_vblank_counter = i915_get_vblank_counter;
> -		dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
> -	}
>  
>  	/*
>  	 * Opt out of the vblank disable timer on everything except gen2.
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index e9f4e22b2a4e..cb13eff78ad9 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -1754,6 +1754,35 @@ enum pipe intel_crtc_pch_transcoder(struct intel_crtc *crtc)
>  		return crtc->pipe;
>  }
>  
> +static u32 intel_crtc_max_vblank_count(const struct intel_crtc_state *crtc_state)
> +{
> +	struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
> +
> +	/*
> +	 * On i965gm the hardware frame counter reads
> +	 * zero when the TV encoder is enabled :(
> +	 */
> +	if (IS_I965GM(dev_priv) &&
> +	    (crtc_state->output_types & BIT(INTEL_OUTPUT_TVOUT)))
> +		return 0;
> +
> +	if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
> +		return 0xffffffff; /* full 32 bit counter */
> +	else if (INTEL_GEN(dev_priv) >= 3)
> +		return 0xffffff; /* only 24 bits of frame count */
> +	else
> +		return 0; /* Gen2 doesn't have a hardware frame counter */
> +}
> +
> +static void intel_crtc_vblank_on(const struct intel_crtc_state *crtc_state)
> +{
> +	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
> +
> +	drm_crtc_set_max_vblank_count(&crtc->base,
> +				      intel_crtc_max_vblank_count(crtc_state));
> +	drm_crtc_vblank_on(&crtc->base);
> +}
> +
>  static void intel_enable_pipe(const struct intel_crtc_state *new_crtc_state)
>  {
>  	struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc);
> @@ -1806,7 +1835,7 @@ static void intel_enable_pipe(const struct intel_crtc_state *new_crtc_state)
>  	 * when it's derived from the timestamps. So let's wait for the
>  	 * pipe to start properly before we call drm_crtc_vblank_on()
>  	 */
> -	if (dev_priv->drm.max_vblank_count == 0)
> +	if (intel_crtc_max_vblank_count(new_crtc_state) == 0)
>  		intel_wait_for_pipe_scanline_moving(crtc);
>  }
>  
> @@ -5617,7 +5646,7 @@ static void ironlake_crtc_enable(struct intel_crtc_state *pipe_config,
>  		ironlake_pch_enable(old_intel_state, pipe_config);
>  
>  	assert_vblank_disabled(crtc);
> -	drm_crtc_vblank_on(crtc);
> +	intel_crtc_vblank_on(pipe_config);
>  
>  	intel_encoders_enable(crtc, pipe_config, old_state);
>  
> @@ -5774,7 +5803,7 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
>  		intel_ddi_set_vc_payload_alloc(pipe_config, true);
>  
>  	assert_vblank_disabled(crtc);
> -	drm_crtc_vblank_on(crtc);
> +	intel_crtc_vblank_on(pipe_config);
>  
>  	intel_encoders_enable(crtc, pipe_config, old_state);
>  
> @@ -6114,7 +6143,7 @@ static void valleyview_crtc_enable(struct intel_crtc_state *pipe_config,
>  	intel_enable_pipe(pipe_config);
>  
>  	assert_vblank_disabled(crtc);
> -	drm_crtc_vblank_on(crtc);
> +	intel_crtc_vblank_on(pipe_config);
>  
>  	intel_encoders_enable(crtc, pipe_config, old_state);
>  }
> @@ -6173,7 +6202,7 @@ static void i9xx_crtc_enable(struct intel_crtc_state *pipe_config,
>  	intel_enable_pipe(pipe_config);
>  
>  	assert_vblank_disabled(crtc);
> -	drm_crtc_vblank_on(crtc);
> +	intel_crtc_vblank_on(pipe_config);
>  
>  	intel_encoders_enable(crtc, pipe_config, old_state);
>  }
> @@ -12653,8 +12682,9 @@ static int intel_atomic_prepare_commit(struct drm_device *dev,
>  u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc)
>  {
>  	struct drm_device *dev = crtc->base.dev;
> +	struct drm_vblank_crtc *vblank = &dev->vblank[drm_crtc_index(&crtc->base)];
>  
> -	if (!dev->max_vblank_count)
> +	if (!vblank->max_vblank_count)
>  		return (u32)drm_crtc_accurate_vblank_count(&crtc->base);
>  
>  	return dev->driver->get_vblank_counter(dev, crtc->pipe);
> @@ -15736,10 +15766,12 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
>  	 * waits, so we need vblank interrupts restored beforehand.
>  	 */
>  	for_each_intel_crtc(&dev_priv->drm, crtc) {
> +		crtc_state = to_intel_crtc_state(crtc->base.state);
> +
>  		drm_crtc_vblank_reset(&crtc->base);
>  
> -		if (crtc->base.state->active)
> -			drm_crtc_vblank_on(&crtc->base);
> +		if (crtc_state->base.active)
> +			intel_crtc_vblank_on(crtc_state);
>  	}
>  
>  	intel_sanitize_plane_mapping(dev_priv);
> -- 
> 2.18.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH v3 02/15] drm/i915: Don't try to use the hardware frame counter with i965gm TV output
@ 2019-01-22 12:51       ` Imre Deak
  0 siblings, 0 replies; 66+ messages in thread
From: Imre Deak @ 2019-01-22 12:51 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, dri-devel, stable

On Tue, Nov 27, 2018 at 10:05:50PM +0200, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> On i965gm the hardware frame counter does not work when
> the TV encoder is active. So let's not try to consult
> the hardware frame counter in that case. Instead we'll
> fall back to the timestamp based guesstimation method
> used on gen2.
> 
> Note that the pipe timings generated by the TV encoder
> are also rather peculiar. Apparently the pipe wants to
> run at a much higher speed (related to the oversample
> clock somehow it seems) but during the vertical active
> period the TV encoder stalls the pipe every few lines
> to keep its speed in check. But once the vertical
> blanking period is reached the pipe gets to run at full
> speed. This means our vblank timestamp estimates are
> suspect. Fixing all that would require quite a bit
> more work. This simple fix at least avoids the nasty
> vblank timeouts that are happening currently.
> 
> Curiously the frame counter works just fine on i945gm
> and gm45. I don't really understand what kind of mishap
> occurred with the hardware design on i965gm. Sadly
> I wasn't able to find any chicken bits etc. that would
> fix the frame counter :(
> 
> v2: Move the zero vs. non-zero hw counter value handling
>     into i915_get_vblank_counter() (Daniel)
>     Use the per-crtc maximum exclusively, leaving the
>     per-device maximum at zero
> v3: max_vblank_count not populated yet in intel_enable_pipe()
>     use intel_crtc_max_vblank_count() instead
> 
> Cc: stable@vger.kernel.org
> Cc: Daniel Vetter <daniel@ffwll.ch>
> Fixes: 51e31d49c890 ("drm/i915: Use generic vblank wait")
> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=93782
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> fix#	_slub_broken.S
  ^ some remnant

Reviewed-by: Imre Deak <imre.deak@intel.com>

> ---
>  drivers/gpu/drm/i915/i915_irq.c      | 27 ++++++++++------
>  drivers/gpu/drm/i915/intel_display.c | 48 +++++++++++++++++++++++-----
>  2 files changed, 58 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index d447d7d508f4..ab2d4eefef18 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -822,11 +822,26 @@ static void i915_enable_asle_pipestat(struct drm_i915_private *dev_priv)
>  static u32 i915_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
>  {
>  	struct drm_i915_private *dev_priv = to_i915(dev);
> +	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
> +	const struct drm_display_mode *mode = &vblank->hwmode;
>  	i915_reg_t high_frame, low_frame;
>  	u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal;
> -	const struct drm_display_mode *mode = &dev->vblank[pipe].hwmode;
>  	unsigned long irqflags;
>  
> +	/*
> +	 * On i965gm TV output the frame counter only works up to
> +	 * the point when we enable the TV encoder. After that the
> +	 * frame counter ceases to work and reads zero. We need a
> +	 * vblank wait before enabling the TV encoder and so we
> +	 * have to enable vblank interrupts while the frame counter
> +	 * is still in a working state. However the core vblank code
> +	 * does not like us returning non-zero frame counter values
> +	 * when we've told it that we don't have a working frame
> +	 * counter. Thus we must stop non-zero values leaking out.
> +	 */
> +	if (!vblank->max_vblank_count)
> +		return 0;
> +
>  	htotal = mode->crtc_htotal;
>  	hsync_start = mode->crtc_hsync_start;
>  	vbl_start = mode->crtc_vblank_start;
> @@ -4836,16 +4851,10 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
>  	if (INTEL_GEN(dev_priv) >= 8)
>  		rps->pm_intrmsk_mbz |= GEN8_PMINTR_DISABLE_REDIRECT_TO_GUC;
>  
> -	if (IS_GEN2(dev_priv)) {
> -		/* Gen2 doesn't have a hardware frame counter */
> -		dev->max_vblank_count = 0;
> -	} else if (IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5) {
> -		dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
> +	if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
>  		dev->driver->get_vblank_counter = g4x_get_vblank_counter;
> -	} else {
> +	else if (INTEL_GEN(dev_priv) >= 3)
>  		dev->driver->get_vblank_counter = i915_get_vblank_counter;
> -		dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
> -	}
>  
>  	/*
>  	 * Opt out of the vblank disable timer on everything except gen2.
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index e9f4e22b2a4e..cb13eff78ad9 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -1754,6 +1754,35 @@ enum pipe intel_crtc_pch_transcoder(struct intel_crtc *crtc)
>  		return crtc->pipe;
>  }
>  
> +static u32 intel_crtc_max_vblank_count(const struct intel_crtc_state *crtc_state)
> +{
> +	struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
> +
> +	/*
> +	 * On i965gm the hardware frame counter reads
> +	 * zero when the TV encoder is enabled :(
> +	 */
> +	if (IS_I965GM(dev_priv) &&
> +	    (crtc_state->output_types & BIT(INTEL_OUTPUT_TVOUT)))
> +		return 0;
> +
> +	if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
> +		return 0xffffffff; /* full 32 bit counter */
> +	else if (INTEL_GEN(dev_priv) >= 3)
> +		return 0xffffff; /* only 24 bits of frame count */
> +	else
> +		return 0; /* Gen2 doesn't have a hardware frame counter */
> +}
> +
> +static void intel_crtc_vblank_on(const struct intel_crtc_state *crtc_state)
> +{
> +	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
> +
> +	drm_crtc_set_max_vblank_count(&crtc->base,
> +				      intel_crtc_max_vblank_count(crtc_state));
> +	drm_crtc_vblank_on(&crtc->base);
> +}
> +
>  static void intel_enable_pipe(const struct intel_crtc_state *new_crtc_state)
>  {
>  	struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc);
> @@ -1806,7 +1835,7 @@ static void intel_enable_pipe(const struct intel_crtc_state *new_crtc_state)
>  	 * when it's derived from the timestamps. So let's wait for the
>  	 * pipe to start properly before we call drm_crtc_vblank_on()
>  	 */
> -	if (dev_priv->drm.max_vblank_count == 0)
> +	if (intel_crtc_max_vblank_count(new_crtc_state) == 0)
>  		intel_wait_for_pipe_scanline_moving(crtc);
>  }
>  
> @@ -5617,7 +5646,7 @@ static void ironlake_crtc_enable(struct intel_crtc_state *pipe_config,
>  		ironlake_pch_enable(old_intel_state, pipe_config);
>  
>  	assert_vblank_disabled(crtc);
> -	drm_crtc_vblank_on(crtc);
> +	intel_crtc_vblank_on(pipe_config);
>  
>  	intel_encoders_enable(crtc, pipe_config, old_state);
>  
> @@ -5774,7 +5803,7 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
>  		intel_ddi_set_vc_payload_alloc(pipe_config, true);
>  
>  	assert_vblank_disabled(crtc);
> -	drm_crtc_vblank_on(crtc);
> +	intel_crtc_vblank_on(pipe_config);
>  
>  	intel_encoders_enable(crtc, pipe_config, old_state);
>  
> @@ -6114,7 +6143,7 @@ static void valleyview_crtc_enable(struct intel_crtc_state *pipe_config,
>  	intel_enable_pipe(pipe_config);
>  
>  	assert_vblank_disabled(crtc);
> -	drm_crtc_vblank_on(crtc);
> +	intel_crtc_vblank_on(pipe_config);
>  
>  	intel_encoders_enable(crtc, pipe_config, old_state);
>  }
> @@ -6173,7 +6202,7 @@ static void i9xx_crtc_enable(struct intel_crtc_state *pipe_config,
>  	intel_enable_pipe(pipe_config);
>  
>  	assert_vblank_disabled(crtc);
> -	drm_crtc_vblank_on(crtc);
> +	intel_crtc_vblank_on(pipe_config);
>  
>  	intel_encoders_enable(crtc, pipe_config, old_state);
>  }
> @@ -12653,8 +12682,9 @@ static int intel_atomic_prepare_commit(struct drm_device *dev,
>  u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc)
>  {
>  	struct drm_device *dev = crtc->base.dev;
> +	struct drm_vblank_crtc *vblank = &dev->vblank[drm_crtc_index(&crtc->base)];
>  
> -	if (!dev->max_vblank_count)
> +	if (!vblank->max_vblank_count)
>  		return (u32)drm_crtc_accurate_vblank_count(&crtc->base);
>  
>  	return dev->driver->get_vblank_counter(dev, crtc->pipe);
> @@ -15736,10 +15766,12 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
>  	 * waits, so we need vblank interrupts restored beforehand.
>  	 */
>  	for_each_intel_crtc(&dev_priv->drm, crtc) {
> +		crtc_state = to_intel_crtc_state(crtc->base.state);
> +
>  		drm_crtc_vblank_reset(&crtc->base);
>  
> -		if (crtc->base.state->active)
> -			drm_crtc_vblank_on(&crtc->base);
> +		if (crtc_state->base.active)
> +			intel_crtc_vblank_on(crtc_state);
>  	}
>  
>  	intel_sanitize_plane_mapping(dev_priv);
> -- 
> 2.18.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 03/15] drm/i915/tv: Fix interlaced ysize calculation
  2018-11-12 16:59 ` [PATCH 03/15] drm/i915/tv: Fix interlaced ysize calculation Ville Syrjala
@ 2019-01-22 12:54   ` Imre Deak
  0 siblings, 0 replies; 66+ messages in thread
From: Imre Deak @ 2019-01-22 12:54 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, dri-devel

On Mon, Nov 12, 2018 at 06:59:47PM +0200, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Fix the calculation of the vertical active period for interlaced
> TV modes.
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

Matches the spec:
Reviewed-by: Imre Deak <imre.deak@intel.com>

> ---
>  drivers/gpu/drm/i915/intel_tv.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
> index 860f306a23ba..219a16d6dcc2 100644
> --- a/drivers/gpu/drm/i915/intel_tv.c
> +++ b/drivers/gpu/drm/i915/intel_tv.c
> @@ -1087,7 +1087,7 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder,
>  	if (tv_mode->progressive)
>  		ysize = tv_mode->nbr_end + 1;
>  	else
> -		ysize = 2*tv_mode->nbr_end + 1;
> +		ysize = 2 * (tv_mode->nbr_end + 1);
>  
>  	xpos += conn_state->tv.margins.left;
>  	ypos += conn_state->tv.margins.top;
> -- 
> 2.18.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 04/15] drm/i915/tv: Fix tv mode clocks
  2018-11-12 16:59 ` [PATCH 04/15] drm/i915/tv: Fix tv mode clocks Ville Syrjala
@ 2019-01-22 12:56   ` Imre Deak
  0 siblings, 0 replies; 66+ messages in thread
From: Imre Deak @ 2019-01-22 12:56 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, dri-devel

On Mon, Nov 12, 2018 at 06:59:48PM +0200, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> The oversample clock is always supposed to be either 108 MHz
> or 148.5 MHz. Make it so.
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

Matches the spec:
Reviewed-by: Imre Deak <imre.deak@intel.com>

> ---
>  drivers/gpu/drm/i915/intel_tv.c | 14 +++++++-------
>  1 file changed, 7 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
> index 219a16d6dcc2..dea24ef88763 100644
> --- a/drivers/gpu/drm/i915/intel_tv.c
> +++ b/drivers/gpu/drm/i915/intel_tv.c
> @@ -636,7 +636,7 @@ static const struct tv_mode tv_modes[] = {
>  	},
>  	{
>  		.name       = "480p",
> -		.clock		= 107520,
> +		.clock		= 108000,
>  		.refresh	= 59940,
>  		.oversample     = TV_OVERSAMPLE_4X,
>  		.component_only = 1,
> @@ -660,7 +660,7 @@ static const struct tv_mode tv_modes[] = {
>  	},
>  	{
>  		.name       = "576p",
> -		.clock		= 107520,
> +		.clock		= 108000,
>  		.refresh	= 50000,
>  		.oversample     = TV_OVERSAMPLE_4X,
>  		.component_only = 1,
> @@ -684,7 +684,7 @@ static const struct tv_mode tv_modes[] = {
>  	},
>  	{
>  		.name       = "720p@60Hz",
> -		.clock		= 148800,
> +		.clock		= 148500,
>  		.refresh	= 60000,
>  		.oversample     = TV_OVERSAMPLE_2X,
>  		.component_only = 1,
> @@ -708,7 +708,7 @@ static const struct tv_mode tv_modes[] = {
>  	},
>  	{
>  		.name       = "720p@50Hz",
> -		.clock		= 148800,
> +		.clock		= 148500,
>  		.refresh	= 50000,
>  		.oversample     = TV_OVERSAMPLE_2X,
>  		.component_only = 1,
> @@ -733,7 +733,7 @@ static const struct tv_mode tv_modes[] = {
>  	},
>  	{
>  		.name       = "1080i@50Hz",
> -		.clock		= 148800,
> +		.clock		= 148500,
>  		.refresh	= 50000,
>  		.oversample     = TV_OVERSAMPLE_2X,
>  		.component_only = 1,
> @@ -759,7 +759,7 @@ static const struct tv_mode tv_modes[] = {
>  	},
>  	{
>  		.name       = "1080i@60Hz",
> -		.clock		= 148800,
> +		.clock		= 148500,
>  		.refresh	= 60000,
>  		.oversample     = TV_OVERSAMPLE_2X,
>  		.component_only = 1,
> @@ -1114,7 +1114,7 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder,
>  static const struct drm_display_mode reported_modes[] = {
>  	{
>  		.name = "NTSC 480i",
> -		.clock = 107520,
> +		.clock = 108000,
>  		.hdisplay = 1280,
>  		.hsync_start = 1368,
>  		.hsync_end = 1496,
> -- 
> 2.18.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 05/15] drm/i915/tv: Store the TV oversampling factor in the TV mode
  2018-11-12 16:59 ` [PATCH 05/15] drm/i915/tv: Store the TV oversampling factor in the TV mode Ville Syrjala
@ 2019-01-22 13:03   ` Imre Deak
  0 siblings, 0 replies; 66+ messages in thread
From: Imre Deak @ 2019-01-22 13:03 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, dri-devel

On Mon, Nov 12, 2018 at 06:59:49PM +0200, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Store the oversampling factor as a number in the TV modes. We
> shall want to arithmetic with this which is easier if it's
> a number we can use directly.
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

Reviewed-by: Imre Deak <imre.deak@intel.com>

> ---
>  drivers/gpu/drm/i915/intel_tv.c | 42 ++++++++++++++++++++++-----------
>  1 file changed, 28 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
> index dea24ef88763..96257b29d07c 100644
> --- a/drivers/gpu/drm/i915/intel_tv.c
> +++ b/drivers/gpu/drm/i915/intel_tv.c
> @@ -307,7 +307,7 @@ struct tv_mode {
>  
>  	u32 clock;
>  	u16 refresh; /* in millihertz (for precision) */
> -	u32 oversample;
> +	u8 oversample;
>  	u8 hsync_end;
>  	u16 hblank_start, hblank_end, htotal;
>  	bool progressive : 1, trilevel_sync : 1, component_only : 1;
> @@ -379,7 +379,7 @@ static const struct tv_mode tv_modes[] = {
>  		.name		= "NTSC-M",
>  		.clock		= 108000,
>  		.refresh	= 59940,
> -		.oversample	= TV_OVERSAMPLE_8X,
> +		.oversample	= 8,
>  		.component_only = 0,
>  		/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
>  
> @@ -422,7 +422,7 @@ static const struct tv_mode tv_modes[] = {
>  		.name		= "NTSC-443",
>  		.clock		= 108000,
>  		.refresh	= 59940,
> -		.oversample	= TV_OVERSAMPLE_8X,
> +		.oversample	= 8,
>  		.component_only = 0,
>  		/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 4.43MHz */
>  		.hsync_end	= 64,		    .hblank_end		= 124,
> @@ -464,7 +464,7 @@ static const struct tv_mode tv_modes[] = {
>  		.name		= "NTSC-J",
>  		.clock		= 108000,
>  		.refresh	= 59940,
> -		.oversample	= TV_OVERSAMPLE_8X,
> +		.oversample	= 8,
>  		.component_only = 0,
>  
>  		/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
> @@ -507,7 +507,7 @@ static const struct tv_mode tv_modes[] = {
>  		.name		= "PAL-M",
>  		.clock		= 108000,
>  		.refresh	= 59940,
> -		.oversample	= TV_OVERSAMPLE_8X,
> +		.oversample	= 8,
>  		.component_only = 0,
>  
>  		/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
> @@ -551,7 +551,7 @@ static const struct tv_mode tv_modes[] = {
>  		.name	    = "PAL-N",
>  		.clock		= 108000,
>  		.refresh	= 50000,
> -		.oversample	= TV_OVERSAMPLE_8X,
> +		.oversample	= 8,
>  		.component_only = 0,
>  
>  		.hsync_end	= 64,		    .hblank_end		= 128,
> @@ -596,7 +596,7 @@ static const struct tv_mode tv_modes[] = {
>  		.name	    = "PAL",
>  		.clock		= 108000,
>  		.refresh	= 50000,
> -		.oversample	= TV_OVERSAMPLE_8X,
> +		.oversample	= 8,
>  		.component_only = 0,
>  
>  		.hsync_end	= 64,		    .hblank_end		= 142,
> @@ -638,7 +638,7 @@ static const struct tv_mode tv_modes[] = {
>  		.name       = "480p",
>  		.clock		= 108000,
>  		.refresh	= 59940,
> -		.oversample     = TV_OVERSAMPLE_4X,
> +		.oversample     = 4,
>  		.component_only = 1,
>  
>  		.hsync_end      = 64,               .hblank_end         = 122,
> @@ -662,7 +662,7 @@ static const struct tv_mode tv_modes[] = {
>  		.name       = "576p",
>  		.clock		= 108000,
>  		.refresh	= 50000,
> -		.oversample     = TV_OVERSAMPLE_4X,
> +		.oversample     = 4,
>  		.component_only = 1,
>  
>  		.hsync_end      = 64,               .hblank_end         = 139,
> @@ -686,7 +686,7 @@ static const struct tv_mode tv_modes[] = {
>  		.name       = "720p@60Hz",
>  		.clock		= 148500,
>  		.refresh	= 60000,
> -		.oversample     = TV_OVERSAMPLE_2X,
> +		.oversample     = 2,
>  		.component_only = 1,
>  
>  		.hsync_end      = 80,               .hblank_end         = 300,
> @@ -710,7 +710,7 @@ static const struct tv_mode tv_modes[] = {
>  		.name       = "720p@50Hz",
>  		.clock		= 148500,
>  		.refresh	= 50000,
> -		.oversample     = TV_OVERSAMPLE_2X,
> +		.oversample     = 2,
>  		.component_only = 1,
>  
>  		.hsync_end      = 80,               .hblank_end         = 300,
> @@ -735,7 +735,7 @@ static const struct tv_mode tv_modes[] = {
>  		.name       = "1080i@50Hz",
>  		.clock		= 148500,
>  		.refresh	= 50000,
> -		.oversample     = TV_OVERSAMPLE_2X,
> +		.oversample     = 2,
>  		.component_only = 1,
>  
>  		.hsync_end      = 88,               .hblank_end         = 235,
> @@ -761,7 +761,7 @@ static const struct tv_mode tv_modes[] = {
>  		.name       = "1080i@60Hz",
>  		.clock		= 148500,
>  		.refresh	= 60000,
> -		.oversample     = TV_OVERSAMPLE_2X,
> +		.oversample     = 2,
>  		.component_only = 1,
>  
>  		.hsync_end      = 88,               .hblank_end         = 235,
> @@ -1030,7 +1030,21 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder,
>  	}
>  
>  	tv_ctl |= TV_ENC_PIPE_SEL(intel_crtc->pipe);
> -	tv_ctl |= tv_mode->oversample;
> +
> +	switch (tv_mode->oversample) {
> +	case 8:
> +		tv_ctl |= TV_OVERSAMPLE_8X;
> +		break;
> +	case 4:
> +		tv_ctl |= TV_OVERSAMPLE_4X;
> +		break;
> +	case 2:
> +		tv_ctl |= TV_OVERSAMPLE_2X;
> +		break;
> +	default:
> +		tv_ctl |= TV_OVERSAMPLE_NONE;
> +		break;
> +	}
>  
>  	if (tv_mode->progressive)
>  		tv_ctl |= TV_PROGRESSIVE;
> -- 
> 2.18.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 06/15] drm/i915/tv: Use bools where appropriate
  2018-11-12 16:59 ` [PATCH 06/15] drm/i915/tv: Use bools where appropriate Ville Syrjala
@ 2019-01-22 13:07   ` Imre Deak
  0 siblings, 0 replies; 66+ messages in thread
From: Imre Deak @ 2019-01-22 13:07 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, dri-devel

On Mon, Nov 12, 2018 at 06:59:50PM +0200, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> 'component_only' is a bool. Initialize it like a bool.
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

Reviewed-by: Imre Deak <imre.deak@intel.com>

> ---
>  drivers/gpu/drm/i915/intel_tv.c | 24 ++++++++++++------------
>  1 file changed, 12 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
> index 96257b29d07c..72de154b8627 100644
> --- a/drivers/gpu/drm/i915/intel_tv.c
> +++ b/drivers/gpu/drm/i915/intel_tv.c
> @@ -380,7 +380,7 @@ static const struct tv_mode tv_modes[] = {
>  		.clock		= 108000,
>  		.refresh	= 59940,
>  		.oversample	= 8,
> -		.component_only = 0,
> +		.component_only = false,
>  		/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
>  
>  		.hsync_end	= 64,		    .hblank_end		= 124,
> @@ -423,7 +423,7 @@ static const struct tv_mode tv_modes[] = {
>  		.clock		= 108000,
>  		.refresh	= 59940,
>  		.oversample	= 8,
> -		.component_only = 0,
> +		.component_only = false,
>  		/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 4.43MHz */
>  		.hsync_end	= 64,		    .hblank_end		= 124,
>  		.hblank_start	= 836,		    .htotal		= 857,
> @@ -465,7 +465,7 @@ static const struct tv_mode tv_modes[] = {
>  		.clock		= 108000,
>  		.refresh	= 59940,
>  		.oversample	= 8,
> -		.component_only = 0,
> +		.component_only = false,
>  
>  		/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
>  		.hsync_end	= 64,		    .hblank_end		= 124,
> @@ -508,7 +508,7 @@ static const struct tv_mode tv_modes[] = {
>  		.clock		= 108000,
>  		.refresh	= 59940,
>  		.oversample	= 8,
> -		.component_only = 0,
> +		.component_only = false,
>  
>  		/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
>  		.hsync_end	= 64,		  .hblank_end		= 124,
> @@ -552,7 +552,7 @@ static const struct tv_mode tv_modes[] = {
>  		.clock		= 108000,
>  		.refresh	= 50000,
>  		.oversample	= 8,
> -		.component_only = 0,
> +		.component_only = false,
>  
>  		.hsync_end	= 64,		    .hblank_end		= 128,
>  		.hblank_start = 844,	    .htotal		= 863,
> @@ -597,7 +597,7 @@ static const struct tv_mode tv_modes[] = {
>  		.clock		= 108000,
>  		.refresh	= 50000,
>  		.oversample	= 8,
> -		.component_only = 0,
> +		.component_only = false,
>  
>  		.hsync_end	= 64,		    .hblank_end		= 142,
>  		.hblank_start	= 844,	    .htotal		= 863,
> @@ -639,7 +639,7 @@ static const struct tv_mode tv_modes[] = {
>  		.clock		= 108000,
>  		.refresh	= 59940,
>  		.oversample     = 4,
> -		.component_only = 1,
> +		.component_only = true,
>  
>  		.hsync_end      = 64,               .hblank_end         = 122,
>  		.hblank_start   = 842,              .htotal             = 857,
> @@ -663,7 +663,7 @@ static const struct tv_mode tv_modes[] = {
>  		.clock		= 108000,
>  		.refresh	= 50000,
>  		.oversample     = 4,
> -		.component_only = 1,
> +		.component_only = true,
>  
>  		.hsync_end      = 64,               .hblank_end         = 139,
>  		.hblank_start   = 859,              .htotal             = 863,
> @@ -687,7 +687,7 @@ static const struct tv_mode tv_modes[] = {
>  		.clock		= 148500,
>  		.refresh	= 60000,
>  		.oversample     = 2,
> -		.component_only = 1,
> +		.component_only = true,
>  
>  		.hsync_end      = 80,               .hblank_end         = 300,
>  		.hblank_start   = 1580,             .htotal             = 1649,
> @@ -711,7 +711,7 @@ static const struct tv_mode tv_modes[] = {
>  		.clock		= 148500,
>  		.refresh	= 50000,
>  		.oversample     = 2,
> -		.component_only = 1,
> +		.component_only = true,
>  
>  		.hsync_end      = 80,               .hblank_end         = 300,
>  		.hblank_start   = 1580,             .htotal             = 1979,
> @@ -736,7 +736,7 @@ static const struct tv_mode tv_modes[] = {
>  		.clock		= 148500,
>  		.refresh	= 50000,
>  		.oversample     = 2,
> -		.component_only = 1,
> +		.component_only = true,
>  
>  		.hsync_end      = 88,               .hblank_end         = 235,
>  		.hblank_start   = 2155,             .htotal             = 2639,
> @@ -762,7 +762,7 @@ static const struct tv_mode tv_modes[] = {
>  		.clock		= 148500,
>  		.refresh	= 60000,
>  		.oversample     = 2,
> -		.component_only = 1,
> +		.component_only = true,
>  
>  		.hsync_end      = 88,               .hblank_end         = 235,
>  		.hblank_start   = 2155,             .htotal             = 2199,
> -- 
> 2.18.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 07/15] drm/i915/tv: Nuke silly 0 initialzation of xpos/ypos
  2018-11-12 16:59 ` [PATCH 07/15] drm/i915/tv: Nuke silly 0 initialzation of xpos/ypos Ville Syrjala
@ 2019-01-22 13:09   ` Imre Deak
  0 siblings, 0 replies; 66+ messages in thread
From: Imre Deak @ 2019-01-22 13:09 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, dri-devel

On Mon, Nov 12, 2018 at 06:59:51PM +0200, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Just assign the margin values directly to xpos/ypos instead
> of first initializing to zero and then adding the values.
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

Reviewed-by: Imre Deak <imre.deak@intel.com>

> ---
>  drivers/gpu/drm/i915/intel_tv.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
> index 72de154b8627..97a82878359f 100644
> --- a/drivers/gpu/drm/i915/intel_tv.c
> +++ b/drivers/gpu/drm/i915/intel_tv.c
> @@ -994,7 +994,7 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder,
>  	const struct video_levels *video_levels;
>  	const struct color_conversion *color_conversion;
>  	bool burst_ena;
> -	int xpos = 0x0, ypos = 0x0;
> +	int xpos, ypos;
>  	unsigned int xsize, ysize;
>  
>  	if (!tv_mode)
> @@ -1103,8 +1103,8 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder,
>  	else
>  		ysize = 2 * (tv_mode->nbr_end + 1);
>  
> -	xpos += conn_state->tv.margins.left;
> -	ypos += conn_state->tv.margins.top;
> +	xpos = conn_state->tv.margins.left;
> +	ypos = conn_state->tv.margins.top;
>  	xsize -= (conn_state->tv.margins.left +
>  		  conn_state->tv.margins.right);
>  	ysize -= (conn_state->tv.margins.top +
> -- 
> 2.18.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [Intel-gfx] [PATCH 08/15] drm/i915/tv: Deobfuscate preferred mode selection
  2018-11-12 16:59 ` [PATCH 08/15] drm/i915/tv: Deobfuscate preferred mode selection Ville Syrjala
@ 2019-01-22 14:43   ` Imre Deak
  0 siblings, 0 replies; 66+ messages in thread
From: Imre Deak @ 2019-01-22 14:43 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, dri-devel

On Mon, Nov 12, 2018 at 06:59:53PM +0200, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Rewrite the preferred mode selection to just check
> whether the TV modes is HD or SD. For SD TV modes we
> favor 480 line modes, for 720p we prefer 720 line modes,
> and for 1080i/p we prefer 1080 line modes.
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

Reviewed-by: Imre Deak <imre.deak@intel.com>

> ---
>  drivers/gpu/drm/i915/intel_tv.c | 50 ++++++++++++++++++++-------------
>  1 file changed, 30 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
> index 97a82878359f..54189080cfb1 100644
> --- a/drivers/gpu/drm/i915/intel_tv.c
> +++ b/drivers/gpu/drm/i915/intel_tv.c
> @@ -860,6 +860,14 @@ intel_tv_mode_valid(struct drm_connector *connector,
>  	return MODE_CLOCK_RANGE;
>  }
>  
> +static int
> +intel_tv_mode_vdisplay(const struct tv_mode *tv_mode)
> +{
> +	if (tv_mode->progressive)
> +		return tv_mode->nbr_end + 1;
> +	else
> +		return 2 * (tv_mode->nbr_end + 1);
> +}
>  
>  static void
>  intel_tv_get_config(struct intel_encoder *encoder,
> @@ -1098,10 +1106,7 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder,
>  	/* Filter ctl must be set before TV_WIN_SIZE */
>  	I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);
>  	xsize = tv_mode->hblank_start - tv_mode->hblank_end;
> -	if (tv_mode->progressive)
> -		ysize = tv_mode->nbr_end + 1;
> -	else
> -		ysize = 2 * (tv_mode->nbr_end + 1);
> +	ysize = intel_tv_mode_vdisplay(tv_mode);
>  
>  	xpos = conn_state->tv.margins.left;
>  	ypos = conn_state->tv.margins.top;
> @@ -1320,22 +1325,28 @@ static const struct input_res {
>  	{"1920x1080", 1920, 1080},
>  };
>  
> -/*
> - * Chose preferred mode  according to line number of TV format
> - */
> +/* Choose preferred mode according to line number of TV format */
> +static bool
> +intel_tv_is_preferred_mode(const struct drm_display_mode *mode,
> +			   const struct tv_mode *tv_mode)
> +{
> +	int vdisplay = intel_tv_mode_vdisplay(tv_mode);
> +
> +	/* prefer 480 line modes for all SD TV modes */
> +	if (vdisplay <= 576)
> +		vdisplay = 480;
> +
> +	return vdisplay == mode->vdisplay;
> +}
> +
>  static void
> -intel_tv_choose_preferred_modes(const struct tv_mode *tv_mode,
> -			       struct drm_display_mode *mode_ptr)
> +intel_tv_set_mode_type(struct drm_display_mode *mode,
> +		       const struct tv_mode *tv_mode)
>  {
> -	if (tv_mode->nbr_end < 480 && mode_ptr->vdisplay == 480)
> -		mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
> -	else if (tv_mode->nbr_end > 480) {
> -		if (tv_mode->progressive == true && tv_mode->nbr_end < 720) {
> -			if (mode_ptr->vdisplay == 720)
> -				mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
> -		} else if (mode_ptr->vdisplay == 1080)
> -				mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
> -	}
> +	mode->type = DRM_MODE_TYPE_DRIVER;
> +
> +	if (intel_tv_is_preferred_mode(mode, tv_mode))
> +		mode->type |= DRM_MODE_TYPE_PREFERRED;
>  }
>  
>  static int
> @@ -1383,8 +1394,7 @@ intel_tv_get_modes(struct drm_connector *connector)
>  		tmp = div_u64(tmp, 1000000);
>  		mode_ptr->clock = (int) tmp;
>  
> -		mode_ptr->type = DRM_MODE_TYPE_DRIVER;
> -		intel_tv_choose_preferred_modes(tv_mode, mode_ptr);
> +		intel_tv_set_mode_type(mode_ptr, tv_mode);
>  		drm_mode_probed_add(connector, mode_ptr);
>  		count++;
>  	}
> -- 
> 2.18.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 09/15] drm/i915/tv: Use drm_mode_set_name() to name TV modes
  2018-11-12 16:59 ` [PATCH 09/15] drm/i915/tv: Use drm_mode_set_name() to name TV modes Ville Syrjala
@ 2019-01-22 14:45   ` Imre Deak
  0 siblings, 0 replies; 66+ messages in thread
From: Imre Deak @ 2019-01-22 14:45 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, dri-devel

On Mon, Nov 12, 2018 at 06:59:54PM +0200, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> No point in storing the mode names in the array. drm_mode_set_name()
> will give us the same names without wasting space for these string
> constants.
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

Reviewed-by: Imre Deak <imre.deak@intel.com>

> ---
>  drivers/gpu/drm/i915/intel_tv.c | 21 +++++++++++----------
>  1 file changed, 11 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
> index 54189080cfb1..433f538261c1 100644
> --- a/drivers/gpu/drm/i915/intel_tv.c
> +++ b/drivers/gpu/drm/i915/intel_tv.c
> @@ -1313,16 +1313,15 @@ intel_tv_detect(struct drm_connector *connector,
>  }
>  
>  static const struct input_res {
> -	const char *name;
> -	int w, h;
> +	u16 w, h;
>  } input_res_table[] = {
> -	{"640x480", 640, 480},
> -	{"800x600", 800, 600},
> -	{"1024x768", 1024, 768},
> -	{"1280x1024", 1280, 1024},
> -	{"848x480", 848, 480},
> -	{"1280x720", 1280, 720},
> -	{"1920x1080", 1920, 1080},
> +	{ 640, 480 },
> +	{ 800, 600 },
> +	{ 1024, 768 },
> +	{ 1280, 1024 },
> +	{ 848, 480 },
> +	{ 1280, 720 },
> +	{ 1920, 1080 },
>  };
>  
>  /* Choose preferred mode according to line number of TV format */
> @@ -1373,7 +1372,6 @@ intel_tv_get_modes(struct drm_connector *connector)
>  		mode_ptr = drm_mode_create(connector->dev);
>  		if (!mode_ptr)
>  			continue;
> -		strlcpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN);
>  
>  		mode_ptr->hdisplay = hactive_s;
>  		mode_ptr->hsync_start = hactive_s + 1;
> @@ -1395,6 +1393,9 @@ intel_tv_get_modes(struct drm_connector *connector)
>  		mode_ptr->clock = (int) tmp;
>  
>  		intel_tv_set_mode_type(mode_ptr, tv_mode);
> +
> +		drm_mode_set_name(mode_ptr);
> +
>  		drm_mode_probed_add(connector, mode_ptr);
>  		count++;
>  	}
> -- 
> 2.18.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 10/15] drm/i915/tv: Make TV mode autoselection actually useable
  2018-11-12 16:59 ` [PATCH 10/15] drm/i915/tv: Make TV mode autoselection actually useable Ville Syrjala
@ 2019-01-22 14:54   ` Imre Deak
  0 siblings, 0 replies; 66+ messages in thread
From: Imre Deak @ 2019-01-22 14:54 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, dri-devel

On Mon, Nov 12, 2018 at 06:59:55PM +0200, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> The current code insists on picking a new TV mode when
> switching between component and non-component cables.
> That's super annoying. Let's just keep the current TV
> mode unless the new cable type actually disagrees with it.
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

Reviewed-by: Imre Deak <imre.deak@intel.com>

> ---
>  drivers/gpu/drm/i915/intel_tv.c | 12 +++++++-----
>  1 file changed, 7 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
> index 433f538261c1..32a8786fe0da 100644
> --- a/drivers/gpu/drm/i915/intel_tv.c
> +++ b/drivers/gpu/drm/i915/intel_tv.c
> @@ -1253,16 +1253,18 @@ static void intel_tv_find_better_format(struct drm_connector *connector)
>  	const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
>  	int i;
>  
> -	if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) ==
> -		tv_mode->component_only)
> +	/* Component supports everything so we can keep the current mode */
> +	if (intel_tv->type == DRM_MODE_CONNECTOR_Component)
>  		return;
>  
> +	/* If the current mode is fine don't change it */
> +	if (!tv_mode->component_only)
> +		return;
>  
>  	for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
> -		tv_mode = tv_modes + i;
> +		tv_mode = &tv_modes[i];
>  
> -		if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) ==
> -			tv_mode->component_only)
> +		if (!tv_mode->component_only)
>  			break;
>  	}
>  
> -- 
> 2.18.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 11/15] drm/i915/tv: Nuke reported_modes[]
  2018-11-12 16:59 ` [PATCH 11/15] drm/i915/tv: Nuke reported_modes[] Ville Syrjala
@ 2019-01-22 15:08   ` Imre Deak
  0 siblings, 0 replies; 66+ messages in thread
From: Imre Deak @ 2019-01-22 15:08 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, dri-devel

On Mon, Nov 12, 2018 at 06:59:56PM +0200, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Remove the silly reported_modes[] array. I suppse once upon a time
> this actually had something to do with modes we reported to userspace.
> Now it is just the placeholder for the mode we use for load detection.
> We don't need it even for that, and instead we can just rely on
> the fallback mode in intel_get_load_detect_pipe().
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

Reviewed-by: Imre Deak <imre.deak@intel.com>

> ---
>  drivers/gpu/drm/i915/intel_tv.c | 22 +---------------------
>  1 file changed, 1 insertion(+), 21 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
> index 32a8786fe0da..c39e9a5b43db 100644
> --- a/drivers/gpu/drm/i915/intel_tv.c
> +++ b/drivers/gpu/drm/i915/intel_tv.c
> @@ -1130,23 +1130,6 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder,
>  	I915_WRITE(TV_CTL, tv_ctl);
>  }
>  
> -static const struct drm_display_mode reported_modes[] = {
> -	{
> -		.name = "NTSC 480i",
> -		.clock = 108000,
> -		.hdisplay = 1280,
> -		.hsync_start = 1368,
> -		.hsync_end = 1496,
> -		.htotal = 1712,
> -
> -		.vdisplay = 1024,
> -		.vsync_start = 1027,
> -		.vsync_end = 1034,
> -		.vtotal = 1104,
> -		.type = DRM_MODE_TYPE_DRIVER,
> -	},
> -};
> -
>  static int
>  intel_tv_detect_type(struct intel_tv *intel_tv,
>  		      struct drm_connector *connector)
> @@ -1276,7 +1259,6 @@ intel_tv_detect(struct drm_connector *connector,
>  		struct drm_modeset_acquire_ctx *ctx,
>  		bool force)
>  {
> -	struct drm_display_mode mode;
>  	struct intel_tv *intel_tv = intel_attached_tv(connector);
>  	enum drm_connector_status status;
>  	int type;
> @@ -1285,13 +1267,11 @@ intel_tv_detect(struct drm_connector *connector,
>  		      connector->base.id, connector->name,
>  		      force);
>  
> -	mode = reported_modes[0];
> -
>  	if (force) {
>  		struct intel_load_detect_pipe tmp;
>  		int ret;
>  
> -		ret = intel_get_load_detect_pipe(connector, &mode, &tmp, ctx);
> +		ret = intel_get_load_detect_pipe(connector, NULL, &tmp, ctx);
>  		if (ret < 0)
>  			return ret;
>  
> -- 
> 2.18.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [Intel-gfx] [PATCH 12/15] drm/i915/tv: Add 1080p30/50/60 TV modes
  2018-11-12 16:59 ` [PATCH 12/15] drm/i915/tv: Add 1080p30/50/60 TV modes Ville Syrjala
@ 2019-01-22 15:09   ` Imre Deak
  0 siblings, 0 replies; 66+ messages in thread
From: Imre Deak @ 2019-01-22 15:09 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, dri-devel

On Mon, Nov 12, 2018 at 06:59:57PM +0200, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Add the missing 1080p TV modes. On gen4 all of them work just fine,
> whereas on gen3 only the 30Hz mode actually works correctly.
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

Matches the spec:
Reviewed-by: Imre Deak <imre.deak@intel.com>

> ---
>  drivers/gpu/drm/i915/intel_tv.c | 90 +++++++++++++++++++++++++++++++--
>  1 file changed, 86 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
> index c39e9a5b43db..216525dd144a 100644
> --- a/drivers/gpu/drm/i915/intel_tv.c
> +++ b/drivers/gpu/drm/i915/intel_tv.c
> @@ -783,6 +783,84 @@ static const struct tv_mode tv_modes[] = {
>  
>  		.filter_table = filter_table,
>  	},
> +
> +	{
> +		.name       = "1080p@30Hz",
> +		.clock		= 148500,
> +		.refresh	= 30000,
> +		.oversample     = 2,
> +		.component_only = true,
> +
> +		.hsync_end      = 88,               .hblank_end         = 235,
> +		.hblank_start   = 2155,             .htotal             = 2199,
> +
> +		.progressive	= true,		    .trilevel_sync = true,
> +
> +		.vsync_start_f1 = 8,               .vsync_start_f2     = 8,
> +		.vsync_len      = 10,
> +
> +		.veq_ena	= false,	.veq_start_f1	= 0,
> +		.veq_start_f2	= 0,		    .veq_len		= 0,
> +
> +		.vi_end_f1      = 44,               .vi_end_f2          = 44,
> +		.nbr_end        = 1079,
> +
> +		.burst_ena      = false,
> +
> +		.filter_table = filter_table,
> +	},
> +
> +	{
> +		.name       = "1080p@50Hz",
> +		.clock		= 148500,
> +		.refresh	= 50000,
> +		.oversample     = 1,
> +		.component_only = true,
> +
> +		.hsync_end      = 88,               .hblank_end         = 235,
> +		.hblank_start   = 2155,             .htotal             = 2639,
> +
> +		.progressive	= true,		    .trilevel_sync = true,
> +
> +		.vsync_start_f1 = 8,               .vsync_start_f2     = 8,
> +		.vsync_len      = 10,
> +
> +		.veq_ena	= false,	.veq_start_f1	= 0,
> +		.veq_start_f2	= 0,		    .veq_len		= 0,
> +
> +		.vi_end_f1      = 44,               .vi_end_f2          = 44,
> +		.nbr_end        = 1079,
> +
> +		.burst_ena      = false,
> +
> +		.filter_table = filter_table,
> +	},
> +
> +	{
> +		.name       = "1080p@60Hz",
> +		.clock		= 148500,
> +		.refresh	= 60000,
> +		.oversample     = 1,
> +		.component_only = true,
> +
> +		.hsync_end      = 88,               .hblank_end         = 235,
> +		.hblank_start   = 2155,             .htotal             = 2199,
> +
> +		.progressive	= true,		    .trilevel_sync = true,
> +
> +		.vsync_start_f1 = 8,               .vsync_start_f2     = 8,
> +		.vsync_len      = 10,
> +
> +		.veq_ena	= false,		    .veq_start_f1	= 0,
> +		.veq_start_f2	= 0,		    .veq_len		= 0,
> +
> +		.vi_end_f1      = 44,               .vi_end_f2          = 44,
> +		.nbr_end        = 1079,
> +
> +		.burst_ena      = false,
> +
> +		.filter_table = filter_table,
> +	},
>  };
>  
>  static struct intel_tv *enc_to_tv(struct intel_encoder *encoder)
> @@ -1538,11 +1616,15 @@ intel_tv_init(struct drm_i915_private *dev_priv)
>  	connector->doublescan_allowed = false;
>  
>  	/* Create TV properties then attach current values */
> -	for (i = 0; i < ARRAY_SIZE(tv_modes); i++)
> +	for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
> +		/* 1080p50/1080p60 not supported on gen3 */
> +		if (IS_GEN3(dev_priv) &&
> +		    tv_modes[i].oversample == 1)
> +			break;
> +
>  		tv_format_names[i] = tv_modes[i].name;
> -	drm_mode_create_tv_properties(dev,
> -				      ARRAY_SIZE(tv_modes),
> -				      tv_format_names);
> +	}
> +	drm_mode_create_tv_properties(dev, i, tv_format_names);
>  
>  	drm_object_attach_property(&connector->base, dev->mode_config.tv_mode_property,
>  				   state->tv.mode);
> -- 
> 2.18.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 13/15] drm/i915/tv: Generate better pipe timings for TV encoder
  2018-11-12 16:59 ` [PATCH 13/15] drm/i915/tv: Generate better pipe timings for TV encoder Ville Syrjala
@ 2019-01-22 17:22   ` Imre Deak
  2019-01-22 17:34     ` Ville Syrjälä
  0 siblings, 1 reply; 66+ messages in thread
From: Imre Deak @ 2019-01-22 17:22 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, dri-devel

On Mon, Nov 12, 2018 at 06:59:58PM +0200, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> To make vblank timestamps work better with the TV encoder let's
> scale the pipe timings such that the relationship between the
> TV active and TV blanking periods is mirrored in the
> corresponding pipe timings.
> 
> Note that in reality the pipe runs at a faster speed during the
> TV vblank, and correspondigly there are periods when the pipe
> is enitrely stopped. We pretend that this isn't the case and
> as such we incur some error in the vblank timestamps during
> the TV vblank. Further explanation of the issues in a big
> comment in the code.
> 
> This makes the vblank timestamps good enough to make
> i965gm (which doesn't have a working frame counter with
> the TV encoder) report correct frame numbers. Previously
> you could get all kinds of nonsense which resulted in
> eg. glxgears reporting that it's running at twice the
> actual framerate in most cases.
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/i915_reg.h |   1 +
>  drivers/gpu/drm/i915/intel_tv.c | 322 +++++++++++++++++++++++++++-----
>  2 files changed, 278 insertions(+), 45 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index fe4b913e46ac..10813ae7bee7 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -4848,6 +4848,7 @@ enum {
>  # define TV_OVERSAMPLE_NONE		(2 << 18)
>  /* Selects 8x oversampling */
>  # define TV_OVERSAMPLE_8X		(3 << 18)
> +# define TV_OVERSAMPLE_MASK		(3 << 18)
>  /* Selects progressive mode rather than interlaced */
>  # define TV_PROGRESSIVE			(1 << 17)
>  /* Sets the colorburst to PAL mode.  Required for non-M PAL modes. */
> diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
> index 216525dd144a..75126fce655d 100644
> --- a/drivers/gpu/drm/i915/intel_tv.c
> +++ b/drivers/gpu/drm/i915/intel_tv.c
> @@ -340,7 +340,6 @@ struct tv_mode {
>  	const struct video_levels *composite_levels, *svideo_levels;
>  	const struct color_conversion *composite_color, *svideo_color;
>  	const u32 *filter_table;
> -	u16 max_srcw;
>  };
>  
>  
> @@ -729,7 +728,6 @@ static const struct tv_mode tv_modes[] = {
>  		.burst_ena      = false,
>  
>  		.filter_table = filter_table,
> -		.max_srcw = 800
>  	},
>  	{
>  		.name       = "1080i@50Hz",
> @@ -947,13 +945,183 @@ intel_tv_mode_vdisplay(const struct tv_mode *tv_mode)
>  		return 2 * (tv_mode->nbr_end + 1);
>  }
>  
> +static void
> +intel_tv_mode_to_mode(struct drm_display_mode *mode,
> +		      const struct tv_mode *tv_mode)
> +{
> +	mode->clock = tv_mode->clock /
> +		(tv_mode->oversample >> !tv_mode->progressive);
> +
> +	/*
> +	 * tv_mode horizontal timings:
> +	 *
> +	 * hsync_end
> +	 *    | hblank_end
> +	 *    |    | hblank_start
> +	 *    |    |       | htotal
> +	 *    |     _______    |
> +	 *     ____/       \___
> +	 * \__/                \
> +	 */
> +	mode->hdisplay =
> +		tv_mode->hblank_start - tv_mode->hblank_end;
> +	mode->hsync_start = mode->hdisplay +
> +		tv_mode->htotal - tv_mode->hblank_start;
> +	mode->hsync_end = mode->hsync_start +
> +		tv_mode->hsync_end;
> +	mode->htotal = tv_mode->htotal + 1;
> +
> +	/*
> +	 * tv_mode vertical timings:
> +	 *
> +	 * vsync_start
> +	 *    | vsync_end
> +	 *    |  | vi_end nbr_end
> +	 *    |  |    |       |
> +	 *    |  |     _______
> +	 * \__    ____/       \
> +	 *    \__/
> +	 */
> +	mode->vdisplay = intel_tv_mode_vdisplay(tv_mode);
> +	if (tv_mode->progressive) {
> +		mode->vsync_start = mode->vdisplay +
> +			tv_mode->vsync_start_f1 + 1;
> +		mode->vsync_end = mode->vsync_start +
> +			tv_mode->vsync_len;
> +		mode->vtotal = mode->vdisplay +
> +			tv_mode->vi_end_f1 + 1;
> +	} else {
> +		mode->vsync_start = mode->vdisplay +
> +			tv_mode->vsync_start_f1 + 1 +
> +			tv_mode->vsync_start_f2 + 1;
> +		mode->vsync_end = mode->vsync_start +
> +			2 * tv_mode->vsync_len;
> +		mode->vtotal = mode->vdisplay +
> +			tv_mode->vi_end_f1 + 1 +
> +			tv_mode->vi_end_f2 + 1;
> +	}
> +
> +	/* TV has it's own notion of sync and other mode flags, so clear them. */
> +	mode->flags = 0;
> +
> +	mode->vrefresh = 0;

Redundant line.

> +	mode->vrefresh = drm_mode_vrefresh(mode);
> +
> +	snprintf(mode->name, sizeof(mode->name),
> +		 "%dx%d%c (%s)",
> +		 mode->hdisplay, mode->vdisplay,
> +		 tv_mode->progressive ? 'p' : 'i',
> +		 tv_mode->name);
> +}
> +
> +static void intel_tv_scale_mode_horiz(struct drm_display_mode *mode,
> +				      int hdisplay, int left_margin,
> +				      int right_margin)
> +{
> +	int hsync_start = mode->hsync_start - mode->hdisplay + right_margin;
> +	int hsync_end = mode->hsync_end - mode->hdisplay + right_margin;
> +	int new_htotal = mode->htotal * hdisplay /
> +		(mode->hdisplay - left_margin - right_margin);
> +
> +	mode->clock = mode->clock * new_htotal / mode->htotal;
> +
> +	mode->hdisplay = hdisplay;
> +	mode->hsync_start = hdisplay + hsync_start * new_htotal / mode->htotal;
> +	mode->hsync_end = hdisplay + hsync_end * new_htotal / mode->htotal;
> +	mode->htotal = new_htotal;
> +}
> +
> +static void intel_tv_scale_mode_vert(struct drm_display_mode *mode,
> +				     int vdisplay, int top_margin,
> +				     int bottom_margin)
> +{
> +	int vsync_start = mode->vsync_start - mode->vdisplay + bottom_margin;
> +	int vsync_end = mode->vsync_end - mode->vdisplay + bottom_margin;
> +	int new_vtotal = mode->vtotal * vdisplay /
> +		(mode->vdisplay - top_margin - bottom_margin);
> +
> +	mode->clock = mode->clock * new_vtotal / mode->vtotal;
> +
> +	mode->vdisplay = vdisplay;
> +	mode->vsync_start = vdisplay + vsync_start * new_vtotal / mode->vtotal;
> +	mode->vsync_end = vdisplay + vsync_end * new_vtotal / mode->vtotal;
> +	mode->vtotal = new_vtotal;
> +}
> +
>  static void
>  intel_tv_get_config(struct intel_encoder *encoder,
>  		    struct intel_crtc_state *pipe_config)
>  {
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +	struct drm_display_mode *adjusted_mode =
> +		&pipe_config->base.adjusted_mode;
> +	struct drm_display_mode mode = {};
> +	u32 tv_ctl, hctl1, hctl3, vctl1, vctl2, tmp;
> +	struct tv_mode tv_mode = {};
> +	int hdisplay = adjusted_mode->crtc_hdisplay;
> +	int vdisplay = adjusted_mode->crtc_vdisplay;
> +	int xsize, ysize, xpos, ypos;
> +
>  	pipe_config->output_types |= BIT(INTEL_OUTPUT_TVOUT);
>  
> -	pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
> +	tv_ctl = I915_READ(TV_CTL);
> +	hctl1 = I915_READ(TV_H_CTL_1);
> +	hctl3 = I915_READ(TV_H_CTL_3);
> +	vctl1 = I915_READ(TV_V_CTL_1);
> +	vctl2 = I915_READ(TV_V_CTL_2);
> +
> +	tv_mode.htotal = (hctl1 & TV_HTOTAL_MASK) >> TV_HTOTAL_SHIFT;
> +	tv_mode.hsync_end = (hctl1 & TV_HSYNC_END_MASK) >> TV_HSYNC_END_SHIFT;
> +
> +	tv_mode.hblank_start = (hctl3 & TV_HBLANK_START_MASK) >> TV_HBLANK_START_SHIFT;
> +	tv_mode.hblank_end = (hctl3 & TV_HSYNC_END_MASK) >> TV_HBLANK_END_SHIFT;
> +
> +	tv_mode.nbr_end = (vctl1 & TV_NBR_END_MASK) >> TV_NBR_END_SHIFT;
> +	tv_mode.vi_end_f1 = (vctl1 & TV_VI_END_F1_MASK) >> TV_VI_END_F1_SHIFT;
> +	tv_mode.vi_end_f2 = (vctl1 & TV_VI_END_F2_MASK) >> TV_VI_END_F2_SHIFT;
> +
> +	tv_mode.vsync_len = (vctl2 & TV_VSYNC_LEN_MASK) >> TV_VSYNC_LEN_SHIFT;
> +	tv_mode.vsync_start_f1 = (vctl2 & TV_VSYNC_START_F1_MASK) >> TV_VSYNC_START_F1_SHIFT;
> +	tv_mode.vsync_start_f2 = (vctl2 & TV_VSYNC_START_F2_MASK) >> TV_VSYNC_START_F2_SHIFT;
> +
> +	tv_mode.clock = pipe_config->port_clock;
> +
> +	tv_mode.progressive = tv_ctl & TV_PROGRESSIVE;
> +
> +	switch (tv_ctl & TV_OVERSAMPLE_MASK) {
> +	case TV_OVERSAMPLE_8X:
> +		tv_mode.oversample = 8;
> +		break;
> +	case TV_OVERSAMPLE_4X:
> +		tv_mode.oversample = 4;
> +		break;
> +	case TV_OVERSAMPLE_2X:
> +		tv_mode.oversample = 2;
> +		break;
> +	default:
> +		tv_mode.oversample = 1;
> +		break;
> +	}
> +
> +	tmp = I915_READ(TV_WIN_POS);
> +	xpos = tmp >> 16;
> +	ypos = tmp & 0xffff;
> +
> +	tmp = I915_READ(TV_WIN_SIZE);
> +	xsize = tmp >> 16;
> +	ysize = tmp & 0xffff;
> +
> +	intel_tv_mode_to_mode(&mode, &tv_mode);
> +
> +	DRM_DEBUG_KMS("TV mode:\n");
> +	drm_mode_debug_printmodeline(&mode);
> +
> +	intel_tv_scale_mode_horiz(&mode, hdisplay,
> +				  xpos, mode.hdisplay - xsize - xpos);
> +	intel_tv_scale_mode_vert(&mode, vdisplay,
> +				 ypos, mode.vdisplay - ysize - ypos);
> +
> +	adjusted_mode->crtc_clock = mode.clock;
>  }
>  
>  static bool
> @@ -964,6 +1132,8 @@ intel_tv_compute_config(struct intel_encoder *encoder,
>  	const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
>  	struct drm_display_mode *adjusted_mode =
>  		&pipe_config->base.adjusted_mode;
> +	int hdisplay = adjusted_mode->crtc_hdisplay;
> +	int vdisplay = adjusted_mode->crtc_vdisplay;
>  
>  	if (!tv_mode)
>  		return false;
> @@ -972,17 +1142,90 @@ intel_tv_compute_config(struct intel_encoder *encoder,
>  		return false;
>  
>  	pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
> -	adjusted_mode->crtc_clock = tv_mode->clock;
> +
>  	DRM_DEBUG_KMS("forcing bpc to 8 for TV\n");
>  	pipe_config->pipe_bpp = 8*3;
>  
> -	/* TV has it's own notion of sync and other mode flags, so clear them. */
> -	adjusted_mode->flags = 0;
> +	pipe_config->port_clock = tv_mode->clock;
> +
> +	intel_tv_mode_to_mode(adjusted_mode, tv_mode);
> +
> +	DRM_DEBUG_KMS("TV mode:\n");
> +	drm_mode_debug_printmodeline(adjusted_mode);
>  
>  	/*
> -	 * FIXME: We don't check whether the input mode is actually what we want
> -	 * or whether userspace is doing something stupid.
> +	 * The pipe scanline counter behaviour looks as follows when
> +	 * using the TV encoder:
> +	 *
> +	 * time ->
> +	 *
> +	 * dsl=vtotal-1       |             |
> +	 *                   ||            ||
> +	 *               ___| |        ___| |
> +	 *              /     |       /     |
> +	 *             /      |      /      |
> +	 * dsl=0   ___/       |_____/       |
> +	 *        | | |  |  | |
> +	 *         ^ ^ ^   ^ ^
> +	 *         | | |   | pipe vblank/first part of tv vblank
> +	 *         | | |   bottom margin
> +	 *         | | active
> +	 *         | top margin
> +	 *         remainder of tv vblank
> +	 *
> +	 * When the TV encoder is used the pipe wants to run faster
> +	 * than expected rate. During the active portion the TV
> +	 * encoder stalls the pipe every few lines to keep it in
> +	 * check. When the TV encoder reaches the bottom margin the
> +	 * pipe simply stops. Once we reach the TV vblank the pipe is
> +	 * no longer stalled and it runs at the max rate (apparently
> +	 * oversample clock on gen3, cdclk on gen4). Once the pipe
> +	 * reaches the pipe vtotal the pipe stops for the remainder
> +	 * of the TV vblank/top margin. The pipe starts up again when
> +	 * the TV encoder exits the top margin.
> +	 *
> +	 * To avoid huge hassles for vblank timestamping we scale
> +	 * the pipe timings as if the pipe always runs at the average
> +	 * rate it maintains during the active period. This also
> +	 * gives us a reasonable guesstimate as to the pixel rate.
> +	 * Due to the variation in the actual pipe speed the scanline
> +	 * counter will give us slightly erroneous results during the
> +	 * TV vblank/margins. But since vtotal was selected such that
> +	 * it matches the average rate of the pipe during the active
> +	 * portion the error shouldn't cause any serious grief to
> +	 * vblank timestamps.

Nice rev. enging and description. Was thinking for a while what is the
max error the isssue you found adds wrt. the actual vblank timestamp,
after your change. AFAIU it's the duration of the flats in the curve,
that is
max_err=+(bottom margin+remainder of tv vblank+top margin).

Reviewed-by: Imre Deak <imre.deak@intel.com>

> +	 *
> +	 * For posterity here is the empirically derived formula
> +	 * that gives us the maximum length of the pipe vblank
> +	 * we can use without causing display corruption. Following
> +	 * this would allow us to have a ticking scanline counter
> +	 * everywhere except during the bottom margin (there the
> +	 * pipe always stops). Ie. this would eliminate the second
> +	 * flat portion of the above graph. However this would also
> +	 * complicate vblank timestamping as the pipe vtotal would
> +	 * no longer match the average rate the pipe runs at during
> +	 * the active portion. Hence following this formula seems
> +	 * more trouble that it's worth.
> +	 *
> +	 * if (IS_GEN4(dev_priv)) {
> +	 *	num = cdclk * (tv_mode->oversample >> !tv_mode->progressive);
> +	 *	den = tv_mode->clock;
> +	 * } else {
> +	 *	num = tv_mode->oversample >> !tv_mode->progressive;
> +	 *	den = 1;
> +	 * }
> +	 * max_pipe_vblank_len ~=
> +	 *	(num * tv_htotal * (tv_vblank_len + top_margin)) /
> +	 *	(den * pipe_htotal);
>  	 */
> +	intel_tv_scale_mode_horiz(adjusted_mode, hdisplay,
> +				  conn_state->tv.margins.left,
> +				  conn_state->tv.margins.right);
> +	intel_tv_scale_mode_vert(adjusted_mode, vdisplay,
> +				 conn_state->tv.margins.top,
> +				 conn_state->tv.margins.bottom);
> +	drm_mode_set_crtcinfo(adjusted_mode, 0);
> +	adjusted_mode->name[0] = '\0';
>  
>  	return true;
>  }
> @@ -1411,52 +1654,41 @@ intel_tv_set_mode_type(struct drm_display_mode *mode,
>  static int
>  intel_tv_get_modes(struct drm_connector *connector)
>  {
> -	struct drm_display_mode *mode_ptr;
>  	const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
> -	int j, count = 0;
> -	u64 tmp;
> +	int i, count = 0;
>  
> -	for (j = 0; j < ARRAY_SIZE(input_res_table);
> -	     j++) {
> -		const struct input_res *input = &input_res_table[j];
> -		unsigned int hactive_s = input->w;
> -		unsigned int vactive_s = input->h;
> -
> -		if (tv_mode->max_srcw && input->w > tv_mode->max_srcw)
> -			continue;
> +	for (i = 0; i < ARRAY_SIZE(input_res_table); i++) {
> +		const struct input_res *input = &input_res_table[i];
> +		struct drm_display_mode *mode;
>  
> -		if (input->w > 1024 && (!tv_mode->progressive
> -					&& !tv_mode->component_only))
> +		if (input->w > 1024 &&
> +		    !tv_mode->progressive &&
> +		    !tv_mode->component_only)
>  			continue;
>  
> -		mode_ptr = drm_mode_create(connector->dev);
> -		if (!mode_ptr)
> +		mode = drm_mode_create(connector->dev);
> +		if (!mode)
>  			continue;
>  
> -		mode_ptr->hdisplay = hactive_s;
> -		mode_ptr->hsync_start = hactive_s + 1;
> -		mode_ptr->hsync_end = hactive_s + 64;
> -		if (mode_ptr->hsync_end <= mode_ptr->hsync_start)
> -			mode_ptr->hsync_end = mode_ptr->hsync_start + 1;
> -		mode_ptr->htotal = hactive_s + 96;
> -
> -		mode_ptr->vdisplay = vactive_s;
> -		mode_ptr->vsync_start = vactive_s + 1;
> -		mode_ptr->vsync_end = vactive_s + 32;
> -		if (mode_ptr->vsync_end <= mode_ptr->vsync_start)
> -			mode_ptr->vsync_end = mode_ptr->vsync_start  + 1;
> -		mode_ptr->vtotal = vactive_s + 33;
> -
> -		tmp = mul_u32_u32(tv_mode->refresh, mode_ptr->vtotal);
> -		tmp *= mode_ptr->htotal;
> -		tmp = div_u64(tmp, 1000000);
> -		mode_ptr->clock = (int) tmp;
> -
> -		intel_tv_set_mode_type(mode_ptr, tv_mode);
> +		/*
> +		 * We take the TV mode and scale it to look
> +		 * like it had the expected h/vdisplay. This
> +		 * provides the most information to userspace
> +		 * about the actual timings of the mode. We
> +		 * do ignore the margins though.
> +		 */
> +		intel_tv_mode_to_mode(mode, tv_mode);
> +		if (count == 0) {
> +			DRM_DEBUG_KMS("TV mode:\n");
> +			drm_mode_debug_printmodeline(mode);
> +		}
> +		intel_tv_scale_mode_horiz(mode, input->w, 0, 0);
> +		intel_tv_scale_mode_vert(mode, input->h, 0, 0);
> +		intel_tv_set_mode_type(mode, tv_mode);
>  
> -		drm_mode_set_name(mode_ptr);
> +		drm_mode_set_name(mode);
>  
> -		drm_mode_probed_add(connector, mode_ptr);
> +		drm_mode_probed_add(connector, mode);
>  		count++;
>  	}
>  
> -- 
> 2.18.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 13/15] drm/i915/tv: Generate better pipe timings for TV encoder
  2019-01-22 17:22   ` Imre Deak
@ 2019-01-22 17:34     ` Ville Syrjälä
  2019-01-23 10:30       ` Imre Deak
  0 siblings, 1 reply; 66+ messages in thread
From: Ville Syrjälä @ 2019-01-22 17:34 UTC (permalink / raw)
  To: Imre Deak; +Cc: intel-gfx, dri-devel

On Tue, Jan 22, 2019 at 07:22:24PM +0200, Imre Deak wrote:
> On Mon, Nov 12, 2018 at 06:59:58PM +0200, Ville Syrjala wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > To make vblank timestamps work better with the TV encoder let's
> > scale the pipe timings such that the relationship between the
> > TV active and TV blanking periods is mirrored in the
> > corresponding pipe timings.
> > 
> > Note that in reality the pipe runs at a faster speed during the
> > TV vblank, and correspondigly there are periods when the pipe
> > is enitrely stopped. We pretend that this isn't the case and
> > as such we incur some error in the vblank timestamps during
> > the TV vblank. Further explanation of the issues in a big
> > comment in the code.
> > 
> > This makes the vblank timestamps good enough to make
> > i965gm (which doesn't have a working frame counter with
> > the TV encoder) report correct frame numbers. Previously
> > you could get all kinds of nonsense which resulted in
> > eg. glxgears reporting that it's running at twice the
> > actual framerate in most cases.
> > 
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >  drivers/gpu/drm/i915/i915_reg.h |   1 +
> >  drivers/gpu/drm/i915/intel_tv.c | 322 +++++++++++++++++++++++++++-----
> >  2 files changed, 278 insertions(+), 45 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> > index fe4b913e46ac..10813ae7bee7 100644
> > --- a/drivers/gpu/drm/i915/i915_reg.h
> > +++ b/drivers/gpu/drm/i915/i915_reg.h
> > @@ -4848,6 +4848,7 @@ enum {
> >  # define TV_OVERSAMPLE_NONE		(2 << 18)
> >  /* Selects 8x oversampling */
> >  # define TV_OVERSAMPLE_8X		(3 << 18)
> > +# define TV_OVERSAMPLE_MASK		(3 << 18)
> >  /* Selects progressive mode rather than interlaced */
> >  # define TV_PROGRESSIVE			(1 << 17)
> >  /* Sets the colorburst to PAL mode.  Required for non-M PAL modes. */
> > diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
> > index 216525dd144a..75126fce655d 100644
> > --- a/drivers/gpu/drm/i915/intel_tv.c
> > +++ b/drivers/gpu/drm/i915/intel_tv.c
> > @@ -340,7 +340,6 @@ struct tv_mode {
> >  	const struct video_levels *composite_levels, *svideo_levels;
> >  	const struct color_conversion *composite_color, *svideo_color;
> >  	const u32 *filter_table;
> > -	u16 max_srcw;
> >  };
> >  
> >  
> > @@ -729,7 +728,6 @@ static const struct tv_mode tv_modes[] = {
> >  		.burst_ena      = false,
> >  
> >  		.filter_table = filter_table,
> > -		.max_srcw = 800
> >  	},
> >  	{
> >  		.name       = "1080i@50Hz",
> > @@ -947,13 +945,183 @@ intel_tv_mode_vdisplay(const struct tv_mode *tv_mode)
> >  		return 2 * (tv_mode->nbr_end + 1);
> >  }
> >  
> > +static void
> > +intel_tv_mode_to_mode(struct drm_display_mode *mode,
> > +		      const struct tv_mode *tv_mode)
> > +{
> > +	mode->clock = tv_mode->clock /
> > +		(tv_mode->oversample >> !tv_mode->progressive);
> > +
> > +	/*
> > +	 * tv_mode horizontal timings:
> > +	 *
> > +	 * hsync_end
> > +	 *    | hblank_end
> > +	 *    |    | hblank_start
> > +	 *    |    |       | htotal
> > +	 *    |     _______    |
> > +	 *     ____/       \___
> > +	 * \__/                \
> > +	 */
> > +	mode->hdisplay =
> > +		tv_mode->hblank_start - tv_mode->hblank_end;
> > +	mode->hsync_start = mode->hdisplay +
> > +		tv_mode->htotal - tv_mode->hblank_start;
> > +	mode->hsync_end = mode->hsync_start +
> > +		tv_mode->hsync_end;
> > +	mode->htotal = tv_mode->htotal + 1;
> > +
> > +	/*
> > +	 * tv_mode vertical timings:
> > +	 *
> > +	 * vsync_start
> > +	 *    | vsync_end
> > +	 *    |  | vi_end nbr_end
> > +	 *    |  |    |       |
> > +	 *    |  |     _______
> > +	 * \__    ____/       \
> > +	 *    \__/
> > +	 */
> > +	mode->vdisplay = intel_tv_mode_vdisplay(tv_mode);
> > +	if (tv_mode->progressive) {
> > +		mode->vsync_start = mode->vdisplay +
> > +			tv_mode->vsync_start_f1 + 1;
> > +		mode->vsync_end = mode->vsync_start +
> > +			tv_mode->vsync_len;
> > +		mode->vtotal = mode->vdisplay +
> > +			tv_mode->vi_end_f1 + 1;
> > +	} else {
> > +		mode->vsync_start = mode->vdisplay +
> > +			tv_mode->vsync_start_f1 + 1 +
> > +			tv_mode->vsync_start_f2 + 1;
> > +		mode->vsync_end = mode->vsync_start +
> > +			2 * tv_mode->vsync_len;
> > +		mode->vtotal = mode->vdisplay +
> > +			tv_mode->vi_end_f1 + 1 +
> > +			tv_mode->vi_end_f2 + 1;
> > +	}
> > +
> > +	/* TV has it's own notion of sync and other mode flags, so clear them. */
> > +	mode->flags = 0;
> > +
> > +	mode->vrefresh = 0;
> 
> Redundant line.

drm_mode_vrefresh() won't recompute the value if it's already
set. So unless we clear it first this would effectively become
'mode->vrefresh = mode->vrefresh'.

The whole mode->vrefesh story is a bit sad, and someone should
really rework how it all works.

> 
> > +	mode->vrefresh = drm_mode_vrefresh(mode);
> > +
> > +	snprintf(mode->name, sizeof(mode->name),
> > +		 "%dx%d%c (%s)",
> > +		 mode->hdisplay, mode->vdisplay,
> > +		 tv_mode->progressive ? 'p' : 'i',
> > +		 tv_mode->name);
> > +}
> > +
> > +static void intel_tv_scale_mode_horiz(struct drm_display_mode *mode,
> > +				      int hdisplay, int left_margin,
> > +				      int right_margin)
> > +{
> > +	int hsync_start = mode->hsync_start - mode->hdisplay + right_margin;
> > +	int hsync_end = mode->hsync_end - mode->hdisplay + right_margin;
> > +	int new_htotal = mode->htotal * hdisplay /
> > +		(mode->hdisplay - left_margin - right_margin);
> > +
> > +	mode->clock = mode->clock * new_htotal / mode->htotal;
> > +
> > +	mode->hdisplay = hdisplay;
> > +	mode->hsync_start = hdisplay + hsync_start * new_htotal / mode->htotal;
> > +	mode->hsync_end = hdisplay + hsync_end * new_htotal / mode->htotal;
> > +	mode->htotal = new_htotal;
> > +}
> > +
> > +static void intel_tv_scale_mode_vert(struct drm_display_mode *mode,
> > +				     int vdisplay, int top_margin,
> > +				     int bottom_margin)
> > +{
> > +	int vsync_start = mode->vsync_start - mode->vdisplay + bottom_margin;
> > +	int vsync_end = mode->vsync_end - mode->vdisplay + bottom_margin;
> > +	int new_vtotal = mode->vtotal * vdisplay /
> > +		(mode->vdisplay - top_margin - bottom_margin);
> > +
> > +	mode->clock = mode->clock * new_vtotal / mode->vtotal;
> > +
> > +	mode->vdisplay = vdisplay;
> > +	mode->vsync_start = vdisplay + vsync_start * new_vtotal / mode->vtotal;
> > +	mode->vsync_end = vdisplay + vsync_end * new_vtotal / mode->vtotal;
> > +	mode->vtotal = new_vtotal;
> > +}
> > +
> >  static void
> >  intel_tv_get_config(struct intel_encoder *encoder,
> >  		    struct intel_crtc_state *pipe_config)
> >  {
> > +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > +	struct drm_display_mode *adjusted_mode =
> > +		&pipe_config->base.adjusted_mode;
> > +	struct drm_display_mode mode = {};
> > +	u32 tv_ctl, hctl1, hctl3, vctl1, vctl2, tmp;
> > +	struct tv_mode tv_mode = {};
> > +	int hdisplay = adjusted_mode->crtc_hdisplay;
> > +	int vdisplay = adjusted_mode->crtc_vdisplay;
> > +	int xsize, ysize, xpos, ypos;
> > +
> >  	pipe_config->output_types |= BIT(INTEL_OUTPUT_TVOUT);
> >  
> > -	pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
> > +	tv_ctl = I915_READ(TV_CTL);
> > +	hctl1 = I915_READ(TV_H_CTL_1);
> > +	hctl3 = I915_READ(TV_H_CTL_3);
> > +	vctl1 = I915_READ(TV_V_CTL_1);
> > +	vctl2 = I915_READ(TV_V_CTL_2);
> > +
> > +	tv_mode.htotal = (hctl1 & TV_HTOTAL_MASK) >> TV_HTOTAL_SHIFT;
> > +	tv_mode.hsync_end = (hctl1 & TV_HSYNC_END_MASK) >> TV_HSYNC_END_SHIFT;
> > +
> > +	tv_mode.hblank_start = (hctl3 & TV_HBLANK_START_MASK) >> TV_HBLANK_START_SHIFT;
> > +	tv_mode.hblank_end = (hctl3 & TV_HSYNC_END_MASK) >> TV_HBLANK_END_SHIFT;
> > +
> > +	tv_mode.nbr_end = (vctl1 & TV_NBR_END_MASK) >> TV_NBR_END_SHIFT;
> > +	tv_mode.vi_end_f1 = (vctl1 & TV_VI_END_F1_MASK) >> TV_VI_END_F1_SHIFT;
> > +	tv_mode.vi_end_f2 = (vctl1 & TV_VI_END_F2_MASK) >> TV_VI_END_F2_SHIFT;
> > +
> > +	tv_mode.vsync_len = (vctl2 & TV_VSYNC_LEN_MASK) >> TV_VSYNC_LEN_SHIFT;
> > +	tv_mode.vsync_start_f1 = (vctl2 & TV_VSYNC_START_F1_MASK) >> TV_VSYNC_START_F1_SHIFT;
> > +	tv_mode.vsync_start_f2 = (vctl2 & TV_VSYNC_START_F2_MASK) >> TV_VSYNC_START_F2_SHIFT;
> > +
> > +	tv_mode.clock = pipe_config->port_clock;
> > +
> > +	tv_mode.progressive = tv_ctl & TV_PROGRESSIVE;
> > +
> > +	switch (tv_ctl & TV_OVERSAMPLE_MASK) {
> > +	case TV_OVERSAMPLE_8X:
> > +		tv_mode.oversample = 8;
> > +		break;
> > +	case TV_OVERSAMPLE_4X:
> > +		tv_mode.oversample = 4;
> > +		break;
> > +	case TV_OVERSAMPLE_2X:
> > +		tv_mode.oversample = 2;
> > +		break;
> > +	default:
> > +		tv_mode.oversample = 1;
> > +		break;
> > +	}
> > +
> > +	tmp = I915_READ(TV_WIN_POS);
> > +	xpos = tmp >> 16;
> > +	ypos = tmp & 0xffff;
> > +
> > +	tmp = I915_READ(TV_WIN_SIZE);
> > +	xsize = tmp >> 16;
> > +	ysize = tmp & 0xffff;
> > +
> > +	intel_tv_mode_to_mode(&mode, &tv_mode);
> > +
> > +	DRM_DEBUG_KMS("TV mode:\n");
> > +	drm_mode_debug_printmodeline(&mode);
> > +
> > +	intel_tv_scale_mode_horiz(&mode, hdisplay,
> > +				  xpos, mode.hdisplay - xsize - xpos);
> > +	intel_tv_scale_mode_vert(&mode, vdisplay,
> > +				 ypos, mode.vdisplay - ysize - ypos);
> > +
> > +	adjusted_mode->crtc_clock = mode.clock;
> >  }
> >  
> >  static bool
> > @@ -964,6 +1132,8 @@ intel_tv_compute_config(struct intel_encoder *encoder,
> >  	const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
> >  	struct drm_display_mode *adjusted_mode =
> >  		&pipe_config->base.adjusted_mode;
> > +	int hdisplay = adjusted_mode->crtc_hdisplay;
> > +	int vdisplay = adjusted_mode->crtc_vdisplay;
> >  
> >  	if (!tv_mode)
> >  		return false;
> > @@ -972,17 +1142,90 @@ intel_tv_compute_config(struct intel_encoder *encoder,
> >  		return false;
> >  
> >  	pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
> > -	adjusted_mode->crtc_clock = tv_mode->clock;
> > +
> >  	DRM_DEBUG_KMS("forcing bpc to 8 for TV\n");
> >  	pipe_config->pipe_bpp = 8*3;
> >  
> > -	/* TV has it's own notion of sync and other mode flags, so clear them. */
> > -	adjusted_mode->flags = 0;
> > +	pipe_config->port_clock = tv_mode->clock;
> > +
> > +	intel_tv_mode_to_mode(adjusted_mode, tv_mode);
> > +
> > +	DRM_DEBUG_KMS("TV mode:\n");
> > +	drm_mode_debug_printmodeline(adjusted_mode);
> >  
> >  	/*
> > -	 * FIXME: We don't check whether the input mode is actually what we want
> > -	 * or whether userspace is doing something stupid.
> > +	 * The pipe scanline counter behaviour looks as follows when
> > +	 * using the TV encoder:
> > +	 *
> > +	 * time ->
> > +	 *
> > +	 * dsl=vtotal-1       |             |
> > +	 *                   ||            ||
> > +	 *               ___| |        ___| |
> > +	 *              /     |       /     |
> > +	 *             /      |      /      |
> > +	 * dsl=0   ___/       |_____/       |
> > +	 *        | | |  |  | |
> > +	 *         ^ ^ ^   ^ ^
> > +	 *         | | |   | pipe vblank/first part of tv vblank
> > +	 *         | | |   bottom margin
> > +	 *         | | active
> > +	 *         | top margin
> > +	 *         remainder of tv vblank
> > +	 *
> > +	 * When the TV encoder is used the pipe wants to run faster
> > +	 * than expected rate. During the active portion the TV
> > +	 * encoder stalls the pipe every few lines to keep it in
> > +	 * check. When the TV encoder reaches the bottom margin the
> > +	 * pipe simply stops. Once we reach the TV vblank the pipe is
> > +	 * no longer stalled and it runs at the max rate (apparently
> > +	 * oversample clock on gen3, cdclk on gen4). Once the pipe
> > +	 * reaches the pipe vtotal the pipe stops for the remainder
> > +	 * of the TV vblank/top margin. The pipe starts up again when
> > +	 * the TV encoder exits the top margin.
> > +	 *
> > +	 * To avoid huge hassles for vblank timestamping we scale
> > +	 * the pipe timings as if the pipe always runs at the average
> > +	 * rate it maintains during the active period. This also
> > +	 * gives us a reasonable guesstimate as to the pixel rate.
> > +	 * Due to the variation in the actual pipe speed the scanline
> > +	 * counter will give us slightly erroneous results during the
> > +	 * TV vblank/margins. But since vtotal was selected such that
> > +	 * it matches the average rate of the pipe during the active
> > +	 * portion the error shouldn't cause any serious grief to
> > +	 * vblank timestamps.
> 
> Nice rev. enging and description. Was thinking for a while what is the
> max error the isssue you found adds wrt. the actual vblank timestamp,
> after your change. AFAIU it's the duration of the flats in the curve,
> that is
> max_err=+(bottom margin+remainder of tv vblank+top margin).
> 
> Reviewed-by: Imre Deak <imre.deak@intel.com>
> 
> > +	 *
> > +	 * For posterity here is the empirically derived formula
> > +	 * that gives us the maximum length of the pipe vblank
> > +	 * we can use without causing display corruption. Following
> > +	 * this would allow us to have a ticking scanline counter
> > +	 * everywhere except during the bottom margin (there the
> > +	 * pipe always stops). Ie. this would eliminate the second
> > +	 * flat portion of the above graph. However this would also
> > +	 * complicate vblank timestamping as the pipe vtotal would
> > +	 * no longer match the average rate the pipe runs at during
> > +	 * the active portion. Hence following this formula seems
> > +	 * more trouble that it's worth.
> > +	 *
> > +	 * if (IS_GEN4(dev_priv)) {
> > +	 *	num = cdclk * (tv_mode->oversample >> !tv_mode->progressive);
> > +	 *	den = tv_mode->clock;
> > +	 * } else {
> > +	 *	num = tv_mode->oversample >> !tv_mode->progressive;
> > +	 *	den = 1;
> > +	 * }
> > +	 * max_pipe_vblank_len ~=
> > +	 *	(num * tv_htotal * (tv_vblank_len + top_margin)) /
> > +	 *	(den * pipe_htotal);
> >  	 */
> > +	intel_tv_scale_mode_horiz(adjusted_mode, hdisplay,
> > +				  conn_state->tv.margins.left,
> > +				  conn_state->tv.margins.right);
> > +	intel_tv_scale_mode_vert(adjusted_mode, vdisplay,
> > +				 conn_state->tv.margins.top,
> > +				 conn_state->tv.margins.bottom);
> > +	drm_mode_set_crtcinfo(adjusted_mode, 0);
> > +	adjusted_mode->name[0] = '\0';
> >  
> >  	return true;
> >  }
> > @@ -1411,52 +1654,41 @@ intel_tv_set_mode_type(struct drm_display_mode *mode,
> >  static int
> >  intel_tv_get_modes(struct drm_connector *connector)
> >  {
> > -	struct drm_display_mode *mode_ptr;
> >  	const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
> > -	int j, count = 0;
> > -	u64 tmp;
> > +	int i, count = 0;
> >  
> > -	for (j = 0; j < ARRAY_SIZE(input_res_table);
> > -	     j++) {
> > -		const struct input_res *input = &input_res_table[j];
> > -		unsigned int hactive_s = input->w;
> > -		unsigned int vactive_s = input->h;
> > -
> > -		if (tv_mode->max_srcw && input->w > tv_mode->max_srcw)
> > -			continue;
> > +	for (i = 0; i < ARRAY_SIZE(input_res_table); i++) {
> > +		const struct input_res *input = &input_res_table[i];
> > +		struct drm_display_mode *mode;
> >  
> > -		if (input->w > 1024 && (!tv_mode->progressive
> > -					&& !tv_mode->component_only))
> > +		if (input->w > 1024 &&
> > +		    !tv_mode->progressive &&
> > +		    !tv_mode->component_only)
> >  			continue;
> >  
> > -		mode_ptr = drm_mode_create(connector->dev);
> > -		if (!mode_ptr)
> > +		mode = drm_mode_create(connector->dev);
> > +		if (!mode)
> >  			continue;
> >  
> > -		mode_ptr->hdisplay = hactive_s;
> > -		mode_ptr->hsync_start = hactive_s + 1;
> > -		mode_ptr->hsync_end = hactive_s + 64;
> > -		if (mode_ptr->hsync_end <= mode_ptr->hsync_start)
> > -			mode_ptr->hsync_end = mode_ptr->hsync_start + 1;
> > -		mode_ptr->htotal = hactive_s + 96;
> > -
> > -		mode_ptr->vdisplay = vactive_s;
> > -		mode_ptr->vsync_start = vactive_s + 1;
> > -		mode_ptr->vsync_end = vactive_s + 32;
> > -		if (mode_ptr->vsync_end <= mode_ptr->vsync_start)
> > -			mode_ptr->vsync_end = mode_ptr->vsync_start  + 1;
> > -		mode_ptr->vtotal = vactive_s + 33;
> > -
> > -		tmp = mul_u32_u32(tv_mode->refresh, mode_ptr->vtotal);
> > -		tmp *= mode_ptr->htotal;
> > -		tmp = div_u64(tmp, 1000000);
> > -		mode_ptr->clock = (int) tmp;
> > -
> > -		intel_tv_set_mode_type(mode_ptr, tv_mode);
> > +		/*
> > +		 * We take the TV mode and scale it to look
> > +		 * like it had the expected h/vdisplay. This
> > +		 * provides the most information to userspace
> > +		 * about the actual timings of the mode. We
> > +		 * do ignore the margins though.
> > +		 */
> > +		intel_tv_mode_to_mode(mode, tv_mode);
> > +		if (count == 0) {
> > +			DRM_DEBUG_KMS("TV mode:\n");
> > +			drm_mode_debug_printmodeline(mode);
> > +		}
> > +		intel_tv_scale_mode_horiz(mode, input->w, 0, 0);
> > +		intel_tv_scale_mode_vert(mode, input->h, 0, 0);
> > +		intel_tv_set_mode_type(mode, tv_mode);
> >  
> > -		drm_mode_set_name(mode_ptr);
> > +		drm_mode_set_name(mode);
> >  
> > -		drm_mode_probed_add(connector, mode_ptr);
> > +		drm_mode_probed_add(connector, mode);
> >  		count++;
> >  	}
> >  
> > -- 
> > 2.18.1
> > 
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Ville Syrjälä
Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 13/15] drm/i915/tv: Generate better pipe timings for TV encoder
  2019-01-22 17:34     ` Ville Syrjälä
@ 2019-01-23 10:30       ` Imre Deak
  0 siblings, 0 replies; 66+ messages in thread
From: Imre Deak @ 2019-01-23 10:30 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx, dri-devel

On Tue, Jan 22, 2019 at 07:34:55PM +0200, Ville Syrjälä wrote:
> On Tue, Jan 22, 2019 at 07:22:24PM +0200, Imre Deak wrote:
> > On Mon, Nov 12, 2018 at 06:59:58PM +0200, Ville Syrjala wrote:
> > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > 
> > > To make vblank timestamps work better with the TV encoder let's
> > > scale the pipe timings such that the relationship between the
> > > TV active and TV blanking periods is mirrored in the
> > > corresponding pipe timings.
> > > 
> > > Note that in reality the pipe runs at a faster speed during the
> > > TV vblank, and correspondigly there are periods when the pipe
> > > is enitrely stopped. We pretend that this isn't the case and
> > > as such we incur some error in the vblank timestamps during
> > > the TV vblank. Further explanation of the issues in a big
> > > comment in the code.
> > > 
> > > This makes the vblank timestamps good enough to make
> > > i965gm (which doesn't have a working frame counter with
> > > the TV encoder) report correct frame numbers. Previously
> > > you could get all kinds of nonsense which resulted in
> > > eg. glxgears reporting that it's running at twice the
> > > actual framerate in most cases.
> > > 
> > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > ---
> > >  drivers/gpu/drm/i915/i915_reg.h |   1 +
> > >  drivers/gpu/drm/i915/intel_tv.c | 322 +++++++++++++++++++++++++++-----
> > >  2 files changed, 278 insertions(+), 45 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> > > index fe4b913e46ac..10813ae7bee7 100644
> > > --- a/drivers/gpu/drm/i915/i915_reg.h
> > > +++ b/drivers/gpu/drm/i915/i915_reg.h
> > > @@ -4848,6 +4848,7 @@ enum {
> > >  # define TV_OVERSAMPLE_NONE		(2 << 18)
> > >  /* Selects 8x oversampling */
> > >  # define TV_OVERSAMPLE_8X		(3 << 18)
> > > +# define TV_OVERSAMPLE_MASK		(3 << 18)
> > >  /* Selects progressive mode rather than interlaced */
> > >  # define TV_PROGRESSIVE			(1 << 17)
> > >  /* Sets the colorburst to PAL mode.  Required for non-M PAL modes. */
> > > diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
> > > index 216525dd144a..75126fce655d 100644
> > > --- a/drivers/gpu/drm/i915/intel_tv.c
> > > +++ b/drivers/gpu/drm/i915/intel_tv.c
> > > @@ -340,7 +340,6 @@ struct tv_mode {
> > >  	const struct video_levels *composite_levels, *svideo_levels;
> > >  	const struct color_conversion *composite_color, *svideo_color;
> > >  	const u32 *filter_table;
> > > -	u16 max_srcw;
> > >  };
> > >  
> > >  
> > > @@ -729,7 +728,6 @@ static const struct tv_mode tv_modes[] = {
> > >  		.burst_ena      = false,
> > >  
> > >  		.filter_table = filter_table,
> > > -		.max_srcw = 800
> > >  	},
> > >  	{
> > >  		.name       = "1080i@50Hz",
> > > @@ -947,13 +945,183 @@ intel_tv_mode_vdisplay(const struct tv_mode *tv_mode)
> > >  		return 2 * (tv_mode->nbr_end + 1);
> > >  }
> > >  
> > > +static void
> > > +intel_tv_mode_to_mode(struct drm_display_mode *mode,
> > > +		      const struct tv_mode *tv_mode)
> > > +{
> > > +	mode->clock = tv_mode->clock /
> > > +		(tv_mode->oversample >> !tv_mode->progressive);
> > > +
> > > +	/*
> > > +	 * tv_mode horizontal timings:
> > > +	 *
> > > +	 * hsync_end
> > > +	 *    | hblank_end
> > > +	 *    |    | hblank_start
> > > +	 *    |    |       | htotal
> > > +	 *    |     _______    |
> > > +	 *     ____/       \___
> > > +	 * \__/                \
> > > +	 */
> > > +	mode->hdisplay =
> > > +		tv_mode->hblank_start - tv_mode->hblank_end;
> > > +	mode->hsync_start = mode->hdisplay +
> > > +		tv_mode->htotal - tv_mode->hblank_start;
> > > +	mode->hsync_end = mode->hsync_start +
> > > +		tv_mode->hsync_end;
> > > +	mode->htotal = tv_mode->htotal + 1;
> > > +
> > > +	/*
> > > +	 * tv_mode vertical timings:
> > > +	 *
> > > +	 * vsync_start
> > > +	 *    | vsync_end
> > > +	 *    |  | vi_end nbr_end
> > > +	 *    |  |    |       |
> > > +	 *    |  |     _______
> > > +	 * \__    ____/       \
> > > +	 *    \__/
> > > +	 */
> > > +	mode->vdisplay = intel_tv_mode_vdisplay(tv_mode);
> > > +	if (tv_mode->progressive) {
> > > +		mode->vsync_start = mode->vdisplay +
> > > +			tv_mode->vsync_start_f1 + 1;
> > > +		mode->vsync_end = mode->vsync_start +
> > > +			tv_mode->vsync_len;
> > > +		mode->vtotal = mode->vdisplay +
> > > +			tv_mode->vi_end_f1 + 1;
> > > +	} else {
> > > +		mode->vsync_start = mode->vdisplay +
> > > +			tv_mode->vsync_start_f1 + 1 +
> > > +			tv_mode->vsync_start_f2 + 1;
> > > +		mode->vsync_end = mode->vsync_start +
> > > +			2 * tv_mode->vsync_len;
> > > +		mode->vtotal = mode->vdisplay +
> > > +			tv_mode->vi_end_f1 + 1 +
> > > +			tv_mode->vi_end_f2 + 1;
> > > +	}
> > > +
> > > +	/* TV has it's own notion of sync and other mode flags, so clear them. */
> > > +	mode->flags = 0;
> > > +
> > > +	mode->vrefresh = 0;
> > 
> > Redundant line.
> 
> drm_mode_vrefresh() won't recompute the value if it's already
> set. So unless we clear it first this would effectively become
> 'mode->vrefresh = mode->vrefresh'.

Oops, correct.

> 
> The whole mode->vrefesh story is a bit sad, and someone should
> really rework how it all works.

Yea, would be nice.

> 
> > 
> > > +	mode->vrefresh = drm_mode_vrefresh(mode);
> > > +
> > > +	snprintf(mode->name, sizeof(mode->name),
> > > +		 "%dx%d%c (%s)",
> > > +		 mode->hdisplay, mode->vdisplay,
> > > +		 tv_mode->progressive ? 'p' : 'i',
> > > +		 tv_mode->name);
> > > +}
> > > +
> > > +static void intel_tv_scale_mode_horiz(struct drm_display_mode *mode,
> > > +				      int hdisplay, int left_margin,
> > > +				      int right_margin)
> > > +{
> > > +	int hsync_start = mode->hsync_start - mode->hdisplay + right_margin;
> > > +	int hsync_end = mode->hsync_end - mode->hdisplay + right_margin;
> > > +	int new_htotal = mode->htotal * hdisplay /
> > > +		(mode->hdisplay - left_margin - right_margin);
> > > +
> > > +	mode->clock = mode->clock * new_htotal / mode->htotal;
> > > +
> > > +	mode->hdisplay = hdisplay;
> > > +	mode->hsync_start = hdisplay + hsync_start * new_htotal / mode->htotal;
> > > +	mode->hsync_end = hdisplay + hsync_end * new_htotal / mode->htotal;
> > > +	mode->htotal = new_htotal;
> > > +}
> > > +
> > > +static void intel_tv_scale_mode_vert(struct drm_display_mode *mode,
> > > +				     int vdisplay, int top_margin,
> > > +				     int bottom_margin)
> > > +{
> > > +	int vsync_start = mode->vsync_start - mode->vdisplay + bottom_margin;
> > > +	int vsync_end = mode->vsync_end - mode->vdisplay + bottom_margin;
> > > +	int new_vtotal = mode->vtotal * vdisplay /
> > > +		(mode->vdisplay - top_margin - bottom_margin);
> > > +
> > > +	mode->clock = mode->clock * new_vtotal / mode->vtotal;
> > > +
> > > +	mode->vdisplay = vdisplay;
> > > +	mode->vsync_start = vdisplay + vsync_start * new_vtotal / mode->vtotal;
> > > +	mode->vsync_end = vdisplay + vsync_end * new_vtotal / mode->vtotal;
> > > +	mode->vtotal = new_vtotal;
> > > +}
> > > +
> > >  static void
> > >  intel_tv_get_config(struct intel_encoder *encoder,
> > >  		    struct intel_crtc_state *pipe_config)
> > >  {
> > > +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > > +	struct drm_display_mode *adjusted_mode =
> > > +		&pipe_config->base.adjusted_mode;
> > > +	struct drm_display_mode mode = {};
> > > +	u32 tv_ctl, hctl1, hctl3, vctl1, vctl2, tmp;
> > > +	struct tv_mode tv_mode = {};
> > > +	int hdisplay = adjusted_mode->crtc_hdisplay;
> > > +	int vdisplay = adjusted_mode->crtc_vdisplay;
> > > +	int xsize, ysize, xpos, ypos;
> > > +
> > >  	pipe_config->output_types |= BIT(INTEL_OUTPUT_TVOUT);
> > >  
> > > -	pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
> > > +	tv_ctl = I915_READ(TV_CTL);
> > > +	hctl1 = I915_READ(TV_H_CTL_1);
> > > +	hctl3 = I915_READ(TV_H_CTL_3);
> > > +	vctl1 = I915_READ(TV_V_CTL_1);
> > > +	vctl2 = I915_READ(TV_V_CTL_2);
> > > +
> > > +	tv_mode.htotal = (hctl1 & TV_HTOTAL_MASK) >> TV_HTOTAL_SHIFT;
> > > +	tv_mode.hsync_end = (hctl1 & TV_HSYNC_END_MASK) >> TV_HSYNC_END_SHIFT;
> > > +
> > > +	tv_mode.hblank_start = (hctl3 & TV_HBLANK_START_MASK) >> TV_HBLANK_START_SHIFT;
> > > +	tv_mode.hblank_end = (hctl3 & TV_HSYNC_END_MASK) >> TV_HBLANK_END_SHIFT;
> > > +
> > > +	tv_mode.nbr_end = (vctl1 & TV_NBR_END_MASK) >> TV_NBR_END_SHIFT;
> > > +	tv_mode.vi_end_f1 = (vctl1 & TV_VI_END_F1_MASK) >> TV_VI_END_F1_SHIFT;
> > > +	tv_mode.vi_end_f2 = (vctl1 & TV_VI_END_F2_MASK) >> TV_VI_END_F2_SHIFT;
> > > +
> > > +	tv_mode.vsync_len = (vctl2 & TV_VSYNC_LEN_MASK) >> TV_VSYNC_LEN_SHIFT;
> > > +	tv_mode.vsync_start_f1 = (vctl2 & TV_VSYNC_START_F1_MASK) >> TV_VSYNC_START_F1_SHIFT;
> > > +	tv_mode.vsync_start_f2 = (vctl2 & TV_VSYNC_START_F2_MASK) >> TV_VSYNC_START_F2_SHIFT;
> > > +
> > > +	tv_mode.clock = pipe_config->port_clock;
> > > +
> > > +	tv_mode.progressive = tv_ctl & TV_PROGRESSIVE;
> > > +
> > > +	switch (tv_ctl & TV_OVERSAMPLE_MASK) {
> > > +	case TV_OVERSAMPLE_8X:
> > > +		tv_mode.oversample = 8;
> > > +		break;
> > > +	case TV_OVERSAMPLE_4X:
> > > +		tv_mode.oversample = 4;
> > > +		break;
> > > +	case TV_OVERSAMPLE_2X:
> > > +		tv_mode.oversample = 2;
> > > +		break;
> > > +	default:
> > > +		tv_mode.oversample = 1;
> > > +		break;
> > > +	}
> > > +
> > > +	tmp = I915_READ(TV_WIN_POS);
> > > +	xpos = tmp >> 16;
> > > +	ypos = tmp & 0xffff;
> > > +
> > > +	tmp = I915_READ(TV_WIN_SIZE);
> > > +	xsize = tmp >> 16;
> > > +	ysize = tmp & 0xffff;
> > > +
> > > +	intel_tv_mode_to_mode(&mode, &tv_mode);
> > > +
> > > +	DRM_DEBUG_KMS("TV mode:\n");
> > > +	drm_mode_debug_printmodeline(&mode);
> > > +
> > > +	intel_tv_scale_mode_horiz(&mode, hdisplay,
> > > +				  xpos, mode.hdisplay - xsize - xpos);
> > > +	intel_tv_scale_mode_vert(&mode, vdisplay,
> > > +				 ypos, mode.vdisplay - ysize - ypos);
> > > +
> > > +	adjusted_mode->crtc_clock = mode.clock;
> > >  }
> > >  
> > >  static bool
> > > @@ -964,6 +1132,8 @@ intel_tv_compute_config(struct intel_encoder *encoder,
> > >  	const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
> > >  	struct drm_display_mode *adjusted_mode =
> > >  		&pipe_config->base.adjusted_mode;
> > > +	int hdisplay = adjusted_mode->crtc_hdisplay;
> > > +	int vdisplay = adjusted_mode->crtc_vdisplay;
> > >  
> > >  	if (!tv_mode)
> > >  		return false;
> > > @@ -972,17 +1142,90 @@ intel_tv_compute_config(struct intel_encoder *encoder,
> > >  		return false;
> > >  
> > >  	pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
> > > -	adjusted_mode->crtc_clock = tv_mode->clock;
> > > +
> > >  	DRM_DEBUG_KMS("forcing bpc to 8 for TV\n");
> > >  	pipe_config->pipe_bpp = 8*3;
> > >  
> > > -	/* TV has it's own notion of sync and other mode flags, so clear them. */
> > > -	adjusted_mode->flags = 0;
> > > +	pipe_config->port_clock = tv_mode->clock;
> > > +
> > > +	intel_tv_mode_to_mode(adjusted_mode, tv_mode);
> > > +
> > > +	DRM_DEBUG_KMS("TV mode:\n");
> > > +	drm_mode_debug_printmodeline(adjusted_mode);
> > >  
> > >  	/*
> > > -	 * FIXME: We don't check whether the input mode is actually what we want
> > > -	 * or whether userspace is doing something stupid.
> > > +	 * The pipe scanline counter behaviour looks as follows when
> > > +	 * using the TV encoder:
> > > +	 *
> > > +	 * time ->
> > > +	 *
> > > +	 * dsl=vtotal-1       |             |
> > > +	 *                   ||            ||
> > > +	 *               ___| |        ___| |
> > > +	 *              /     |       /     |
> > > +	 *             /      |      /      |
> > > +	 * dsl=0   ___/       |_____/       |
> > > +	 *        | | |  |  | |
> > > +	 *         ^ ^ ^   ^ ^
> > > +	 *         | | |   | pipe vblank/first part of tv vblank
> > > +	 *         | | |   bottom margin
> > > +	 *         | | active
> > > +	 *         | top margin
> > > +	 *         remainder of tv vblank
> > > +	 *
> > > +	 * When the TV encoder is used the pipe wants to run faster
> > > +	 * than expected rate. During the active portion the TV
> > > +	 * encoder stalls the pipe every few lines to keep it in
> > > +	 * check. When the TV encoder reaches the bottom margin the
> > > +	 * pipe simply stops. Once we reach the TV vblank the pipe is
> > > +	 * no longer stalled and it runs at the max rate (apparently
> > > +	 * oversample clock on gen3, cdclk on gen4). Once the pipe
> > > +	 * reaches the pipe vtotal the pipe stops for the remainder
> > > +	 * of the TV vblank/top margin. The pipe starts up again when
> > > +	 * the TV encoder exits the top margin.
> > > +	 *
> > > +	 * To avoid huge hassles for vblank timestamping we scale
> > > +	 * the pipe timings as if the pipe always runs at the average
> > > +	 * rate it maintains during the active period. This also
> > > +	 * gives us a reasonable guesstimate as to the pixel rate.
> > > +	 * Due to the variation in the actual pipe speed the scanline
> > > +	 * counter will give us slightly erroneous results during the
> > > +	 * TV vblank/margins. But since vtotal was selected such that
> > > +	 * it matches the average rate of the pipe during the active
> > > +	 * portion the error shouldn't cause any serious grief to
> > > +	 * vblank timestamps.
> > 
> > Nice rev. enging and description. Was thinking for a while what is the
> > max error the isssue you found adds wrt. the actual vblank timestamp,
> > after your change. AFAIU it's the duration of the flats in the curve,
> > that is
> > max_err=+(bottom margin+remainder of tv vblank+top margin).
> > 
> > Reviewed-by: Imre Deak <imre.deak@intel.com>
> > 
> > > +	 *
> > > +	 * For posterity here is the empirically derived formula
> > > +	 * that gives us the maximum length of the pipe vblank
> > > +	 * we can use without causing display corruption. Following
> > > +	 * this would allow us to have a ticking scanline counter
> > > +	 * everywhere except during the bottom margin (there the
> > > +	 * pipe always stops). Ie. this would eliminate the second
> > > +	 * flat portion of the above graph. However this would also
> > > +	 * complicate vblank timestamping as the pipe vtotal would
> > > +	 * no longer match the average rate the pipe runs at during
> > > +	 * the active portion. Hence following this formula seems
> > > +	 * more trouble that it's worth.
> > > +	 *
> > > +	 * if (IS_GEN4(dev_priv)) {
> > > +	 *	num = cdclk * (tv_mode->oversample >> !tv_mode->progressive);
> > > +	 *	den = tv_mode->clock;
> > > +	 * } else {
> > > +	 *	num = tv_mode->oversample >> !tv_mode->progressive;
> > > +	 *	den = 1;
> > > +	 * }
> > > +	 * max_pipe_vblank_len ~=
> > > +	 *	(num * tv_htotal * (tv_vblank_len + top_margin)) /
> > > +	 *	(den * pipe_htotal);
> > >  	 */
> > > +	intel_tv_scale_mode_horiz(adjusted_mode, hdisplay,
> > > +				  conn_state->tv.margins.left,
> > > +				  conn_state->tv.margins.right);
> > > +	intel_tv_scale_mode_vert(adjusted_mode, vdisplay,
> > > +				 conn_state->tv.margins.top,
> > > +				 conn_state->tv.margins.bottom);
> > > +	drm_mode_set_crtcinfo(adjusted_mode, 0);
> > > +	adjusted_mode->name[0] = '\0';
> > >  
> > >  	return true;
> > >  }
> > > @@ -1411,52 +1654,41 @@ intel_tv_set_mode_type(struct drm_display_mode *mode,
> > >  static int
> > >  intel_tv_get_modes(struct drm_connector *connector)
> > >  {
> > > -	struct drm_display_mode *mode_ptr;
> > >  	const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
> > > -	int j, count = 0;
> > > -	u64 tmp;
> > > +	int i, count = 0;
> > >  
> > > -	for (j = 0; j < ARRAY_SIZE(input_res_table);
> > > -	     j++) {
> > > -		const struct input_res *input = &input_res_table[j];
> > > -		unsigned int hactive_s = input->w;
> > > -		unsigned int vactive_s = input->h;
> > > -
> > > -		if (tv_mode->max_srcw && input->w > tv_mode->max_srcw)
> > > -			continue;
> > > +	for (i = 0; i < ARRAY_SIZE(input_res_table); i++) {
> > > +		const struct input_res *input = &input_res_table[i];
> > > +		struct drm_display_mode *mode;
> > >  
> > > -		if (input->w > 1024 && (!tv_mode->progressive
> > > -					&& !tv_mode->component_only))
> > > +		if (input->w > 1024 &&
> > > +		    !tv_mode->progressive &&
> > > +		    !tv_mode->component_only)
> > >  			continue;
> > >  
> > > -		mode_ptr = drm_mode_create(connector->dev);
> > > -		if (!mode_ptr)
> > > +		mode = drm_mode_create(connector->dev);
> > > +		if (!mode)
> > >  			continue;
> > >  
> > > -		mode_ptr->hdisplay = hactive_s;
> > > -		mode_ptr->hsync_start = hactive_s + 1;
> > > -		mode_ptr->hsync_end = hactive_s + 64;
> > > -		if (mode_ptr->hsync_end <= mode_ptr->hsync_start)
> > > -			mode_ptr->hsync_end = mode_ptr->hsync_start + 1;
> > > -		mode_ptr->htotal = hactive_s + 96;
> > > -
> > > -		mode_ptr->vdisplay = vactive_s;
> > > -		mode_ptr->vsync_start = vactive_s + 1;
> > > -		mode_ptr->vsync_end = vactive_s + 32;
> > > -		if (mode_ptr->vsync_end <= mode_ptr->vsync_start)
> > > -			mode_ptr->vsync_end = mode_ptr->vsync_start  + 1;
> > > -		mode_ptr->vtotal = vactive_s + 33;
> > > -
> > > -		tmp = mul_u32_u32(tv_mode->refresh, mode_ptr->vtotal);
> > > -		tmp *= mode_ptr->htotal;
> > > -		tmp = div_u64(tmp, 1000000);
> > > -		mode_ptr->clock = (int) tmp;
> > > -
> > > -		intel_tv_set_mode_type(mode_ptr, tv_mode);
> > > +		/*
> > > +		 * We take the TV mode and scale it to look
> > > +		 * like it had the expected h/vdisplay. This
> > > +		 * provides the most information to userspace
> > > +		 * about the actual timings of the mode. We
> > > +		 * do ignore the margins though.
> > > +		 */
> > > +		intel_tv_mode_to_mode(mode, tv_mode);
> > > +		if (count == 0) {
> > > +			DRM_DEBUG_KMS("TV mode:\n");
> > > +			drm_mode_debug_printmodeline(mode);
> > > +		}
> > > +		intel_tv_scale_mode_horiz(mode, input->w, 0, 0);
> > > +		intel_tv_scale_mode_vert(mode, input->h, 0, 0);
> > > +		intel_tv_set_mode_type(mode, tv_mode);
> > >  
> > > -		drm_mode_set_name(mode_ptr);
> > > +		drm_mode_set_name(mode);
> > >  
> > > -		drm_mode_probed_add(connector, mode_ptr);
> > > +		drm_mode_probed_add(connector, mode);
> > >  		count++;
> > >  	}
> > >  
> > > -- 
> > > 2.18.1
> > > 
> > > _______________________________________________
> > > dri-devel mailing list
> > > dri-devel@lists.freedesktop.org
> > > https://lists.freedesktop.org/mailman/listinfo/dri-devel
> 
> -- 
> Ville Syrjälä
> Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 14/15] drm/i915/tv: Fix >1024 modes on gen3
  2018-11-12 16:59 ` [PATCH 14/15] drm/i915/tv: Fix >1024 modes on gen3 Ville Syrjala
@ 2019-01-23 13:49   ` Imre Deak
  2019-01-23 16:38     ` [Intel-gfx] " Ville Syrjälä
  2019-01-25 18:11     ` [Intel-gfx] " Ville Syrjälä
  0 siblings, 2 replies; 66+ messages in thread
From: Imre Deak @ 2019-01-23 13:49 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, dri-devel

On Mon, Nov 12, 2018 at 06:59:59PM +0200, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> On gen3 we must disable the TV encoder vertical filter for >1024
> pixel wide sources. Once that's done all we can is try to center
> the image on the screen. Naturally the TV mode vertical resolution
> must be equal or larger than the user mode vertical resolution
> or else we'd have to cut off part of the user mode.
> 
> And while we may not be able to respect the user's choice of
> top and bottom borders exactly (or we'd have to reject he mode
> most likely), we can try to maintain the relative sizes of the
> top and bottom border with respect to each orher.
> 
> Additionally we must configure the pipe as interlaced if the
> TV mode is interlaced.
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/intel_tv.c | 100 +++++++++++++++++++++++++++++---
>  1 file changed, 92 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
> index 75126fce655d..7099d837e31a 100644
> --- a/drivers/gpu/drm/i915/intel_tv.c
> +++ b/drivers/gpu/drm/i915/intel_tv.c
> @@ -861,6 +861,44 @@ static const struct tv_mode tv_modes[] = {
>  	},
>  };
>  
> +struct intel_tv_connector_state {
> +	struct drm_connector_state base;
> +
> +	/*
> +	 * May need to override the user margins for
> +	 * gen3 >1024 wide source vertical centering.
> +	 */
> +	struct {
> +		u16 top, bottom;
> +	} margins;
> +
> +	bool bypass_vfilter;
> +};
> +
> +#define to_intel_tv_connector_state(x) container_of(x, struct intel_tv_connector_state, base)
> +
> +/**
> + * intel_digital_connector_duplicate_state - duplicate connector state
      ^intel_tv_connector_duplicate_state
> + * @connector: digital connector
                  ^tv connector?
> + *
> + * Allocates and returns a copy of the connector state (both common and
> + * digital connector specific) for the specified connector.
> + *
> + * Returns: The newly allocated connector state, or NULL on failure.
> + */
> +struct drm_connector_state *
> +intel_tv_connector_duplicate_state(struct drm_connector *connector)
> +{
> +	struct intel_tv_connector_state *state;
> +
> +	state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL);
> +	if (!state)
> +		return NULL;
> +
> +	__drm_atomic_helper_connector_duplicate_state(connector, &state->base);
> +	return &state->base;
> +}

You didn't add the corresponding checks for the new
intel_tv_connector_state fields to intel_tv_atomic_check(). I suppose
that's ok since something resulting in a change in those will force a
modeset anyway:

Reviewed-by: Imre Deak <imre.deak@intel.com>

> +
>  static struct intel_tv *enc_to_tv(struct intel_encoder *encoder)
>  {
>  	return container_of(encoder, struct intel_tv, base);
> @@ -1129,6 +1167,9 @@ intel_tv_compute_config(struct intel_encoder *encoder,
>  			struct intel_crtc_state *pipe_config,
>  			struct drm_connector_state *conn_state)
>  {
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +	struct intel_tv_connector_state *tv_conn_state =
> +		to_intel_tv_connector_state(conn_state);
>  	const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
>  	struct drm_display_mode *adjusted_mode =
>  		&pipe_config->base.adjusted_mode;
> @@ -1149,6 +1190,43 @@ intel_tv_compute_config(struct intel_encoder *encoder,
>  	pipe_config->port_clock = tv_mode->clock;
>  
>  	intel_tv_mode_to_mode(adjusted_mode, tv_mode);
> +	drm_mode_set_crtcinfo(adjusted_mode, 0);
> +
> +	if (IS_GEN3(dev_priv) && hdisplay > 1024) {
> +		int extra, top, bottom;
> +
> +		extra = adjusted_mode->crtc_vdisplay - vdisplay;
> +
> +		if (extra < 0) {
> +			DRM_DEBUG_KMS("No vertical scaling for >1024 pixel wide modes\n");
> +			return false;
> +		}
> +
> +		/* Need to turn off the vertical filter and center the image */
> +
> +		/* Attempt to maintain the relative sizes of the margins */
> +		top = conn_state->tv.margins.top;
> +		bottom = conn_state->tv.margins.bottom;
> +
> +		if (top + bottom)
> +			top = extra * top / (top + bottom);
> +		else
> +			top = extra / 2;
> +		bottom = extra - top;
> +
> +		tv_conn_state->margins.top = top;
> +		tv_conn_state->margins.bottom = bottom;
> +
> +		tv_conn_state->bypass_vfilter = true;
> +
> +		if (!tv_mode->progressive)
> +			adjusted_mode->flags |= DRM_MODE_FLAG_INTERLACE;
> +	} else {
> +		tv_conn_state->margins.top = conn_state->tv.margins.top;
> +		tv_conn_state->margins.bottom = conn_state->tv.margins.bottom;
> +
> +		tv_conn_state->bypass_vfilter = false;
> +	}
>  
>  	DRM_DEBUG_KMS("TV mode:\n");
>  	drm_mode_debug_printmodeline(adjusted_mode);
> @@ -1222,8 +1300,8 @@ intel_tv_compute_config(struct intel_encoder *encoder,
>  				  conn_state->tv.margins.left,
>  				  conn_state->tv.margins.right);
>  	intel_tv_scale_mode_vert(adjusted_mode, vdisplay,
> -				 conn_state->tv.margins.top,
> -				 conn_state->tv.margins.bottom);
> +				 tv_conn_state->margins.top,
> +				 tv_conn_state->margins.bottom);
>  	drm_mode_set_crtcinfo(adjusted_mode, 0);
>  	adjusted_mode->name[0] = '\0';
>  
> @@ -1316,8 +1394,10 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder,
>  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
>  	struct intel_tv *intel_tv = enc_to_tv(encoder);
> +	const struct intel_tv_connector_state *tv_conn_state =
> +		to_intel_tv_connector_state(conn_state);
>  	const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
> -	u32 tv_ctl;
> +	u32 tv_ctl, tv_filter_ctl;
>  	u32 scctl1, scctl2, scctl3;
>  	int i, j;
>  	const struct video_levels *video_levels;
> @@ -1425,16 +1505,20 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder,
>  	assert_pipe_disabled(dev_priv, intel_crtc->pipe);
>  
>  	/* Filter ctl must be set before TV_WIN_SIZE */
> -	I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);
> +	tv_filter_ctl = TV_AUTO_SCALE;
> +	if (tv_conn_state->bypass_vfilter)
> +		tv_filter_ctl |= TV_V_FILTER_BYPASS;
> +	I915_WRITE(TV_FILTER_CTL_1, tv_filter_ctl);
> +
>  	xsize = tv_mode->hblank_start - tv_mode->hblank_end;
>  	ysize = intel_tv_mode_vdisplay(tv_mode);
>  
>  	xpos = conn_state->tv.margins.left;
> -	ypos = conn_state->tv.margins.top;
> +	ypos = tv_conn_state->margins.top;
>  	xsize -= (conn_state->tv.margins.left +
>  		  conn_state->tv.margins.right);
> -	ysize -= (conn_state->tv.margins.top +
> -		  conn_state->tv.margins.bottom);
> +	ysize -= (tv_conn_state->margins.top +
> +		  tv_conn_state->margins.bottom);
>  	I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos);
>  	I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize);
>  
> @@ -1701,7 +1785,7 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = {
>  	.destroy = intel_connector_destroy,
>  	.fill_modes = drm_helper_probe_single_connector_modes,
>  	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> -	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> +	.atomic_duplicate_state = intel_tv_connector_duplicate_state,
>  };
>  
>  static int intel_tv_atomic_check(struct drm_connector *connector,
> -- 
> 2.18.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 15/15] drm/i915/tv: Filter out >1024 wide modes that would need vertical scaling on gen3
  2018-11-12 17:00 ` [PATCH 15/15] drm/i915/tv: Filter out >1024 wide modes that would need vertical scaling " Ville Syrjala
@ 2019-01-23 13:49   ` Imre Deak
  0 siblings, 0 replies; 66+ messages in thread
From: Imre Deak @ 2019-01-23 13:49 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, dri-devel

On Mon, Nov 12, 2018 at 07:00:00PM +0200, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Since gen3 can't handle >1024 wide sources with vertical scaling
> let's not advertize such modes in the mode list. Less tempetation
> to the user to try out things that won't work.
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

Reviewed-by: Imre Deak <imre.deak@intel.com>

> ---
>  drivers/gpu/drm/i915/intel_tv.c | 6 ++++++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
> index 7099d837e31a..89c537839273 100644
> --- a/drivers/gpu/drm/i915/intel_tv.c
> +++ b/drivers/gpu/drm/i915/intel_tv.c
> @@ -1738,6 +1738,7 @@ intel_tv_set_mode_type(struct drm_display_mode *mode,
>  static int
>  intel_tv_get_modes(struct drm_connector *connector)
>  {
> +	struct drm_i915_private *dev_priv = to_i915(connector->dev);
>  	const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
>  	int i, count = 0;
>  
> @@ -1750,6 +1751,11 @@ intel_tv_get_modes(struct drm_connector *connector)
>  		    !tv_mode->component_only)
>  			continue;
>  
> +		/* no vertical scaling with wide sources on gen3 */
> +		if (IS_GEN3(dev_priv) && input->w > 1024 &&
> +		    input->h > intel_tv_mode_vdisplay(tv_mode))
> +			continue;
> +
>  		mode = drm_mode_create(connector->dev);
>  		if (!mode)
>  			continue;
> -- 
> 2.18.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [Intel-gfx] [PATCH 14/15] drm/i915/tv: Fix >1024 modes on gen3
  2019-01-23 13:49   ` Imre Deak
@ 2019-01-23 16:38     ` Ville Syrjälä
  2019-01-24 10:40       ` Imre Deak
  2019-01-25 18:11     ` [Intel-gfx] " Ville Syrjälä
  1 sibling, 1 reply; 66+ messages in thread
From: Ville Syrjälä @ 2019-01-23 16:38 UTC (permalink / raw)
  To: Imre Deak; +Cc: intel-gfx, dri-devel

On Wed, Jan 23, 2019 at 03:49:02PM +0200, Imre Deak wrote:
> On Mon, Nov 12, 2018 at 06:59:59PM +0200, Ville Syrjala wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > On gen3 we must disable the TV encoder vertical filter for >1024
> > pixel wide sources. Once that's done all we can is try to center
> > the image on the screen. Naturally the TV mode vertical resolution
> > must be equal or larger than the user mode vertical resolution
> > or else we'd have to cut off part of the user mode.
> > 
> > And while we may not be able to respect the user's choice of
> > top and bottom borders exactly (or we'd have to reject he mode
> > most likely), we can try to maintain the relative sizes of the
> > top and bottom border with respect to each orher.
> > 
> > Additionally we must configure the pipe as interlaced if the
> > TV mode is interlaced.
> > 
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_tv.c | 100 +++++++++++++++++++++++++++++---
> >  1 file changed, 92 insertions(+), 8 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
> > index 75126fce655d..7099d837e31a 100644
> > --- a/drivers/gpu/drm/i915/intel_tv.c
> > +++ b/drivers/gpu/drm/i915/intel_tv.c
> > @@ -861,6 +861,44 @@ static const struct tv_mode tv_modes[] = {
> >  	},
> >  };
> >  
> > +struct intel_tv_connector_state {
> > +	struct drm_connector_state base;
> > +
> > +	/*
> > +	 * May need to override the user margins for
> > +	 * gen3 >1024 wide source vertical centering.
> > +	 */
> > +	struct {
> > +		u16 top, bottom;
> > +	} margins;
> > +
> > +	bool bypass_vfilter;
> > +};
> > +
> > +#define to_intel_tv_connector_state(x) container_of(x, struct intel_tv_connector_state, base)
> > +
> > +/**
> > + * intel_digital_connector_duplicate_state - duplicate connector state
>       ^intel_tv_connector_duplicate_state
> > + * @connector: digital connector
>                   ^tv connector?
> > + *
> > + * Allocates and returns a copy of the connector state (both common and
> > + * digital connector specific) for the specified connector.
> > + *
> > + * Returns: The newly allocated connector state, or NULL on failure.
> > + */
> > +struct drm_connector_state *
> > +intel_tv_connector_duplicate_state(struct drm_connector *connector)
> > +{
> > +	struct intel_tv_connector_state *state;
> > +
> > +	state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL);
> > +	if (!state)
> > +		return NULL;
> > +
> > +	__drm_atomic_helper_connector_duplicate_state(connector, &state->base);
> > +	return &state->base;
> > +}
> 
> You didn't add the corresponding checks for the new
> intel_tv_connector_state fields to intel_tv_atomic_check(). I suppose
> that's ok since something resulting in a change in those will force a
> modeset anyway:

The new fields are not visible to the user so nothing external
will change them. intel_tv_compute_config() (which is executed
after .atomic_check()) will just recompute them based on other
user visible state.

> 
> Reviewed-by: Imre Deak <imre.deak@intel.com>
> 
> > +
> >  static struct intel_tv *enc_to_tv(struct intel_encoder *encoder)
> >  {
> >  	return container_of(encoder, struct intel_tv, base);
> > @@ -1129,6 +1167,9 @@ intel_tv_compute_config(struct intel_encoder *encoder,
> >  			struct intel_crtc_state *pipe_config,
> >  			struct drm_connector_state *conn_state)
> >  {
> > +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > +	struct intel_tv_connector_state *tv_conn_state =
> > +		to_intel_tv_connector_state(conn_state);
> >  	const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
> >  	struct drm_display_mode *adjusted_mode =
> >  		&pipe_config->base.adjusted_mode;
> > @@ -1149,6 +1190,43 @@ intel_tv_compute_config(struct intel_encoder *encoder,
> >  	pipe_config->port_clock = tv_mode->clock;
> >  
> >  	intel_tv_mode_to_mode(adjusted_mode, tv_mode);
> > +	drm_mode_set_crtcinfo(adjusted_mode, 0);
> > +
> > +	if (IS_GEN3(dev_priv) && hdisplay > 1024) {
> > +		int extra, top, bottom;
> > +
> > +		extra = adjusted_mode->crtc_vdisplay - vdisplay;
> > +
> > +		if (extra < 0) {
> > +			DRM_DEBUG_KMS("No vertical scaling for >1024 pixel wide modes\n");
> > +			return false;
> > +		}
> > +
> > +		/* Need to turn off the vertical filter and center the image */
> > +
> > +		/* Attempt to maintain the relative sizes of the margins */
> > +		top = conn_state->tv.margins.top;
> > +		bottom = conn_state->tv.margins.bottom;
> > +
> > +		if (top + bottom)
> > +			top = extra * top / (top + bottom);
> > +		else
> > +			top = extra / 2;
> > +		bottom = extra - top;
> > +
> > +		tv_conn_state->margins.top = top;
> > +		tv_conn_state->margins.bottom = bottom;
> > +
> > +		tv_conn_state->bypass_vfilter = true;
> > +
> > +		if (!tv_mode->progressive)
> > +			adjusted_mode->flags |= DRM_MODE_FLAG_INTERLACE;
> > +	} else {
> > +		tv_conn_state->margins.top = conn_state->tv.margins.top;
> > +		tv_conn_state->margins.bottom = conn_state->tv.margins.bottom;
> > +
> > +		tv_conn_state->bypass_vfilter = false;
> > +	}
> >  
> >  	DRM_DEBUG_KMS("TV mode:\n");
> >  	drm_mode_debug_printmodeline(adjusted_mode);
> > @@ -1222,8 +1300,8 @@ intel_tv_compute_config(struct intel_encoder *encoder,
> >  				  conn_state->tv.margins.left,
> >  				  conn_state->tv.margins.right);
> >  	intel_tv_scale_mode_vert(adjusted_mode, vdisplay,
> > -				 conn_state->tv.margins.top,
> > -				 conn_state->tv.margins.bottom);
> > +				 tv_conn_state->margins.top,
> > +				 tv_conn_state->margins.bottom);
> >  	drm_mode_set_crtcinfo(adjusted_mode, 0);
> >  	adjusted_mode->name[0] = '\0';
> >  
> > @@ -1316,8 +1394,10 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder,
> >  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> >  	struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
> >  	struct intel_tv *intel_tv = enc_to_tv(encoder);
> > +	const struct intel_tv_connector_state *tv_conn_state =
> > +		to_intel_tv_connector_state(conn_state);
> >  	const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
> > -	u32 tv_ctl;
> > +	u32 tv_ctl, tv_filter_ctl;
> >  	u32 scctl1, scctl2, scctl3;
> >  	int i, j;
> >  	const struct video_levels *video_levels;
> > @@ -1425,16 +1505,20 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder,
> >  	assert_pipe_disabled(dev_priv, intel_crtc->pipe);
> >  
> >  	/* Filter ctl must be set before TV_WIN_SIZE */
> > -	I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);
> > +	tv_filter_ctl = TV_AUTO_SCALE;
> > +	if (tv_conn_state->bypass_vfilter)
> > +		tv_filter_ctl |= TV_V_FILTER_BYPASS;
> > +	I915_WRITE(TV_FILTER_CTL_1, tv_filter_ctl);
> > +
> >  	xsize = tv_mode->hblank_start - tv_mode->hblank_end;
> >  	ysize = intel_tv_mode_vdisplay(tv_mode);
> >  
> >  	xpos = conn_state->tv.margins.left;
> > -	ypos = conn_state->tv.margins.top;
> > +	ypos = tv_conn_state->margins.top;
> >  	xsize -= (conn_state->tv.margins.left +
> >  		  conn_state->tv.margins.right);
> > -	ysize -= (conn_state->tv.margins.top +
> > -		  conn_state->tv.margins.bottom);
> > +	ysize -= (tv_conn_state->margins.top +
> > +		  tv_conn_state->margins.bottom);
> >  	I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos);
> >  	I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize);
> >  
> > @@ -1701,7 +1785,7 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = {
> >  	.destroy = intel_connector_destroy,
> >  	.fill_modes = drm_helper_probe_single_connector_modes,
> >  	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> > -	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> > +	.atomic_duplicate_state = intel_tv_connector_duplicate_state,
> >  };
> >  
> >  static int intel_tv_atomic_check(struct drm_connector *connector,
> > -- 
> > 2.18.1
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Ville Syrjälä
Intel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 14/15] drm/i915/tv: Fix >1024 modes on gen3
  2019-01-23 16:38     ` [Intel-gfx] " Ville Syrjälä
@ 2019-01-24 10:40       ` Imre Deak
  0 siblings, 0 replies; 66+ messages in thread
From: Imre Deak @ 2019-01-24 10:40 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx, dri-devel

On Wed, Jan 23, 2019 at 06:38:17PM +0200, Ville Syrjälä wrote:
> On Wed, Jan 23, 2019 at 03:49:02PM +0200, Imre Deak wrote:
> > On Mon, Nov 12, 2018 at 06:59:59PM +0200, Ville Syrjala wrote:
> > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > 
> > > On gen3 we must disable the TV encoder vertical filter for >1024
> > > pixel wide sources. Once that's done all we can is try to center
> > > the image on the screen. Naturally the TV mode vertical resolution
> > > must be equal or larger than the user mode vertical resolution
> > > or else we'd have to cut off part of the user mode.
> > > 
> > > And while we may not be able to respect the user's choice of
> > > top and bottom borders exactly (or we'd have to reject he mode
> > > most likely), we can try to maintain the relative sizes of the
> > > top and bottom border with respect to each orher.
> > > 
> > > Additionally we must configure the pipe as interlaced if the
> > > TV mode is interlaced.
> > > 
> > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > ---
> > >  drivers/gpu/drm/i915/intel_tv.c | 100 +++++++++++++++++++++++++++++---
> > >  1 file changed, 92 insertions(+), 8 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
> > > index 75126fce655d..7099d837e31a 100644
> > > --- a/drivers/gpu/drm/i915/intel_tv.c
> > > +++ b/drivers/gpu/drm/i915/intel_tv.c
> > > @@ -861,6 +861,44 @@ static const struct tv_mode tv_modes[] = {
> > >  	},
> > >  };
> > >  
> > > +struct intel_tv_connector_state {
> > > +	struct drm_connector_state base;
> > > +
> > > +	/*
> > > +	 * May need to override the user margins for
> > > +	 * gen3 >1024 wide source vertical centering.
> > > +	 */
> > > +	struct {
> > > +		u16 top, bottom;
> > > +	} margins;
> > > +
> > > +	bool bypass_vfilter;
> > > +};
> > > +
> > > +#define to_intel_tv_connector_state(x) container_of(x, struct intel_tv_connector_state, base)
> > > +
> > > +/**
> > > + * intel_digital_connector_duplicate_state - duplicate connector state
> >       ^intel_tv_connector_duplicate_state
> > > + * @connector: digital connector
> >                   ^tv connector?
> > > + *
> > > + * Allocates and returns a copy of the connector state (both common and
> > > + * digital connector specific) for the specified connector.
> > > + *
> > > + * Returns: The newly allocated connector state, or NULL on failure.
> > > + */
> > > +struct drm_connector_state *
> > > +intel_tv_connector_duplicate_state(struct drm_connector *connector)
> > > +{
> > > +	struct intel_tv_connector_state *state;
> > > +
> > > +	state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL);
> > > +	if (!state)
> > > +		return NULL;
> > > +
> > > +	__drm_atomic_helper_connector_duplicate_state(connector, &state->base);
> > > +	return &state->base;
> > > +}
> > 
> > You didn't add the corresponding checks for the new
> > intel_tv_connector_state fields to intel_tv_atomic_check(). I suppose
> > that's ok since something resulting in a change in those will force a
> > modeset anyway:
> 
> The new fields are not visible to the user so nothing external
> will change them. intel_tv_compute_config() (which is executed
> after .atomic_check()) will just recompute them based on other
> user visible state.

Ah, right, that explains and I missed the fact that it makes no sense to
check any params that are computed :/

> 
> > 
> > Reviewed-by: Imre Deak <imre.deak@intel.com>
> > 
> > > +
> > >  static struct intel_tv *enc_to_tv(struct intel_encoder *encoder)
> > >  {
> > >  	return container_of(encoder, struct intel_tv, base);
> > > @@ -1129,6 +1167,9 @@ intel_tv_compute_config(struct intel_encoder *encoder,
> > >  			struct intel_crtc_state *pipe_config,
> > >  			struct drm_connector_state *conn_state)
> > >  {
> > > +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > > +	struct intel_tv_connector_state *tv_conn_state =
> > > +		to_intel_tv_connector_state(conn_state);
> > >  	const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
> > >  	struct drm_display_mode *adjusted_mode =
> > >  		&pipe_config->base.adjusted_mode;
> > > @@ -1149,6 +1190,43 @@ intel_tv_compute_config(struct intel_encoder *encoder,
> > >  	pipe_config->port_clock = tv_mode->clock;
> > >  
> > >  	intel_tv_mode_to_mode(adjusted_mode, tv_mode);
> > > +	drm_mode_set_crtcinfo(adjusted_mode, 0);
> > > +
> > > +	if (IS_GEN3(dev_priv) && hdisplay > 1024) {
> > > +		int extra, top, bottom;
> > > +
> > > +		extra = adjusted_mode->crtc_vdisplay - vdisplay;
> > > +
> > > +		if (extra < 0) {
> > > +			DRM_DEBUG_KMS("No vertical scaling for >1024 pixel wide modes\n");
> > > +			return false;
> > > +		}
> > > +
> > > +		/* Need to turn off the vertical filter and center the image */
> > > +
> > > +		/* Attempt to maintain the relative sizes of the margins */
> > > +		top = conn_state->tv.margins.top;
> > > +		bottom = conn_state->tv.margins.bottom;
> > > +
> > > +		if (top + bottom)
> > > +			top = extra * top / (top + bottom);
> > > +		else
> > > +			top = extra / 2;
> > > +		bottom = extra - top;
> > > +
> > > +		tv_conn_state->margins.top = top;
> > > +		tv_conn_state->margins.bottom = bottom;
> > > +
> > > +		tv_conn_state->bypass_vfilter = true;
> > > +
> > > +		if (!tv_mode->progressive)
> > > +			adjusted_mode->flags |= DRM_MODE_FLAG_INTERLACE;
> > > +	} else {
> > > +		tv_conn_state->margins.top = conn_state->tv.margins.top;
> > > +		tv_conn_state->margins.bottom = conn_state->tv.margins.bottom;
> > > +
> > > +		tv_conn_state->bypass_vfilter = false;
> > > +	}
> > >  
> > >  	DRM_DEBUG_KMS("TV mode:\n");
> > >  	drm_mode_debug_printmodeline(adjusted_mode);
> > > @@ -1222,8 +1300,8 @@ intel_tv_compute_config(struct intel_encoder *encoder,
> > >  				  conn_state->tv.margins.left,
> > >  				  conn_state->tv.margins.right);
> > >  	intel_tv_scale_mode_vert(adjusted_mode, vdisplay,
> > > -				 conn_state->tv.margins.top,
> > > -				 conn_state->tv.margins.bottom);
> > > +				 tv_conn_state->margins.top,
> > > +				 tv_conn_state->margins.bottom);
> > >  	drm_mode_set_crtcinfo(adjusted_mode, 0);
> > >  	adjusted_mode->name[0] = '\0';
> > >  
> > > @@ -1316,8 +1394,10 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder,
> > >  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > >  	struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
> > >  	struct intel_tv *intel_tv = enc_to_tv(encoder);
> > > +	const struct intel_tv_connector_state *tv_conn_state =
> > > +		to_intel_tv_connector_state(conn_state);
> > >  	const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
> > > -	u32 tv_ctl;
> > > +	u32 tv_ctl, tv_filter_ctl;
> > >  	u32 scctl1, scctl2, scctl3;
> > >  	int i, j;
> > >  	const struct video_levels *video_levels;
> > > @@ -1425,16 +1505,20 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder,
> > >  	assert_pipe_disabled(dev_priv, intel_crtc->pipe);
> > >  
> > >  	/* Filter ctl must be set before TV_WIN_SIZE */
> > > -	I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);
> > > +	tv_filter_ctl = TV_AUTO_SCALE;
> > > +	if (tv_conn_state->bypass_vfilter)
> > > +		tv_filter_ctl |= TV_V_FILTER_BYPASS;
> > > +	I915_WRITE(TV_FILTER_CTL_1, tv_filter_ctl);
> > > +
> > >  	xsize = tv_mode->hblank_start - tv_mode->hblank_end;
> > >  	ysize = intel_tv_mode_vdisplay(tv_mode);
> > >  
> > >  	xpos = conn_state->tv.margins.left;
> > > -	ypos = conn_state->tv.margins.top;
> > > +	ypos = tv_conn_state->margins.top;
> > >  	xsize -= (conn_state->tv.margins.left +
> > >  		  conn_state->tv.margins.right);
> > > -	ysize -= (conn_state->tv.margins.top +
> > > -		  conn_state->tv.margins.bottom);
> > > +	ysize -= (tv_conn_state->margins.top +
> > > +		  tv_conn_state->margins.bottom);
> > >  	I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos);
> > >  	I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize);
> > >  
> > > @@ -1701,7 +1785,7 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = {
> > >  	.destroy = intel_connector_destroy,
> > >  	.fill_modes = drm_helper_probe_single_connector_modes,
> > >  	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> > > -	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> > > +	.atomic_duplicate_state = intel_tv_connector_duplicate_state,
> > >  };
> > >  
> > >  static int intel_tv_atomic_check(struct drm_connector *connector,
> > > -- 
> > > 2.18.1
> > > 
> > > _______________________________________________
> > > Intel-gfx mailing list
> > > Intel-gfx@lists.freedesktop.org
> > > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
> -- 
> Ville Syrjälä
> Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [Intel-gfx] [PATCH 14/15] drm/i915/tv: Fix >1024 modes on gen3
  2019-01-23 13:49   ` Imre Deak
  2019-01-23 16:38     ` [Intel-gfx] " Ville Syrjälä
@ 2019-01-25 18:11     ` Ville Syrjälä
  1 sibling, 0 replies; 66+ messages in thread
From: Ville Syrjälä @ 2019-01-25 18:11 UTC (permalink / raw)
  To: Imre Deak; +Cc: intel-gfx, dri-devel

On Wed, Jan 23, 2019 at 03:49:02PM +0200, Imre Deak wrote:
> On Mon, Nov 12, 2018 at 06:59:59PM +0200, Ville Syrjala wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > On gen3 we must disable the TV encoder vertical filter for >1024
> > pixel wide sources. Once that's done all we can is try to center
> > the image on the screen. Naturally the TV mode vertical resolution
> > must be equal or larger than the user mode vertical resolution
> > or else we'd have to cut off part of the user mode.
> > 
> > And while we may not be able to respect the user's choice of
> > top and bottom borders exactly (or we'd have to reject he mode
> > most likely), we can try to maintain the relative sizes of the
> > top and bottom border with respect to each orher.
> > 
> > Additionally we must configure the pipe as interlaced if the
> > TV mode is interlaced.
> > 
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_tv.c | 100 +++++++++++++++++++++++++++++---
> >  1 file changed, 92 insertions(+), 8 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
> > index 75126fce655d..7099d837e31a 100644
> > --- a/drivers/gpu/drm/i915/intel_tv.c
> > +++ b/drivers/gpu/drm/i915/intel_tv.c
> > @@ -861,6 +861,44 @@ static const struct tv_mode tv_modes[] = {
> >  	},
> >  };
> >  
> > +struct intel_tv_connector_state {
> > +	struct drm_connector_state base;
> > +
> > +	/*
> > +	 * May need to override the user margins for
> > +	 * gen3 >1024 wide source vertical centering.
> > +	 */
> > +	struct {
> > +		u16 top, bottom;
> > +	} margins;
> > +
> > +	bool bypass_vfilter;
> > +};
> > +
> > +#define to_intel_tv_connector_state(x) container_of(x, struct intel_tv_connector_state, base)
> > +
> > +/**
> > + * intel_digital_connector_duplicate_state - duplicate connector state
>       ^intel_tv_connector_duplicate_state
> > + * @connector: digital connector
>                   ^tv connector?

Copy paste fail. I just dropped the kerneldoc here and made the
function static. Also fixed up the s/IS_GEN3(x)/IS_GEN(x,3)/ type
of things and pushed the lot to dinq.

Thanks for the review.

> > + *
> > + * Allocates and returns a copy of the connector state (both common and
> > + * digital connector specific) for the specified connector.
> > + *
> > + * Returns: The newly allocated connector state, or NULL on failure.
> > + */
> > +struct drm_connector_state *
> > +intel_tv_connector_duplicate_state(struct drm_connector *connector)
> > +{
> > +	struct intel_tv_connector_state *state;
> > +
> > +	state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL);
> > +	if (!state)
> > +		return NULL;
> > +
> > +	__drm_atomic_helper_connector_duplicate_state(connector, &state->base);
> > +	return &state->base;
> > +}
> 
> You didn't add the corresponding checks for the new
> intel_tv_connector_state fields to intel_tv_atomic_check(). I suppose
> that's ok since something resulting in a change in those will force a
> modeset anyway:
> 
> Reviewed-by: Imre Deak <imre.deak@intel.com>
> 
> > +
> >  static struct intel_tv *enc_to_tv(struct intel_encoder *encoder)
> >  {
> >  	return container_of(encoder, struct intel_tv, base);
> > @@ -1129,6 +1167,9 @@ intel_tv_compute_config(struct intel_encoder *encoder,
> >  			struct intel_crtc_state *pipe_config,
> >  			struct drm_connector_state *conn_state)
> >  {
> > +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > +	struct intel_tv_connector_state *tv_conn_state =
> > +		to_intel_tv_connector_state(conn_state);
> >  	const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
> >  	struct drm_display_mode *adjusted_mode =
> >  		&pipe_config->base.adjusted_mode;
> > @@ -1149,6 +1190,43 @@ intel_tv_compute_config(struct intel_encoder *encoder,
> >  	pipe_config->port_clock = tv_mode->clock;
> >  
> >  	intel_tv_mode_to_mode(adjusted_mode, tv_mode);
> > +	drm_mode_set_crtcinfo(adjusted_mode, 0);
> > +
> > +	if (IS_GEN3(dev_priv) && hdisplay > 1024) {
> > +		int extra, top, bottom;
> > +
> > +		extra = adjusted_mode->crtc_vdisplay - vdisplay;
> > +
> > +		if (extra < 0) {
> > +			DRM_DEBUG_KMS("No vertical scaling for >1024 pixel wide modes\n");
> > +			return false;
> > +		}
> > +
> > +		/* Need to turn off the vertical filter and center the image */
> > +
> > +		/* Attempt to maintain the relative sizes of the margins */
> > +		top = conn_state->tv.margins.top;
> > +		bottom = conn_state->tv.margins.bottom;
> > +
> > +		if (top + bottom)
> > +			top = extra * top / (top + bottom);
> > +		else
> > +			top = extra / 2;
> > +		bottom = extra - top;
> > +
> > +		tv_conn_state->margins.top = top;
> > +		tv_conn_state->margins.bottom = bottom;
> > +
> > +		tv_conn_state->bypass_vfilter = true;
> > +
> > +		if (!tv_mode->progressive)
> > +			adjusted_mode->flags |= DRM_MODE_FLAG_INTERLACE;
> > +	} else {
> > +		tv_conn_state->margins.top = conn_state->tv.margins.top;
> > +		tv_conn_state->margins.bottom = conn_state->tv.margins.bottom;
> > +
> > +		tv_conn_state->bypass_vfilter = false;
> > +	}
> >  
> >  	DRM_DEBUG_KMS("TV mode:\n");
> >  	drm_mode_debug_printmodeline(adjusted_mode);
> > @@ -1222,8 +1300,8 @@ intel_tv_compute_config(struct intel_encoder *encoder,
> >  				  conn_state->tv.margins.left,
> >  				  conn_state->tv.margins.right);
> >  	intel_tv_scale_mode_vert(adjusted_mode, vdisplay,
> > -				 conn_state->tv.margins.top,
> > -				 conn_state->tv.margins.bottom);
> > +				 tv_conn_state->margins.top,
> > +				 tv_conn_state->margins.bottom);
> >  	drm_mode_set_crtcinfo(adjusted_mode, 0);
> >  	adjusted_mode->name[0] = '\0';
> >  
> > @@ -1316,8 +1394,10 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder,
> >  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> >  	struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
> >  	struct intel_tv *intel_tv = enc_to_tv(encoder);
> > +	const struct intel_tv_connector_state *tv_conn_state =
> > +		to_intel_tv_connector_state(conn_state);
> >  	const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
> > -	u32 tv_ctl;
> > +	u32 tv_ctl, tv_filter_ctl;
> >  	u32 scctl1, scctl2, scctl3;
> >  	int i, j;
> >  	const struct video_levels *video_levels;
> > @@ -1425,16 +1505,20 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder,
> >  	assert_pipe_disabled(dev_priv, intel_crtc->pipe);
> >  
> >  	/* Filter ctl must be set before TV_WIN_SIZE */
> > -	I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);
> > +	tv_filter_ctl = TV_AUTO_SCALE;
> > +	if (tv_conn_state->bypass_vfilter)
> > +		tv_filter_ctl |= TV_V_FILTER_BYPASS;
> > +	I915_WRITE(TV_FILTER_CTL_1, tv_filter_ctl);
> > +
> >  	xsize = tv_mode->hblank_start - tv_mode->hblank_end;
> >  	ysize = intel_tv_mode_vdisplay(tv_mode);
> >  
> >  	xpos = conn_state->tv.margins.left;
> > -	ypos = conn_state->tv.margins.top;
> > +	ypos = tv_conn_state->margins.top;
> >  	xsize -= (conn_state->tv.margins.left +
> >  		  conn_state->tv.margins.right);
> > -	ysize -= (conn_state->tv.margins.top +
> > -		  conn_state->tv.margins.bottom);
> > +	ysize -= (tv_conn_state->margins.top +
> > +		  tv_conn_state->margins.bottom);
> >  	I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos);
> >  	I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize);
> >  
> > @@ -1701,7 +1785,7 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = {
> >  	.destroy = intel_connector_destroy,
> >  	.fill_modes = drm_helper_probe_single_connector_modes,
> >  	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> > -	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> > +	.atomic_duplicate_state = intel_tv_connector_duplicate_state,
> >  };
> >  
> >  static int intel_tv_atomic_check(struct drm_connector *connector,
> > -- 
> > 2.18.1
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Ville Syrjälä
Intel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 66+ messages in thread

end of thread, other threads:[~2019-01-25 18:11 UTC | newest]

Thread overview: 66+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-11-12 16:59 [PATCH 00/15] drm/i915: Fix TV encoder support Ville Syrjala
2018-11-12 16:59 ` [PATCH 01/15] drm/vblank: Allow dynamic per-crtc max_vblank_count Ville Syrjala
2018-11-21  9:27   ` Daniel Vetter
2018-11-21  9:27     ` Daniel Vetter
2018-11-21 11:37     ` Ville Syrjälä
2018-11-21 11:37       ` Ville Syrjälä
2018-11-21 15:19       ` Daniel Vetter
2018-11-21 15:19         ` Daniel Vetter
2018-11-21 16:16         ` Ville Syrjälä
2018-11-21 16:16           ` Ville Syrjälä
2018-11-21 16:22           ` Daniel Vetter
2018-11-21 16:22             ` Daniel Vetter
2018-11-21 16:46             ` Ville Syrjälä
2018-11-21 16:46               ` Ville Syrjälä
2018-11-22  8:53               ` Daniel Vetter
2018-11-22  8:53                 ` Daniel Vetter
2018-11-27 18:20   ` [PATCH v2 " Ville Syrjala
2018-11-27 18:20     ` Ville Syrjala
2018-11-27 19:42     ` Daniel Vetter
2018-11-27 19:42       ` Daniel Vetter
2018-11-12 16:59 ` [PATCH 02/15] drm/i915: Don't try to use the hardware frame counter with i965gm TV output Ville Syrjala
2018-11-27 18:21   ` [PATCH v2 " Ville Syrjala
2018-11-27 20:05   ` [PATCH v3 " Ville Syrjala
2019-01-22 12:51     ` Imre Deak
2019-01-22 12:51       ` Imre Deak
2018-11-12 16:59 ` [PATCH 03/15] drm/i915/tv: Fix interlaced ysize calculation Ville Syrjala
2019-01-22 12:54   ` Imre Deak
2018-11-12 16:59 ` [PATCH 04/15] drm/i915/tv: Fix tv mode clocks Ville Syrjala
2019-01-22 12:56   ` Imre Deak
2018-11-12 16:59 ` [PATCH 05/15] drm/i915/tv: Store the TV oversampling factor in the TV mode Ville Syrjala
2019-01-22 13:03   ` Imre Deak
2018-11-12 16:59 ` [PATCH 06/15] drm/i915/tv: Use bools where appropriate Ville Syrjala
2019-01-22 13:07   ` Imre Deak
2018-11-12 16:59 ` [PATCH 07/15] drm/i915/tv: Nuke silly 0 initialzation of xpos/ypos Ville Syrjala
2019-01-22 13:09   ` Imre Deak
2018-11-12 16:59 ` [PATCH 07/15] drm/i915/tv: Nuke silly 0 inittialization " Ville Syrjala
2018-11-12 16:59 ` [PATCH 08/15] drm/i915/tv: Deobfuscate preferred mode selection Ville Syrjala
2019-01-22 14:43   ` [Intel-gfx] " Imre Deak
2018-11-12 16:59 ` [PATCH 09/15] drm/i915/tv: Use drm_mode_set_name() to name TV modes Ville Syrjala
2019-01-22 14:45   ` Imre Deak
2018-11-12 16:59 ` [PATCH 10/15] drm/i915/tv: Make TV mode autoselection actually useable Ville Syrjala
2019-01-22 14:54   ` Imre Deak
2018-11-12 16:59 ` [PATCH 11/15] drm/i915/tv: Nuke reported_modes[] Ville Syrjala
2019-01-22 15:08   ` Imre Deak
2018-11-12 16:59 ` [PATCH 12/15] drm/i915/tv: Add 1080p30/50/60 TV modes Ville Syrjala
2019-01-22 15:09   ` [Intel-gfx] " Imre Deak
2018-11-12 16:59 ` [PATCH 13/15] drm/i915/tv: Generate better pipe timings for TV encoder Ville Syrjala
2019-01-22 17:22   ` Imre Deak
2019-01-22 17:34     ` Ville Syrjälä
2019-01-23 10:30       ` Imre Deak
2018-11-12 16:59 ` [PATCH 14/15] drm/i915/tv: Fix >1024 modes on gen3 Ville Syrjala
2019-01-23 13:49   ` Imre Deak
2019-01-23 16:38     ` [Intel-gfx] " Ville Syrjälä
2019-01-24 10:40       ` Imre Deak
2019-01-25 18:11     ` [Intel-gfx] " Ville Syrjälä
2018-11-12 17:00 ` [PATCH 15/15] drm/i915/tv: Filter out >1024 wide modes that would need vertical scaling " Ville Syrjala
2019-01-23 13:49   ` Imre Deak
2018-11-12 17:16 ` ✗ Fi.CI.SPARSE: warning for drm/i915: Fix TV encoder support Patchwork
2018-11-12 17:31 ` ✓ Fi.CI.BAT: success " Patchwork
2018-11-12 20:06 ` ✓ Fi.CI.IGT: " Patchwork
2018-11-21 16:51 ` ✗ Fi.CI.BAT: failure for drm/i915: Fix TV encoder support (rev2) Patchwork
2018-11-27 19:11 ` ✗ Fi.CI.SPARSE: warning for drm/i915: Fix TV encoder support (rev4) Patchwork
2018-11-27 19:23 ` ✗ Fi.CI.BAT: failure " Patchwork
2018-11-27 20:37 ` ✗ Fi.CI.SPARSE: warning for drm/i915: Fix TV encoder support (rev5) Patchwork
2018-11-27 20:48 ` ✓ Fi.CI.BAT: success " Patchwork
2018-11-28  5:33 ` ✓ Fi.CI.IGT: " Patchwork

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.