[PATCH RFC v3 06/37] drm/connector: hdmi: Add support for output format

From: Maxime Ripard
Date: Tue Oct 31 2023 - 12:49:18 EST


Just like BPC, we'll add support for automatic selection of the output
format for HDMI connectors.

Let's add the needed defaults and fields for now.

Signed-off-by: Maxime Ripard <mripard@xxxxxxxxxx>
---
drivers/gpu/drm/drm_atomic.c | 2 ++
drivers/gpu/drm/drm_atomic_state_helper.c | 4 +++-
drivers/gpu/drm/drm_connector.c | 28 ++++++++++++++++++++++++++++
include/drm/drm_connector.h | 16 ++++++++++++++++
4 files changed, 49 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 51aac1b2aaaf..0ebe1142dcfe 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -1148,6 +1148,8 @@ static void drm_atomic_connector_print_state(struct drm_printer *p,
drm_hdmi_connector_get_broadcast_rgb_name(state->hdmi.broadcast_rgb));
drm_printf(p, "\tis_full_range=%c\n", state->hdmi.is_full_range ? 'y' : 'n');
drm_printf(p, "\toutput_bpc=%u\n", state->hdmi.output_bpc);
+ drm_printf(p, "\toutput_format=%s\n",
+ drm_hdmi_connector_get_output_format_name(state->hdmi.output_format));
}

if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
index 406ba358aa14..37262dd002c8 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -575,6 +575,7 @@ void __drm_atomic_helper_connector_hdmi_reset(struct drm_connector *connector,
new_state->max_bpc = max_bpc;
new_state->max_requested_bpc = max_bpc;
new_state->hdmi.output_bpc = max_bpc;
+ new_state->hdmi.output_format = HDMI_COLORSPACE_RGB;
new_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_AUTO;
}
EXPORT_SYMBOL(__drm_atomic_helper_connector_hdmi_reset);
@@ -692,7 +693,8 @@ int drm_atomic_helper_connector_hdmi_check(struct drm_connector *connector,
new_state->hdmi.is_full_range = hdmi_is_full_range(connector, new_state);

if (old_state->hdmi.broadcast_rgb != new_state->hdmi.broadcast_rgb ||
- old_state->hdmi.output_bpc != new_state->hdmi.output_bpc) {
+ old_state->hdmi.output_bpc != new_state->hdmi.output_bpc ||
+ old_state->hdmi.output_format != new_state->hdmi.output_format) {
struct drm_crtc *crtc = new_state->crtc;
struct drm_crtc_state *crtc_state;

diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 508d1c667732..9037e1b1b383 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -459,6 +459,7 @@ EXPORT_SYMBOL(drmm_connector_init);
* @funcs: callbacks for this connector
* @connector_type: user visible type of the connector
* @ddc: optional pointer to the associated ddc adapter
+ * @supported_formats: Bitmask of @hdmi_colorspace listing supported output formats
* @max_bpc: Maximum bits per char the HDMI connector supports
*
* Initialises a preallocated HDMI connector. Connectors can be
@@ -477,6 +478,7 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
const struct drm_connector_funcs *funcs,
int connector_type,
struct i2c_adapter *ddc,
+ unsigned long supported_formats,
unsigned int max_bpc)
{
int ret;
@@ -489,6 +491,8 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
if (ret)
return ret;

+ connector->hdmi.supported_formats = supported_formats;
+
if (max_bpc) {
if (!(max_bpc == 8 || max_bpc == 10 || max_bpc == 12))
return -EINVAL;
@@ -1215,6 +1219,30 @@ drm_hdmi_connector_get_broadcast_rgb_name(enum drm_hdmi_broadcast_rgb broadcast_
}
EXPORT_SYMBOL(drm_hdmi_connector_get_broadcast_rgb_name);

+static const char * const output_format_str[] = {
+ [HDMI_COLORSPACE_RGB] = "RGB",
+ [HDMI_COLORSPACE_YUV420] = "YUV 4:2:0",
+ [HDMI_COLORSPACE_YUV422] = "YUV 4:2:2",
+ [HDMI_COLORSPACE_YUV444] = "YUV 4:4:4",
+};
+
+/*
+ * drm_hdmi_connector_get_output_format_name() - Return a string for HDMI connector output format
+ * @fmt: Output format to compute name of
+ *
+ * Returns: the name of the output format, or NULL if the type is not
+ * valid.
+ */
+const char *
+drm_hdmi_connector_get_output_format_name(enum hdmi_colorspace fmt)
+{
+ if (fmt >= ARRAY_SIZE(output_format_str))
+ return NULL;
+
+ return output_format_str[fmt];
+}
+EXPORT_SYMBOL(drm_hdmi_connector_get_output_format_name);
+
/**
* DOC: standard connector properties
*
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 2d664b6ac0a6..32f0b3b7383e 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -391,6 +391,8 @@ enum drm_hdmi_broadcast_rgb {

const char *
drm_hdmi_connector_get_broadcast_rgb_name(enum drm_hdmi_broadcast_rgb broadcast_rgb);
+const char *
+drm_hdmi_connector_get_output_format_name(enum hdmi_colorspace fmt);

/**
* struct drm_monitor_range_info - Panel's Monitor range in EDID for
@@ -1064,6 +1066,11 @@ struct drm_connector_state {
* @output_bpc: Bits per color channel to output.
*/
unsigned int output_bpc;
+
+ /**
+ * @output_format: Pixel format to output in.
+ */
+ enum hdmi_colorspace output_format;
} hdmi;
};

@@ -1930,6 +1937,14 @@ struct drm_connector {

/** @hdr_sink_metadata: HDR Metadata Information read from sink */
struct hdr_sink_metadata hdr_sink_metadata;
+
+ struct {
+ /**
+ * @supported_formats: Bitmask of @hdmi_colorspace
+ * supported by the controller.
+ */
+ unsigned long supported_formats;
+ } hdmi;
};

#define obj_to_connector(x) container_of(x, struct drm_connector, base)
@@ -1953,6 +1968,7 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
const struct drm_connector_funcs *funcs,
int connector_type,
struct i2c_adapter *ddc,
+ unsigned long supported_formats,
unsigned int max_bpc);
void drm_connector_attach_edid_property(struct drm_connector *connector);
int drm_connector_register(struct drm_connector *connector);

--
2.41.0