summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_atomic_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/drm_atomic_helper.c')
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c333
1 files changed, 208 insertions, 125 deletions
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 5186d2114a50..5302ab324898 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -574,6 +574,30 @@ mode_valid(struct drm_atomic_state *state)
return 0;
}
+static int drm_atomic_check_valid_clones(struct drm_atomic_state *state,
+ struct drm_crtc *crtc)
+{
+ struct drm_encoder *drm_enc;
+ struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+ crtc);
+
+ drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc_state->encoder_mask) {
+ if (!drm_enc->possible_clones) {
+ DRM_DEBUG("enc%d possible_clones is 0\n", drm_enc->base.id);
+ continue;
+ }
+
+ if ((crtc_state->encoder_mask & drm_enc->possible_clones) !=
+ crtc_state->encoder_mask) {
+ DRM_DEBUG("crtc%d failed valid clone check for mask 0x%x\n",
+ crtc->base.id, crtc_state->encoder_mask);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
/**
* drm_atomic_helper_check_modeset - validate state object for modeset changes
* @dev: DRM device
@@ -666,8 +690,9 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
}
if (new_crtc_state->enable != has_connectors) {
- drm_dbg_atomic(dev, "[CRTC:%d:%s] enabled/connectors mismatch\n",
- crtc->base.id, crtc->name);
+ drm_dbg_atomic(dev, "[CRTC:%d:%s] enabled/connectors mismatch (%d/%d)\n",
+ crtc->base.id, crtc->name,
+ new_crtc_state->enable, has_connectors);
return -EINVAL;
}
@@ -745,6 +770,10 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
ret = drm_atomic_add_affected_planes(state, crtc);
if (ret != 0)
return ret;
+
+ ret = drm_atomic_check_valid_clones(state, crtc);
+ if (ret != 0)
+ return ret;
}
/*
@@ -1059,6 +1088,15 @@ EXPORT_SYMBOL(drm_atomic_helper_check_planes);
* For example enable/disable of a cursor plane which have fixed zpos value
* would trigger all other enabled planes to be forced to the state change.
*
+ * IMPORTANT:
+ *
+ * As this function calls drm_atomic_helper_check_modeset() internally, its
+ * restrictions also apply:
+ * Drivers which set &drm_crtc_state.mode_changed (e.g. in their
+ * &drm_plane_helper_funcs.atomic_check hooks if a plane update can't be done
+ * without a full modeset) _must_ call drm_atomic_helper_check_modeset()
+ * function again after that change.
+ *
* RETURNS:
* Zero for success or -errno
*/
@@ -1122,7 +1160,7 @@ crtc_needs_disable(struct drm_crtc_state *old_state,
}
static void
-disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
+disable_outputs(struct drm_device *dev, struct drm_atomic_state *state)
{
struct drm_connector *connector;
struct drm_connector_state *old_conn_state, *new_conn_state;
@@ -1130,7 +1168,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
struct drm_crtc_state *old_crtc_state, *new_crtc_state;
int i;
- for_each_oldnew_connector_in_state(old_state, connector, old_conn_state, new_conn_state, i) {
+ for_each_oldnew_connector_in_state(state, connector, old_conn_state, new_conn_state, i) {
const struct drm_encoder_helper_funcs *funcs;
struct drm_encoder *encoder;
struct drm_bridge *bridge;
@@ -1142,11 +1180,11 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
if (!old_conn_state->crtc)
continue;
- old_crtc_state = drm_atomic_get_old_crtc_state(old_state, old_conn_state->crtc);
+ old_crtc_state = drm_atomic_get_old_crtc_state(state, old_conn_state->crtc);
if (new_conn_state->crtc)
new_crtc_state = drm_atomic_get_new_crtc_state(
- old_state,
+ state,
new_conn_state->crtc);
else
new_crtc_state = NULL;
@@ -1173,12 +1211,12 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
* it away), so we won't call disable hooks twice.
*/
bridge = drm_bridge_chain_get_first_bridge(encoder);
- drm_atomic_bridge_chain_disable(bridge, old_state);
+ drm_atomic_bridge_chain_disable(bridge, state);
/* Right function depends upon target state. */
if (funcs) {
if (funcs->atomic_disable)
- funcs->atomic_disable(encoder, old_state);
+ funcs->atomic_disable(encoder, state);
else if (new_conn_state->crtc && funcs->prepare)
funcs->prepare(encoder);
else if (funcs->disable)
@@ -1187,10 +1225,10 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
}
- drm_atomic_bridge_chain_post_disable(bridge, old_state);
+ drm_atomic_bridge_chain_post_disable(bridge, state);
}
- for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
+ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
const struct drm_crtc_helper_funcs *funcs;
int ret;
@@ -1211,7 +1249,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
if (new_crtc_state->enable && funcs->prepare)
funcs->prepare(crtc);
else if (funcs->atomic_disable)
- funcs->atomic_disable(crtc, old_state);
+ funcs->atomic_disable(crtc, state);
else if (funcs->disable)
funcs->disable(crtc);
else if (funcs->dpms)
@@ -1239,7 +1277,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
/**
* drm_atomic_helper_update_legacy_modeset_state - update legacy modeset state
* @dev: DRM device
- * @old_state: atomic state object with old state structures
+ * @state: atomic state object being committed
*
* This function updates all the various legacy modeset state pointers in
* connectors, encoders and CRTCs.
@@ -1255,7 +1293,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
*/
void
drm_atomic_helper_update_legacy_modeset_state(struct drm_device *dev,
- struct drm_atomic_state *old_state)
+ struct drm_atomic_state *state)
{
struct drm_connector *connector;
struct drm_connector_state *old_conn_state, *new_conn_state;
@@ -1264,7 +1302,7 @@ drm_atomic_helper_update_legacy_modeset_state(struct drm_device *dev,
int i;
/* clear out existing links and update dpms */
- for_each_oldnew_connector_in_state(old_state, connector, old_conn_state, new_conn_state, i) {
+ for_each_oldnew_connector_in_state(state, connector, old_conn_state, new_conn_state, i) {
if (connector->encoder) {
WARN_ON(!connector->encoder->crtc);
@@ -1285,7 +1323,7 @@ drm_atomic_helper_update_legacy_modeset_state(struct drm_device *dev,
}
/* set new links */
- for_each_new_connector_in_state(old_state, connector, new_conn_state, i) {
+ for_each_new_connector_in_state(state, connector, new_conn_state, i) {
if (!new_conn_state->crtc)
continue;
@@ -1297,7 +1335,7 @@ drm_atomic_helper_update_legacy_modeset_state(struct drm_device *dev,
}
/* set legacy state in the crtc structure */
- for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {
+ for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
struct drm_plane *primary = crtc->primary;
struct drm_plane_state *new_plane_state;
@@ -1305,7 +1343,7 @@ drm_atomic_helper_update_legacy_modeset_state(struct drm_device *dev,
crtc->enabled = new_crtc_state->enable;
new_plane_state =
- drm_atomic_get_new_plane_state(old_state, primary);
+ drm_atomic_get_new_plane_state(state, primary);
if (new_plane_state && new_plane_state->crtc == crtc) {
crtc->x = new_plane_state->src_x >> 16;
@@ -1337,7 +1375,7 @@ void drm_atomic_helper_calc_timestamping_constants(struct drm_atomic_state *stat
EXPORT_SYMBOL(drm_atomic_helper_calc_timestamping_constants);
static void
-crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
+crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *state)
{
struct drm_crtc *crtc;
struct drm_crtc_state *new_crtc_state;
@@ -1345,7 +1383,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
struct drm_connector_state *new_conn_state;
int i;
- for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {
+ for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
const struct drm_crtc_helper_funcs *funcs;
if (!new_crtc_state->mode_changed)
@@ -1361,7 +1399,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
}
}
- for_each_new_connector_in_state(old_state, connector, new_conn_state, i) {
+ for_each_new_connector_in_state(state, connector, new_conn_state, i) {
const struct drm_encoder_helper_funcs *funcs;
struct drm_encoder *encoder;
struct drm_display_mode *mode, *adjusted_mode;
@@ -1376,7 +1414,7 @@ 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)
+ if (!new_crtc_state->mode_changed && !new_crtc_state->connectors_changed)
continue;
drm_dbg_atomic(dev, "modeset on [ENCODER:%d:%s]\n",
@@ -1401,7 +1439,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
/**
* drm_atomic_helper_commit_modeset_disables - modeset commit to disable outputs
* @dev: DRM device
- * @old_state: atomic state object with old state structures
+ * @state: atomic state object being committed
*
* This function shuts down all the outputs that need to be shut down and
* prepares them (if required) with the new mode.
@@ -1413,25 +1451,25 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
* PM since planes updates then only happen when the CRTC is actually enabled.
*/
void drm_atomic_helper_commit_modeset_disables(struct drm_device *dev,
- struct drm_atomic_state *old_state)
+ struct drm_atomic_state *state)
{
- disable_outputs(dev, old_state);
+ disable_outputs(dev, state);
- drm_atomic_helper_update_legacy_modeset_state(dev, old_state);
- drm_atomic_helper_calc_timestamping_constants(old_state);
+ drm_atomic_helper_update_legacy_modeset_state(dev, state);
+ drm_atomic_helper_calc_timestamping_constants(state);
- crtc_set_mode(dev, old_state);
+ crtc_set_mode(dev, state);
}
EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_disables);
static void drm_atomic_helper_commit_writebacks(struct drm_device *dev,
- struct drm_atomic_state *old_state)
+ struct drm_atomic_state *state)
{
struct drm_connector *connector;
struct drm_connector_state *new_conn_state;
int i;
- for_each_new_connector_in_state(old_state, connector, new_conn_state, i) {
+ for_each_new_connector_in_state(state, connector, new_conn_state, i) {
const struct drm_connector_helper_funcs *funcs;
funcs = connector->helper_private;
@@ -1440,7 +1478,7 @@ static void drm_atomic_helper_commit_writebacks(struct drm_device *dev,
if (new_conn_state->writeback_job && new_conn_state->writeback_job->fb) {
WARN_ON(connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK);
- funcs->atomic_commit(connector, old_state);
+ funcs->atomic_commit(connector, state);
}
}
}
@@ -1448,7 +1486,7 @@ static void drm_atomic_helper_commit_writebacks(struct drm_device *dev,
/**
* drm_atomic_helper_commit_modeset_enables - modeset commit to enable outputs
* @dev: DRM device
- * @old_state: atomic state object with old state structures
+ * @state: atomic state object being committed
*
* This function enables all the outputs with the new configuration which had to
* be turned off for the update.
@@ -1460,7 +1498,7 @@ static void drm_atomic_helper_commit_writebacks(struct drm_device *dev,
* PM since planes updates then only happen when the CRTC is actually enabled.
*/
void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
- struct drm_atomic_state *old_state)
+ struct drm_atomic_state *state)
{
struct drm_crtc *crtc;
struct drm_crtc_state *old_crtc_state;
@@ -1469,7 +1507,7 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
struct drm_connector_state *new_conn_state;
int i;
- for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
+ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
const struct drm_crtc_helper_funcs *funcs;
/* Need to filter out CRTCs where only planes change. */
@@ -1485,13 +1523,13 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
drm_dbg_atomic(dev, "enabling [CRTC:%d:%s]\n",
crtc->base.id, crtc->name);
if (funcs->atomic_enable)
- funcs->atomic_enable(crtc, old_state);
+ funcs->atomic_enable(crtc, state);
else if (funcs->commit)
funcs->commit(crtc);
}
}
- for_each_new_connector_in_state(old_state, connector, new_conn_state, i) {
+ for_each_new_connector_in_state(state, connector, new_conn_state, i) {
const struct drm_encoder_helper_funcs *funcs;
struct drm_encoder *encoder;
struct drm_bridge *bridge;
@@ -1514,21 +1552,21 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
* it away), so we won't call enable hooks twice.
*/
bridge = drm_bridge_chain_get_first_bridge(encoder);
- drm_atomic_bridge_chain_pre_enable(bridge, old_state);
+ drm_atomic_bridge_chain_pre_enable(bridge, state);
if (funcs) {
if (funcs->atomic_enable)
- funcs->atomic_enable(encoder, old_state);
+ funcs->atomic_enable(encoder, state);
else if (funcs->enable)
funcs->enable(encoder);
else if (funcs->commit)
funcs->commit(encoder);
}
- drm_atomic_bridge_chain_enable(bridge, old_state);
+ drm_atomic_bridge_chain_enable(bridge, state);
}
- drm_atomic_helper_commit_writebacks(dev, old_state);
+ drm_atomic_helper_commit_writebacks(dev, state);
}
EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_enables);
@@ -1630,7 +1668,7 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_fences);
/**
* drm_atomic_helper_wait_for_vblanks - wait for vblank on CRTCs
* @dev: DRM device
- * @old_state: atomic state object with old state structures
+ * @state: atomic state object being committed
*
* Helper to, after atomic commit, wait for vblanks on all affected
* CRTCs (ie. before cleaning up old framebuffers using
@@ -1644,7 +1682,7 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_fences);
*/
void
drm_atomic_helper_wait_for_vblanks(struct drm_device *dev,
- struct drm_atomic_state *old_state)
+ struct drm_atomic_state *state)
{
struct drm_crtc *crtc;
struct drm_crtc_state *old_crtc_state, *new_crtc_state;
@@ -1655,10 +1693,10 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev,
* Legacy cursor ioctls are completely unsynced, and userspace
* relies on that (by doing tons of cursor updates).
*/
- if (old_state->legacy_cursor_update)
+ if (state->legacy_cursor_update)
return;
- for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
+ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
if (!new_crtc_state->active)
continue;
@@ -1667,17 +1705,17 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev,
continue;
crtc_mask |= drm_crtc_mask(crtc);
- old_state->crtcs[i].last_vblank_count = drm_crtc_vblank_count(crtc);
+ state->crtcs[i].last_vblank_count = drm_crtc_vblank_count(crtc);
}
- for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) {
+ for_each_old_crtc_in_state(state, crtc, old_crtc_state, i) {
if (!(crtc_mask & drm_crtc_mask(crtc)))
continue;
ret = wait_event_timeout(dev->vblank[i].queue,
- old_state->crtcs[i].last_vblank_count !=
- drm_crtc_vblank_count(crtc),
- msecs_to_jiffies(100));
+ state->crtcs[i].last_vblank_count !=
+ drm_crtc_vblank_count(crtc),
+ msecs_to_jiffies(100));
WARN(!ret, "[CRTC:%d:%s] vblank wait timed out\n",
crtc->base.id, crtc->name);
@@ -1690,7 +1728,7 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks);
/**
* drm_atomic_helper_wait_for_flip_done - wait for all page flips to be done
* @dev: DRM device
- * @old_state: atomic state object with old state structures
+ * @state: atomic state object being committed
*
* Helper to, after atomic commit, wait for page flips on all affected
* crtcs (ie. before cleaning up old framebuffers using
@@ -1703,16 +1741,16 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_vblanks);
* initialized using drm_atomic_helper_setup_commit().
*/
void drm_atomic_helper_wait_for_flip_done(struct drm_device *dev,
- struct drm_atomic_state *old_state)
+ struct drm_atomic_state *state)
{
struct drm_crtc *crtc;
int i;
for (i = 0; i < dev->mode_config.num_crtc; i++) {
- struct drm_crtc_commit *commit = old_state->crtcs[i].commit;
+ struct drm_crtc_commit *commit = state->crtcs[i].commit;
int ret;
- crtc = old_state->crtcs[i].ptr;
+ crtc = state->crtcs[i].ptr;
if (!crtc || !commit)
continue;
@@ -1723,14 +1761,14 @@ void drm_atomic_helper_wait_for_flip_done(struct drm_device *dev,
crtc->base.id, crtc->name);
}
- if (old_state->fake_commit)
- complete_all(&old_state->fake_commit->flip_done);
+ if (state->fake_commit)
+ complete_all(&state->fake_commit->flip_done);
}
EXPORT_SYMBOL(drm_atomic_helper_wait_for_flip_done);
/**
* drm_atomic_helper_commit_tail - commit atomic update to hardware
- * @old_state: atomic state object with old state structures
+ * @state: atomic state object being committed
*
* This is the default implementation for the
* &drm_mode_config_helper_funcs.atomic_commit_tail hook, for drivers
@@ -1741,29 +1779,29 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_flip_done);
* Note that the default ordering of how the various stages are called is to
* match the legacy modeset helper library closest.
*/
-void drm_atomic_helper_commit_tail(struct drm_atomic_state *old_state)
+void drm_atomic_helper_commit_tail(struct drm_atomic_state *state)
{
- struct drm_device *dev = old_state->dev;
+ struct drm_device *dev = state->dev;
- drm_atomic_helper_commit_modeset_disables(dev, old_state);
+ drm_atomic_helper_commit_modeset_disables(dev, state);
- drm_atomic_helper_commit_planes(dev, old_state, 0);
+ drm_atomic_helper_commit_planes(dev, state, 0);
- drm_atomic_helper_commit_modeset_enables(dev, old_state);
+ drm_atomic_helper_commit_modeset_enables(dev, state);
- drm_atomic_helper_fake_vblank(old_state);
+ drm_atomic_helper_fake_vblank(state);
- drm_atomic_helper_commit_hw_done(old_state);
+ drm_atomic_helper_commit_hw_done(state);
- drm_atomic_helper_wait_for_vblanks(dev, old_state);
+ drm_atomic_helper_wait_for_vblanks(dev, state);
- drm_atomic_helper_cleanup_planes(dev, old_state);
+ drm_atomic_helper_cleanup_planes(dev, state);
}
EXPORT_SYMBOL(drm_atomic_helper_commit_tail);
/**
* drm_atomic_helper_commit_tail_rpm - commit atomic update to hardware
- * @old_state: new modeset state to be committed
+ * @state: new modeset state to be committed
*
* This is an alternative implementation for the
* &drm_mode_config_helper_funcs.atomic_commit_tail hook, for drivers
@@ -1771,30 +1809,30 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_tail);
* commit. Otherwise, one should use the default implementation
* drm_atomic_helper_commit_tail().
*/
-void drm_atomic_helper_commit_tail_rpm(struct drm_atomic_state *old_state)
+void drm_atomic_helper_commit_tail_rpm(struct drm_atomic_state *state)
{
- struct drm_device *dev = old_state->dev;
+ struct drm_device *dev = state->dev;
- drm_atomic_helper_commit_modeset_disables(dev, old_state);
+ drm_atomic_helper_commit_modeset_disables(dev, state);
- drm_atomic_helper_commit_modeset_enables(dev, old_state);
+ drm_atomic_helper_commit_modeset_enables(dev, state);
- drm_atomic_helper_commit_planes(dev, old_state,
+ drm_atomic_helper_commit_planes(dev, state,
DRM_PLANE_COMMIT_ACTIVE_ONLY);
- drm_atomic_helper_fake_vblank(old_state);
+ drm_atomic_helper_fake_vblank(state);
- drm_atomic_helper_commit_hw_done(old_state);
+ drm_atomic_helper_commit_hw_done(state);
- drm_atomic_helper_wait_for_vblanks(dev, old_state);
+ drm_atomic_helper_wait_for_vblanks(dev, state);
- drm_atomic_helper_cleanup_planes(dev, old_state);
+ drm_atomic_helper_cleanup_planes(dev, state);
}
EXPORT_SYMBOL(drm_atomic_helper_commit_tail_rpm);
-static void commit_tail(struct drm_atomic_state *old_state)
+static void commit_tail(struct drm_atomic_state *state)
{
- struct drm_device *dev = old_state->dev;
+ struct drm_device *dev = state->dev;
const struct drm_mode_config_helper_funcs *funcs;
struct drm_crtc_state *new_crtc_state;
struct drm_crtc *crtc;
@@ -1816,33 +1854,33 @@ static void commit_tail(struct drm_atomic_state *old_state)
*/
start = ktime_get();
- drm_atomic_helper_wait_for_fences(dev, old_state, false);
+ drm_atomic_helper_wait_for_fences(dev, state, false);
- drm_atomic_helper_wait_for_dependencies(old_state);
+ drm_atomic_helper_wait_for_dependencies(state);
/*
* We cannot safely access new_crtc_state after
* drm_atomic_helper_commit_hw_done() so figure out which crtc's have
* self-refresh active beforehand:
*/
- for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i)
+ for_each_new_crtc_in_state(state, crtc, new_crtc_state, i)
if (new_crtc_state->self_refresh_active)
new_self_refresh_mask |= BIT(i);
if (funcs && funcs->atomic_commit_tail)
- funcs->atomic_commit_tail(old_state);
+ funcs->atomic_commit_tail(state);
else
- drm_atomic_helper_commit_tail(old_state);
+ drm_atomic_helper_commit_tail(state);
commit_time_ms = ktime_ms_delta(ktime_get(), start);
if (commit_time_ms > 0)
- drm_self_refresh_helper_update_avg_times(old_state,
+ drm_self_refresh_helper_update_avg_times(state,
(unsigned long)commit_time_ms,
new_self_refresh_mask);
- drm_atomic_helper_commit_cleanup_done(old_state);
+ drm_atomic_helper_commit_cleanup_done(state);
- drm_atomic_state_put(old_state);
+ drm_atomic_state_put(state);
}
static void commit_work(struct work_struct *work)
@@ -1928,7 +1966,7 @@ int drm_atomic_helper_async_check(struct drm_device *dev,
return -EBUSY;
}
- ret = funcs->atomic_async_check(plane, state);
+ ret = funcs->atomic_async_check(plane, state, false);
if (ret != 0)
drm_dbg_atomic(dev,
"[PLANE:%d:%s] driver async check failed\n",
@@ -2385,17 +2423,17 @@ EXPORT_SYMBOL(drm_atomic_helper_setup_commit);
/**
* drm_atomic_helper_wait_for_dependencies - wait for required preceding commits
- * @old_state: atomic state object with old state structures
+ * @state: atomic state object being committed
*
* This function waits for all preceding commits that touch the same CRTC as
- * @old_state to both be committed to the hardware (as signalled by
+ * @state to both be committed to the hardware (as signalled by
* drm_atomic_helper_commit_hw_done()) and executed by the hardware (as signalled
* by calling drm_crtc_send_vblank_event() on the &drm_crtc_state.event).
*
* This is part of the atomic helper support for nonblocking commits, see
* drm_atomic_helper_setup_commit() for an overview.
*/
-void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *old_state)
+void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *state)
{
struct drm_crtc *crtc;
struct drm_crtc_state *old_crtc_state;
@@ -2406,7 +2444,7 @@ void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *old_state)
int i;
long ret;
- for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) {
+ for_each_old_crtc_in_state(state, crtc, old_crtc_state, i) {
ret = drm_crtc_commit_wait(old_crtc_state->commit);
if (ret)
drm_err(crtc->dev,
@@ -2414,7 +2452,7 @@ void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *old_state)
crtc->base.id, crtc->name);
}
- for_each_old_connector_in_state(old_state, conn, old_conn_state, i) {
+ for_each_old_connector_in_state(state, conn, old_conn_state, i) {
ret = drm_crtc_commit_wait(old_conn_state->commit);
if (ret)
drm_err(conn->dev,
@@ -2422,7 +2460,7 @@ void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *old_state)
conn->base.id, conn->name);
}
- for_each_old_plane_in_state(old_state, plane, old_plane_state, i) {
+ for_each_old_plane_in_state(state, plane, old_plane_state, i) {
ret = drm_crtc_commit_wait(old_plane_state->commit);
if (ret)
drm_err(plane->dev,
@@ -2434,7 +2472,7 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies);
/**
* drm_atomic_helper_fake_vblank - fake VBLANK events if needed
- * @old_state: atomic state object with old state structures
+ * @state: atomic state object being committed
*
* This function walks all CRTCs and fakes VBLANK events on those with
* &drm_crtc_state.no_vblank set to true and &drm_crtc_state.event != NULL.
@@ -2450,32 +2488,32 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies);
* This is part of the atomic helper support for nonblocking commits, see
* drm_atomic_helper_setup_commit() for an overview.
*/
-void drm_atomic_helper_fake_vblank(struct drm_atomic_state *old_state)
+void drm_atomic_helper_fake_vblank(struct drm_atomic_state *state)
{
struct drm_crtc_state *new_crtc_state;
struct drm_crtc *crtc;
int i;
- for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {
+ for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
unsigned long flags;
if (!new_crtc_state->no_vblank)
continue;
- spin_lock_irqsave(&old_state->dev->event_lock, flags);
+ spin_lock_irqsave(&state->dev->event_lock, flags);
if (new_crtc_state->event) {
drm_crtc_send_vblank_event(crtc,
new_crtc_state->event);
new_crtc_state->event = NULL;
}
- spin_unlock_irqrestore(&old_state->dev->event_lock, flags);
+ spin_unlock_irqrestore(&state->dev->event_lock, flags);
}
}
EXPORT_SYMBOL(drm_atomic_helper_fake_vblank);
/**
* drm_atomic_helper_commit_hw_done - setup possible nonblocking commit
- * @old_state: atomic state object with old state structures
+ * @state: atomic state object being committed
*
* This function is used to signal completion of the hardware commit step. After
* this step the driver is not allowed to read or change any permanent software
@@ -2488,14 +2526,14 @@ EXPORT_SYMBOL(drm_atomic_helper_fake_vblank);
* This is part of the atomic helper support for nonblocking commits, see
* drm_atomic_helper_setup_commit() for an overview.
*/
-void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state)
+void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *state)
{
struct drm_crtc *crtc;
struct drm_crtc_state *old_crtc_state, *new_crtc_state;
struct drm_crtc_commit *commit;
int i;
- for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
+ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
commit = new_crtc_state->commit;
if (!commit)
continue;
@@ -2515,32 +2553,32 @@ void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state)
complete_all(&commit->hw_done);
}
- if (old_state->fake_commit) {
- complete_all(&old_state->fake_commit->hw_done);
- complete_all(&old_state->fake_commit->flip_done);
+ if (state->fake_commit) {
+ complete_all(&state->fake_commit->hw_done);
+ complete_all(&state->fake_commit->flip_done);
}
}
EXPORT_SYMBOL(drm_atomic_helper_commit_hw_done);
/**
* drm_atomic_helper_commit_cleanup_done - signal completion of commit
- * @old_state: atomic state object with old state structures
+ * @state: atomic state object being committed
*
- * This signals completion of the atomic update @old_state, including any
+ * This signals completion of the atomic update @state, including any
* cleanup work. If used, it must be called right before calling
* drm_atomic_state_put().
*
* This is part of the atomic helper support for nonblocking commits, see
* drm_atomic_helper_setup_commit() for an overview.
*/
-void drm_atomic_helper_commit_cleanup_done(struct drm_atomic_state *old_state)
+void drm_atomic_helper_commit_cleanup_done(struct drm_atomic_state *state)
{
struct drm_crtc *crtc;
struct drm_crtc_state *old_crtc_state;
struct drm_crtc_commit *commit;
int i;
- for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) {
+ for_each_old_crtc_in_state(state, crtc, old_crtc_state, i) {
commit = old_crtc_state->commit;
if (WARN_ON(!commit))
continue;
@@ -2553,9 +2591,9 @@ void drm_atomic_helper_commit_cleanup_done(struct drm_atomic_state *old_state)
spin_unlock(&crtc->commit_lock);
}
- if (old_state->fake_commit) {
- complete_all(&old_state->fake_commit->cleanup_done);
- WARN_ON(!try_wait_for_completion(&old_state->fake_commit->hw_done));
+ if (state->fake_commit) {
+ complete_all(&state->fake_commit->cleanup_done);
+ WARN_ON(!try_wait_for_completion(&state->fake_commit->hw_done));
}
}
EXPORT_SYMBOL(drm_atomic_helper_commit_cleanup_done);
@@ -2693,7 +2731,7 @@ static bool plane_crtc_active(const struct drm_plane_state *state)
/**
* drm_atomic_helper_commit_planes - commit plane state
* @dev: DRM device
- * @old_state: atomic state object with old state structures
+ * @state: atomic state object being committed
* @flags: flags for committing plane state
*
* This function commits the new plane state using the plane and atomic helper
@@ -2701,7 +2739,7 @@ static bool plane_crtc_active(const struct drm_plane_state *state)
* been pushed into the relevant object state pointers, since this step can no
* longer fail.
*
- * It still requires the global state object @old_state to know which planes and
+ * It still requires the global state object @state to know which planes and
* crtcs need to be updated though.
*
* Note that this function does all plane updates across all CRTCs in one step.
@@ -2732,7 +2770,7 @@ static bool plane_crtc_active(const struct drm_plane_state *state)
* This should not be copied blindly by drivers.
*/
void drm_atomic_helper_commit_planes(struct drm_device *dev,
- struct drm_atomic_state *old_state,
+ struct drm_atomic_state *state,
uint32_t flags)
{
struct drm_crtc *crtc;
@@ -2743,7 +2781,7 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
bool active_only = flags & DRM_PLANE_COMMIT_ACTIVE_ONLY;
bool no_disable = flags & DRM_PLANE_COMMIT_NO_DISABLE_AFTER_MODESET;
- for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
+ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
const struct drm_crtc_helper_funcs *funcs;
funcs = crtc->helper_private;
@@ -2754,10 +2792,10 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
if (active_only && !new_crtc_state->active)
continue;
- funcs->atomic_begin(crtc, old_state);
+ funcs->atomic_begin(crtc, state);
}
- for_each_oldnew_plane_in_state(old_state, plane, old_plane_state, new_plane_state, i) {
+ for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
const struct drm_plane_helper_funcs *funcs;
bool disabling;
@@ -2795,18 +2833,18 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
no_disable)
continue;
- funcs->atomic_disable(plane, old_state);
+ funcs->atomic_disable(plane, state);
} else if (new_plane_state->crtc || disabling) {
- funcs->atomic_update(plane, old_state);
+ funcs->atomic_update(plane, state);
if (!disabling && funcs->atomic_enable) {
if (drm_atomic_plane_enabling(old_plane_state, new_plane_state))
- funcs->atomic_enable(plane, old_state);
+ funcs->atomic_enable(plane, state);
}
}
}
- for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
+ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
const struct drm_crtc_helper_funcs *funcs;
funcs = crtc->helper_private;
@@ -2817,14 +2855,14 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
if (active_only && !new_crtc_state->active)
continue;
- funcs->atomic_flush(crtc, old_state);
+ funcs->atomic_flush(crtc, state);
}
/*
* Signal end of framebuffer access here before hw_done. After hw_done,
* a later commit might have already released the plane state.
*/
- for_each_old_plane_in_state(old_state, plane, old_plane_state, i) {
+ for_each_old_plane_in_state(state, plane, old_plane_state, i) {
const struct drm_plane_helper_funcs *funcs = plane->helper_private;
if (funcs->end_fb_access)
@@ -2951,10 +2989,10 @@ EXPORT_SYMBOL(drm_atomic_helper_disable_planes_on_crtc);
/**
* drm_atomic_helper_cleanup_planes - cleanup plane resources after commit
* @dev: DRM device
- * @old_state: atomic state object with old state structures
+ * @state: atomic state object being committed
*
* This function cleans up plane state, specifically framebuffers, from the old
- * configuration. Hence the old configuration must be perserved in @old_state to
+ * configuration. Hence the old configuration must be perserved in @state to
* be able to call this function.
*
* This function may not be called on the new state when the atomic update
@@ -2962,13 +3000,13 @@ EXPORT_SYMBOL(drm_atomic_helper_disable_planes_on_crtc);
* drm_atomic_helper_unprepare_planes() in this case.
*/
void drm_atomic_helper_cleanup_planes(struct drm_device *dev,
- struct drm_atomic_state *old_state)
+ struct drm_atomic_state *state)
{
struct drm_plane *plane;
struct drm_plane_state *old_plane_state;
int i;
- for_each_old_plane_in_state(old_state, plane, old_plane_state, i) {
+ for_each_old_plane_in_state(state, plane, old_plane_state, i) {
const struct drm_plane_helper_funcs *funcs = plane->helper_private;
if (funcs->cleanup_fb)
@@ -3363,6 +3401,51 @@ free:
EXPORT_SYMBOL(drm_atomic_helper_disable_all);
/**
+ * drm_atomic_helper_reset_crtc - reset the active outputs of a CRTC
+ * @crtc: DRM CRTC
+ * @ctx: lock acquisition context
+ *
+ * Reset the active outputs by indicating that connectors have changed.
+ * This implies a reset of all active components available between the CRTC and
+ * connectors.
+ *
+ * NOTE: This relies on resetting &drm_crtc_state.connectors_changed.
+ * For drivers which optimize out unnecessary modesets this will result in
+ * a no-op commit, achieving nothing.
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
+ */
+int drm_atomic_helper_reset_crtc(struct drm_crtc *crtc,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ struct drm_atomic_state *state;
+ struct drm_crtc_state *crtc_state;
+ int ret;
+
+ state = drm_atomic_state_alloc(crtc->dev);
+ if (!state)
+ return -ENOMEM;
+
+ state->acquire_ctx = ctx;
+
+ crtc_state = drm_atomic_get_crtc_state(state, crtc);
+ if (IS_ERR(crtc_state)) {
+ ret = PTR_ERR(crtc_state);
+ goto out;
+ }
+
+ crtc_state->connectors_changed = true;
+
+ ret = drm_atomic_commit(state);
+out:
+ drm_atomic_state_put(state);
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_atomic_helper_reset_crtc);
+
+/**
* drm_atomic_helper_shutdown - shutdown all CRTC
* @dev: DRM device
*