drm/i915: Accept more fixed modes with VRR panels
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Tue, 31 May 2022 19:18:41 +0000 (22:18 +0300)
committerVille Syrjälä <ville.syrjala@linux.intel.com>
Wed, 1 Jun 2022 13:45:42 +0000 (16:45 +0300)
It seem that when dealing with VRR capable eDP panels we need
to accept fixed modes with variable vblank length (which is what
VRR varies dynamically). Typically the preferred mode seems to be
a non-VRR more (lowish dotclock/refresh rate + short vblank).

We also have examples where it looks like even the hblank length
is a bit different between the preferred mode vs. VRR mode(s).
So let's just accept anything that has matching hdisp+vdisp+flags.

v2: Document that is_alt_drrs_mode() is a subset of is_alt_vrr_mode() (Jani)

Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/125
Reviewed-by: Jani Nikula <jani.nikula@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220531191844.11313-4-ville.syrjala@linux.intel.com
drivers/gpu/drm/i915/display/intel_dp.c
drivers/gpu/drm/i915/display/intel_lvds.c
drivers/gpu/drm/i915/display/intel_panel.c
drivers/gpu/drm/i915/display/intel_panel.h
drivers/gpu/drm/i915/display/intel_sdvo.c

index f74acc746d11a5242b84c08d78191a6d3aa43dfb..a00c82ac46f48d73e6f81d7f6f249b0a41716e8f 100644 (file)
@@ -5216,7 +5216,8 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
                              IS_ERR(edid) ? NULL : edid);
 
        intel_panel_add_edid_fixed_modes(intel_connector,
-                                        intel_connector->panel.vbt.drrs_type != DRRS_TYPE_NONE);
+                                        intel_connector->panel.vbt.drrs_type != DRRS_TYPE_NONE,
+                                        intel_vrr_is_capable(intel_connector));
 
        /* MSO requires information from the EDID */
        intel_edp_mso_init(intel_dp);
index 595f03343939fcac1f6f218f9cb6ac19012d2ff5..e55802b454613fb8267955ca8b1e10e1af666b52 100644 (file)
@@ -972,7 +972,8 @@ void intel_lvds_init(struct drm_i915_private *dev_priv)
 
        /* Try EDID first */
        intel_panel_add_edid_fixed_modes(intel_connector,
-                                        intel_connector->panel.vbt.drrs_type != DRRS_TYPE_NONE);
+                                        intel_connector->panel.vbt.drrs_type != DRRS_TYPE_NONE,
+                                        false);
 
        /* Failed to get EDID, what about VBT? */
        if (!intel_panel_preferred_fixed_mode(intel_connector))
index f55e4eafd74ea6c38d5a9f2b8bf10b46a6b07259..237a40623dd7b8dab8e9efb53e22f832740c2e6f 100644 (file)
@@ -71,6 +71,27 @@ intel_panel_fixed_mode(struct intel_connector *connector,
        return best_mode;
 }
 
+static bool is_alt_drrs_mode(const struct drm_display_mode *mode,
+                            const struct drm_display_mode *preferred_mode)
+{
+       return drm_mode_match(mode, preferred_mode,
+                             DRM_MODE_MATCH_TIMINGS |
+                             DRM_MODE_MATCH_FLAGS |
+                             DRM_MODE_MATCH_3D_FLAGS) &&
+               mode->clock != preferred_mode->clock;
+}
+
+static bool is_alt_vrr_mode(const struct drm_display_mode *mode,
+                           const struct drm_display_mode *preferred_mode)
+{
+       return drm_mode_match(mode, preferred_mode,
+                             DRM_MODE_MATCH_FLAGS |
+                             DRM_MODE_MATCH_3D_FLAGS) &&
+               mode->hdisplay == preferred_mode->hdisplay &&
+               mode->vdisplay == preferred_mode->vdisplay &&
+               mode->clock != preferred_mode->clock;
+}
+
 const struct drm_display_mode *
 intel_panel_downclock_mode(struct intel_connector *connector,
                           const struct drm_display_mode *adjusted_mode)
@@ -83,7 +104,8 @@ intel_panel_downclock_mode(struct intel_connector *connector,
        list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head) {
                int vrefresh = drm_mode_vrefresh(fixed_mode);
 
-               if (vrefresh >= min_vrefresh && vrefresh < max_vrefresh) {
+               if (is_alt_drrs_mode(fixed_mode, adjusted_mode) &&
+                   vrefresh >= min_vrefresh && vrefresh < max_vrefresh) {
                        max_vrefresh = vrefresh;
                        best_mode = fixed_mode;
                }
@@ -151,16 +173,18 @@ int intel_panel_compute_config(struct intel_connector *connector,
 }
 
 static bool is_alt_fixed_mode(const struct drm_display_mode *mode,
-                             const struct drm_display_mode *preferred_mode)
+                             const struct drm_display_mode *preferred_mode,
+                             bool has_vrr)
 {
-       return drm_mode_match(mode, preferred_mode,
-                             DRM_MODE_MATCH_TIMINGS |
-                             DRM_MODE_MATCH_FLAGS |
-                             DRM_MODE_MATCH_3D_FLAGS) &&
-               mode->clock != preferred_mode->clock;
+       /* is_alt_drrs_mode() is a subset of is_alt_vrr_mode() */
+       if (has_vrr)
+               return is_alt_vrr_mode(mode, preferred_mode);
+       else
+               return is_alt_drrs_mode(mode, preferred_mode);
 }
 
-static void intel_panel_add_edid_alt_fixed_modes(struct intel_connector *connector)
+static void intel_panel_add_edid_alt_fixed_modes(struct intel_connector *connector,
+                                                bool has_vrr)
 {
        struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
        const struct drm_display_mode *preferred_mode =
@@ -168,7 +192,7 @@ static void intel_panel_add_edid_alt_fixed_modes(struct intel_connector *connect
        struct drm_display_mode *mode, *next;
 
        list_for_each_entry_safe(mode, next, &connector->base.probed_modes, head) {
-               if (!is_alt_fixed_mode(mode, preferred_mode))
+               if (!is_alt_fixed_mode(mode, preferred_mode, has_vrr))
                        continue;
 
                drm_dbg_kms(&dev_priv->drm,
@@ -226,11 +250,12 @@ static void intel_panel_destroy_probed_modes(struct intel_connector *connector)
        }
 }
 
-void intel_panel_add_edid_fixed_modes(struct intel_connector *connector, bool has_drrs)
+void intel_panel_add_edid_fixed_modes(struct intel_connector *connector,
+                                     bool has_drrs, bool has_vrr)
 {
        intel_panel_add_edid_preferred_mode(connector);
-       if (intel_panel_preferred_fixed_mode(connector) && has_drrs)
-               intel_panel_add_edid_alt_fixed_modes(connector);
+       if (intel_panel_preferred_fixed_mode(connector) && (has_drrs || has_vrr))
+               intel_panel_add_edid_alt_fixed_modes(connector, has_vrr);
        intel_panel_destroy_probed_modes(connector);
 }
 
index 2e32bb728beb86e6ac5efc059573c67bed275326..b087c0c3cc6db54610f2241f50c5896ed34e6986 100644 (file)
@@ -40,7 +40,8 @@ int intel_panel_fitting(struct intel_crtc_state *crtc_state,
                        const struct drm_connector_state *conn_state);
 int intel_panel_compute_config(struct intel_connector *connector,
                               struct drm_display_mode *adjusted_mode);
-void intel_panel_add_edid_fixed_modes(struct intel_connector *connector, bool has_drrs);
+void intel_panel_add_edid_fixed_modes(struct intel_connector *connector,
+                                     bool has_drrs, bool has_vrr);
 void intel_panel_add_vbt_lfp_fixed_mode(struct intel_connector *connector);
 void intel_panel_add_vbt_sdvo_fixed_mode(struct intel_connector *connector);
 void intel_panel_add_encoder_fixed_mode(struct intel_connector *connector,
index ba76783994ae059909138be020769f6b54574b84..81f700517e894bbbe3904f81ff1ae1e064a7ce2f 100644 (file)
@@ -2910,7 +2910,7 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)
 
        if (!intel_panel_preferred_fixed_mode(intel_connector)) {
                intel_ddc_get_modes(connector, &intel_sdvo->ddc);
-               intel_panel_add_edid_fixed_modes(intel_connector, false);
+               intel_panel_add_edid_fixed_modes(intel_connector, false, false);
        }
 
        intel_panel_init(intel_connector);