All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/7] drm/probe-helpers: Work around multi-outputs-per-CRTC problem
@ 2024-07-15  9:38 Thomas Zimmermann
  2024-07-15  9:38 ` [PATCH 1/7] drm/probe-helper: Call connector detect functions in single helper Thomas Zimmermann
                   ` (7 more replies)
  0 siblings, 8 replies; 16+ messages in thread
From: Thomas Zimmermann @ 2024-07-15  9:38 UTC (permalink / raw)
  To: jfalempe, airlied, daniel, airlied, mripard, maarten.lankhorst
  Cc: dri-devel, Thomas Zimmermann

Old or simple hardware only supports a single CRTC with multiple
conenctoed outputs. This breaks most userspace compositors, which
only support a single output per CRTC. This currently happens with
ast and mgag200 drivers. The drivers contain a work around that
dynamically disables all but one connected output.

Patches 1 and 2 push the workaround into probe helpers and make it
configurable in the kernel config. For each connector, the driver
needs to specify a bitmask of connectors with higher priority. If
one of them is connected, the connector at hand is always reported
as disconnected. Connectors without priority bitmask as not affected.

Patches 3 to 5 update and simplify the ast drivers. The new workaround
now allows to have multiple physical conenctors in ast. So patch 5
finally allows VGA and DisplayPort on the same device.

Patches 6 and 7 update mgag200.

Any future driver that exposes the same problem as ast and mgag200
can simply hook into the workaround. Hopefully userspace can be fixed
at some point.

Thomas Zimmermann (7):
  drm/probe-helper: Call connector detect functions in single helper
  drm/probe-helper: Optionally report single connected output per CRTC
  drm/ast: Set connector priorities
  drm/ast: Remove struct ast_bmc_connector
  drm/ast: Support ASTDP and VGA at the same time
  drm/mgag200: Set connector priorities
  drm/mgag200: Remove struct mgag200_bmc_connector

 drivers/gpu/drm/Kconfig                   |  15 +++
 drivers/gpu/drm/ast/ast_drv.h             |  17 +--
 drivers/gpu/drm/ast/ast_main.c            |   2 +-
 drivers/gpu/drm/ast/ast_mode.c            |  49 ++------
 drivers/gpu/drm/drm_probe_helper.c        | 137 +++++++++++++++++++---
 drivers/gpu/drm/mgag200/mgag200_bmc.c     |  44 +------
 drivers/gpu/drm/mgag200/mgag200_drv.h     |   9 +-
 drivers/gpu/drm/mgag200/mgag200_g200eh.c  |   4 +-
 drivers/gpu/drm/mgag200/mgag200_g200eh3.c |   4 +-
 drivers/gpu/drm/mgag200/mgag200_g200er.c  |   4 +-
 drivers/gpu/drm/mgag200/mgag200_g200ev.c  |   4 +-
 drivers/gpu/drm/mgag200/mgag200_g200ew3.c |   4 +-
 drivers/gpu/drm/mgag200/mgag200_g200se.c  |   4 +-
 drivers/gpu/drm/mgag200/mgag200_g200wb.c  |   4 +-
 include/drm/drm_connector.h               |   2 +
 include/drm/drm_probe_helper.h            |   2 +
 16 files changed, 177 insertions(+), 128 deletions(-)

-- 
2.45.2


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 1/7] drm/probe-helper: Call connector detect functions in single helper
  2024-07-15  9:38 [PATCH 0/7] drm/probe-helpers: Work around multi-outputs-per-CRTC problem Thomas Zimmermann
@ 2024-07-15  9:38 ` Thomas Zimmermann
  2024-07-16  8:21   ` Maxime Ripard
  2024-07-15  9:38 ` [PATCH 2/7] drm/probe-helper: Optionally report single connected output per CRTC Thomas Zimmermann
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 16+ messages in thread
From: Thomas Zimmermann @ 2024-07-15  9:38 UTC (permalink / raw)
  To: jfalempe, airlied, daniel, airlied, mripard, maarten.lankhorst
  Cc: dri-devel, Thomas Zimmermann

Move the logic to call the connector's detect helper into a single
internal function. Reduces code dupliction.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/drm_probe_helper.c | 33 +++++++++++++++---------------
 1 file changed, 17 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index bb49d552e671..f14301abf53f 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -338,10 +338,23 @@ void drm_kms_helper_poll_reschedule(struct drm_device *dev)
 }
 EXPORT_SYMBOL(drm_kms_helper_poll_reschedule);
 
+static int detect_connector_status(struct drm_connector *connector,
+				   struct drm_modeset_acquire_ctx *ctx,
+				   bool force)
+{
+	const struct drm_connector_helper_funcs *funcs = connector->helper_private;
+
+	if (funcs->detect_ctx)
+		return funcs->detect_ctx(connector, ctx, force);
+	else if (connector->funcs->detect)
+		return connector->funcs->detect(connector, force);
+
+	return connector_status_connected;
+}
+
 static enum drm_connector_status
 drm_helper_probe_detect_ctx(struct drm_connector *connector, bool force)
 {
-	const struct drm_connector_helper_funcs *funcs = connector->helper_private;
 	struct drm_modeset_acquire_ctx ctx;
 	int ret;
 
@@ -349,14 +362,8 @@ drm_helper_probe_detect_ctx(struct drm_connector *connector, bool force)
 
 retry:
 	ret = drm_modeset_lock(&connector->dev->mode_config.connection_mutex, &ctx);
-	if (!ret) {
-		if (funcs->detect_ctx)
-			ret = funcs->detect_ctx(connector, &ctx, force);
-		else if (connector->funcs->detect)
-			ret = connector->funcs->detect(connector, force);
-		else
-			ret = connector_status_connected;
-	}
+	if (!ret)
+		ret = detect_connector_status(connector, &ctx, force);
 
 	if (ret == -EDEADLK) {
 		drm_modeset_backoff(&ctx);
@@ -390,7 +397,6 @@ drm_helper_probe_detect(struct drm_connector *connector,
 			struct drm_modeset_acquire_ctx *ctx,
 			bool force)
 {
-	const struct drm_connector_helper_funcs *funcs = connector->helper_private;
 	struct drm_device *dev = connector->dev;
 	int ret;
 
@@ -401,12 +407,7 @@ drm_helper_probe_detect(struct drm_connector *connector,
 	if (ret)
 		return ret;
 
-	if (funcs->detect_ctx)
-		ret = funcs->detect_ctx(connector, ctx, force);
-	else if (connector->funcs->detect)
-		ret = connector->funcs->detect(connector, force);
-	else
-		ret = connector_status_connected;
+	ret = detect_connector_status(connector, ctx, force);
 
 	if (ret != connector->status)
 		connector->epoch_counter += 1;
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 2/7] drm/probe-helper: Optionally report single connected output per CRTC
  2024-07-15  9:38 [PATCH 0/7] drm/probe-helpers: Work around multi-outputs-per-CRTC problem Thomas Zimmermann
  2024-07-15  9:38 ` [PATCH 1/7] drm/probe-helper: Call connector detect functions in single helper Thomas Zimmermann
@ 2024-07-15  9:38 ` Thomas Zimmermann
  2024-07-16  9:01   ` Maxime Ripard
  2024-07-16  9:46   ` Daniel Vetter
  2024-07-15  9:38 ` [PATCH 3/7] drm/ast: Set connector priorities Thomas Zimmermann
                   ` (5 subsequent siblings)
  7 siblings, 2 replies; 16+ messages in thread
From: Thomas Zimmermann @ 2024-07-15  9:38 UTC (permalink / raw)
  To: jfalempe, airlied, daniel, airlied, mripard, maarten.lankhorst
  Cc: dri-devel, Thomas Zimmermann

For CRTCs with multiple outputs (i.e., encoders plus connectors),
only report at most a single connected output to userspace. Make
this configurable via CONFIG_DRM_REPORT_SINGLE_CONNECTED_CRTC_OUTPUT.

Having multiple connected outputs on the same CRTC complicates
display-mode and format selection, so most userspace does not
support this. This is mostly not a problem in practice, as modern
display hardware provides a separate CRTC for each output. On
old hardware or hardware with BMCs, a single CRTC often drives
multiple displays. Only reporting one of them as connected makes
the hardware compatible with common userspace.

Add the field prioritized_connectors to struct drm_connector. The
bitmask signals which other connectors have priority. Also provide
the helper drm_probe_helper_prioritize_connectors() that sets
default priorities for a given set of connectors. Calling the
helper should be enough to set up the functionality for most drivers.

With the prioritization bits in place, update connector-status
detection to test against prioritized conenctors. So when the probe
helpers detect a connector as connected, test against the prioritized
connectors. If any is also connected, set the connector status to
disconnected.

Please note that this functionality is a workaround for limitations
in userspace. If your compositor supports multiple outputs per CRTC,
CONFIG_DRM_REPORT_SINGLE_CONNECTED_CRTC_OUTPUT should be disabled.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/Kconfig            |  15 +++++
 drivers/gpu/drm/drm_probe_helper.c | 104 +++++++++++++++++++++++++++++
 include/drm/drm_connector.h        |   2 +
 include/drm/drm_probe_helper.h     |   2 +
 4 files changed, 123 insertions(+)

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index fd0749c0c630..d1afdbd2d93b 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -105,6 +105,21 @@ config DRM_KMS_HELPER
 	help
 	  CRTC helpers for KMS drivers.
 
+config DRM_REPORT_SINGLE_CONNECTED_CRTC_OUTPUT
+       bool "Report only a single connected output per CRTC"
+       depends on DRM
+       default n
+       help
+         CRTCs can support multiple encoders and connectors for output.
+         More than one pair can be connected to a display at a time. Most
+         userspace only supports at most one connected output per CRTC at a
+	 time. Enable this option to let DRM report at most one connected
+	 output per CRTC. This is mostly relevant for low-end and old
+	 hardware. Most modern graphics hardware supports a separate CRTC
+	 per output and won't be affected by this setting.
+
+         If in doubt, say "Y".
+
 config DRM_PANIC
 	bool "Display a user-friendly message when a kernel panic occurs"
 	depends on DRM && !(FRAMEBUFFER_CONSOLE && VT_CONSOLE)
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index f14301abf53f..fc0652635148 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -352,6 +352,74 @@ static int detect_connector_status(struct drm_connector *connector,
 	return connector_status_connected;
 }
 
+static int reported_connector_status(struct drm_connector *connector, int detected_status,
+				     struct drm_modeset_acquire_ctx *ctx, bool force)
+{
+#if defined(CONFIG_DRM_REPORT_SINGLE_CONNECTED_CRTC_OUTPUT)
+	struct drm_connector *prio_connector = connector;
+	struct drm_device *dev = connector->dev;
+	struct drm_connector_list_iter iter;
+	struct drm_connector *pos;
+	u32 connector_mask;
+	int ret = 0;
+
+	if (!connector->prioritized_connectors)
+		return detected_status;
+
+	if (detected_status != connector_status_connected)
+		return detected_status;
+
+	connector_mask = drm_connector_mask(connector);
+
+	/*
+	 * Find the connector with status 'connected' and a higher
+	 * priority.
+	 */
+	drm_connector_list_iter_begin(dev, &iter);
+	drm_for_each_connector_iter(pos, &iter) {
+		if (!(drm_connector_mask(pos) & connector->prioritized_connectors))
+			continue;
+
+		/*
+		 * Warn if connector has priority over itself.
+		 */
+		if (drm_WARN_ON_ONCE(dev, pos == connector))
+			continue;
+
+		/*
+		 * Warn if both connectors have priority over each other. Pick the
+		 * one with the lower index.
+		 */
+		if (drm_WARN_ON_ONCE(dev, pos->prioritized_connectors & connector_mask)) {
+			if (pos->index > connector->index)
+				continue;
+		}
+
+		ret = detect_connector_status(pos, ctx, force);
+		if (ret < 0)
+			break;
+		if (ret == connector_status_disconnected)
+			continue;
+
+		prio_connector = pos;
+		break;
+	}
+	drm_connector_list_iter_end(&iter);
+
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * We've found another connected connector. Report our connector
+	 * as 'disconnected'.
+	 */
+	if (prio_connector != connector)
+		detected_status = connector_status_disconnected;
+#endif
+
+	return detected_status;
+}
+
 static enum drm_connector_status
 drm_helper_probe_detect_ctx(struct drm_connector *connector, bool force)
 {
@@ -373,6 +441,12 @@ drm_helper_probe_detect_ctx(struct drm_connector *connector, bool force)
 	if (WARN_ON(ret < 0))
 		ret = connector_status_unknown;
 
+	ret = reported_connector_status(connector, ret, &ctx, force);
+	if (ret == -EDEADLK) {
+		drm_modeset_backoff(&ctx);
+		goto retry;
+	}
+
 	if (ret != connector->status)
 		connector->epoch_counter += 1;
 
@@ -408,6 +482,7 @@ drm_helper_probe_detect(struct drm_connector *connector,
 		return ret;
 
 	ret = detect_connector_status(connector, ctx, force);
+	ret = reported_connector_status(connector, ret, ctx, force);
 
 	if (ret != connector->status)
 		connector->epoch_counter += 1;
@@ -416,6 +491,35 @@ drm_helper_probe_detect(struct drm_connector *connector,
 }
 EXPORT_SYMBOL(drm_helper_probe_detect);
 
+/**
+ * drm_probe_helper_prioritize_connectors - Set connector priorities
+ * @dev: the DRM device with connectors
+ * @connector_mask: Bitmask connector indices
+ *
+ * drm_probe_helper_prioritize_connectors() prioritizes all connectors
+ * specified in @connector_mask. All given connectors are assumed to
+ * interfere with each other. Connectors with a lower index have priority
+ * over connectors with a higher index.
+ */
+void drm_probe_helper_prioritize_connectors(struct drm_device *dev, u32 connector_mask)
+{
+	struct drm_connector_list_iter iter;
+	struct drm_connector *connector;
+	u32 prioritized_connectors = 0;
+
+	drm_connector_list_iter_begin(dev, &iter);
+	drm_for_each_connector_iter(connector, &iter) {
+		u32 mask = drm_connector_mask(connector);
+
+		if (!(mask & connector_mask))
+			continue;
+		connector->prioritized_connectors = prioritized_connectors;
+		prioritized_connectors |= mask;
+	}
+	drm_connector_list_iter_end(&iter);
+}
+EXPORT_SYMBOL(drm_probe_helper_prioritize_connectors);
+
 static int drm_helper_probe_get_modes(struct drm_connector *connector)
 {
 	const struct drm_connector_helper_funcs *connector_funcs =
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 5ad735253413..e3039478e928 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1985,6 +1985,8 @@ struct drm_connector {
 	/** @epoch_counter: used to detect any other changes in connector, besides status */
 	u64 epoch_counter;
 
+	u32 prioritized_connectors;
+
 	/**
 	 * @possible_encoders: Bit mask of encoders that can drive this
 	 * connector, drm_encoder_index() determines the index into the bitfield
diff --git a/include/drm/drm_probe_helper.h b/include/drm/drm_probe_helper.h
index d6ce7b218b77..05e23485550d 100644
--- a/include/drm/drm_probe_helper.h
+++ b/include/drm/drm_probe_helper.h
@@ -17,6 +17,8 @@ int drm_helper_probe_detect(struct drm_connector *connector,
 			    struct drm_modeset_acquire_ctx *ctx,
 			    bool force);
 
+void drm_probe_helper_prioritize_connectors(struct drm_device *dev, u32 connector_mask);
+
 int drmm_kms_helper_poll_init(struct drm_device *dev);
 void drm_kms_helper_poll_init(struct drm_device *dev);
 void drm_kms_helper_poll_fini(struct drm_device *dev);
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 3/7] drm/ast: Set connector priorities
  2024-07-15  9:38 [PATCH 0/7] drm/probe-helpers: Work around multi-outputs-per-CRTC problem Thomas Zimmermann
  2024-07-15  9:38 ` [PATCH 1/7] drm/probe-helper: Call connector detect functions in single helper Thomas Zimmermann
  2024-07-15  9:38 ` [PATCH 2/7] drm/probe-helper: Optionally report single connected output per CRTC Thomas Zimmermann
@ 2024-07-15  9:38 ` Thomas Zimmermann
  2024-07-15  9:39 ` [PATCH 4/7] drm/ast: Remove struct ast_bmc_connector Thomas Zimmermann
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Thomas Zimmermann @ 2024-07-15  9:38 UTC (permalink / raw)
  To: jfalempe, airlied, daniel, airlied, mripard, maarten.lankhorst
  Cc: dri-devel, Thomas Zimmermann

Call drm_probe_helper_prioritize_connectors() to set connector
priorities. Guarantees that only a single output is connected at a
time.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/ast/ast_mode.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
index dc8f639e82fd..ac8a3c6b8bf8 100644
--- a/drivers/gpu/drm/ast/ast_mode.c
+++ b/drivers/gpu/drm/ast/ast_mode.c
@@ -1970,6 +1970,9 @@ int ast_mode_config_init(struct ast_device *ast)
 	if (ret)
 		return ret;
 
+	/* All connectors interfere with each other. */
+	drm_probe_helper_prioritize_connectors(dev, GENMASK(dev->mode_config.num_connector, 0));
+
 	drm_mode_config_reset(dev);
 
 	ret = drmm_kms_helper_poll_init(dev);
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 4/7] drm/ast: Remove struct ast_bmc_connector
  2024-07-15  9:38 [PATCH 0/7] drm/probe-helpers: Work around multi-outputs-per-CRTC problem Thomas Zimmermann
                   ` (2 preceding siblings ...)
  2024-07-15  9:38 ` [PATCH 3/7] drm/ast: Set connector priorities Thomas Zimmermann
@ 2024-07-15  9:39 ` Thomas Zimmermann
  2024-07-15  9:39 ` [PATCH 5/7] drm/ast: Support ASTDP and VGA at the same time Thomas Zimmermann
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Thomas Zimmermann @ 2024-07-15  9:39 UTC (permalink / raw)
  To: jfalempe, airlied, daniel, airlied, mripard, maarten.lankhorst
  Cc: dri-devel, Thomas Zimmermann

Ast's BMC connector tracks the status of an underlying physical
connector and set BMC status accordingly. This functionality has
been moved into probe helpers. The BMC is always connected and the
helpers compute the correct status. Hence, remove the driver's
dedicated code.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/ast/ast_drv.h  | 17 +------------
 drivers/gpu/drm/ast/ast_mode.c | 46 ++++------------------------------
 2 files changed, 6 insertions(+), 57 deletions(-)

diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h
index ba3d86973995..faafb696dc74 100644
--- a/drivers/gpu/drm/ast/ast_drv.h
+++ b/drivers/gpu/drm/ast/ast_drv.h
@@ -146,21 +146,6 @@ static inline struct ast_plane *to_ast_plane(struct drm_plane *plane)
 	return container_of(plane, struct ast_plane, base);
 }
 
-/*
- * BMC
- */
-
-struct ast_bmc_connector {
-	struct drm_connector base;
-	struct drm_connector *physical_connector;
-};
-
-static inline struct ast_bmc_connector *
-to_ast_bmc_connector(struct drm_connector *connector)
-{
-	return container_of(connector, struct ast_bmc_connector, base);
-}
-
 /*
  * Device
  */
@@ -208,7 +193,7 @@ struct ast_device {
 		} astdp;
 		struct {
 			struct drm_encoder encoder;
-			struct ast_bmc_connector bmc_connector;
+			struct drm_connector connector;
 		} bmc;
 	} output;
 
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
index ac8a3c6b8bf8..f59cb0f8fbb2 100644
--- a/drivers/gpu/drm/ast/ast_mode.c
+++ b/drivers/gpu/drm/ast/ast_mode.c
@@ -1761,30 +1761,6 @@ static const struct drm_encoder_funcs ast_bmc_encoder_funcs = {
 	.destroy = drm_encoder_cleanup,
 };
 
-static int ast_bmc_connector_helper_detect_ctx(struct drm_connector *connector,
-					       struct drm_modeset_acquire_ctx *ctx,
-					       bool force)
-{
-	struct ast_bmc_connector *bmc_connector = to_ast_bmc_connector(connector);
-	struct drm_connector *physical_connector = bmc_connector->physical_connector;
-
-	/*
-	 * Most user-space compositors cannot handle more than one connected
-	 * connector per CRTC. Hence, we only mark the BMC as connected if the
-	 * physical connector is disconnected. If the physical connector's status
-	 * is connected or unknown, the BMC remains disconnected. This has no
-	 * effect on the output of the BMC.
-	 *
-	 * FIXME: Remove this logic once user-space compositors can handle more
-	 *        than one connector per CRTC. The BMC should always be connected.
-	 */
-
-	if (physical_connector && physical_connector->status == connector_status_disconnected)
-		return connector_status_connected;
-
-	return connector_status_disconnected;
-}
-
 static int ast_bmc_connector_helper_get_modes(struct drm_connector *connector)
 {
 	return drm_add_modes_noedid(connector, 4096, 4096);
@@ -1792,7 +1768,6 @@ static int ast_bmc_connector_helper_get_modes(struct drm_connector *connector)
 
 static const struct drm_connector_helper_funcs ast_bmc_connector_helper_funcs = {
 	.get_modes = ast_bmc_connector_helper_get_modes,
-	.detect_ctx = ast_bmc_connector_helper_detect_ctx,
 };
 
 static const struct drm_connector_funcs ast_bmc_connector_funcs = {
@@ -1804,10 +1779,8 @@ static const struct drm_connector_funcs ast_bmc_connector_funcs = {
 };
 
 static int ast_bmc_connector_init(struct drm_device *dev,
-				  struct ast_bmc_connector *bmc_connector,
-				  struct drm_connector *physical_connector)
+				  struct drm_connector *connector)
 {
-	struct drm_connector *connector = &bmc_connector->base;
 	int ret;
 
 	ret = drm_connector_init(dev, connector, &ast_bmc_connector_funcs,
@@ -1817,19 +1790,15 @@ static int ast_bmc_connector_init(struct drm_device *dev,
 
 	drm_connector_helper_add(connector, &ast_bmc_connector_helper_funcs);
 
-	bmc_connector->physical_connector = physical_connector;
-
 	return 0;
 }
 
-static int ast_bmc_output_init(struct ast_device *ast,
-			       struct drm_connector *physical_connector)
+static int ast_bmc_output_init(struct ast_device *ast)
 {
 	struct drm_device *dev = &ast->base;
 	struct drm_crtc *crtc = &ast->crtc;
 	struct drm_encoder *encoder = &ast->output.bmc.encoder;
-	struct ast_bmc_connector *bmc_connector = &ast->output.bmc.bmc_connector;
-	struct drm_connector *connector = &bmc_connector->base;
+	struct drm_connector *connector = &ast->output.bmc.connector;
 	int ret;
 
 	ret = drm_encoder_init(dev, encoder,
@@ -1839,7 +1808,7 @@ static int ast_bmc_output_init(struct ast_device *ast,
 		return ret;
 	encoder->possible_crtcs = drm_crtc_mask(crtc);
 
-	ret = ast_bmc_connector_init(dev, bmc_connector, physical_connector);
+	ret = ast_bmc_connector_init(dev, connector);
 	if (ret)
 		return ret;
 
@@ -1901,7 +1870,6 @@ static const struct drm_mode_config_funcs ast_mode_config_funcs = {
 int ast_mode_config_init(struct ast_device *ast)
 {
 	struct drm_device *dev = &ast->base;
-	struct drm_connector *physical_connector = NULL;
 	int ret;
 
 	ret = drmm_mutex_init(dev, &ast->modeset_lock);
@@ -1946,27 +1914,23 @@ int ast_mode_config_init(struct ast_device *ast)
 		ret = ast_vga_output_init(ast);
 		if (ret)
 			return ret;
-		physical_connector = &ast->output.vga.connector;
 	}
 	if (ast->tx_chip_types & AST_TX_SIL164_BIT) {
 		ret = ast_sil164_output_init(ast);
 		if (ret)
 			return ret;
-		physical_connector = &ast->output.sil164.connector;
 	}
 	if (ast->tx_chip_types & AST_TX_DP501_BIT) {
 		ret = ast_dp501_output_init(ast);
 		if (ret)
 			return ret;
-		physical_connector = &ast->output.dp501.connector;
 	}
 	if (ast->tx_chip_types & AST_TX_ASTDP_BIT) {
 		ret = ast_astdp_output_init(ast);
 		if (ret)
 			return ret;
-		physical_connector = &ast->output.astdp.connector;
 	}
-	ret = ast_bmc_output_init(ast, physical_connector);
+	ret = ast_bmc_output_init(ast);
 	if (ret)
 		return ret;
 
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 5/7] drm/ast: Support ASTDP and VGA at the same time
  2024-07-15  9:38 [PATCH 0/7] drm/probe-helpers: Work around multi-outputs-per-CRTC problem Thomas Zimmermann
                   ` (3 preceding siblings ...)
  2024-07-15  9:39 ` [PATCH 4/7] drm/ast: Remove struct ast_bmc_connector Thomas Zimmermann
@ 2024-07-15  9:39 ` Thomas Zimmermann
  2024-07-16  8:42   ` oushixiong
  2024-07-15  9:39 ` [PATCH 6/7] drm/mgag200: Set connector priorities Thomas Zimmermann
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 16+ messages in thread
From: Thomas Zimmermann @ 2024-07-15  9:39 UTC (permalink / raw)
  To: jfalempe, airlied, daniel, airlied, mripard, maarten.lankhorst
  Cc: dri-devel, Thomas Zimmermann, Shixiong Ou

AST2600 can host VGA and DisplayPort outputs. Support both on the
same device. As userspace can often only support a single output per
CRTC, connectors are prioritized against each other by the probe
helpers.

Reported-by: Shixiong Ou <oushixiong@kylinos.cn>
Closes: https://lore.kernel.org/dri-devel/20240711090102.352213-1-oushixiong1025@163.com/
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/ast/ast_main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c
index 0637abb70361..d43aedaa8dd0 100644
--- a/drivers/gpu/drm/ast/ast_main.c
+++ b/drivers/gpu/drm/ast/ast_main.c
@@ -115,7 +115,7 @@ static void ast_detect_tx_chip(struct ast_device *ast, bool need_post)
 	} else if (IS_AST_GEN7(ast)) {
 		if (ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xD1, TX_TYPE_MASK) ==
 		    ASTDP_DPMCU_TX) {
-			ast->tx_chip_types = AST_TX_ASTDP_BIT;
+			ast->tx_chip_types |= AST_TX_ASTDP_BIT;
 			ast_dp_launch(&ast->base);
 		}
 	}
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 6/7] drm/mgag200: Set connector priorities
  2024-07-15  9:38 [PATCH 0/7] drm/probe-helpers: Work around multi-outputs-per-CRTC problem Thomas Zimmermann
                   ` (4 preceding siblings ...)
  2024-07-15  9:39 ` [PATCH 5/7] drm/ast: Support ASTDP and VGA at the same time Thomas Zimmermann
@ 2024-07-15  9:39 ` Thomas Zimmermann
  2024-07-15  9:39 ` [PATCH 7/7] drm/mgag200: Remove struct mgag200_bmc_connector Thomas Zimmermann
  2024-07-17 12:54 ` [PATCH 0/7] drm/probe-helpers: Work around multi-outputs-per-CRTC problem Thomas Zimmermann
  7 siblings, 0 replies; 16+ messages in thread
From: Thomas Zimmermann @ 2024-07-15  9:39 UTC (permalink / raw)
  To: jfalempe, airlied, daniel, airlied, mripard, maarten.lankhorst
  Cc: dri-devel, Thomas Zimmermann

Call drm_probe_helper_prioritize_connectors() to set connector
priorities. Guarantees that only a single output is connected at a
time.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/mgag200/mgag200_g200eh.c  | 2 ++
 drivers/gpu/drm/mgag200/mgag200_g200eh3.c | 2 ++
 drivers/gpu/drm/mgag200/mgag200_g200er.c  | 2 ++
 drivers/gpu/drm/mgag200/mgag200_g200ev.c  | 2 ++
 drivers/gpu/drm/mgag200/mgag200_g200ew3.c | 2 ++
 drivers/gpu/drm/mgag200/mgag200_g200se.c  | 2 ++
 drivers/gpu/drm/mgag200/mgag200_g200wb.c  | 2 ++
 7 files changed, 14 insertions(+)

diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh.c b/drivers/gpu/drm/mgag200/mgag200_g200eh.c
index 52bf49ead5c5..c8204e8a1daf 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200eh.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200eh.c
@@ -222,6 +222,8 @@ static int mgag200_g200eh_pipeline_init(struct mga_device *mdev)
 	if (ret)
 		return ret;
 
+	drm_probe_helper_prioritize_connectors(dev, GENMASK(dev->mode_config.num_connector, 0));
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c
index e7f89b2a59fd..749baefb0a7e 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c
@@ -126,6 +126,8 @@ static int mgag200_g200eh3_pipeline_init(struct mga_device *mdev)
 	if (ret)
 		return ret;
 
+	drm_probe_helper_prioritize_connectors(dev, GENMASK(dev->mode_config.num_connector, 0));
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200er.c b/drivers/gpu/drm/mgag200/mgag200_g200er.c
index 737a48aa9160..e8c84d3258aa 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200er.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200er.c
@@ -262,6 +262,8 @@ static int mgag200_g200er_pipeline_init(struct mga_device *mdev)
 	if (ret)
 		return ret;
 
+	drm_probe_helper_prioritize_connectors(dev, GENMASK(dev->mode_config.num_connector, 0));
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ev.c b/drivers/gpu/drm/mgag200/mgag200_g200ev.c
index 8d1ccc2ad94a..e2b13a90b405 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200ev.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200ev.c
@@ -263,6 +263,8 @@ static int mgag200_g200ev_pipeline_init(struct mga_device *mdev)
 	if (ret)
 		return ret;
 
+	drm_probe_helper_prioritize_connectors(dev, GENMASK(dev->mode_config.num_connector, 0));
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c
index 265f3e95830a..384041e7b839 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c
@@ -135,6 +135,8 @@ static int mgag200_g200ew3_pipeline_init(struct mga_device *mdev)
 	if (ret)
 		return ret;
 
+	drm_probe_helper_prioritize_connectors(dev, GENMASK(dev->mode_config.num_connector, 0));
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200se.c b/drivers/gpu/drm/mgag200/mgag200_g200se.c
index cf7f6897838f..95514dcb8c53 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200se.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200se.c
@@ -394,6 +394,8 @@ static int mgag200_g200se_pipeline_init(struct mga_device *mdev)
 	if (ret)
 		return ret;
 
+	drm_probe_helper_prioritize_connectors(dev, GENMASK(dev->mode_config.num_connector, 0));
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200wb.c b/drivers/gpu/drm/mgag200/mgag200_g200wb.c
index e25477347c3e..0100b4d03b89 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200wb.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200wb.c
@@ -269,6 +269,8 @@ static int mgag200_g200wb_pipeline_init(struct mga_device *mdev)
 	if (ret)
 		return ret;
 
+	drm_probe_helper_prioritize_connectors(dev, GENMASK(dev->mode_config.num_connector, 0));
+
 	return 0;
 }
 
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 7/7] drm/mgag200: Remove struct mgag200_bmc_connector
  2024-07-15  9:38 [PATCH 0/7] drm/probe-helpers: Work around multi-outputs-per-CRTC problem Thomas Zimmermann
                   ` (5 preceding siblings ...)
  2024-07-15  9:39 ` [PATCH 6/7] drm/mgag200: Set connector priorities Thomas Zimmermann
@ 2024-07-15  9:39 ` Thomas Zimmermann
  2024-07-17 12:54 ` [PATCH 0/7] drm/probe-helpers: Work around multi-outputs-per-CRTC problem Thomas Zimmermann
  7 siblings, 0 replies; 16+ messages in thread
From: Thomas Zimmermann @ 2024-07-15  9:39 UTC (permalink / raw)
  To: jfalempe, airlied, daniel, airlied, mripard, maarten.lankhorst
  Cc: dri-devel, Thomas Zimmermann

Mgag200's BMC connector tracks the status of an underlying physical
connector and set BMC status accordingly. This functionality has
been moved into probe helpers. The BMC is always connected and the
helpers compute the correct status. Hence, remove the driver's
dedicated code.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/mgag200/mgag200_bmc.c     | 44 +++--------------------
 drivers/gpu/drm/mgag200/mgag200_drv.h     |  9 ++---
 drivers/gpu/drm/mgag200/mgag200_g200eh.c  |  2 +-
 drivers/gpu/drm/mgag200/mgag200_g200eh3.c |  2 +-
 drivers/gpu/drm/mgag200/mgag200_g200er.c  |  2 +-
 drivers/gpu/drm/mgag200/mgag200_g200ev.c  |  2 +-
 drivers/gpu/drm/mgag200/mgag200_g200ew3.c |  2 +-
 drivers/gpu/drm/mgag200/mgag200_g200se.c  |  2 +-
 drivers/gpu/drm/mgag200/mgag200_g200wb.c  |  2 +-
 9 files changed, 13 insertions(+), 54 deletions(-)

diff --git a/drivers/gpu/drm/mgag200/mgag200_bmc.c b/drivers/gpu/drm/mgag200/mgag200_bmc.c
index 45e35dffb3ea..1e0537f9cbea 100644
--- a/drivers/gpu/drm/mgag200/mgag200_bmc.c
+++ b/drivers/gpu/drm/mgag200/mgag200_bmc.c
@@ -9,11 +9,6 @@
 
 #include "mgag200_drv.h"
 
-static struct mgag200_bmc_connector *to_mgag200_bmc_connector(struct drm_connector *connector)
-{
-	return container_of(connector, struct mgag200_bmc_connector, base);
-}
-
 void mgag200_bmc_stop_scanout(struct mga_device *mdev)
 {
 	u8 tmp;
@@ -107,30 +102,6 @@ static const struct drm_encoder_funcs mgag200_bmc_encoder_funcs = {
 	.destroy = drm_encoder_cleanup,
 };
 
-static int mgag200_bmc_connector_helper_detect_ctx(struct drm_connector *connector,
-						   struct drm_modeset_acquire_ctx *ctx,
-						   bool force)
-{
-	struct mgag200_bmc_connector *bmc_connector = to_mgag200_bmc_connector(connector);
-	struct drm_connector *physical_connector = bmc_connector->physical_connector;
-
-	/*
-	 * Most user-space compositors cannot handle more than one connected
-	 * connector per CRTC. Hence, we only mark the BMC as connected if the
-	 * physical connector is disconnected. If the physical connector's status
-	 * is connected or unknown, the BMC remains disconnected. This has no
-	 * effect on the output of the BMC.
-	 *
-	 * FIXME: Remove this logic once user-space compositors can handle more
-	 *        than one connector per CRTC. The BMC should always be connected.
-	 */
-
-	if (physical_connector && physical_connector->status == connector_status_disconnected)
-		return connector_status_connected;
-
-	return connector_status_disconnected;
-}
-
 static int mgag200_bmc_connector_helper_get_modes(struct drm_connector *connector)
 {
 	struct drm_device *dev = connector->dev;
@@ -142,7 +113,6 @@ static int mgag200_bmc_connector_helper_get_modes(struct drm_connector *connecto
 
 static const struct drm_connector_helper_funcs mgag200_bmc_connector_helper_funcs = {
 	.get_modes = mgag200_bmc_connector_helper_get_modes,
-	.detect_ctx = mgag200_bmc_connector_helper_detect_ctx,
 };
 
 static const struct drm_connector_funcs mgag200_bmc_connector_funcs = {
@@ -154,10 +124,8 @@ static const struct drm_connector_funcs mgag200_bmc_connector_funcs = {
 };
 
 static int mgag200_bmc_connector_init(struct drm_device *dev,
-				      struct mgag200_bmc_connector *bmc_connector,
-				      struct drm_connector *physical_connector)
+				      struct drm_connector *connector)
 {
-	struct drm_connector *connector = &bmc_connector->base;
 	int ret;
 
 	ret = drm_connector_init(dev, connector, &mgag200_bmc_connector_funcs,
@@ -166,17 +134,14 @@ static int mgag200_bmc_connector_init(struct drm_device *dev,
 		return ret;
 	drm_connector_helper_add(connector, &mgag200_bmc_connector_helper_funcs);
 
-	bmc_connector->physical_connector = physical_connector;
-
 	return 0;
 }
 
-int mgag200_bmc_output_init(struct mga_device *mdev, struct drm_connector *physical_connector)
+int mgag200_bmc_output_init(struct mga_device *mdev)
 {
 	struct drm_device *dev = &mdev->base;
 	struct drm_crtc *crtc = &mdev->crtc;
 	struct drm_encoder *encoder;
-	struct mgag200_bmc_connector *bmc_connector;
 	struct drm_connector *connector;
 	int ret;
 
@@ -187,11 +152,10 @@ int mgag200_bmc_output_init(struct mga_device *mdev, struct drm_connector *physi
 		return ret;
 	encoder->possible_crtcs = drm_crtc_mask(crtc);
 
-	bmc_connector = &mdev->output.bmc.bmc_connector;
-	ret = mgag200_bmc_connector_init(dev, bmc_connector, physical_connector);
+	connector = &mdev->output.bmc.connector;
+	ret = mgag200_bmc_connector_init(dev, connector);
 	if (ret)
 		return ret;
-	connector = &bmc_connector->base;
 
 	ret = drm_connector_attach_encoder(connector, encoder);
 	if (ret)
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h
index f97eaa49b089..abc7a58ed762 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.h
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.h
@@ -188,11 +188,6 @@ static inline struct mgag200_crtc_state *to_mgag200_crtc_state(struct drm_crtc_s
 	return container_of(base, struct mgag200_crtc_state, base);
 }
 
-struct mgag200_bmc_connector {
-	struct drm_connector base;
-	struct drm_connector *physical_connector;
-};
-
 enum mga_type {
 	G200_PCI,
 	G200_AGP,
@@ -285,7 +280,7 @@ struct mga_device {
 		} vga;
 		struct {
 			struct drm_encoder encoder;
-			struct mgag200_bmc_connector bmc_connector;
+			struct drm_connector connector;
 		} bmc;
 	} output;
 };
@@ -433,6 +428,6 @@ int mgag200_vga_output_init(struct mga_device *mdev);
 /* mgag200_bmc.c */
 void mgag200_bmc_stop_scanout(struct mga_device *mdev);
 void mgag200_bmc_start_scanout(struct mga_device *mdev);
-int mgag200_bmc_output_init(struct mga_device *mdev, struct drm_connector *physical_connector);
+int mgag200_bmc_output_init(struct mga_device *mdev);
 
 #endif				/* __MGAG200_DRV_H__ */
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh.c b/drivers/gpu/drm/mgag200/mgag200_g200eh.c
index c8204e8a1daf..a0f860c394b3 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200eh.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200eh.c
@@ -218,7 +218,7 @@ static int mgag200_g200eh_pipeline_init(struct mga_device *mdev)
 	if (ret)
 		return ret;
 
-	ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
+	ret = mgag200_bmc_output_init(mdev);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c
index 749baefb0a7e..a7373d6572e7 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c
@@ -122,7 +122,7 @@ static int mgag200_g200eh3_pipeline_init(struct mga_device *mdev)
 	if (ret)
 		return ret;
 
-	ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
+	ret = mgag200_bmc_output_init(mdev);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200er.c b/drivers/gpu/drm/mgag200/mgag200_g200er.c
index e8c84d3258aa..0407ee540b20 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200er.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200er.c
@@ -258,7 +258,7 @@ static int mgag200_g200er_pipeline_init(struct mga_device *mdev)
 	if (ret)
 		return ret;
 
-	ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
+	ret = mgag200_bmc_output_init(mdev);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ev.c b/drivers/gpu/drm/mgag200/mgag200_g200ev.c
index e2b13a90b405..51530831d5f0 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200ev.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200ev.c
@@ -259,7 +259,7 @@ static int mgag200_g200ev_pipeline_init(struct mga_device *mdev)
 	if (ret)
 		return ret;
 
-	ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
+	ret = mgag200_bmc_output_init(mdev);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c
index 384041e7b839..f18122230ffb 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c
@@ -131,7 +131,7 @@ static int mgag200_g200ew3_pipeline_init(struct mga_device *mdev)
 	if (ret)
 		return ret;
 
-	ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
+	ret = mgag200_bmc_output_init(mdev);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200se.c b/drivers/gpu/drm/mgag200/mgag200_g200se.c
index 95514dcb8c53..847f0859cf62 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200se.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200se.c
@@ -390,7 +390,7 @@ static int mgag200_g200se_pipeline_init(struct mga_device *mdev)
 	if (ret)
 		return ret;
 
-	ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
+	ret = mgag200_bmc_output_init(mdev);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200wb.c b/drivers/gpu/drm/mgag200/mgag200_g200wb.c
index 0100b4d03b89..be60237680ca 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200wb.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200wb.c
@@ -265,7 +265,7 @@ static int mgag200_g200wb_pipeline_init(struct mga_device *mdev)
 	if (ret)
 		return ret;
 
-	ret = mgag200_bmc_output_init(mdev, &mdev->output.vga.connector);
+	ret = mgag200_bmc_output_init(mdev);
 	if (ret)
 		return ret;
 
-- 
2.45.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/7] drm/probe-helper: Call connector detect functions in single helper
  2024-07-15  9:38 ` [PATCH 1/7] drm/probe-helper: Call connector detect functions in single helper Thomas Zimmermann
@ 2024-07-16  8:21   ` Maxime Ripard
  0 siblings, 0 replies; 16+ messages in thread
From: Maxime Ripard @ 2024-07-16  8:21 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: airlied, airlied, daniel, dri-devel, jfalempe, maarten.lankhorst,
	mripard, Maxime Ripard

On Mon, 15 Jul 2024 11:38:57 +0200, Thomas Zimmermann wrote:
> Move the logic to call the connector's detect helper into a single
> internal function. Reduces code dupliction.
> 
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>

Acked-by: Maxime Ripard <mripard@kernel.org>

Thanks!
Maxime

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 5/7] drm/ast: Support ASTDP and VGA at the same time
  2024-07-15  9:39 ` [PATCH 5/7] drm/ast: Support ASTDP and VGA at the same time Thomas Zimmermann
@ 2024-07-16  8:42   ` oushixiong
  0 siblings, 0 replies; 16+ messages in thread
From: oushixiong @ 2024-07-16  8:42 UTC (permalink / raw)
  To: Thomas Zimmermann, jfalempe, airlied, daniel, airlied, mripard,
	maarten.lankhorst
  Cc: dri-devel

Tested-by: Shixiong Ou <oushixiong@kylinos.cn>

在 2024/7/15 17:39, Thomas Zimmermann 写道:
> AST2600 can host VGA and DisplayPort outputs. Support both on the
> same device. As userspace can often only support a single output per
> CRTC, connectors are prioritized against each other by the probe
> helpers.
>
> Reported-by: Shixiong Ou <oushixiong@kylinos.cn>
> Closes: https://lore.kernel.org/dri-devel/20240711090102.352213-1-oushixiong1025@163.com/
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
>   drivers/gpu/drm/ast/ast_main.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c
> index 0637abb70361..d43aedaa8dd0 100644
> --- a/drivers/gpu/drm/ast/ast_main.c
> +++ b/drivers/gpu/drm/ast/ast_main.c
> @@ -115,7 +115,7 @@ static void ast_detect_tx_chip(struct ast_device *ast, bool need_post)
>   	} else if (IS_AST_GEN7(ast)) {
>   		if (ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xD1, TX_TYPE_MASK) ==
>   		    ASTDP_DPMCU_TX) {
> -			ast->tx_chip_types = AST_TX_ASTDP_BIT;
> +			ast->tx_chip_types |= AST_TX_ASTDP_BIT;
>   			ast_dp_launch(&ast->base);
>   		}
>   	}

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/7] drm/probe-helper: Optionally report single connected output per CRTC
  2024-07-15  9:38 ` [PATCH 2/7] drm/probe-helper: Optionally report single connected output per CRTC Thomas Zimmermann
@ 2024-07-16  9:01   ` Maxime Ripard
  2024-07-16 10:47     ` Thomas Zimmermann
  2024-07-16  9:46   ` Daniel Vetter
  1 sibling, 1 reply; 16+ messages in thread
From: Maxime Ripard @ 2024-07-16  9:01 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: jfalempe, airlied, daniel, airlied, maarten.lankhorst, dri-devel

[-- Attachment #1: Type: text/plain, Size: 2627 bytes --]

Hi,

On Mon, Jul 15, 2024 at 11:38:58AM GMT, Thomas Zimmermann wrote:
> For CRTCs with multiple outputs (i.e., encoders plus connectors),
> only report at most a single connected output to userspace. Make
> this configurable via CONFIG_DRM_REPORT_SINGLE_CONNECTED_CRTC_OUTPUT.
> 
> Having multiple connected outputs on the same CRTC complicates
> display-mode and format selection, so most userspace does not
> support this. This is mostly not a problem in practice, as modern
> display hardware provides a separate CRTC for each output.

Do they?

At least the RaspberryPi has multiple connectors on a single CRTC, and
for multiple CRTCs.

My understanding is that it's definitely expected, and any decent
user-space should expect it.

Did you have any bug with this?

And if it was the case, we wouldn't support cloning at all. I couldn't
really find how cloning works exactly, but my understanding was that
it's the difference between drm_encoder.possible_crtcs and
possible_clones: possible_crtcs lists the CRTCs it can be connected to,
and possible_clones the other encoders that can run with in parallel.

> On old hardware or hardware with BMCs, a single CRTC often drives
> multiple displays. Only reporting one of them as connected makes
> the hardware compatible with common userspace.
> 
> Add the field prioritized_connectors to struct drm_connector. The
> bitmask signals which other connectors have priority. Also provide
> the helper drm_probe_helper_prioritize_connectors() that sets
> default priorities for a given set of connectors. Calling the
> helper should be enough to set up the functionality for most drivers.
> 
> With the prioritization bits in place, update connector-status
> detection to test against prioritized conenctors. So when the probe
> helpers detect a connector as connected, test against the prioritized
> connectors. If any is also connected, set the connector status to
> disconnected.
> 
> Please note that this functionality is a workaround for limitations
> in userspace. If your compositor supports multiple outputs per CRTC,
> CONFIG_DRM_REPORT_SINGLE_CONNECTED_CRTC_OUTPUT should be disabled.
> 
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>

The whole "is it actually needed" discussion aside, I'm not sure it's a
good idea to use a config option for that. Chances are distros will
either enable it or disable it depending on what they/their customers
workload will typically look like, and it won't make the kernel or
compositor's job any easier.

Could we use a client capability for that maybe?

Maxime

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/7] drm/probe-helper: Optionally report single connected output per CRTC
  2024-07-15  9:38 ` [PATCH 2/7] drm/probe-helper: Optionally report single connected output per CRTC Thomas Zimmermann
  2024-07-16  9:01   ` Maxime Ripard
@ 2024-07-16  9:46   ` Daniel Vetter
  2024-07-16 10:37     ` Thomas Zimmermann
  1 sibling, 1 reply; 16+ messages in thread
From: Daniel Vetter @ 2024-07-16  9:46 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: jfalempe, airlied, daniel, airlied, mripard, maarten.lankhorst,
	dri-devel

On Mon, Jul 15, 2024 at 11:38:58AM +0200, Thomas Zimmermann wrote:
> For CRTCs with multiple outputs (i.e., encoders plus connectors),
> only report at most a single connected output to userspace. Make
> this configurable via CONFIG_DRM_REPORT_SINGLE_CONNECTED_CRTC_OUTPUT.
> 
> Having multiple connected outputs on the same CRTC complicates
> display-mode and format selection, so most userspace does not
> support this. This is mostly not a problem in practice, as modern
> display hardware provides a separate CRTC for each output. On
> old hardware or hardware with BMCs, a single CRTC often drives
> multiple displays. Only reporting one of them as connected makes
> the hardware compatible with common userspace.
> 
> Add the field prioritized_connectors to struct drm_connector. The
> bitmask signals which other connectors have priority. Also provide
> the helper drm_probe_helper_prioritize_connectors() that sets
> default priorities for a given set of connectors. Calling the
> helper should be enough to set up the functionality for most drivers.
> 
> With the prioritization bits in place, update connector-status
> detection to test against prioritized conenctors. So when the probe
> helpers detect a connector as connected, test against the prioritized
> connectors. If any is also connected, set the connector status to
> disconnected.
> 
> Please note that this functionality is a workaround for limitations
> in userspace. If your compositor supports multiple outputs per CRTC,
> CONFIG_DRM_REPORT_SINGLE_CONNECTED_CRTC_OUTPUT should be disabled.
> 
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
>  drivers/gpu/drm/Kconfig            |  15 +++++
>  drivers/gpu/drm/drm_probe_helper.c | 104 +++++++++++++++++++++++++++++
>  include/drm/drm_connector.h        |   2 +
>  include/drm/drm_probe_helper.h     |   2 +
>  4 files changed, 123 insertions(+)
> 
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index fd0749c0c630..d1afdbd2d93b 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -105,6 +105,21 @@ config DRM_KMS_HELPER
>  	help
>  	  CRTC helpers for KMS drivers.
>  
> +config DRM_REPORT_SINGLE_CONNECTED_CRTC_OUTPUT
> +       bool "Report only a single connected output per CRTC"
> +       depends on DRM
> +       default n
> +       help
> +         CRTCs can support multiple encoders and connectors for output.
> +         More than one pair can be connected to a display at a time. Most
> +         userspace only supports at most one connected output per CRTC at a
> +	 time. Enable this option to let DRM report at most one connected
> +	 output per CRTC. This is mostly relevant for low-end and old
> +	 hardware. Most modern graphics hardware supports a separate CRTC
> +	 per output and won't be affected by this setting.
> +
> +         If in doubt, say "Y".

Uh I think this is way too much, because this defacto makes this uapi for
all drivers, forever.

The reason we added the hacks for the bmc connectors was the old "no
regressions" rule: Adding the BMC connectors broke the setup for existing
users, we can't have that, hence why the hack was needed. For any new
driver, or for new platforms, we don't have this regression problem.

So I think the better way to lift this code from ast/mga is if we a lot
more focused workaround:

- Add a new probe helper for subordinate connectors, they will report
  disconnected if any other connector is connected.

- Put a really big warning onto that function that it should only be used
  as a workaround for the regression case, not anywhere else.

- Ideally drivers also don't use that for any new chips where the "no
  regression" rule doesn't apply.

- I wouldn't bother with the Kconfig, because if we make it a global
  option we cannot ever change it anyway. The only way to phase this out
  is by never applying this hack to new hardware support.

I think it would be also good to link to the specific userspace that falls
over, and how it falls over. At least hunting around in git history for
ast/mga200 didn't reveal anything.

Cheers, Sima
> +
>  config DRM_PANIC
>  	bool "Display a user-friendly message when a kernel panic occurs"
>  	depends on DRM && !(FRAMEBUFFER_CONSOLE && VT_CONSOLE)
> diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
> index f14301abf53f..fc0652635148 100644
> --- a/drivers/gpu/drm/drm_probe_helper.c
> +++ b/drivers/gpu/drm/drm_probe_helper.c
> @@ -352,6 +352,74 @@ static int detect_connector_status(struct drm_connector *connector,
>  	return connector_status_connected;
>  }
>  
> +static int reported_connector_status(struct drm_connector *connector, int detected_status,
> +				     struct drm_modeset_acquire_ctx *ctx, bool force)
> +{
> +#if defined(CONFIG_DRM_REPORT_SINGLE_CONNECTED_CRTC_OUTPUT)
> +	struct drm_connector *prio_connector = connector;
> +	struct drm_device *dev = connector->dev;
> +	struct drm_connector_list_iter iter;
> +	struct drm_connector *pos;
> +	u32 connector_mask;
> +	int ret = 0;
> +
> +	if (!connector->prioritized_connectors)
> +		return detected_status;
> +
> +	if (detected_status != connector_status_connected)
> +		return detected_status;
> +
> +	connector_mask = drm_connector_mask(connector);
> +
> +	/*
> +	 * Find the connector with status 'connected' and a higher
> +	 * priority.
> +	 */
> +	drm_connector_list_iter_begin(dev, &iter);
> +	drm_for_each_connector_iter(pos, &iter) {
> +		if (!(drm_connector_mask(pos) & connector->prioritized_connectors))
> +			continue;
> +
> +		/*
> +		 * Warn if connector has priority over itself.
> +		 */
> +		if (drm_WARN_ON_ONCE(dev, pos == connector))
> +			continue;
> +
> +		/*
> +		 * Warn if both connectors have priority over each other. Pick the
> +		 * one with the lower index.
> +		 */
> +		if (drm_WARN_ON_ONCE(dev, pos->prioritized_connectors & connector_mask)) {
> +			if (pos->index > connector->index)
> +				continue;
> +		}
> +
> +		ret = detect_connector_status(pos, ctx, force);
> +		if (ret < 0)
> +			break;
> +		if (ret == connector_status_disconnected)
> +			continue;
> +
> +		prio_connector = pos;
> +		break;
> +	}
> +	drm_connector_list_iter_end(&iter);
> +
> +	if (ret < 0)
> +		return ret;
> +
> +	/*
> +	 * We've found another connected connector. Report our connector
> +	 * as 'disconnected'.
> +	 */
> +	if (prio_connector != connector)
> +		detected_status = connector_status_disconnected;
> +#endif
> +
> +	return detected_status;
> +}
> +
>  static enum drm_connector_status
>  drm_helper_probe_detect_ctx(struct drm_connector *connector, bool force)
>  {
> @@ -373,6 +441,12 @@ drm_helper_probe_detect_ctx(struct drm_connector *connector, bool force)
>  	if (WARN_ON(ret < 0))
>  		ret = connector_status_unknown;
>  
> +	ret = reported_connector_status(connector, ret, &ctx, force);
> +	if (ret == -EDEADLK) {
> +		drm_modeset_backoff(&ctx);
> +		goto retry;
> +	}
> +
>  	if (ret != connector->status)
>  		connector->epoch_counter += 1;
>  
> @@ -408,6 +482,7 @@ drm_helper_probe_detect(struct drm_connector *connector,
>  		return ret;
>  
>  	ret = detect_connector_status(connector, ctx, force);
> +	ret = reported_connector_status(connector, ret, ctx, force);
>  
>  	if (ret != connector->status)
>  		connector->epoch_counter += 1;
> @@ -416,6 +491,35 @@ drm_helper_probe_detect(struct drm_connector *connector,
>  }
>  EXPORT_SYMBOL(drm_helper_probe_detect);
>  
> +/**
> + * drm_probe_helper_prioritize_connectors - Set connector priorities
> + * @dev: the DRM device with connectors
> + * @connector_mask: Bitmask connector indices
> + *
> + * drm_probe_helper_prioritize_connectors() prioritizes all connectors
> + * specified in @connector_mask. All given connectors are assumed to
> + * interfere with each other. Connectors with a lower index have priority
> + * over connectors with a higher index.
> + */
> +void drm_probe_helper_prioritize_connectors(struct drm_device *dev, u32 connector_mask)
> +{
> +	struct drm_connector_list_iter iter;
> +	struct drm_connector *connector;
> +	u32 prioritized_connectors = 0;
> +
> +	drm_connector_list_iter_begin(dev, &iter);
> +	drm_for_each_connector_iter(connector, &iter) {
> +		u32 mask = drm_connector_mask(connector);
> +
> +		if (!(mask & connector_mask))
> +			continue;
> +		connector->prioritized_connectors = prioritized_connectors;
> +		prioritized_connectors |= mask;
> +	}
> +	drm_connector_list_iter_end(&iter);
> +}
> +EXPORT_SYMBOL(drm_probe_helper_prioritize_connectors);
> +
>  static int drm_helper_probe_get_modes(struct drm_connector *connector)
>  {
>  	const struct drm_connector_helper_funcs *connector_funcs =
> diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> index 5ad735253413..e3039478e928 100644
> --- a/include/drm/drm_connector.h
> +++ b/include/drm/drm_connector.h
> @@ -1985,6 +1985,8 @@ struct drm_connector {
>  	/** @epoch_counter: used to detect any other changes in connector, besides status */
>  	u64 epoch_counter;
>  
> +	u32 prioritized_connectors;
> +
>  	/**
>  	 * @possible_encoders: Bit mask of encoders that can drive this
>  	 * connector, drm_encoder_index() determines the index into the bitfield
> diff --git a/include/drm/drm_probe_helper.h b/include/drm/drm_probe_helper.h
> index d6ce7b218b77..05e23485550d 100644
> --- a/include/drm/drm_probe_helper.h
> +++ b/include/drm/drm_probe_helper.h
> @@ -17,6 +17,8 @@ int drm_helper_probe_detect(struct drm_connector *connector,
>  			    struct drm_modeset_acquire_ctx *ctx,
>  			    bool force);
>  
> +void drm_probe_helper_prioritize_connectors(struct drm_device *dev, u32 connector_mask);
> +
>  int drmm_kms_helper_poll_init(struct drm_device *dev);
>  void drm_kms_helper_poll_init(struct drm_device *dev);
>  void drm_kms_helper_poll_fini(struct drm_device *dev);
> -- 
> 2.45.2
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/7] drm/probe-helper: Optionally report single connected output per CRTC
  2024-07-16  9:46   ` Daniel Vetter
@ 2024-07-16 10:37     ` Thomas Zimmermann
  0 siblings, 0 replies; 16+ messages in thread
From: Thomas Zimmermann @ 2024-07-16 10:37 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: jfalempe, airlied, daniel, airlied, mripard, maarten.lankhorst,
	dri-devel

Hi

Am 16.07.24 um 11:46 schrieb Daniel Vetter:
> On Mon, Jul 15, 2024 at 11:38:58AM +0200, Thomas Zimmermann wrote:
>> For CRTCs with multiple outputs (i.e., encoders plus connectors),
>> only report at most a single connected output to userspace. Make
>> this configurable via CONFIG_DRM_REPORT_SINGLE_CONNECTED_CRTC_OUTPUT.
>>
>> Having multiple connected outputs on the same CRTC complicates
>> display-mode and format selection, so most userspace does not
>> support this. This is mostly not a problem in practice, as modern
>> display hardware provides a separate CRTC for each output. On
>> old hardware or hardware with BMCs, a single CRTC often drives
>> multiple displays. Only reporting one of them as connected makes
>> the hardware compatible with common userspace.
>>
>> Add the field prioritized_connectors to struct drm_connector. The
>> bitmask signals which other connectors have priority. Also provide
>> the helper drm_probe_helper_prioritize_connectors() that sets
>> default priorities for a given set of connectors. Calling the
>> helper should be enough to set up the functionality for most drivers.
>>
>> With the prioritization bits in place, update connector-status
>> detection to test against prioritized conenctors. So when the probe
>> helpers detect a connector as connected, test against the prioritized
>> connectors. If any is also connected, set the connector status to
>> disconnected.
>>
>> Please note that this functionality is a workaround for limitations
>> in userspace. If your compositor supports multiple outputs per CRTC,
>> CONFIG_DRM_REPORT_SINGLE_CONNECTED_CRTC_OUTPUT should be disabled.
>>
>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>> ---
>>   drivers/gpu/drm/Kconfig            |  15 +++++
>>   drivers/gpu/drm/drm_probe_helper.c | 104 +++++++++++++++++++++++++++++
>>   include/drm/drm_connector.h        |   2 +
>>   include/drm/drm_probe_helper.h     |   2 +
>>   4 files changed, 123 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
>> index fd0749c0c630..d1afdbd2d93b 100644
>> --- a/drivers/gpu/drm/Kconfig
>> +++ b/drivers/gpu/drm/Kconfig
>> @@ -105,6 +105,21 @@ config DRM_KMS_HELPER
>>   	help
>>   	  CRTC helpers for KMS drivers.
>>   
>> +config DRM_REPORT_SINGLE_CONNECTED_CRTC_OUTPUT
>> +       bool "Report only a single connected output per CRTC"
>> +       depends on DRM
>> +       default n
>> +       help
>> +         CRTCs can support multiple encoders and connectors for output.
>> +         More than one pair can be connected to a display at a time. Most
>> +         userspace only supports at most one connected output per CRTC at a
>> +	 time. Enable this option to let DRM report at most one connected
>> +	 output per CRTC. This is mostly relevant for low-end and old
>> +	 hardware. Most modern graphics hardware supports a separate CRTC
>> +	 per output and won't be affected by this setting.
>> +
>> +         If in doubt, say "Y".
> Uh I think this is way too much, because this defacto makes this uapi for
> all drivers, forever.
>
> The reason we added the hacks for the bmc connectors was the old "no
> regressions" rule: Adding the BMC connectors broke the setup for existing
> users, we can't have that, hence why the hack was needed. For any new
> driver, or for new platforms, we don't have this regression problem.

It's a problem with userspace, not with drivers. The ast and mgag200 
drivers would be fixed easily.

Wrt UAPI, drivers have to opt-in by setting the prioritized_connectors 
bitmask. Anything but ast and mgag200 will not be affected in any case. 
And for ast/mgag200 there's also no change from the current behavior.

>
> So I think the better way to lift this code from ast/mga is if we a lot
> more focused workaround:
>
> - Add a new probe helper for subordinate connectors, they will report
>    disconnected if any other connector is connected.

There are no subordinate connectors. They are all equal. The current 
patch does what you suggest, but in a generic fashion. I'd otherwise 
have to introduce more abstraction to each affected driver to 
differentiate between the reported status and the real status.

>
> - Put a really big warning onto that function that it should only be used
>    as a workaround for the regression case, not anywhere else.

Isn't that what the patch already does in some way?

>
> - Ideally drivers also don't use that for any new chips where the "no
>    regression" rule doesn't apply.
>
> - I wouldn't bother with the Kconfig, because if we make it a global
>    option we cannot ever change it anyway. The only way to phase this out
>    is by never applying this hack to new hardware support.

I liked Maxime's idea of providing a client cap for userspace that is 
not affected.

I don't think that current userspace treats ast and mgag200 any 
different from the other drivers. It's just that userspace doesn't 
support these drivers' hardware layout. If we add a new driver for new 
hardware with similar limitations, it would also be affected. I think 
that userspace would end up in a whack-a-mole situation if they start 
treating such hardware specifically.

The real fix here is userspace supporting (or at least actively 
ignoring) multiple connected outputs per CRTC.

>
> I think it would be also good to link to the specific userspace that falls
> over, and how it falls over. At least hunting around in git history for
> ast/mga200 didn't reveal anything.

AFAIU it's most of current userspace. At least Gnome, but also KDE and 
Weston.

Best regards
Thomas

>
> Cheers, Sima
>> +
>>   config DRM_PANIC
>>   	bool "Display a user-friendly message when a kernel panic occurs"
>>   	depends on DRM && !(FRAMEBUFFER_CONSOLE && VT_CONSOLE)
>> diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
>> index f14301abf53f..fc0652635148 100644
>> --- a/drivers/gpu/drm/drm_probe_helper.c
>> +++ b/drivers/gpu/drm/drm_probe_helper.c
>> @@ -352,6 +352,74 @@ static int detect_connector_status(struct drm_connector *connector,
>>   	return connector_status_connected;
>>   }
>>   
>> +static int reported_connector_status(struct drm_connector *connector, int detected_status,
>> +				     struct drm_modeset_acquire_ctx *ctx, bool force)
>> +{
>> +#if defined(CONFIG_DRM_REPORT_SINGLE_CONNECTED_CRTC_OUTPUT)
>> +	struct drm_connector *prio_connector = connector;
>> +	struct drm_device *dev = connector->dev;
>> +	struct drm_connector_list_iter iter;
>> +	struct drm_connector *pos;
>> +	u32 connector_mask;
>> +	int ret = 0;
>> +
>> +	if (!connector->prioritized_connectors)
>> +		return detected_status;
>> +
>> +	if (detected_status != connector_status_connected)
>> +		return detected_status;
>> +
>> +	connector_mask = drm_connector_mask(connector);
>> +
>> +	/*
>> +	 * Find the connector with status 'connected' and a higher
>> +	 * priority.
>> +	 */
>> +	drm_connector_list_iter_begin(dev, &iter);
>> +	drm_for_each_connector_iter(pos, &iter) {
>> +		if (!(drm_connector_mask(pos) & connector->prioritized_connectors))
>> +			continue;
>> +
>> +		/*
>> +		 * Warn if connector has priority over itself.
>> +		 */
>> +		if (drm_WARN_ON_ONCE(dev, pos == connector))
>> +			continue;
>> +
>> +		/*
>> +		 * Warn if both connectors have priority over each other. Pick the
>> +		 * one with the lower index.
>> +		 */
>> +		if (drm_WARN_ON_ONCE(dev, pos->prioritized_connectors & connector_mask)) {
>> +			if (pos->index > connector->index)
>> +				continue;
>> +		}
>> +
>> +		ret = detect_connector_status(pos, ctx, force);
>> +		if (ret < 0)
>> +			break;
>> +		if (ret == connector_status_disconnected)
>> +			continue;
>> +
>> +		prio_connector = pos;
>> +		break;
>> +	}
>> +	drm_connector_list_iter_end(&iter);
>> +
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	/*
>> +	 * We've found another connected connector. Report our connector
>> +	 * as 'disconnected'.
>> +	 */
>> +	if (prio_connector != connector)
>> +		detected_status = connector_status_disconnected;
>> +#endif
>> +
>> +	return detected_status;
>> +}
>> +
>>   static enum drm_connector_status
>>   drm_helper_probe_detect_ctx(struct drm_connector *connector, bool force)
>>   {
>> @@ -373,6 +441,12 @@ drm_helper_probe_detect_ctx(struct drm_connector *connector, bool force)
>>   	if (WARN_ON(ret < 0))
>>   		ret = connector_status_unknown;
>>   
>> +	ret = reported_connector_status(connector, ret, &ctx, force);
>> +	if (ret == -EDEADLK) {
>> +		drm_modeset_backoff(&ctx);
>> +		goto retry;
>> +	}
>> +
>>   	if (ret != connector->status)
>>   		connector->epoch_counter += 1;
>>   
>> @@ -408,6 +482,7 @@ drm_helper_probe_detect(struct drm_connector *connector,
>>   		return ret;
>>   
>>   	ret = detect_connector_status(connector, ctx, force);
>> +	ret = reported_connector_status(connector, ret, ctx, force);
>>   
>>   	if (ret != connector->status)
>>   		connector->epoch_counter += 1;
>> @@ -416,6 +491,35 @@ drm_helper_probe_detect(struct drm_connector *connector,
>>   }
>>   EXPORT_SYMBOL(drm_helper_probe_detect);
>>   
>> +/**
>> + * drm_probe_helper_prioritize_connectors - Set connector priorities
>> + * @dev: the DRM device with connectors
>> + * @connector_mask: Bitmask connector indices
>> + *
>> + * drm_probe_helper_prioritize_connectors() prioritizes all connectors
>> + * specified in @connector_mask. All given connectors are assumed to
>> + * interfere with each other. Connectors with a lower index have priority
>> + * over connectors with a higher index.
>> + */
>> +void drm_probe_helper_prioritize_connectors(struct drm_device *dev, u32 connector_mask)
>> +{
>> +	struct drm_connector_list_iter iter;
>> +	struct drm_connector *connector;
>> +	u32 prioritized_connectors = 0;
>> +
>> +	drm_connector_list_iter_begin(dev, &iter);
>> +	drm_for_each_connector_iter(connector, &iter) {
>> +		u32 mask = drm_connector_mask(connector);
>> +
>> +		if (!(mask & connector_mask))
>> +			continue;
>> +		connector->prioritized_connectors = prioritized_connectors;
>> +		prioritized_connectors |= mask;
>> +	}
>> +	drm_connector_list_iter_end(&iter);
>> +}
>> +EXPORT_SYMBOL(drm_probe_helper_prioritize_connectors);
>> +
>>   static int drm_helper_probe_get_modes(struct drm_connector *connector)
>>   {
>>   	const struct drm_connector_helper_funcs *connector_funcs =
>> diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
>> index 5ad735253413..e3039478e928 100644
>> --- a/include/drm/drm_connector.h
>> +++ b/include/drm/drm_connector.h
>> @@ -1985,6 +1985,8 @@ struct drm_connector {
>>   	/** @epoch_counter: used to detect any other changes in connector, besides status */
>>   	u64 epoch_counter;
>>   
>> +	u32 prioritized_connectors;
>> +
>>   	/**
>>   	 * @possible_encoders: Bit mask of encoders that can drive this
>>   	 * connector, drm_encoder_index() determines the index into the bitfield
>> diff --git a/include/drm/drm_probe_helper.h b/include/drm/drm_probe_helper.h
>> index d6ce7b218b77..05e23485550d 100644
>> --- a/include/drm/drm_probe_helper.h
>> +++ b/include/drm/drm_probe_helper.h
>> @@ -17,6 +17,8 @@ int drm_helper_probe_detect(struct drm_connector *connector,
>>   			    struct drm_modeset_acquire_ctx *ctx,
>>   			    bool force);
>>   
>> +void drm_probe_helper_prioritize_connectors(struct drm_device *dev, u32 connector_mask);
>> +
>>   int drmm_kms_helper_poll_init(struct drm_device *dev);
>>   void drm_kms_helper_poll_init(struct drm_device *dev);
>>   void drm_kms_helper_poll_fini(struct drm_device *dev);
>> -- 
>> 2.45.2
>>

-- 
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/7] drm/probe-helper: Optionally report single connected output per CRTC
  2024-07-16  9:01   ` Maxime Ripard
@ 2024-07-16 10:47     ` Thomas Zimmermann
  0 siblings, 0 replies; 16+ messages in thread
From: Thomas Zimmermann @ 2024-07-16 10:47 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: jfalempe, airlied, daniel, airlied, maarten.lankhorst, dri-devel

Hi

Am 16.07.24 um 11:01 schrieb Maxime Ripard:
> Hi,
>
> On Mon, Jul 15, 2024 at 11:38:58AM GMT, Thomas Zimmermann wrote:
>> For CRTCs with multiple outputs (i.e., encoders plus connectors),
>> only report at most a single connected output to userspace. Make
>> this configurable via CONFIG_DRM_REPORT_SINGLE_CONNECTED_CRTC_OUTPUT.
>>
>> Having multiple connected outputs on the same CRTC complicates
>> display-mode and format selection, so most userspace does not
>> support this. This is mostly not a problem in practice, as modern
>> display hardware provides a separate CRTC for each output.
> Do they?

That was my understanding from discussions with Gnome devs. Or at least, 
it's what they officially support.

>
> At least the RaspberryPi has multiple connectors on a single CRTC, and
> for multiple CRTCs.

I think userspace wants at least one CRTC per output, but doesn't care 
about details.

>
> My understanding is that it's definitely expected, and any decent
> user-space should expect it.
>
> Did you have any bug with this?

https://gitlab.gnome.org/GNOME/mutter/-/issues/3157

There was also a lengthy discussion on IRC a few months ago IIRC.

> And if it was the case, we wouldn't support cloning at all. I couldn't
> really find how cloning works exactly, but my understanding was that
> it's the difference between drm_encoder.possible_crtcs and
> possible_clones: possible_crtcs lists the CRTCs it can be connected to,
> and possible_clones the other encoders that can run with in parallel.

I'd prefer to solve this with the possible_clones field. But it didn't 
work. Any ideas on that?

>
>> On old hardware or hardware with BMCs, a single CRTC often drives
>> multiple displays. Only reporting one of them as connected makes
>> the hardware compatible with common userspace.
>>
>> Add the field prioritized_connectors to struct drm_connector. The
>> bitmask signals which other connectors have priority. Also provide
>> the helper drm_probe_helper_prioritize_connectors() that sets
>> default priorities for a given set of connectors. Calling the
>> helper should be enough to set up the functionality for most drivers.
>>
>> With the prioritization bits in place, update connector-status
>> detection to test against prioritized conenctors. So when the probe
>> helpers detect a connector as connected, test against the prioritized
>> connectors. If any is also connected, set the connector status to
>> disconnected.
>>
>> Please note that this functionality is a workaround for limitations
>> in userspace. If your compositor supports multiple outputs per CRTC,
>> CONFIG_DRM_REPORT_SINGLE_CONNECTED_CRTC_OUTPUT should be disabled.
>>
>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> The whole "is it actually needed" discussion aside, I'm not sure it's a
> good idea to use a config option for that. Chances are distros will
> either enable it or disable it depending on what they/their customers
> workload will typically look like, and it won't make the kernel or
> compositor's job any easier.
>
> Could we use a client capability for that maybe?

I like this idea.

Best regards
Thomas

>
> Maxime

-- 
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/7] drm/probe-helpers: Work around multi-outputs-per-CRTC problem
  2024-07-15  9:38 [PATCH 0/7] drm/probe-helpers: Work around multi-outputs-per-CRTC problem Thomas Zimmermann
                   ` (6 preceding siblings ...)
  2024-07-15  9:39 ` [PATCH 7/7] drm/mgag200: Remove struct mgag200_bmc_connector Thomas Zimmermann
@ 2024-07-17 12:54 ` Thomas Zimmermann
  7 siblings, 0 replies; 16+ messages in thread
From: Thomas Zimmermann @ 2024-07-17 12:54 UTC (permalink / raw)
  To: jfalempe, airlied, daniel, airlied, mripard, maarten.lankhorst; +Cc: dri-devel

As discussed on irc, we rather improve the in-kernel DRM client's 
support for cloned outputs (for fbcon) and then remove the hacks from 
the ast and mgag200 drivers. Userspace compositors need to support 
cloned outputs to a minimum.

https://dri.freedesktop.org/~cbrill/dri-log/index.php?channel=dri-devel&date=2024-07-17

Best regards
Thomas

Am 15.07.24 um 11:38 schrieb Thomas Zimmermann:
> Old or simple hardware only supports a single CRTC with multiple
> conenctoed outputs. This breaks most userspace compositors, which
> only support a single output per CRTC. This currently happens with
> ast and mgag200 drivers. The drivers contain a work around that
> dynamically disables all but one connected output.
>
> Patches 1 and 2 push the workaround into probe helpers and make it
> configurable in the kernel config. For each connector, the driver
> needs to specify a bitmask of connectors with higher priority. If
> one of them is connected, the connector at hand is always reported
> as disconnected. Connectors without priority bitmask as not affected.
>
> Patches 3 to 5 update and simplify the ast drivers. The new workaround
> now allows to have multiple physical conenctors in ast. So patch 5
> finally allows VGA and DisplayPort on the same device.
>
> Patches 6 and 7 update mgag200.
>
> Any future driver that exposes the same problem as ast and mgag200
> can simply hook into the workaround. Hopefully userspace can be fixed
> at some point.
>
> Thomas Zimmermann (7):
>    drm/probe-helper: Call connector detect functions in single helper
>    drm/probe-helper: Optionally report single connected output per CRTC
>    drm/ast: Set connector priorities
>    drm/ast: Remove struct ast_bmc_connector
>    drm/ast: Support ASTDP and VGA at the same time
>    drm/mgag200: Set connector priorities
>    drm/mgag200: Remove struct mgag200_bmc_connector
>
>   drivers/gpu/drm/Kconfig                   |  15 +++
>   drivers/gpu/drm/ast/ast_drv.h             |  17 +--
>   drivers/gpu/drm/ast/ast_main.c            |   2 +-
>   drivers/gpu/drm/ast/ast_mode.c            |  49 ++------
>   drivers/gpu/drm/drm_probe_helper.c        | 137 +++++++++++++++++++---
>   drivers/gpu/drm/mgag200/mgag200_bmc.c     |  44 +------
>   drivers/gpu/drm/mgag200/mgag200_drv.h     |   9 +-
>   drivers/gpu/drm/mgag200/mgag200_g200eh.c  |   4 +-
>   drivers/gpu/drm/mgag200/mgag200_g200eh3.c |   4 +-
>   drivers/gpu/drm/mgag200/mgag200_g200er.c  |   4 +-
>   drivers/gpu/drm/mgag200/mgag200_g200ev.c  |   4 +-
>   drivers/gpu/drm/mgag200/mgag200_g200ew3.c |   4 +-
>   drivers/gpu/drm/mgag200/mgag200_g200se.c  |   4 +-
>   drivers/gpu/drm/mgag200/mgag200_g200wb.c  |   4 +-
>   include/drm/drm_connector.h               |   2 +
>   include/drm/drm_probe_helper.h            |   2 +
>   16 files changed, 177 insertions(+), 128 deletions(-)
>

-- 
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 1/7] drm/probe-helper: Call connector detect functions in single helper
  2024-10-11  6:43 [PATCH 0/7] drm: Add physical status and BMC support to conenctor Thomas Zimmermann
@ 2024-10-11  6:43 ` Thomas Zimmermann
  0 siblings, 0 replies; 16+ messages in thread
From: Thomas Zimmermann @ 2024-10-11  6:43 UTC (permalink / raw)
  To: maarten.lankhorst, mripard, airlied, simona, jani.nikula, airlied,
	jfalempe
  Cc: dri-devel, Thomas Zimmermann

Move the logic to call the connector's detect helper into a single
internal function. Reduces code duplication.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Acked-by: Maxime Ripard <mripard@kernel.org>
---
 drivers/gpu/drm/drm_probe_helper.c | 33 +++++++++++++++---------------
 1 file changed, 17 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index 92f21764246f..62a2e5bcb315 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -338,10 +338,23 @@ void drm_kms_helper_poll_reschedule(struct drm_device *dev)
 }
 EXPORT_SYMBOL(drm_kms_helper_poll_reschedule);
 
+static int detect_connector_status(struct drm_connector *connector,
+				   struct drm_modeset_acquire_ctx *ctx,
+				   bool force)
+{
+	const struct drm_connector_helper_funcs *funcs = connector->helper_private;
+
+	if (funcs->detect_ctx)
+		return funcs->detect_ctx(connector, ctx, force);
+	else if (connector->funcs->detect)
+		return connector->funcs->detect(connector, force);
+
+	return connector_status_connected;
+}
+
 static enum drm_connector_status
 drm_helper_probe_detect_ctx(struct drm_connector *connector, bool force)
 {
-	const struct drm_connector_helper_funcs *funcs = connector->helper_private;
 	struct drm_modeset_acquire_ctx ctx;
 	int ret;
 
@@ -349,14 +362,8 @@ drm_helper_probe_detect_ctx(struct drm_connector *connector, bool force)
 
 retry:
 	ret = drm_modeset_lock(&connector->dev->mode_config.connection_mutex, &ctx);
-	if (!ret) {
-		if (funcs->detect_ctx)
-			ret = funcs->detect_ctx(connector, &ctx, force);
-		else if (connector->funcs->detect)
-			ret = connector->funcs->detect(connector, force);
-		else
-			ret = connector_status_connected;
-	}
+	if (!ret)
+		ret = detect_connector_status(connector, &ctx, force);
 
 	if (ret == -EDEADLK) {
 		drm_modeset_backoff(&ctx);
@@ -390,7 +397,6 @@ drm_helper_probe_detect(struct drm_connector *connector,
 			struct drm_modeset_acquire_ctx *ctx,
 			bool force)
 {
-	const struct drm_connector_helper_funcs *funcs = connector->helper_private;
 	struct drm_device *dev = connector->dev;
 	int ret;
 
@@ -401,12 +407,7 @@ drm_helper_probe_detect(struct drm_connector *connector,
 	if (ret)
 		return ret;
 
-	if (funcs->detect_ctx)
-		ret = funcs->detect_ctx(connector, ctx, force);
-	else if (connector->funcs->detect)
-		ret = connector->funcs->detect(connector, force);
-	else
-		ret = connector_status_connected;
+	ret = detect_connector_status(connector, ctx, force);
 
 	if (ret != connector->status)
 		connector->epoch_counter += 1;
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2024-10-11  6:57 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-07-15  9:38 [PATCH 0/7] drm/probe-helpers: Work around multi-outputs-per-CRTC problem Thomas Zimmermann
2024-07-15  9:38 ` [PATCH 1/7] drm/probe-helper: Call connector detect functions in single helper Thomas Zimmermann
2024-07-16  8:21   ` Maxime Ripard
2024-07-15  9:38 ` [PATCH 2/7] drm/probe-helper: Optionally report single connected output per CRTC Thomas Zimmermann
2024-07-16  9:01   ` Maxime Ripard
2024-07-16 10:47     ` Thomas Zimmermann
2024-07-16  9:46   ` Daniel Vetter
2024-07-16 10:37     ` Thomas Zimmermann
2024-07-15  9:38 ` [PATCH 3/7] drm/ast: Set connector priorities Thomas Zimmermann
2024-07-15  9:39 ` [PATCH 4/7] drm/ast: Remove struct ast_bmc_connector Thomas Zimmermann
2024-07-15  9:39 ` [PATCH 5/7] drm/ast: Support ASTDP and VGA at the same time Thomas Zimmermann
2024-07-16  8:42   ` oushixiong
2024-07-15  9:39 ` [PATCH 6/7] drm/mgag200: Set connector priorities Thomas Zimmermann
2024-07-15  9:39 ` [PATCH 7/7] drm/mgag200: Remove struct mgag200_bmc_connector Thomas Zimmermann
2024-07-17 12:54 ` [PATCH 0/7] drm/probe-helpers: Work around multi-outputs-per-CRTC problem Thomas Zimmermann
  -- strict thread matches above, loose matches on Subject: below --
2024-10-11  6:43 [PATCH 0/7] drm: Add physical status and BMC support to conenctor Thomas Zimmermann
2024-10-11  6:43 ` [PATCH 1/7] drm/probe-helper: Call connector detect functions in single helper Thomas Zimmermann

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.