[PATCH v6 16/23] drm/probe-helper: Provide a TV get_modes helper

maxime at cerno.tech maxime at cerno.tech
Wed Oct 26 08:33:35 PDT 2022


Most of the TV connectors will need a similar get_modes implementation
that will, depending on the drivers' capabilities, register the 480i and
576i modes.

That implementation will also need to set the preferred flag and order
the modes based on the driver and users preferrence.

This is especially important to guarantee that a userspace stack such as
Xorg can start and pick up the preferred mode while maintaining a
working output.

Signed-off-by: Maxime Ripard <maxime at cerno.tech>

---
Changes in v6:
- New patch
---
 drivers/gpu/drm/drm_probe_helper.c | 97 ++++++++++++++++++++++++++++++++++++++
 include/drm/drm_probe_helper.h     |  1 +
 2 files changed, 98 insertions(+)

diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index 69b0b2b9cc1c..4a60575f5c66 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -1147,3 +1147,100 @@ int drm_connector_helper_get_modes(struct drm_connector *connector)
 	return count;
 }
 EXPORT_SYMBOL(drm_connector_helper_get_modes);
+
+static bool tv_mode_supported(struct drm_connector *connector,
+			      enum drm_connector_tv_mode mode)
+{
+	struct drm_device *dev = connector->dev;
+	struct drm_property *property = dev->mode_config.tv_mode_property;
+
+	unsigned int i;
+
+	for (i = 0; i < property->num_values; i++)
+		if (property->values[i] == mode)
+			return true;
+
+	return false;
+}
+
+/**
+ * drm_connector_helper_tv_get_modes - Fills the modes availables to a TV connector
+ * @connector: The connector
+ *
+ * Fills the available modes for a TV connector based on the supported
+ * TV modes, and the default mode expressed by the kernel command line.
+ *
+ * This can be used as the default TV connector helper .get_modes() hook
+ * if the driver does not need any special processing.
+ *
+ * Returns:
+ * The number of modes added to the connector.
+ */
+int drm_connector_helper_tv_get_modes(struct drm_connector *connector)
+{
+	struct drm_device *dev = connector->dev;
+	struct drm_cmdline_mode *cmdline = &connector->cmdline_mode;
+	struct drm_display_mode *tv_modes[2] = {};
+	struct drm_display_mode *mode;
+	unsigned int first_mode_idx;
+	unsigned int count = 0;
+	uint64_t default_mode;
+	int ret;
+
+	if (!dev->mode_config.tv_mode_property)
+		return 0;
+
+	if (tv_mode_supported(connector, DRM_MODE_TV_MODE_NTSC) ||
+	    tv_mode_supported(connector, DRM_MODE_TV_MODE_NTSC_443) ||
+	    tv_mode_supported(connector, DRM_MODE_TV_MODE_NTSC_J) ||
+	    tv_mode_supported(connector, DRM_MODE_TV_MODE_PAL_M)) {
+		mode = drm_mode_analog_ntsc_480i(connector->dev);
+		if (!mode)
+			return 0;
+
+		tv_modes[count++] = mode;
+	}
+
+	if (tv_mode_supported(connector, DRM_MODE_TV_MODE_PAL) ||
+	    tv_mode_supported(connector, DRM_MODE_TV_MODE_PAL_N) ||
+	    tv_mode_supported(connector, DRM_MODE_TV_MODE_SECAM)) {
+		mode = drm_mode_analog_pal_576i(connector->dev);
+		if (!mode)
+			return 0;
+
+		tv_modes[count++] = mode;
+	}
+
+	if (count == 1) {
+		mode->type |= DRM_MODE_TYPE_PREFERRED;
+		drm_mode_probed_add(connector, mode);
+		return count;
+	}
+
+	ret = drm_object_property_get_default_value(&connector->base,
+						    dev->mode_config.tv_mode_property,
+						    &default_mode);
+	if (ret)
+		return 0;
+
+	if (cmdline->tv_mode_specified)
+		default_mode = cmdline->tv_mode;
+
+	if ((default_mode == DRM_MODE_TV_MODE_NTSC) ||
+	    (default_mode == DRM_MODE_TV_MODE_NTSC_443) ||
+	    (default_mode == DRM_MODE_TV_MODE_NTSC_J) ||
+	    (default_mode == DRM_MODE_TV_MODE_PAL_M))
+		first_mode_idx = 0;
+	else
+		first_mode_idx = 1;
+
+	mode = tv_modes[first_mode_idx];
+	mode->type |= DRM_MODE_TYPE_PREFERRED;
+	drm_mode_probed_add(connector, mode);
+
+	mode = first_mode_idx ? tv_modes[0] : tv_modes[1];
+	drm_mode_probed_add(connector, mode);
+
+	return count;
+}
+EXPORT_SYMBOL(drm_connector_helper_tv_get_modes);
diff --git a/include/drm/drm_probe_helper.h b/include/drm/drm_probe_helper.h
index 5880daa14624..4977e0ab72db 100644
--- a/include/drm/drm_probe_helper.h
+++ b/include/drm/drm_probe_helper.h
@@ -35,5 +35,6 @@ int drm_connector_helper_get_modes_from_ddc(struct drm_connector *connector);
 int drm_connector_helper_get_modes_fixed(struct drm_connector *connector,
 					 const struct drm_display_mode *fixed_mode);
 int drm_connector_helper_get_modes(struct drm_connector *connector);
+int drm_connector_helper_tv_get_modes(struct drm_connector *connector);
 
 #endif

-- 
b4 0.11.0-dev-99e3a



More information about the linux-arm-kernel mailing list