[PATCH v8 02/39] drm/connector: Add caps-based HDMI connector init helper
Cristian Ciocaltea
cristian.ciocaltea at collabora.com
Thu Jul 2 07:46:15 PDT 2026
In preparation for adding HDMI 2.x source capabilities, introduce struct
drm_connector_hdmi_caps and a new drmm_connector_hdmi_init_with_caps()
helper.
The existing drmm_connector_hdmi_init() helper currently takes
individual capability arguments such as supported_formats and max_bpc.
Adding more HDMI-specific arguments to that function would not scale
well, so move those values into a dedicated capabilities structure and
implement the existing helper as a wrapper around the new caps-based
interface.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
drivers/gpu/drm/drm_connector.c | 202 +++++++++++++++++++++++++++-------------
include/drm/drm_connector.h | 55 +++++++++++
2 files changed, 193 insertions(+), 64 deletions(-)
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 8b4baed060f3..c7ce6b7bd8b0 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -542,6 +542,137 @@ int drmm_connector_init(struct drm_device *dev,
}
EXPORT_SYMBOL(drmm_connector_init);
+/**
+ * drmm_connector_hdmi_init_with_caps - Init a preallocated HDMI connector
+ * @dev: DRM device
+ * @connector: A pointer to the HDMI connector to init
+ * @vendor: HDMI Controller Vendor name
+ * @product: HDMI Controller Product name
+ * @funcs: callbacks for this connector
+ * @hdmi_funcs: HDMI-related callbacks for this connector
+ * @connector_type: user visible type of the connector
+ * @ddc: optional pointer to the associated ddc adapter
+ * @caps: optional HDMI connector capabilities
+ *
+ * Initialises a preallocated HDMI connector. Connectors can be
+ * subclassed as part of driver connector objects.
+ *
+ * Cleanup is automatically handled with a call to
+ * drm_connector_cleanup() in a DRM-managed action.
+ *
+ * The connector structure should be allocated with drmm_kzalloc().
+ *
+ * The @drm_connector_funcs.destroy hook must be NULL.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int drmm_connector_hdmi_init_with_caps(struct drm_device *dev,
+ struct drm_connector *connector,
+ const char *vendor, const char *product,
+ const struct drm_connector_funcs *funcs,
+ const struct drm_connector_hdmi_funcs *hdmi_funcs,
+ int connector_type,
+ struct i2c_adapter *ddc,
+ const struct drm_connector_hdmi_caps *caps)
+{
+ int ret;
+
+ if (!vendor || !product)
+ return -EINVAL;
+
+ if ((strlen(vendor) > DRM_CONNECTOR_HDMI_VENDOR_LEN) ||
+ (strlen(product) > DRM_CONNECTOR_HDMI_PRODUCT_LEN))
+ return -EINVAL;
+
+ if (!(connector_type == DRM_MODE_CONNECTOR_HDMIA ||
+ connector_type == DRM_MODE_CONNECTOR_HDMIB))
+ return -EINVAL;
+
+ if (!caps)
+ return -EINVAL;
+
+ if (!caps->supported_formats ||
+ !(caps->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444)))
+ return -EINVAL;
+
+ if (connector->ycbcr_420_allowed !=
+ !!(caps->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420)))
+ return -EINVAL;
+
+ if (!(caps->max_bpc == 8 || caps->max_bpc == 10 || caps->max_bpc == 12))
+ return -EINVAL;
+
+ if (!hdmi_funcs->avi.clear_infoframe ||
+ !hdmi_funcs->avi.write_infoframe ||
+ !hdmi_funcs->hdmi.clear_infoframe ||
+ !hdmi_funcs->hdmi.write_infoframe)
+ return -EINVAL;
+
+ ret = drmm_connector_init(dev, connector, funcs, connector_type, ddc);
+ if (ret)
+ return ret;
+
+ connector->hdmi.supported_formats = caps->supported_formats;
+
+ /*
+ * The supported HDMI version can be used to infer the maximum TMDS
+ * character rate allowed by the specification. Some controllers,
+ * however, may support a lower rate than that version would imply.
+ *
+ * A non-zero caps->max_tmds_char_rate lets drivers override the
+ * inferred limit with the actual controller capability. A value of
+ * zero keeps the default limit inferred from supported_hdmi_ver.
+ */
+ if (caps->supported_hdmi_ver >= HDMI_VERSION_2_0)
+ connector->hdmi.max_tmds_char_rate = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ;
+ else if (caps->supported_hdmi_ver >= HDMI_VERSION_1_3)
+ connector->hdmi.max_tmds_char_rate = HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ;
+ else if (caps->supported_hdmi_ver >= HDMI_VERSION_1_0)
+ connector->hdmi.max_tmds_char_rate = HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ;
+
+ if (caps->max_tmds_char_rate) {
+ if (caps->max_tmds_char_rate > connector->hdmi.max_tmds_char_rate)
+ return -EINVAL;
+ connector->hdmi.max_tmds_char_rate = caps->max_tmds_char_rate;
+ }
+
+ strtomem_pad(connector->hdmi.vendor, vendor, 0);
+ strtomem_pad(connector->hdmi.product, product, 0);
+
+ /*
+ * drm_connector_attach_max_bpc_property() requires the
+ * connector to have a state.
+ */
+ if (connector->funcs->atomic_create_state) {
+ struct drm_connector_state *state;
+
+ state = connector->funcs->atomic_create_state(connector);
+ if (IS_ERR(state))
+ return PTR_ERR(state);
+
+ connector->state = state;
+ } else if (connector->funcs->reset) {
+ connector->funcs->reset(connector);
+ }
+
+ drm_connector_attach_max_bpc_property(connector, 8, caps->max_bpc);
+ connector->max_bpc = caps->max_bpc;
+
+ if (caps->max_bpc > 8)
+ drm_connector_attach_hdr_output_metadata_property(connector);
+
+ ret = drm_connector_attach_color_format_property(connector,
+ caps->supported_formats);
+ if (ret)
+ return ret;
+
+ connector->hdmi.funcs = hdmi_funcs;
+
+ return 0;
+}
+EXPORT_SYMBOL(drmm_connector_hdmi_init_with_caps);
+
/**
* drmm_connector_hdmi_init - Init a preallocated HDMI connector
* @dev: DRM device
@@ -578,71 +709,14 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
unsigned long supported_formats,
unsigned int max_bpc)
{
- int ret;
+ struct drm_connector_hdmi_caps caps = {
+ .supported_formats = supported_formats,
+ .max_bpc = max_bpc,
+ };
- if (!vendor || !product)
- return -EINVAL;
-
- if ((strlen(vendor) > DRM_CONNECTOR_HDMI_VENDOR_LEN) ||
- (strlen(product) > DRM_CONNECTOR_HDMI_PRODUCT_LEN))
- return -EINVAL;
-
- if (!(connector_type == DRM_MODE_CONNECTOR_HDMIA ||
- connector_type == DRM_MODE_CONNECTOR_HDMIB))
- return -EINVAL;
-
- if (!supported_formats || !(supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444)))
- return -EINVAL;
-
- if (connector->ycbcr_420_allowed != !!(supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420)))
- return -EINVAL;
-
- if (!(max_bpc == 8 || max_bpc == 10 || max_bpc == 12))
- return -EINVAL;
-
- if (!hdmi_funcs->avi.clear_infoframe ||
- !hdmi_funcs->avi.write_infoframe ||
- !hdmi_funcs->hdmi.clear_infoframe ||
- !hdmi_funcs->hdmi.write_infoframe)
- return -EINVAL;
-
- ret = drmm_connector_init(dev, connector, funcs, connector_type, ddc);
- if (ret)
- return ret;
-
- connector->hdmi.supported_formats = supported_formats;
- strtomem_pad(connector->hdmi.vendor, vendor, 0);
- strtomem_pad(connector->hdmi.product, product, 0);
-
- /*
- * drm_connector_attach_max_bpc_property() requires the
- * connector to have a state.
- */
- if (connector->funcs->atomic_create_state) {
- struct drm_connector_state *state;
-
- state = connector->funcs->atomic_create_state(connector);
- if (IS_ERR(state))
- return PTR_ERR(state);
-
- connector->state = state;
- } else if (connector->funcs->reset) {
- connector->funcs->reset(connector);
- }
-
- drm_connector_attach_max_bpc_property(connector, 8, max_bpc);
- connector->max_bpc = max_bpc;
-
- if (max_bpc > 8)
- drm_connector_attach_hdr_output_metadata_property(connector);
-
- ret = drm_connector_attach_color_format_property(connector, supported_formats);
- if (ret)
- return ret;
-
- connector->hdmi.funcs = hdmi_funcs;
-
- return 0;
+ return drmm_connector_hdmi_init_with_caps(dev, connector, vendor,
+ product, funcs, hdmi_funcs,
+ connector_type, ddc, &caps);
}
EXPORT_SYMBOL(drmm_connector_hdmi_init);
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index af075c38f4db..961a729d0869 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -2029,6 +2029,47 @@ struct drm_connector_hdmi_audio {
int dai_port;
};
+/**
+ * struct drm_connector_hdmi_caps - HDMI capabilities structure
+ *
+ * This structure is required to initialize the connector using
+ * drmm_connector_hdmi_init_with_caps().
+ */
+struct drm_connector_hdmi_caps {
+ /**
+ * @supported_hdmi_ver:
+ *
+ * Maximum HDMI specification version supported by the controller side
+ * of this connector. This describes the controller capability only;
+ * the effective link capabilities may be further restricted by the
+ * sink, bridge, or mode validation.
+ *
+ * HDMI_VERSION_UNKNOWN means legacy/default behaviour.
+ */
+ enum hdmi_version supported_hdmi_ver;
+
+ /**
+ * @supported_formats:
+ *
+ * Bitmask of @drm_output_color_format listing supported output formats.
+ */
+ unsigned long supported_formats;
+
+ /**
+ * @max_tmds_char_rate:
+ *
+ * Maximum TMDS character rate supported by the source, in Hz.
+ * A value of 0 means the core should use the default limit implied by
+ * @supported_hdmi_ver.
+ */
+ unsigned long long max_tmds_char_rate;
+
+ /**
+ * @max_bpc: Maximum bits per char the HDMI connector supports.
+ */
+ unsigned int max_bpc;
+};
+
/*
* struct drm_connector_hdmi - DRM Connector HDMI-related structure
*/
@@ -2051,6 +2092,12 @@ struct drm_connector_hdmi {
*/
unsigned long supported_formats;
+ /**
+ * @max_tmds_char_rate: Maximum TMDS character rate, in Hz,
+ * supported by the controller.
+ */
+ unsigned long long max_tmds_char_rate;
+
/**
* @funcs: HDMI connector Control Functions
*/
@@ -2555,6 +2602,14 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
struct i2c_adapter *ddc,
unsigned long supported_formats,
unsigned int max_bpc);
+int drmm_connector_hdmi_init_with_caps(struct drm_device *dev,
+ struct drm_connector *connector,
+ const char *vendor, const char *product,
+ const struct drm_connector_funcs *funcs,
+ const struct drm_connector_hdmi_funcs *hdmi_funcs,
+ int connector_type,
+ struct i2c_adapter *ddc,
+ const struct drm_connector_hdmi_caps *caps);
void drm_connector_attach_edid_property(struct drm_connector *connector);
int drm_connector_register(struct drm_connector *connector);
int drm_connector_dynamic_register(struct drm_connector *connector);
--
2.54.0
More information about the linux-arm-kernel
mailing list