|
|
@@ -125,6 +125,47 @@ get_current_crtc_for_encoder(struct drm_device *dev,
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
+static void
|
|
|
+set_best_encoder(struct drm_atomic_state *state,
|
|
|
+ struct drm_connector_state *conn_state,
|
|
|
+ struct drm_encoder *encoder)
|
|
|
+{
|
|
|
+ struct drm_crtc_state *crtc_state;
|
|
|
+ struct drm_crtc *crtc;
|
|
|
+
|
|
|
+ if (conn_state->best_encoder) {
|
|
|
+ /* Unset the encoder_mask in the old crtc state. */
|
|
|
+ crtc = conn_state->connector->state->crtc;
|
|
|
+
|
|
|
+ /* A NULL crtc is an error here because we should have
|
|
|
+ * duplicated a NULL best_encoder when crtc was NULL.
|
|
|
+ * As an exception restoring duplicated atomic state
|
|
|
+ * during resume is allowed, so don't warn when
|
|
|
+ * best_encoder is equal to encoder we intend to set.
|
|
|
+ */
|
|
|
+ WARN_ON(!crtc && encoder != conn_state->best_encoder);
|
|
|
+ if (crtc) {
|
|
|
+ crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
|
|
|
+
|
|
|
+ crtc_state->encoder_mask &=
|
|
|
+ ~(1 << drm_encoder_index(conn_state->best_encoder));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (encoder) {
|
|
|
+ crtc = conn_state->crtc;
|
|
|
+ WARN_ON(!crtc);
|
|
|
+ if (crtc) {
|
|
|
+ crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
|
|
|
+
|
|
|
+ crtc_state->encoder_mask |=
|
|
|
+ 1 << drm_encoder_index(encoder);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ conn_state->best_encoder = encoder;
|
|
|
+}
|
|
|
+
|
|
|
static int
|
|
|
steal_encoder(struct drm_atomic_state *state,
|
|
|
struct drm_encoder *encoder,
|
|
|
@@ -164,7 +205,10 @@ steal_encoder(struct drm_atomic_state *state,
|
|
|
if (IS_ERR(connector_state))
|
|
|
return PTR_ERR(connector_state);
|
|
|
|
|
|
- connector_state->best_encoder = NULL;
|
|
|
+ if (connector_state->best_encoder != encoder)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ set_best_encoder(state, connector_state, NULL);
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
@@ -212,7 +256,7 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
|
|
|
connector->base.id,
|
|
|
connector->name);
|
|
|
|
|
|
- connector_state->best_encoder = NULL;
|
|
|
+ set_best_encoder(state, connector_state, NULL);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
@@ -241,6 +285,8 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
|
|
|
}
|
|
|
|
|
|
if (new_encoder == connector_state->best_encoder) {
|
|
|
+ set_best_encoder(state, connector_state, new_encoder);
|
|
|
+
|
|
|
DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] keeps [ENCODER:%d:%s], now on [CRTC:%d:%s]\n",
|
|
|
connector->base.id,
|
|
|
connector->name,
|
|
|
@@ -275,7 +321,8 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
|
|
|
if (WARN_ON(!connector_state->crtc))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- connector_state->best_encoder = new_encoder;
|
|
|
+ set_best_encoder(state, connector_state, new_encoder);
|
|
|
+
|
|
|
idx = drm_crtc_index(connector_state->crtc);
|
|
|
|
|
|
crtc_state = state->crtc_states[idx];
|