drm/i915/edp: Allow alternate fixed mode for eDP if available.
authorJim Bride <jim.bride@linux.intel.com>
Wed, 9 Aug 2017 19:48:53 +0000 (12:48 -0700)
committerRodrigo Vivi <rodrigo.vivi@intel.com>
Tue, 15 Aug 2017 23:43:33 +0000 (16:43 -0700)
Some fixed resolution panels actually support more than one mode,
with the only thing different being the refresh rate.  Having this
alternate mode available to us is desirable, because it allows us to
test PSR on panels whose setup time at the preferred mode is too long.
With this patch we allow the use of the alternate mode if it's
available and it was specifically requested.

v2 and v3: Rebase
v4: * Fix up some leaky mode stuff (Chris)
    * Rebase
v5: * Fix a NULL pointer derefrence (David Weinehall)
v6: * Whitespace / spelling / checkpatch clean-up; no functional
      change. (David)
    * Rebase

Cc: David Weinehall <david.weinehall@linux.intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Paulo Zanoni <paulo.r.zanoni@intel.com>
Cc: Jani Nikula <jani.nikula@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: David Weinehall <david.weinehall@linux.intel.com>
Signed-off-by: Jim Bride <jim.bride@linux.intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/1502308133-26892-1-git-send-email-jim.bride@linux.intel.com
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_dsi.c
drivers/gpu/drm/i915/intel_dvo.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_panel.c

index e5f787319725a5274f5ea6cb6b77a054a7e1644b..4fd4853b2250635630fcd7d0363b48a3b8886c52 100644 (file)
@@ -1619,6 +1619,23 @@ static int intel_dp_compute_bpp(struct intel_dp *intel_dp,
        return bpp;
 }
 
+static bool intel_edp_compare_alt_mode(struct drm_display_mode *m1,
+                                      struct drm_display_mode *m2)
+{
+       bool bres = false;
+
+       if (m1 && m2)
+               bres = (m1->hdisplay == m2->hdisplay &&
+                       m1->hsync_start == m2->hsync_start &&
+                       m1->hsync_end == m2->hsync_end &&
+                       m1->htotal == m2->htotal &&
+                       m1->vdisplay == m2->vdisplay &&
+                       m1->vsync_start == m2->vsync_start &&
+                       m1->vsync_end == m2->vsync_end &&
+                       m1->vtotal == m2->vtotal);
+       return bres;
+}
+
 bool
 intel_dp_compute_config(struct intel_encoder *encoder,
                        struct intel_crtc_state *pipe_config,
@@ -1665,8 +1682,16 @@ intel_dp_compute_config(struct intel_encoder *encoder,
                pipe_config->has_audio = intel_conn_state->force_audio == HDMI_AUDIO_ON;
 
        if (is_edp(intel_dp) && intel_connector->panel.fixed_mode) {
-               intel_fixed_panel_mode(intel_connector->panel.fixed_mode,
-                                      adjusted_mode);
+               struct drm_display_mode *panel_mode =
+                       intel_connector->panel.alt_fixed_mode;
+               struct drm_display_mode *req_mode = &pipe_config->base.mode;
+
+               if (!intel_edp_compare_alt_mode(req_mode, panel_mode))
+                       panel_mode = intel_connector->panel.fixed_mode;
+
+               drm_mode_debug_printmodeline(panel_mode);
+
+               intel_fixed_panel_mode(panel_mode, adjusted_mode);
 
                if (INTEL_GEN(dev_priv) >= 9) {
                        int ret;
@@ -5794,6 +5819,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
        struct drm_device *dev = intel_encoder->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct drm_display_mode *fixed_mode = NULL;
+       struct drm_display_mode *alt_fixed_mode = NULL;
        struct drm_display_mode *downclock_mode = NULL;
        bool has_dpcd;
        struct drm_display_mode *scan;
@@ -5849,13 +5875,14 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
        }
        intel_connector->edid = edid;
 
-       /* prefer fixed mode from EDID if available */
+       /* prefer fixed mode from EDID if available, save an alt mode also */
        list_for_each_entry(scan, &connector->probed_modes, head) {
                if ((scan->type & DRM_MODE_TYPE_PREFERRED)) {
                        fixed_mode = drm_mode_duplicate(dev, scan);
                        downclock_mode = intel_dp_drrs_init(
                                                intel_connector, fixed_mode);
-                       break;
+               } else if (!alt_fixed_mode) {
+                       alt_fixed_mode = drm_mode_duplicate(dev, scan);
                }
        }
 
@@ -5892,7 +5919,8 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
                              pipe_name(pipe));
        }
 
-       intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode);
+       intel_panel_init(&intel_connector->panel, fixed_mode, alt_fixed_mode,
+                        downclock_mode);
        intel_connector->panel.backlight.power = intel_edp_backlight_power;
        intel_panel_setup_backlight(connector, pipe);
 
index b1dd5d6ed0f3e8f1693e8c8b641b834eb18a7949..fa47285918f4d9fcbf67941a449fdd4c1e9b0552 100644 (file)
@@ -265,6 +265,7 @@ struct intel_encoder {
 
 struct intel_panel {
        struct drm_display_mode *fixed_mode;
+       struct drm_display_mode *alt_fixed_mode;
        struct drm_display_mode *downclock_mode;
 
        /* backlight */
@@ -1678,6 +1679,7 @@ void intel_overlay_reset(struct drm_i915_private *dev_priv);
 /* intel_panel.c */
 int intel_panel_init(struct intel_panel *panel,
                     struct drm_display_mode *fixed_mode,
+                    struct drm_display_mode *alt_fixed_mode,
                     struct drm_display_mode *downclock_mode);
 void intel_panel_fini(struct intel_panel *panel);
 void intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
index b0b3adf016f830ab394fbbe27344cd3f43a52e56..f0c11aec5ea5c99933f4243d9ce408692cd66cda 100644 (file)
@@ -1849,7 +1849,7 @@ void intel_dsi_init(struct drm_i915_private *dev_priv)
        connector->display_info.width_mm = fixed_mode->width_mm;
        connector->display_info.height_mm = fixed_mode->height_mm;
 
-       intel_panel_init(&intel_connector->panel, fixed_mode, NULL);
+       intel_panel_init(&intel_connector->panel, fixed_mode, NULL, NULL);
        intel_panel_setup_backlight(connector, INVALID_PIPE);
 
        intel_dsi_add_properties(intel_connector);
index baf369d2de304b56883e6aa1a83dec909516d59b..c0a027274c0661570b1dc1c69ecbcbc3f3039f76 100644 (file)
@@ -552,7 +552,7 @@ void intel_dvo_init(struct drm_i915_private *dev_priv)
                         */
                        intel_panel_init(&intel_connector->panel,
                                         intel_dvo_get_current_mode(connector),
-                                        NULL);
+                                        NULL, NULL);
                        intel_dvo->panel_wants_dither = true;
                }
 
index 61d557948e2150bd9e511baccf930722950026e1..8e215777c7f49460499e23a915a1a4b88366838e 100644 (file)
@@ -1138,7 +1138,8 @@ void intel_lvds_init(struct drm_i915_private *dev_priv)
 out:
        mutex_unlock(&dev->mode_config.mutex);
 
-       intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode);
+       intel_panel_init(&intel_connector->panel, fixed_mode, NULL,
+                        downclock_mode);
        intel_panel_setup_backlight(connector, INVALID_PIPE);
 
        lvds_encoder->is_dual_link = compute_is_dual_link_lvds(lvds_encoder);
index 88018fccdb9fcff550c9326d525a0033070a1e8e..a17b1de7d7e0edf9ec2f605a2d257227587599ba 100644 (file)
@@ -1920,11 +1920,13 @@ intel_panel_init_backlight_funcs(struct intel_panel *panel)
 
 int intel_panel_init(struct intel_panel *panel,
                     struct drm_display_mode *fixed_mode,
+                    struct drm_display_mode *alt_fixed_mode,
                     struct drm_display_mode *downclock_mode)
 {
        intel_panel_init_backlight_funcs(panel);
 
        panel->fixed_mode = fixed_mode;
+       panel->alt_fixed_mode = alt_fixed_mode;
        panel->downclock_mode = downclock_mode;
 
        return 0;
@@ -1938,6 +1940,10 @@ void intel_panel_fini(struct intel_panel *panel)
        if (panel->fixed_mode)
                drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode);
 
+       if (panel->alt_fixed_mode)
+               drm_mode_destroy(intel_connector->base.dev,
+                               panel->alt_fixed_mode);
+
        if (panel->downclock_mode)
                drm_mode_destroy(intel_connector->base.dev,
                                panel->downclock_mode);