[v7,13/17] drm/dp_mst: Add helper to trigger modeset on affected DSC MST CRTCs
diff mbox series

Message ID 20191116220128.16598-14-mikita.lipski@amd.com
State New
Headers show
Series
  • DSC MST support for DRM and AMDGPU
Related show

Commit Message

Lipski, Mikita Nov. 16, 2019, 10:01 p.m. UTC
From: Mikita Lipski <mikita.lipski@amd.com>

[why]
Whenever a connector on an MST network is changed or
undergoes a modeset, the DSC configs for each stream on that
topology will be recalculated. This can change their required
bandwidth, requiring a full reprogramming, as though a modeset
was performed, even if that stream did not change timing.

[how]
Adding helper to trigger modesets on MST DSC connectors
by setting mode_changed flag on CRTCs in the same topology
as affected connector

Signed-off-by: Mikita Lipski <mikita.lipski@amd.com>
---
 drivers/gpu/drm/drm_dp_mst_topology.c | 90 +++++++++++++++++++++++++++
 include/drm/drm_dp_mst_helper.h       |  2 +
 2 files changed, 92 insertions(+)

Patch
diff mbox series

diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index 5072c1e3dcfe..4d9089fe84c1 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -73,6 +73,7 @@  static bool drm_dp_validate_guid(struct drm_dp_mst_topology_mgr *mgr,
 static int drm_dp_mst_register_i2c_bus(struct drm_dp_aux *aux);
 static void drm_dp_mst_unregister_i2c_bus(struct drm_dp_aux *aux);
 static void drm_dp_mst_kick_tx(struct drm_dp_mst_topology_mgr *mgr);
+static bool drm_dp_mst_is_dsc_supported(struct drm_dp_mst_port *port);
 
 #define DP_STR(x) [DP_ ## x] = #x
 
@@ -3936,6 +3937,66 @@  drm_dp_mst_atomic_check_topology_state(struct drm_dp_mst_topology_mgr *mgr,
 	return 0;
 }
 
+/**
+ * drm_dp_mst_add_affected_dsc_crtcs
+ * @state: Pointer to the new &struct drm_dp_mst_topology_state
+ * @port: Pointer tothe port of connector with new state
+ *
+ * Whenever there is a change in mst topology
+ * DSC configuration would have to be recalculated
+ * therefore we need to trigger modeset on all affected
+ * CRTCs in that topology
+ *
+ * See also:
+ * drm_dp_mst_atomic_enable_dsc()
+ */
+int drm_dp_mst_add_affected_dsc_crtcs(struct drm_atomic_state *state, struct drm_dp_mst_port *port)
+{
+	struct drm_dp_mst_topology_state *mst_state;
+	struct drm_dp_vcpi_allocation *pos;
+	struct drm_connector *connector;
+	struct drm_connector_state *conn_state;
+	struct drm_crtc *crtc;
+	struct drm_crtc_state *crtc_state;
+
+	if (!port)
+		return -EINVAL;
+
+	mst_state = drm_atomic_get_mst_topology_state(state, port->mgr);
+
+	list_for_each_entry(pos, &mst_state->vcpis, next) {
+
+		connector = pos->port->connector;
+
+		if (!connector)
+			return -EINVAL;
+
+		conn_state = drm_atomic_get_connector_state(state, connector);
+
+		if (IS_ERR(conn_state))
+			return PTR_ERR(conn_state);
+
+		crtc = conn_state->crtc;
+
+		if (!crtc)
+			return -EINVAL;
+
+		if (!drm_dp_mst_is_dsc_supported(pos->port))
+			continue;
+
+		crtc_state = drm_atomic_get_crtc_state(mst_state->base.state, crtc);
+
+		if (IS_ERR(crtc_state))
+			return PTR_ERR(crtc_state);
+
+		DRM_DEBUG_ATOMIC("[MST PORT:%p] Setting mode_changed flag on CRTC %p\n", port, crtc);
+
+		crtc_state->mode_changed = true;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(drm_dp_mst_add_affected_dsc_crtcs);
+
 /**
  * drm_dp_mst_atomic_enable_dsc - Set DSC Enable Flag to On/Off
  * @state: Pointer to the new drm_atomic_state 
@@ -4433,3 +4494,32 @@  struct drm_dp_aux *drm_dp_mst_dsc_aux_for_port(struct drm_dp_mst_port *port)
 	return NULL;
 }
 EXPORT_SYMBOL(drm_dp_mst_dsc_aux_for_port);
+
+/**
+ * drm_dp_mst_is_dsc_supported() - Verify DSC support on connector
+ * @port: The port to check. A leaf of the MST tree with an attached display.
+ *
+ * Acquiring correct aux from drm_dp_mst_dsc_aux_for_port
+ * and verifying DPCD flag that the aux is DSC capable
+ *
+ * Returns:
+ * True / False - if DSC is supported
+ */
+static bool drm_dp_mst_is_dsc_supported(struct drm_dp_mst_port *port)
+{
+	struct drm_dp_aux *dsc_aux;
+	u8 endpoint_dsc;
+
+	dsc_aux = drm_dp_mst_dsc_aux_for_port(port);
+
+	if (!dsc_aux)
+		return false;
+
+	if (drm_dp_dpcd_read(&port->aux, DP_DSC_SUPPORT, &endpoint_dsc, 1) < 0)
+		return false;
+
+	if (endpoint_dsc & DP_DSC_DECOMPRESSION_IS_SUPPORTED)
+		return true;
+
+	return false;
+}
diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h
index 5a119a40ed5a..7d1e5e42c9ac 100644
--- a/include/drm/drm_dp_mst_helper.h
+++ b/include/drm/drm_dp_mst_helper.h
@@ -669,6 +669,8 @@  int drm_dp_mst_atomic_enable_dsc(struct drm_atomic_state *state,
 				 struct drm_dp_mst_port *port,
 				 int pbn, int pbn_div,
 				 bool enable);
+int drm_dp_mst_add_affected_dsc_crtcs(struct drm_atomic_state *state,
+				      struct drm_dp_mst_port *port);
 int __must_check
 drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state,
 				 struct drm_dp_mst_topology_mgr *mgr,