summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/drm_atomic_helper.c
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2015-01-22 15:36:21 (GMT)
committerDaniel Vetter <daniel.vetter@ffwll.ch>2015-01-27 09:02:18 (GMT)
commiteab3bbeffd152125ae0f90863b8e9bc8eef49423 (patch)
tree544f11ec5b22e8c941b638761aeddf0431117943 /drivers/gpu/drm/drm_atomic_helper.c
parent960cd9d4fef6dd9e235c0e5c0d4ed027f8a48025 (diff)
downloadlinux-eab3bbeffd152125ae0f90863b8e9bc8eef49423.tar.xz
drm/atomic: Add drm_crtc_state->active
This is the infrastructure for DPMS ported to the atomic world. Fundamental changes compare to legacy DPMS are: - No more per-connector dpms state, instead there's just one per each display pipeline. So if you clone either you have to unclone first if you only want to switch off one screen, or you just switch of everything (like all desktops do). This massively reduces complexity for cloning since now there's no more half-enabled cloned configs to consider. - Only on/off, dpms standby/suspend are as dead as real CRTs. Again reduces complexity a lot. Now especially for backwards compat the really important part for dpms support is that dpms on always succeeds (except for hw death and unplugged cables ofc). Which means everything that could fail (like configuration checking, resources assignments and buffer management) must be done irrespective from ->active. ->active is really only a toggle to change the hardware state. More precisely: - Drivers MUST NOT look at ->active in their ->atomic_check callbacks. Changes to ->active MUST always suceed if nothing else changes. - Drivers using the atomic helpers MUST NOT look at ->active anywhere, period. The helpers will take care of calling the respective enable/modeset/disable hooks as necessary. As before the helpers will carefully keep track of the state and not call any hooks unecessarily, so still no double-disables or enables like with crtc helpers. - ->mode_set hooks are only called when the mode or output configuration changes, not for changes in ->active state. - Drivers which reconstruct the state objects in their ->reset hooks or through some other hw state readout infrastructure must ensure that ->active reflects actual hw state. This just implements the core bits and helper logic, a subsequent patch will implement the helper code to implement legacy dpms with this. v2: Rebase on top of the drm ioctl work: - Move crtc checks to the core check function. - Also check for ->active_changed when deciding whether a modeset might happen (for the ALLOW_MODESET mode). - Expose the ->active state with an atomic prop. v3: Review from Rob - Spelling fix in comment. - Extract needs_modeset helper to consolidate the ->mode_changed || ->active_changed checks. v4: Fixup fumble between crtc->state and crtc_state. Cc: Rob Clark <robdclark@gmail.com> Reviewed-by: Thierry Reding <treding@nvidia.com> Tested-by: Thierry Reding <treding@nvidia.com> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Diffstat (limited to 'drivers/gpu/drm/drm_atomic_helper.c')
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c54
1 files changed, 49 insertions, 5 deletions
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 541ba83..3f17933 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -330,6 +330,12 @@ mode_fixup(struct drm_atomic_state *state)
return 0;
}
+static bool
+needs_modeset(struct drm_crtc_state *state)
+{
+ return state->mode_changed || state->active_changed;
+}
+
/**
* drm_atomic_helper_check - validate state object for modeset changes
* @dev: DRM device
@@ -404,12 +410,27 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
crtc = state->crtcs[i];
crtc_state = state->crtc_states[i];
- if (!crtc || !crtc_state->mode_changed)
+ if (!crtc)
continue;
- DRM_DEBUG_KMS("[CRTC:%d] needs full modeset, enable: %c\n",
+ /*
+ * We must set ->active_changed after walking connectors for
+ * otherwise an update that only changes active would result in
+ * a full modeset because update_connector_routing force that.
+ */
+ if (crtc->state->active != crtc_state->active) {
+ DRM_DEBUG_KMS("[CRTC:%d] active changed\n",
+ crtc->base.id);
+ crtc_state->active_changed = true;
+ }
+
+ if (!needs_modeset(crtc_state))
+ continue;
+
+ DRM_DEBUG_KMS("[CRTC:%d] needs all connectors, enable: %c, active: %c\n",
crtc->base.id,
- crtc_state->enable ? 'y' : 'n');
+ crtc_state->enable ? 'y' : 'n',
+ crtc_state->active ? 'y' : 'n');
ret = drm_atomic_add_affected_connectors(state, crtc);
if (ret != 0)
@@ -545,6 +566,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
struct drm_connector *connector;
struct drm_encoder_helper_funcs *funcs;
struct drm_encoder *encoder;
+ struct drm_crtc_state *old_crtc_state;
old_conn_state = old_state->connector_states[i];
connector = old_state->connectors[i];
@@ -554,6 +576,11 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
if (!old_conn_state || !old_conn_state->crtc)
continue;
+ old_crtc_state = old_state->crtc_states[drm_crtc_index(old_conn_state->crtc)];
+
+ if (!old_crtc_state->active)
+ continue;
+
encoder = old_conn_state->best_encoder;
/* We shouldn't get this far if we didn't previously have
@@ -586,11 +613,16 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
for (i = 0; i < ncrtcs; i++) {
struct drm_crtc_helper_funcs *funcs;
struct drm_crtc *crtc;
+ struct drm_crtc_state *old_crtc_state;
crtc = old_state->crtcs[i];
+ old_crtc_state = old_state->crtc_states[i];
/* Shut down everything that needs a full modeset. */
- if (!crtc || !crtc->state->mode_changed)
+ if (!crtc || !needs_modeset(crtc->state))
+ continue;
+
+ if (!old_crtc_state->active)
continue;
funcs = crtc->helper_private;
@@ -697,6 +729,9 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
mode = &new_crtc_state->mode;
adjusted_mode = &new_crtc_state->adjusted_mode;
+ if (!new_crtc_state->mode_changed)
+ continue;
+
/*
* Each encoder has at most one connector (since we always steal
* it away), so we won't call call mode_set hooks twice.
@@ -749,7 +784,10 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev,
crtc = old_state->crtcs[i];
/* Need to filter out CRTCs where only planes change. */
- if (!crtc || !crtc->state->mode_changed)
+ if (!crtc || !needs_modeset(crtc->state))
+ continue;
+
+ if (!crtc->state->active)
continue;
funcs = crtc->helper_private;
@@ -768,6 +806,9 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev,
if (!connector || !connector->state->best_encoder)
continue;
+ if (!connector->state->crtc->state->active)
+ continue;
+
encoder = connector->state->best_encoder;
funcs = encoder->helper_private;
@@ -1518,6 +1559,7 @@ retry:
WARN_ON(set->num_connectors);
crtc_state->enable = false;
+ crtc_state->active = false;
ret = drm_atomic_set_crtc_for_plane(primary_state, NULL);
if (ret != 0)
@@ -1532,6 +1574,7 @@ retry:
WARN_ON(!set->num_connectors);
crtc_state->enable = true;
+ crtc_state->active = true;
drm_mode_copy(&crtc_state->mode, set->mode);
ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
@@ -1894,6 +1937,7 @@ drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc)
if (state) {
state->mode_changed = false;
+ state->active_changed = false;
state->planes_changed = false;
state->event = NULL;
}