From patchwork Fri Jun 19 08:02:26 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maarten Lankhorst X-Patchwork-Id: 6643361 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id B8223C0020 for ; Fri, 19 Jun 2015 08:02:53 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 851C220965 for ; Fri, 19 Jun 2015 08:02:50 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id C74BD2091F for ; Fri, 19 Jun 2015 08:02:47 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 5E90A6E652; Fri, 19 Jun 2015 01:02:46 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mblankhorst.nl (mblankhorst.nl [141.105.120.124]) by gabe.freedesktop.org (Postfix) with ESMTP id 6469C6ED75 for ; Fri, 19 Jun 2015 01:02:45 -0700 (PDT) Received: from patser.lan (5ED48611.cm-7-5c.dynamic.ziggo.nl [94.212.134.17]) (using TLSv1 with cipher ECDHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) (Authenticated sender: mlankhorst) by mblankhorst.nl (Postfix) with ESMTPSA id 2EE8E18C014; Fri, 19 Jun 2015 10:02:37 +0200 (CEST) From: Maarten Lankhorst To: intel-gfx@lists.freedesktop.org Date: Fri, 19 Jun 2015 10:02:26 +0200 Message-Id: <1434700950-16242-4-git-send-email-maarten.lankhorst@linux.intel.com> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1434700950-16242-1-git-send-email-maarten.lankhorst@linux.intel.com> References: <1434700950-16242-1-git-send-email-maarten.lankhorst@linux.intel.com> Subject: [Intel-gfx] [RFC PATCH 3/7] All changes from try2. X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Spam-Status: No, score=-4.5 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Always read out plane state, and do an initial modeset in modeset_gem_init. --- drivers/gpu/drm/i915/i915_dma.c | 12 +- drivers/gpu/drm/i915/i915_drv.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 7 +- drivers/gpu/drm/i915/intel_atomic.c | 7 - drivers/gpu/drm/i915/intel_display.c | 501 ++++++++++++++++++----------------- drivers/gpu/drm/i915/intel_drv.h | 3 +- drivers/gpu/drm/i915/intel_fbdev.c | 12 +- drivers/gpu/drm/i915/intel_lvds.c | 2 +- 8 files changed, 280 insertions(+), 266 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 88795d2f1819..ede07f6fe7f7 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -393,6 +393,7 @@ static const struct vga_switcheroo_client_ops i915_switcheroo_ops = { static int i915_load_modeset_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_atomic_state *state; int ret; ret = intel_parse_bios(dev); @@ -431,13 +432,18 @@ static int i915_load_modeset_init(struct drm_device *dev) /* Important: The output setup functions called by modeset_init need * working irqs for e.g. gmbus and dp aux transfers. */ - intel_modeset_init(dev); + state = intel_modeset_init(dev); ret = i915_gem_init(dev); - if (ret) + if (ret) { + if (state) { + drm_atomic_state_free(state); + drm_modeset_unlock_all(dev); + } goto cleanup_irq; + } - intel_modeset_gem_init(dev); + intel_modeset_gem_init(dev, state); /* Always safe in the mode setting case. */ /* FIXME: do pre/post-mode set stuff in core KMS code */ diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 78ef0bb53c36..a29b24bca25e 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -758,7 +758,7 @@ static int i915_drm_resume(struct drm_device *dev) spin_unlock_irq(&dev_priv->irq_lock); drm_modeset_lock_all(dev); - intel_modeset_setup_hw_state(dev, true); + intel_display_resume(dev); drm_modeset_unlock_all(dev); intel_dp_mst_resume(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d9410bd4ab59..e67d2f1e3ab8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3233,13 +3233,12 @@ static inline void intel_unregister_dsm_handler(void) { return; } /* modesetting */ extern void intel_modeset_init_hw(struct drm_device *dev); -extern void intel_modeset_init(struct drm_device *dev); -extern void intel_modeset_gem_init(struct drm_device *dev); +extern struct drm_atomic_state *intel_modeset_init(struct drm_device *dev); +extern void intel_modeset_gem_init(struct drm_device *dev, struct drm_atomic_state *); extern void intel_modeset_cleanup(struct drm_device *dev); extern void intel_connector_unregister(struct intel_connector *); extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state); -extern void intel_modeset_setup_hw_state(struct drm_device *dev, - bool force_restore); +extern void intel_display_resume(struct drm_device *dev); extern void i915_redisable_vga(struct drm_device *dev); extern void i915_redisable_vga_power_on(struct drm_device *dev); extern bool ironlake_set_drps(struct drm_device *dev, u8 val); diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 4d87574a2032..f36fcc7ceecb 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -98,13 +98,6 @@ int intel_atomic_check(struct drm_device *dev, return -EINVAL; } - if (crtc_state && - crtc_state->quirks & PIPE_CONFIG_QUIRK_INITIAL_PLANES) { - ret = drm_atomic_add_affected_planes(state, &nuclear_crtc->base); - if (ret) - return ret; - } - ret = drm_atomic_helper_check_planes(dev, state); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 41193dab58c5..9b2acc7b4e29 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -109,6 +109,9 @@ static void skl_init_scalers(struct drm_device *dev, struct intel_crtc *intel_cr struct intel_crtc_state *crtc_state); static int i9xx_get_refclk(const struct intel_crtc_state *crtc_state, int num_connectors); +static void intel_pre_disable_primary(struct drm_crtc *crtc); +static struct drm_atomic_state * +intel_modeset_setup_hw_state(struct drm_device *dev, bool force_restore); static struct intel_encoder *intel_find_encoder(struct intel_connector *connector, int pipe) { @@ -2567,40 +2570,41 @@ update_state_fb(struct drm_plane *plane) static void intel_find_initial_plane_obj(struct intel_crtc *intel_crtc, - struct intel_initial_plane_config *plane_config) + struct intel_initial_plane_config *plane_config, + struct intel_plane_state *plane_state) { + struct drm_atomic_state *state = plane_state->base.state; struct drm_device *dev = intel_crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *c; - struct intel_crtc *i; struct drm_i915_gem_object *obj; - struct drm_plane *primary = intel_crtc->base.primary; struct drm_framebuffer *fb; + struct drm_plane *plane = plane_state->base.plane, *drm_plane; + struct drm_plane_state *drm_plane_state; + int i, ret; if (!plane_config->fb) return; if (intel_alloc_initial_plane_obj(intel_crtc, plane_config)) { - fb = &plane_config->fb->base; - goto valid_fb; - } + int ret; - kfree(plane_config->fb); + fb = &plane_config->fb->base; + ret = intel_pin_and_fence_fb_obj(plane, fb, &plane_state->base, NULL); + if (!ret) + goto valid_fb; + drm_framebuffer_unreference(fb); + } else + kfree(plane_config->fb); /* * Failed to alloc the obj, check to see if we should share * an fb with another CRTC instead */ - for_each_crtc(dev, c) { - i = to_intel_crtc(c); - - if (c == &intel_crtc->base) + for_each_plane_in_state(state, drm_plane, drm_plane_state, i) { + if (drm_plane->type != DRM_PLANE_TYPE_PRIMARY) continue; - if (!i->active) - continue; - - fb = c->primary->fb; + fb = drm_plane_state->fb; if (!fb) continue; @@ -2611,17 +2615,22 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc, } } + intel_pre_disable_primary(&intel_crtc->base); + to_intel_plane(plane)->disable_plane(plane, &intel_crtc->base); + return; valid_fb: + drm_atomic_set_fb_for_plane(&plane_state->base, fb); + ret = drm_atomic_set_crtc_for_plane(&plane_state->base, &intel_crtc->base); + WARN_ON(ret); + plane->fb = fb; + + plane_state->visible = true; obj = intel_fb_obj(fb); if (obj->tiling_mode != I915_TILING_NONE) dev_priv->preserve_bios_swizzle = true; - primary->fb = fb; - primary->crtc = primary->state->crtc = &intel_crtc->base; - update_state_fb(primary); - intel_crtc->base.state->plane_mask |= (1 << drm_plane_index(primary)); obj->frontbuffer_bits |= INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe); } @@ -3229,7 +3238,7 @@ void intel_finish_reset(struct drm_device *dev) dev_priv->display.hpd_irq_setup(dev); spin_unlock_irq(&dev_priv->irq_lock); - intel_modeset_setup_hw_state(dev, true); + intel_display_resume(dev); intel_hpd_init(dev_priv); @@ -6190,6 +6199,11 @@ void intel_display_suspend(struct drm_device *dev) intel_crtc_disable_noatomic(crtc); } +void intel_display_resume(struct drm_device *dev) +{ + intel_modeset_setup_hw_state(dev, true); +} + /* Master function to enable/disable CRTC and corresponding power wells */ int intel_crtc_control(struct drm_crtc *crtc, bool enable) { @@ -7700,9 +7714,14 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode, mode->vsync_end = pipe_config->base.adjusted_mode.crtc_vsync_end; mode->flags = pipe_config->base.adjusted_mode.flags; + mode->type = DRM_MODE_TYPE_DRIVER; mode->clock = pipe_config->base.adjusted_mode.crtc_clock; mode->flags |= pipe_config->base.adjusted_mode.flags; + + mode->hsync = drm_mode_hsync(mode); + mode->vrefresh = drm_mode_vrefresh(mode); + drm_mode_set_name(mode); } static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc) @@ -11772,34 +11791,6 @@ static bool check_encoder_cloning(struct drm_atomic_state *state, return true; } -static void intel_crtc_check_initial_planes(struct drm_crtc *crtc, - struct drm_crtc_state *crtc_state) -{ - struct intel_crtc_state *pipe_config = - to_intel_crtc_state(crtc_state); - struct drm_plane *p; - unsigned visible_mask = 0; - - drm_for_each_plane_mask(p, crtc->dev, crtc_state->plane_mask) { - struct drm_plane_state *plane_state = - drm_atomic_get_existing_plane_state(crtc_state->state, p); - - if (WARN_ON(!plane_state)) - continue; - - if (!plane_state->fb) - crtc_state->plane_mask &= - ~(1 << drm_plane_index(p)); - else if (to_intel_plane_state(plane_state)->visible) - visible_mask |= 1 << drm_plane_index(p); - } - - if (!visible_mask) - return; - - pipe_config->quirks &= ~PIPE_CONFIG_QUIRK_INITIAL_PLANES; -} - static int intel_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state) { @@ -11821,10 +11812,6 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, "[CRTC:%i] mismatch between state->active(%i) and crtc->active(%i)\n", idx, crtc->state->active, intel_crtc->active); - /* plane mask is fixed up after all initial planes are calculated */ - if (pipe_config->quirks & PIPE_CONFIG_QUIRK_INITIAL_PLANES) - intel_crtc_check_initial_planes(crtc, crtc_state); - if (mode_changed) intel_crtc->atomic.update_wm = !crtc_state->active; @@ -12374,24 +12361,35 @@ static bool intel_fuzzy_clock_check(int clock1, int clock2) static bool intel_pipe_config_compare(struct drm_device *dev, struct intel_crtc_state *current_config, - struct intel_crtc_state *pipe_config) + struct intel_crtc_state *pipe_config, + bool check_only) { + bool ret = true; + +#define INTEL_ERR_OR_DBG_KMS(fmt, ...) \ + do { \ + if (!check_only) \ + DRM_ERROR(fmt, ##__VA_ARGS__); \ + else \ + DRM_DEBUG_KMS(fmt, ##__VA_ARGS__); \ + } while (0) + #define PIPE_CONF_CHECK_X(name) \ if (current_config->name != pipe_config->name) { \ - DRM_ERROR("mismatch in " #name " " \ + INTEL_ERR_OR_DBG_KMS("mismatch in " #name " " \ "(expected 0x%08x, found 0x%08x)\n", \ current_config->name, \ pipe_config->name); \ - return false; \ + ret = false; \ } #define PIPE_CONF_CHECK_I(name) \ if (current_config->name != pipe_config->name) { \ - DRM_ERROR("mismatch in " #name " " \ + INTEL_ERR_OR_DBG_KMS("mismatch in " #name " " \ "(expected %i, found %i)\n", \ current_config->name, \ pipe_config->name); \ - return false; \ + ret = false; \ } /* This is required for BDW+ where there is only one set of registers for @@ -12402,30 +12400,30 @@ intel_pipe_config_compare(struct drm_device *dev, #define PIPE_CONF_CHECK_I_ALT(name, alt_name) \ if ((current_config->name != pipe_config->name) && \ (current_config->alt_name != pipe_config->name)) { \ - DRM_ERROR("mismatch in " #name " " \ + INTEL_ERR_OR_DBG_KMS("mismatch in " #name " " \ "(expected %i or %i, found %i)\n", \ current_config->name, \ current_config->alt_name, \ pipe_config->name); \ - return false; \ + ret = false; \ } #define PIPE_CONF_CHECK_FLAGS(name, mask) \ if ((current_config->name ^ pipe_config->name) & (mask)) { \ - DRM_ERROR("mismatch in " #name "(" #mask ") " \ + INTEL_ERR_OR_DBG_KMS("mismatch in " #name "(" #mask ") " \ "(expected %i, found %i)\n", \ current_config->name & (mask), \ pipe_config->name & (mask)); \ - return false; \ + ret = false; \ } #define PIPE_CONF_CHECK_CLOCK_FUZZY(name) \ if (!intel_fuzzy_clock_check(current_config->name, pipe_config->name)) { \ - DRM_ERROR("mismatch in " #name " " \ + INTEL_ERR_OR_DBG_KMS("mismatch in " #name " " \ "(expected %i, found %i)\n", \ current_config->name, \ pipe_config->name); \ - return false; \ + ret = false; \ } #define PIPE_CONF_QUIRK(quirk) \ @@ -12559,8 +12557,9 @@ intel_pipe_config_compare(struct drm_device *dev, #undef PIPE_CONF_CHECK_FLAGS #undef PIPE_CONF_CHECK_CLOCK_FUZZY #undef PIPE_CONF_QUIRK +#undef INTEL_ERR_OR_DBG_KMS - return true; + return ret; } static void check_wm_state(struct drm_device *dev) @@ -12757,7 +12756,7 @@ check_crtc_state(struct drm_device *dev) "(expected %i, found %i)\n", crtc->base.state->active, crtc->active); if (active && - !intel_pipe_config_compare(dev, crtc->config, &pipe_config)) { + !intel_pipe_config_compare(dev, crtc->config, &pipe_config, false)) { I915_STATE_WARN(1, "pipe state doesn't match!\n"); intel_dump_pipe_config(crtc, &pipe_config, "[hw state]"); @@ -13064,20 +13063,6 @@ intel_modeset_compute_config(struct drm_atomic_state *state) continue; } - if (to_intel_crtc_state(crtc_state)->quirks & - PIPE_CONFIG_QUIRK_INITIAL_PLANES) { - ret = drm_atomic_add_affected_planes(state, crtc); - if (ret) - return ret; - - /* - * We ought to handle i915.fastboot here. - * If no modeset is required and the primary plane has - * a fb, update the members of crtc_state as needed, - * and run the necessary updates during vblank evasion. - */ - } - if (!needs_modeset(crtc_state)) { ret = drm_atomic_add_affected_connectors(state, crtc); if (ret) @@ -13140,6 +13125,12 @@ static int __intel_set_mode(struct drm_atomic_state *state) intel_crtc->active = false; intel_disable_shared_dpll(intel_crtc); } + + /* FIXME: Move this to i9xx_crtc_disable when it gets a pointer + * to the old crtc_state. */ + if (to_intel_crtc_state(crtc_state)->quirks & + PIPE_CONFIG_QUIRK_WRONG_PLANE) + intel_crtc->plane = !intel_crtc->plane; } /* Only after disabling all output pipelines that will be changed can we @@ -14975,12 +14966,12 @@ void intel_modeset_init_hw(struct drm_device *dev) intel_enable_gt_powersave(dev); } -void intel_modeset_init(struct drm_device *dev) +struct drm_atomic_state *intel_modeset_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_atomic_state *state; int sprite, ret; enum pipe pipe; - struct intel_crtc *crtc; drm_mode_config_init(dev); @@ -14999,7 +14990,7 @@ void intel_modeset_init(struct drm_device *dev) intel_init_pm(dev); if (INTEL_INFO(dev)->num_pipes == 0) - return; + return NULL; intel_init_display(dev); intel_init_audio(dev); @@ -15054,30 +15045,11 @@ void intel_modeset_init(struct drm_device *dev) intel_fbc_disable(dev); drm_modeset_lock_all(dev); - intel_modeset_setup_hw_state(dev, false); - drm_modeset_unlock_all(dev); - - for_each_intel_crtc(dev, crtc) { - if (!crtc->active) - continue; + state = intel_modeset_setup_hw_state(dev, false); + if (!state) + drm_modeset_unlock_all(dev); - /* - * Note that reserving the BIOS fb up front prevents us - * from stuffing other stolen allocations like the ring - * on top. This prevents some ugliness at boot time, and - * can even allow for smooth boot transitions if the BIOS - * fb is large enough for the active pipe configuration. - */ - if (dev_priv->display.get_initial_plane_config) { - dev_priv->display.get_initial_plane_config(crtc, - &crtc->plane_config); - /* - * If the fb is shared between multiple heads, we'll - * just get the first one. - */ - intel_find_initial_plane_obj(crtc, &crtc->plane_config); - } - } + return state; } static void intel_enable_pipe_a(struct drm_device *dev) @@ -15124,13 +15096,17 @@ intel_check_plane_mapping(struct intel_crtc *crtc) return true; } -static void intel_sanitize_crtc(struct intel_crtc *crtc) +static void intel_sanitize_crtc(struct intel_crtc *crtc, + struct intel_crtc_state *pipe_config, + bool force_restore) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_encoder *encoder; + struct drm_atomic_state *state = pipe_config->base.state; + struct intel_crtc_state *hw_state = + to_intel_crtc_state(crtc->base.state); u32 reg; - bool enable; /* Clear any frame start delays used for debugging left by the BIOS */ reg = PIPECONF(crtc->config->cpu_transcoder); @@ -15144,27 +15120,55 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) drm_crtc_vblank_on(&crtc->base); } - /* We need to sanitize the plane -> pipe mapping first because this will - * disable the crtc (and hence change the state) if it is wrong. Note - * that gen4+ has a fixed plane -> pipe mapping. */ - if (INTEL_INFO(dev)->gen < 4 && !intel_check_plane_mapping(crtc)) { - bool plane; + /* set up current state */ + if (!force_restore && hw_state->base.active) { + bool enable; - DRM_DEBUG_KMS("[CRTC:%d] wrong plane connection detected!\n", - crtc->base.base.id); + memcpy(pipe_config, hw_state, sizeof(*pipe_config)); + __drm_atomic_helper_crtc_duplicate_state(&crtc->base, &pipe_config->base); + pipe_config->base.state = state; - /* Pipe has the wrong plane attached and the plane is active. - * Temporarily change the plane mapping and disable everything - * ... */ - plane = crtc->plane; - to_intel_plane_state(crtc->base.primary->state)->visible = true; - crtc->plane = !plane; - intel_crtc_disable_noatomic(&crtc->base); - crtc->plane = plane; + enable = false; + for_each_encoder_on_crtc(dev, &crtc->base, encoder) + enable |= encoder->connectors_active; + + pipe_config->base.active = !!enable; + } + + if (hw_state->quirks & PIPE_CONFIG_QUIRK_WRONG_PLANE) { + if (force_restore || i915.fastboot) + pipe_config->base.mode_changed = true; + else + pipe_config->base.active = false; } - if (dev_priv->quirks & QUIRK_PIPEA_FORCE && - crtc->pipe == PIPE_A && !crtc->active) { + /* XXX: This is needs to be modified for making fastboot possible + * by default without requiring a modeset. + */ + if (hw_state->base.active && pipe_config->base.active) { + struct intel_crtc_state sw_state; + + memset(&sw_state, 0, sizeof(sw_state)); + sw_state.base = pipe_config->base; + sw_state.scaler_state = pipe_config->scaler_state; + sw_state.shared_dpll = pipe_config->shared_dpll; + sw_state.dpll_hw_state = pipe_config->dpll_hw_state; + sw_state.ddi_pll_sel = pipe_config->ddi_pll_sel; + + intel_modeset_pipe_config(&crtc->base, &sw_state); + + /* Check if we need to force a modeset */ + if (!intel_pipe_config_compare(dev, &sw_state, hw_state, !i915.fastboot)) { + DRM_DEBUG_KMS("sw and hw state differ, forcing modeset\n"); + pipe_config->base.mode_changed = true; + } else { + *pipe_config = sw_state; + } + } + + + if (dev_priv->quirks & QUIRK_PIPEA_FORCE && !hw_state->base.active && + crtc->pipe == PIPE_A && !pipe_config->base.active) { /* BIOS forgot to enable pipe A, this mostly happens after * resume. Force-enable the pipe to fix this, the update_dpms * call below we restore the pipe to the right state, but leave @@ -15172,44 +15176,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) intel_enable_pipe_a(dev); } - /* Adjust the state of the output pipe according to whether we - * have active connectors/encoders. */ - enable = false; - for_each_encoder_on_crtc(dev, &crtc->base, encoder) - enable |= encoder->connectors_active; - - if (!enable) - intel_crtc_disable_noatomic(&crtc->base); - - if (crtc->active != crtc->base.state->active) { - - /* This can happen either due to bugs in the get_hw_state - * functions or because of calls to intel_crtc_disable_noatomic, - * or because the pipe is force-enabled due to the - * pipe A quirk. */ - DRM_DEBUG_KMS("[CRTC:%d] hw state adjusted, was %s, now %s\n", - crtc->base.base.id, - crtc->base.state->enable ? "enabled" : "disabled", - crtc->active ? "enabled" : "disabled"); - - crtc->base.state->enable = crtc->active; - crtc->base.state->active = crtc->active; - crtc->base.enabled = crtc->active; - - /* Because we only establish the connector -> encoder -> - * crtc links if something is active, this means the - * crtc is now deactivated. Break the links. connector - * -> encoder links are only establish when things are - * actually up, hence no need to break them. */ - WARN_ON(crtc->active); - - for_each_encoder_on_crtc(dev, &crtc->base, encoder) { - WARN_ON(encoder->connectors_active); - encoder->base.crtc = NULL; - } - } - - if (crtc->active || HAS_GMCH_DISPLAY(dev)) { + if (hw_state->base.active || HAS_GMCH_DISPLAY(dev)) { /* * We start out with underrun reporting disabled to avoid races. * For correct bookkeeping mark this on active crtcs. @@ -15265,6 +15232,7 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder) for_each_intel_connector(dev, connector) { if (connector->encoder != encoder) continue; + connector->base.dpms = DRM_MODE_DPMS_OFF; connector->base.encoder = NULL; } @@ -15301,74 +15269,54 @@ void i915_redisable_vga(struct drm_device *dev) i915_redisable_vga_power_on(dev); } -static bool primary_get_hw_state(struct intel_crtc *crtc) -{ - struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; - - return !!(I915_READ(DSPCNTR(crtc->plane)) & DISPLAY_PLANE_ENABLE); -} - static int readout_plane_state(struct drm_atomic_state *state, struct intel_crtc *crtc, struct intel_crtc_state *crtc_state) { - struct intel_plane *p; + struct intel_initial_plane_config plane_config = {}; struct drm_plane_state *drm_plane_state; + struct intel_plane *p; bool active = crtc_state->base.active; - int ret = 0; - - if (active) { - crtc_state->quirks |= PIPE_CONFIG_QUIRK_INITIAL_PLANES; - - /* apply to previous sw state too */ - to_intel_crtc_state(crtc->base.state)->quirks |= - PIPE_CONFIG_QUIRK_INITIAL_PLANES; - } for_each_intel_plane(crtc->base.dev, p) { - bool visible = active; + struct intel_plane_state *plane_state; if (crtc->pipe != p->pipe) continue; drm_plane_state = drm_atomic_get_plane_state(state, &p->base); - if (IS_ERR(drm_plane_state)) { - ret = PTR_ERR(drm_plane_state); - break; - } + if (IS_ERR(drm_plane_state)) + return PTR_ERR(drm_plane_state); + plane_state = to_intel_plane_state(drm_plane_state); /* Plane scaler state is not touched here. The first atomic * commit will restore all plane scalers to its old state. */ + plane_state->visible = false; if (active && p->base.type == DRM_PLANE_TYPE_PRIMARY) { - visible = primary_get_hw_state(crtc); - to_intel_plane_state(drm_plane_state)->visible = visible; - } else { - /* - * unknown state, assume it's off to force a transition - * to on when calculating state changes. - */ - to_intel_plane_state(drm_plane_state)->visible = false; - } + to_i915(state->dev)->display.get_initial_plane_config(crtc, &plane_config); + intel_find_initial_plane_obj(crtc, &plane_config, plane_state); + } else if (active) + p->disable_plane(&p->base, &crtc->base); - p->base.crtc = drm_plane_state->crtc; - if (visible) { - crtc_state->base.plane_mask |= - 1 << drm_plane_index(&p->base); - } else { - crtc_state->base.plane_mask &= - ~(1 << drm_plane_index(&p->base)); + if (!plane_state->visible) { + int ret; + ret = drm_atomic_set_crtc_for_plane(drm_plane_state, NULL); + WARN_ON(ret); + drm_atomic_set_fb_for_plane(drm_plane_state, NULL); } + p->base.crtc = drm_plane_state->crtc; } - return ret; + return 0; } static int readout_hw_crtc_state(struct drm_atomic_state *state, struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = to_i915(state->dev); + struct drm_device *dev = state->dev; + struct drm_i915_private *dev_priv = to_i915(dev); struct intel_crtc_state *crtc_state; int ret; @@ -15380,6 +15328,7 @@ static int readout_hw_crtc_state(struct drm_atomic_state *state, if (ret) return ret; + __drm_atomic_helper_crtc_destroy_state(&crtc->base, &crtc_state->base); memset(crtc_state, 0, sizeof(*crtc_state)); crtc_state->base.crtc = &crtc->base; crtc_state->base.state = state; @@ -15397,6 +15346,22 @@ static int readout_hw_crtc_state(struct drm_atomic_state *state, crtc->base.base.id, crtc_state->base.active ? "enabled" : "disabled"); + /* We need to sanitize the plane -> pipe mapping first because this will + * disable the crtc (and hence change the state) if it is wrong. Note + * that gen4+ has a fixed plane -> pipe mapping. */ + if (INTEL_INFO(dev)->gen < 4 && !intel_check_plane_mapping(crtc)) { + DRM_DEBUG_KMS("[CRTC:%d] wrong plane connection detected!\n", + crtc->base.base.id); + + /* Pipe has the wrong plane attached and the plane is active. + * Temporarily change the plane mapping and disable everything + * ... */ + crtc_state->quirks |= + PIPE_CONFIG_QUIRK_WRONG_PLANE; + + crtc->plane = !crtc->plane; + } + return readout_plane_state(state, crtc, crtc_state); } @@ -15512,7 +15477,7 @@ static int readout_hw_connector_encoder_state(struct drm_atomic_state *state) encoder->get_config(encoder, crtc_state); - if (connector_state) + if (!WARN_ON(!connector_state)) connector_state->crtc = &crtc->base; } else { encoder->base.crtc = NULL; @@ -15565,8 +15530,8 @@ err_free: /* Scan out the current hw modeset state, sanitizes it and maps it into the drm * and i915 state tracking structures. */ -void intel_modeset_setup_hw_state(struct drm_device *dev, - bool force_restore) +static struct drm_atomic_state * +intel_modeset_setup_hw_state(struct drm_device *dev, bool force_restore) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; @@ -15574,27 +15539,42 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, struct intel_encoder *encoder; struct drm_atomic_state *state; struct intel_shared_dpll_config shared_dplls[I915_NUM_PLLS]; - int i; + int i, ret; state = intel_modeset_readout_hw_state(dev); if (IS_ERR(state)) { DRM_ERROR("Failed to read out hw state\n"); - return; + return NULL; } drm_atomic_helper_swap_state(dev, state); - /* swap sw/hw dpll state */ - intel_atomic_duplicate_dpll_state(dev_priv, shared_dplls); - intel_shared_dpll_commit(state); - memcpy(to_intel_atomic_state(state)->shared_dpll, - shared_dplls, sizeof(*shared_dplls) * dev_priv->num_shared_dpll); + if (force_restore) { + /* swap sw/hw dpll state */ + intel_atomic_duplicate_dpll_state(dev_priv, shared_dplls); + intel_shared_dpll_commit(state); + memcpy(to_intel_atomic_state(state)->shared_dpll, + shared_dplls, sizeof(*shared_dplls) * dev_priv->num_shared_dpll); + } else { + intel_shared_dpll_commit(state); + to_intel_atomic_state(state)->dpll_set = false; + } /* HW state is read out, now we need to sanitize this mess. */ for_each_intel_encoder(dev, encoder) { intel_sanitize_encoder(encoder); } + if (!force_restore) { + struct drm_connector_state *conn_state; + struct drm_connector *connector; + + for_each_connector_in_state(state, connector, conn_state, i) { + conn_state->best_encoder = connector->state->best_encoder; + conn_state->crtc = connector->state->crtc; + } + } + for_each_crtc_in_state(state, crtc, crtc_state, i) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -15616,7 +15596,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, &crtc->state->adjusted_mode); } - intel_sanitize_crtc(intel_crtc); + intel_sanitize_crtc(intel_crtc, to_intel_crtc_state(crtc_state), force_restore); /* * sanitize_crtc may have forced an update of crtc->state, @@ -15646,29 +15626,28 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, else if (HAS_PCH_SPLIT(dev)) ilk_wm_get_hw_state(dev); - if (force_restore) { - int ret; + if (!force_restore) + return state; - i915_redisable_vga(dev); + i915_redisable_vga(dev); - ret = intel_set_mode(state); - if (ret) { - DRM_ERROR("Failed to restore previous mode\n"); - drm_atomic_state_free(state); - } - } else { + ret = intel_set_mode(state); + if (ret) { + DRM_ERROR("Failed to restore previous mode\n"); drm_atomic_state_free(state); } intel_modeset_check_state(dev); + return NULL; } -void intel_modeset_gem_init(struct drm_device *dev) +void intel_modeset_gem_init(struct drm_device *dev, struct drm_atomic_state *state) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *c; struct drm_i915_gem_object *obj; - int ret; + struct drm_crtc_state *crtc_state; + struct drm_crtc *c; + int ret, i; mutex_lock(&dev->struct_mutex); intel_init_gt_powersave(dev); @@ -15693,27 +15672,67 @@ void intel_modeset_gem_init(struct drm_device *dev) * pinned & fenced. When we do the allocation it's too early * for this. */ - for_each_crtc(dev, c) { - obj = intel_fb_obj(c->primary->fb); + for_each_crtc_in_state(state, c, crtc_state, i) { + struct drm_connector_state *conn_state; + struct drm_connector *connector; + int j; + struct drm_plane *primary = c->primary; + + obj = intel_fb_obj(primary->state->fb); if (obj == NULL) - continue; + goto disable; mutex_lock(&dev->struct_mutex); - ret = intel_pin_and_fence_fb_obj(c->primary, - c->primary->fb, - c->primary->state, - NULL); + ret = intel_pin_and_fence_fb_obj(primary, primary->state->fb, + primary->state, NULL); mutex_unlock(&dev->struct_mutex); - if (ret) { - DRM_ERROR("failed to pin boot fb on pipe %d\n", - to_intel_crtc(c)->pipe); - drm_framebuffer_unreference(c->primary->fb); - c->primary->fb = NULL; - c->primary->crtc = c->primary->state->crtc = NULL; - update_state_fb(c->primary); - c->state->plane_mask &= ~(1 << drm_plane_index(c->primary)); + if (!ret && !crtc_state->active) + goto disable; + + if (!ret) { + struct drm_plane_state *plane_state = + drm_atomic_get_existing_plane_state(state, primary); + + ret = drm_atomic_set_crtc_for_plane(plane_state, c); + WARN_ON(ret); + drm_atomic_set_fb_for_plane(plane_state, primary->state->fb); + continue; + } + + + obj->frontbuffer_bits &= + ~INTEL_FRONTBUFFER_PRIMARY(to_intel_crtc(c)->pipe); + + DRM_ERROR("failed to pin boot fb on pipe %d: %i\n", + to_intel_crtc(c)->pipe, ret); + + drm_framebuffer_unreference(primary->state->fb); + drm_framebuffer_unreference(primary->fb); + primary->fb = primary->state->fb = NULL; + primary->crtc = primary->state->crtc = NULL; + /* Do not update crtc_state->plane_mask, this forces + * the disabling of the primary plane during modeset. + */ + +disable: + crtc_state->active = crtc_state->enable = false; + + ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL); + WARN_ON(ret); + + for_each_connector_in_state(state, connector, conn_state, j) { + if (conn_state->crtc != c) + continue; + + ret = drm_atomic_set_crtc_for_connector(conn_state, NULL); + WARN_ON(ret); } + } + ret = intel_set_mode(state); + if (ret) + DRM_ERROR("Initial modeset failed with %i\n", ret); + drm_modeset_unlock_all(dev); intel_backlight_register(dev); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index bc7d0a003c8e..ea380b83eb5d 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -330,7 +330,7 @@ struct intel_crtc_state { */ #define PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS (1<<0) /* unreliable sync mode.flags */ #define PIPE_CONFIG_QUIRK_INHERITED_MODE (1<<1) /* mode inherited from firmware */ -#define PIPE_CONFIG_QUIRK_INITIAL_PLANES (1<<2) /* planes are in unknown state */ +#define PIPE_CONFIG_QUIRK_WRONG_PLANE (1<<2) /* intel_crtc->plane is wrong */ unsigned long quirks; /* Pipe source size (ie. panel fitter input size) @@ -528,7 +528,6 @@ struct intel_crtc { uint32_t cursor_size; uint32_t cursor_base; - struct intel_initial_plane_config plane_config; struct intel_crtc_state *config; /* reset counter value when the last flip was submitted */ diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 6372cfc7d053..6ac4990a0c11 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -582,7 +582,6 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, struct intel_framebuffer *fb = NULL; struct drm_crtc *crtc; struct intel_crtc *intel_crtc; - struct intel_initial_plane_config *plane_config = NULL; unsigned int max_size = 0; if (!i915.fastboot) @@ -590,20 +589,21 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, /* Find the largest fb */ for_each_crtc(dev, crtc) { + struct intel_framebuffer *plane_fb = + to_intel_framebuffer(crtc->primary->state->fb); intel_crtc = to_intel_crtc(crtc); - if (!intel_crtc->active || !crtc->primary->fb) { + if (!intel_crtc->active || !plane_fb) { DRM_DEBUG_KMS("pipe %c not active or no fb, skipping\n", pipe_name(intel_crtc->pipe)); continue; } - if (intel_crtc->plane_config.size > max_size) { + if (plane_fb->obj->base.size > max_size) { DRM_DEBUG_KMS("found possible fb from plane %c\n", pipe_name(intel_crtc->pipe)); - plane_config = &intel_crtc->plane_config; fb = to_intel_framebuffer(crtc->primary->fb); - max_size = plane_config->size; + max_size = fb->obj->base.size; } } @@ -638,7 +638,6 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, DRM_DEBUG_KMS("fb not wide enough for plane %c (%d vs %d)\n", pipe_name(intel_crtc->pipe), cur_size, fb->base.pitches[0]); - plane_config = NULL; fb = NULL; break; } @@ -659,7 +658,6 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, DRM_DEBUG_KMS("fb not big enough for plane %c (%d vs %d)\n", pipe_name(intel_crtc->pipe), cur_size, max_size); - plane_config = NULL; fb = NULL; break; } diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 161ab26f81fb..78d86ae01621 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -452,7 +452,7 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, */ if (!HAS_PCH_SPLIT(dev)) { drm_modeset_lock_all(dev); - intel_modeset_setup_hw_state(dev, true); + intel_display_resume(dev); drm_modeset_unlock_all(dev); }