From 5c1e34261907736dc3b3a7219b2f48f353f10a93 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 14 Jul 2015 15:58:28 +0200 Subject: [PATCH] drm/i915: Readout initial hw mode. 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 Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 62 ++++++++++++++++++---------- drivers/gpu/drm/i915/intel_fbdev.c | 11 ++--- 2 files changed, 44 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1b8a17c67ff5..a1341cbd40e0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -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); diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index b791f2374f3b..7eff33ff84f6 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -483,18 +483,13 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, * 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;