drm/i915: Readout initial hw mode.
authorMaarten Lankhorst <maarten.lankhorst@linux.intel.com>
Tue, 14 Jul 2015 13:58:28 +0000 (15:58 +0200)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Tue, 14 Jul 2015 15:18:51 +0000 (17:18 +0200)
drm/i915: Readout initial hw mode, v2.

Atomic requires a mode blob when crtc_state->enable is true, or
you get a huge warn_on.

With a few tweaks the mode we read out from hardware could be used
as the real mode without a modeset, but this requires too much
testing, so for now force a modeset the first time the mode blob's
updated.

This preserves the old behavior, because previously we never set
the initial mode, which always meant that a modeset happened
when the mode was first set.

Changes since v1:
- Add a description in intel_modeset_readout_hw_state of how the
  recalculation is done.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_fbdev.c

index 1b8a17c67ff5de7560e50b592b892700c33de57e..a1341cbd40e0929a43ce9be37edd91404b8f03df 100644 (file)
@@ -13146,7 +13146,7 @@ intel_modeset_compute_config(struct drm_atomic_state *state)
        for_each_crtc_in_state(state, crtc, crtc_state, i) {
                struct intel_crtc_state *pipe_config =
                        to_intel_crtc_state(crtc_state);
-               bool modeset, recalc;
+               bool modeset, recalc = false;
 
                if (!crtc_state->enable) {
                        if (needs_modeset(crtc_state))
@@ -13155,7 +13155,10 @@ intel_modeset_compute_config(struct drm_atomic_state *state)
                }
 
                modeset = needs_modeset(crtc_state);
-               recalc = pipe_config->quirks & PIPE_CONFIG_QUIRK_INHERITED_MODE;
+               /* see comment in intel_modeset_readout_hw_state */
+               if (!modeset && crtc_state->mode_blob != crtc->state->mode_blob &&
+                   pipe_config->quirks & PIPE_CONFIG_QUIRK_INHERITED_MODE)
+                       recalc = true;
 
                if (!modeset && !recalc)
                        continue;
@@ -13170,9 +13173,10 @@ intel_modeset_compute_config(struct drm_atomic_state *state)
                if (ret)
                        return ret;
 
-               if (recalc && !intel_pipe_config_compare(state->dev,
+               if (recalc && (!i915.fastboot ||
+                   !intel_pipe_config_compare(state->dev,
                                        to_intel_crtc_state(crtc->state),
-                                       pipe_config, true)) {
+                                       pipe_config, true))) {
                        modeset = crtc_state->mode_changed = true;
 
                        ret = drm_atomic_add_affected_planes(state, crtc);
@@ -15451,11 +15455,42 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
                crtc->active = dev_priv->display.get_pipe_config(crtc,
                                                                 crtc->config);
 
-               crtc->base.state->enable = crtc->active;
                crtc->base.state->active = crtc->active;
                crtc->base.enabled = crtc->active;
-               crtc->base.hwmode = crtc->config->base.adjusted_mode;
 
+               memset(&crtc->base.mode, 0, sizeof(crtc->base.mode));
+               if (crtc->base.state->active) {
+                       intel_mode_from_pipe_config(&crtc->base.mode, crtc->config);
+                       intel_mode_from_pipe_config(&crtc->base.state->adjusted_mode, crtc->config);
+                       WARN_ON(drm_atomic_set_mode_for_crtc(crtc->base.state, &crtc->base.mode));
+
+                       /*
+                        * The initial mode needs to be set in order to keep
+                        * the atomic core happy. It wants a valid mode if the
+                        * crtc's enabled, so we do the above call.
+                        *
+                        * At this point some state updated by the connectors
+                        * in their ->detect() callback has not run yet, so
+                        * no recalculation can be done yet.
+                        *
+                        * Even if we could do a recalculation and modeset
+                        * right now it would cause a double modeset if
+                        * fbdev or userspace chooses a different initial mode.
+                        *
+                        * So to prevent the double modeset, fail the memcmp
+                        * test in drm_atomic_set_mode_for_crtc to get a new
+                        * mode blob, and compare if the mode blob changed
+                        * when the PIPE_CONFIG_QUIRK_INHERITED_MODE quirk is
+                        * set.
+                        *
+                        * If that happens, someone indicated they wanted a
+                        * mode change, which means it's safe to do a full
+                        * recalculation.
+                        */
+                       crtc->base.state->mode.private_flags = ~0;
+               }
+
+               crtc->base.hwmode = crtc->config->base.adjusted_mode;
                readout_plane_state(crtc, to_intel_crtc_state(crtc->base.state));
 
                DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n",
@@ -15532,21 +15567,6 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
 
        intel_modeset_readout_hw_state(dev);
 
-       /*
-        * Now that we have the config, copy it to each CRTC struct
-        * Note that this could go away if we move to using crtc_config
-        * checking everywhere.
-        */
-       for_each_intel_crtc(dev, crtc) {
-               if (crtc->active && i915.fastboot) {
-                       intel_mode_from_pipe_config(&crtc->base.mode,
-                                                   crtc->config);
-                       DRM_DEBUG_KMS("[CRTC:%d] found active mode: ",
-                                     crtc->base.base.id);
-                       drm_mode_debug_printmodeline(&crtc->base.mode);
-               }
-       }
-
        /* HW state is read out, now we need to sanitize this mess. */
        for_each_intel_encoder(dev, encoder) {
                intel_sanitize_encoder(encoder);
index b791f2374f3b54cb8643735c142918dd12413054..7eff33ff84f69de52839817ac8d57ac219da5b53 100644 (file)
@@ -483,18 +483,13 @@ retry:
                         * IMPORTANT: We want to use the adjusted mode (i.e.
                         * after the panel fitter upscaling) as the initial
                         * config, not the input mode, which is what crtc->mode
-                        * usually contains. But since our current fastboot
+                        * usually contains. But since our current
                         * code puts a mode derived from the post-pfit timings
-                        * into crtc->mode this works out correctly. We don't
-                        * use hwmode anywhere right now, so use it for this
-                        * since the fb helper layer wants a pointer to
-                        * something we own.
+                        * into crtc->mode this works out correctly.
                         */
                        DRM_DEBUG_KMS("looking for current mode on connector %s\n",
                                      connector->name);
-                       intel_mode_from_pipe_config(&encoder->crtc->hwmode,
-                                                   to_intel_crtc(encoder->crtc)->config);
-                       modes[i] = &encoder->crtc->hwmode;
+                       modes[i] = &encoder->crtc->mode;
                }
                crtcs[i] = new_crtc;