[Intel-gfx] [RFC PATCH 3/7] All changes from try2.
Maarten Lankhorst
maarten.lankhorst at linux.intel.com
Fri Jun 19 01:02:26 PDT 2015
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);
}
--
2.1.0
More information about the Intel-gfx
mailing list