static void ironlake_pch_clock_get(struct intel_crtc *crtc,
struct intel_crtc_state *pipe_config);
-static int intel_set_mode(struct drm_atomic_state *state);
static int intel_framebuffer_init(struct drm_device *dev,
struct intel_framebuffer *ifb,
struct drm_mode_fb_cmd2 *mode_cmd,
struct intel_crtc_state *crtc_state);
static int i9xx_get_refclk(const struct intel_crtc_state *crtc_state,
int num_connectors);
-
-static struct intel_encoder *intel_find_encoder(struct intel_connector *connector, int pipe)
-{
- if (!connector->mst_port)
- return connector->encoder;
- else
- return &connector->mst_port->mst_encoders[pipe]->base;
-}
+static void intel_modeset_setup_hw_state(struct drm_device *dev);
typedef struct {
int min, max;
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);
unsigned long mask;
enum transcoder transcoder;
+ if (!crtc->state->active)
+ return 0;
+
transcoder = intel_pipe_to_cpu_transcoder(dev->dev_private, pipe);
mask = BIT(POWER_DOMAIN_PIPE(pipe));
return mask;
}
-static void modeset_update_crtc_power_domains(struct drm_atomic_state *state)
+static unsigned long modeset_get_crtc_power_domains(struct drm_crtc *crtc)
{
- struct drm_device *dev = state->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- unsigned long pipe_domains[I915_MAX_PIPES] = { 0, };
- struct intel_crtc *crtc;
+ struct drm_i915_private *dev_priv = crtc->dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ enum intel_display_power_domain domain;
+ unsigned long domains, new_domains, old_domains;
- /*
- * First get all needed power domains, then put all unneeded, to avoid
- * any unnecessary toggling of the power wells.
- */
- for_each_intel_crtc(dev, crtc) {
- enum intel_display_power_domain domain;
+ old_domains = intel_crtc->enabled_power_domains;
+ intel_crtc->enabled_power_domains = new_domains = get_crtc_power_domains(crtc);
- if (!crtc->base.state->enable)
- continue;
+ domains = new_domains & ~old_domains;
- pipe_domains[crtc->pipe] = get_crtc_power_domains(&crtc->base);
+ for_each_power_domain(domain, domains)
+ intel_display_power_get(dev_priv, domain);
+
+ return old_domains & ~new_domains;
+}
+
+static void modeset_put_power_domains(struct drm_i915_private *dev_priv,
+ unsigned long domains)
+{
+ enum intel_display_power_domain domain;
- for_each_power_domain(domain, pipe_domains[crtc->pipe])
- intel_display_power_get(dev_priv, domain);
+ for_each_power_domain(domain, domains)
+ intel_display_power_put(dev_priv, domain);
+}
+
+static void modeset_update_crtc_power_domains(struct drm_atomic_state *state)
+{
+ struct drm_device *dev = state->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ unsigned long put_domains[I915_MAX_PIPES] = {};
+ struct drm_crtc_state *crtc_state;
+ struct drm_crtc *crtc;
+ int i;
+
+ for_each_crtc_in_state(state, crtc, crtc_state, i) {
+ if (needs_modeset(crtc->state))
+ put_domains[to_intel_crtc(crtc)->pipe] =
+ modeset_get_crtc_power_domains(crtc);
}
if (dev_priv->display.modeset_commit_cdclk) {
dev_priv->display.modeset_commit_cdclk(state);
}
- for_each_intel_crtc(dev, crtc) {
- enum intel_display_power_domain domain;
-
- for_each_power_domain(domain, crtc->enabled_power_domains)
- intel_display_power_put(dev_priv, domain);
-
- crtc->enabled_power_domains = pipe_domains[crtc->pipe];
- }
-
- intel_display_set_init_power(dev_priv, false);
+ for (i = 0; i < I915_MAX_PIPES; i++)
+ if (put_domains[i])
+ modeset_put_power_domains(dev_priv, put_domains[i]);
}
static void intel_update_max_cdclk(struct drm_device *dev)
intel_crtc_disable_planes(crtc, crtc->state->plane_mask);
dev_priv->display.crtc_disable(crtc);
+ intel_disable_shared_dpll(intel_crtc);
domains = intel_crtc->enabled_power_domains;
for_each_power_domain(domain, domains)
* turn all crtc's off, but do not adjust state
* This has to be paired with a call to intel_modeset_setup_hw_state.
*/
-void intel_display_suspend(struct drm_device *dev)
+int intel_display_suspend(struct drm_device *dev)
{
+ struct drm_mode_config *config = &dev->mode_config;
+ struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx;
+ struct drm_atomic_state *state;
struct drm_crtc *crtc;
+ unsigned crtc_mask = 0;
+ int ret = 0;
- for_each_crtc(dev, crtc)
- intel_crtc_disable_noatomic(crtc);
+ if (WARN_ON(!ctx))
+ return 0;
+
+ lockdep_assert_held(&ctx->ww_ctx);
+ state = drm_atomic_state_alloc(dev);
+ if (WARN_ON(!state))
+ return -ENOMEM;
+
+ state->acquire_ctx = ctx;
+ state->allow_modeset = true;
+
+ for_each_crtc(dev, crtc) {
+ struct drm_crtc_state *crtc_state =
+ drm_atomic_get_crtc_state(state, crtc);
+
+ ret = PTR_ERR_OR_ZERO(crtc_state);
+ if (ret)
+ goto free;
+
+ if (!crtc_state->active)
+ continue;
+
+ crtc_state->active = false;
+ crtc_mask |= 1 << drm_crtc_index(crtc);
+ }
+
+ if (crtc_mask) {
+ ret = drm_atomic_commit(state);
+
+ if (!ret) {
+ for_each_crtc(dev, crtc)
+ if (crtc_mask & (1 << drm_crtc_index(crtc)))
+ crtc->state->active = true;
+
+ return ret;
+ }
+ }
+
+free:
+ if (ret)
+ DRM_ERROR("Suspending crtc's failed with %i\n", ret);
+ drm_atomic_state_free(state);
+ return ret;
}
/* Master function to enable/disable CRTC and corresponding power wells */
}
pipe_config->base.active = enable;
- ret = intel_set_mode(state);
+ ret = drm_atomic_commit(state);
if (!ret)
return ret;
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)
int pipe = pipe_config->cpu_transcoder;
enum dpio_channel port = vlv_pipe_to_channel(pipe);
intel_clock_t clock;
- u32 cmn_dw13, pll_dw0, pll_dw1, pll_dw2;
+ u32 cmn_dw13, pll_dw0, pll_dw1, pll_dw2, pll_dw3;
int refclk = 100000;
mutex_lock(&dev_priv->sb_lock);
pll_dw0 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW0(port));
pll_dw1 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW1(port));
pll_dw2 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW2(port));
+ pll_dw3 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW3(port));
mutex_unlock(&dev_priv->sb_lock);
clock.m1 = (pll_dw1 & 0x7) == DPIO_CHV_M1_DIV_BY_2 ? 2 : 0;
- clock.m2 = ((pll_dw0 & 0xff) << 22) | (pll_dw2 & 0x3fffff);
+ clock.m2 = (pll_dw0 & 0xff) << 22;
+ if (pll_dw3 & DPIO_CHV_FRAC_DIV_EN)
+ clock.m2 |= pll_dw2 & 0x3fffff;
clock.n = (pll_dw1 >> DPIO_CHV_N_DIV_SHIFT) & 0xf;
clock.p1 = (cmn_dw13 >> DPIO_CHV_P1_DIV_SHIFT) & 0x7;
clock.p2 = (cmn_dw13 >> DPIO_CHV_P2_DIV_SHIFT) & 0x1f;
retry:
ret = drm_modeset_lock(&config->connection_mutex, ctx);
if (ret)
- goto fail_unlock;
+ goto fail;
/*
* Algorithm gets a little messy:
ret = drm_modeset_lock(&crtc->mutex, ctx);
if (ret)
- goto fail_unlock;
+ goto fail;
ret = drm_modeset_lock(&crtc->primary->mutex, ctx);
if (ret)
- goto fail_unlock;
+ goto fail;
old->dpms_mode = connector->dpms;
old->load_detect_temp = false;
continue;
if (possible_crtc->state->enable)
continue;
- /* This can occur when applying the pipe A quirk on resume. */
- if (to_intel_crtc(possible_crtc)->new_enabled)
- continue;
crtc = possible_crtc;
break;
*/
if (!crtc) {
DRM_DEBUG_KMS("no pipe available for load-detect\n");
- goto fail_unlock;
+ goto fail;
}
ret = drm_modeset_lock(&crtc->mutex, ctx);
if (ret)
- goto fail_unlock;
+ goto fail;
ret = drm_modeset_lock(&crtc->primary->mutex, ctx);
if (ret)
- goto fail_unlock;
- intel_encoder->new_crtc = to_intel_crtc(crtc);
- to_intel_connector(connector)->new_encoder = intel_encoder;
+ goto fail;
intel_crtc = to_intel_crtc(crtc);
- intel_crtc->new_enabled = true;
old->dpms_mode = connector->dpms;
old->load_detect_temp = true;
old->release_fb = NULL;
drm_mode_copy(&crtc_state->base.mode, mode);
- if (intel_set_mode(state)) {
+ if (drm_atomic_commit(state)) {
DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n");
if (old->release_fb)
old->release_fb->funcs->destroy(old->release_fb);
intel_wait_for_vblank(dev, intel_crtc->pipe);
return true;
- fail:
- intel_crtc->new_enabled = crtc->state->enable;
-fail_unlock:
+fail:
drm_atomic_state_free(state);
state = NULL;
if (IS_ERR(crtc_state))
goto fail;
- to_intel_connector(connector)->new_encoder = NULL;
- intel_encoder->new_crtc = NULL;
- intel_crtc->new_enabled = false;
-
connector_state->best_encoder = NULL;
connector_state->crtc = NULL;
if (ret)
goto fail;
- ret = intel_set_mode(state);
+ ret = drm_atomic_commit(state);
if (ret)
goto fail;
static void intel_do_mmio_flip(struct intel_crtc *intel_crtc)
{
struct drm_device *dev = intel_crtc->base.dev;
- bool atomic_update;
u32 start_vbl_count;
intel_mark_page_flip_active(intel_crtc);
- atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
+ intel_pipe_update_start(intel_crtc, &start_vbl_count);
if (INTEL_INFO(dev)->gen >= 9)
skl_do_mmio_flip(intel_crtc);
/* use_mmio_flip() retricts MMIO flips to ilk+ */
ilk_do_mmio_flip(intel_crtc);
- if (atomic_update)
- intel_pipe_update_end(intel_crtc, start_vbl_count);
+ intel_pipe_update_end(intel_crtc, start_vbl_count);
}
static void intel_mmio_flip_work_func(struct work_struct *work)
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)
{
"[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 && !crtc_state->active)
intel_crtc->atomic.update_wm_post = true;
.atomic_check = intel_crtc_atomic_check,
};
-/**
- * intel_modeset_update_staged_output_state
- *
- * Updates the staged output configuration state, e.g. after we've read out the
- * current hw state.
- */
-static void intel_modeset_update_staged_output_state(struct drm_device *dev)
-{
- struct intel_crtc *crtc;
- struct intel_encoder *encoder;
- struct intel_connector *connector;
-
- for_each_intel_connector(dev, connector) {
- connector->new_encoder =
- to_intel_encoder(connector->base.encoder);
- }
-
- for_each_intel_encoder(dev, encoder) {
- encoder->new_crtc =
- to_intel_crtc(encoder->base.crtc);
- }
-
- for_each_intel_crtc(dev, crtc) {
- crtc->new_enabled = crtc->base.state->enable;
- }
-}
-
-/* Transitional helper to copy current connector/encoder state to
- * connector->state. This is needed so that code that is partially
- * converted to atomic does the right thing.
- */
static void intel_modeset_update_connector_atomic_state(struct drm_device *dev)
{
struct intel_connector *connector;
}
drm_atomic_helper_update_legacy_modeset_state(state->dev, state);
- intel_modeset_update_staged_output_state(state->dev);
/* Double check state. */
for_each_crtc_in_state(state, crtc, crtc_state, i) {
struct intel_connector *connector;
for_each_intel_connector(dev, connector) {
+ struct drm_encoder *encoder = connector->base.encoder;
+ struct drm_connector_state *state = connector->base.state;
+
/* This also checks the encoder/connector hw state with the
* ->get_hw_state callbacks. */
intel_connector_check_state(connector);
- I915_STATE_WARN(&connector->new_encoder->base != connector->base.encoder,
+ I915_STATE_WARN(state->best_encoder != encoder,
"connector's staged encoder doesn't match current encoder\n");
}
}
encoder->base.base.id,
encoder->base.name);
- I915_STATE_WARN(&encoder->new_crtc->base != encoder->base.crtc,
- "encoder's stage crtc doesn't match current crtc\n");
I915_STATE_WARN(encoder->connectors_active && !encoder->base.crtc,
"encoder's active_connectors set, but no crtc\n");
enabled = true;
if (connector->base.dpms != DRM_MODE_DPMS_OFF)
active = true;
+
+ I915_STATE_WARN(connector->base.state->crtc !=
+ encoder->base.crtc,
+ "connector's crtc doesn't match encoder crtc\n");
}
/*
* for MST connectors if we unplug the connector is gone
}
-/* Code that should eventually be part of atomic_check() */
static int intel_modeset_checks(struct drm_atomic_state *state)
{
struct drm_device *dev = state->dev;
return 0;
}
-static int
-intel_modeset_compute_config(struct drm_atomic_state *state)
+/**
+ * intel_atomic_check - validate state object
+ * @dev: drm device
+ * @state: state to validate
+ */
+static int intel_atomic_check(struct drm_device *dev,
+ struct drm_atomic_state *state)
{
struct drm_crtc *crtc;
struct drm_crtc_state *crtc_state;
int ret, i;
bool any_ms = false;
- ret = drm_atomic_helper_check_modeset(state->dev, state);
+ ret = drm_atomic_helper_check_modeset(dev, state);
if (ret)
return ret;
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))
continue;
}
- if (pipe_config->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.
- */
- }
-
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;
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);
return drm_atomic_helper_check_planes(state->dev, state);
}
-static int __intel_set_mode(struct drm_atomic_state *state)
+/**
+ * intel_atomic_commit - commit validated state object
+ * @dev: DRM device
+ * @state: the top-level driver state object
+ * @async: asynchronous commit
+ *
+ * This function commits a top-level state object that has been validated
+ * with drm_atomic_helper_check().
+ *
+ * FIXME: Atomic modeset support for i915 is not yet complete. At the moment
+ * we can only handle plane-related operations and do not yet support
+ * asynchronous commit.
+ *
+ * RETURNS
+ * Zero for success or -errno.
+ */
+static int intel_atomic_commit(struct drm_device *dev,
+ struct drm_atomic_state *state,
+ bool async)
{
- struct drm_device *dev = state->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc;
struct drm_crtc_state *crtc_state;
int i;
bool any_ms = false;
+ if (async) {
+ DRM_DEBUG_KMS("i915 does not yet support async commit\n");
+ return -EINVAL;
+ }
+
ret = drm_atomic_helper_prepare_planes(dev, state);
if (ret)
return ret;
/* Now enable the clocks, plane, pipe, and connectors that we set up. */
for_each_crtc_in_state(state, crtc, crtc_state, i) {
- if (needs_modeset(crtc->state) && crtc->state->active) {
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ bool modeset = needs_modeset(crtc->state);
+
+ if (modeset && crtc->state->active) {
update_scanline_offset(to_intel_crtc(crtc));
dev_priv->display.crtc_enable(crtc);
}
+ if (!modeset)
+ intel_pre_plane_update(intel_crtc);
+
drm_atomic_helper_commit_planes_on_crtc(crtc_state);
+ intel_post_plane_update(intel_crtc);
}
/* FIXME: add subpixel order */
+ drm_atomic_helper_wait_for_vblanks(dev, state);
drm_atomic_helper_cleanup_planes(dev, state);
-
drm_atomic_state_free(state);
- return 0;
-}
-
-static int intel_set_mode_checked(struct drm_atomic_state *state)
-{
- struct drm_device *dev = state->dev;
- int ret;
-
- ret = __intel_set_mode(state);
- if (ret == 0)
+ if (any_ms)
intel_modeset_check_state(dev);
- return ret;
-}
-
-static int intel_set_mode(struct drm_atomic_state *state)
-{
- int ret;
-
- ret = intel_modeset_compute_config(state);
- if (ret)
- return ret;
-
- return intel_set_mode_checked(state);
+ return 0;
}
void intel_crtc_restore_mode(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct drm_atomic_state *state;
- struct intel_encoder *encoder;
- struct intel_connector *connector;
- struct drm_connector_state *connector_state;
- struct intel_crtc_state *crtc_state;
+ struct drm_crtc_state *crtc_state;
int ret;
state = drm_atomic_state_alloc(dev);
if (!state) {
- DRM_DEBUG_KMS("[CRTC:%d] mode restore failed, out of memory",
+ DRM_DEBUG_KMS("[CRTC:%d] crtc restore failed, out of memory",
crtc->base.id);
return;
}
- state->acquire_ctx = dev->mode_config.acquire_ctx;
-
- /* The force restore path in the HW readout code relies on the staged
- * config still keeping the user requested config while the actual
- * state has been overwritten by the configuration read from HW. We
- * need to copy the staged config to the atomic state, otherwise the
- * mode set will just reapply the state the HW is already in. */
- for_each_intel_encoder(dev, encoder) {
- if (&encoder->new_crtc->base != crtc)
- continue;
+ state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
- for_each_intel_connector(dev, connector) {
- if (connector->new_encoder != encoder)
- continue;
-
- connector_state = drm_atomic_get_connector_state(state, &connector->base);
- if (IS_ERR(connector_state)) {
- DRM_DEBUG_KMS("Failed to add [CONNECTOR:%d:%s] to state: %ld\n",
- connector->base.base.id,
- connector->base.name,
- PTR_ERR(connector_state));
- continue;
- }
+retry:
+ crtc_state = drm_atomic_get_crtc_state(state, crtc);
+ ret = PTR_ERR_OR_ZERO(crtc_state);
+ if (!ret) {
+ if (!crtc_state->active)
+ goto out;
- connector_state->crtc = crtc;
- connector_state->best_encoder = &encoder->base;
- }
+ crtc_state->mode_changed = true;
+ ret = drm_atomic_commit(state);
}
- crtc_state = intel_atomic_get_crtc_state(state, to_intel_crtc(crtc));
- if (IS_ERR(crtc_state)) {
- DRM_DEBUG_KMS("Failed to add [CRTC:%d] to state: %ld\n",
- crtc->base.id, PTR_ERR(crtc_state));
- drm_atomic_state_free(state);
- return;
+ if (ret == -EDEADLK) {
+ drm_atomic_state_clear(state);
+ drm_modeset_backoff(state->acquire_ctx);
+ goto retry;
}
- crtc_state->base.active = crtc_state->base.enable =
- to_intel_crtc(crtc)->new_enabled;
-
- drm_mode_copy(&crtc_state->base.mode, &crtc->mode);
-
- intel_modeset_setup_plane_state(state, crtc, &crtc->mode,
- crtc->primary->fb, crtc->x, crtc->y);
-
- ret = intel_set_mode(state);
if (ret)
+out:
drm_atomic_state_free(state);
}
#undef for_each_intel_crtc_masked
-static bool intel_connector_in_mode_set(struct intel_connector *connector,
- struct drm_mode_set *set)
-{
- int ro;
-
- for (ro = 0; ro < set->num_connectors; ro++)
- if (set->connectors[ro] == &connector->base)
- return true;
-
- return false;
-}
-
-static int
-intel_modeset_stage_output_state(struct drm_device *dev,
- struct drm_mode_set *set,
- struct drm_atomic_state *state)
-{
- struct intel_connector *connector;
- struct drm_connector *drm_connector;
- struct drm_connector_state *connector_state;
- struct drm_crtc *crtc;
- struct drm_crtc_state *crtc_state;
- int i, ret;
-
- /* The upper layers ensure that we either disable a crtc or have a list
- * of connectors. For paranoia, double-check this. */
- WARN_ON(!set->fb && (set->num_connectors != 0));
- WARN_ON(set->fb && (set->num_connectors == 0));
-
- for_each_intel_connector(dev, connector) {
- bool in_mode_set = intel_connector_in_mode_set(connector, set);
-
- if (!in_mode_set && connector->base.state->crtc != set->crtc)
- continue;
-
- connector_state =
- drm_atomic_get_connector_state(state, &connector->base);
- if (IS_ERR(connector_state))
- return PTR_ERR(connector_state);
-
- if (in_mode_set) {
- int pipe = to_intel_crtc(set->crtc)->pipe;
- connector_state->best_encoder =
- &intel_find_encoder(connector, pipe)->base;
- }
-
- if (connector->base.state->crtc != set->crtc)
- continue;
-
- /* If we disable the crtc, disable all its connectors. Also, if
- * the connector is on the changing crtc but not on the new
- * connector list, disable it. */
- if (!set->fb || !in_mode_set) {
- connector_state->best_encoder = NULL;
-
- DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n",
- connector->base.base.id,
- connector->base.name);
- }
- }
- /* connector->new_encoder is now updated for all connectors. */
-
- for_each_connector_in_state(state, drm_connector, connector_state, i) {
- connector = to_intel_connector(drm_connector);
-
- if (!connector_state->best_encoder) {
- ret = drm_atomic_set_crtc_for_connector(connector_state,
- NULL);
- if (ret)
- return ret;
-
- continue;
- }
-
- if (intel_connector_in_mode_set(connector, set)) {
- struct drm_crtc *crtc = connector->base.state->crtc;
-
- /* If this connector was in a previous crtc, add it
- * to the state. We might need to disable it. */
- if (crtc) {
- crtc_state =
- drm_atomic_get_crtc_state(state, crtc);
- if (IS_ERR(crtc_state))
- return PTR_ERR(crtc_state);
- }
-
- ret = drm_atomic_set_crtc_for_connector(connector_state,
- set->crtc);
- if (ret)
- return ret;
- }
-
- /* Make sure the new CRTC will work with the encoder */
- if (!drm_encoder_crtc_ok(connector_state->best_encoder,
- connector_state->crtc)) {
- return -EINVAL;
- }
-
- DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n",
- connector->base.base.id,
- connector->base.name,
- connector_state->crtc->base.id);
-
- if (connector_state->best_encoder != &connector->encoder->base)
- connector->encoder =
- to_intel_encoder(connector_state->best_encoder);
- }
-
- for_each_crtc_in_state(state, crtc, crtc_state, i) {
- bool has_connectors;
-
- ret = drm_atomic_add_affected_connectors(state, crtc);
- if (ret)
- return ret;
-
- has_connectors = !!drm_atomic_connectors_for_crtc(state, crtc);
- if (has_connectors != crtc_state->enable)
- crtc_state->enable =
- crtc_state->active = has_connectors;
- }
-
- ret = intel_modeset_setup_plane_state(state, set->crtc, set->mode,
- set->fb, set->x, set->y);
- if (ret)
- return ret;
-
- crtc_state = drm_atomic_get_crtc_state(state, set->crtc);
- if (IS_ERR(crtc_state))
- return PTR_ERR(crtc_state);
-
- ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode);
- if (ret)
- return ret;
-
- if (set->num_connectors)
- crtc_state->active = true;
-
- return 0;
-}
-
-static int intel_crtc_set_config(struct drm_mode_set *set)
-{
- struct drm_device *dev;
- struct drm_atomic_state *state = NULL;
- int ret;
-
- BUG_ON(!set);
- BUG_ON(!set->crtc);
- BUG_ON(!set->crtc->helper_private);
-
- /* Enforce sane interface api - has been abused by the fb helper. */
- BUG_ON(!set->mode && set->fb);
- BUG_ON(set->fb && set->num_connectors == 0);
-
- if (set->fb) {
- DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n",
- set->crtc->base.id, set->fb->base.id,
- (int)set->num_connectors, set->x, set->y);
- } else {
- DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id);
- }
-
- dev = set->crtc->dev;
-
- state = drm_atomic_state_alloc(dev);
- if (!state)
- return -ENOMEM;
-
- state->acquire_ctx = dev->mode_config.acquire_ctx;
-
- ret = intel_modeset_stage_output_state(dev, set, state);
- if (ret)
- goto out;
-
- ret = intel_modeset_compute_config(state);
- if (ret)
- goto out;
-
- intel_update_pipe_size(to_intel_crtc(set->crtc));
-
- ret = intel_set_mode_checked(state);
- if (ret) {
- DRM_DEBUG_KMS("failed to set mode on [CRTC:%d], err = %d\n",
- set->crtc->base.id, ret);
- }
-
-out:
- if (ret)
- drm_atomic_state_free(state);
- return ret;
-}
-
static const struct drm_crtc_funcs intel_crtc_funcs = {
.gamma_set = intel_crtc_gamma_set,
- .set_config = intel_crtc_set_config,
+ .set_config = drm_atomic_helper_set_config,
.destroy = intel_crtc_destroy,
.page_flip = intel_crtc_page_flip,
.atomic_duplicate_state = intel_crtc_duplicate_state,
static void intel_begin_crtc_commit(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- if (!needs_modeset(crtc->state))
- intel_pre_plane_update(intel_crtc);
-
if (intel_crtc->atomic.update_wm_pre)
intel_update_watermarks(crtc);
- intel_runtime_pm_get(dev_priv);
-
/* Perform vblank evasion around commit operation */
if (crtc->state->active)
- intel_crtc->atomic.evade =
- intel_pipe_update_start(intel_crtc,
- &intel_crtc->atomic.start_vbl_count);
+ intel_pipe_update_start(intel_crtc, &intel_crtc->start_vbl_count);
if (!needs_modeset(crtc->state) && INTEL_INFO(dev)->gen >= 9)
skl_detach_scalers(intel_crtc);
static void intel_finish_crtc_commit(struct drm_crtc *crtc)
{
- struct drm_device *dev = crtc->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- if (intel_crtc->atomic.evade)
- intel_pipe_update_end(intel_crtc,
- intel_crtc->atomic.start_vbl_count);
-
- intel_runtime_pm_put(dev_priv);
-
- intel_post_plane_update(intel_crtc);
+ if (crtc->state->active)
+ intel_pipe_update_end(intel_crtc, intel_crtc->start_vbl_count);
}
/**
intel_fbc_disable(dev_priv);
drm_modeset_lock_all(dev);
- intel_modeset_setup_hw_state(dev, false);
+ intel_modeset_setup_hw_state(dev);
drm_modeset_unlock_all(dev);
for_each_intel_crtc(dev, crtc) {
+ struct intel_initial_plane_config plane_config = {};
+
if (!crtc->active)
continue;
* 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);
- }
+ dev_priv->display.get_initial_plane_config(crtc,
+ &plane_config);
+
+ /*
+ * If the fb is shared between multiple heads, we'll
+ * just get the first one.
+ */
+ intel_find_initial_plane_obj(crtc, &plane_config);
}
}
/* restore vblank interrupts to correct state */
drm_crtc_vblank_reset(&crtc->base);
if (crtc->active) {
+ drm_calc_timestamping_constants(&crtc->base, &crtc->base.hwmode);
update_scanline_offset(crtc);
drm_crtc_vblank_on(&crtc->base);
}
crtc->base.state->enable ? "enabled" : "disabled",
crtc->active ? "enabled" : "disabled");
- crtc->base.state->enable = crtc->active;
+ WARN_ON(drm_atomic_set_mode_for_crtc(crtc->base.state, NULL) < 0);
crtc->base.state->active = crtc->active;
crtc->base.enabled = crtc->active;
struct intel_crtc_state *crtc_state)
{
struct intel_plane *p;
- struct drm_plane_state *drm_plane_state;
+ struct intel_plane_state *plane_state;
bool active = crtc_state->base.active;
- 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;
-
if (crtc->pipe != p->pipe)
continue;
- drm_plane_state = p->base.state;
+ plane_state = to_intel_plane_state(p->base.state);
- /* Plane scaler state is not touched here. The first atomic
- * commit will restore all plane scalers to its old state.
- */
-
- 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;
- }
+ if (p->base.type == DRM_PLANE_TYPE_PRIMARY)
+ plane_state->visible = primary_get_hw_state(crtc);
+ else {
+ if (active)
+ p->disable_plane(&p->base, &crtc->base);
- if (visible) {
- crtc_state->base.plane_mask |=
- 1 << drm_plane_index(&p->base);
- } else if (crtc_state->base.state) {
- /* Make this unconditional for atomic hw readout. */
- crtc_state->base.plane_mask &=
- ~(1 << drm_plane_index(&p->base));
+ plane_state->visible = false;
}
}
}
int i;
for_each_intel_crtc(dev, crtc) {
+ __drm_atomic_helper_crtc_destroy_state(&crtc->base, crtc->base.state);
memset(crtc->config, 0, sizeof(*crtc->config));
crtc->config->base.crtc = &crtc->base;
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",
}
}
-/* 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)
+/* Scan out the current hw modeset state,
+ * and sanitizes it to the current state
+ */
+static void
+intel_modeset_setup_hw_state(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
enum pipe pipe;
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);
else if (HAS_PCH_SPLIT(dev))
ilk_wm_get_hw_state(dev);
- if (force_restore) {
- i915_redisable_vga(dev);
+ for_each_intel_crtc(dev, crtc) {
+ unsigned long put_domains;
- /*
- * We need to use raw interfaces for restoring state to avoid
- * checking (bogus) intermediate states.
- */
- for_each_pipe(dev_priv, pipe) {
- struct drm_crtc *crtc =
- dev_priv->pipe_to_crtc_mapping[pipe];
+ put_domains = modeset_get_crtc_power_domains(&crtc->base);
+ if (WARN_ON(put_domains))
+ modeset_put_power_domains(dev_priv, put_domains);
+ }
+ intel_display_set_init_power(dev_priv, false);
+}
- intel_crtc_restore_mode(crtc);
- }
- } else {
- intel_modeset_update_staged_output_state(dev);
+void intel_display_resume(struct drm_device *dev)
+{
+ struct drm_atomic_state *state = drm_atomic_state_alloc(dev);
+ struct intel_connector *conn;
+ struct intel_plane *plane;
+ struct drm_crtc *crtc;
+ int ret;
+
+ if (!state)
+ return;
+
+ state->acquire_ctx = dev->mode_config.acquire_ctx;
+
+ /* preserve complete old state, including dpll */
+ intel_atomic_get_shared_dpll_state(state);
+
+ for_each_crtc(dev, crtc) {
+ struct drm_crtc_state *crtc_state =
+ drm_atomic_get_crtc_state(state, crtc);
+
+ ret = PTR_ERR_OR_ZERO(crtc_state);
+ if (ret)
+ goto err;
+
+ /* force a restore */
+ crtc_state->mode_changed = true;
}
- intel_modeset_check_state(dev);
+ for_each_intel_plane(dev, plane) {
+ ret = PTR_ERR_OR_ZERO(drm_atomic_get_plane_state(state, &plane->base));
+ if (ret)
+ goto err;
+ }
+
+ for_each_intel_connector(dev, conn) {
+ ret = PTR_ERR_OR_ZERO(drm_atomic_get_connector_state(state, &conn->base));
+ if (ret)
+ goto err;
+ }
+
+ intel_modeset_setup_hw_state(dev);
+
+ i915_redisable_vga(dev);
+ ret = drm_atomic_commit(state);
+ if (!ret)
+ return;
+
+err:
+ DRM_ERROR("Restoring old state failed with %i\n", ret);
+ drm_atomic_state_free(state);
}
void intel_modeset_gem_init(struct drm_device *dev)