* [PATCH v11 01/22] drm/amd/display: Remove unnecessary SIGNAL_TYPE_HDMI_TYPE_A check
2026-03-24 16:01 [PATCH v11 00/22] Add new general DRM property "color format" Nicolas Frattaroli
@ 2026-03-24 16:01 ` Nicolas Frattaroli
2026-03-24 16:01 ` [PATCH v11 02/22] drm/display: hdmi-state-helper: Use default case for unsupported formats Nicolas Frattaroli
` (20 subsequent siblings)
21 siblings, 0 replies; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-24 16:01 UTC (permalink / raw)
To: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc,
Nicolas Frattaroli, Werner Sembach, Andri Yngvason
From: Werner Sembach <wse@tuxedocomputers.com>
Remove unnecessary SIGNAL_TYPE_HDMI_TYPE_A check that was performed in the
drm_mode_is_420_only() case, but not in the drm_mode_is_420_also() &&
force_yuv420_output case.
Without further knowledge if YCbCr 4:2:0 is supported outside of HDMI,
there is no reason to use RGB when the display
reports drm_mode_is_420_only() even on a non HDMI connection.
This patch also moves both checks in the same if-case. This eliminates an
extra else-if-case.
Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
Signed-off-by: Andri Yngvason <andri@yngvason.is>
Tested-by: Andri Yngvason <andri@yngvason.is>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 646fbdd5688b..86a64e98e8a1 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6713,12 +6713,9 @@ static void fill_stream_properties_from_drm_display_mode(
timing_out->v_border_top = 0;
timing_out->v_border_bottom = 0;
/* TODO: un-hardcode */
- if (drm_mode_is_420_only(info, mode_in)
- && stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
- timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
- else if (drm_mode_is_420_also(info, mode_in)
- && aconnector
- && aconnector->force_yuv420_output)
+ if (drm_mode_is_420_only(info, mode_in) ||
+ (aconnector && aconnector->force_yuv420_output &&
+ drm_mode_is_420_also(info, mode_in)))
timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
else if ((connector->display_info.color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422))
&& aconnector
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread* [PATCH v11 02/22] drm/display: hdmi-state-helper: Use default case for unsupported formats
2026-03-24 16:01 [PATCH v11 00/22] Add new general DRM property "color format" Nicolas Frattaroli
2026-03-24 16:01 ` [PATCH v11 01/22] drm/amd/display: Remove unnecessary SIGNAL_TYPE_HDMI_TYPE_A check Nicolas Frattaroli
@ 2026-03-24 16:01 ` Nicolas Frattaroli
2026-03-24 16:01 ` [PATCH v11 03/22] drm: Add new general DRM property "color format" Nicolas Frattaroli
` (19 subsequent siblings)
21 siblings, 0 replies; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-24 16:01 UTC (permalink / raw)
To: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc,
Nicolas Frattaroli, Cristian Ciocaltea
Switch statements that do not handle all possible values of an
enumeration will generate a warning during compilation. In preparation
for adding a COUNT value to the end of the enum, this needs to be dealt
with.
Add a default case to sink_supports_format_bpc's DRM_OUTPUT_COLOR_FORMAT
switch statement, and move the log-and-return unknown pixel format
handling into it.
No functional change.
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index 9f3b696aceeb..a0d88701d236 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -541,10 +541,11 @@ sink_supports_format_bpc(const struct drm_connector *connector,
drm_dbg_kms(dev, "YUV444 format supported in that configuration.\n");
return true;
- }
- drm_dbg_kms(dev, "Unsupported pixel format.\n");
- return false;
+ default:
+ drm_dbg_kms(dev, "Unsupported pixel format.\n");
+ return false;
+ }
}
static enum drm_mode_status
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread* [PATCH v11 03/22] drm: Add new general DRM property "color format"
2026-03-24 16:01 [PATCH v11 00/22] Add new general DRM property "color format" Nicolas Frattaroli
2026-03-24 16:01 ` [PATCH v11 01/22] drm/amd/display: Remove unnecessary SIGNAL_TYPE_HDMI_TYPE_A check Nicolas Frattaroli
2026-03-24 16:01 ` [PATCH v11 02/22] drm/display: hdmi-state-helper: Use default case for unsupported formats Nicolas Frattaroli
@ 2026-03-24 16:01 ` Nicolas Frattaroli
2026-03-24 17:00 ` Ville Syrjälä
2026-03-25 12:49 ` Dave Stevenson
2026-03-24 16:01 ` [PATCH v11 04/22] drm/bridge: Act on the DRM color format property Nicolas Frattaroli
` (18 subsequent siblings)
21 siblings, 2 replies; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-24 16:01 UTC (permalink / raw)
To: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc,
Nicolas Frattaroli, Werner Sembach, Andri Yngvason, Marius Vlad
Add a new general DRM property named "color format" which can be used by
userspace to request the display driver to output a particular color
format.
Possible options are:
- auto (setup by default, driver internally picks the color format)
- rgb
- ycbcr444
- ycbcr422
- ycbcr420
Drivers should advertise from this list which formats they support.
Together with this list and EDID data from the sink we should be able
to relay a list of usable color formats to users to pick from.
Co-developed-by: Werner Sembach <wse@tuxedocomputers.com>
Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
Co-developed-by: Andri Yngvason <andri@yngvason.is>
Signed-off-by: Andri Yngvason <andri@yngvason.is>
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/drm_atomic_helper.c | 5 ++
drivers/gpu/drm/drm_atomic_uapi.c | 11 ++++
drivers/gpu/drm/drm_connector.c | 108 ++++++++++++++++++++++++++++++++++++
include/drm/drm_connector.h | 104 ++++++++++++++++++++++++++++++++++
4 files changed, 228 insertions(+)
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 26953ed6b53e..b7753454b777 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -737,6 +737,11 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
if (old_connector_state->max_requested_bpc !=
new_connector_state->max_requested_bpc)
new_crtc_state->connectors_changed = true;
+
+ if (old_connector_state->color_format !=
+ new_connector_state->color_format)
+ new_crtc_state->connectors_changed = true;
+
}
if (funcs->atomic_check)
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
index 5bd5bf6661df..dee510c85e59 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -935,6 +935,15 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector,
state->privacy_screen_sw_state = val;
} else if (property == connector->broadcast_rgb_property) {
state->hdmi.broadcast_rgb = val;
+ } else if (property == connector->color_format_property) {
+ if (val > INT_MAX || !drm_connector_color_format_valid(val)) {
+ drm_dbg_atomic(connector->dev,
+ "[CONNECTOR:%d:%s] unknown color format %llu\n",
+ connector->base.id, connector->name, val);
+ return -EINVAL;
+ }
+
+ state->color_format = val;
} else if (connector->funcs->atomic_set_property) {
return connector->funcs->atomic_set_property(connector,
state, property, val);
@@ -1020,6 +1029,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
*val = state->privacy_screen_sw_state;
} else if (property == connector->broadcast_rgb_property) {
*val = state->hdmi.broadcast_rgb;
+ } else if (property == connector->color_format_property) {
+ *val = state->color_format;
} else if (connector->funcs->atomic_get_property) {
return connector->funcs->atomic_get_property(connector,
state, property, val);
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 47dc53c4a738..e848374dee0b 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1388,6 +1388,18 @@ static const u32 hdmi_colorspaces =
BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65) |
BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER);
+static const u32 hdmi_colorformats =
+ BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
+
+static const u32 dp_colorformats =
+ BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
+
/*
* As per DP 1.4a spec, 2.2.5.7.5 VSC SDP Payload for Pixel Encoding/Colorimetry
* Format Table 2-120
@@ -2940,6 +2952,102 @@ int drm_connector_attach_colorspace_property(struct drm_connector *connector)
}
EXPORT_SYMBOL(drm_connector_attach_colorspace_property);
+/**
+ * drm_connector_attach_color_format_property - create and attach color format property
+ * @connector: connector to create the color format property on
+ * @supported_color_formats: bitmask of bit-shifted &enum drm_output_color_format
+ * values the connector supports
+ *
+ * Called by a driver to create a color format property. The property is
+ * attached to the connector automatically on success.
+ *
+ * @supported_color_formats should only include color formats the connector
+ * type can actually support.
+ *
+ * Returns:
+ * 0 on success, negative errno on error
+ */
+int drm_connector_attach_color_format_property(struct drm_connector *connector,
+ unsigned long supported_color_formats)
+{
+ struct drm_device *dev = connector->dev;
+ struct drm_prop_enum_list enum_list[DRM_CONNECTOR_COLOR_FORMAT_COUNT];
+ unsigned int i = 0;
+ unsigned long fmt;
+
+ if (connector->color_format_property)
+ return 0;
+
+ if (!supported_color_formats) {
+ drm_err(dev, "No supported color formats provided on [CONNECTOR:%d:%s]\n",
+ connector->base.id, connector->name);
+ return -EINVAL;
+ }
+
+ if (supported_color_formats & ~GENMASK(DRM_OUTPUT_COLOR_FORMAT_COUNT - 1, 0)) {
+ drm_err(dev, "Unknown color formats provided on [CONNECTOR:%d:%s]\n",
+ connector->base.id, connector->name);
+ return -EINVAL;
+ }
+
+ switch (connector->connector_type) {
+ case DRM_MODE_CONNECTOR_HDMIA:
+ case DRM_MODE_CONNECTOR_HDMIB:
+ if (supported_color_formats & ~hdmi_colorformats) {
+ drm_err(dev, "Color formats not allowed for HDMI on [CONNECTOR:%d:%s]\n",
+ connector->base.id, connector->name);
+ return -EINVAL;
+ }
+ break;
+ case DRM_MODE_CONNECTOR_DisplayPort:
+ case DRM_MODE_CONNECTOR_eDP:
+ if (supported_color_formats & ~dp_colorformats) {
+ drm_err(dev, "Color formats not allowed for DP on [CONNECTOR:%d:%s]\n",
+ connector->base.id, connector->name);
+ return -EINVAL;
+ }
+ break;
+ }
+
+ enum_list[0].name = "AUTO";
+ enum_list[0].type = DRM_CONNECTOR_COLOR_FORMAT_AUTO;
+
+ for_each_set_bit(fmt, &supported_color_formats, DRM_OUTPUT_COLOR_FORMAT_COUNT) {
+ switch (fmt) {
+ case DRM_OUTPUT_COLOR_FORMAT_RGB444:
+ enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_RGB444;
+ break;
+ case DRM_OUTPUT_COLOR_FORMAT_YCBCR444:
+ enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR444;
+ break;
+ case DRM_OUTPUT_COLOR_FORMAT_YCBCR422:
+ enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR422;
+ break;
+ case DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
+ enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR420;
+ break;
+ default:
+ drm_warn(dev, "Unknown supported format %ld on [CONNECTOR:%d:%s]\n",
+ fmt, connector->base.id, connector->name);
+ continue;
+ }
+ enum_list[i].name = drm_hdmi_connector_get_output_format_name(fmt);
+ }
+
+ connector->color_format_property =
+ drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, "color format",
+ enum_list, i + 1);
+
+ if (!connector->color_format_property)
+ return -ENOMEM;
+
+ drm_object_attach_property(&connector->base, connector->color_format_property,
+ DRM_CONNECTOR_COLOR_FORMAT_AUTO);
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_connector_attach_color_format_property);
+
/**
* drm_connector_atomic_hdr_metadata_equal - checks if the hdr metadata changed
* @old_state: old connector state to compare
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index af8b92d2d5b7..bd549f912b76 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -571,14 +571,102 @@ enum drm_colorspace {
* YCbCr 4:2:2 output format (ie. with horizontal subsampling)
* @DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
* YCbCr 4:2:0 output format (ie. with horizontal and vertical subsampling)
+ * @DRM_OUTPUT_COLOR_FORMAT_COUNT:
+ * Number of valid output color format values in this enum
*/
enum drm_output_color_format {
DRM_OUTPUT_COLOR_FORMAT_RGB444 = 0,
DRM_OUTPUT_COLOR_FORMAT_YCBCR444,
DRM_OUTPUT_COLOR_FORMAT_YCBCR422,
DRM_OUTPUT_COLOR_FORMAT_YCBCR420,
+ DRM_OUTPUT_COLOR_FORMAT_COUNT,
};
+/**
+ * enum drm_connector_color_format - Connector Color Format Request
+ *
+ * This enum, unlike &enum drm_output_color_format, is used to specify requests
+ * for a specific color format on a connector through the DRM "color format"
+ * property. The difference is that it has an "AUTO" value to specify that
+ * no specific choice has been made.
+ */
+enum drm_connector_color_format {
+ /**
+ * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
+ * helpers should pick a suitable color format. All implementations of a
+ * specific display protocol must behave the same way with "AUTO", but
+ * different display protocols do not necessarily have the same "AUTO"
+ * semantics.
+ *
+ * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
+ * bandwidth required for full-scale RGB is not available, or the mode
+ * is YCbCr 4:2:0-only, as long as the mode and output both support
+ * YCbCr 4:2:0.
+ *
+ * For display protocols other than HDMI, the recursive bridge chain
+ * format selection picks the first chain of bridge formats that works,
+ * as has already been the case before the introduction of the "color
+ * format" property. Non-HDMI bridges should therefore either sort their
+ * bus output formats by preference, or agree on a unified auto format
+ * selection logic that's implemented in a common state helper (like
+ * how HDMI does it).
+ */
+ DRM_CONNECTOR_COLOR_FORMAT_AUTO = 0,
+
+ /**
+ * @DRM_CONNECTOR_COLOR_FORMAT_RGB444: RGB output format
+ */
+ DRM_CONNECTOR_COLOR_FORMAT_RGB444,
+
+ /**
+ * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR444: YCbCr 4:4:4 output format (ie.
+ * not subsampled)
+ */
+ DRM_CONNECTOR_COLOR_FORMAT_YCBCR444,
+
+ /**
+ * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR422: YCbCr 4:2:2 output format (ie.
+ * with horizontal subsampling)
+ */
+ DRM_CONNECTOR_COLOR_FORMAT_YCBCR422,
+
+ /**
+ * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR420: YCbCr 4:2:0 output format (ie.
+ * with horizontal and vertical subsampling)
+ */
+ DRM_CONNECTOR_COLOR_FORMAT_YCBCR420,
+
+ /**
+ * @DRM_CONNECTOR_COLOR_FORMAT_COUNT: Number of valid connector color
+ * format values in this enum
+ */
+ DRM_CONNECTOR_COLOR_FORMAT_COUNT,
+};
+
+/**
+ * drm_connector_color_format_valid - Validate drm_connector_color_format value
+ * @fmt: value to check against all values of &enum drm_connector_color_format
+ *
+ * Checks whether the passed in value of @fmt is one of the allowable values in
+ * &enum drm_connector_color_format.
+ *
+ * Returns: %true if it's a valid value for the enum, %false otherwise.
+ */
+static inline bool __pure
+drm_connector_color_format_valid(enum drm_connector_color_format fmt)
+{
+ switch (fmt) {
+ case DRM_CONNECTOR_COLOR_FORMAT_AUTO:
+ case DRM_CONNECTOR_COLOR_FORMAT_RGB444:
+ case DRM_CONNECTOR_COLOR_FORMAT_YCBCR444:
+ case DRM_CONNECTOR_COLOR_FORMAT_YCBCR422:
+ case DRM_CONNECTOR_COLOR_FORMAT_YCBCR420:
+ return true;
+ default:
+ return false;
+ }
+}
+
const char *
drm_hdmi_connector_get_output_format_name(enum drm_output_color_format fmt);
@@ -1129,6 +1217,13 @@ struct drm_connector_state {
*/
enum drm_colorspace colorspace;
+ /**
+ * @color_format: State variable for Connector property to request
+ * color format change on Sink. This is most commonly used to switch
+ * between RGB to YUV and vice-versa.
+ */
+ enum drm_connector_color_format color_format;
+
/**
* @writeback_job: Writeback job for writeback connectors
*
@@ -2127,6 +2222,12 @@ struct drm_connector {
*/
struct drm_property *colorspace_property;
+ /**
+ * @color_format_property: Connector property to set the suitable
+ * color format supported by the sink.
+ */
+ struct drm_property *color_format_property;
+
/**
* @path_blob_ptr:
*
@@ -2610,6 +2711,9 @@ bool drm_connector_has_possible_encoder(struct drm_connector *connector,
struct drm_encoder *encoder);
const char *drm_get_colorspace_name(enum drm_colorspace colorspace);
+int drm_connector_attach_color_format_property(struct drm_connector *connector,
+ unsigned long supported_color_formats);
+
/**
* drm_for_each_connector_iter - connector_list iterator macro
* @connector: &struct drm_connector pointer used as cursor
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
2026-03-24 16:01 ` [PATCH v11 03/22] drm: Add new general DRM property "color format" Nicolas Frattaroli
@ 2026-03-24 17:00 ` Ville Syrjälä
2026-03-24 19:10 ` Nicolas Frattaroli
2026-03-25 12:49 ` Dave Stevenson
1 sibling, 1 reply; 48+ messages in thread
From: Ville Syrjälä @ 2026-03-24 17:00 UTC (permalink / raw)
To: Nicolas Frattaroli
Cc: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan, kernel, amd-gfx, dri-devel,
linux-kernel, linux-arm-kernel, linux-rockchip, intel-gfx,
intel-xe, linux-doc, Werner Sembach, Andri Yngvason, Marius Vlad
On Tue, Mar 24, 2026 at 05:01:07PM +0100, Nicolas Frattaroli wrote:
> +enum drm_connector_color_format {
> + /**
> + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> + * helpers should pick a suitable color format. All implementations of a
> + * specific display protocol must behave the same way with "AUTO", but
> + * different display protocols do not necessarily have the same "AUTO"
> + * semantics.
> + *
> + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> + * bandwidth required for full-scale RGB is not available, or the mode
> + * is YCbCr 4:2:0-only, as long as the mode and output both support
> + * YCbCr 4:2:0.
> + *
> + * For display protocols other than HDMI, the recursive bridge chain
> + * format selection picks the first chain of bridge formats that works,
> + * as has already been the case before the introduction of the "color
> + * format" property. Non-HDMI bridges should therefore either sort their
> + * bus output formats by preference, or agree on a unified auto format
> + * selection logic that's implemented in a common state helper (like
> + * how HDMI does it).
> + */
> + DRM_CONNECTOR_COLOR_FORMAT_AUTO = 0,
> +
> + /**
> + * @DRM_CONNECTOR_COLOR_FORMAT_RGB444: RGB output format
> + */
> + DRM_CONNECTOR_COLOR_FORMAT_RGB444,
> +
> + /**
> + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR444: YCbCr 4:4:4 output format (ie.
> + * not subsampled)
> + */
> + DRM_CONNECTOR_COLOR_FORMAT_YCBCR444,
> +
> + /**
> + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR422: YCbCr 4:2:2 output format (ie.
> + * with horizontal subsampling)
> + */
> + DRM_CONNECTOR_COLOR_FORMAT_YCBCR422,
> +
> + /**
> + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR420: YCbCr 4:2:0 output format (ie.
> + * with horizontal and vertical subsampling)
> + */
> + DRM_CONNECTOR_COLOR_FORMAT_YCBCR420,
Seems like this should document what the quantization range
should be for each format.
> +
> + /**
> + * @DRM_CONNECTOR_COLOR_FORMAT_COUNT: Number of valid connector color
> + * format values in this enum
> + */
> + DRM_CONNECTOR_COLOR_FORMAT_COUNT,
> +};
> +
> +/**
> + * drm_connector_color_format_valid - Validate drm_connector_color_format value
> + * @fmt: value to check against all values of &enum drm_connector_color_format
> + *
> + * Checks whether the passed in value of @fmt is one of the allowable values in
> + * &enum drm_connector_color_format.
> + *
> + * Returns: %true if it's a valid value for the enum, %false otherwise.
> + */
> +static inline bool __pure
> +drm_connector_color_format_valid(enum drm_connector_color_format fmt)
> +{
> + switch (fmt) {
> + case DRM_CONNECTOR_COLOR_FORMAT_AUTO:
> + case DRM_CONNECTOR_COLOR_FORMAT_RGB444:
> + case DRM_CONNECTOR_COLOR_FORMAT_YCBCR444:
> + case DRM_CONNECTOR_COLOR_FORMAT_YCBCR422:
> + case DRM_CONNECTOR_COLOR_FORMAT_YCBCR420:
> + return true;
> + default:
> + return false;
> + }
> +}
> +
> const char *
> drm_hdmi_connector_get_output_format_name(enum drm_output_color_format fmt);
>
> @@ -1129,6 +1217,13 @@ struct drm_connector_state {
> */
> enum drm_colorspace colorspace;
>
> + /**
> + * @color_format: State variable for Connector property to request
> + * color format change on Sink. This is most commonly used to switch
> + * between RGB to YUV and vice-versa.
> + */
> + enum drm_connector_color_format color_format;
> +
> /**
> * @writeback_job: Writeback job for writeback connectors
> *
> @@ -2127,6 +2222,12 @@ struct drm_connector {
> */
> struct drm_property *colorspace_property;
>
> + /**
> + * @color_format_property: Connector property to set the suitable
> + * color format supported by the sink.
> + */
> + struct drm_property *color_format_property;
> +
> /**
> * @path_blob_ptr:
> *
> @@ -2610,6 +2711,9 @@ bool drm_connector_has_possible_encoder(struct drm_connector *connector,
> struct drm_encoder *encoder);
> const char *drm_get_colorspace_name(enum drm_colorspace colorspace);
>
> +int drm_connector_attach_color_format_property(struct drm_connector *connector,
> + unsigned long supported_color_formats);
> +
> /**
> * drm_for_each_connector_iter - connector_list iterator macro
> * @connector: &struct drm_connector pointer used as cursor
>
> --
> 2.53.0
--
Ville Syrjälä
Intel
^ permalink raw reply [flat|nested] 48+ messages in thread* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
2026-03-24 17:00 ` Ville Syrjälä
@ 2026-03-24 19:10 ` Nicolas Frattaroli
2026-03-24 19:53 ` Ville Syrjälä
0 siblings, 1 reply; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-24 19:10 UTC (permalink / raw)
To: Ville Syrjälä
Cc: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan, kernel, amd-gfx, dri-devel,
linux-kernel, linux-arm-kernel, linux-rockchip, intel-gfx,
intel-xe, linux-doc, Werner Sembach, Andri Yngvason, Marius Vlad
On Tuesday, 24 March 2026 18:00:45 Central European Standard Time Ville Syrjälä wrote:
> On Tue, Mar 24, 2026 at 05:01:07PM +0100, Nicolas Frattaroli wrote:
> > +enum drm_connector_color_format {
> > + /**
> > + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> > + * helpers should pick a suitable color format. All implementations of a
> > + * specific display protocol must behave the same way with "AUTO", but
> > + * different display protocols do not necessarily have the same "AUTO"
> > + * semantics.
> > + *
> > + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> > + * bandwidth required for full-scale RGB is not available, or the mode
> > + * is YCbCr 4:2:0-only, as long as the mode and output both support
> > + * YCbCr 4:2:0.
> > + *
> > + * For display protocols other than HDMI, the recursive bridge chain
> > + * format selection picks the first chain of bridge formats that works,
> > + * as has already been the case before the introduction of the "color
> > + * format" property. Non-HDMI bridges should therefore either sort their
> > + * bus output formats by preference, or agree on a unified auto format
> > + * selection logic that's implemented in a common state helper (like
> > + * how HDMI does it).
> > + */
> > + DRM_CONNECTOR_COLOR_FORMAT_AUTO = 0,
> > +
> > + /**
> > + * @DRM_CONNECTOR_COLOR_FORMAT_RGB444: RGB output format
> > + */
> > + DRM_CONNECTOR_COLOR_FORMAT_RGB444,
> > +
> > + /**
> > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR444: YCbCr 4:4:4 output format (ie.
> > + * not subsampled)
> > + */
> > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR444,
> > +
> > + /**
> > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR422: YCbCr 4:2:2 output format (ie.
> > + * with horizontal subsampling)
> > + */
> > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR422,
> > +
> > + /**
> > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR420: YCbCr 4:2:0 output format (ie.
> > + * with horizontal and vertical subsampling)
> > + */
> > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR420,
>
> Seems like this should document what the quantization range
> should be for each format.
>
I don't think so? If you want per-component bit depth values,
DRM_FORMAT_* defines would be the appropriate values to use. This
enum is more abstract than that, and is there to communicate
YUV vs. RGB and chroma subsampling, with bit depth being handled
by other properties.
If you mean the factor used for subsampling, then that'd only be
relevant if YCBCR410 was supported where one chroma plane isn't
halved but quartered in resolution. I suspect 4:1:0 will never
be added; no digital display protocol standard supports it to my
knowledge, and hopefully none ever will.
> > +
> > + /**
> > + * @DRM_CONNECTOR_COLOR_FORMAT_COUNT: Number of valid connector color
> > + * format values in this enum
> > + */
> > + DRM_CONNECTOR_COLOR_FORMAT_COUNT,
> > +};
> > +
> > +/**
> > + * drm_connector_color_format_valid - Validate drm_connector_color_format value
> > + * @fmt: value to check against all values of &enum drm_connector_color_format
> > + *
> > + * Checks whether the passed in value of @fmt is one of the allowable values in
> > + * &enum drm_connector_color_format.
> > + *
> > + * Returns: %true if it's a valid value for the enum, %false otherwise.
> > + */
> > +static inline bool __pure
> > +drm_connector_color_format_valid(enum drm_connector_color_format fmt)
> > +{
> > + switch (fmt) {
> > + case DRM_CONNECTOR_COLOR_FORMAT_AUTO:
> > + case DRM_CONNECTOR_COLOR_FORMAT_RGB444:
> > + case DRM_CONNECTOR_COLOR_FORMAT_YCBCR444:
> > + case DRM_CONNECTOR_COLOR_FORMAT_YCBCR422:
> > + case DRM_CONNECTOR_COLOR_FORMAT_YCBCR420:
> > + return true;
> > + default:
> > + return false;
> > + }
> > +}
> > +
> > const char *
> > drm_hdmi_connector_get_output_format_name(enum drm_output_color_format fmt);
> >
> > @@ -1129,6 +1217,13 @@ struct drm_connector_state {
> > */
> > enum drm_colorspace colorspace;
> >
> > + /**
> > + * @color_format: State variable for Connector property to request
> > + * color format change on Sink. This is most commonly used to switch
> > + * between RGB to YUV and vice-versa.
> > + */
> > + enum drm_connector_color_format color_format;
> > +
> > /**
> > * @writeback_job: Writeback job for writeback connectors
> > *
> > @@ -2127,6 +2222,12 @@ struct drm_connector {
> > */
> > struct drm_property *colorspace_property;
> >
> > + /**
> > + * @color_format_property: Connector property to set the suitable
> > + * color format supported by the sink.
> > + */
> > + struct drm_property *color_format_property;
> > +
> > /**
> > * @path_blob_ptr:
> > *
> > @@ -2610,6 +2711,9 @@ bool drm_connector_has_possible_encoder(struct drm_connector *connector,
> > struct drm_encoder *encoder);
> > const char *drm_get_colorspace_name(enum drm_colorspace colorspace);
> >
> > +int drm_connector_attach_color_format_property(struct drm_connector *connector,
> > + unsigned long supported_color_formats);
> > +
> > /**
> > * drm_for_each_connector_iter - connector_list iterator macro
> > * @connector: &struct drm_connector pointer used as cursor
> >
>
>
^ permalink raw reply [flat|nested] 48+ messages in thread* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
2026-03-24 19:10 ` Nicolas Frattaroli
@ 2026-03-24 19:53 ` Ville Syrjälä
2026-03-25 8:24 ` Maxime Ripard
2026-03-25 13:05 ` Nicolas Frattaroli
0 siblings, 2 replies; 48+ messages in thread
From: Ville Syrjälä @ 2026-03-24 19:53 UTC (permalink / raw)
To: Nicolas Frattaroli
Cc: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan, kernel, amd-gfx, dri-devel,
linux-kernel, linux-arm-kernel, linux-rockchip, intel-gfx,
intel-xe, linux-doc, Werner Sembach, Andri Yngvason, Marius Vlad
On Tue, Mar 24, 2026 at 08:10:11PM +0100, Nicolas Frattaroli wrote:
> On Tuesday, 24 March 2026 18:00:45 Central European Standard Time Ville Syrjälä wrote:
> > On Tue, Mar 24, 2026 at 05:01:07PM +0100, Nicolas Frattaroli wrote:
> > > +enum drm_connector_color_format {
> > > + /**
> > > + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> > > + * helpers should pick a suitable color format. All implementations of a
> > > + * specific display protocol must behave the same way with "AUTO", but
> > > + * different display protocols do not necessarily have the same "AUTO"
> > > + * semantics.
> > > + *
> > > + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> > > + * bandwidth required for full-scale RGB is not available, or the mode
> > > + * is YCbCr 4:2:0-only, as long as the mode and output both support
> > > + * YCbCr 4:2:0.
> > > + *
> > > + * For display protocols other than HDMI, the recursive bridge chain
> > > + * format selection picks the first chain of bridge formats that works,
> > > + * as has already been the case before the introduction of the "color
> > > + * format" property. Non-HDMI bridges should therefore either sort their
> > > + * bus output formats by preference, or agree on a unified auto format
> > > + * selection logic that's implemented in a common state helper (like
> > > + * how HDMI does it).
> > > + */
> > > + DRM_CONNECTOR_COLOR_FORMAT_AUTO = 0,
> > > +
> > > + /**
> > > + * @DRM_CONNECTOR_COLOR_FORMAT_RGB444: RGB output format
> > > + */
> > > + DRM_CONNECTOR_COLOR_FORMAT_RGB444,
> > > +
> > > + /**
> > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR444: YCbCr 4:4:4 output format (ie.
> > > + * not subsampled)
> > > + */
> > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR444,
> > > +
> > > + /**
> > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR422: YCbCr 4:2:2 output format (ie.
> > > + * with horizontal subsampling)
> > > + */
> > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR422,
> > > +
> > > + /**
> > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR420: YCbCr 4:2:0 output format (ie.
> > > + * with horizontal and vertical subsampling)
> > > + */
> > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR420,
> >
> > Seems like this should document what the quantization range
> > should be for each format.
> >
>
> I don't think so? If you want per-component bit depth values,
> DRM_FORMAT_* defines would be the appropriate values to use. This
> enum is more abstract than that, and is there to communicate
> YUV vs. RGB and chroma subsampling, with bit depth being handled
> by other properties.
>
> If you mean the factor used for subsampling, then that'd only be
> relevant if YCBCR410 was supported where one chroma plane isn't
> halved but quartered in resolution. I suspect 4:1:0 will never
> be added; no digital display protocol standard supports it to my
> knowledge, and hopefully none ever will.
No, I mean the quantization range (16-235 vs. 0-255 etc).
The i915 behaviour is that YCbCr is always limited range,
RGB can either be full or limited range depending on the
"Broadcast RGB" property and other related factors.
--
Ville Syrjälä
Intel
^ permalink raw reply [flat|nested] 48+ messages in thread* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
2026-03-24 19:53 ` Ville Syrjälä
@ 2026-03-25 8:24 ` Maxime Ripard
2026-03-25 11:03 ` Ville Syrjälä
2026-03-25 13:05 ` Nicolas Frattaroli
1 sibling, 1 reply; 48+ messages in thread
From: Maxime Ripard @ 2026-03-25 8:24 UTC (permalink / raw)
To: Ville Syrjälä
Cc: Nicolas Frattaroli, Harry Wentland, Leo Li, Rodrigo Siqueira,
Alex Deucher, Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Thomas Zimmermann, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Sandy Huang, Heiko Stübner, Andy Yan,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Dmitry Baryshkov, Sascha Hauer, Rob Herring, Jonathan Corbet,
Shuah Khan, kernel, amd-gfx, dri-devel, linux-kernel,
linux-arm-kernel, linux-rockchip, intel-gfx, intel-xe, linux-doc,
Werner Sembach, Andri Yngvason, Marius Vlad
[-- Attachment #1: Type: text/plain, Size: 3633 bytes --]
On Tue, Mar 24, 2026 at 09:53:35PM +0200, Ville Syrjälä wrote:
> On Tue, Mar 24, 2026 at 08:10:11PM +0100, Nicolas Frattaroli wrote:
> > On Tuesday, 24 March 2026 18:00:45 Central European Standard Time Ville Syrjälä wrote:
> > > On Tue, Mar 24, 2026 at 05:01:07PM +0100, Nicolas Frattaroli wrote:
> > > > +enum drm_connector_color_format {
> > > > + /**
> > > > + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> > > > + * helpers should pick a suitable color format. All implementations of a
> > > > + * specific display protocol must behave the same way with "AUTO", but
> > > > + * different display protocols do not necessarily have the same "AUTO"
> > > > + * semantics.
> > > > + *
> > > > + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> > > > + * bandwidth required for full-scale RGB is not available, or the mode
> > > > + * is YCbCr 4:2:0-only, as long as the mode and output both support
> > > > + * YCbCr 4:2:0.
> > > > + *
> > > > + * For display protocols other than HDMI, the recursive bridge chain
> > > > + * format selection picks the first chain of bridge formats that works,
> > > > + * as has already been the case before the introduction of the "color
> > > > + * format" property. Non-HDMI bridges should therefore either sort their
> > > > + * bus output formats by preference, or agree on a unified auto format
> > > > + * selection logic that's implemented in a common state helper (like
> > > > + * how HDMI does it).
> > > > + */
> > > > + DRM_CONNECTOR_COLOR_FORMAT_AUTO = 0,
> > > > +
> > > > + /**
> > > > + * @DRM_CONNECTOR_COLOR_FORMAT_RGB444: RGB output format
> > > > + */
> > > > + DRM_CONNECTOR_COLOR_FORMAT_RGB444,
> > > > +
> > > > + /**
> > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR444: YCbCr 4:4:4 output format (ie.
> > > > + * not subsampled)
> > > > + */
> > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR444,
> > > > +
> > > > + /**
> > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR422: YCbCr 4:2:2 output format (ie.
> > > > + * with horizontal subsampling)
> > > > + */
> > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR422,
> > > > +
> > > > + /**
> > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR420: YCbCr 4:2:0 output format (ie.
> > > > + * with horizontal and vertical subsampling)
> > > > + */
> > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR420,
> > >
> > > Seems like this should document what the quantization range
> > > should be for each format.
> > >
> >
> > I don't think so? If you want per-component bit depth values,
> > DRM_FORMAT_* defines would be the appropriate values to use. This
> > enum is more abstract than that, and is there to communicate
> > YUV vs. RGB and chroma subsampling, with bit depth being handled
> > by other properties.
> >
> > If you mean the factor used for subsampling, then that'd only be
> > relevant if YCBCR410 was supported where one chroma plane isn't
> > halved but quartered in resolution. I suspect 4:1:0 will never
> > be added; no digital display protocol standard supports it to my
> > knowledge, and hopefully none ever will.
>
> No, I mean the quantization range (16-235 vs. 0-255 etc).
>
> The i915 behaviour is that YCbCr is always limited range,
> RGB can either be full or limited range depending on the
> "Broadcast RGB" property and other related factors.
So far the HDMI state has both the format and quantization range as
different fields. I'm not sure we need to document the range in the
format field, maybe only mention it's not part of the format but has a
field of its own?
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply [flat|nested] 48+ messages in thread* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
2026-03-25 8:24 ` Maxime Ripard
@ 2026-03-25 11:03 ` Ville Syrjälä
2026-03-25 11:17 ` Ville Syrjälä
` (2 more replies)
0 siblings, 3 replies; 48+ messages in thread
From: Ville Syrjälä @ 2026-03-25 11:03 UTC (permalink / raw)
To: Maxime Ripard
Cc: Nicolas Frattaroli, Harry Wentland, Leo Li, Rodrigo Siqueira,
Alex Deucher, Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Thomas Zimmermann, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Sandy Huang, Heiko Stübner, Andy Yan,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Dmitry Baryshkov, Sascha Hauer, Rob Herring, Jonathan Corbet,
Shuah Khan, kernel, amd-gfx, dri-devel, linux-kernel,
linux-arm-kernel, linux-rockchip, intel-gfx, intel-xe, linux-doc,
Werner Sembach, Andri Yngvason, Marius Vlad
On Wed, Mar 25, 2026 at 09:24:27AM +0100, Maxime Ripard wrote:
> On Tue, Mar 24, 2026 at 09:53:35PM +0200, Ville Syrjälä wrote:
> > On Tue, Mar 24, 2026 at 08:10:11PM +0100, Nicolas Frattaroli wrote:
> > > On Tuesday, 24 March 2026 18:00:45 Central European Standard Time Ville Syrjälä wrote:
> > > > On Tue, Mar 24, 2026 at 05:01:07PM +0100, Nicolas Frattaroli wrote:
> > > > > +enum drm_connector_color_format {
> > > > > + /**
> > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> > > > > + * helpers should pick a suitable color format. All implementations of a
> > > > > + * specific display protocol must behave the same way with "AUTO", but
> > > > > + * different display protocols do not necessarily have the same "AUTO"
> > > > > + * semantics.
> > > > > + *
> > > > > + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> > > > > + * bandwidth required for full-scale RGB is not available, or the mode
> > > > > + * is YCbCr 4:2:0-only, as long as the mode and output both support
> > > > > + * YCbCr 4:2:0.
> > > > > + *
> > > > > + * For display protocols other than HDMI, the recursive bridge chain
> > > > > + * format selection picks the first chain of bridge formats that works,
> > > > > + * as has already been the case before the introduction of the "color
> > > > > + * format" property. Non-HDMI bridges should therefore either sort their
> > > > > + * bus output formats by preference, or agree on a unified auto format
> > > > > + * selection logic that's implemented in a common state helper (like
> > > > > + * how HDMI does it).
> > > > > + */
> > > > > + DRM_CONNECTOR_COLOR_FORMAT_AUTO = 0,
> > > > > +
> > > > > + /**
> > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_RGB444: RGB output format
> > > > > + */
> > > > > + DRM_CONNECTOR_COLOR_FORMAT_RGB444,
> > > > > +
> > > > > + /**
> > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR444: YCbCr 4:4:4 output format (ie.
> > > > > + * not subsampled)
> > > > > + */
> > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR444,
> > > > > +
> > > > > + /**
> > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR422: YCbCr 4:2:2 output format (ie.
> > > > > + * with horizontal subsampling)
> > > > > + */
> > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR422,
> > > > > +
> > > > > + /**
> > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR420: YCbCr 4:2:0 output format (ie.
> > > > > + * with horizontal and vertical subsampling)
> > > > > + */
> > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR420,
> > > >
> > > > Seems like this should document what the quantization range
> > > > should be for each format.
> > > >
> > >
> > > I don't think so? If you want per-component bit depth values,
> > > DRM_FORMAT_* defines would be the appropriate values to use. This
> > > enum is more abstract than that, and is there to communicate
> > > YUV vs. RGB and chroma subsampling, with bit depth being handled
> > > by other properties.
> > >
> > > If you mean the factor used for subsampling, then that'd only be
> > > relevant if YCBCR410 was supported where one chroma plane isn't
> > > halved but quartered in resolution. I suspect 4:1:0 will never
> > > be added; no digital display protocol standard supports it to my
> > > knowledge, and hopefully none ever will.
> >
> > No, I mean the quantization range (16-235 vs. 0-255 etc).
> >
> > The i915 behaviour is that YCbCr is always limited range,
> > RGB can either be full or limited range depending on the
> > "Broadcast RGB" property and other related factors.
>
> So far the HDMI state has both the format and quantization range as
> different fields. I'm not sure we need to document the range in the
> format field, maybe only mention it's not part of the format but has a
> field of its own?
I think we only have it for RGB (on some drivers only?). For YCbCr
I think the assumption is limited range everywhere.
But I'm not really concerned about documenting struct members.
What I'm talking about is the *uapi* docs. Surely userspace
will want to know what the new property actually does so the
uapi needs to be documented properly. And down the line some
new driver might also implement the wrong behaviour if there
is no clear specification.
So I'm thinking (or perhaps hoping) the rule might be something like:
- YCbCr limited range
- RGB full range if "Broadcast RGB" property is not present
- RGB full or limited range based on the "Broadcast RGB" property
if it's present
I think the "Broadcast RGB" property itself might also be lacking
proper uapi docs, so that may need to be remedied as well.
--
Ville Syrjälä
Intel
^ permalink raw reply [flat|nested] 48+ messages in thread* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
2026-03-25 11:03 ` Ville Syrjälä
@ 2026-03-25 11:17 ` Ville Syrjälä
2026-03-25 14:56 ` Maxime Ripard
2026-03-26 12:44 ` Nicolas Frattaroli
2 siblings, 0 replies; 48+ messages in thread
From: Ville Syrjälä @ 2026-03-25 11:17 UTC (permalink / raw)
To: Maxime Ripard
Cc: Nicolas Frattaroli, Harry Wentland, Leo Li, Rodrigo Siqueira,
Alex Deucher, Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Thomas Zimmermann, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Sandy Huang, Heiko Stübner, Andy Yan,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Dmitry Baryshkov, Sascha Hauer, Rob Herring, Jonathan Corbet,
Shuah Khan, kernel, amd-gfx, dri-devel, linux-kernel,
linux-arm-kernel, linux-rockchip, intel-gfx, intel-xe, linux-doc,
Werner Sembach, Andri Yngvason, Marius Vlad
On Wed, Mar 25, 2026 at 01:03:07PM +0200, Ville Syrjälä wrote:
> On Wed, Mar 25, 2026 at 09:24:27AM +0100, Maxime Ripard wrote:
> > On Tue, Mar 24, 2026 at 09:53:35PM +0200, Ville Syrjälä wrote:
> > > On Tue, Mar 24, 2026 at 08:10:11PM +0100, Nicolas Frattaroli wrote:
> > > > On Tuesday, 24 March 2026 18:00:45 Central European Standard Time Ville Syrjälä wrote:
> > > > > On Tue, Mar 24, 2026 at 05:01:07PM +0100, Nicolas Frattaroli wrote:
> > > > > > +enum drm_connector_color_format {
> > > > > > + /**
> > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> > > > > > + * helpers should pick a suitable color format. All implementations of a
> > > > > > + * specific display protocol must behave the same way with "AUTO", but
> > > > > > + * different display protocols do not necessarily have the same "AUTO"
> > > > > > + * semantics.
> > > > > > + *
> > > > > > + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> > > > > > + * bandwidth required for full-scale RGB is not available, or the mode
> > > > > > + * is YCbCr 4:2:0-only, as long as the mode and output both support
> > > > > > + * YCbCr 4:2:0.
> > > > > > + *
> > > > > > + * For display protocols other than HDMI, the recursive bridge chain
> > > > > > + * format selection picks the first chain of bridge formats that works,
> > > > > > + * as has already been the case before the introduction of the "color
> > > > > > + * format" property. Non-HDMI bridges should therefore either sort their
> > > > > > + * bus output formats by preference, or agree on a unified auto format
> > > > > > + * selection logic that's implemented in a common state helper (like
> > > > > > + * how HDMI does it).
> > > > > > + */
> > > > > > + DRM_CONNECTOR_COLOR_FORMAT_AUTO = 0,
> > > > > > +
> > > > > > + /**
> > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_RGB444: RGB output format
> > > > > > + */
> > > > > > + DRM_CONNECTOR_COLOR_FORMAT_RGB444,
> > > > > > +
> > > > > > + /**
> > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR444: YCbCr 4:4:4 output format (ie.
> > > > > > + * not subsampled)
> > > > > > + */
> > > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR444,
> > > > > > +
> > > > > > + /**
> > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR422: YCbCr 4:2:2 output format (ie.
> > > > > > + * with horizontal subsampling)
> > > > > > + */
> > > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR422,
> > > > > > +
> > > > > > + /**
> > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR420: YCbCr 4:2:0 output format (ie.
> > > > > > + * with horizontal and vertical subsampling)
> > > > > > + */
> > > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR420,
> > > > >
> > > > > Seems like this should document what the quantization range
> > > > > should be for each format.
> > > > >
> > > >
> > > > I don't think so? If you want per-component bit depth values,
> > > > DRM_FORMAT_* defines would be the appropriate values to use. This
> > > > enum is more abstract than that, and is there to communicate
> > > > YUV vs. RGB and chroma subsampling, with bit depth being handled
> > > > by other properties.
> > > >
> > > > If you mean the factor used for subsampling, then that'd only be
> > > > relevant if YCBCR410 was supported where one chroma plane isn't
> > > > halved but quartered in resolution. I suspect 4:1:0 will never
> > > > be added; no digital display protocol standard supports it to my
> > > > knowledge, and hopefully none ever will.
> > >
> > > No, I mean the quantization range (16-235 vs. 0-255 etc).
> > >
> > > The i915 behaviour is that YCbCr is always limited range,
> > > RGB can either be full or limited range depending on the
> > > "Broadcast RGB" property and other related factors.
> >
> > So far the HDMI state has both the format and quantization range as
> > different fields. I'm not sure we need to document the range in the
> > format field, maybe only mention it's not part of the format but has a
> > field of its own?
>
> I think we only have it for RGB (on some drivers only?). For YCbCr
> I think the assumption is limited range everywhere.
>
> But I'm not really concerned about documenting struct members.
> What I'm talking about is the *uapi* docs. Surely userspace
> will want to know what the new property actually does so the
> uapi needs to be documented properly. And down the line some
> new driver might also implement the wrong behaviour if there
> is no clear specification.
>
> So I'm thinking (or perhaps hoping) the rule might be something like:
> - YCbCr limited range
> - RGB full range if "Broadcast RGB" property is not present
> - RGB full or limited range based on the "Broadcast RGB" property
> if it's present
>
> I think the "Broadcast RGB" property itself might also be lacking
> proper uapi docs, so that may need to be remedied as well.
Oh, and I think a bunch of infoframe code still needs changes to
set up the quantization range properly for YCbCr. i915 does handle
that part correctly, but eg. hdmi_generate_avi_infoframe() does not.
I didn't spot any changes to that in the series.
--
Ville Syrjälä
Intel
^ permalink raw reply [flat|nested] 48+ messages in thread* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
2026-03-25 11:03 ` Ville Syrjälä
2026-03-25 11:17 ` Ville Syrjälä
@ 2026-03-25 14:56 ` Maxime Ripard
2026-03-25 18:43 ` Ville Syrjälä
2026-03-26 12:44 ` Nicolas Frattaroli
2 siblings, 1 reply; 48+ messages in thread
From: Maxime Ripard @ 2026-03-25 14:56 UTC (permalink / raw)
To: Ville Syrjälä
Cc: Nicolas Frattaroli, Harry Wentland, Leo Li, Rodrigo Siqueira,
Alex Deucher, Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Thomas Zimmermann, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Sandy Huang, Heiko Stübner, Andy Yan,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Dmitry Baryshkov, Sascha Hauer, Rob Herring, Jonathan Corbet,
Shuah Khan, kernel, amd-gfx, dri-devel, linux-kernel,
linux-arm-kernel, linux-rockchip, intel-gfx, intel-xe, linux-doc,
Werner Sembach, Andri Yngvason, Marius Vlad
[-- Attachment #1: Type: text/plain, Size: 5249 bytes --]
On Wed, Mar 25, 2026 at 01:03:07PM +0200, Ville Syrjälä wrote:
> On Wed, Mar 25, 2026 at 09:24:27AM +0100, Maxime Ripard wrote:
> > On Tue, Mar 24, 2026 at 09:53:35PM +0200, Ville Syrjälä wrote:
> > > On Tue, Mar 24, 2026 at 08:10:11PM +0100, Nicolas Frattaroli wrote:
> > > > On Tuesday, 24 March 2026 18:00:45 Central European Standard Time Ville Syrjälä wrote:
> > > > > On Tue, Mar 24, 2026 at 05:01:07PM +0100, Nicolas Frattaroli wrote:
> > > > > > +enum drm_connector_color_format {
> > > > > > + /**
> > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> > > > > > + * helpers should pick a suitable color format. All implementations of a
> > > > > > + * specific display protocol must behave the same way with "AUTO", but
> > > > > > + * different display protocols do not necessarily have the same "AUTO"
> > > > > > + * semantics.
> > > > > > + *
> > > > > > + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> > > > > > + * bandwidth required for full-scale RGB is not available, or the mode
> > > > > > + * is YCbCr 4:2:0-only, as long as the mode and output both support
> > > > > > + * YCbCr 4:2:0.
> > > > > > + *
> > > > > > + * For display protocols other than HDMI, the recursive bridge chain
> > > > > > + * format selection picks the first chain of bridge formats that works,
> > > > > > + * as has already been the case before the introduction of the "color
> > > > > > + * format" property. Non-HDMI bridges should therefore either sort their
> > > > > > + * bus output formats by preference, or agree on a unified auto format
> > > > > > + * selection logic that's implemented in a common state helper (like
> > > > > > + * how HDMI does it).
> > > > > > + */
> > > > > > + DRM_CONNECTOR_COLOR_FORMAT_AUTO = 0,
> > > > > > +
> > > > > > + /**
> > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_RGB444: RGB output format
> > > > > > + */
> > > > > > + DRM_CONNECTOR_COLOR_FORMAT_RGB444,
> > > > > > +
> > > > > > + /**
> > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR444: YCbCr 4:4:4 output format (ie.
> > > > > > + * not subsampled)
> > > > > > + */
> > > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR444,
> > > > > > +
> > > > > > + /**
> > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR422: YCbCr 4:2:2 output format (ie.
> > > > > > + * with horizontal subsampling)
> > > > > > + */
> > > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR422,
> > > > > > +
> > > > > > + /**
> > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR420: YCbCr 4:2:0 output format (ie.
> > > > > > + * with horizontal and vertical subsampling)
> > > > > > + */
> > > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR420,
> > > > >
> > > > > Seems like this should document what the quantization range
> > > > > should be for each format.
> > > > >
> > > >
> > > > I don't think so? If you want per-component bit depth values,
> > > > DRM_FORMAT_* defines would be the appropriate values to use. This
> > > > enum is more abstract than that, and is there to communicate
> > > > YUV vs. RGB and chroma subsampling, with bit depth being handled
> > > > by other properties.
> > > >
> > > > If you mean the factor used for subsampling, then that'd only be
> > > > relevant if YCBCR410 was supported where one chroma plane isn't
> > > > halved but quartered in resolution. I suspect 4:1:0 will never
> > > > be added; no digital display protocol standard supports it to my
> > > > knowledge, and hopefully none ever will.
> > >
> > > No, I mean the quantization range (16-235 vs. 0-255 etc).
> > >
> > > The i915 behaviour is that YCbCr is always limited range,
> > > RGB can either be full or limited range depending on the
> > > "Broadcast RGB" property and other related factors.
> >
> > So far the HDMI state has both the format and quantization range as
> > different fields. I'm not sure we need to document the range in the
> > format field, maybe only mention it's not part of the format but has a
> > field of its own?
>
> I think we only have it for RGB (on some drivers only?). For YCbCr
> I think the assumption is limited range everywhere.
>
> But I'm not really concerned about documenting struct members.
> What I'm talking about is the *uapi* docs. Surely userspace
> will want to know what the new property actually does so the
> uapi needs to be documented properly. And down the line some
> new driver might also implement the wrong behaviour if there
> is no clear specification.
Ack
> So I'm thinking (or perhaps hoping) the rule might be something like:
> - YCbCr limited range
> - RGB full range if "Broadcast RGB" property is not present
Isn't it much more complicated than that for HDMI though? My
recollection was that any VIC but VIC1 would be limited range, and
anything else full range?
> - RGB full or limited range based on the "Broadcast RGB" property
> if it's present
>
> I think the "Broadcast RGB" property itself might also be lacking
> proper uapi docs, so that may need to be remedied as well.
I took care of documenting it when merging the HDMI helpers:
https://docs.kernel.org/gpu/drm-kms.html#hdmi-specific-connector-properties
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply [flat|nested] 48+ messages in thread* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
2026-03-25 14:56 ` Maxime Ripard
@ 2026-03-25 18:43 ` Ville Syrjälä
2026-03-26 17:02 ` Maxime Ripard
0 siblings, 1 reply; 48+ messages in thread
From: Ville Syrjälä @ 2026-03-25 18:43 UTC (permalink / raw)
To: Maxime Ripard
Cc: Nicolas Frattaroli, Harry Wentland, Leo Li, Rodrigo Siqueira,
Alex Deucher, Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Thomas Zimmermann, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Sandy Huang, Heiko Stübner, Andy Yan,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Dmitry Baryshkov, Sascha Hauer, Rob Herring, Jonathan Corbet,
Shuah Khan, kernel, amd-gfx, dri-devel, linux-kernel,
linux-arm-kernel, linux-rockchip, intel-gfx, intel-xe, linux-doc,
Werner Sembach, Andri Yngvason, Marius Vlad
On Wed, Mar 25, 2026 at 03:56:58PM +0100, Maxime Ripard wrote:
> On Wed, Mar 25, 2026 at 01:03:07PM +0200, Ville Syrjälä wrote:
> > On Wed, Mar 25, 2026 at 09:24:27AM +0100, Maxime Ripard wrote:
> > > On Tue, Mar 24, 2026 at 09:53:35PM +0200, Ville Syrjälä wrote:
> > > > On Tue, Mar 24, 2026 at 08:10:11PM +0100, Nicolas Frattaroli wrote:
> > > > > On Tuesday, 24 March 2026 18:00:45 Central European Standard Time Ville Syrjälä wrote:
> > > > > > On Tue, Mar 24, 2026 at 05:01:07PM +0100, Nicolas Frattaroli wrote:
> > > > > > > +enum drm_connector_color_format {
> > > > > > > + /**
> > > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> > > > > > > + * helpers should pick a suitable color format. All implementations of a
> > > > > > > + * specific display protocol must behave the same way with "AUTO", but
> > > > > > > + * different display protocols do not necessarily have the same "AUTO"
> > > > > > > + * semantics.
> > > > > > > + *
> > > > > > > + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> > > > > > > + * bandwidth required for full-scale RGB is not available, or the mode
> > > > > > > + * is YCbCr 4:2:0-only, as long as the mode and output both support
> > > > > > > + * YCbCr 4:2:0.
> > > > > > > + *
> > > > > > > + * For display protocols other than HDMI, the recursive bridge chain
> > > > > > > + * format selection picks the first chain of bridge formats that works,
> > > > > > > + * as has already been the case before the introduction of the "color
> > > > > > > + * format" property. Non-HDMI bridges should therefore either sort their
> > > > > > > + * bus output formats by preference, or agree on a unified auto format
> > > > > > > + * selection logic that's implemented in a common state helper (like
> > > > > > > + * how HDMI does it).
> > > > > > > + */
> > > > > > > + DRM_CONNECTOR_COLOR_FORMAT_AUTO = 0,
> > > > > > > +
> > > > > > > + /**
> > > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_RGB444: RGB output format
> > > > > > > + */
> > > > > > > + DRM_CONNECTOR_COLOR_FORMAT_RGB444,
> > > > > > > +
> > > > > > > + /**
> > > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR444: YCbCr 4:4:4 output format (ie.
> > > > > > > + * not subsampled)
> > > > > > > + */
> > > > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR444,
> > > > > > > +
> > > > > > > + /**
> > > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR422: YCbCr 4:2:2 output format (ie.
> > > > > > > + * with horizontal subsampling)
> > > > > > > + */
> > > > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR422,
> > > > > > > +
> > > > > > > + /**
> > > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR420: YCbCr 4:2:0 output format (ie.
> > > > > > > + * with horizontal and vertical subsampling)
> > > > > > > + */
> > > > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR420,
> > > > > >
> > > > > > Seems like this should document what the quantization range
> > > > > > should be for each format.
> > > > > >
> > > > >
> > > > > I don't think so? If you want per-component bit depth values,
> > > > > DRM_FORMAT_* defines would be the appropriate values to use. This
> > > > > enum is more abstract than that, and is there to communicate
> > > > > YUV vs. RGB and chroma subsampling, with bit depth being handled
> > > > > by other properties.
> > > > >
> > > > > If you mean the factor used for subsampling, then that'd only be
> > > > > relevant if YCBCR410 was supported where one chroma plane isn't
> > > > > halved but quartered in resolution. I suspect 4:1:0 will never
> > > > > be added; no digital display protocol standard supports it to my
> > > > > knowledge, and hopefully none ever will.
> > > >
> > > > No, I mean the quantization range (16-235 vs. 0-255 etc).
> > > >
> > > > The i915 behaviour is that YCbCr is always limited range,
> > > > RGB can either be full or limited range depending on the
> > > > "Broadcast RGB" property and other related factors.
> > >
> > > So far the HDMI state has both the format and quantization range as
> > > different fields. I'm not sure we need to document the range in the
> > > format field, maybe only mention it's not part of the format but has a
> > > field of its own?
> >
> > I think we only have it for RGB (on some drivers only?). For YCbCr
> > I think the assumption is limited range everywhere.
> >
> > But I'm not really concerned about documenting struct members.
> > What I'm talking about is the *uapi* docs. Surely userspace
> > will want to know what the new property actually does so the
> > uapi needs to be documented properly. And down the line some
> > new driver might also implement the wrong behaviour if there
> > is no clear specification.
>
> Ack
>
> > So I'm thinking (or perhaps hoping) the rule might be something like:
> > - YCbCr limited range
> > - RGB full range if "Broadcast RGB" property is not present
>
> Isn't it much more complicated than that for HDMI though? My
> recollection was that any VIC but VIC1 would be limited range, and
> anything else full range?
Do we have some driver that implements the CTA-861 CE vs. IT mode
logic but doesn't expose the "Broadcast RGB" property? I was hoping
those would always go hand in hand now.
>
> > - RGB full or limited range based on the "Broadcast RGB" property
> > if it's present
> >
> > I think the "Broadcast RGB" property itself might also be lacking
> > proper uapi docs, so that may need to be remedied as well.
>
> I took care of documenting it when merging the HDMI helpers:
> https://docs.kernel.org/gpu/drm-kms.html#hdmi-specific-connector-properties
>
> Maxime
--
Ville Syrjälä
Intel
^ permalink raw reply [flat|nested] 48+ messages in thread* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
2026-03-25 18:43 ` Ville Syrjälä
@ 2026-03-26 17:02 ` Maxime Ripard
2026-03-26 17:58 ` Ville Syrjälä
0 siblings, 1 reply; 48+ messages in thread
From: Maxime Ripard @ 2026-03-26 17:02 UTC (permalink / raw)
To: Ville Syrjälä
Cc: Nicolas Frattaroli, Harry Wentland, Leo Li, Rodrigo Siqueira,
Alex Deucher, Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Thomas Zimmermann, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Sandy Huang, Heiko Stübner, Andy Yan,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Dmitry Baryshkov, Sascha Hauer, Rob Herring, Jonathan Corbet,
Shuah Khan, kernel, amd-gfx, dri-devel, linux-kernel,
linux-arm-kernel, linux-rockchip, intel-gfx, intel-xe, linux-doc,
Werner Sembach, Andri Yngvason, Marius Vlad
[-- Attachment #1: Type: text/plain, Size: 5891 bytes --]
On Wed, Mar 25, 2026 at 08:43:15PM +0200, Ville Syrjälä wrote:
> On Wed, Mar 25, 2026 at 03:56:58PM +0100, Maxime Ripard wrote:
> > On Wed, Mar 25, 2026 at 01:03:07PM +0200, Ville Syrjälä wrote:
> > > On Wed, Mar 25, 2026 at 09:24:27AM +0100, Maxime Ripard wrote:
> > > > On Tue, Mar 24, 2026 at 09:53:35PM +0200, Ville Syrjälä wrote:
> > > > > On Tue, Mar 24, 2026 at 08:10:11PM +0100, Nicolas Frattaroli wrote:
> > > > > > On Tuesday, 24 March 2026 18:00:45 Central European Standard Time Ville Syrjälä wrote:
> > > > > > > On Tue, Mar 24, 2026 at 05:01:07PM +0100, Nicolas Frattaroli wrote:
> > > > > > > > +enum drm_connector_color_format {
> > > > > > > > + /**
> > > > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> > > > > > > > + * helpers should pick a suitable color format. All implementations of a
> > > > > > > > + * specific display protocol must behave the same way with "AUTO", but
> > > > > > > > + * different display protocols do not necessarily have the same "AUTO"
> > > > > > > > + * semantics.
> > > > > > > > + *
> > > > > > > > + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> > > > > > > > + * bandwidth required for full-scale RGB is not available, or the mode
> > > > > > > > + * is YCbCr 4:2:0-only, as long as the mode and output both support
> > > > > > > > + * YCbCr 4:2:0.
> > > > > > > > + *
> > > > > > > > + * For display protocols other than HDMI, the recursive bridge chain
> > > > > > > > + * format selection picks the first chain of bridge formats that works,
> > > > > > > > + * as has already been the case before the introduction of the "color
> > > > > > > > + * format" property. Non-HDMI bridges should therefore either sort their
> > > > > > > > + * bus output formats by preference, or agree on a unified auto format
> > > > > > > > + * selection logic that's implemented in a common state helper (like
> > > > > > > > + * how HDMI does it).
> > > > > > > > + */
> > > > > > > > + DRM_CONNECTOR_COLOR_FORMAT_AUTO = 0,
> > > > > > > > +
> > > > > > > > + /**
> > > > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_RGB444: RGB output format
> > > > > > > > + */
> > > > > > > > + DRM_CONNECTOR_COLOR_FORMAT_RGB444,
> > > > > > > > +
> > > > > > > > + /**
> > > > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR444: YCbCr 4:4:4 output format (ie.
> > > > > > > > + * not subsampled)
> > > > > > > > + */
> > > > > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR444,
> > > > > > > > +
> > > > > > > > + /**
> > > > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR422: YCbCr 4:2:2 output format (ie.
> > > > > > > > + * with horizontal subsampling)
> > > > > > > > + */
> > > > > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR422,
> > > > > > > > +
> > > > > > > > + /**
> > > > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR420: YCbCr 4:2:0 output format (ie.
> > > > > > > > + * with horizontal and vertical subsampling)
> > > > > > > > + */
> > > > > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR420,
> > > > > > >
> > > > > > > Seems like this should document what the quantization range
> > > > > > > should be for each format.
> > > > > > >
> > > > > >
> > > > > > I don't think so? If you want per-component bit depth values,
> > > > > > DRM_FORMAT_* defines would be the appropriate values to use. This
> > > > > > enum is more abstract than that, and is there to communicate
> > > > > > YUV vs. RGB and chroma subsampling, with bit depth being handled
> > > > > > by other properties.
> > > > > >
> > > > > > If you mean the factor used for subsampling, then that'd only be
> > > > > > relevant if YCBCR410 was supported where one chroma plane isn't
> > > > > > halved but quartered in resolution. I suspect 4:1:0 will never
> > > > > > be added; no digital display protocol standard supports it to my
> > > > > > knowledge, and hopefully none ever will.
> > > > >
> > > > > No, I mean the quantization range (16-235 vs. 0-255 etc).
> > > > >
> > > > > The i915 behaviour is that YCbCr is always limited range,
> > > > > RGB can either be full or limited range depending on the
> > > > > "Broadcast RGB" property and other related factors.
> > > >
> > > > So far the HDMI state has both the format and quantization range as
> > > > different fields. I'm not sure we need to document the range in the
> > > > format field, maybe only mention it's not part of the format but has a
> > > > field of its own?
> > >
> > > I think we only have it for RGB (on some drivers only?). For YCbCr
> > > I think the assumption is limited range everywhere.
> > >
> > > But I'm not really concerned about documenting struct members.
> > > What I'm talking about is the *uapi* docs. Surely userspace
> > > will want to know what the new property actually does so the
> > > uapi needs to be documented properly. And down the line some
> > > new driver might also implement the wrong behaviour if there
> > > is no clear specification.
> >
> > Ack
> >
> > > So I'm thinking (or perhaps hoping) the rule might be something like:
> > > - YCbCr limited range
> > > - RGB full range if "Broadcast RGB" property is not present
> >
> > Isn't it much more complicated than that for HDMI though? My
> > recollection was that any VIC but VIC1 would be limited range, and
> > anything else full range?
>
> Do we have some driver that implements the CTA-861 CE vs. IT mode
> logic but doesn't expose the "Broadcast RGB" property? I was hoping
> those would always go hand in hand now.
I'm not sure. i915 and the HDMI state helpers handle it properly (I
think?) but it looks like only vc4 registers the Broadcast RGB property
and uses the HDMI state helpers.
And it looks like amdgpu registers Broadcast RGB but doesn't use
drm_default_rgb_quant_range() which seems suspicious?
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply [flat|nested] 48+ messages in thread* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
2026-03-26 17:02 ` Maxime Ripard
@ 2026-03-26 17:58 ` Ville Syrjälä
0 siblings, 0 replies; 48+ messages in thread
From: Ville Syrjälä @ 2026-03-26 17:58 UTC (permalink / raw)
To: Maxime Ripard
Cc: Nicolas Frattaroli, Harry Wentland, Leo Li, Rodrigo Siqueira,
Alex Deucher, Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Thomas Zimmermann, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Sandy Huang, Heiko Stübner, Andy Yan,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Dmitry Baryshkov, Sascha Hauer, Rob Herring, Jonathan Corbet,
Shuah Khan, kernel, amd-gfx, dri-devel, linux-kernel,
linux-arm-kernel, linux-rockchip, intel-gfx, intel-xe, linux-doc,
Werner Sembach, Andri Yngvason, Marius Vlad
On Thu, Mar 26, 2026 at 06:02:47PM +0100, Maxime Ripard wrote:
> On Wed, Mar 25, 2026 at 08:43:15PM +0200, Ville Syrjälä wrote:
> > On Wed, Mar 25, 2026 at 03:56:58PM +0100, Maxime Ripard wrote:
> > > On Wed, Mar 25, 2026 at 01:03:07PM +0200, Ville Syrjälä wrote:
> > > > On Wed, Mar 25, 2026 at 09:24:27AM +0100, Maxime Ripard wrote:
> > > > > On Tue, Mar 24, 2026 at 09:53:35PM +0200, Ville Syrjälä wrote:
> > > > > > On Tue, Mar 24, 2026 at 08:10:11PM +0100, Nicolas Frattaroli wrote:
> > > > > > > On Tuesday, 24 March 2026 18:00:45 Central European Standard Time Ville Syrjälä wrote:
> > > > > > > > On Tue, Mar 24, 2026 at 05:01:07PM +0100, Nicolas Frattaroli wrote:
> > > > > > > > > +enum drm_connector_color_format {
> > > > > > > > > + /**
> > > > > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> > > > > > > > > + * helpers should pick a suitable color format. All implementations of a
> > > > > > > > > + * specific display protocol must behave the same way with "AUTO", but
> > > > > > > > > + * different display protocols do not necessarily have the same "AUTO"
> > > > > > > > > + * semantics.
> > > > > > > > > + *
> > > > > > > > > + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> > > > > > > > > + * bandwidth required for full-scale RGB is not available, or the mode
> > > > > > > > > + * is YCbCr 4:2:0-only, as long as the mode and output both support
> > > > > > > > > + * YCbCr 4:2:0.
> > > > > > > > > + *
> > > > > > > > > + * For display protocols other than HDMI, the recursive bridge chain
> > > > > > > > > + * format selection picks the first chain of bridge formats that works,
> > > > > > > > > + * as has already been the case before the introduction of the "color
> > > > > > > > > + * format" property. Non-HDMI bridges should therefore either sort their
> > > > > > > > > + * bus output formats by preference, or agree on a unified auto format
> > > > > > > > > + * selection logic that's implemented in a common state helper (like
> > > > > > > > > + * how HDMI does it).
> > > > > > > > > + */
> > > > > > > > > + DRM_CONNECTOR_COLOR_FORMAT_AUTO = 0,
> > > > > > > > > +
> > > > > > > > > + /**
> > > > > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_RGB444: RGB output format
> > > > > > > > > + */
> > > > > > > > > + DRM_CONNECTOR_COLOR_FORMAT_RGB444,
> > > > > > > > > +
> > > > > > > > > + /**
> > > > > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR444: YCbCr 4:4:4 output format (ie.
> > > > > > > > > + * not subsampled)
> > > > > > > > > + */
> > > > > > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR444,
> > > > > > > > > +
> > > > > > > > > + /**
> > > > > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR422: YCbCr 4:2:2 output format (ie.
> > > > > > > > > + * with horizontal subsampling)
> > > > > > > > > + */
> > > > > > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR422,
> > > > > > > > > +
> > > > > > > > > + /**
> > > > > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR420: YCbCr 4:2:0 output format (ie.
> > > > > > > > > + * with horizontal and vertical subsampling)
> > > > > > > > > + */
> > > > > > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR420,
> > > > > > > >
> > > > > > > > Seems like this should document what the quantization range
> > > > > > > > should be for each format.
> > > > > > > >
> > > > > > >
> > > > > > > I don't think so? If you want per-component bit depth values,
> > > > > > > DRM_FORMAT_* defines would be the appropriate values to use. This
> > > > > > > enum is more abstract than that, and is there to communicate
> > > > > > > YUV vs. RGB and chroma subsampling, with bit depth being handled
> > > > > > > by other properties.
> > > > > > >
> > > > > > > If you mean the factor used for subsampling, then that'd only be
> > > > > > > relevant if YCBCR410 was supported where one chroma plane isn't
> > > > > > > halved but quartered in resolution. I suspect 4:1:0 will never
> > > > > > > be added; no digital display protocol standard supports it to my
> > > > > > > knowledge, and hopefully none ever will.
> > > > > >
> > > > > > No, I mean the quantization range (16-235 vs. 0-255 etc).
> > > > > >
> > > > > > The i915 behaviour is that YCbCr is always limited range,
> > > > > > RGB can either be full or limited range depending on the
> > > > > > "Broadcast RGB" property and other related factors.
> > > > >
> > > > > So far the HDMI state has both the format and quantization range as
> > > > > different fields. I'm not sure we need to document the range in the
> > > > > format field, maybe only mention it's not part of the format but has a
> > > > > field of its own?
> > > >
> > > > I think we only have it for RGB (on some drivers only?). For YCbCr
> > > > I think the assumption is limited range everywhere.
> > > >
> > > > But I'm not really concerned about documenting struct members.
> > > > What I'm talking about is the *uapi* docs. Surely userspace
> > > > will want to know what the new property actually does so the
> > > > uapi needs to be documented properly. And down the line some
> > > > new driver might also implement the wrong behaviour if there
> > > > is no clear specification.
> > >
> > > Ack
> > >
> > > > So I'm thinking (or perhaps hoping) the rule might be something like:
> > > > - YCbCr limited range
> > > > - RGB full range if "Broadcast RGB" property is not present
> > >
> > > Isn't it much more complicated than that for HDMI though? My
> > > recollection was that any VIC but VIC1 would be limited range, and
> > > anything else full range?
> >
> > Do we have some driver that implements the CTA-861 CE vs. IT mode
> > logic but doesn't expose the "Broadcast RGB" property? I was hoping
> > those would always go hand in hand now.
>
> I'm not sure. i915 and the HDMI state helpers handle it properly (I
> think?) but it looks like only vc4 registers the Broadcast RGB property
> and uses the HDMI state helpers.
>
> And it looks like amdgpu registers Broadcast RGB but doesn't use
> drm_default_rgb_quant_range() which seems suspicious?
If they want just manual full vs. limited then they should
limit the property to not expose the "auto" option at all.
amdgpu also ties this in with the "colorspace" property, which
originally in i915 only controlled the infoframes/etc. But on
amdgpu it now controls various aspects of output color
transformation. The end result is that the property is a complete
mess with most of the values making no sense. And for whatever
reason everyone involved refused to remove/deprecate the
nonsensical values :/
Looks like this series should make sure the documentation for
the "colorspace" property is in sync with the new property
as well. Currently now it's giving conflicting information.
--
Ville Syrjälä
Intel
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
2026-03-25 11:03 ` Ville Syrjälä
2026-03-25 11:17 ` Ville Syrjälä
2026-03-25 14:56 ` Maxime Ripard
@ 2026-03-26 12:44 ` Nicolas Frattaroli
2026-03-26 13:07 ` Ville Syrjälä
2026-03-26 16:40 ` Daniel Stone
2 siblings, 2 replies; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-26 12:44 UTC (permalink / raw)
To: Maxime Ripard, Ville Syrjälä
Cc: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Thomas Zimmermann, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Sandy Huang, Heiko Stübner, Andy Yan,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Dmitry Baryshkov, Sascha Hauer, Rob Herring, Jonathan Corbet,
Shuah Khan, kernel, amd-gfx, dri-devel, linux-kernel,
linux-arm-kernel, linux-rockchip, intel-gfx, intel-xe, linux-doc,
Werner Sembach, Andri Yngvason, Marius Vlad
On Wednesday, 25 March 2026 12:03:07 Central European Standard Time Ville Syrjälä wrote:
> On Wed, Mar 25, 2026 at 09:24:27AM +0100, Maxime Ripard wrote:
> > On Tue, Mar 24, 2026 at 09:53:35PM +0200, Ville Syrjälä wrote:
> > > On Tue, Mar 24, 2026 at 08:10:11PM +0100, Nicolas Frattaroli wrote:
> > > > On Tuesday, 24 March 2026 18:00:45 Central European Standard Time Ville Syrjälä wrote:
> > > > > On Tue, Mar 24, 2026 at 05:01:07PM +0100, Nicolas Frattaroli wrote:
> > > > > > +enum drm_connector_color_format {
> > > > > > + /**
> > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> > > > > > + * helpers should pick a suitable color format. All implementations of a
> > > > > > + * specific display protocol must behave the same way with "AUTO", but
> > > > > > + * different display protocols do not necessarily have the same "AUTO"
> > > > > > + * semantics.
> > > > > > + *
> > > > > > + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> > > > > > + * bandwidth required for full-scale RGB is not available, or the mode
> > > > > > + * is YCbCr 4:2:0-only, as long as the mode and output both support
> > > > > > + * YCbCr 4:2:0.
> > > > > > + *
> > > > > > + * For display protocols other than HDMI, the recursive bridge chain
> > > > > > + * format selection picks the first chain of bridge formats that works,
> > > > > > + * as has already been the case before the introduction of the "color
> > > > > > + * format" property. Non-HDMI bridges should therefore either sort their
> > > > > > + * bus output formats by preference, or agree on a unified auto format
> > > > > > + * selection logic that's implemented in a common state helper (like
> > > > > > + * how HDMI does it).
> > > > > > + */
> > > > > > + DRM_CONNECTOR_COLOR_FORMAT_AUTO = 0,
> > > > > > +
> > > > > > + /**
> > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_RGB444: RGB output format
> > > > > > + */
> > > > > > + DRM_CONNECTOR_COLOR_FORMAT_RGB444,
> > > > > > +
> > > > > > + /**
> > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR444: YCbCr 4:4:4 output format (ie.
> > > > > > + * not subsampled)
> > > > > > + */
> > > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR444,
> > > > > > +
> > > > > > + /**
> > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR422: YCbCr 4:2:2 output format (ie.
> > > > > > + * with horizontal subsampling)
> > > > > > + */
> > > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR422,
> > > > > > +
> > > > > > + /**
> > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR420: YCbCr 4:2:0 output format (ie.
> > > > > > + * with horizontal and vertical subsampling)
> > > > > > + */
> > > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR420,
> > > > >
> > > > > Seems like this should document what the quantization range
> > > > > should be for each format.
> > > > >
> > > >
> > > > I don't think so? If you want per-component bit depth values,
> > > > DRM_FORMAT_* defines would be the appropriate values to use. This
> > > > enum is more abstract than that, and is there to communicate
> > > > YUV vs. RGB and chroma subsampling, with bit depth being handled
> > > > by other properties.
> > > >
> > > > If you mean the factor used for subsampling, then that'd only be
> > > > relevant if YCBCR410 was supported where one chroma plane isn't
> > > > halved but quartered in resolution. I suspect 4:1:0 will never
> > > > be added; no digital display protocol standard supports it to my
> > > > knowledge, and hopefully none ever will.
> > >
> > > No, I mean the quantization range (16-235 vs. 0-255 etc).
> > >
> > > The i915 behaviour is that YCbCr is always limited range,
> > > RGB can either be full or limited range depending on the
> > > "Broadcast RGB" property and other related factors.
> >
> > So far the HDMI state has both the format and quantization range as
> > different fields. I'm not sure we need to document the range in the
> > format field, maybe only mention it's not part of the format but has a
> > field of its own?
>
> I think we only have it for RGB (on some drivers only?). For YCbCr
> I think the assumption is limited range everywhere.
>
> But I'm not really concerned about documenting struct members.
> What I'm talking about is the *uapi* docs. Surely userspace
> will want to know what the new property actually does so the
> uapi needs to be documented properly. And down the line some
> new driver might also implement the wrong behaviour if there
> is no clear specification.
>
> So I'm thinking (or perhaps hoping) the rule might be something like:
> - YCbCr limited range
> - RGB full range if "Broadcast RGB" property is not present
> - RGB full or limited range based on the "Broadcast RGB" property
> if it's present
>
> I think the "Broadcast RGB" property itself might also be lacking
> proper uapi docs, so that may need to be remedied as well.
>
>
Alright, so in v12 I'll do the following:
- Add a line to all YCBCR connector formats that specifies they're
limited range as long as Broadcast RGB is limited. Whether it's limited
range when Broadcast RGB is full is purposefully left undefined.
In the future, we can expand this to state they're limited range by
default unless some other property is set. If we're not re-using
Broadcast RGB for that, this will work out fine, because users who
don't know about the eventual new property won't have this behaviour
changed. If we do re-use "Broadcast RGB" for that, then only users
relying on things we explicitly left undefined will get surprise
full range YCBCR.
- Add a line to the RGB connector format that specifies its range
depends on the "Broadcast RGB" property
This is a bit of a mess, because it's entirely reasonable that a
future YCBCR range property would want to default to full range
so that users get the most color out of their monitors. But with
this description of the connector color formats, we can't do that.
If there are alternate suggestions, I'm open for them. We can't
really rename "Broadcast RGB" but if I had a time machine, that'd
be my first choice.
Kind regards,
Nicolas Frattaroli
^ permalink raw reply [flat|nested] 48+ messages in thread* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
2026-03-26 12:44 ` Nicolas Frattaroli
@ 2026-03-26 13:07 ` Ville Syrjälä
2026-03-26 13:26 ` Nicolas Frattaroli
2026-03-26 16:40 ` Daniel Stone
1 sibling, 1 reply; 48+ messages in thread
From: Ville Syrjälä @ 2026-03-26 13:07 UTC (permalink / raw)
To: Nicolas Frattaroli
Cc: Maxime Ripard, Harry Wentland, Leo Li, Rodrigo Siqueira,
Alex Deucher, Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Thomas Zimmermann, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Sandy Huang, Heiko Stübner, Andy Yan,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Dmitry Baryshkov, Sascha Hauer, Rob Herring, Jonathan Corbet,
Shuah Khan, kernel, amd-gfx, dri-devel, linux-kernel,
linux-arm-kernel, linux-rockchip, intel-gfx, intel-xe, linux-doc,
Werner Sembach, Andri Yngvason, Marius Vlad
On Thu, Mar 26, 2026 at 01:44:03PM +0100, Nicolas Frattaroli wrote:
> On Wednesday, 25 March 2026 12:03:07 Central European Standard Time Ville Syrjälä wrote:
> > On Wed, Mar 25, 2026 at 09:24:27AM +0100, Maxime Ripard wrote:
> > > On Tue, Mar 24, 2026 at 09:53:35PM +0200, Ville Syrjälä wrote:
> > > > On Tue, Mar 24, 2026 at 08:10:11PM +0100, Nicolas Frattaroli wrote:
> > > > > On Tuesday, 24 March 2026 18:00:45 Central European Standard Time Ville Syrjälä wrote:
> > > > > > On Tue, Mar 24, 2026 at 05:01:07PM +0100, Nicolas Frattaroli wrote:
> > > > > > > +enum drm_connector_color_format {
> > > > > > > + /**
> > > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> > > > > > > + * helpers should pick a suitable color format. All implementations of a
> > > > > > > + * specific display protocol must behave the same way with "AUTO", but
> > > > > > > + * different display protocols do not necessarily have the same "AUTO"
> > > > > > > + * semantics.
> > > > > > > + *
> > > > > > > + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> > > > > > > + * bandwidth required for full-scale RGB is not available, or the mode
> > > > > > > + * is YCbCr 4:2:0-only, as long as the mode and output both support
> > > > > > > + * YCbCr 4:2:0.
> > > > > > > + *
> > > > > > > + * For display protocols other than HDMI, the recursive bridge chain
> > > > > > > + * format selection picks the first chain of bridge formats that works,
> > > > > > > + * as has already been the case before the introduction of the "color
> > > > > > > + * format" property. Non-HDMI bridges should therefore either sort their
> > > > > > > + * bus output formats by preference, or agree on a unified auto format
> > > > > > > + * selection logic that's implemented in a common state helper (like
> > > > > > > + * how HDMI does it).
> > > > > > > + */
> > > > > > > + DRM_CONNECTOR_COLOR_FORMAT_AUTO = 0,
> > > > > > > +
> > > > > > > + /**
> > > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_RGB444: RGB output format
> > > > > > > + */
> > > > > > > + DRM_CONNECTOR_COLOR_FORMAT_RGB444,
> > > > > > > +
> > > > > > > + /**
> > > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR444: YCbCr 4:4:4 output format (ie.
> > > > > > > + * not subsampled)
> > > > > > > + */
> > > > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR444,
> > > > > > > +
> > > > > > > + /**
> > > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR422: YCbCr 4:2:2 output format (ie.
> > > > > > > + * with horizontal subsampling)
> > > > > > > + */
> > > > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR422,
> > > > > > > +
> > > > > > > + /**
> > > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR420: YCbCr 4:2:0 output format (ie.
> > > > > > > + * with horizontal and vertical subsampling)
> > > > > > > + */
> > > > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR420,
> > > > > >
> > > > > > Seems like this should document what the quantization range
> > > > > > should be for each format.
> > > > > >
> > > > >
> > > > > I don't think so? If you want per-component bit depth values,
> > > > > DRM_FORMAT_* defines would be the appropriate values to use. This
> > > > > enum is more abstract than that, and is there to communicate
> > > > > YUV vs. RGB and chroma subsampling, with bit depth being handled
> > > > > by other properties.
> > > > >
> > > > > If you mean the factor used for subsampling, then that'd only be
> > > > > relevant if YCBCR410 was supported where one chroma plane isn't
> > > > > halved but quartered in resolution. I suspect 4:1:0 will never
> > > > > be added; no digital display protocol standard supports it to my
> > > > > knowledge, and hopefully none ever will.
> > > >
> > > > No, I mean the quantization range (16-235 vs. 0-255 etc).
> > > >
> > > > The i915 behaviour is that YCbCr is always limited range,
> > > > RGB can either be full or limited range depending on the
> > > > "Broadcast RGB" property and other related factors.
> > >
> > > So far the HDMI state has both the format and quantization range as
> > > different fields. I'm not sure we need to document the range in the
> > > format field, maybe only mention it's not part of the format but has a
> > > field of its own?
> >
> > I think we only have it for RGB (on some drivers only?). For YCbCr
> > I think the assumption is limited range everywhere.
> >
> > But I'm not really concerned about documenting struct members.
> > What I'm talking about is the *uapi* docs. Surely userspace
> > will want to know what the new property actually does so the
> > uapi needs to be documented properly. And down the line some
> > new driver might also implement the wrong behaviour if there
> > is no clear specification.
> >
> > So I'm thinking (or perhaps hoping) the rule might be something like:
> > - YCbCr limited range
> > - RGB full range if "Broadcast RGB" property is not present
> > - RGB full or limited range based on the "Broadcast RGB" property
> > if it's present
> >
> > I think the "Broadcast RGB" property itself might also be lacking
> > proper uapi docs, so that may need to be remedied as well.
> >
> >
>
> Alright, so in v12 I'll do the following:
>
> - Add a line to all YCBCR connector formats that specifies they're
> limited range as long as Broadcast RGB is limited. Whether it's limited
> range when Broadcast RGB is full is purposefully left undefined.
"Broadcast RGB", as the name implies, only affects RGB output.
> In the future, we can expand this to state they're limited range by
> default unless some other property is set. If we're not re-using
> Broadcast RGB for that, this will work out fine, because users who
> don't know about the eventual new property won't have this behaviour
> changed. If we do re-use "Broadcast RGB" for that, then only users
> relying on things we explicitly left undefined will get surprise
> full range YCBCR.
> - Add a line to the RGB connector format that specifies its range
> depends on the "Broadcast RGB" property
>
> This is a bit of a mess, because it's entirely reasonable that a
> future YCBCR range property would want to default to full range
> so that users get the most color out of their monitors. But with
> this description of the connector color formats, we can't do that.
>
> If there are alternate suggestions, I'm open for them. We can't
> really rename "Broadcast RGB" but if I had a time machine, that'd
> be my first choice.
>
> Kind regards,
> Nicolas Frattaroli
>
--
Ville Syrjälä
Intel
^ permalink raw reply [flat|nested] 48+ messages in thread* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
2026-03-26 13:07 ` Ville Syrjälä
@ 2026-03-26 13:26 ` Nicolas Frattaroli
0 siblings, 0 replies; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-26 13:26 UTC (permalink / raw)
To: Ville Syrjälä
Cc: Maxime Ripard, Harry Wentland, Leo Li, Rodrigo Siqueira,
Alex Deucher, Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Thomas Zimmermann, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Sandy Huang, Heiko Stübner, Andy Yan,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Dmitry Baryshkov, Sascha Hauer, Rob Herring, Jonathan Corbet,
Shuah Khan, kernel, amd-gfx, dri-devel, linux-kernel,
linux-arm-kernel, linux-rockchip, intel-gfx, intel-xe, linux-doc,
Werner Sembach, Andri Yngvason, Marius Vlad
On Thursday, 26 March 2026 14:07:15 Central European Standard Time Ville Syrjälä wrote:
> On Thu, Mar 26, 2026 at 01:44:03PM +0100, Nicolas Frattaroli wrote:
> > On Wednesday, 25 March 2026 12:03:07 Central European Standard Time Ville Syrjälä wrote:
> > > On Wed, Mar 25, 2026 at 09:24:27AM +0100, Maxime Ripard wrote:
> > > > On Tue, Mar 24, 2026 at 09:53:35PM +0200, Ville Syrjälä wrote:
> > > > > On Tue, Mar 24, 2026 at 08:10:11PM +0100, Nicolas Frattaroli wrote:
> > > > > > On Tuesday, 24 March 2026 18:00:45 Central European Standard Time Ville Syrjälä wrote:
> > > > > > > On Tue, Mar 24, 2026 at 05:01:07PM +0100, Nicolas Frattaroli wrote:
> > > > > > > > +enum drm_connector_color_format {
> > > > > > > > + /**
> > > > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> > > > > > > > + * helpers should pick a suitable color format. All implementations of a
> > > > > > > > + * specific display protocol must behave the same way with "AUTO", but
> > > > > > > > + * different display protocols do not necessarily have the same "AUTO"
> > > > > > > > + * semantics.
> > > > > > > > + *
> > > > > > > > + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> > > > > > > > + * bandwidth required for full-scale RGB is not available, or the mode
> > > > > > > > + * is YCbCr 4:2:0-only, as long as the mode and output both support
> > > > > > > > + * YCbCr 4:2:0.
> > > > > > > > + *
> > > > > > > > + * For display protocols other than HDMI, the recursive bridge chain
> > > > > > > > + * format selection picks the first chain of bridge formats that works,
> > > > > > > > + * as has already been the case before the introduction of the "color
> > > > > > > > + * format" property. Non-HDMI bridges should therefore either sort their
> > > > > > > > + * bus output formats by preference, or agree on a unified auto format
> > > > > > > > + * selection logic that's implemented in a common state helper (like
> > > > > > > > + * how HDMI does it).
> > > > > > > > + */
> > > > > > > > + DRM_CONNECTOR_COLOR_FORMAT_AUTO = 0,
> > > > > > > > +
> > > > > > > > + /**
> > > > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_RGB444: RGB output format
> > > > > > > > + */
> > > > > > > > + DRM_CONNECTOR_COLOR_FORMAT_RGB444,
> > > > > > > > +
> > > > > > > > + /**
> > > > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR444: YCbCr 4:4:4 output format (ie.
> > > > > > > > + * not subsampled)
> > > > > > > > + */
> > > > > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR444,
> > > > > > > > +
> > > > > > > > + /**
> > > > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR422: YCbCr 4:2:2 output format (ie.
> > > > > > > > + * with horizontal subsampling)
> > > > > > > > + */
> > > > > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR422,
> > > > > > > > +
> > > > > > > > + /**
> > > > > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR420: YCbCr 4:2:0 output format (ie.
> > > > > > > > + * with horizontal and vertical subsampling)
> > > > > > > > + */
> > > > > > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR420,
> > > > > > >
> > > > > > > Seems like this should document what the quantization range
> > > > > > > should be for each format.
> > > > > > >
> > > > > >
> > > > > > I don't think so? If you want per-component bit depth values,
> > > > > > DRM_FORMAT_* defines would be the appropriate values to use. This
> > > > > > enum is more abstract than that, and is there to communicate
> > > > > > YUV vs. RGB and chroma subsampling, with bit depth being handled
> > > > > > by other properties.
> > > > > >
> > > > > > If you mean the factor used for subsampling, then that'd only be
> > > > > > relevant if YCBCR410 was supported where one chroma plane isn't
> > > > > > halved but quartered in resolution. I suspect 4:1:0 will never
> > > > > > be added; no digital display protocol standard supports it to my
> > > > > > knowledge, and hopefully none ever will.
> > > > >
> > > > > No, I mean the quantization range (16-235 vs. 0-255 etc).
> > > > >
> > > > > The i915 behaviour is that YCbCr is always limited range,
> > > > > RGB can either be full or limited range depending on the
> > > > > "Broadcast RGB" property and other related factors.
> > > >
> > > > So far the HDMI state has both the format and quantization range as
> > > > different fields. I'm not sure we need to document the range in the
> > > > format field, maybe only mention it's not part of the format but has a
> > > > field of its own?
> > >
> > > I think we only have it for RGB (on some drivers only?). For YCbCr
> > > I think the assumption is limited range everywhere.
> > >
> > > But I'm not really concerned about documenting struct members.
> > > What I'm talking about is the *uapi* docs. Surely userspace
> > > will want to know what the new property actually does so the
> > > uapi needs to be documented properly. And down the line some
> > > new driver might also implement the wrong behaviour if there
> > > is no clear specification.
> > >
> > > So I'm thinking (or perhaps hoping) the rule might be something like:
> > > - YCbCr limited range
> > > - RGB full range if "Broadcast RGB" property is not present
> > > - RGB full or limited range based on the "Broadcast RGB" property
> > > if it's present
> > >
> > > I think the "Broadcast RGB" property itself might also be lacking
> > > proper uapi docs, so that may need to be remedied as well.
> > >
> > >
> >
> > Alright, so in v12 I'll do the following:
> >
> > - Add a line to all YCBCR connector formats that specifies they're
> > limited range as long as Broadcast RGB is limited. Whether it's limited
> > range when Broadcast RGB is full is purposefully left undefined.
>
> "Broadcast RGB", as the name implies, only affects RGB output.
Alright, I'll scratch the overcomplicated undefined behaviour thing
and just say it's limited range, and in the future, we can extend it
to limited range by default but full range if another new property is
set.
>
> > In the future, we can expand this to state they're limited range by
> > default unless some other property is set. If we're not re-using
> > Broadcast RGB for that, this will work out fine, because users who
> > don't know about the eventual new property won't have this behaviour
> > changed. If we do re-use "Broadcast RGB" for that, then only users
> > relying on things we explicitly left undefined will get surprise
> > full range YCBCR.
> > - Add a line to the RGB connector format that specifies its range
> > depends on the "Broadcast RGB" property
> >
> > This is a bit of a mess, because it's entirely reasonable that a
> > future YCBCR range property would want to default to full range
> > so that users get the most color out of their monitors. But with
> > this description of the connector color formats, we can't do that.
> >
> > If there are alternate suggestions, I'm open for them. We can't
> > really rename "Broadcast RGB" but if I had a time machine, that'd
> > be my first choice.
> >
> > Kind regards,
> > Nicolas Frattaroli
> >
>
>
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
2026-03-26 12:44 ` Nicolas Frattaroli
2026-03-26 13:07 ` Ville Syrjälä
@ 2026-03-26 16:40 ` Daniel Stone
1 sibling, 0 replies; 48+ messages in thread
From: Daniel Stone @ 2026-03-26 16:40 UTC (permalink / raw)
To: Nicolas Frattaroli
Cc: Maxime Ripard, Ville Syrjälä, Harry Wentland, Leo Li,
Rodrigo Siqueira, Alex Deucher, Christian König,
David Airlie, Simona Vetter, Maarten Lankhorst, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan, kernel, amd-gfx, dri-devel,
linux-kernel, linux-arm-kernel, linux-rockchip, intel-gfx,
intel-xe, linux-doc, Werner Sembach, Andri Yngvason, Marius Vlad
Hi there,
On Thu, 26 Mar 2026 at 12:44, Nicolas Frattaroli
<nicolas.frattaroli@collabora.com> wrote:
> On Wednesday, 25 March 2026 12:03:07 Central European Standard Time Ville Syrjälä wrote:
> > But I'm not really concerned about documenting struct members.
> > What I'm talking about is the *uapi* docs. Surely userspace
> > will want to know what the new property actually does so the
> > uapi needs to be documented properly. And down the line some
> > new driver might also implement the wrong behaviour if there
> > is no clear specification.
> >
> > So I'm thinking (or perhaps hoping) the rule might be something like:
> > - YCbCr limited range
> > - RGB full range if "Broadcast RGB" property is not present
> > - RGB full or limited range based on the "Broadcast RGB" property
> > if it's present
> >
> > I think the "Broadcast RGB" property itself might also be lacking
> > proper uapi docs, so that may need to be remedied as well.
>
> Alright, so in v12 I'll do the following:
>
> - Add a line to all YCBCR connector formats that specifies they're
> limited range as long as Broadcast RGB is limited. Whether it's limited
> range when Broadcast RGB is full is purposefully left undefined.
> In the future, we can expand this to state they're limited range by
> default unless some other property is set. If we're not re-using
> Broadcast RGB for that, this will work out fine, because users who
> don't know about the eventual new property won't have this behaviour
> changed. If we do re-use "Broadcast RGB" for that, then only users
> relying on things we explicitly left undefined will get surprise
> full range YCBCR.
> - Add a line to the RGB connector format that specifies its range
> depends on the "Broadcast RGB" property
>
> This is a bit of a mess, because it's entirely reasonable that a
> future YCBCR range property would want to default to full range
> so that users get the most color out of their monitors. But with
> this description of the connector color formats, we can't do that.
>
> If there are alternate suggestions, I'm open for them. We can't
> really rename "Broadcast RGB" but if I had a time machine, that'd
> be my first choice.
'Broadcast RGB' isn't what you want even if it could handle YUV, since
it also sets up colour transforms to modify the data ... so we need a
separate, orthogonal, property which only affects the HDMI infoframe,
rather than applying any transforms.
Cheers,
Daniel
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
2026-03-24 19:53 ` Ville Syrjälä
2026-03-25 8:24 ` Maxime Ripard
@ 2026-03-25 13:05 ` Nicolas Frattaroli
1 sibling, 0 replies; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-25 13:05 UTC (permalink / raw)
To: Ville Syrjälä
Cc: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan, kernel, amd-gfx, dri-devel,
linux-kernel, linux-arm-kernel, linux-rockchip, intel-gfx,
intel-xe, linux-doc, Werner Sembach, Andri Yngvason, Marius Vlad
On Tuesday, 24 March 2026 20:53:35 Central European Standard Time Ville Syrjälä wrote:
> On Tue, Mar 24, 2026 at 08:10:11PM +0100, Nicolas Frattaroli wrote:
> > On Tuesday, 24 March 2026 18:00:45 Central European Standard Time Ville Syrjälä wrote:
> > > On Tue, Mar 24, 2026 at 05:01:07PM +0100, Nicolas Frattaroli wrote:
> > > > +enum drm_connector_color_format {
> > > > + /**
> > > > + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> > > > + * helpers should pick a suitable color format. All implementations of a
> > > > + * specific display protocol must behave the same way with "AUTO", but
> > > > + * different display protocols do not necessarily have the same "AUTO"
> > > > + * semantics.
> > > > + *
> > > > + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> > > > + * bandwidth required for full-scale RGB is not available, or the mode
> > > > + * is YCbCr 4:2:0-only, as long as the mode and output both support
> > > > + * YCbCr 4:2:0.
> > > > + *
> > > > + * For display protocols other than HDMI, the recursive bridge chain
> > > > + * format selection picks the first chain of bridge formats that works,
> > > > + * as has already been the case before the introduction of the "color
> > > > + * format" property. Non-HDMI bridges should therefore either sort their
> > > > + * bus output formats by preference, or agree on a unified auto format
> > > > + * selection logic that's implemented in a common state helper (like
> > > > + * how HDMI does it).
> > > > + */
> > > > + DRM_CONNECTOR_COLOR_FORMAT_AUTO = 0,
> > > > +
> > > > + /**
> > > > + * @DRM_CONNECTOR_COLOR_FORMAT_RGB444: RGB output format
> > > > + */
> > > > + DRM_CONNECTOR_COLOR_FORMAT_RGB444,
> > > > +
> > > > + /**
> > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR444: YCbCr 4:4:4 output format (ie.
> > > > + * not subsampled)
> > > > + */
> > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR444,
> > > > +
> > > > + /**
> > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR422: YCbCr 4:2:2 output format (ie.
> > > > + * with horizontal subsampling)
> > > > + */
> > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR422,
> > > > +
> > > > + /**
> > > > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR420: YCbCr 4:2:0 output format (ie.
> > > > + * with horizontal and vertical subsampling)
> > > > + */
> > > > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR420,
> > >
> > > Seems like this should document what the quantization range
> > > should be for each format.
> > >
> >
> > I don't think so? If you want per-component bit depth values,
> > DRM_FORMAT_* defines would be the appropriate values to use. This
> > enum is more abstract than that, and is there to communicate
> > YUV vs. RGB and chroma subsampling, with bit depth being handled
> > by other properties.
> >
> > If you mean the factor used for subsampling, then that'd only be
> > relevant if YCBCR410 was supported where one chroma plane isn't
> > halved but quartered in resolution. I suspect 4:1:0 will never
> > be added; no digital display protocol standard supports it to my
> > knowledge, and hopefully none ever will.
>
> No, I mean the quantization range (16-235 vs. 0-255 etc).
>
> The i915 behaviour is that YCbCr is always limited range,
> RGB can either be full or limited range depending on the
> "Broadcast RGB" property and other related factors.
>
>
I do agree that this would be useful to be precise about, but I'm
not sure mainline is currently capable of even making a definitive
statement about this because every implementation will do its own
thing probably.
If we do add YCbCr quantization range as a separate property (though
I'd really would've loved it if "Broadcast RGB" was named differently
so it wouldn't be confusing if we overloaded that property's meaning
to also apply to YCbCr) then the resulting docs change for these
enums would be to say that quantization range is a separate property.
I do think making it separate is the best path forward, and I'm willing
to adjust the docs to mention this, but I think implementing YCbCr limited
versus full range in this series as well would drastically widen the scope
again.
Kind regards,
Nicolas Frattaroli
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
2026-03-24 16:01 ` [PATCH v11 03/22] drm: Add new general DRM property "color format" Nicolas Frattaroli
2026-03-24 17:00 ` Ville Syrjälä
@ 2026-03-25 12:49 ` Dave Stevenson
2026-03-25 13:05 ` Maxime Ripard
` (2 more replies)
1 sibling, 3 replies; 48+ messages in thread
From: Dave Stevenson @ 2026-03-25 12:49 UTC (permalink / raw)
To: Nicolas Frattaroli
Cc: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan, kernel, amd-gfx, dri-devel,
linux-kernel, linux-arm-kernel, linux-rockchip, intel-gfx,
intel-xe, linux-doc, Werner Sembach, Andri Yngvason, Marius Vlad
On Tue, 24 Mar 2026 at 16:02, Nicolas Frattaroli
<nicolas.frattaroli@collabora.com> wrote:
>
> Add a new general DRM property named "color format" which can be used by
> userspace to request the display driver to output a particular color
> format.
>
> Possible options are:
> - auto (setup by default, driver internally picks the color format)
> - rgb
> - ycbcr444
> - ycbcr422
> - ycbcr420
>
> Drivers should advertise from this list which formats they support.
> Together with this list and EDID data from the sink we should be able
> to relay a list of usable color formats to users to pick from.
>
> Co-developed-by: Werner Sembach <wse@tuxedocomputers.com>
> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
> Co-developed-by: Andri Yngvason <andri@yngvason.is>
> Signed-off-by: Andri Yngvason <andri@yngvason.is>
> Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
> Reviewed-by: Maxime Ripard <mripard@kernel.org>
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
> ---
> drivers/gpu/drm/drm_atomic_helper.c | 5 ++
> drivers/gpu/drm/drm_atomic_uapi.c | 11 ++++
> drivers/gpu/drm/drm_connector.c | 108 ++++++++++++++++++++++++++++++++++++
> include/drm/drm_connector.h | 104 ++++++++++++++++++++++++++++++++++
> 4 files changed, 228 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 26953ed6b53e..b7753454b777 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -737,6 +737,11 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
> if (old_connector_state->max_requested_bpc !=
> new_connector_state->max_requested_bpc)
> new_crtc_state->connectors_changed = true;
> +
> + if (old_connector_state->color_format !=
> + new_connector_state->color_format)
> + new_crtc_state->connectors_changed = true;
> +
> }
>
> if (funcs->atomic_check)
> diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
> index 5bd5bf6661df..dee510c85e59 100644
> --- a/drivers/gpu/drm/drm_atomic_uapi.c
> +++ b/drivers/gpu/drm/drm_atomic_uapi.c
> @@ -935,6 +935,15 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector,
> state->privacy_screen_sw_state = val;
> } else if (property == connector->broadcast_rgb_property) {
> state->hdmi.broadcast_rgb = val;
> + } else if (property == connector->color_format_property) {
> + if (val > INT_MAX || !drm_connector_color_format_valid(val)) {
> + drm_dbg_atomic(connector->dev,
> + "[CONNECTOR:%d:%s] unknown color format %llu\n",
> + connector->base.id, connector->name, val);
> + return -EINVAL;
> + }
> +
> + state->color_format = val;
> } else if (connector->funcs->atomic_set_property) {
> return connector->funcs->atomic_set_property(connector,
> state, property, val);
> @@ -1020,6 +1029,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
> *val = state->privacy_screen_sw_state;
> } else if (property == connector->broadcast_rgb_property) {
> *val = state->hdmi.broadcast_rgb;
> + } else if (property == connector->color_format_property) {
> + *val = state->color_format;
> } else if (connector->funcs->atomic_get_property) {
> return connector->funcs->atomic_get_property(connector,
> state, property, val);
> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> index 47dc53c4a738..e848374dee0b 100644
> --- a/drivers/gpu/drm/drm_connector.c
> +++ b/drivers/gpu/drm/drm_connector.c
> @@ -1388,6 +1388,18 @@ static const u32 hdmi_colorspaces =
> BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65) |
> BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER);
>
> +static const u32 hdmi_colorformats =
> + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
> + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
> + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
> + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
> +
> +static const u32 dp_colorformats =
> + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
> + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
> + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
> + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
> +
> /*
> * As per DP 1.4a spec, 2.2.5.7.5 VSC SDP Payload for Pixel Encoding/Colorimetry
> * Format Table 2-120
> @@ -2940,6 +2952,102 @@ int drm_connector_attach_colorspace_property(struct drm_connector *connector)
> }
> EXPORT_SYMBOL(drm_connector_attach_colorspace_property);
>
> +/**
> + * drm_connector_attach_color_format_property - create and attach color format property
> + * @connector: connector to create the color format property on
> + * @supported_color_formats: bitmask of bit-shifted &enum drm_output_color_format
> + * values the connector supports
> + *
> + * Called by a driver to create a color format property. The property is
> + * attached to the connector automatically on success.
> + *
> + * @supported_color_formats should only include color formats the connector
> + * type can actually support.
> + *
> + * Returns:
> + * 0 on success, negative errno on error
> + */
> +int drm_connector_attach_color_format_property(struct drm_connector *connector,
> + unsigned long supported_color_formats)
> +{
> + struct drm_device *dev = connector->dev;
> + struct drm_prop_enum_list enum_list[DRM_CONNECTOR_COLOR_FORMAT_COUNT];
> + unsigned int i = 0;
> + unsigned long fmt;
> +
> + if (connector->color_format_property)
> + return 0;
> +
> + if (!supported_color_formats) {
> + drm_err(dev, "No supported color formats provided on [CONNECTOR:%d:%s]\n",
> + connector->base.id, connector->name);
> + return -EINVAL;
> + }
> +
> + if (supported_color_formats & ~GENMASK(DRM_OUTPUT_COLOR_FORMAT_COUNT - 1, 0)) {
> + drm_err(dev, "Unknown color formats provided on [CONNECTOR:%d:%s]\n",
> + connector->base.id, connector->name);
> + return -EINVAL;
> + }
> +
> + switch (connector->connector_type) {
> + case DRM_MODE_CONNECTOR_HDMIA:
> + case DRM_MODE_CONNECTOR_HDMIB:
> + if (supported_color_formats & ~hdmi_colorformats) {
> + drm_err(dev, "Color formats not allowed for HDMI on [CONNECTOR:%d:%s]\n",
> + connector->base.id, connector->name);
> + return -EINVAL;
> + }
> + break;
> + case DRM_MODE_CONNECTOR_DisplayPort:
> + case DRM_MODE_CONNECTOR_eDP:
> + if (supported_color_formats & ~dp_colorformats) {
> + drm_err(dev, "Color formats not allowed for DP on [CONNECTOR:%d:%s]\n",
> + connector->base.id, connector->name);
> + return -EINVAL;
> + }
> + break;
> + }
> +
> + enum_list[0].name = "AUTO";
> + enum_list[0].type = DRM_CONNECTOR_COLOR_FORMAT_AUTO;
> +
> + for_each_set_bit(fmt, &supported_color_formats, DRM_OUTPUT_COLOR_FORMAT_COUNT) {
> + switch (fmt) {
> + case DRM_OUTPUT_COLOR_FORMAT_RGB444:
> + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_RGB444;
> + break;
> + case DRM_OUTPUT_COLOR_FORMAT_YCBCR444:
> + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR444;
> + break;
> + case DRM_OUTPUT_COLOR_FORMAT_YCBCR422:
> + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR422;
> + break;
> + case DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
> + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR420;
> + break;
> + default:
> + drm_warn(dev, "Unknown supported format %ld on [CONNECTOR:%d:%s]\n",
> + fmt, connector->base.id, connector->name);
> + continue;
> + }
> + enum_list[i].name = drm_hdmi_connector_get_output_format_name(fmt);
> + }
> +
> + connector->color_format_property =
> + drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, "color format",
> + enum_list, i + 1);
> +
> + if (!connector->color_format_property)
> + return -ENOMEM;
> +
> + drm_object_attach_property(&connector->base, connector->color_format_property,
> + DRM_CONNECTOR_COLOR_FORMAT_AUTO);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(drm_connector_attach_color_format_property);
> +
> /**
> * drm_connector_atomic_hdr_metadata_equal - checks if the hdr metadata changed
> * @old_state: old connector state to compare
> diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> index af8b92d2d5b7..bd549f912b76 100644
> --- a/include/drm/drm_connector.h
> +++ b/include/drm/drm_connector.h
> @@ -571,14 +571,102 @@ enum drm_colorspace {
> * YCbCr 4:2:2 output format (ie. with horizontal subsampling)
> * @DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
> * YCbCr 4:2:0 output format (ie. with horizontal and vertical subsampling)
> + * @DRM_OUTPUT_COLOR_FORMAT_COUNT:
> + * Number of valid output color format values in this enum
> */
> enum drm_output_color_format {
> DRM_OUTPUT_COLOR_FORMAT_RGB444 = 0,
> DRM_OUTPUT_COLOR_FORMAT_YCBCR444,
> DRM_OUTPUT_COLOR_FORMAT_YCBCR422,
> DRM_OUTPUT_COLOR_FORMAT_YCBCR420,
> + DRM_OUTPUT_COLOR_FORMAT_COUNT,
> };
>
> +/**
> + * enum drm_connector_color_format - Connector Color Format Request
> + *
> + * This enum, unlike &enum drm_output_color_format, is used to specify requests
> + * for a specific color format on a connector through the DRM "color format"
> + * property. The difference is that it has an "AUTO" value to specify that
> + * no specific choice has been made.
> + */
> +enum drm_connector_color_format {
> + /**
> + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> + * helpers should pick a suitable color format. All implementations of a
> + * specific display protocol must behave the same way with "AUTO", but
> + * different display protocols do not necessarily have the same "AUTO"
> + * semantics.
> + *
> + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> + * bandwidth required for full-scale RGB is not available, or the mode
> + * is YCbCr 4:2:0-only, as long as the mode and output both support
> + * YCbCr 4:2:0.
Is there a reason you propose dropping back to YCbCr 4:2:0 without
trying YCbCr 4:2:2 first? Minimising the subsampling is surely
beneficial, and vc4 for one can do 4:2:2 but not 4:2:0.
Dave
> + *
> + * For display protocols other than HDMI, the recursive bridge chain
> + * format selection picks the first chain of bridge formats that works,
> + * as has already been the case before the introduction of the "color
> + * format" property. Non-HDMI bridges should therefore either sort their
> + * bus output formats by preference, or agree on a unified auto format
> + * selection logic that's implemented in a common state helper (like
> + * how HDMI does it).
> + */
> + DRM_CONNECTOR_COLOR_FORMAT_AUTO = 0,
> +
> + /**
> + * @DRM_CONNECTOR_COLOR_FORMAT_RGB444: RGB output format
> + */
> + DRM_CONNECTOR_COLOR_FORMAT_RGB444,
> +
> + /**
> + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR444: YCbCr 4:4:4 output format (ie.
> + * not subsampled)
> + */
> + DRM_CONNECTOR_COLOR_FORMAT_YCBCR444,
> +
> + /**
> + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR422: YCbCr 4:2:2 output format (ie.
> + * with horizontal subsampling)
> + */
> + DRM_CONNECTOR_COLOR_FORMAT_YCBCR422,
> +
> + /**
> + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR420: YCbCr 4:2:0 output format (ie.
> + * with horizontal and vertical subsampling)
> + */
> + DRM_CONNECTOR_COLOR_FORMAT_YCBCR420,
> +
> + /**
> + * @DRM_CONNECTOR_COLOR_FORMAT_COUNT: Number of valid connector color
> + * format values in this enum
> + */
> + DRM_CONNECTOR_COLOR_FORMAT_COUNT,
> +};
> +
> +/**
> + * drm_connector_color_format_valid - Validate drm_connector_color_format value
> + * @fmt: value to check against all values of &enum drm_connector_color_format
> + *
> + * Checks whether the passed in value of @fmt is one of the allowable values in
> + * &enum drm_connector_color_format.
> + *
> + * Returns: %true if it's a valid value for the enum, %false otherwise.
> + */
> +static inline bool __pure
> +drm_connector_color_format_valid(enum drm_connector_color_format fmt)
> +{
> + switch (fmt) {
> + case DRM_CONNECTOR_COLOR_FORMAT_AUTO:
> + case DRM_CONNECTOR_COLOR_FORMAT_RGB444:
> + case DRM_CONNECTOR_COLOR_FORMAT_YCBCR444:
> + case DRM_CONNECTOR_COLOR_FORMAT_YCBCR422:
> + case DRM_CONNECTOR_COLOR_FORMAT_YCBCR420:
> + return true;
> + default:
> + return false;
> + }
> +}
> +
> const char *
> drm_hdmi_connector_get_output_format_name(enum drm_output_color_format fmt);
>
> @@ -1129,6 +1217,13 @@ struct drm_connector_state {
> */
> enum drm_colorspace colorspace;
>
> + /**
> + * @color_format: State variable for Connector property to request
> + * color format change on Sink. This is most commonly used to switch
> + * between RGB to YUV and vice-versa.
> + */
> + enum drm_connector_color_format color_format;
> +
> /**
> * @writeback_job: Writeback job for writeback connectors
> *
> @@ -2127,6 +2222,12 @@ struct drm_connector {
> */
> struct drm_property *colorspace_property;
>
> + /**
> + * @color_format_property: Connector property to set the suitable
> + * color format supported by the sink.
> + */
> + struct drm_property *color_format_property;
> +
> /**
> * @path_blob_ptr:
> *
> @@ -2610,6 +2711,9 @@ bool drm_connector_has_possible_encoder(struct drm_connector *connector,
> struct drm_encoder *encoder);
> const char *drm_get_colorspace_name(enum drm_colorspace colorspace);
>
> +int drm_connector_attach_color_format_property(struct drm_connector *connector,
> + unsigned long supported_color_formats);
> +
> /**
> * drm_for_each_connector_iter - connector_list iterator macro
> * @connector: &struct drm_connector pointer used as cursor
>
> --
> 2.53.0
>
^ permalink raw reply [flat|nested] 48+ messages in thread* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
2026-03-25 12:49 ` Dave Stevenson
@ 2026-03-25 13:05 ` Maxime Ripard
2026-03-25 13:21 ` Nicolas Frattaroli
2026-03-25 13:11 ` Nicolas Frattaroli
2026-03-25 13:43 ` Ville Syrjälä
2 siblings, 1 reply; 48+ messages in thread
From: Maxime Ripard @ 2026-03-25 13:05 UTC (permalink / raw)
To: Dave Stevenson
Cc: Nicolas Frattaroli, Harry Wentland, Leo Li, Rodrigo Siqueira,
Alex Deucher, Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Thomas Zimmermann, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Sandy Huang, Heiko Stübner, Andy Yan,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Dmitry Baryshkov, Sascha Hauer, Rob Herring, Jonathan Corbet,
Shuah Khan, kernel, amd-gfx, dri-devel, linux-kernel,
linux-arm-kernel, linux-rockchip, intel-gfx, intel-xe, linux-doc,
Werner Sembach, Andri Yngvason, Marius Vlad
[-- Attachment #1: Type: text/plain, Size: 2493 bytes --]
Hi Dave,
On Wed, Mar 25, 2026 at 12:49:19PM +0000, Dave Stevenson wrote:
> > diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> > index af8b92d2d5b7..bd549f912b76 100644
> > --- a/include/drm/drm_connector.h
> > +++ b/include/drm/drm_connector.h
> > @@ -571,14 +571,102 @@ enum drm_colorspace {
> > * YCbCr 4:2:2 output format (ie. with horizontal subsampling)
> > * @DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
> > * YCbCr 4:2:0 output format (ie. with horizontal and vertical subsampling)
> > + * @DRM_OUTPUT_COLOR_FORMAT_COUNT:
> > + * Number of valid output color format values in this enum
> > */
> > enum drm_output_color_format {
> > DRM_OUTPUT_COLOR_FORMAT_RGB444 = 0,
> > DRM_OUTPUT_COLOR_FORMAT_YCBCR444,
> > DRM_OUTPUT_COLOR_FORMAT_YCBCR422,
> > DRM_OUTPUT_COLOR_FORMAT_YCBCR420,
> > + DRM_OUTPUT_COLOR_FORMAT_COUNT,
> > };
> >
> > +/**
> > + * enum drm_connector_color_format - Connector Color Format Request
> > + *
> > + * This enum, unlike &enum drm_output_color_format, is used to specify requests
> > + * for a specific color format on a connector through the DRM "color format"
> > + * property. The difference is that it has an "AUTO" value to specify that
> > + * no specific choice has been made.
> > + */
> > +enum drm_connector_color_format {
> > + /**
> > + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> > + * helpers should pick a suitable color format. All implementations of a
> > + * specific display protocol must behave the same way with "AUTO", but
> > + * different display protocols do not necessarily have the same "AUTO"
> > + * semantics.
> > + *
> > + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> > + * bandwidth required for full-scale RGB is not available, or the mode
> > + * is YCbCr 4:2:0-only, as long as the mode and output both support
> > + * YCbCr 4:2:0.
>
> Is there a reason you propose dropping back to YCbCr 4:2:0 without
> trying YCbCr 4:2:2 first? Minimising the subsampling is surely
> beneficial, and vc4 for one can do 4:2:2 but not 4:2:0.
The "auto" behaviour is strictly identical to the one we have right now,
and this one stems from i915. Back when all that logic was added, it was
decided to align every driver behavior on i915 because that's what most
compositors would expect.
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply [flat|nested] 48+ messages in thread* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
2026-03-25 13:05 ` Maxime Ripard
@ 2026-03-25 13:21 ` Nicolas Frattaroli
2026-03-25 13:44 ` Maxime Ripard
0 siblings, 1 reply; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-25 13:21 UTC (permalink / raw)
To: Dave Stevenson, Maxime Ripard
Cc: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Thomas Zimmermann, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Sandy Huang, Heiko Stübner, Andy Yan,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Dmitry Baryshkov, Sascha Hauer, Rob Herring, Jonathan Corbet,
Shuah Khan, kernel, amd-gfx, dri-devel, linux-kernel,
linux-arm-kernel, linux-rockchip, intel-gfx, intel-xe, linux-doc,
Werner Sembach, Andri Yngvason, Marius Vlad
On Wednesday, 25 March 2026 14:05:25 Central European Standard Time Maxime Ripard wrote:
> Hi Dave,
>
> On Wed, Mar 25, 2026 at 12:49:19PM +0000, Dave Stevenson wrote:
> > > diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> > > index af8b92d2d5b7..bd549f912b76 100644
> > > --- a/include/drm/drm_connector.h
> > > +++ b/include/drm/drm_connector.h
> > > @@ -571,14 +571,102 @@ enum drm_colorspace {
> > > * YCbCr 4:2:2 output format (ie. with horizontal subsampling)
> > > * @DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
> > > * YCbCr 4:2:0 output format (ie. with horizontal and vertical subsampling)
> > > + * @DRM_OUTPUT_COLOR_FORMAT_COUNT:
> > > + * Number of valid output color format values in this enum
> > > */
> > > enum drm_output_color_format {
> > > DRM_OUTPUT_COLOR_FORMAT_RGB444 = 0,
> > > DRM_OUTPUT_COLOR_FORMAT_YCBCR444,
> > > DRM_OUTPUT_COLOR_FORMAT_YCBCR422,
> > > DRM_OUTPUT_COLOR_FORMAT_YCBCR420,
> > > + DRM_OUTPUT_COLOR_FORMAT_COUNT,
> > > };
> > >
> > > +/**
> > > + * enum drm_connector_color_format - Connector Color Format Request
> > > + *
> > > + * This enum, unlike &enum drm_output_color_format, is used to specify requests
> > > + * for a specific color format on a connector through the DRM "color format"
> > > + * property. The difference is that it has an "AUTO" value to specify that
> > > + * no specific choice has been made.
> > > + */
> > > +enum drm_connector_color_format {
> > > + /**
> > > + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> > > + * helpers should pick a suitable color format. All implementations of a
> > > + * specific display protocol must behave the same way with "AUTO", but
> > > + * different display protocols do not necessarily have the same "AUTO"
> > > + * semantics.
> > > + *
> > > + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> > > + * bandwidth required for full-scale RGB is not available, or the mode
> > > + * is YCbCr 4:2:0-only, as long as the mode and output both support
> > > + * YCbCr 4:2:0.
> >
> > Is there a reason you propose dropping back to YCbCr 4:2:0 without
> > trying YCbCr 4:2:2 first? Minimising the subsampling is surely
> > beneficial, and vc4 for one can do 4:2:2 but not 4:2:0.
>
> The "auto" behaviour is strictly identical to the one we have right now,
> and this one stems from i915. Back when all that logic was added, it was
> decided to align every driver behavior on i915 because that's what most
> compositors would expect.
Hi Maxime,
would it be okay to extend the behavior while we're at it? 4:2:2 does save
bandwidth compared to RGB (unlike YCbCr 4:4:4). I do think 4:2:2 instead of
4:2:0 will provide benefits in some cases. I assume hardware that supports
4:2:2 only instead of 4:2:0 does so in order to save >= 1 horizontal
row of local SRAM buffer in the display controller for any downscaling,
as it'll only need to consider neighbouring pixels on the same row.
Kind regards,
Nicolas Frattaroli
>
> Maxime
>
^ permalink raw reply [flat|nested] 48+ messages in thread* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
2026-03-25 13:21 ` Nicolas Frattaroli
@ 2026-03-25 13:44 ` Maxime Ripard
0 siblings, 0 replies; 48+ messages in thread
From: Maxime Ripard @ 2026-03-25 13:44 UTC (permalink / raw)
To: Nicolas Frattaroli
Cc: Dave Stevenson, Harry Wentland, Leo Li, Rodrigo Siqueira,
Alex Deucher, Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Thomas Zimmermann, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Sandy Huang, Heiko Stübner, Andy Yan,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Dmitry Baryshkov, Sascha Hauer, Rob Herring, Jonathan Corbet,
Shuah Khan, kernel, amd-gfx, dri-devel, linux-kernel,
linux-arm-kernel, linux-rockchip, intel-gfx, intel-xe, linux-doc,
Werner Sembach, Andri Yngvason, Marius Vlad
[-- Attachment #1: Type: text/plain, Size: 3249 bytes --]
On Wed, Mar 25, 2026 at 02:21:24PM +0100, Nicolas Frattaroli wrote:
> On Wednesday, 25 March 2026 14:05:25 Central European Standard Time Maxime Ripard wrote:
> > Hi Dave,
> >
> > On Wed, Mar 25, 2026 at 12:49:19PM +0000, Dave Stevenson wrote:
> > > > diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> > > > index af8b92d2d5b7..bd549f912b76 100644
> > > > --- a/include/drm/drm_connector.h
> > > > +++ b/include/drm/drm_connector.h
> > > > @@ -571,14 +571,102 @@ enum drm_colorspace {
> > > > * YCbCr 4:2:2 output format (ie. with horizontal subsampling)
> > > > * @DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
> > > > * YCbCr 4:2:0 output format (ie. with horizontal and vertical subsampling)
> > > > + * @DRM_OUTPUT_COLOR_FORMAT_COUNT:
> > > > + * Number of valid output color format values in this enum
> > > > */
> > > > enum drm_output_color_format {
> > > > DRM_OUTPUT_COLOR_FORMAT_RGB444 = 0,
> > > > DRM_OUTPUT_COLOR_FORMAT_YCBCR444,
> > > > DRM_OUTPUT_COLOR_FORMAT_YCBCR422,
> > > > DRM_OUTPUT_COLOR_FORMAT_YCBCR420,
> > > > + DRM_OUTPUT_COLOR_FORMAT_COUNT,
> > > > };
> > > >
> > > > +/**
> > > > + * enum drm_connector_color_format - Connector Color Format Request
> > > > + *
> > > > + * This enum, unlike &enum drm_output_color_format, is used to specify requests
> > > > + * for a specific color format on a connector through the DRM "color format"
> > > > + * property. The difference is that it has an "AUTO" value to specify that
> > > > + * no specific choice has been made.
> > > > + */
> > > > +enum drm_connector_color_format {
> > > > + /**
> > > > + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> > > > + * helpers should pick a suitable color format. All implementations of a
> > > > + * specific display protocol must behave the same way with "AUTO", but
> > > > + * different display protocols do not necessarily have the same "AUTO"
> > > > + * semantics.
> > > > + *
> > > > + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> > > > + * bandwidth required for full-scale RGB is not available, or the mode
> > > > + * is YCbCr 4:2:0-only, as long as the mode and output both support
> > > > + * YCbCr 4:2:0.
> > >
> > > Is there a reason you propose dropping back to YCbCr 4:2:0 without
> > > trying YCbCr 4:2:2 first? Minimising the subsampling is surely
> > > beneficial, and vc4 for one can do 4:2:2 but not 4:2:0.
> >
> > The "auto" behaviour is strictly identical to the one we have right now,
> > and this one stems from i915. Back when all that logic was added, it was
> > decided to align every driver behavior on i915 because that's what most
> > compositors would expect.
>
> would it be okay to extend the behavior while we're at it? 4:2:2 does save
> bandwidth compared to RGB (unlike YCbCr 4:4:4). I do think 4:2:2 instead of
> 4:2:0 will provide benefits in some cases.
I don't really know, we would need to ask some Wayland/Weston devs as
well, but it sure is something worth discussing.
I wouldn't do it in this series but as a follow-up though.
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
2026-03-25 12:49 ` Dave Stevenson
2026-03-25 13:05 ` Maxime Ripard
@ 2026-03-25 13:11 ` Nicolas Frattaroli
2026-03-25 13:43 ` Ville Syrjälä
2 siblings, 0 replies; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-25 13:11 UTC (permalink / raw)
To: Dave Stevenson
Cc: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan, kernel, amd-gfx, dri-devel,
linux-kernel, linux-arm-kernel, linux-rockchip, intel-gfx,
intel-xe, linux-doc, Werner Sembach, Andri Yngvason, Marius Vlad
On Wednesday, 25 March 2026 13:49:19 Central European Standard Time Dave Stevenson wrote:
> On Tue, 24 Mar 2026 at 16:02, Nicolas Frattaroli
> <nicolas.frattaroli@collabora.com> wrote:
> >
> > Add a new general DRM property named "color format" which can be used by
> > userspace to request the display driver to output a particular color
> > format.
> >
> > Possible options are:
> > - auto (setup by default, driver internally picks the color format)
> > - rgb
> > - ycbcr444
> > - ycbcr422
> > - ycbcr420
> >
> > Drivers should advertise from this list which formats they support.
> > Together with this list and EDID data from the sink we should be able
> > to relay a list of usable color formats to users to pick from.
> >
> > Co-developed-by: Werner Sembach <wse@tuxedocomputers.com>
> > Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
> > Co-developed-by: Andri Yngvason <andri@yngvason.is>
> > Signed-off-by: Andri Yngvason <andri@yngvason.is>
> > Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
> > Reviewed-by: Maxime Ripard <mripard@kernel.org>
> > Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
> > ---
> > drivers/gpu/drm/drm_atomic_helper.c | 5 ++
> > drivers/gpu/drm/drm_atomic_uapi.c | 11 ++++
> > drivers/gpu/drm/drm_connector.c | 108 ++++++++++++++++++++++++++++++++++++
> > include/drm/drm_connector.h | 104 ++++++++++++++++++++++++++++++++++
> > 4 files changed, 228 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> > index 26953ed6b53e..b7753454b777 100644
> > --- a/drivers/gpu/drm/drm_atomic_helper.c
> > +++ b/drivers/gpu/drm/drm_atomic_helper.c
> > @@ -737,6 +737,11 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
> > if (old_connector_state->max_requested_bpc !=
> > new_connector_state->max_requested_bpc)
> > new_crtc_state->connectors_changed = true;
> > +
> > + if (old_connector_state->color_format !=
> > + new_connector_state->color_format)
> > + new_crtc_state->connectors_changed = true;
> > +
> > }
> >
> > if (funcs->atomic_check)
> > diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
> > index 5bd5bf6661df..dee510c85e59 100644
> > --- a/drivers/gpu/drm/drm_atomic_uapi.c
> > +++ b/drivers/gpu/drm/drm_atomic_uapi.c
> > @@ -935,6 +935,15 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector,
> > state->privacy_screen_sw_state = val;
> > } else if (property == connector->broadcast_rgb_property) {
> > state->hdmi.broadcast_rgb = val;
> > + } else if (property == connector->color_format_property) {
> > + if (val > INT_MAX || !drm_connector_color_format_valid(val)) {
> > + drm_dbg_atomic(connector->dev,
> > + "[CONNECTOR:%d:%s] unknown color format %llu\n",
> > + connector->base.id, connector->name, val);
> > + return -EINVAL;
> > + }
> > +
> > + state->color_format = val;
> > } else if (connector->funcs->atomic_set_property) {
> > return connector->funcs->atomic_set_property(connector,
> > state, property, val);
> > @@ -1020,6 +1029,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
> > *val = state->privacy_screen_sw_state;
> > } else if (property == connector->broadcast_rgb_property) {
> > *val = state->hdmi.broadcast_rgb;
> > + } else if (property == connector->color_format_property) {
> > + *val = state->color_format;
> > } else if (connector->funcs->atomic_get_property) {
> > return connector->funcs->atomic_get_property(connector,
> > state, property, val);
> > diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> > index 47dc53c4a738..e848374dee0b 100644
> > --- a/drivers/gpu/drm/drm_connector.c
> > +++ b/drivers/gpu/drm/drm_connector.c
> > @@ -1388,6 +1388,18 @@ static const u32 hdmi_colorspaces =
> > BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65) |
> > BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER);
> >
> > +static const u32 hdmi_colorformats =
> > + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
> > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
> > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
> > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
> > +
> > +static const u32 dp_colorformats =
> > + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
> > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
> > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
> > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
> > +
> > /*
> > * As per DP 1.4a spec, 2.2.5.7.5 VSC SDP Payload for Pixel Encoding/Colorimetry
> > * Format Table 2-120
> > @@ -2940,6 +2952,102 @@ int drm_connector_attach_colorspace_property(struct drm_connector *connector)
> > }
> > EXPORT_SYMBOL(drm_connector_attach_colorspace_property);
> >
> > +/**
> > + * drm_connector_attach_color_format_property - create and attach color format property
> > + * @connector: connector to create the color format property on
> > + * @supported_color_formats: bitmask of bit-shifted &enum drm_output_color_format
> > + * values the connector supports
> > + *
> > + * Called by a driver to create a color format property. The property is
> > + * attached to the connector automatically on success.
> > + *
> > + * @supported_color_formats should only include color formats the connector
> > + * type can actually support.
> > + *
> > + * Returns:
> > + * 0 on success, negative errno on error
> > + */
> > +int drm_connector_attach_color_format_property(struct drm_connector *connector,
> > + unsigned long supported_color_formats)
> > +{
> > + struct drm_device *dev = connector->dev;
> > + struct drm_prop_enum_list enum_list[DRM_CONNECTOR_COLOR_FORMAT_COUNT];
> > + unsigned int i = 0;
> > + unsigned long fmt;
> > +
> > + if (connector->color_format_property)
> > + return 0;
> > +
> > + if (!supported_color_formats) {
> > + drm_err(dev, "No supported color formats provided on [CONNECTOR:%d:%s]\n",
> > + connector->base.id, connector->name);
> > + return -EINVAL;
> > + }
> > +
> > + if (supported_color_formats & ~GENMASK(DRM_OUTPUT_COLOR_FORMAT_COUNT - 1, 0)) {
> > + drm_err(dev, "Unknown color formats provided on [CONNECTOR:%d:%s]\n",
> > + connector->base.id, connector->name);
> > + return -EINVAL;
> > + }
> > +
> > + switch (connector->connector_type) {
> > + case DRM_MODE_CONNECTOR_HDMIA:
> > + case DRM_MODE_CONNECTOR_HDMIB:
> > + if (supported_color_formats & ~hdmi_colorformats) {
> > + drm_err(dev, "Color formats not allowed for HDMI on [CONNECTOR:%d:%s]\n",
> > + connector->base.id, connector->name);
> > + return -EINVAL;
> > + }
> > + break;
> > + case DRM_MODE_CONNECTOR_DisplayPort:
> > + case DRM_MODE_CONNECTOR_eDP:
> > + if (supported_color_formats & ~dp_colorformats) {
> > + drm_err(dev, "Color formats not allowed for DP on [CONNECTOR:%d:%s]\n",
> > + connector->base.id, connector->name);
> > + return -EINVAL;
> > + }
> > + break;
> > + }
> > +
> > + enum_list[0].name = "AUTO";
> > + enum_list[0].type = DRM_CONNECTOR_COLOR_FORMAT_AUTO;
> > +
> > + for_each_set_bit(fmt, &supported_color_formats, DRM_OUTPUT_COLOR_FORMAT_COUNT) {
> > + switch (fmt) {
> > + case DRM_OUTPUT_COLOR_FORMAT_RGB444:
> > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_RGB444;
> > + break;
> > + case DRM_OUTPUT_COLOR_FORMAT_YCBCR444:
> > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR444;
> > + break;
> > + case DRM_OUTPUT_COLOR_FORMAT_YCBCR422:
> > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR422;
> > + break;
> > + case DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
> > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR420;
> > + break;
> > + default:
> > + drm_warn(dev, "Unknown supported format %ld on [CONNECTOR:%d:%s]\n",
> > + fmt, connector->base.id, connector->name);
> > + continue;
> > + }
> > + enum_list[i].name = drm_hdmi_connector_get_output_format_name(fmt);
> > + }
> > +
> > + connector->color_format_property =
> > + drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, "color format",
> > + enum_list, i + 1);
> > +
> > + if (!connector->color_format_property)
> > + return -ENOMEM;
> > +
> > + drm_object_attach_property(&connector->base, connector->color_format_property,
> > + DRM_CONNECTOR_COLOR_FORMAT_AUTO);
> > +
> > + return 0;
> > +}
> > +EXPORT_SYMBOL(drm_connector_attach_color_format_property);
> > +
> > /**
> > * drm_connector_atomic_hdr_metadata_equal - checks if the hdr metadata changed
> > * @old_state: old connector state to compare
> > diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> > index af8b92d2d5b7..bd549f912b76 100644
> > --- a/include/drm/drm_connector.h
> > +++ b/include/drm/drm_connector.h
> > @@ -571,14 +571,102 @@ enum drm_colorspace {
> > * YCbCr 4:2:2 output format (ie. with horizontal subsampling)
> > * @DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
> > * YCbCr 4:2:0 output format (ie. with horizontal and vertical subsampling)
> > + * @DRM_OUTPUT_COLOR_FORMAT_COUNT:
> > + * Number of valid output color format values in this enum
> > */
> > enum drm_output_color_format {
> > DRM_OUTPUT_COLOR_FORMAT_RGB444 = 0,
> > DRM_OUTPUT_COLOR_FORMAT_YCBCR444,
> > DRM_OUTPUT_COLOR_FORMAT_YCBCR422,
> > DRM_OUTPUT_COLOR_FORMAT_YCBCR420,
> > + DRM_OUTPUT_COLOR_FORMAT_COUNT,
> > };
> >
> > +/**
> > + * enum drm_connector_color_format - Connector Color Format Request
> > + *
> > + * This enum, unlike &enum drm_output_color_format, is used to specify requests
> > + * for a specific color format on a connector through the DRM "color format"
> > + * property. The difference is that it has an "AUTO" value to specify that
> > + * no specific choice has been made.
> > + */
> > +enum drm_connector_color_format {
> > + /**
> > + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> > + * helpers should pick a suitable color format. All implementations of a
> > + * specific display protocol must behave the same way with "AUTO", but
> > + * different display protocols do not necessarily have the same "AUTO"
> > + * semantics.
> > + *
> > + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> > + * bandwidth required for full-scale RGB is not available, or the mode
> > + * is YCbCr 4:2:0-only, as long as the mode and output both support
> > + * YCbCr 4:2:0.
>
> Is there a reason you propose dropping back to YCbCr 4:2:0 without
> trying YCbCr 4:2:2 first? Minimising the subsampling is surely
> beneficial, and vc4 for one can do 4:2:2 but not 4:2:0.
I worked under the assumption that 4:2:0 was more common than 4:2:2 based
on the existing HDMI state helper code that also doesn't try 4:2:2 first.
But this is a good point, it should try 4:2:2 as well (at least on
implementations where it's supported, e.g. i915 does not support 4:2:2 at
all from what I see.)
Kind regards,
Nicolas Frattaroli
>
> Dave
>
> > + *
> > + * For display protocols other than HDMI, the recursive bridge chain
> > + * format selection picks the first chain of bridge formats that works,
> > + * as has already been the case before the introduction of the "color
> > + * format" property. Non-HDMI bridges should therefore either sort their
> > + * bus output formats by preference, or agree on a unified auto format
> > + * selection logic that's implemented in a common state helper (like
> > + * how HDMI does it).
> > + */
> > + DRM_CONNECTOR_COLOR_FORMAT_AUTO = 0,
> > +
> > + /**
> > + * @DRM_CONNECTOR_COLOR_FORMAT_RGB444: RGB output format
> > + */
> > + DRM_CONNECTOR_COLOR_FORMAT_RGB444,
> > +
> > + /**
> > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR444: YCbCr 4:4:4 output format (ie.
> > + * not subsampled)
> > + */
> > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR444,
> > +
> > + /**
> > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR422: YCbCr 4:2:2 output format (ie.
> > + * with horizontal subsampling)
> > + */
> > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR422,
> > +
> > + /**
> > + * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR420: YCbCr 4:2:0 output format (ie.
> > + * with horizontal and vertical subsampling)
> > + */
> > + DRM_CONNECTOR_COLOR_FORMAT_YCBCR420,
> > +
> > + /**
> > + * @DRM_CONNECTOR_COLOR_FORMAT_COUNT: Number of valid connector color
> > + * format values in this enum
> > + */
> > + DRM_CONNECTOR_COLOR_FORMAT_COUNT,
> > +};
> > +
> > +/**
> > + * drm_connector_color_format_valid - Validate drm_connector_color_format value
> > + * @fmt: value to check against all values of &enum drm_connector_color_format
> > + *
> > + * Checks whether the passed in value of @fmt is one of the allowable values in
> > + * &enum drm_connector_color_format.
> > + *
> > + * Returns: %true if it's a valid value for the enum, %false otherwise.
> > + */
> > +static inline bool __pure
> > +drm_connector_color_format_valid(enum drm_connector_color_format fmt)
> > +{
> > + switch (fmt) {
> > + case DRM_CONNECTOR_COLOR_FORMAT_AUTO:
> > + case DRM_CONNECTOR_COLOR_FORMAT_RGB444:
> > + case DRM_CONNECTOR_COLOR_FORMAT_YCBCR444:
> > + case DRM_CONNECTOR_COLOR_FORMAT_YCBCR422:
> > + case DRM_CONNECTOR_COLOR_FORMAT_YCBCR420:
> > + return true;
> > + default:
> > + return false;
> > + }
> > +}
> > +
> > const char *
> > drm_hdmi_connector_get_output_format_name(enum drm_output_color_format fmt);
> >
> > @@ -1129,6 +1217,13 @@ struct drm_connector_state {
> > */
> > enum drm_colorspace colorspace;
> >
> > + /**
> > + * @color_format: State variable for Connector property to request
> > + * color format change on Sink. This is most commonly used to switch
> > + * between RGB to YUV and vice-versa.
> > + */
> > + enum drm_connector_color_format color_format;
> > +
> > /**
> > * @writeback_job: Writeback job for writeback connectors
> > *
> > @@ -2127,6 +2222,12 @@ struct drm_connector {
> > */
> > struct drm_property *colorspace_property;
> >
> > + /**
> > + * @color_format_property: Connector property to set the suitable
> > + * color format supported by the sink.
> > + */
> > + struct drm_property *color_format_property;
> > +
> > /**
> > * @path_blob_ptr:
> > *
> > @@ -2610,6 +2711,9 @@ bool drm_connector_has_possible_encoder(struct drm_connector *connector,
> > struct drm_encoder *encoder);
> > const char *drm_get_colorspace_name(enum drm_colorspace colorspace);
> >
> > +int drm_connector_attach_color_format_property(struct drm_connector *connector,
> > + unsigned long supported_color_formats);
> > +
> > /**
> > * drm_for_each_connector_iter - connector_list iterator macro
> > * @connector: &struct drm_connector pointer used as cursor
> >
> > --
> > 2.53.0
> >
>
^ permalink raw reply [flat|nested] 48+ messages in thread* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
2026-03-25 12:49 ` Dave Stevenson
2026-03-25 13:05 ` Maxime Ripard
2026-03-25 13:11 ` Nicolas Frattaroli
@ 2026-03-25 13:43 ` Ville Syrjälä
2026-03-26 11:16 ` Dave Stevenson
2 siblings, 1 reply; 48+ messages in thread
From: Ville Syrjälä @ 2026-03-25 13:43 UTC (permalink / raw)
To: Dave Stevenson
Cc: Nicolas Frattaroli, Harry Wentland, Leo Li, Rodrigo Siqueira,
Alex Deucher, Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan, kernel, amd-gfx, dri-devel,
linux-kernel, linux-arm-kernel, linux-rockchip, intel-gfx,
intel-xe, linux-doc, Werner Sembach, Andri Yngvason, Marius Vlad
On Wed, Mar 25, 2026 at 12:49:19PM +0000, Dave Stevenson wrote:
> On Tue, 24 Mar 2026 at 16:02, Nicolas Frattaroli
> <nicolas.frattaroli@collabora.com> wrote:
> >
> > Add a new general DRM property named "color format" which can be used by
> > userspace to request the display driver to output a particular color
> > format.
> >
> > Possible options are:
> > - auto (setup by default, driver internally picks the color format)
> > - rgb
> > - ycbcr444
> > - ycbcr422
> > - ycbcr420
> >
> > Drivers should advertise from this list which formats they support.
> > Together with this list and EDID data from the sink we should be able
> > to relay a list of usable color formats to users to pick from.
> >
> > Co-developed-by: Werner Sembach <wse@tuxedocomputers.com>
> > Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
> > Co-developed-by: Andri Yngvason <andri@yngvason.is>
> > Signed-off-by: Andri Yngvason <andri@yngvason.is>
> > Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
> > Reviewed-by: Maxime Ripard <mripard@kernel.org>
> > Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
> > ---
> > drivers/gpu/drm/drm_atomic_helper.c | 5 ++
> > drivers/gpu/drm/drm_atomic_uapi.c | 11 ++++
> > drivers/gpu/drm/drm_connector.c | 108 ++++++++++++++++++++++++++++++++++++
> > include/drm/drm_connector.h | 104 ++++++++++++++++++++++++++++++++++
> > 4 files changed, 228 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> > index 26953ed6b53e..b7753454b777 100644
> > --- a/drivers/gpu/drm/drm_atomic_helper.c
> > +++ b/drivers/gpu/drm/drm_atomic_helper.c
> > @@ -737,6 +737,11 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
> > if (old_connector_state->max_requested_bpc !=
> > new_connector_state->max_requested_bpc)
> > new_crtc_state->connectors_changed = true;
> > +
> > + if (old_connector_state->color_format !=
> > + new_connector_state->color_format)
> > + new_crtc_state->connectors_changed = true;
> > +
> > }
> >
> > if (funcs->atomic_check)
> > diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
> > index 5bd5bf6661df..dee510c85e59 100644
> > --- a/drivers/gpu/drm/drm_atomic_uapi.c
> > +++ b/drivers/gpu/drm/drm_atomic_uapi.c
> > @@ -935,6 +935,15 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector,
> > state->privacy_screen_sw_state = val;
> > } else if (property == connector->broadcast_rgb_property) {
> > state->hdmi.broadcast_rgb = val;
> > + } else if (property == connector->color_format_property) {
> > + if (val > INT_MAX || !drm_connector_color_format_valid(val)) {
> > + drm_dbg_atomic(connector->dev,
> > + "[CONNECTOR:%d:%s] unknown color format %llu\n",
> > + connector->base.id, connector->name, val);
> > + return -EINVAL;
> > + }
> > +
> > + state->color_format = val;
> > } else if (connector->funcs->atomic_set_property) {
> > return connector->funcs->atomic_set_property(connector,
> > state, property, val);
> > @@ -1020,6 +1029,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
> > *val = state->privacy_screen_sw_state;
> > } else if (property == connector->broadcast_rgb_property) {
> > *val = state->hdmi.broadcast_rgb;
> > + } else if (property == connector->color_format_property) {
> > + *val = state->color_format;
> > } else if (connector->funcs->atomic_get_property) {
> > return connector->funcs->atomic_get_property(connector,
> > state, property, val);
> > diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> > index 47dc53c4a738..e848374dee0b 100644
> > --- a/drivers/gpu/drm/drm_connector.c
> > +++ b/drivers/gpu/drm/drm_connector.c
> > @@ -1388,6 +1388,18 @@ static const u32 hdmi_colorspaces =
> > BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65) |
> > BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER);
> >
> > +static const u32 hdmi_colorformats =
> > + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
> > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
> > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
> > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
> > +
> > +static const u32 dp_colorformats =
> > + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
> > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
> > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
> > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
> > +
> > /*
> > * As per DP 1.4a spec, 2.2.5.7.5 VSC SDP Payload for Pixel Encoding/Colorimetry
> > * Format Table 2-120
> > @@ -2940,6 +2952,102 @@ int drm_connector_attach_colorspace_property(struct drm_connector *connector)
> > }
> > EXPORT_SYMBOL(drm_connector_attach_colorspace_property);
> >
> > +/**
> > + * drm_connector_attach_color_format_property - create and attach color format property
> > + * @connector: connector to create the color format property on
> > + * @supported_color_formats: bitmask of bit-shifted &enum drm_output_color_format
> > + * values the connector supports
> > + *
> > + * Called by a driver to create a color format property. The property is
> > + * attached to the connector automatically on success.
> > + *
> > + * @supported_color_formats should only include color formats the connector
> > + * type can actually support.
> > + *
> > + * Returns:
> > + * 0 on success, negative errno on error
> > + */
> > +int drm_connector_attach_color_format_property(struct drm_connector *connector,
> > + unsigned long supported_color_formats)
> > +{
> > + struct drm_device *dev = connector->dev;
> > + struct drm_prop_enum_list enum_list[DRM_CONNECTOR_COLOR_FORMAT_COUNT];
> > + unsigned int i = 0;
> > + unsigned long fmt;
> > +
> > + if (connector->color_format_property)
> > + return 0;
> > +
> > + if (!supported_color_formats) {
> > + drm_err(dev, "No supported color formats provided on [CONNECTOR:%d:%s]\n",
> > + connector->base.id, connector->name);
> > + return -EINVAL;
> > + }
> > +
> > + if (supported_color_formats & ~GENMASK(DRM_OUTPUT_COLOR_FORMAT_COUNT - 1, 0)) {
> > + drm_err(dev, "Unknown color formats provided on [CONNECTOR:%d:%s]\n",
> > + connector->base.id, connector->name);
> > + return -EINVAL;
> > + }
> > +
> > + switch (connector->connector_type) {
> > + case DRM_MODE_CONNECTOR_HDMIA:
> > + case DRM_MODE_CONNECTOR_HDMIB:
> > + if (supported_color_formats & ~hdmi_colorformats) {
> > + drm_err(dev, "Color formats not allowed for HDMI on [CONNECTOR:%d:%s]\n",
> > + connector->base.id, connector->name);
> > + return -EINVAL;
> > + }
> > + break;
> > + case DRM_MODE_CONNECTOR_DisplayPort:
> > + case DRM_MODE_CONNECTOR_eDP:
> > + if (supported_color_formats & ~dp_colorformats) {
> > + drm_err(dev, "Color formats not allowed for DP on [CONNECTOR:%d:%s]\n",
> > + connector->base.id, connector->name);
> > + return -EINVAL;
> > + }
> > + break;
> > + }
> > +
> > + enum_list[0].name = "AUTO";
> > + enum_list[0].type = DRM_CONNECTOR_COLOR_FORMAT_AUTO;
> > +
> > + for_each_set_bit(fmt, &supported_color_formats, DRM_OUTPUT_COLOR_FORMAT_COUNT) {
> > + switch (fmt) {
> > + case DRM_OUTPUT_COLOR_FORMAT_RGB444:
> > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_RGB444;
> > + break;
> > + case DRM_OUTPUT_COLOR_FORMAT_YCBCR444:
> > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR444;
> > + break;
> > + case DRM_OUTPUT_COLOR_FORMAT_YCBCR422:
> > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR422;
> > + break;
> > + case DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
> > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR420;
> > + break;
> > + default:
> > + drm_warn(dev, "Unknown supported format %ld on [CONNECTOR:%d:%s]\n",
> > + fmt, connector->base.id, connector->name);
> > + continue;
> > + }
> > + enum_list[i].name = drm_hdmi_connector_get_output_format_name(fmt);
> > + }
> > +
> > + connector->color_format_property =
> > + drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, "color format",
> > + enum_list, i + 1);
> > +
> > + if (!connector->color_format_property)
> > + return -ENOMEM;
> > +
> > + drm_object_attach_property(&connector->base, connector->color_format_property,
> > + DRM_CONNECTOR_COLOR_FORMAT_AUTO);
> > +
> > + return 0;
> > +}
> > +EXPORT_SYMBOL(drm_connector_attach_color_format_property);
> > +
> > /**
> > * drm_connector_atomic_hdr_metadata_equal - checks if the hdr metadata changed
> > * @old_state: old connector state to compare
> > diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> > index af8b92d2d5b7..bd549f912b76 100644
> > --- a/include/drm/drm_connector.h
> > +++ b/include/drm/drm_connector.h
> > @@ -571,14 +571,102 @@ enum drm_colorspace {
> > * YCbCr 4:2:2 output format (ie. with horizontal subsampling)
> > * @DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
> > * YCbCr 4:2:0 output format (ie. with horizontal and vertical subsampling)
> > + * @DRM_OUTPUT_COLOR_FORMAT_COUNT:
> > + * Number of valid output color format values in this enum
> > */
> > enum drm_output_color_format {
> > DRM_OUTPUT_COLOR_FORMAT_RGB444 = 0,
> > DRM_OUTPUT_COLOR_FORMAT_YCBCR444,
> > DRM_OUTPUT_COLOR_FORMAT_YCBCR422,
> > DRM_OUTPUT_COLOR_FORMAT_YCBCR420,
> > + DRM_OUTPUT_COLOR_FORMAT_COUNT,
> > };
> >
> > +/**
> > + * enum drm_connector_color_format - Connector Color Format Request
> > + *
> > + * This enum, unlike &enum drm_output_color_format, is used to specify requests
> > + * for a specific color format on a connector through the DRM "color format"
> > + * property. The difference is that it has an "AUTO" value to specify that
> > + * no specific choice has been made.
> > + */
> > +enum drm_connector_color_format {
> > + /**
> > + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> > + * helpers should pick a suitable color format. All implementations of a
> > + * specific display protocol must behave the same way with "AUTO", but
> > + * different display protocols do not necessarily have the same "AUTO"
> > + * semantics.
> > + *
> > + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> > + * bandwidth required for full-scale RGB is not available, or the mode
> > + * is YCbCr 4:2:0-only, as long as the mode and output both support
> > + * YCbCr 4:2:0.
>
> Is there a reason you propose dropping back to YCbCr 4:2:0 without
> trying YCbCr 4:2:2 first? Minimising the subsampling is surely
> beneficial, and vc4 for one can do 4:2:2 but not 4:2:0.
On HDMI 4:2:2 is always 12bpc, so it doesn't save any bandwidth
compared to 8bpc 4:4:4.
--
Ville Syrjälä
Intel
^ permalink raw reply [flat|nested] 48+ messages in thread* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
2026-03-25 13:43 ` Ville Syrjälä
@ 2026-03-26 11:16 ` Dave Stevenson
2026-03-26 12:02 ` Nicolas Frattaroli
2026-03-26 12:13 ` Ville Syrjälä
0 siblings, 2 replies; 48+ messages in thread
From: Dave Stevenson @ 2026-03-26 11:16 UTC (permalink / raw)
To: Ville Syrjälä
Cc: Nicolas Frattaroli, Harry Wentland, Leo Li, Rodrigo Siqueira,
Alex Deucher, Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan, kernel, amd-gfx, dri-devel,
linux-kernel, linux-arm-kernel, linux-rockchip, intel-gfx,
intel-xe, linux-doc, Werner Sembach, Andri Yngvason, Marius Vlad
On Wed, 25 Mar 2026 at 13:43, Ville Syrjälä
<ville.syrjala@linux.intel.com> wrote:
>
> On Wed, Mar 25, 2026 at 12:49:19PM +0000, Dave Stevenson wrote:
> > On Tue, 24 Mar 2026 at 16:02, Nicolas Frattaroli
> > <nicolas.frattaroli@collabora.com> wrote:
> > >
> > > Add a new general DRM property named "color format" which can be used by
> > > userspace to request the display driver to output a particular color
> > > format.
> > >
> > > Possible options are:
> > > - auto (setup by default, driver internally picks the color format)
> > > - rgb
> > > - ycbcr444
> > > - ycbcr422
> > > - ycbcr420
> > >
> > > Drivers should advertise from this list which formats they support.
> > > Together with this list and EDID data from the sink we should be able
> > > to relay a list of usable color formats to users to pick from.
> > >
> > > Co-developed-by: Werner Sembach <wse@tuxedocomputers.com>
> > > Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
> > > Co-developed-by: Andri Yngvason <andri@yngvason.is>
> > > Signed-off-by: Andri Yngvason <andri@yngvason.is>
> > > Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
> > > Reviewed-by: Maxime Ripard <mripard@kernel.org>
> > > Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
> > > ---
> > > drivers/gpu/drm/drm_atomic_helper.c | 5 ++
> > > drivers/gpu/drm/drm_atomic_uapi.c | 11 ++++
> > > drivers/gpu/drm/drm_connector.c | 108 ++++++++++++++++++++++++++++++++++++
> > > include/drm/drm_connector.h | 104 ++++++++++++++++++++++++++++++++++
> > > 4 files changed, 228 insertions(+)
> > >
> > > diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> > > index 26953ed6b53e..b7753454b777 100644
> > > --- a/drivers/gpu/drm/drm_atomic_helper.c
> > > +++ b/drivers/gpu/drm/drm_atomic_helper.c
> > > @@ -737,6 +737,11 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
> > > if (old_connector_state->max_requested_bpc !=
> > > new_connector_state->max_requested_bpc)
> > > new_crtc_state->connectors_changed = true;
> > > +
> > > + if (old_connector_state->color_format !=
> > > + new_connector_state->color_format)
> > > + new_crtc_state->connectors_changed = true;
> > > +
> > > }
> > >
> > > if (funcs->atomic_check)
> > > diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
> > > index 5bd5bf6661df..dee510c85e59 100644
> > > --- a/drivers/gpu/drm/drm_atomic_uapi.c
> > > +++ b/drivers/gpu/drm/drm_atomic_uapi.c
> > > @@ -935,6 +935,15 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector,
> > > state->privacy_screen_sw_state = val;
> > > } else if (property == connector->broadcast_rgb_property) {
> > > state->hdmi.broadcast_rgb = val;
> > > + } else if (property == connector->color_format_property) {
> > > + if (val > INT_MAX || !drm_connector_color_format_valid(val)) {
> > > + drm_dbg_atomic(connector->dev,
> > > + "[CONNECTOR:%d:%s] unknown color format %llu\n",
> > > + connector->base.id, connector->name, val);
> > > + return -EINVAL;
> > > + }
> > > +
> > > + state->color_format = val;
> > > } else if (connector->funcs->atomic_set_property) {
> > > return connector->funcs->atomic_set_property(connector,
> > > state, property, val);
> > > @@ -1020,6 +1029,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
> > > *val = state->privacy_screen_sw_state;
> > > } else if (property == connector->broadcast_rgb_property) {
> > > *val = state->hdmi.broadcast_rgb;
> > > + } else if (property == connector->color_format_property) {
> > > + *val = state->color_format;
> > > } else if (connector->funcs->atomic_get_property) {
> > > return connector->funcs->atomic_get_property(connector,
> > > state, property, val);
> > > diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> > > index 47dc53c4a738..e848374dee0b 100644
> > > --- a/drivers/gpu/drm/drm_connector.c
> > > +++ b/drivers/gpu/drm/drm_connector.c
> > > @@ -1388,6 +1388,18 @@ static const u32 hdmi_colorspaces =
> > > BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65) |
> > > BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER);
> > >
> > > +static const u32 hdmi_colorformats =
> > > + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
> > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
> > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
> > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
> > > +
> > > +static const u32 dp_colorformats =
> > > + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
> > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
> > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
> > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
> > > +
> > > /*
> > > * As per DP 1.4a spec, 2.2.5.7.5 VSC SDP Payload for Pixel Encoding/Colorimetry
> > > * Format Table 2-120
> > > @@ -2940,6 +2952,102 @@ int drm_connector_attach_colorspace_property(struct drm_connector *connector)
> > > }
> > > EXPORT_SYMBOL(drm_connector_attach_colorspace_property);
> > >
> > > +/**
> > > + * drm_connector_attach_color_format_property - create and attach color format property
> > > + * @connector: connector to create the color format property on
> > > + * @supported_color_formats: bitmask of bit-shifted &enum drm_output_color_format
> > > + * values the connector supports
> > > + *
> > > + * Called by a driver to create a color format property. The property is
> > > + * attached to the connector automatically on success.
> > > + *
> > > + * @supported_color_formats should only include color formats the connector
> > > + * type can actually support.
> > > + *
> > > + * Returns:
> > > + * 0 on success, negative errno on error
> > > + */
> > > +int drm_connector_attach_color_format_property(struct drm_connector *connector,
> > > + unsigned long supported_color_formats)
> > > +{
> > > + struct drm_device *dev = connector->dev;
> > > + struct drm_prop_enum_list enum_list[DRM_CONNECTOR_COLOR_FORMAT_COUNT];
> > > + unsigned int i = 0;
> > > + unsigned long fmt;
> > > +
> > > + if (connector->color_format_property)
> > > + return 0;
> > > +
> > > + if (!supported_color_formats) {
> > > + drm_err(dev, "No supported color formats provided on [CONNECTOR:%d:%s]\n",
> > > + connector->base.id, connector->name);
> > > + return -EINVAL;
> > > + }
> > > +
> > > + if (supported_color_formats & ~GENMASK(DRM_OUTPUT_COLOR_FORMAT_COUNT - 1, 0)) {
> > > + drm_err(dev, "Unknown color formats provided on [CONNECTOR:%d:%s]\n",
> > > + connector->base.id, connector->name);
> > > + return -EINVAL;
> > > + }
> > > +
> > > + switch (connector->connector_type) {
> > > + case DRM_MODE_CONNECTOR_HDMIA:
> > > + case DRM_MODE_CONNECTOR_HDMIB:
> > > + if (supported_color_formats & ~hdmi_colorformats) {
> > > + drm_err(dev, "Color formats not allowed for HDMI on [CONNECTOR:%d:%s]\n",
> > > + connector->base.id, connector->name);
> > > + return -EINVAL;
> > > + }
> > > + break;
> > > + case DRM_MODE_CONNECTOR_DisplayPort:
> > > + case DRM_MODE_CONNECTOR_eDP:
> > > + if (supported_color_formats & ~dp_colorformats) {
> > > + drm_err(dev, "Color formats not allowed for DP on [CONNECTOR:%d:%s]\n",
> > > + connector->base.id, connector->name);
> > > + return -EINVAL;
> > > + }
> > > + break;
> > > + }
> > > +
> > > + enum_list[0].name = "AUTO";
> > > + enum_list[0].type = DRM_CONNECTOR_COLOR_FORMAT_AUTO;
> > > +
> > > + for_each_set_bit(fmt, &supported_color_formats, DRM_OUTPUT_COLOR_FORMAT_COUNT) {
> > > + switch (fmt) {
> > > + case DRM_OUTPUT_COLOR_FORMAT_RGB444:
> > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_RGB444;
> > > + break;
> > > + case DRM_OUTPUT_COLOR_FORMAT_YCBCR444:
> > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR444;
> > > + break;
> > > + case DRM_OUTPUT_COLOR_FORMAT_YCBCR422:
> > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR422;
> > > + break;
> > > + case DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
> > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR420;
> > > + break;
> > > + default:
> > > + drm_warn(dev, "Unknown supported format %ld on [CONNECTOR:%d:%s]\n",
> > > + fmt, connector->base.id, connector->name);
> > > + continue;
> > > + }
> > > + enum_list[i].name = drm_hdmi_connector_get_output_format_name(fmt);
> > > + }
> > > +
> > > + connector->color_format_property =
> > > + drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, "color format",
> > > + enum_list, i + 1);
> > > +
> > > + if (!connector->color_format_property)
> > > + return -ENOMEM;
> > > +
> > > + drm_object_attach_property(&connector->base, connector->color_format_property,
> > > + DRM_CONNECTOR_COLOR_FORMAT_AUTO);
> > > +
> > > + return 0;
> > > +}
> > > +EXPORT_SYMBOL(drm_connector_attach_color_format_property);
> > > +
> > > /**
> > > * drm_connector_atomic_hdr_metadata_equal - checks if the hdr metadata changed
> > > * @old_state: old connector state to compare
> > > diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> > > index af8b92d2d5b7..bd549f912b76 100644
> > > --- a/include/drm/drm_connector.h
> > > +++ b/include/drm/drm_connector.h
> > > @@ -571,14 +571,102 @@ enum drm_colorspace {
> > > * YCbCr 4:2:2 output format (ie. with horizontal subsampling)
> > > * @DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
> > > * YCbCr 4:2:0 output format (ie. with horizontal and vertical subsampling)
> > > + * @DRM_OUTPUT_COLOR_FORMAT_COUNT:
> > > + * Number of valid output color format values in this enum
> > > */
> > > enum drm_output_color_format {
> > > DRM_OUTPUT_COLOR_FORMAT_RGB444 = 0,
> > > DRM_OUTPUT_COLOR_FORMAT_YCBCR444,
> > > DRM_OUTPUT_COLOR_FORMAT_YCBCR422,
> > > DRM_OUTPUT_COLOR_FORMAT_YCBCR420,
> > > + DRM_OUTPUT_COLOR_FORMAT_COUNT,
> > > };
> > >
> > > +/**
> > > + * enum drm_connector_color_format - Connector Color Format Request
> > > + *
> > > + * This enum, unlike &enum drm_output_color_format, is used to specify requests
> > > + * for a specific color format on a connector through the DRM "color format"
> > > + * property. The difference is that it has an "AUTO" value to specify that
> > > + * no specific choice has been made.
> > > + */
> > > +enum drm_connector_color_format {
> > > + /**
> > > + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> > > + * helpers should pick a suitable color format. All implementations of a
> > > + * specific display protocol must behave the same way with "AUTO", but
> > > + * different display protocols do not necessarily have the same "AUTO"
> > > + * semantics.
> > > + *
> > > + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> > > + * bandwidth required for full-scale RGB is not available, or the mode
> > > + * is YCbCr 4:2:0-only, as long as the mode and output both support
> > > + * YCbCr 4:2:0.
> >
> > Is there a reason you propose dropping back to YCbCr 4:2:0 without
> > trying YCbCr 4:2:2 first? Minimising the subsampling is surely
> > beneficial, and vc4 for one can do 4:2:2 but not 4:2:0.
>
> On HDMI 4:2:2 is always 12bpc, so it doesn't save any bandwidth
> compared to 8bpc 4:4:4.
It does save bandwidth against 10 or 12bpc RGB 4:4:4.
Or is the implication that max_bpc = 12 and
DRM_CONNECTOR_COLOR_FORMAT_AUTO should drop bpc down to 8 and select
RGB in preference to selecting 4:2:2?
Dave
> --
> Ville Syrjälä
> Intel
^ permalink raw reply [flat|nested] 48+ messages in thread* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
2026-03-26 11:16 ` Dave Stevenson
@ 2026-03-26 12:02 ` Nicolas Frattaroli
2026-03-26 12:13 ` Ville Syrjälä
1 sibling, 0 replies; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-26 12:02 UTC (permalink / raw)
To: Ville Syrjälä, Dave Stevenson
Cc: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan, kernel, amd-gfx, dri-devel,
linux-kernel, linux-arm-kernel, linux-rockchip, intel-gfx,
intel-xe, linux-doc, Werner Sembach, Andri Yngvason, Marius Vlad
On Thursday, 26 March 2026 12:16:12 Central European Standard Time Dave Stevenson wrote:
> On Wed, 25 Mar 2026 at 13:43, Ville Syrjälä
> <ville.syrjala@linux.intel.com> wrote:
> >
> > On Wed, Mar 25, 2026 at 12:49:19PM +0000, Dave Stevenson wrote:
> > > On Tue, 24 Mar 2026 at 16:02, Nicolas Frattaroli
> > > <nicolas.frattaroli@collabora.com> wrote:
> > > >
> > > > Add a new general DRM property named "color format" which can be used by
> > > > userspace to request the display driver to output a particular color
> > > > format.
> > > >
> > > > Possible options are:
> > > > - auto (setup by default, driver internally picks the color format)
> > > > - rgb
> > > > - ycbcr444
> > > > - ycbcr422
> > > > - ycbcr420
> > > >
> > > > Drivers should advertise from this list which formats they support.
> > > > Together with this list and EDID data from the sink we should be able
> > > > to relay a list of usable color formats to users to pick from.
> > > >
> > > > Co-developed-by: Werner Sembach <wse@tuxedocomputers.com>
> > > > Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
> > > > Co-developed-by: Andri Yngvason <andri@yngvason.is>
> > > > Signed-off-by: Andri Yngvason <andri@yngvason.is>
> > > > Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
> > > > Reviewed-by: Maxime Ripard <mripard@kernel.org>
> > > > Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
> > > > ---
> > > > drivers/gpu/drm/drm_atomic_helper.c | 5 ++
> > > > drivers/gpu/drm/drm_atomic_uapi.c | 11 ++++
> > > > drivers/gpu/drm/drm_connector.c | 108 ++++++++++++++++++++++++++++++++++++
> > > > include/drm/drm_connector.h | 104 ++++++++++++++++++++++++++++++++++
> > > > 4 files changed, 228 insertions(+)
> > > >
> > > > diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> > > > index 26953ed6b53e..b7753454b777 100644
> > > > --- a/drivers/gpu/drm/drm_atomic_helper.c
> > > > +++ b/drivers/gpu/drm/drm_atomic_helper.c
> > > > @@ -737,6 +737,11 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
> > > > if (old_connector_state->max_requested_bpc !=
> > > > new_connector_state->max_requested_bpc)
> > > > new_crtc_state->connectors_changed = true;
> > > > +
> > > > + if (old_connector_state->color_format !=
> > > > + new_connector_state->color_format)
> > > > + new_crtc_state->connectors_changed = true;
> > > > +
> > > > }
> > > >
> > > > if (funcs->atomic_check)
> > > > diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
> > > > index 5bd5bf6661df..dee510c85e59 100644
> > > > --- a/drivers/gpu/drm/drm_atomic_uapi.c
> > > > +++ b/drivers/gpu/drm/drm_atomic_uapi.c
> > > > @@ -935,6 +935,15 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector,
> > > > state->privacy_screen_sw_state = val;
> > > > } else if (property == connector->broadcast_rgb_property) {
> > > > state->hdmi.broadcast_rgb = val;
> > > > + } else if (property == connector->color_format_property) {
> > > > + if (val > INT_MAX || !drm_connector_color_format_valid(val)) {
> > > > + drm_dbg_atomic(connector->dev,
> > > > + "[CONNECTOR:%d:%s] unknown color format %llu\n",
> > > > + connector->base.id, connector->name, val);
> > > > + return -EINVAL;
> > > > + }
> > > > +
> > > > + state->color_format = val;
> > > > } else if (connector->funcs->atomic_set_property) {
> > > > return connector->funcs->atomic_set_property(connector,
> > > > state, property, val);
> > > > @@ -1020,6 +1029,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
> > > > *val = state->privacy_screen_sw_state;
> > > > } else if (property == connector->broadcast_rgb_property) {
> > > > *val = state->hdmi.broadcast_rgb;
> > > > + } else if (property == connector->color_format_property) {
> > > > + *val = state->color_format;
> > > > } else if (connector->funcs->atomic_get_property) {
> > > > return connector->funcs->atomic_get_property(connector,
> > > > state, property, val);
> > > > diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> > > > index 47dc53c4a738..e848374dee0b 100644
> > > > --- a/drivers/gpu/drm/drm_connector.c
> > > > +++ b/drivers/gpu/drm/drm_connector.c
> > > > @@ -1388,6 +1388,18 @@ static const u32 hdmi_colorspaces =
> > > > BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65) |
> > > > BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER);
> > > >
> > > > +static const u32 hdmi_colorformats =
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
> > > > +
> > > > +static const u32 dp_colorformats =
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
> > > > +
> > > > /*
> > > > * As per DP 1.4a spec, 2.2.5.7.5 VSC SDP Payload for Pixel Encoding/Colorimetry
> > > > * Format Table 2-120
> > > > @@ -2940,6 +2952,102 @@ int drm_connector_attach_colorspace_property(struct drm_connector *connector)
> > > > }
> > > > EXPORT_SYMBOL(drm_connector_attach_colorspace_property);
> > > >
> > > > +/**
> > > > + * drm_connector_attach_color_format_property - create and attach color format property
> > > > + * @connector: connector to create the color format property on
> > > > + * @supported_color_formats: bitmask of bit-shifted &enum drm_output_color_format
> > > > + * values the connector supports
> > > > + *
> > > > + * Called by a driver to create a color format property. The property is
> > > > + * attached to the connector automatically on success.
> > > > + *
> > > > + * @supported_color_formats should only include color formats the connector
> > > > + * type can actually support.
> > > > + *
> > > > + * Returns:
> > > > + * 0 on success, negative errno on error
> > > > + */
> > > > +int drm_connector_attach_color_format_property(struct drm_connector *connector,
> > > > + unsigned long supported_color_formats)
> > > > +{
> > > > + struct drm_device *dev = connector->dev;
> > > > + struct drm_prop_enum_list enum_list[DRM_CONNECTOR_COLOR_FORMAT_COUNT];
> > > > + unsigned int i = 0;
> > > > + unsigned long fmt;
> > > > +
> > > > + if (connector->color_format_property)
> > > > + return 0;
> > > > +
> > > > + if (!supported_color_formats) {
> > > > + drm_err(dev, "No supported color formats provided on [CONNECTOR:%d:%s]\n",
> > > > + connector->base.id, connector->name);
> > > > + return -EINVAL;
> > > > + }
> > > > +
> > > > + if (supported_color_formats & ~GENMASK(DRM_OUTPUT_COLOR_FORMAT_COUNT - 1, 0)) {
> > > > + drm_err(dev, "Unknown color formats provided on [CONNECTOR:%d:%s]\n",
> > > > + connector->base.id, connector->name);
> > > > + return -EINVAL;
> > > > + }
> > > > +
> > > > + switch (connector->connector_type) {
> > > > + case DRM_MODE_CONNECTOR_HDMIA:
> > > > + case DRM_MODE_CONNECTOR_HDMIB:
> > > > + if (supported_color_formats & ~hdmi_colorformats) {
> > > > + drm_err(dev, "Color formats not allowed for HDMI on [CONNECTOR:%d:%s]\n",
> > > > + connector->base.id, connector->name);
> > > > + return -EINVAL;
> > > > + }
> > > > + break;
> > > > + case DRM_MODE_CONNECTOR_DisplayPort:
> > > > + case DRM_MODE_CONNECTOR_eDP:
> > > > + if (supported_color_formats & ~dp_colorformats) {
> > > > + drm_err(dev, "Color formats not allowed for DP on [CONNECTOR:%d:%s]\n",
> > > > + connector->base.id, connector->name);
> > > > + return -EINVAL;
> > > > + }
> > > > + break;
> > > > + }
> > > > +
> > > > + enum_list[0].name = "AUTO";
> > > > + enum_list[0].type = DRM_CONNECTOR_COLOR_FORMAT_AUTO;
> > > > +
> > > > + for_each_set_bit(fmt, &supported_color_formats, DRM_OUTPUT_COLOR_FORMAT_COUNT) {
> > > > + switch (fmt) {
> > > > + case DRM_OUTPUT_COLOR_FORMAT_RGB444:
> > > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_RGB444;
> > > > + break;
> > > > + case DRM_OUTPUT_COLOR_FORMAT_YCBCR444:
> > > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR444;
> > > > + break;
> > > > + case DRM_OUTPUT_COLOR_FORMAT_YCBCR422:
> > > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR422;
> > > > + break;
> > > > + case DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
> > > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR420;
> > > > + break;
> > > > + default:
> > > > + drm_warn(dev, "Unknown supported format %ld on [CONNECTOR:%d:%s]\n",
> > > > + fmt, connector->base.id, connector->name);
> > > > + continue;
> > > > + }
> > > > + enum_list[i].name = drm_hdmi_connector_get_output_format_name(fmt);
> > > > + }
> > > > +
> > > > + connector->color_format_property =
> > > > + drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, "color format",
> > > > + enum_list, i + 1);
> > > > +
> > > > + if (!connector->color_format_property)
> > > > + return -ENOMEM;
> > > > +
> > > > + drm_object_attach_property(&connector->base, connector->color_format_property,
> > > > + DRM_CONNECTOR_COLOR_FORMAT_AUTO);
> > > > +
> > > > + return 0;
> > > > +}
> > > > +EXPORT_SYMBOL(drm_connector_attach_color_format_property);
> > > > +
> > > > /**
> > > > * drm_connector_atomic_hdr_metadata_equal - checks if the hdr metadata changed
> > > > * @old_state: old connector state to compare
> > > > diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> > > > index af8b92d2d5b7..bd549f912b76 100644
> > > > --- a/include/drm/drm_connector.h
> > > > +++ b/include/drm/drm_connector.h
> > > > @@ -571,14 +571,102 @@ enum drm_colorspace {
> > > > * YCbCr 4:2:2 output format (ie. with horizontal subsampling)
> > > > * @DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
> > > > * YCbCr 4:2:0 output format (ie. with horizontal and vertical subsampling)
> > > > + * @DRM_OUTPUT_COLOR_FORMAT_COUNT:
> > > > + * Number of valid output color format values in this enum
> > > > */
> > > > enum drm_output_color_format {
> > > > DRM_OUTPUT_COLOR_FORMAT_RGB444 = 0,
> > > > DRM_OUTPUT_COLOR_FORMAT_YCBCR444,
> > > > DRM_OUTPUT_COLOR_FORMAT_YCBCR422,
> > > > DRM_OUTPUT_COLOR_FORMAT_YCBCR420,
> > > > + DRM_OUTPUT_COLOR_FORMAT_COUNT,
> > > > };
> > > >
> > > > +/**
> > > > + * enum drm_connector_color_format - Connector Color Format Request
> > > > + *
> > > > + * This enum, unlike &enum drm_output_color_format, is used to specify requests
> > > > + * for a specific color format on a connector through the DRM "color format"
> > > > + * property. The difference is that it has an "AUTO" value to specify that
> > > > + * no specific choice has been made.
> > > > + */
> > > > +enum drm_connector_color_format {
> > > > + /**
> > > > + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> > > > + * helpers should pick a suitable color format. All implementations of a
> > > > + * specific display protocol must behave the same way with "AUTO", but
> > > > + * different display protocols do not necessarily have the same "AUTO"
> > > > + * semantics.
> > > > + *
> > > > + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> > > > + * bandwidth required for full-scale RGB is not available, or the mode
> > > > + * is YCbCr 4:2:0-only, as long as the mode and output both support
> > > > + * YCbCr 4:2:0.
> > >
> > > Is there a reason you propose dropping back to YCbCr 4:2:0 without
> > > trying YCbCr 4:2:2 first? Minimising the subsampling is surely
> > > beneficial, and vc4 for one can do 4:2:2 but not 4:2:0.
> >
> > On HDMI 4:2:2 is always 12bpc, so it doesn't save any bandwidth
> > compared to 8bpc 4:4:4.
>
> It does save bandwidth against 10 or 12bpc RGB 4:4:4.
>
> Or is the implication that max_bpc = 12 and
> DRM_CONNECTOR_COLOR_FORMAT_AUTO should drop bpc down to 8 and select
> RGB in preference to selecting 4:2:2?
Yes. Some people consider max-bpc to not be a legitimate way of requesting
an actual bpc, and don't think drivers will choose the highest bpc <= max-bpc,
and instead may negotiate a fantasy number anywhere below or equal to max-bpc.
Of course this logic could be done in userspace which knows whether the
less chroma for more bit depth trade-off is worth it, but userspace does
not know the negotiated link bpc, and my attempts at adding a property for
it are being blocked.
>
> Dave
>
> > --
> > Ville Syrjälä
> > Intel
>
^ permalink raw reply [flat|nested] 48+ messages in thread* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
2026-03-26 11:16 ` Dave Stevenson
2026-03-26 12:02 ` Nicolas Frattaroli
@ 2026-03-26 12:13 ` Ville Syrjälä
2026-03-26 13:39 ` Dave Stevenson
1 sibling, 1 reply; 48+ messages in thread
From: Ville Syrjälä @ 2026-03-26 12:13 UTC (permalink / raw)
To: Dave Stevenson
Cc: Nicolas Frattaroli, Harry Wentland, Leo Li, Rodrigo Siqueira,
Alex Deucher, Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan, kernel, amd-gfx, dri-devel,
linux-kernel, linux-arm-kernel, linux-rockchip, intel-gfx,
intel-xe, linux-doc, Werner Sembach, Andri Yngvason, Marius Vlad
On Thu, Mar 26, 2026 at 11:16:12AM +0000, Dave Stevenson wrote:
> On Wed, 25 Mar 2026 at 13:43, Ville Syrjälä
> <ville.syrjala@linux.intel.com> wrote:
> >
> > On Wed, Mar 25, 2026 at 12:49:19PM +0000, Dave Stevenson wrote:
> > > On Tue, 24 Mar 2026 at 16:02, Nicolas Frattaroli
> > > <nicolas.frattaroli@collabora.com> wrote:
> > > >
> > > > Add a new general DRM property named "color format" which can be used by
> > > > userspace to request the display driver to output a particular color
> > > > format.
> > > >
> > > > Possible options are:
> > > > - auto (setup by default, driver internally picks the color format)
> > > > - rgb
> > > > - ycbcr444
> > > > - ycbcr422
> > > > - ycbcr420
> > > >
> > > > Drivers should advertise from this list which formats they support.
> > > > Together with this list and EDID data from the sink we should be able
> > > > to relay a list of usable color formats to users to pick from.
> > > >
> > > > Co-developed-by: Werner Sembach <wse@tuxedocomputers.com>
> > > > Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
> > > > Co-developed-by: Andri Yngvason <andri@yngvason.is>
> > > > Signed-off-by: Andri Yngvason <andri@yngvason.is>
> > > > Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
> > > > Reviewed-by: Maxime Ripard <mripard@kernel.org>
> > > > Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
> > > > ---
> > > > drivers/gpu/drm/drm_atomic_helper.c | 5 ++
> > > > drivers/gpu/drm/drm_atomic_uapi.c | 11 ++++
> > > > drivers/gpu/drm/drm_connector.c | 108 ++++++++++++++++++++++++++++++++++++
> > > > include/drm/drm_connector.h | 104 ++++++++++++++++++++++++++++++++++
> > > > 4 files changed, 228 insertions(+)
> > > >
> > > > diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> > > > index 26953ed6b53e..b7753454b777 100644
> > > > --- a/drivers/gpu/drm/drm_atomic_helper.c
> > > > +++ b/drivers/gpu/drm/drm_atomic_helper.c
> > > > @@ -737,6 +737,11 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
> > > > if (old_connector_state->max_requested_bpc !=
> > > > new_connector_state->max_requested_bpc)
> > > > new_crtc_state->connectors_changed = true;
> > > > +
> > > > + if (old_connector_state->color_format !=
> > > > + new_connector_state->color_format)
> > > > + new_crtc_state->connectors_changed = true;
> > > > +
> > > > }
> > > >
> > > > if (funcs->atomic_check)
> > > > diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
> > > > index 5bd5bf6661df..dee510c85e59 100644
> > > > --- a/drivers/gpu/drm/drm_atomic_uapi.c
> > > > +++ b/drivers/gpu/drm/drm_atomic_uapi.c
> > > > @@ -935,6 +935,15 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector,
> > > > state->privacy_screen_sw_state = val;
> > > > } else if (property == connector->broadcast_rgb_property) {
> > > > state->hdmi.broadcast_rgb = val;
> > > > + } else if (property == connector->color_format_property) {
> > > > + if (val > INT_MAX || !drm_connector_color_format_valid(val)) {
> > > > + drm_dbg_atomic(connector->dev,
> > > > + "[CONNECTOR:%d:%s] unknown color format %llu\n",
> > > > + connector->base.id, connector->name, val);
> > > > + return -EINVAL;
> > > > + }
> > > > +
> > > > + state->color_format = val;
> > > > } else if (connector->funcs->atomic_set_property) {
> > > > return connector->funcs->atomic_set_property(connector,
> > > > state, property, val);
> > > > @@ -1020,6 +1029,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
> > > > *val = state->privacy_screen_sw_state;
> > > > } else if (property == connector->broadcast_rgb_property) {
> > > > *val = state->hdmi.broadcast_rgb;
> > > > + } else if (property == connector->color_format_property) {
> > > > + *val = state->color_format;
> > > > } else if (connector->funcs->atomic_get_property) {
> > > > return connector->funcs->atomic_get_property(connector,
> > > > state, property, val);
> > > > diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> > > > index 47dc53c4a738..e848374dee0b 100644
> > > > --- a/drivers/gpu/drm/drm_connector.c
> > > > +++ b/drivers/gpu/drm/drm_connector.c
> > > > @@ -1388,6 +1388,18 @@ static const u32 hdmi_colorspaces =
> > > > BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65) |
> > > > BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER);
> > > >
> > > > +static const u32 hdmi_colorformats =
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
> > > > +
> > > > +static const u32 dp_colorformats =
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
> > > > +
> > > > /*
> > > > * As per DP 1.4a spec, 2.2.5.7.5 VSC SDP Payload for Pixel Encoding/Colorimetry
> > > > * Format Table 2-120
> > > > @@ -2940,6 +2952,102 @@ int drm_connector_attach_colorspace_property(struct drm_connector *connector)
> > > > }
> > > > EXPORT_SYMBOL(drm_connector_attach_colorspace_property);
> > > >
> > > > +/**
> > > > + * drm_connector_attach_color_format_property - create and attach color format property
> > > > + * @connector: connector to create the color format property on
> > > > + * @supported_color_formats: bitmask of bit-shifted &enum drm_output_color_format
> > > > + * values the connector supports
> > > > + *
> > > > + * Called by a driver to create a color format property. The property is
> > > > + * attached to the connector automatically on success.
> > > > + *
> > > > + * @supported_color_formats should only include color formats the connector
> > > > + * type can actually support.
> > > > + *
> > > > + * Returns:
> > > > + * 0 on success, negative errno on error
> > > > + */
> > > > +int drm_connector_attach_color_format_property(struct drm_connector *connector,
> > > > + unsigned long supported_color_formats)
> > > > +{
> > > > + struct drm_device *dev = connector->dev;
> > > > + struct drm_prop_enum_list enum_list[DRM_CONNECTOR_COLOR_FORMAT_COUNT];
> > > > + unsigned int i = 0;
> > > > + unsigned long fmt;
> > > > +
> > > > + if (connector->color_format_property)
> > > > + return 0;
> > > > +
> > > > + if (!supported_color_formats) {
> > > > + drm_err(dev, "No supported color formats provided on [CONNECTOR:%d:%s]\n",
> > > > + connector->base.id, connector->name);
> > > > + return -EINVAL;
> > > > + }
> > > > +
> > > > + if (supported_color_formats & ~GENMASK(DRM_OUTPUT_COLOR_FORMAT_COUNT - 1, 0)) {
> > > > + drm_err(dev, "Unknown color formats provided on [CONNECTOR:%d:%s]\n",
> > > > + connector->base.id, connector->name);
> > > > + return -EINVAL;
> > > > + }
> > > > +
> > > > + switch (connector->connector_type) {
> > > > + case DRM_MODE_CONNECTOR_HDMIA:
> > > > + case DRM_MODE_CONNECTOR_HDMIB:
> > > > + if (supported_color_formats & ~hdmi_colorformats) {
> > > > + drm_err(dev, "Color formats not allowed for HDMI on [CONNECTOR:%d:%s]\n",
> > > > + connector->base.id, connector->name);
> > > > + return -EINVAL;
> > > > + }
> > > > + break;
> > > > + case DRM_MODE_CONNECTOR_DisplayPort:
> > > > + case DRM_MODE_CONNECTOR_eDP:
> > > > + if (supported_color_formats & ~dp_colorformats) {
> > > > + drm_err(dev, "Color formats not allowed for DP on [CONNECTOR:%d:%s]\n",
> > > > + connector->base.id, connector->name);
> > > > + return -EINVAL;
> > > > + }
> > > > + break;
> > > > + }
> > > > +
> > > > + enum_list[0].name = "AUTO";
> > > > + enum_list[0].type = DRM_CONNECTOR_COLOR_FORMAT_AUTO;
> > > > +
> > > > + for_each_set_bit(fmt, &supported_color_formats, DRM_OUTPUT_COLOR_FORMAT_COUNT) {
> > > > + switch (fmt) {
> > > > + case DRM_OUTPUT_COLOR_FORMAT_RGB444:
> > > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_RGB444;
> > > > + break;
> > > > + case DRM_OUTPUT_COLOR_FORMAT_YCBCR444:
> > > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR444;
> > > > + break;
> > > > + case DRM_OUTPUT_COLOR_FORMAT_YCBCR422:
> > > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR422;
> > > > + break;
> > > > + case DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
> > > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR420;
> > > > + break;
> > > > + default:
> > > > + drm_warn(dev, "Unknown supported format %ld on [CONNECTOR:%d:%s]\n",
> > > > + fmt, connector->base.id, connector->name);
> > > > + continue;
> > > > + }
> > > > + enum_list[i].name = drm_hdmi_connector_get_output_format_name(fmt);
> > > > + }
> > > > +
> > > > + connector->color_format_property =
> > > > + drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, "color format",
> > > > + enum_list, i + 1);
> > > > +
> > > > + if (!connector->color_format_property)
> > > > + return -ENOMEM;
> > > > +
> > > > + drm_object_attach_property(&connector->base, connector->color_format_property,
> > > > + DRM_CONNECTOR_COLOR_FORMAT_AUTO);
> > > > +
> > > > + return 0;
> > > > +}
> > > > +EXPORT_SYMBOL(drm_connector_attach_color_format_property);
> > > > +
> > > > /**
> > > > * drm_connector_atomic_hdr_metadata_equal - checks if the hdr metadata changed
> > > > * @old_state: old connector state to compare
> > > > diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> > > > index af8b92d2d5b7..bd549f912b76 100644
> > > > --- a/include/drm/drm_connector.h
> > > > +++ b/include/drm/drm_connector.h
> > > > @@ -571,14 +571,102 @@ enum drm_colorspace {
> > > > * YCbCr 4:2:2 output format (ie. with horizontal subsampling)
> > > > * @DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
> > > > * YCbCr 4:2:0 output format (ie. with horizontal and vertical subsampling)
> > > > + * @DRM_OUTPUT_COLOR_FORMAT_COUNT:
> > > > + * Number of valid output color format values in this enum
> > > > */
> > > > enum drm_output_color_format {
> > > > DRM_OUTPUT_COLOR_FORMAT_RGB444 = 0,
> > > > DRM_OUTPUT_COLOR_FORMAT_YCBCR444,
> > > > DRM_OUTPUT_COLOR_FORMAT_YCBCR422,
> > > > DRM_OUTPUT_COLOR_FORMAT_YCBCR420,
> > > > + DRM_OUTPUT_COLOR_FORMAT_COUNT,
> > > > };
> > > >
> > > > +/**
> > > > + * enum drm_connector_color_format - Connector Color Format Request
> > > > + *
> > > > + * This enum, unlike &enum drm_output_color_format, is used to specify requests
> > > > + * for a specific color format on a connector through the DRM "color format"
> > > > + * property. The difference is that it has an "AUTO" value to specify that
> > > > + * no specific choice has been made.
> > > > + */
> > > > +enum drm_connector_color_format {
> > > > + /**
> > > > + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> > > > + * helpers should pick a suitable color format. All implementations of a
> > > > + * specific display protocol must behave the same way with "AUTO", but
> > > > + * different display protocols do not necessarily have the same "AUTO"
> > > > + * semantics.
> > > > + *
> > > > + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> > > > + * bandwidth required for full-scale RGB is not available, or the mode
> > > > + * is YCbCr 4:2:0-only, as long as the mode and output both support
> > > > + * YCbCr 4:2:0.
> > >
> > > Is there a reason you propose dropping back to YCbCr 4:2:0 without
> > > trying YCbCr 4:2:2 first? Minimising the subsampling is surely
> > > beneficial, and vc4 for one can do 4:2:2 but not 4:2:0.
> >
> > On HDMI 4:2:2 is always 12bpc, so it doesn't save any bandwidth
> > compared to 8bpc 4:4:4.
>
> It does save bandwidth against 10 or 12bpc RGB 4:4:4.
>
> Or is the implication that max_bpc = 12 and
> DRM_CONNECTOR_COLOR_FORMAT_AUTO should drop bpc down to 8 and select
> RGB in preference to selecting 4:2:2?
Yeah, YCbCr has all kinds of extra complications compared to RGB, so
the policy is to use RGB if possible, and only fall back to YCbCr as a
last resort. And in that case 4:2:0 is the only thing that can help.
--
Ville Syrjälä
Intel
^ permalink raw reply [flat|nested] 48+ messages in thread* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
2026-03-26 12:13 ` Ville Syrjälä
@ 2026-03-26 13:39 ` Dave Stevenson
0 siblings, 0 replies; 48+ messages in thread
From: Dave Stevenson @ 2026-03-26 13:39 UTC (permalink / raw)
To: Ville Syrjälä
Cc: Nicolas Frattaroli, Harry Wentland, Leo Li, Rodrigo Siqueira,
Alex Deucher, Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan, kernel, amd-gfx, dri-devel,
linux-kernel, linux-arm-kernel, linux-rockchip, intel-gfx,
intel-xe, linux-doc, Werner Sembach, Andri Yngvason, Marius Vlad
On Thu, 26 Mar 2026 at 12:13, Ville Syrjälä
<ville.syrjala@linux.intel.com> wrote:
>
> On Thu, Mar 26, 2026 at 11:16:12AM +0000, Dave Stevenson wrote:
> > On Wed, 25 Mar 2026 at 13:43, Ville Syrjälä
> > <ville.syrjala@linux.intel.com> wrote:
> > >
> > > On Wed, Mar 25, 2026 at 12:49:19PM +0000, Dave Stevenson wrote:
> > > > On Tue, 24 Mar 2026 at 16:02, Nicolas Frattaroli
> > > > <nicolas.frattaroli@collabora.com> wrote:
> > > > >
> > > > > Add a new general DRM property named "color format" which can be used by
> > > > > userspace to request the display driver to output a particular color
> > > > > format.
> > > > >
> > > > > Possible options are:
> > > > > - auto (setup by default, driver internally picks the color format)
> > > > > - rgb
> > > > > - ycbcr444
> > > > > - ycbcr422
> > > > > - ycbcr420
> > > > >
> > > > > Drivers should advertise from this list which formats they support.
> > > > > Together with this list and EDID data from the sink we should be able
> > > > > to relay a list of usable color formats to users to pick from.
> > > > >
> > > > > Co-developed-by: Werner Sembach <wse@tuxedocomputers.com>
> > > > > Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
> > > > > Co-developed-by: Andri Yngvason <andri@yngvason.is>
> > > > > Signed-off-by: Andri Yngvason <andri@yngvason.is>
> > > > > Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
> > > > > Reviewed-by: Maxime Ripard <mripard@kernel.org>
> > > > > Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
> > > > > ---
> > > > > drivers/gpu/drm/drm_atomic_helper.c | 5 ++
> > > > > drivers/gpu/drm/drm_atomic_uapi.c | 11 ++++
> > > > > drivers/gpu/drm/drm_connector.c | 108 ++++++++++++++++++++++++++++++++++++
> > > > > include/drm/drm_connector.h | 104 ++++++++++++++++++++++++++++++++++
> > > > > 4 files changed, 228 insertions(+)
> > > > >
> > > > > diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> > > > > index 26953ed6b53e..b7753454b777 100644
> > > > > --- a/drivers/gpu/drm/drm_atomic_helper.c
> > > > > +++ b/drivers/gpu/drm/drm_atomic_helper.c
> > > > > @@ -737,6 +737,11 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
> > > > > if (old_connector_state->max_requested_bpc !=
> > > > > new_connector_state->max_requested_bpc)
> > > > > new_crtc_state->connectors_changed = true;
> > > > > +
> > > > > + if (old_connector_state->color_format !=
> > > > > + new_connector_state->color_format)
> > > > > + new_crtc_state->connectors_changed = true;
> > > > > +
> > > > > }
> > > > >
> > > > > if (funcs->atomic_check)
> > > > > diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
> > > > > index 5bd5bf6661df..dee510c85e59 100644
> > > > > --- a/drivers/gpu/drm/drm_atomic_uapi.c
> > > > > +++ b/drivers/gpu/drm/drm_atomic_uapi.c
> > > > > @@ -935,6 +935,15 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector,
> > > > > state->privacy_screen_sw_state = val;
> > > > > } else if (property == connector->broadcast_rgb_property) {
> > > > > state->hdmi.broadcast_rgb = val;
> > > > > + } else if (property == connector->color_format_property) {
> > > > > + if (val > INT_MAX || !drm_connector_color_format_valid(val)) {
> > > > > + drm_dbg_atomic(connector->dev,
> > > > > + "[CONNECTOR:%d:%s] unknown color format %llu\n",
> > > > > + connector->base.id, connector->name, val);
> > > > > + return -EINVAL;
> > > > > + }
> > > > > +
> > > > > + state->color_format = val;
> > > > > } else if (connector->funcs->atomic_set_property) {
> > > > > return connector->funcs->atomic_set_property(connector,
> > > > > state, property, val);
> > > > > @@ -1020,6 +1029,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
> > > > > *val = state->privacy_screen_sw_state;
> > > > > } else if (property == connector->broadcast_rgb_property) {
> > > > > *val = state->hdmi.broadcast_rgb;
> > > > > + } else if (property == connector->color_format_property) {
> > > > > + *val = state->color_format;
> > > > > } else if (connector->funcs->atomic_get_property) {
> > > > > return connector->funcs->atomic_get_property(connector,
> > > > > state, property, val);
> > > > > diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> > > > > index 47dc53c4a738..e848374dee0b 100644
> > > > > --- a/drivers/gpu/drm/drm_connector.c
> > > > > +++ b/drivers/gpu/drm/drm_connector.c
> > > > > @@ -1388,6 +1388,18 @@ static const u32 hdmi_colorspaces =
> > > > > BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65) |
> > > > > BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER);
> > > > >
> > > > > +static const u32 hdmi_colorformats =
> > > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
> > > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
> > > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
> > > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
> > > > > +
> > > > > +static const u32 dp_colorformats =
> > > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
> > > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
> > > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
> > > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
> > > > > +
> > > > > /*
> > > > > * As per DP 1.4a spec, 2.2.5.7.5 VSC SDP Payload for Pixel Encoding/Colorimetry
> > > > > * Format Table 2-120
> > > > > @@ -2940,6 +2952,102 @@ int drm_connector_attach_colorspace_property(struct drm_connector *connector)
> > > > > }
> > > > > EXPORT_SYMBOL(drm_connector_attach_colorspace_property);
> > > > >
> > > > > +/**
> > > > > + * drm_connector_attach_color_format_property - create and attach color format property
> > > > > + * @connector: connector to create the color format property on
> > > > > + * @supported_color_formats: bitmask of bit-shifted &enum drm_output_color_format
> > > > > + * values the connector supports
> > > > > + *
> > > > > + * Called by a driver to create a color format property. The property is
> > > > > + * attached to the connector automatically on success.
> > > > > + *
> > > > > + * @supported_color_formats should only include color formats the connector
> > > > > + * type can actually support.
> > > > > + *
> > > > > + * Returns:
> > > > > + * 0 on success, negative errno on error
> > > > > + */
> > > > > +int drm_connector_attach_color_format_property(struct drm_connector *connector,
> > > > > + unsigned long supported_color_formats)
> > > > > +{
> > > > > + struct drm_device *dev = connector->dev;
> > > > > + struct drm_prop_enum_list enum_list[DRM_CONNECTOR_COLOR_FORMAT_COUNT];
> > > > > + unsigned int i = 0;
> > > > > + unsigned long fmt;
> > > > > +
> > > > > + if (connector->color_format_property)
> > > > > + return 0;
> > > > > +
> > > > > + if (!supported_color_formats) {
> > > > > + drm_err(dev, "No supported color formats provided on [CONNECTOR:%d:%s]\n",
> > > > > + connector->base.id, connector->name);
> > > > > + return -EINVAL;
> > > > > + }
> > > > > +
> > > > > + if (supported_color_formats & ~GENMASK(DRM_OUTPUT_COLOR_FORMAT_COUNT - 1, 0)) {
> > > > > + drm_err(dev, "Unknown color formats provided on [CONNECTOR:%d:%s]\n",
> > > > > + connector->base.id, connector->name);
> > > > > + return -EINVAL;
> > > > > + }
> > > > > +
> > > > > + switch (connector->connector_type) {
> > > > > + case DRM_MODE_CONNECTOR_HDMIA:
> > > > > + case DRM_MODE_CONNECTOR_HDMIB:
> > > > > + if (supported_color_formats & ~hdmi_colorformats) {
> > > > > + drm_err(dev, "Color formats not allowed for HDMI on [CONNECTOR:%d:%s]\n",
> > > > > + connector->base.id, connector->name);
> > > > > + return -EINVAL;
> > > > > + }
> > > > > + break;
> > > > > + case DRM_MODE_CONNECTOR_DisplayPort:
> > > > > + case DRM_MODE_CONNECTOR_eDP:
> > > > > + if (supported_color_formats & ~dp_colorformats) {
> > > > > + drm_err(dev, "Color formats not allowed for DP on [CONNECTOR:%d:%s]\n",
> > > > > + connector->base.id, connector->name);
> > > > > + return -EINVAL;
> > > > > + }
> > > > > + break;
> > > > > + }
> > > > > +
> > > > > + enum_list[0].name = "AUTO";
> > > > > + enum_list[0].type = DRM_CONNECTOR_COLOR_FORMAT_AUTO;
> > > > > +
> > > > > + for_each_set_bit(fmt, &supported_color_formats, DRM_OUTPUT_COLOR_FORMAT_COUNT) {
> > > > > + switch (fmt) {
> > > > > + case DRM_OUTPUT_COLOR_FORMAT_RGB444:
> > > > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_RGB444;
> > > > > + break;
> > > > > + case DRM_OUTPUT_COLOR_FORMAT_YCBCR444:
> > > > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR444;
> > > > > + break;
> > > > > + case DRM_OUTPUT_COLOR_FORMAT_YCBCR422:
> > > > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR422;
> > > > > + break;
> > > > > + case DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
> > > > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR420;
> > > > > + break;
> > > > > + default:
> > > > > + drm_warn(dev, "Unknown supported format %ld on [CONNECTOR:%d:%s]\n",
> > > > > + fmt, connector->base.id, connector->name);
> > > > > + continue;
> > > > > + }
> > > > > + enum_list[i].name = drm_hdmi_connector_get_output_format_name(fmt);
> > > > > + }
> > > > > +
> > > > > + connector->color_format_property =
> > > > > + drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, "color format",
> > > > > + enum_list, i + 1);
> > > > > +
> > > > > + if (!connector->color_format_property)
> > > > > + return -ENOMEM;
> > > > > +
> > > > > + drm_object_attach_property(&connector->base, connector->color_format_property,
> > > > > + DRM_CONNECTOR_COLOR_FORMAT_AUTO);
> > > > > +
> > > > > + return 0;
> > > > > +}
> > > > > +EXPORT_SYMBOL(drm_connector_attach_color_format_property);
> > > > > +
> > > > > /**
> > > > > * drm_connector_atomic_hdr_metadata_equal - checks if the hdr metadata changed
> > > > > * @old_state: old connector state to compare
> > > > > diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> > > > > index af8b92d2d5b7..bd549f912b76 100644
> > > > > --- a/include/drm/drm_connector.h
> > > > > +++ b/include/drm/drm_connector.h
> > > > > @@ -571,14 +571,102 @@ enum drm_colorspace {
> > > > > * YCbCr 4:2:2 output format (ie. with horizontal subsampling)
> > > > > * @DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
> > > > > * YCbCr 4:2:0 output format (ie. with horizontal and vertical subsampling)
> > > > > + * @DRM_OUTPUT_COLOR_FORMAT_COUNT:
> > > > > + * Number of valid output color format values in this enum
> > > > > */
> > > > > enum drm_output_color_format {
> > > > > DRM_OUTPUT_COLOR_FORMAT_RGB444 = 0,
> > > > > DRM_OUTPUT_COLOR_FORMAT_YCBCR444,
> > > > > DRM_OUTPUT_COLOR_FORMAT_YCBCR422,
> > > > > DRM_OUTPUT_COLOR_FORMAT_YCBCR420,
> > > > > + DRM_OUTPUT_COLOR_FORMAT_COUNT,
> > > > > };
> > > > >
> > > > > +/**
> > > > > + * enum drm_connector_color_format - Connector Color Format Request
> > > > > + *
> > > > > + * This enum, unlike &enum drm_output_color_format, is used to specify requests
> > > > > + * for a specific color format on a connector through the DRM "color format"
> > > > > + * property. The difference is that it has an "AUTO" value to specify that
> > > > > + * no specific choice has been made.
> > > > > + */
> > > > > +enum drm_connector_color_format {
> > > > > + /**
> > > > > + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> > > > > + * helpers should pick a suitable color format. All implementations of a
> > > > > + * specific display protocol must behave the same way with "AUTO", but
> > > > > + * different display protocols do not necessarily have the same "AUTO"
> > > > > + * semantics.
> > > > > + *
> > > > > + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> > > > > + * bandwidth required for full-scale RGB is not available, or the mode
> > > > > + * is YCbCr 4:2:0-only, as long as the mode and output both support
> > > > > + * YCbCr 4:2:0.
> > > >
> > > > Is there a reason you propose dropping back to YCbCr 4:2:0 without
> > > > trying YCbCr 4:2:2 first? Minimising the subsampling is surely
> > > > beneficial, and vc4 for one can do 4:2:2 but not 4:2:0.
> > >
> > > On HDMI 4:2:2 is always 12bpc, so it doesn't save any bandwidth
> > > compared to 8bpc 4:4:4.
> >
> > It does save bandwidth against 10 or 12bpc RGB 4:4:4.
> >
> > Or is the implication that max_bpc = 12 and
> > DRM_CONNECTOR_COLOR_FORMAT_AUTO should drop bpc down to 8 and select
> > RGB in preference to selecting 4:2:2?
>
> Yeah, YCbCr has all kinds of extra complications compared to RGB, so
> the policy is to use RGB if possible, and only fall back to YCbCr as a
> last resort. And in that case 4:2:0 is the only thing that can help.
So a media player wanting to do 12bpc HDR playback at 4k60 over HDMI
2.0 ends up with 8bpc RGB regardless. That sucks.
I guess at least an override is being added so userspace can take control.
I'd missed that vc4 had its behaviour changed with the
drm_hdmi_state_helper update :-(
Dave
^ permalink raw reply [flat|nested] 48+ messages in thread
* [PATCH v11 04/22] drm/bridge: Act on the DRM color format property
2026-03-24 16:01 [PATCH v11 00/22] Add new general DRM property "color format" Nicolas Frattaroli
` (2 preceding siblings ...)
2026-03-24 16:01 ` [PATCH v11 03/22] drm: Add new general DRM property "color format" Nicolas Frattaroli
@ 2026-03-24 16:01 ` Nicolas Frattaroli
2026-03-24 16:01 ` [PATCH v11 05/22] drm/atomic-helper: Add HDMI bridge output bus formats helper Nicolas Frattaroli
` (17 subsequent siblings)
21 siblings, 0 replies; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-24 16:01 UTC (permalink / raw)
To: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc,
Nicolas Frattaroli
The new DRM color format property allows userspace to request a specific
color format on a connector. In turn, this fills the connector state's
color_format member to switch color formats.
Make drm_bridges consider the color_format set in the connector state
during the atomic bridge check. For bridges that represent HDMI bridges,
rely on whatever format the HDMI logic set. Reject any output bus
formats that do not correspond to the requested color format.
Non-HDMI last bridges with DRM_CONNECTOR_COLOR_FORMAT_AUTO set will end
up choosing the first output format that functions to make a whole
recursive bridge chain format selection succeed.
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/drm_bridge.c | 89 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 88 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 1c2903c6e44b..9ee3a8c25510 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -1150,6 +1150,47 @@ static int select_bus_fmt_recursive(struct drm_bridge *first_bridge,
return ret;
}
+static bool __pure bus_format_is_color_fmt(u32 bus_fmt, enum drm_connector_color_format fmt)
+{
+ if (fmt == DRM_CONNECTOR_COLOR_FORMAT_AUTO)
+ return true;
+
+ switch (bus_fmt) {
+ case MEDIA_BUS_FMT_FIXED:
+ return true;
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ case MEDIA_BUS_FMT_RGB101010_1X30:
+ case MEDIA_BUS_FMT_RGB121212_1X36:
+ case MEDIA_BUS_FMT_RGB161616_1X48:
+ return fmt == DRM_CONNECTOR_COLOR_FORMAT_RGB444;
+ case MEDIA_BUS_FMT_YUV8_1X24:
+ case MEDIA_BUS_FMT_YUV10_1X30:
+ case MEDIA_BUS_FMT_YUV12_1X36:
+ case MEDIA_BUS_FMT_YUV16_1X48:
+ return fmt == DRM_CONNECTOR_COLOR_FORMAT_YCBCR444;
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_VYUY8_1X16:
+ case MEDIA_BUS_FMT_YUYV8_1X16:
+ case MEDIA_BUS_FMT_YVYU8_1X16:
+ case MEDIA_BUS_FMT_UYVY10_1X20:
+ case MEDIA_BUS_FMT_YUYV10_1X20:
+ case MEDIA_BUS_FMT_VYUY10_1X20:
+ case MEDIA_BUS_FMT_YVYU10_1X20:
+ case MEDIA_BUS_FMT_UYVY12_1X24:
+ case MEDIA_BUS_FMT_VYUY12_1X24:
+ case MEDIA_BUS_FMT_YUYV12_1X24:
+ case MEDIA_BUS_FMT_YVYU12_1X24:
+ return fmt == DRM_CONNECTOR_COLOR_FORMAT_YCBCR422;
+ case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+ case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+ case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
+ case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
+ return fmt == DRM_CONNECTOR_COLOR_FORMAT_YCBCR420;
+ default:
+ return false;
+ }
+}
+
/*
* This function is called by &drm_atomic_bridge_chain_check() just before
* calling &drm_bridge_funcs.atomic_check() on all elements of the chain.
@@ -1193,6 +1234,7 @@ drm_atomic_bridge_chain_select_bus_fmts(struct drm_bridge *bridge,
struct drm_encoder *encoder = bridge->encoder;
struct drm_bridge_state *last_bridge_state;
unsigned int i, num_out_bus_fmts = 0;
+ enum drm_connector_color_format fmt;
u32 *out_bus_fmts;
int ret = 0;
@@ -1234,13 +1276,58 @@ drm_atomic_bridge_chain_select_bus_fmts(struct drm_bridge *bridge,
out_bus_fmts[0] = MEDIA_BUS_FMT_FIXED;
}
+ /*
+ * On HDMI connectors, use the output format chosen by whatever does the
+ * HDMI logic. For everyone else, just trust that the bridge out_bus_fmts
+ * are sorted by preference for %DRM_CONNECTOR_COLOR_FORMAT_AUTO, as
+ * bus_format_is_color_fmt() always returns true for AUTO.
+ */
+ if (last_bridge->type == DRM_MODE_CONNECTOR_HDMIA) {
+ drm_dbg_kms(last_bridge->dev,
+ "HDMI bridge requests format %s\n",
+ drm_hdmi_connector_get_output_format_name(
+ conn_state->hdmi.output_format));
+ switch (conn_state->hdmi.output_format) {
+ case DRM_OUTPUT_COLOR_FORMAT_RGB444:
+ fmt = DRM_CONNECTOR_COLOR_FORMAT_RGB444;
+ break;
+ case DRM_OUTPUT_COLOR_FORMAT_YCBCR444:
+ fmt = DRM_CONNECTOR_COLOR_FORMAT_YCBCR444;
+ break;
+ case DRM_OUTPUT_COLOR_FORMAT_YCBCR422:
+ fmt = DRM_CONNECTOR_COLOR_FORMAT_YCBCR422;
+ break;
+ case DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
+ fmt = DRM_CONNECTOR_COLOR_FORMAT_YCBCR420;
+ break;
+ default:
+ ret = -EINVAL;
+ goto out_free_bus_fmts;
+ }
+ } else {
+ fmt = conn_state->color_format;
+ drm_dbg_kms(last_bridge->dev, "Non-HDMI bridge requests format %d\n", fmt);
+ }
+
for (i = 0; i < num_out_bus_fmts; i++) {
+ if (!bus_format_is_color_fmt(out_bus_fmts[i], fmt)) {
+ drm_dbg_kms(last_bridge->dev,
+ "Skipping bus format 0x%04x as it doesn't match format %d\n",
+ out_bus_fmts[i], fmt);
+ ret = -ENOTSUPP;
+ continue;
+ }
ret = select_bus_fmt_recursive(bridge, last_bridge, crtc_state,
conn_state, out_bus_fmts[i]);
- if (ret != -ENOTSUPP)
+ if (ret != -ENOTSUPP) {
+ drm_dbg_kms(last_bridge->dev,
+ "Found bridge chain ending with bus format 0x%04x\n",
+ out_bus_fmts[i]);
break;
+ }
}
+out_free_bus_fmts:
kfree(out_bus_fmts);
return ret;
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread* [PATCH v11 05/22] drm/atomic-helper: Add HDMI bridge output bus formats helper
2026-03-24 16:01 [PATCH v11 00/22] Add new general DRM property "color format" Nicolas Frattaroli
` (3 preceding siblings ...)
2026-03-24 16:01 ` [PATCH v11 04/22] drm/bridge: Act on the DRM color format property Nicolas Frattaroli
@ 2026-03-24 16:01 ` Nicolas Frattaroli
2026-03-24 16:01 ` [PATCH v11 06/22] drm/display: hdmi-state-helper: Act on color format DRM property Nicolas Frattaroli
` (16 subsequent siblings)
21 siblings, 0 replies; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-24 16:01 UTC (permalink / raw)
To: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc,
Nicolas Frattaroli
The drm_bridge_funcs atomic_get_output_bus_fmts operation should be the
same for likely every HDMI connector bridge, unless such an HDMI
connector bridge has some special hardware restrictions that I cannot
envision yet.
To avoid code duplication and standardize on a set of media bus formats
that the HDMI output color formats translate to, add a common helper
function that implements this operation to the drm bridge helpers.
The function returns a list of output bus formats based on the HDMI
bridge's current output bits-per-component, and its bitmask of supported
color formats.
To guard against future expansion of DRM_OUTPUT_COLOR_FORMAT outgrowing
the hweight8 call, add a BUILD_BUG_ON statement where it's used that
checks for DRM_OUTPUT_COLOR_FORMAT_COUNT. The justification for not
using hweight32 in all cases is that not all ISAs have a popcount
instruction, and will benefit from a smaller/faster software
implementation that doesn't have to operate across all bits.
The justification for not defining an hweight_color depending on the
value of DRM_OUTPUT_COLOR_FORMAT_COUNT is that this count enum value is
only known at compile time, not at preprocessor time.
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/drm_atomic_helper.c | 81 +++++++++++++++++++++++++++++++++++++
include/drm/drm_atomic_helper.h | 7 ++++
2 files changed, 88 insertions(+)
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index b7753454b777..e8613e6df1f4 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -28,6 +28,7 @@
#include <linux/export.h>
#include <linux/dma-fence.h>
#include <linux/ktime.h>
+#include <linux/media-bus-format.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
@@ -4095,3 +4096,83 @@ drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge,
return input_fmts;
}
EXPORT_SYMBOL(drm_atomic_helper_bridge_propagate_bus_fmt);
+
+/**
+ * drm_atomic_helper_bridge_get_hdmi_output_bus_fmts - helper implementing
+ * atomic_get_output_bus_fmts for HDMI
+ * @bridge: pointer to &struct drm_bridge
+ * @bridge_state: pointer to the current bridge state
+ * @crtc_state: pointer to the current CRTC state
+ * @conn_state: pointer to the current connector state
+ * @num_output_fmts: pointer to where the number of entries in the returned array
+ * will be stored. Set to 0 if unsuccessful.
+ *
+ * Common implementation for the &drm_bridge_funcs.atomic_get_output_bus_fmts
+ * operation that's applicable to HDMI connectors.
+ *
+ * Returns: a newly allocated array of u32 values of length \*@num_output_fmts,
+ * representing all the MEDIA_BUS_FMTS\_ for the current connector state's
+ * chosen HDMI output bits per compoennt, or %NULL if it fails to allocate one.
+ */
+u32 *
+drm_atomic_helper_bridge_get_hdmi_output_bus_fmts(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state,
+ unsigned int *num_output_fmts)
+{
+ unsigned int num_fmts = 0;
+ u32 *out_fmts;
+
+ /*
+ * bridge->supported_formats is a bit field of BIT(enum drm_output_color_format)
+ * values. The smallest hweight that is smaller than or equal to
+ * %DRM_OUTPUT_COLOR_FORMAT_COUNT will do for counting set bits here.
+ */
+ BUILD_BUG_ON(const_true(DRM_OUTPUT_COLOR_FORMAT_COUNT > 8));
+ out_fmts = kmalloc_array(hweight8(bridge->supported_formats),
+ sizeof(u32), GFP_KERNEL);
+ if (!out_fmts) {
+ *num_output_fmts = 0;
+ return NULL;
+ }
+
+ switch (conn_state->hdmi.output_bpc) {
+ case 12:
+ if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444))
+ out_fmts[num_fmts++] = MEDIA_BUS_FMT_RGB121212_1X36;
+ if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444))
+ out_fmts[num_fmts++] = MEDIA_BUS_FMT_YUV12_1X36;
+ if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422))
+ out_fmts[num_fmts++] = MEDIA_BUS_FMT_UYVY12_1X24;
+ if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420))
+ out_fmts[num_fmts++] = MEDIA_BUS_FMT_UYYVYY12_0_5X36;
+ break;
+ case 10:
+ if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444))
+ out_fmts[num_fmts++] = MEDIA_BUS_FMT_RGB101010_1X30;
+ if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444))
+ out_fmts[num_fmts++] = MEDIA_BUS_FMT_YUV10_1X30;
+ if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422))
+ out_fmts[num_fmts++] = MEDIA_BUS_FMT_UYVY10_1X20;
+ if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420))
+ out_fmts[num_fmts++] = MEDIA_BUS_FMT_UYYVYY10_0_5X30;
+ break;
+ default:
+ if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444))
+ out_fmts[num_fmts++] = MEDIA_BUS_FMT_RGB888_1X24;
+ if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444))
+ out_fmts[num_fmts++] = MEDIA_BUS_FMT_YUV8_1X24;
+ if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422))
+ out_fmts[num_fmts++] = MEDIA_BUS_FMT_UYVY8_1X16;
+ if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420))
+ out_fmts[num_fmts++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
+ break;
+ }
+
+ *num_output_fmts = num_fmts;
+
+ return out_fmts;
+}
+EXPORT_SYMBOL(drm_atomic_helper_bridge_get_hdmi_output_bus_fmts);
+
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index e154ee4f0696..7256eaca109b 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -295,4 +295,11 @@ drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge,
u32 output_fmt,
unsigned int *num_input_fmts);
+u32 *
+drm_atomic_helper_bridge_get_hdmi_output_bus_fmts(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state,
+ unsigned int *num_output_fmts);
+
#endif /* DRM_ATOMIC_HELPER_H_ */
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread* [PATCH v11 06/22] drm/display: hdmi-state-helper: Act on color format DRM property
2026-03-24 16:01 [PATCH v11 00/22] Add new general DRM property "color format" Nicolas Frattaroli
` (4 preceding siblings ...)
2026-03-24 16:01 ` [PATCH v11 05/22] drm/atomic-helper: Add HDMI bridge output bus formats helper Nicolas Frattaroli
@ 2026-03-24 16:01 ` Nicolas Frattaroli
2026-03-24 16:01 ` [PATCH v11 07/22] drm/display: hdmi-state-helper: Try subsampling in mode_valid Nicolas Frattaroli
` (15 subsequent siblings)
21 siblings, 0 replies; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-24 16:01 UTC (permalink / raw)
To: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc,
Nicolas Frattaroli, Dmitry Baryshkov
With the introduction of the "color format" DRM property, which allows
userspace to request a specific color format, the HDMI state helper
should implement this.
Implement it by translating the requested drm_connector_color_format to
a drm_output_color_format enum value as per the logic HDMI should use
for this: Auto is translated to RGB, and a fallback to YUV420 is only
performed if the original color format was auto.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 31 +++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index a0d88701d236..954f8b2973fc 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -670,8 +670,39 @@ hdmi_compute_config(const struct drm_connector *connector,
unsigned int max_bpc = clamp_t(unsigned int,
conn_state->max_bpc,
8, connector->max_bpc);
+ enum drm_output_color_format fmt;
int ret;
+ if (conn_state->color_format != DRM_CONNECTOR_COLOR_FORMAT_AUTO) {
+ switch (conn_state->color_format) {
+ case DRM_CONNECTOR_COLOR_FORMAT_AUTO:
+ drm_warn(connector->dev, "AUTO format in non-AUTO path.\n");
+ fallthrough;
+ case DRM_CONNECTOR_COLOR_FORMAT_RGB444:
+ fmt = DRM_OUTPUT_COLOR_FORMAT_RGB444;
+ break;
+ case DRM_CONNECTOR_COLOR_FORMAT_YCBCR444:
+ fmt = DRM_OUTPUT_COLOR_FORMAT_YCBCR444;
+ break;
+ case DRM_CONNECTOR_COLOR_FORMAT_YCBCR422:
+ fmt = DRM_OUTPUT_COLOR_FORMAT_YCBCR422;
+ break;
+ case DRM_CONNECTOR_COLOR_FORMAT_YCBCR420:
+ fmt = DRM_OUTPUT_COLOR_FORMAT_YCBCR420;
+ break;
+ default:
+ drm_dbg_kms(connector->dev, "HDMI does not support color format '%d'.\n",
+ conn_state->color_format);
+ return -EINVAL;
+ }
+
+ return hdmi_compute_format_bpc(connector, conn_state, mode, max_bpc, fmt);
+ }
+
+ /*
+ * For %DRM_CONNECTOR_COLOR_FORMAT_AUTO, try RGB first, and fall back
+ * to the less bandwidth-intensive YCBCR420 if RGB fails.
+ */
ret = hdmi_compute_format_bpc(connector, conn_state, mode, max_bpc,
DRM_OUTPUT_COLOR_FORMAT_RGB444);
if (ret) {
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread* [PATCH v11 07/22] drm/display: hdmi-state-helper: Try subsampling in mode_valid
2026-03-24 16:01 [PATCH v11 00/22] Add new general DRM property "color format" Nicolas Frattaroli
` (5 preceding siblings ...)
2026-03-24 16:01 ` [PATCH v11 06/22] drm/display: hdmi-state-helper: Act on color format DRM property Nicolas Frattaroli
@ 2026-03-24 16:01 ` Nicolas Frattaroli
2026-03-24 16:01 ` [PATCH v11 08/22] drm/i915: Implement the "color format" DRM property Nicolas Frattaroli
` (14 subsequent siblings)
21 siblings, 0 replies; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-24 16:01 UTC (permalink / raw)
To: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc,
Nicolas Frattaroli, Dmitry Baryshkov
drm_hdmi_connector_mode_valid assumes modes are only valid if they work
with RGB. The reality is more complex however: YCbCr 4:2:0
chroma-subsampled modes only require half the pixel clock that the same
mode would require in RGB.
This leads to drm_hdmi_connector_mode_valid rejecting perfectly valid
420-only or 420-also modes.
Fix this by checking whether the mode is 420-capable first. If so, then
proceed by checking it with DRM_OUTPUT_COLOR_FORMAT_YCBCR420 so long as
the connector has legalized 420, otherwise error out. If the mode is not
420-capable, check with RGB as was previously always the case.
Fixes: 47368ab437fd ("drm/display: hdmi: add generic mode_valid helper")
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index 954f8b2973fc..5cc30da30989 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -942,8 +942,21 @@ drm_hdmi_connector_mode_valid(struct drm_connector *connector,
const struct drm_display_mode *mode)
{
unsigned long long clock;
+ enum drm_output_color_format fmt;
+
+ if (drm_mode_is_420_only(&connector->display_info, mode)) {
+ if (connector->ycbcr_420_allowed)
+ fmt = DRM_OUTPUT_COLOR_FORMAT_YCBCR420;
+ else
+ return MODE_NO_420;
+ } else if (drm_mode_is_420_also(&connector->display_info, mode) &&
+ connector->ycbcr_420_allowed) {
+ fmt = DRM_OUTPUT_COLOR_FORMAT_YCBCR420;
+ } else {
+ fmt = DRM_OUTPUT_COLOR_FORMAT_RGB444;
+ }
- clock = drm_hdmi_compute_mode_clock(mode, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444);
+ clock = drm_hdmi_compute_mode_clock(mode, 8, fmt);
if (!clock)
return MODE_ERROR;
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread* [PATCH v11 08/22] drm/i915: Implement the "color format" DRM property
2026-03-24 16:01 [PATCH v11 00/22] Add new general DRM property "color format" Nicolas Frattaroli
` (6 preceding siblings ...)
2026-03-24 16:01 ` [PATCH v11 07/22] drm/display: hdmi-state-helper: Try subsampling in mode_valid Nicolas Frattaroli
@ 2026-03-24 16:01 ` Nicolas Frattaroli
2026-03-24 16:01 ` [PATCH v11 09/22] drm/amdgpu: Implement " Nicolas Frattaroli
` (13 subsequent siblings)
21 siblings, 0 replies; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-24 16:01 UTC (permalink / raw)
To: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc,
Nicolas Frattaroli, Werner Sembach, Andri Yngvason, Marius Vlad
This includes RGB, YUV420, YUV444 and Auto. Auto will pick RGB, unless
the mode being asked for is YUV420-only, in which case it picks YUV420.
Should the explicitly requested color format not be supported by the
sink, then an error is returned to userspace, so that it can make a
better choice.
Co-developed-by: Werner Sembach <wse@tuxedocomputers.com>
Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
Co-developed-by: Andri Yngvason <andri@yngvason.is>
Signed-off-by: Andri Yngvason <andri@yngvason.is>
Co-developed-by: Marius Vlad <marius.vlad@collabora.com>
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/i915/display/intel_connector.c | 10 ++++
drivers/gpu/drm/i915/display/intel_connector.h | 1 +
drivers/gpu/drm/i915/display/intel_dp.c | 71 ++++++++++++++++++++-----
drivers/gpu/drm/i915/display/intel_dp.h | 4 ++
drivers/gpu/drm/i915/display/intel_dp_mst.c | 52 ++++++++++++++++++-
drivers/gpu/drm/i915/display/intel_hdmi.c | 72 ++++++++++++++++++++------
6 files changed, 181 insertions(+), 29 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/intel_connector.c b/drivers/gpu/drm/i915/display/intel_connector.c
index 7ef9338d67ab..d54ae1522b6f 100644
--- a/drivers/gpu/drm/i915/display/intel_connector.c
+++ b/drivers/gpu/drm/i915/display/intel_connector.c
@@ -38,6 +38,10 @@
#include "intel_hdcp.h"
#include "intel_panel.h"
+static const u32 supported_colorformats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
+
static void intel_connector_modeset_retry_work_fn(struct work_struct *work)
{
struct intel_connector *connector = container_of(work, typeof(*connector),
@@ -321,6 +325,12 @@ intel_attach_dp_colorspace_property(struct drm_connector *connector)
drm_connector_attach_colorspace_property(connector);
}
+void
+intel_attach_colorformat_property(struct drm_connector *connector)
+{
+ drm_connector_attach_color_format_property(connector, supported_colorformats);
+}
+
void
intel_attach_scaling_mode_property(struct drm_connector *connector)
{
diff --git a/drivers/gpu/drm/i915/display/intel_connector.h b/drivers/gpu/drm/i915/display/intel_connector.h
index 0aa86626e646..fe6149d1d559 100644
--- a/drivers/gpu/drm/i915/display/intel_connector.h
+++ b/drivers/gpu/drm/i915/display/intel_connector.h
@@ -31,6 +31,7 @@ void intel_attach_broadcast_rgb_property(struct drm_connector *connector);
void intel_attach_aspect_ratio_property(struct drm_connector *connector);
void intel_attach_hdmi_colorspace_property(struct drm_connector *connector);
void intel_attach_dp_colorspace_property(struct drm_connector *connector);
+void intel_attach_colorformat_property(struct drm_connector *connector);
void intel_attach_scaling_mode_property(struct drm_connector *connector);
void intel_connector_queue_modeset_retry_work(struct intel_connector *connector);
void intel_connector_cancel_modeset_retry_work(struct intel_connector *connector);
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 4955bd8b11d7..31f2bb92bba6 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -1178,7 +1178,7 @@ dfp_can_convert(struct intel_dp *intel_dp,
return false;
}
-static enum intel_output_format
+enum intel_output_format
intel_dp_output_format(struct intel_connector *connector,
enum intel_output_format sink_format)
{
@@ -3337,17 +3337,24 @@ intel_dp_compute_output_format(struct intel_encoder *encoder,
struct intel_connector *connector = intel_dp->attached_connector;
const struct drm_display_info *info = &connector->base.display_info;
const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
- bool ycbcr_420_only;
+ enum drm_connector_color_format actual_format;
int ret;
- ycbcr_420_only = drm_mode_is_420_only(info, adjusted_mode);
+ if ((conn_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_YCBCR420 &&
+ drm_mode_is_420(info, adjusted_mode)) ||
+ (conn_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_AUTO &&
+ drm_mode_is_420_only(info, adjusted_mode)))
+ crtc_state->sink_format = INTEL_OUTPUT_FORMAT_YCBCR420;
+ else if (conn_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_YCBCR444)
+ crtc_state->sink_format = INTEL_OUTPUT_FORMAT_YCBCR444;
+ else
+ crtc_state->sink_format = INTEL_OUTPUT_FORMAT_RGB;
- if (ycbcr_420_only && !connector->base.ycbcr_420_allowed) {
+ if (crtc_state->sink_format == INTEL_OUTPUT_FORMAT_YCBCR420 &&
+ !connector->base.ycbcr_420_allowed) {
drm_dbg_kms(display->drm,
- "YCbCr 4:2:0 mode but YCbCr 4:2:0 output not possible. Falling back to RGB.\n");
- crtc_state->sink_format = INTEL_OUTPUT_FORMAT_RGB;
- } else {
- crtc_state->sink_format = intel_dp_sink_format(connector, adjusted_mode);
+ "YCbCr 4:2:0 mode requested but unsupported by connector.\n");
+ return -EINVAL;
}
crtc_state->output_format = intel_dp_output_format(connector, crtc_state->sink_format);
@@ -3355,9 +3362,20 @@ intel_dp_compute_output_format(struct intel_encoder *encoder,
ret = intel_dp_compute_link_config(encoder, crtc_state, conn_state,
respect_downstream_limits);
if (ret) {
- if (crtc_state->sink_format == INTEL_OUTPUT_FORMAT_YCBCR420 ||
- !connector->base.ycbcr_420_allowed ||
- !drm_mode_is_420_also(info, adjusted_mode))
+ /*
+ * If no valid link config can be found due to bandwidth constraints,
+ * degrade from RGB/YCbCr 4:4:4 to YCbCr 4:2:0 if permitted by
+ * the source and sink.
+ */
+ if (!connector->base.ycbcr_420_allowed)
+ return ret;
+ /* No point in trying YCbCr420 a second time. */
+ if (crtc_state->sink_format == INTEL_OUTPUT_FORMAT_YCBCR420)
+ return ret;
+ if (!drm_mode_is_420(info, adjusted_mode))
+ return ret;
+ /* If a non-AUTO color format is chosen, don't fall back. */
+ if (conn_state->color_format)
return ret;
crtc_state->sink_format = INTEL_OUTPUT_FORMAT_YCBCR420;
@@ -3365,9 +3383,36 @@ intel_dp_compute_output_format(struct intel_encoder *encoder,
crtc_state->sink_format);
ret = intel_dp_compute_link_config(encoder, crtc_state, conn_state,
respect_downstream_limits);
+ if (ret)
+ return ret;
}
- return ret;
+ if (conn_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_AUTO)
+ return 0;
+
+ switch (crtc_state->sink_format) {
+ case INTEL_OUTPUT_FORMAT_RGB:
+ actual_format = DRM_CONNECTOR_COLOR_FORMAT_RGB444;
+ break;
+ case INTEL_OUTPUT_FORMAT_YCBCR444:
+ actual_format = DRM_CONNECTOR_COLOR_FORMAT_YCBCR444;
+ break;
+ case INTEL_OUTPUT_FORMAT_YCBCR420:
+ actual_format = DRM_CONNECTOR_COLOR_FORMAT_YCBCR420;
+ break;
+ default:
+ drm_dbg_kms(display->drm, "Intel format %d has no connector equivalent\n",
+ crtc_state->sink_format);
+ return -EINVAL;
+ }
+
+ if (actual_format != conn_state->color_format) {
+ drm_dbg_kms(display->drm, "Requested connector color format %d, got %d\n",
+ conn_state->color_format, actual_format);
+ return -EINVAL;
+ }
+
+ return 0;
}
void
@@ -6956,6 +7001,8 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *_connec
intel_attach_dp_colorspace_property(&connector->base);
}
+ intel_attach_colorformat_property(&connector->base);
+
if (intel_dp_has_gamut_metadata_dip(&dp_to_dig_port(intel_dp)->base))
drm_connector_attach_hdr_output_metadata_property(&connector->base);
diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
index 2849b9ecdc71..c42badf752e2 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.h
+++ b/drivers/gpu/drm/i915/display/intel_dp.h
@@ -204,6 +204,10 @@ bool intel_dp_compute_config_limits(struct intel_dp *intel_dp,
void intel_dp_get_dsc_sink_cap(u8 dpcd_rev,
const struct drm_dp_desc *desc, bool is_branch,
struct intel_connector *connector);
+enum intel_output_format
+intel_dp_output_format(struct intel_connector *connector,
+ enum intel_output_format sink_format);
+
bool intel_dp_has_gamut_metadata_dip(struct intel_encoder *encoder);
bool intel_dp_link_params_valid(struct intel_dp *intel_dp, int link_rate,
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
index 887b6de14e46..1b939c7adf9d 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
@@ -705,10 +705,13 @@ static int mst_stream_compute_config(struct intel_encoder *encoder,
struct intel_atomic_state *state = to_intel_atomic_state(conn_state->state);
struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc);
struct intel_dp *intel_dp = to_primary_dp(encoder);
+ enum drm_connector_color_format actual_format;
struct intel_connector *connector =
to_intel_connector(conn_state->connector);
const struct drm_display_mode *adjusted_mode =
&pipe_config->hw.adjusted_mode;
+ const struct drm_display_info *info =
+ &connector->base.display_info;
int num_joined_pipes;
int ret = -EINVAL;
@@ -719,10 +722,53 @@ static int mst_stream_compute_config(struct intel_encoder *encoder,
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
return -EINVAL;
- pipe_config->sink_format = INTEL_OUTPUT_FORMAT_RGB;
- pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
+ if ((conn_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_YCBCR420 &&
+ drm_mode_is_420(info, adjusted_mode)) ||
+ (conn_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_AUTO &&
+ drm_mode_is_420_only(info, adjusted_mode))) {
+ pipe_config->sink_format = INTEL_OUTPUT_FORMAT_YCBCR420;
+ } else if (conn_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_YCBCR444) {
+ pipe_config->sink_format = INTEL_OUTPUT_FORMAT_YCBCR444;
+ } else if (conn_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_AUTO ||
+ conn_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_RGB444) {
+ pipe_config->sink_format = INTEL_OUTPUT_FORMAT_RGB;
+ } else {
+ drm_dbg_kms(display->drm, "Requested format %d unsupported.\n",
+ conn_state->color_format);
+ return -EINVAL;
+ }
+
+ if (pipe_config->sink_format == INTEL_OUTPUT_FORMAT_YCBCR420 &&
+ !connector->base.ycbcr_420_allowed) {
+ drm_dbg_kms(display->drm,
+ "YCbCr 4:2:0 mode requested but unsupported by connector.\n");
+ return -EINVAL;
+ }
+
+ pipe_config->output_format = intel_dp_output_format(connector, pipe_config->sink_format);
pipe_config->has_pch_encoder = false;
+ /* Validate that the right format was picked if explicitly requested */
+ if (conn_state->color_format != DRM_CONNECTOR_COLOR_FORMAT_AUTO) {
+ switch (pipe_config->output_format) {
+ case INTEL_OUTPUT_FORMAT_RGB:
+ actual_format = DRM_CONNECTOR_COLOR_FORMAT_RGB444;
+ break;
+ case INTEL_OUTPUT_FORMAT_YCBCR444:
+ actual_format = DRM_CONNECTOR_COLOR_FORMAT_YCBCR444;
+ break;
+ case INTEL_OUTPUT_FORMAT_YCBCR420:
+ actual_format = DRM_CONNECTOR_COLOR_FORMAT_YCBCR420;
+ break;
+ }
+
+ if (actual_format != conn_state->color_format) {
+ drm_dbg_kms(display->drm, "Requested connector color format %d, got %d\n",
+ conn_state->color_format, actual_format);
+ return -EINVAL;
+ }
+ }
+
for_each_joiner_candidate(connector, adjusted_mode, num_joined_pipes) {
if (num_joined_pipes > 1)
pipe_config->joiner_pipes = GENMASK(crtc->pipe + num_joined_pipes - 1,
@@ -1693,6 +1739,8 @@ static int mst_topology_add_connector_properties(struct intel_dp *intel_dp,
if (connector->base.max_bpc_property)
drm_connector_attach_max_bpc_property(&connector->base, 6, 12);
+ intel_attach_colorformat_property(&connector->base);
+
return drm_connector_set_path_property(&connector->base, pathprop);
}
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 05e898d10a2b..6b685d9a458e 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -2270,33 +2270,73 @@ static int intel_hdmi_compute_output_format(struct intel_encoder *encoder,
struct intel_connector *connector = to_intel_connector(conn_state->connector);
const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
const struct drm_display_info *info = &connector->base.display_info;
- bool ycbcr_420_only = drm_mode_is_420_only(info, adjusted_mode);
+ enum drm_connector_color_format req_fmt = conn_state->color_format;
+ enum drm_connector_color_format actual_fmt;
int ret;
- crtc_state->sink_format =
- intel_hdmi_sink_format(crtc_state, connector, ycbcr_420_only);
-
- if (ycbcr_420_only && crtc_state->sink_format != INTEL_OUTPUT_FORMAT_YCBCR420) {
- drm_dbg_kms(display->drm,
- "YCbCr 4:2:0 mode but YCbCr 4:2:0 output not possible. Falling back to RGB.\n");
- crtc_state->sink_format = INTEL_OUTPUT_FORMAT_RGB;
- }
+ if (!req_fmt)
+ crtc_state->sink_format =
+ intel_hdmi_sink_format(crtc_state, connector,
+ drm_mode_is_420_only(info, adjusted_mode));
+ else if (req_fmt == DRM_CONNECTOR_COLOR_FORMAT_YCBCR444)
+ crtc_state->sink_format = INTEL_OUTPUT_FORMAT_YCBCR444;
+ else
+ crtc_state->sink_format =
+ intel_hdmi_sink_format(crtc_state, connector,
+ req_fmt == DRM_CONNECTOR_COLOR_FORMAT_YCBCR420);
crtc_state->output_format = intel_hdmi_output_format(crtc_state);
ret = intel_hdmi_compute_clock(encoder, crtc_state, respect_downstream_limits);
if (ret) {
- if (crtc_state->sink_format == INTEL_OUTPUT_FORMAT_YCBCR420 ||
- !crtc_state->has_hdmi_sink ||
- !connector->base.ycbcr_420_allowed ||
- !drm_mode_is_420_also(info, adjusted_mode))
+ /*
+ * If no valid link config can be found due to bandwidth constraints,
+ * degrade from RGB/YCbCr 4:4:4 to YCbCr 4:2:0 if permitted by
+ * the source and sink.
+ */
+ if (!connector->base.ycbcr_420_allowed)
+ return ret;
+ /* No point in trying YCbCr420 a second time. */
+ if (crtc_state->sink_format == INTEL_OUTPUT_FORMAT_YCBCR420)
+ return ret;
+ if (!drm_mode_is_420(info, adjusted_mode))
+ return ret;
+ /* If a non-AUTO color format is chosen, don't fall back. */
+ if (req_fmt)
return ret;
crtc_state->sink_format = INTEL_OUTPUT_FORMAT_YCBCR420;
crtc_state->output_format = intel_hdmi_output_format(crtc_state);
ret = intel_hdmi_compute_clock(encoder, crtc_state, respect_downstream_limits);
+ if (ret)
+ return ret;
}
- return ret;
+ if (req_fmt == DRM_CONNECTOR_COLOR_FORMAT_AUTO)
+ return 0;
+
+ switch (crtc_state->sink_format) {
+ case INTEL_OUTPUT_FORMAT_RGB:
+ actual_fmt = DRM_CONNECTOR_COLOR_FORMAT_RGB444;
+ break;
+ case INTEL_OUTPUT_FORMAT_YCBCR444:
+ actual_fmt = DRM_CONNECTOR_COLOR_FORMAT_YCBCR444;
+ break;
+ case INTEL_OUTPUT_FORMAT_YCBCR420:
+ actual_fmt = DRM_CONNECTOR_COLOR_FORMAT_YCBCR420;
+ break;
+ default:
+ drm_dbg_kms(display->drm, "Intel format %d has no connector equivalent\n",
+ crtc_state->sink_format);
+ return -EINVAL;
+ }
+
+ if (req_fmt != actual_fmt) {
+ drm_dbg_kms(display->drm, "Requested connector color format %d, got %d\n",
+ req_fmt, actual_fmt);
+ return -EINVAL;
+ }
+
+ return 0;
}
static bool intel_hdmi_is_cloned(const struct intel_crtc_state *crtc_state)
@@ -2689,8 +2729,10 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *_
if (DISPLAY_VER(display) >= 10)
drm_connector_attach_hdr_output_metadata_property(&connector->base);
- if (!HAS_GMCH(display))
+ if (!HAS_GMCH(display)) {
drm_connector_attach_max_bpc_property(&connector->base, 8, 12);
+ intel_attach_colorformat_property(&connector->base);
+ }
}
/*
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread* [PATCH v11 09/22] drm/amdgpu: Implement "color format" DRM property
2026-03-24 16:01 [PATCH v11 00/22] Add new general DRM property "color format" Nicolas Frattaroli
` (7 preceding siblings ...)
2026-03-24 16:01 ` [PATCH v11 08/22] drm/i915: Implement the "color format" DRM property Nicolas Frattaroli
@ 2026-03-24 16:01 ` Nicolas Frattaroli
2026-03-24 16:01 ` [PATCH v11 10/22] drm/rockchip: Add YUV422 output mode constants for VOP2 Nicolas Frattaroli
` (12 subsequent siblings)
21 siblings, 0 replies; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-24 16:01 UTC (permalink / raw)
To: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc,
Nicolas Frattaroli, Werner Sembach, Andri Yngvason, Marius Vlad
The "color format" DRM property allows userspace to explicitly pick a
color format to use. If an unsupported color format is requested,
userspace will be given an error instead of silently having its request
disobeyed.
The default case, which is AUTO, picks YCbCr 4:2:0 if it's a 4:2:0-only
mode, and RGB in all other cases.
Co-developed-by: Werner Sembach <wse@tuxedocomputers.com>
Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
Co-developed-by: Andri Yngvason <andri@yngvason.is>
Signed-off-by: Andri Yngvason <andri@yngvason.is>
Co-developed-by: Marius Vlad <marius.vlad@collabora.com>
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 90 +++++++++++++++++++---
.../amd/display/amdgpu_dm/amdgpu_dm_mst_types.c | 9 +++
2 files changed, 88 insertions(+), 11 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 86a64e98e8a1..5d3c6f3984ab 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6695,11 +6695,14 @@ static void fill_stream_properties_from_drm_display_mode(
const struct dc_stream_state *old_stream,
int requested_bpc)
{
+ bool is_dp_or_hdmi = dc_is_hdmi_signal(stream->signal) || dc_is_dp_signal(stream->signal);
struct dc_crtc_timing *timing_out = &stream->timing;
const struct drm_display_info *info = &connector->display_info;
struct amdgpu_dm_connector *aconnector = NULL;
struct hdmi_vendor_infoframe hv_frame;
struct hdmi_avi_infoframe avi_frame;
+ bool want_420;
+ bool want_422;
ssize_t err;
if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK)
@@ -6712,20 +6715,41 @@ static void fill_stream_properties_from_drm_display_mode(
timing_out->h_border_right = 0;
timing_out->v_border_top = 0;
timing_out->v_border_bottom = 0;
- /* TODO: un-hardcode */
- if (drm_mode_is_420_only(info, mode_in) ||
- (aconnector && aconnector->force_yuv420_output &&
- drm_mode_is_420_also(info, mode_in)))
+
+ want_420 = (aconnector && aconnector->force_yuv420_output) ||
+ (connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_YCBCR420);
+ want_422 = (aconnector && aconnector->force_yuv422_output) ||
+ (connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_YCBCR422);
+
+ if (drm_mode_is_420_only(info, mode_in) &&
+ (want_420 || connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_AUTO)) {
timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
- else if ((connector->display_info.color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422))
- && aconnector
- && aconnector->force_yuv422_output)
+ } else if (drm_mode_is_420_also(info, mode_in) && want_420) {
+ timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
+ } else if ((info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422)) &&
+ want_422 && is_dp_or_hdmi) {
timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR422;
- else if ((connector->display_info.color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444))
- && stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
+ } else if (connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_YCBCR444 &&
+ (info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444)) &&
+ is_dp_or_hdmi) {
timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR444;
- else
+ } else if (connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_RGB444 ||
+ connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_AUTO) {
timing_out->pixel_encoding = PIXEL_ENCODING_RGB;
+ } else {
+ /*
+ * If a format was explicitly requested but the requested format
+ * can't be satisfied, set it to an invalid value so that an
+ * error bubbles up to userspace. This way, userspace knows it
+ * needs to make a better choice.
+ */
+ if (connector_state->color_format != DRM_CONNECTOR_COLOR_FORMAT_AUTO)
+ timing_out->pixel_encoding = PIXEL_ENCODING_UNDEFINED;
+ else if (drm_mode_is_420_only(info, mode_in))
+ timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
+ else
+ timing_out->pixel_encoding = PIXEL_ENCODING_RGB;
+ }
timing_out->timing_3d_format = TIMING_3D_FORMAT_NONE;
timing_out->display_color_depth = convert_color_depth_from_display_info(
@@ -8075,6 +8099,38 @@ static enum dc_status dm_validate_stream_and_context(struct dc *dc,
return dc_result;
}
+static enum dc_status
+dm_validate_stream_color_format(const struct drm_connector_state *drm_state,
+ const struct dc_stream_state *stream)
+{
+ enum dc_pixel_encoding encoding;
+
+ if (!drm_state->color_format)
+ return DC_OK;
+
+ switch (drm_state->color_format) {
+ case DRM_CONNECTOR_COLOR_FORMAT_AUTO:
+ case DRM_CONNECTOR_COLOR_FORMAT_RGB444:
+ encoding = PIXEL_ENCODING_RGB;
+ break;
+ case DRM_CONNECTOR_COLOR_FORMAT_YCBCR444:
+ encoding = PIXEL_ENCODING_YCBCR444;
+ break;
+ case DRM_CONNECTOR_COLOR_FORMAT_YCBCR422:
+ encoding = PIXEL_ENCODING_YCBCR422;
+ break;
+ case DRM_CONNECTOR_COLOR_FORMAT_YCBCR420:
+ encoding = PIXEL_ENCODING_YCBCR420;
+ break;
+ default:
+ encoding = PIXEL_ENCODING_UNDEFINED;
+ break;
+ }
+
+ return encoding == stream->timing.pixel_encoding ?
+ DC_OK : DC_UNSUPPORTED_VALUE;
+}
+
struct dc_stream_state *
create_validate_stream_for_sink(struct drm_connector *connector,
const struct drm_display_mode *drm_mode,
@@ -8121,6 +8177,9 @@ create_validate_stream_for_sink(struct drm_connector *connector,
if (dc_result == DC_OK)
dc_result = dm_validate_stream_and_context(adev->dm.dc, stream);
+ if (dc_result == DC_OK)
+ dc_result = dm_validate_stream_color_format(drm_state, stream);
+
if (dc_result != DC_OK) {
drm_dbg_kms(connector->dev, "Pruned mode %d x %d (clk %d) %s %s -- %s\n",
drm_mode->hdisplay,
@@ -8950,6 +9009,12 @@ static const u32 supported_colorspaces =
BIT(DRM_MODE_COLORIMETRY_BT2020_RGB) |
BIT(DRM_MODE_COLORIMETRY_BT2020_YCC);
+static const u32 supported_colorformats =
+ BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
+
void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
struct amdgpu_dm_connector *aconnector,
int connector_type,
@@ -9066,8 +9131,11 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
connector_type == DRM_MODE_CONNECTOR_eDP) {
drm_connector_attach_hdr_output_metadata_property(&aconnector->base);
- if (!aconnector->mst_root)
+ if (!aconnector->mst_root) {
drm_connector_attach_vrr_capable_property(&aconnector->base);
+ drm_connector_attach_color_format_property(&aconnector->base,
+ supported_colorformats);
+ }
if (adev->dm.hdcp_workqueue)
drm_connector_attach_content_protection_property(&aconnector->base, true);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index 7be50e8c0636..9bced7257f8b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -52,6 +52,12 @@
#define PEAK_FACTOR_X1000 1006
+static const u32 supported_colorformats =
+ BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
+
/*
* This function handles both native AUX and I2C-Over-AUX transactions.
*/
@@ -679,6 +685,9 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
if (connector->max_bpc_property)
drm_connector_attach_max_bpc_property(connector, 8, 16);
+ drm_connector_attach_color_format_property(&aconnector->base,
+ supported_colorformats);
+
connector->vrr_capable_property = master->base.vrr_capable_property;
if (connector->vrr_capable_property)
drm_connector_attach_vrr_capable_property(connector);
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread* [PATCH v11 10/22] drm/rockchip: Add YUV422 output mode constants for VOP2
2026-03-24 16:01 [PATCH v11 00/22] Add new general DRM property "color format" Nicolas Frattaroli
` (8 preceding siblings ...)
2026-03-24 16:01 ` [PATCH v11 09/22] drm/amdgpu: Implement " Nicolas Frattaroli
@ 2026-03-24 16:01 ` Nicolas Frattaroli
2026-03-24 16:01 ` [PATCH v11 11/22] drm/rockchip: vop2: Add RK3576 to the RG swap special case Nicolas Frattaroli
` (11 subsequent siblings)
21 siblings, 0 replies; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-24 16:01 UTC (permalink / raw)
To: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc,
Nicolas Frattaroli, Andy Yan
The Rockchip display controller has a general YUV422 output mode, and
some SoC-specific connector-specific output modes for RK3576.
Add them, based on the values in downstream and the TRM (dsp_out_mode in
RK3576 TRM Part 2, register POST*_CTRL_POST_DSP_CTRL).
Reviewed-by: Andy Yan <andyshrk@163.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index 2e86ad00979c..4705dc6b8bd7 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -30,10 +30,14 @@
#define ROCKCHIP_OUT_MODE_P565 2
#define ROCKCHIP_OUT_MODE_BT656 5
#define ROCKCHIP_OUT_MODE_S888 8
+#define ROCKCHIP_OUT_MODE_YUV422 9
#define ROCKCHIP_OUT_MODE_S888_DUMMY 12
#define ROCKCHIP_OUT_MODE_YUV420 14
/* for use special outface */
#define ROCKCHIP_OUT_MODE_AAAA 15
+/* SoC specific output modes */
+#define ROCKCHIP_OUT_MODE_YUV422_RK3576_DP 12
+#define ROCKCHIP_OUT_MODE_YUV422_RK3576_HDMI 13
/* output flags */
#define ROCKCHIP_OUTPUT_DSI_DUAL BIT(0)
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread* [PATCH v11 11/22] drm/rockchip: vop2: Add RK3576 to the RG swap special case
2026-03-24 16:01 [PATCH v11 00/22] Add new general DRM property "color format" Nicolas Frattaroli
` (9 preceding siblings ...)
2026-03-24 16:01 ` [PATCH v11 10/22] drm/rockchip: Add YUV422 output mode constants for VOP2 Nicolas Frattaroli
@ 2026-03-24 16:01 ` Nicolas Frattaroli
2026-03-24 16:01 ` [PATCH v11 12/22] drm/rockchip: vop2: Recognise 10-bit YUV422 as YUV format Nicolas Frattaroli
` (10 subsequent siblings)
21 siblings, 0 replies; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-24 16:01 UTC (permalink / raw)
To: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc,
Nicolas Frattaroli, Andy Yan
Much like RK3588, RK3576 requires an RG swap to be performed for YUV444
8-bit and YUV444 10-bit bus formats.
Add its version to the already existing check for RK3588, so that YUV444
output is correct on this platform.
Fixes: 944757a4cba6 ("drm/rockchip: vop2: Add support for rk3576")
Reviewed-by: Andy Yan <andyshrk@163.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 843c7ef979b2..d3b76e7e785e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -337,7 +337,8 @@ static bool vop2_output_uv_swap(u32 bus_format, u32 output_mode)
static bool vop2_output_rg_swap(struct vop2 *vop2, u32 bus_format)
{
- if (vop2->version == VOP_VERSION_RK3588) {
+ if (vop2->version == VOP_VERSION_RK3588 ||
+ vop2->version == VOP_VERSION_RK3576) {
if (bus_format == MEDIA_BUS_FMT_YUV8_1X24 ||
bus_format == MEDIA_BUS_FMT_YUV10_1X30)
return true;
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread* [PATCH v11 12/22] drm/rockchip: vop2: Recognise 10-bit YUV422 as YUV format
2026-03-24 16:01 [PATCH v11 00/22] Add new general DRM property "color format" Nicolas Frattaroli
` (10 preceding siblings ...)
2026-03-24 16:01 ` [PATCH v11 11/22] drm/rockchip: vop2: Add RK3576 to the RG swap special case Nicolas Frattaroli
@ 2026-03-24 16:01 ` Nicolas Frattaroli
2026-03-24 16:01 ` [PATCH v11 13/22] drm/rockchip: vop2: Set correct output format for RK3576 YUV422 Nicolas Frattaroli
` (9 subsequent siblings)
21 siblings, 0 replies; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-24 16:01 UTC (permalink / raw)
To: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc,
Nicolas Frattaroli, Cristian Ciocaltea
The Rockchip VOP2 video output driver has a "is_yuv_output" function,
which returns true when a given bus format is a YUV format, and false
otherwise.
This switch statement is lacking the bus format used for YUV422 10-bit.
Add the two component orderings of the YUV422 10-bit bus formats to the
switch statement.
Fixes: 604be85547ce ("drm/rockchip: Add VOP2 driver")
Reviewed-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index d3b76e7e785e..59d15bacf023 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -352,6 +352,8 @@ static bool is_yuv_output(u32 bus_format)
switch (bus_format) {
case MEDIA_BUS_FMT_YUV8_1X24:
case MEDIA_BUS_FMT_YUV10_1X30:
+ case MEDIA_BUS_FMT_YUYV10_1X20:
+ case MEDIA_BUS_FMT_UYVY10_1X20:
case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
case MEDIA_BUS_FMT_YUYV8_2X8:
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread* [PATCH v11 13/22] drm/rockchip: vop2: Set correct output format for RK3576 YUV422
2026-03-24 16:01 [PATCH v11 00/22] Add new general DRM property "color format" Nicolas Frattaroli
` (11 preceding siblings ...)
2026-03-24 16:01 ` [PATCH v11 12/22] drm/rockchip: vop2: Recognise 10-bit YUV422 as YUV format Nicolas Frattaroli
@ 2026-03-24 16:01 ` Nicolas Frattaroli
2026-03-24 16:01 ` [PATCH v11 14/22] drm/bridge: dw-hdmi-qp: Use common HDMI output bus fmts helper Nicolas Frattaroli
` (8 subsequent siblings)
21 siblings, 0 replies; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-24 16:01 UTC (permalink / raw)
To: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc,
Nicolas Frattaroli, Andy Yan
For RK3576 to be able to output YUV422 signals, it first needs to be
able to pick the right output mode in the display controller to do so.
The RK3576 hardware specifies different output formats depending on the
used display protocol.
Adjust the written register value based on the SoC and connector, so
other users of vcstate->output_mode don't have to care about this.
Reviewed-by: Andy Yan <andyshrk@163.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 59d15bacf023..e76e00f0a530 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1702,6 +1702,22 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc,
if (vcstate->output_mode == ROCKCHIP_OUT_MODE_AAAA &&
!(vp_data->feature & VOP2_VP_FEATURE_OUTPUT_10BIT))
out_mode = ROCKCHIP_OUT_MODE_P888;
+ else if (vcstate->output_mode == ROCKCHIP_OUT_MODE_YUV422 &&
+ vop2->version == VOP_VERSION_RK3576)
+ switch (vcstate->output_type) {
+ case DRM_MODE_CONNECTOR_DisplayPort:
+ case DRM_MODE_CONNECTOR_eDP:
+ out_mode = ROCKCHIP_OUT_MODE_YUV422_RK3576_DP;
+ break;
+ case DRM_MODE_CONNECTOR_HDMIA:
+ out_mode = ROCKCHIP_OUT_MODE_YUV422_RK3576_HDMI;
+ break;
+ default:
+ drm_err(vop2->drm, "Unknown DRM_MODE_CONNECTOR %d\n",
+ vcstate->output_type);
+ vop2_unlock(vop2);
+ return;
+ }
else
out_mode = vcstate->output_mode;
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread* [PATCH v11 14/22] drm/bridge: dw-hdmi-qp: Use common HDMI output bus fmts helper
2026-03-24 16:01 [PATCH v11 00/22] Add new general DRM property "color format" Nicolas Frattaroli
` (12 preceding siblings ...)
2026-03-24 16:01 ` [PATCH v11 13/22] drm/rockchip: vop2: Set correct output format for RK3576 YUV422 Nicolas Frattaroli
@ 2026-03-24 16:01 ` Nicolas Frattaroli
2026-03-24 16:01 ` [PATCH v11 15/22] drm/rockchip: dw_hdmi_qp: Implement "color format" DRM property Nicolas Frattaroli
` (7 subsequent siblings)
21 siblings, 0 replies; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-24 16:01 UTC (permalink / raw)
To: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc,
Nicolas Frattaroli, Cristian Ciocaltea
Make use of the common drm_bridge_funcs.atomic_get_output_bus_fmts
helper for HDMI bridge connectors.
This allows dw-hdmi-qp HDMI bridges to participate in recursive bus
format selection in a meaningful way.
Reviewed-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index d649a1cf07f5..5380aa7d82a8 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -1192,6 +1192,7 @@ static int dw_hdmi_qp_cec_transmit(struct drm_bridge *bridge, u8 attempts,
#endif /* CONFIG_DRM_DW_HDMI_QP_CEC */
static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {
+ .atomic_get_output_bus_fmts = drm_atomic_helper_bridge_get_hdmi_output_bus_fmts,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
.atomic_reset = drm_atomic_helper_bridge_reset,
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread* [PATCH v11 15/22] drm/rockchip: dw_hdmi_qp: Implement "color format" DRM property
2026-03-24 16:01 [PATCH v11 00/22] Add new general DRM property "color format" Nicolas Frattaroli
` (13 preceding siblings ...)
2026-03-24 16:01 ` [PATCH v11 14/22] drm/bridge: dw-hdmi-qp: Use common HDMI output bus fmts helper Nicolas Frattaroli
@ 2026-03-24 16:01 ` Nicolas Frattaroli
2026-03-24 16:01 ` [PATCH v11 16/22] drm/rockchip: dw_hdmi_qp: Set supported_formats platdata Nicolas Frattaroli
` (6 subsequent siblings)
21 siblings, 0 replies; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-24 16:01 UTC (permalink / raw)
To: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc,
Nicolas Frattaroli, Cristian Ciocaltea
Switch between requested color formats by setting the right bus formats,
configuring the VO GRF registers, and setting the right output mode.
To do this, the encoder's atomic_check queries the bus format of the
first bridge, which was determined by the bridge chain recursive format
selection. Pick the input format if it's !FIXED, otherwise, pick the
output format.
The previously unused GRF register color format defines are redone as
well. Both RK3588 and RK3576 use the same defines; it didn't look like
this as there was a typo in the previously (unused) definition.
Reviewed-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 107 ++++++++++++++++++++++---
1 file changed, 98 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 1a09bcc96c3e..e2fa1aa53394 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -11,6 +11,7 @@
#include <linux/gpio/consumer.h>
#include <linux/hw_bitfield.h>
#include <linux/mfd/syscon.h>
+#include <linux/media-bus-format.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/phy/phy.h>
@@ -43,10 +44,6 @@
#define RK3576_8BPC 0x0
#define RK3576_10BPC 0x6
#define RK3576_COLOR_FORMAT_MASK GENMASK(7, 4)
-#define RK3576_RGB 0x9
-#define RK3576_YUV422 0x1
-#define RK3576_YUV444 0x2
-#define RK3576_YUV420 0x3
#define RK3576_CECIN_MASK BIT(3)
#define RK3576_VO0_GRF_SOC_CON14 0x0038
@@ -74,8 +71,6 @@
#define RK3588_8BPC 0x0
#define RK3588_10BPC 0x6
#define RK3588_COLOR_FORMAT_MASK GENMASK(3, 0)
-#define RK3588_RGB 0x0
-#define RK3588_YUV420 0x3
#define RK3588_SCLIN_MASK BIT(9)
#define RK3588_SDAIN_MASK BIT(10)
#define RK3588_MODE_MASK BIT(11)
@@ -87,6 +82,11 @@
#define HOTPLUG_DEBOUNCE_MS 150
#define MAX_HDMI_PORT_NUM 2
+#define RK_COLOR_FMT_RGB 0x0
+#define RK_COLOR_FMT_YUV422 0x1
+#define RK_COLOR_FMT_YUV444 0x2
+#define RK_COLOR_FMT_YUV420 0x3
+
struct rockchip_hdmi_qp {
struct device *dev;
struct regmap *regmap;
@@ -115,6 +115,33 @@ static struct rockchip_hdmi_qp *to_rockchip_hdmi_qp(struct drm_encoder *encoder)
return container_of(rkencoder, struct rockchip_hdmi_qp, encoder);
}
+/**
+ * dw_hdmi_qp_rockchip_bus_fmt_to_reg - converts a bus format to a GRF reg value
+ * @bus_fmt: One of the MEDIA_BUS_FMT_s allowed by this driver's atomic_check
+ *
+ * Returns: an unshifted value to be written to the COLOR_FORMAT GRF register
+ * on success, or %-EINVAL if the bus format is not supported.
+ */
+static int __pure dw_hdmi_qp_rockchip_bus_fmt_to_reg(u32 bus_fmt)
+{
+ switch (bus_fmt) {
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ case MEDIA_BUS_FMT_RGB101010_1X30:
+ return RK_COLOR_FMT_RGB;
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_UYVY10_1X20:
+ return RK_COLOR_FMT_YUV422;
+ case MEDIA_BUS_FMT_YUV8_1X24:
+ case MEDIA_BUS_FMT_YUV10_1X30:
+ return RK_COLOR_FMT_YUV444;
+ case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+ case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+ return RK_COLOR_FMT_YUV420;
+ }
+
+ return -EINVAL;
+}
+
static void dw_hdmi_qp_rockchip_encoder_enable(struct drm_encoder *encoder)
{
struct rockchip_hdmi_qp *hdmi = to_rockchip_hdmi_qp(encoder);
@@ -130,29 +157,83 @@ static void dw_hdmi_qp_rockchip_encoder_enable(struct drm_encoder *encoder)
hdmi->ctrl_ops->enc_init(hdmi, to_rockchip_crtc_state(crtc->state));
}
+/**
+ * dw_hdmi_qp_rockchip_get_vop_format - get the bus format VOP should output
+ * @encoder: pointer to a &struct drm_encoder
+ * @conn_state: pointer to the current atomic &struct drm_connector_state
+ *
+ * Determines which bus format the Rockchip video processor should output as
+ * to feed into the bridge chain.
+ *
+ * Returns a MEDIA_BUS_FMT_* on success, or %0 on error.
+ */
+static u32 dw_hdmi_qp_rockchip_get_vop_format(struct drm_encoder *encoder,
+ struct drm_connector_state *conn_state)
+{
+ struct drm_bridge *bridge __free(drm_bridge_put) = NULL;
+ struct drm_bridge_state *bstate;
+
+ bridge = drm_bridge_chain_get_first_bridge(encoder);
+ if (!bridge)
+ return 0;
+
+ bstate = drm_atomic_get_bridge_state(conn_state->state, bridge);
+ if (!bstate)
+ return 0;
+
+ if (bstate->input_bus_cfg.format != MEDIA_BUS_FMT_FIXED)
+ return bstate->input_bus_cfg.format;
+
+ return bstate->output_bus_cfg.format;
+}
+
static int
dw_hdmi_qp_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state)
{
- struct rockchip_hdmi_qp *hdmi = to_rockchip_hdmi_qp(encoder);
struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
+ struct rockchip_hdmi_qp *hdmi = to_rockchip_hdmi_qp(encoder);
union phy_configure_opts phy_cfg = {};
+ u32 ingest_fmt;
int ret;
+ ingest_fmt = dw_hdmi_qp_rockchip_get_vop_format(encoder, conn_state);
+ if (!ingest_fmt)
+ return -EINVAL;
+
if (hdmi->tmds_char_rate == conn_state->hdmi.tmds_char_rate &&
- s->output_bpc == conn_state->hdmi.output_bpc)
+ s->output_bpc == conn_state->hdmi.output_bpc &&
+ s->bus_format == ingest_fmt)
return 0;
+ switch (ingest_fmt) {
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ case MEDIA_BUS_FMT_RGB101010_1X30:
+ case MEDIA_BUS_FMT_YUV8_1X24:
+ case MEDIA_BUS_FMT_YUV10_1X30:
+ s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
+ break;
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ s->output_mode = ROCKCHIP_OUT_MODE_YUV422;
+ break;
+ case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+ case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+ s->output_mode = ROCKCHIP_OUT_MODE_YUV420;
+ break;
+ default:
+ return -EINVAL;
+ }
+
phy_cfg.hdmi.tmds_char_rate = conn_state->hdmi.tmds_char_rate;
phy_cfg.hdmi.bpc = conn_state->hdmi.output_bpc;
ret = phy_configure(hdmi->phy, &phy_cfg);
if (!ret) {
hdmi->tmds_char_rate = conn_state->hdmi.tmds_char_rate;
- s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
s->output_type = DRM_MODE_CONNECTOR_HDMIA;
s->output_bpc = conn_state->hdmi.output_bpc;
+ s->bus_format = ingest_fmt;
} else {
dev_err(hdmi->dev, "Failed to configure phy: %d\n", ret);
}
@@ -382,6 +463,7 @@ static void dw_hdmi_qp_rk3588_io_init(struct rockchip_hdmi_qp *hdmi)
static void dw_hdmi_qp_rk3576_enc_init(struct rockchip_hdmi_qp *hdmi,
struct rockchip_crtc_state *state)
{
+ int color = dw_hdmi_qp_rockchip_bus_fmt_to_reg(state->bus_format);
u32 val;
if (state->output_bpc == 10)
@@ -389,12 +471,16 @@ static void dw_hdmi_qp_rk3576_enc_init(struct rockchip_hdmi_qp *hdmi,
else
val = FIELD_PREP_WM16(RK3576_COLOR_DEPTH_MASK, RK3576_8BPC);
+ if (likely(color >= 0))
+ val |= FIELD_PREP_WM16(RK3576_COLOR_FORMAT_MASK, color);
+
regmap_write(hdmi->vo_regmap, RK3576_VO0_GRF_SOC_CON8, val);
}
static void dw_hdmi_qp_rk3588_enc_init(struct rockchip_hdmi_qp *hdmi,
struct rockchip_crtc_state *state)
{
+ int color = dw_hdmi_qp_rockchip_bus_fmt_to_reg(state->bus_format);
u32 val;
if (state->output_bpc == 10)
@@ -402,6 +488,9 @@ static void dw_hdmi_qp_rk3588_enc_init(struct rockchip_hdmi_qp *hdmi,
else
val = FIELD_PREP_WM16(RK3588_COLOR_DEPTH_MASK, RK3588_8BPC);
+ if (likely(color >= 0))
+ val |= FIELD_PREP_WM16(RK3588_COLOR_FORMAT_MASK, color);
+
regmap_write(hdmi->vo_regmap,
hdmi->port_id ? RK3588_GRF_VO1_CON6 : RK3588_GRF_VO1_CON3,
val);
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread* [PATCH v11 16/22] drm/rockchip: dw_hdmi_qp: Set supported_formats platdata
2026-03-24 16:01 [PATCH v11 00/22] Add new general DRM property "color format" Nicolas Frattaroli
` (14 preceding siblings ...)
2026-03-24 16:01 ` [PATCH v11 15/22] drm/rockchip: dw_hdmi_qp: Implement "color format" DRM property Nicolas Frattaroli
@ 2026-03-24 16:01 ` Nicolas Frattaroli
2026-03-24 16:01 ` [PATCH v11 17/22] drm/connector: Register color format property on HDMI connectors Nicolas Frattaroli
` (5 subsequent siblings)
21 siblings, 0 replies; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-24 16:01 UTC (permalink / raw)
To: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc,
Nicolas Frattaroli, Cristian Ciocaltea
With the introduction of the supported_formats member in the
dw-hdmi-qp platform data struct, drivers that have access to this
information should now set it.
Set it in the rockchip dw_hdmi_qp glue driver.
This allows this information to be passed down to the dw-hdmi-qp core,
which sets it in the bridge it creates, and consequently will allow the
common HDMI bridge code to act on it.
Reviewed-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index e2fa1aa53394..ec78c6895334 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -601,6 +601,10 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
plat_data.phy_data = hdmi;
plat_data.max_bpc = 10;
+ plat_data.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422);
+
encoder = &hdmi->encoder.encoder;
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread* [PATCH v11 17/22] drm/connector: Register color format property on HDMI connectors
2026-03-24 16:01 [PATCH v11 00/22] Add new general DRM property "color format" Nicolas Frattaroli
` (15 preceding siblings ...)
2026-03-24 16:01 ` [PATCH v11 16/22] drm/rockchip: dw_hdmi_qp: Set supported_formats platdata Nicolas Frattaroli
@ 2026-03-24 16:01 ` Nicolas Frattaroli
2026-03-24 16:01 ` [PATCH v11 18/22] drm/tests: hdmi: Add tests for the color_format property Nicolas Frattaroli
` (4 subsequent siblings)
21 siblings, 0 replies; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-24 16:01 UTC (permalink / raw)
To: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc,
Nicolas Frattaroli
The drmm_connector_hdmi_init function can figure out what DRM color
formats are supported by a particular connector based on the supported
HDMI format bitmask that's passed in.
Use it to register the drm color format property.
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/drm_connector.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index e848374dee0b..724245d2df29 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -627,6 +627,10 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
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;
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread* [PATCH v11 18/22] drm/tests: hdmi: Add tests for the color_format property
2026-03-24 16:01 [PATCH v11 00/22] Add new general DRM property "color format" Nicolas Frattaroli
` (16 preceding siblings ...)
2026-03-24 16:01 ` [PATCH v11 17/22] drm/connector: Register color format property on HDMI connectors Nicolas Frattaroli
@ 2026-03-24 16:01 ` Nicolas Frattaroli
2026-03-24 16:01 ` [PATCH v11 19/22] drm/tests: hdmi: Add tests for HDMI helper's mode_valid Nicolas Frattaroli
` (3 subsequent siblings)
21 siblings, 0 replies; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-24 16:01 UTC (permalink / raw)
To: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc,
Nicolas Frattaroli
Add some KUnit tests to check the color_format property is working as
expected with the HDMI state helper.
Existing tests are extended to also test the
DRM_CONNECTOR_COLOR_FORMAT_AUTO case, in order to avoid duplicating test
cases. For the explicitly selected color format cases, parameterized
tests are added.
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 236 +++++++++++++++++++++
1 file changed, 236 insertions(+)
diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
index a4357efaa983..3444c93c615f 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -60,6 +60,23 @@ static struct drm_display_mode *find_preferred_mode(struct drm_connector *connec
return preferred;
}
+static struct drm_display_mode *find_420_only_mode(struct drm_connector *connector)
+{
+ struct drm_device *drm = connector->dev;
+ struct drm_display_mode *mode;
+
+ mutex_lock(&drm->mode_config.mutex);
+ list_for_each_entry(mode, &connector->modes, head) {
+ if (drm_mode_is_420_only(&connector->display_info, mode)) {
+ mutex_unlock(&drm->mode_config.mutex);
+ return mode;
+ }
+ }
+ mutex_unlock(&drm->mode_config.mutex);
+
+ return NULL;
+}
+
static int set_connector_edid(struct kunit *test, struct drm_connector *connector,
const void *edid, size_t edid_len)
{
@@ -1547,6 +1564,7 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_yuv420(struct kunit *test)
* RGB/10bpc
* - The chosen mode has a TMDS character rate lower than the display
* supports in YUV422/12bpc.
+ * - The HDMI connector state's color format property is unset (i.e. AUTO)
*
* Then we will prefer to keep the RGB format with a lower bpc over
* picking YUV422.
@@ -1609,6 +1627,7 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv422(struct kunit
conn_state = conn->state;
KUNIT_ASSERT_NOT_NULL(test, conn_state);
+ KUNIT_ASSERT_EQ(test, conn_state->color_format, DRM_CONNECTOR_COLOR_FORMAT_AUTO);
KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 10);
KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, DRM_OUTPUT_COLOR_FORMAT_RGB444);
@@ -1626,6 +1645,7 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv422(struct kunit
* RGB/8bpc
* - The chosen mode has a TMDS character rate lower than the display
* supports in YUV420/12bpc.
+ * - The HDMI connector state's color format property is unset (i.e. AUTO)
*
* Then we will prefer to keep the RGB format with a lower bpc over
* picking YUV420.
@@ -1687,6 +1707,7 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv420(struct kunit
conn_state = conn->state;
KUNIT_ASSERT_NOT_NULL(test, conn_state);
+ KUNIT_ASSERT_EQ(test, conn_state->color_format, DRM_CONNECTOR_COLOR_FORMAT_AUTO);
KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8);
KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, DRM_OUTPUT_COLOR_FORMAT_RGB444);
@@ -2198,6 +2219,217 @@ static void drm_test_check_disable_connector(struct kunit *test)
drm_modeset_acquire_fini(&ctx);
}
+struct color_format_test_param {
+ enum drm_connector_color_format fmt;
+ enum drm_output_color_format expected;
+ int expected_ret;
+ const char *desc;
+};
+
+/* Test that if:
+ * - an HDMI connector supports RGB, YUV444, YUV422, and YUV420
+ * - the display supports RGB, YUV444, YUV422, and YUV420
+ * - the "color format" property is set
+ * then, for the preferred mode, for a given "color format" option:
+ * - DRM_CONNECTOR_COLOR_FORMAT_AUTO results in an output format of RGB
+ * - DRM_CONNECTOR_COLOR_FORMAT_YCBCR422 results in an output format of YUV422
+ * - DRM_CONNECTOR_COLOR_FORMAT_YCBCR420 results in an output format of YUV420
+ * - DRM_CONNECTOR_COLOR_FORMAT_YCBCR444 results in an output format of YUV444
+ * - DRM_CONNECTOR_COLOR_FORMAT_RGB results in an HDMI output format of RGB
+ */
+static void drm_test_check_hdmi_color_format(struct kunit *test)
+{
+ const struct color_format_test_param *param = test->param_value;
+ struct drm_atomic_helper_connector_hdmi_priv *priv;
+ struct drm_connector_state *conn_state;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_crtc_state *crtc_state;
+ struct drm_atomic_state *state;
+ struct drm_display_info *info;
+ struct drm_display_mode *preferred;
+ int ret;
+
+ priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+ BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
+ 12,
+ &dummy_connector_hdmi_funcs,
+ test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+ KUNIT_ASSERT_TRUE(test, priv->connector.ycbcr_420_allowed);
+
+ info = &priv->connector.display_info;
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+ preferred = find_preferred_mode(&priv->connector);
+ KUNIT_ASSERT_TRUE(test, drm_mode_is_420(info, preferred));
+
+ state = drm_kunit_helper_atomic_state_alloc(test, &priv->drm, &ctx);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+ conn_state = drm_atomic_get_connector_state(state, &priv->connector);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+
+ conn_state->color_format = param->fmt;
+
+ ret = drm_atomic_set_crtc_for_connector(conn_state, priv->crtc);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ crtc_state = drm_atomic_get_crtc_state(state, priv->crtc);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+ ret = drm_atomic_set_mode_for_crtc(crtc_state, preferred);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ crtc_state->enable = true;
+ crtc_state->active = true;
+
+ ret = drm_atomic_check_only(state);
+ KUNIT_EXPECT_EQ(test, ret, param->expected_ret);
+ KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, param->expected);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+}
+
+static const struct color_format_test_param hdmi_color_format_params[] = {
+ {
+ .fmt = DRM_CONNECTOR_COLOR_FORMAT_AUTO,
+ .expected = DRM_OUTPUT_COLOR_FORMAT_RGB444,
+ .expected_ret = 0,
+ .desc = "AUTO -> RGB"
+ },
+ {
+ .fmt = DRM_CONNECTOR_COLOR_FORMAT_YCBCR422,
+ .expected = DRM_OUTPUT_COLOR_FORMAT_YCBCR422,
+ .expected_ret = 0,
+ .desc = "YCBCR422 -> YUV422"
+ },
+ {
+ .fmt = DRM_CONNECTOR_COLOR_FORMAT_YCBCR420,
+ .expected = DRM_OUTPUT_COLOR_FORMAT_YCBCR420,
+ .expected_ret = 0,
+ .desc = "YCBCR420 -> YUV420"
+ },
+ {
+ .fmt = DRM_CONNECTOR_COLOR_FORMAT_YCBCR444,
+ .expected = DRM_OUTPUT_COLOR_FORMAT_YCBCR444,
+ .expected_ret = 0,
+ .desc = "YCBCR444 -> YUV444"
+ },
+ {
+ .fmt = DRM_CONNECTOR_COLOR_FORMAT_RGB444,
+ .expected = DRM_OUTPUT_COLOR_FORMAT_RGB444,
+ .expected_ret = 0,
+ .desc = "RGB -> RGB"
+ },
+};
+
+KUNIT_ARRAY_PARAM_DESC(check_hdmi_color_format, hdmi_color_format_params, desc);
+
+/* Test that if:
+ * - the HDMI connector supports RGB, YUV422, YUV420, and YUV444
+ * - the display has a YUV420-only mode
+ * - the "color format" property is explicitly set (i.e. !AUTO)
+ * then:
+ * - color format DRM_CONNECTOR_COLOR_FORMAT_RGB444 will fail
+ * drm_atomic_check_only for the YUV420-only mode with -EINVAL
+ * - color format DRM_CONNECTOR_COLOR_FORMAT_YCBCR444 will fail
+ * drm_atomic_check_only for the YUV420-only mode with -EINVAL
+ * - color format DRM_CONNECTOR_COLOR_FORMAT_YCBCR422 will fail
+ * drm_atomic_check_only for the YUV420-only mode with -EINVAL
+ * - color format DRM_CONNECTOR_COLOR_FORMAT_YCBCR420 passes
+ * drm_atomic_check_only for the YUV420-only mode
+ */
+static void drm_test_check_hdmi_color_format_420_only(struct kunit *test)
+{
+ const struct color_format_test_param *param = test->param_value;
+ struct drm_atomic_helper_connector_hdmi_priv *priv;
+ struct drm_connector_state *conn_state;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_crtc_state *crtc_state;
+ struct drm_atomic_state *state;
+ struct drm_display_mode *dank;
+ int ret;
+
+ priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+ BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
+ 12,
+ &dummy_connector_hdmi_funcs,
+ test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+ dank = find_420_only_mode(&priv->connector);
+ KUNIT_ASSERT_NOT_NULL(test, dank);
+
+ state = drm_kunit_helper_atomic_state_alloc(test, &priv->drm, &ctx);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+ conn_state = drm_atomic_get_connector_state(state, &priv->connector);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+
+ conn_state->color_format = param->fmt;
+
+ ret = drm_atomic_set_crtc_for_connector(conn_state, priv->crtc);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ crtc_state = drm_atomic_get_crtc_state(state, priv->crtc);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+ ret = drm_atomic_set_mode_for_crtc(crtc_state, dank);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ crtc_state->enable = true;
+ crtc_state->active = true;
+
+ ret = drm_atomic_check_only(state);
+ KUNIT_EXPECT_EQ(test, ret, param->expected_ret);
+ if (!param->expected_ret)
+ KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, param->expected);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+};
+
+static const struct color_format_test_param hdmi_color_format_420_only_params[] = {
+ {
+ .fmt = DRM_CONNECTOR_COLOR_FORMAT_RGB444,
+ .expected = DRM_OUTPUT_COLOR_FORMAT_RGB444,
+ .expected_ret = -EINVAL,
+ .desc = "RGB should fail"
+ },
+ {
+ .fmt = DRM_CONNECTOR_COLOR_FORMAT_YCBCR444,
+ .expected = DRM_OUTPUT_COLOR_FORMAT_YCBCR444,
+ .expected_ret = -EINVAL,
+ .desc = "YUV444 should fail"
+ },
+ {
+ .fmt = DRM_CONNECTOR_COLOR_FORMAT_YCBCR422,
+ .expected = DRM_OUTPUT_COLOR_FORMAT_YCBCR422,
+ .expected_ret = -EINVAL,
+ .desc = "YUV422 should fail"
+ },
+ {
+ .fmt = DRM_CONNECTOR_COLOR_FORMAT_YCBCR420,
+ .expected = DRM_OUTPUT_COLOR_FORMAT_YCBCR420,
+ .expected_ret = 0,
+ .desc = "YUV420 should work"
+ },
+};
+
+KUNIT_ARRAY_PARAM_DESC(check_hdmi_color_format_420_only,
+ hdmi_color_format_420_only_params, desc);
+
static struct kunit_case drm_atomic_helper_connector_hdmi_check_tests[] = {
KUNIT_CASE(drm_test_check_broadcast_rgb_auto_cea_mode),
KUNIT_CASE(drm_test_check_broadcast_rgb_auto_cea_mode_vic_1),
@@ -2227,6 +2459,10 @@ static struct kunit_case drm_atomic_helper_connector_hdmi_check_tests[] = {
KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_8bpc),
KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_10bpc),
KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_12bpc),
+ KUNIT_CASE_PARAM(drm_test_check_hdmi_color_format,
+ check_hdmi_color_format_gen_params),
+ KUNIT_CASE_PARAM(drm_test_check_hdmi_color_format_420_only,
+ check_hdmi_color_format_420_only_gen_params),
/*
* TODO: We should have tests to check that a change in the
* format triggers a CRTC mode change just like we do for the
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread* [PATCH v11 19/22] drm/tests: hdmi: Add tests for HDMI helper's mode_valid
2026-03-24 16:01 [PATCH v11 00/22] Add new general DRM property "color format" Nicolas Frattaroli
` (17 preceding siblings ...)
2026-03-24 16:01 ` [PATCH v11 18/22] drm/tests: hdmi: Add tests for the color_format property Nicolas Frattaroli
@ 2026-03-24 16:01 ` Nicolas Frattaroli
2026-03-24 16:01 ` [PATCH v11 20/22] drm/tests: bridge: Add KUnit tests for bridge chain format selection Nicolas Frattaroli
` (2 subsequent siblings)
21 siblings, 0 replies; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-24 16:01 UTC (permalink / raw)
To: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc,
Nicolas Frattaroli
Add some KUnit tests to verify that the HDMI state helper's mode_valid
implementation does not improperly reject chroma subsampled modes on the
basis of their clock rate not being satisfiable in RGB.
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 109 +++++++++++++++++++++
1 file changed, 109 insertions(+)
diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
index 3444c93c615f..74c9933eabfc 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -77,6 +77,23 @@ static struct drm_display_mode *find_420_only_mode(struct drm_connector *connect
return NULL;
}
+static struct drm_display_mode *find_420_also_mode(struct drm_connector *connector)
+{
+ struct drm_device *drm = connector->dev;
+ struct drm_display_mode *mode;
+
+ mutex_lock(&drm->mode_config.mutex);
+ list_for_each_entry(mode, &connector->modes, head) {
+ if (drm_mode_is_420_also(&connector->display_info, mode)) {
+ mutex_unlock(&drm->mode_config.mutex);
+ return mode;
+ }
+ }
+ mutex_unlock(&drm->mode_config.mutex);
+
+ return NULL;
+}
+
static int set_connector_edid(struct kunit *test, struct drm_connector *connector,
const void *edid, size_t edid_len)
{
@@ -2745,11 +2762,103 @@ static void drm_test_check_mode_valid_reject_max_clock(struct kunit *test)
KUNIT_EXPECT_EQ(test, preferred->clock, 25200);
}
+/*
+ * Test that drm_hdmi_connector_mode_valid() will accept modes that require a
+ * 4:2:0 chroma subsampling, even if said mode would violate maximum clock
+ * constraints if it used RGB 4:4:4.
+ */
+static void drm_test_check_mode_valid_yuv420_only_max_clock(struct kunit *test)
+{
+ struct drm_atomic_helper_connector_hdmi_priv *priv;
+ struct drm_display_mode *dank;
+ struct drm_connector *conn;
+
+ priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+ BIT(HDMI_COLORSPACE_RGB) |
+ BIT(HDMI_COLORSPACE_YUV420),
+ 8,
+ &dummy_connector_hdmi_funcs,
+ test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ conn = &priv->connector;
+ KUNIT_ASSERT_EQ(test, conn->display_info.max_tmds_clock, 200 * 1000);
+
+ dank = find_420_only_mode(conn);
+ KUNIT_ASSERT_NOT_NULL(test, dank);
+ KUNIT_EXPECT_EQ(test, dank->hdisplay, 3840);
+ KUNIT_EXPECT_EQ(test, dank->vdisplay, 2160);
+
+ /*
+ * Note: The mode's "clock" here is not accurate to the actual TMDS
+ * clock that HDMI will use for a subsampled mode. Hence, why the mode's
+ * clock is above the .max_tmds_clock of 200MHz.
+ */
+ KUNIT_EXPECT_EQ(test, dank->clock, 297000);
+}
+
+/*
+ * Test that drm_hdmi_connector_mode_valid() will reject modes that require
+ * 4:2:0 chroma subsampling, if the connector does not support 4:2:0.
+ */
+static void
+drm_test_check_mode_valid_reject_yuv420_only_connector(struct kunit *test)
+{
+ struct drm_atomic_helper_connector_hdmi_priv *priv;
+ struct drm_display_mode *dank;
+ struct drm_connector *conn;
+
+ priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+ BIT(HDMI_COLORSPACE_RGB),
+ 8,
+ &dummy_connector_hdmi_funcs,
+ test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ conn = &priv->connector;
+ KUNIT_ASSERT_EQ(test, conn->display_info.max_tmds_clock, 200 * 1000);
+
+ dank = find_420_only_mode(conn);
+ KUNIT_EXPECT_NULL(test, dank);
+}
+
+/*
+ * Test that drm_hdmi_connector_mode_valid() will accept modes that allow (among
+ * other color formats) 4:2:0 chroma subsampling, even if the connector does not
+ * support 4:2:0, but the mode's clock works for RGB 4:4:4.
+ */
+static void
+drm_test_check_mode_valid_accept_yuv420_also_connector_rgb(struct kunit *test)
+{
+ struct drm_atomic_helper_connector_hdmi_priv *priv;
+ struct drm_display_mode *mode;
+ struct drm_connector *conn;
+
+ priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+ BIT(HDMI_COLORSPACE_RGB),
+ 8,
+ &dummy_connector_hdmi_funcs,
+ test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ conn = &priv->connector;
+ KUNIT_ASSERT_EQ(test, conn->display_info.max_tmds_clock, 340 * 1000);
+
+ mode = find_420_also_mode(conn);
+ KUNIT_ASSERT_NOT_NULL(test, mode);
+ KUNIT_EXPECT_EQ(test, mode->hdisplay, 3840);
+ KUNIT_EXPECT_EQ(test, mode->vdisplay, 2160);
+ KUNIT_EXPECT_EQ(test, mode->clock, 297000);
+}
+
static struct kunit_case drm_atomic_helper_connector_hdmi_mode_valid_tests[] = {
KUNIT_CASE(drm_test_check_mode_valid),
KUNIT_CASE(drm_test_check_mode_valid_reject),
KUNIT_CASE(drm_test_check_mode_valid_reject_rate),
KUNIT_CASE(drm_test_check_mode_valid_reject_max_clock),
+ KUNIT_CASE(drm_test_check_mode_valid_yuv420_only_max_clock),
+ KUNIT_CASE(drm_test_check_mode_valid_reject_yuv420_only_connector),
+ KUNIT_CASE(drm_test_check_mode_valid_accept_yuv420_also_connector_rgb),
{ }
};
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread* [PATCH v11 20/22] drm/tests: bridge: Add KUnit tests for bridge chain format selection
2026-03-24 16:01 [PATCH v11 00/22] Add new general DRM property "color format" Nicolas Frattaroli
` (18 preceding siblings ...)
2026-03-24 16:01 ` [PATCH v11 19/22] drm/tests: hdmi: Add tests for HDMI helper's mode_valid Nicolas Frattaroli
@ 2026-03-24 16:01 ` Nicolas Frattaroli
2026-03-24 16:01 ` [PATCH v11 21/22] drm/tests: bridge: Add test for HDMI output bus formats helper Nicolas Frattaroli
2026-03-24 16:01 ` [PATCH v11 22/22] drm/bridge: Document bridge chain format selection Nicolas Frattaroli
21 siblings, 0 replies; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-24 16:01 UTC (permalink / raw)
To: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc,
Nicolas Frattaroli
With the "color format" property, the bridge chain format selection has
gained increased complexity. Instead of simply finding any sequence of
bus formats that works, the bridge chain format selection needs to pick
a sequence that results in the requested color format.
Add KUnit tests for this new logic. These take the form of some pleasant
preprocessor macros to make it less cumbersome to define test bridges
with a set of possible input and output formats.
The input and output formats are defined for bridges in the form of
tuples, where the first member defines the input format, and the second
member defines the output format that can be produced from this input
format. This means the tests can construct scenarios in which not all
inputs can be converted to all outputs.
Some tests are added to test interesting scenarios to exercise the bus
format selection in the presence of a specific color format request.
Furthermore, tests are added to verify that bridge chains that end in an
HDMI connector will always prefer RGB when the color format is
DRM_CONNECTOR_COLOR_FORMAT_AUTO, as is the behaviour in the HDMI state
helpers.
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/tests/drm_bridge_test.c | 787 ++++++++++++++++++++++++++++++++
1 file changed, 787 insertions(+)
diff --git a/drivers/gpu/drm/tests/drm_bridge_test.c b/drivers/gpu/drm/tests/drm_bridge_test.c
index 887020141c7f..cb821c606070 100644
--- a/drivers/gpu/drm/tests/drm_bridge_test.c
+++ b/drivers/gpu/drm/tests/drm_bridge_test.c
@@ -2,15 +2,23 @@
/*
* Kunit test for drm_bridge functions
*/
+#include <linux/cleanup.h>
+#include <linux/media-bus-format.h>
+
#include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_atomic_uapi.h>
#include <drm/drm_bridge.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_bridge_helper.h>
+#include <drm/drm_edid.h>
#include <drm/drm_kunit_helpers.h>
+#include <drm/drm_managed.h>
#include <kunit/device.h>
#include <kunit/test.h>
+#include "drm_kunit_edid.h"
+
/*
* Mimick the typical "private" struct defined by a bridge driver, which
* embeds a bridge plus other fields.
@@ -37,6 +45,21 @@ struct drm_bridge_init_priv {
bool destroyed;
};
+struct drm_bridge_chain_priv {
+ struct drm_device drm;
+ struct drm_encoder encoder;
+ struct drm_plane *plane;
+ struct drm_crtc *crtc;
+ struct drm_connector *connector;
+ unsigned int num_bridges;
+
+ /**
+ * @test_bridges: array of pointers to &struct drm_bridge_priv entries
+ * of which the first @num_bridges entries are valid.
+ */
+ struct drm_bridge_priv **test_bridges;
+};
+
static struct drm_bridge_priv *bridge_to_priv(struct drm_bridge *bridge)
{
return container_of(bridge, struct drm_bridge_priv, bridge);
@@ -95,6 +118,229 @@ static const struct drm_bridge_funcs drm_test_bridge_atomic_funcs = {
.atomic_reset = drm_atomic_helper_bridge_reset,
};
+/**
+ * struct fmt_tuple - a tuple of input/output MEDIA_BUS_FMT_*
+ */
+struct fmt_tuple {
+ u32 in_fmt;
+ u32 out_fmt;
+};
+
+/*
+ * Format mapping that only accepts RGB888, and outputs only RGB888
+ */
+static const struct fmt_tuple rgb8_passthrough[] = {
+ { MEDIA_BUS_FMT_RGB888_1X24, MEDIA_BUS_FMT_RGB888_1X24 },
+};
+
+/*
+ * Format mapping that only accepts YUV444, and outputs only YUV444
+ */
+static const struct fmt_tuple yuv8_passthrough[] = {
+ { MEDIA_BUS_FMT_YUV8_1X24, MEDIA_BUS_FMT_YUV8_1X24 },
+};
+
+/*
+ * Format mapping where 8bpc RGB -> 8bpc YUV444, or ID(RGB) or ID(YUV444)
+ */
+static const struct fmt_tuple rgb8_to_yuv8_or_id[] = {
+ { MEDIA_BUS_FMT_RGB888_1X24, MEDIA_BUS_FMT_RGB888_1X24 },
+ { MEDIA_BUS_FMT_YUV8_1X24, MEDIA_BUS_FMT_YUV8_1X24 },
+ { MEDIA_BUS_FMT_RGB888_1X24, MEDIA_BUS_FMT_YUV8_1X24 },
+};
+
+static const struct fmt_tuple rgb8_to_id_yuv8_or_yuv8_to_yuv422_yuv420[] = {
+ { MEDIA_BUS_FMT_RGB888_1X24, MEDIA_BUS_FMT_RGB888_1X24 },
+ { MEDIA_BUS_FMT_RGB888_1X24, MEDIA_BUS_FMT_YUV8_1X24 },
+ { MEDIA_BUS_FMT_YUV8_1X24, MEDIA_BUS_FMT_UYVY8_1X16 },
+ { MEDIA_BUS_FMT_YUV8_1X24, MEDIA_BUS_FMT_UYYVYY8_0_5X24 },
+};
+
+/*
+ * Format mapping where 8bpc YUV444 -> 8bpc RGB, or ID(YUV444)
+ */
+static const struct fmt_tuple yuv8_to_rgb8_or_id[] = {
+ { MEDIA_BUS_FMT_YUV8_1X24, MEDIA_BUS_FMT_YUV8_1X24 },
+ { MEDIA_BUS_FMT_YUV8_1X24, MEDIA_BUS_FMT_RGB888_1X24 },
+};
+
+/*
+ * A format mapping that acts like a video processor that generates an RGB signal
+ */
+static const struct fmt_tuple rgb_producer[] = {
+ { MEDIA_BUS_FMT_FIXED, MEDIA_BUS_FMT_RGB888_1X24 },
+ { MEDIA_BUS_FMT_FIXED, MEDIA_BUS_FMT_RGB101010_1X30 },
+ { MEDIA_BUS_FMT_FIXED, MEDIA_BUS_FMT_RGB121212_1X36 },
+};
+
+/*
+ * A format mapping that acts like a video processor that generates an 8-bit RGB,
+ * YUV444 or YUV420 signal
+ */
+static const struct fmt_tuple rgb_yuv444_yuv420_producer[] = {
+ { MEDIA_BUS_FMT_FIXED, MEDIA_BUS_FMT_RGB888_1X24 },
+ { MEDIA_BUS_FMT_FIXED, MEDIA_BUS_FMT_YUV8_1X24 },
+ { MEDIA_BUS_FMT_FIXED, MEDIA_BUS_FMT_UYYVYY8_0_5X24 },
+};
+
+static const struct fmt_tuple rgb8_yuv444_yuv422_passthrough[] = {
+ { MEDIA_BUS_FMT_RGB888_1X24, MEDIA_BUS_FMT_RGB888_1X24 },
+ { MEDIA_BUS_FMT_YUV8_1X24, MEDIA_BUS_FMT_YUV8_1X24 },
+ { MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_UYVY8_1X16 },
+};
+
+static const struct fmt_tuple yuv444_yuv422_rgb8_passthrough[] = {
+ { MEDIA_BUS_FMT_YUV8_1X24, MEDIA_BUS_FMT_YUV8_1X24 },
+ { MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_UYVY8_1X16 },
+ { MEDIA_BUS_FMT_RGB888_1X24, MEDIA_BUS_FMT_RGB888_1X24 },
+};
+
+static bool fmt_in_list(const u32 fmt, const u32 *out_fmts, const size_t num_fmts)
+{
+ size_t i;
+
+ for (i = 0; i < num_fmts; i++)
+ if (out_fmts[i] == fmt)
+ return true;
+
+ return false;
+}
+
+/**
+ * get_tuples_out_fmts - Get unique output formats of a &struct fmt_tuple list
+ * @fmt_tuples: array of &struct fmt_tuple
+ * @num_fmt_tuples: number of entries in @fmt_tuples
+ * @out_fmts: target array to store the unique output bus formats
+ *
+ * Returns the number of unique output formats, i.e. the number of entries in
+ * @out_fmts that were populated with sensible values.
+ */
+static size_t get_tuples_out_fmts(const struct fmt_tuple *fmt_tuples,
+ const size_t num_fmt_tuples, u32 *out_fmts)
+{
+ size_t num_unique = 0;
+ size_t i;
+
+ for (i = 0; i < num_fmt_tuples; i++)
+ if (!fmt_in_list(fmt_tuples[i].out_fmt, out_fmts, num_unique))
+ out_fmts[num_unique++] = fmt_tuples[i].out_fmt;
+
+ return num_unique;
+}
+
+#define DEFINE_FMT_FUNCS_FROM_TUPLES(name) \
+static u32 *drm_test_bridge_ ## name ## _out_fmts(struct drm_bridge *bridge, \
+ struct drm_bridge_state *bridge_state, \
+ struct drm_crtc_state *crtc_state, \
+ struct drm_connector_state *conn_state, \
+ unsigned int *num_output_fmts) \
+{ \
+ u32 *out_fmts = kcalloc(ARRAY_SIZE((name)), sizeof(u32), GFP_KERNEL); \
+ \
+ if (out_fmts) \
+ *num_output_fmts = get_tuples_out_fmts((name), ARRAY_SIZE((name)), out_fmts); \
+ else \
+ *num_output_fmts = 0; \
+ \
+ return out_fmts; \
+} \
+ \
+static u32 *drm_test_bridge_ ## name ## _in_fmts(struct drm_bridge *bridge, \
+ struct drm_bridge_state *bridge_state, \
+ struct drm_crtc_state *crtc_state, \
+ struct drm_connector_state *conn_state, \
+ u32 output_fmt, \
+ unsigned int *num_input_fmts) \
+{ \
+ u32 *in_fmts = kcalloc(ARRAY_SIZE((name)), sizeof(u32), GFP_KERNEL); \
+ unsigned int num_fmts = 0; \
+ size_t i; \
+ \
+ if (!in_fmts) { \
+ *num_input_fmts = 0; \
+ return NULL; \
+ } \
+ \
+ for (i = 0; i < ARRAY_SIZE((name)); i++) \
+ if ((name)[i].out_fmt == output_fmt) \
+ in_fmts[num_fmts++] = (name)[i].in_fmt; \
+ \
+ *num_input_fmts = num_fmts; \
+ \
+ return in_fmts; \
+}
+
+#define DRM_BRIDGE_ATOMIC_WITH_BUS_FMT_HDMI_FUNC(ident, input_fmts_func, output_fmts_func, \
+ hdmi_write_infoframe_func, \
+ hdmi_clear_infoframe_func) \
+static const struct drm_bridge_funcs (ident) = { \
+ .atomic_enable = drm_test_bridge_atomic_enable, \
+ .atomic_disable = drm_test_bridge_atomic_disable, \
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, \
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, \
+ .atomic_reset = drm_atomic_helper_bridge_reset, \
+ .atomic_get_input_bus_fmts = (input_fmts_func), \
+ .atomic_get_output_bus_fmts = (output_fmts_func), \
+ .hdmi_write_avi_infoframe = (hdmi_write_infoframe_func), \
+ .hdmi_clear_avi_infoframe = (hdmi_clear_infoframe_func), \
+ .hdmi_write_hdmi_infoframe = (hdmi_write_infoframe_func), \
+ .hdmi_clear_hdmi_infoframe = (hdmi_clear_infoframe_func), \
+}
+
+#define DRM_BRIDGE_ATOMIC_WITH_BUS_FMT_FUNC(ident, input_fmts_func, output_fmts_func) \
+ DRM_BRIDGE_ATOMIC_WITH_BUS_FMT_HDMI_FUNC(ident, input_fmts_func, output_fmts_func, \
+ NULL, NULL)
+
+#define DRM_BRIDGE_ATOMIC_WITH_BUS_FMT(_name) \
+ DRM_BRIDGE_ATOMIC_WITH_BUS_FMT_FUNC(_name ## _funcs, \
+ drm_test_bridge_ ## _name ## _in_fmts, \
+ drm_test_bridge_ ## _name ## _out_fmts)
+
+static int drm_test_bridge_write_infoframe_stub(struct drm_bridge *bridge,
+ const u8 *buffer, size_t len)
+{
+ return 0;
+}
+
+static int drm_test_bridge_clear_infoframe_stub(struct drm_bridge *bridge)
+{
+ return 0;
+}
+
+#define DRM_BRIDGE_ATOMIC_WITH_BUS_FMT_HDMI(_name) \
+ DRM_BRIDGE_ATOMIC_WITH_BUS_FMT_HDMI_FUNC(_name ## _hdmi ## _funcs, \
+ drm_test_bridge_ ## _name ## _in_fmts, \
+ drm_test_bridge_ ## _name ## _out_fmts, \
+ drm_test_bridge_write_infoframe_stub, \
+ drm_test_bridge_clear_infoframe_stub)
+DEFINE_FMT_FUNCS_FROM_TUPLES(rgb8_passthrough)
+DRM_BRIDGE_ATOMIC_WITH_BUS_FMT(rgb8_passthrough);
+
+DEFINE_FMT_FUNCS_FROM_TUPLES(yuv8_passthrough)
+DRM_BRIDGE_ATOMIC_WITH_BUS_FMT(yuv8_passthrough);
+
+DEFINE_FMT_FUNCS_FROM_TUPLES(rgb8_to_yuv8_or_id)
+DRM_BRIDGE_ATOMIC_WITH_BUS_FMT(rgb8_to_yuv8_or_id);
+
+DEFINE_FMT_FUNCS_FROM_TUPLES(yuv8_to_rgb8_or_id)
+DRM_BRIDGE_ATOMIC_WITH_BUS_FMT(yuv8_to_rgb8_or_id);
+
+DEFINE_FMT_FUNCS_FROM_TUPLES(rgb_producer)
+DRM_BRIDGE_ATOMIC_WITH_BUS_FMT(rgb_producer);
+
+DEFINE_FMT_FUNCS_FROM_TUPLES(rgb_yuv444_yuv420_producer)
+DRM_BRIDGE_ATOMIC_WITH_BUS_FMT(rgb_yuv444_yuv420_producer);
+
+DEFINE_FMT_FUNCS_FROM_TUPLES(rgb8_to_id_yuv8_or_yuv8_to_yuv422_yuv420)
+DRM_BRIDGE_ATOMIC_WITH_BUS_FMT(rgb8_to_id_yuv8_or_yuv8_to_yuv422_yuv420);
+
+DEFINE_FMT_FUNCS_FROM_TUPLES(rgb8_yuv444_yuv422_passthrough)
+DRM_BRIDGE_ATOMIC_WITH_BUS_FMT(rgb8_yuv444_yuv422_passthrough);
+
+DEFINE_FMT_FUNCS_FROM_TUPLES(yuv444_yuv422_rgb8_passthrough)
+DRM_BRIDGE_ATOMIC_WITH_BUS_FMT(yuv444_yuv422_rgb8_passthrough);
+DRM_BRIDGE_ATOMIC_WITH_BUS_FMT_HDMI(yuv444_yuv422_rgb8_passthrough);
+
KUNIT_DEFINE_ACTION_WRAPPER(drm_bridge_remove_wrapper,
drm_bridge_remove,
struct drm_bridge *);
@@ -180,6 +426,119 @@ drm_test_bridge_init(struct kunit *test, const struct drm_bridge_funcs *funcs)
return priv;
}
+static struct drm_bridge_chain_priv *
+drm_test_bridge_chain_init(struct kunit *test, unsigned int num_bridges,
+ const struct drm_bridge_funcs **funcs)
+{
+ struct drm_bridge_chain_priv *priv;
+ const struct drm_edid *edid;
+ struct drm_bridge *prev;
+ struct drm_encoder *enc;
+ struct drm_bridge *bridge;
+ struct drm_device *drm;
+ bool has_hdmi = false;
+ struct device *dev;
+ unsigned int i;
+ int ret;
+
+ dev = drm_kunit_helper_alloc_device(test);
+ if (IS_ERR(dev))
+ return ERR_CAST(dev);
+
+ priv = drm_kunit_helper_alloc_drm_device(test, dev, struct drm_bridge_chain_priv,
+ drm, DRIVER_MODESET | DRIVER_ATOMIC);
+ if (IS_ERR(priv))
+ return ERR_CAST(priv);
+
+ drm = &priv->drm;
+
+ priv->test_bridges = drmm_kmalloc_array(drm, num_bridges, sizeof(*priv->test_bridges),
+ GFP_KERNEL);
+ if (!priv->test_bridges)
+ return ERR_PTR(-ENOMEM);
+
+ priv->num_bridges = num_bridges;
+
+ for (i = 0; i < num_bridges; i++) {
+ priv->test_bridges[i] = devm_drm_bridge_alloc(dev, struct drm_bridge_priv,
+ bridge, funcs[i]);
+ if (IS_ERR(priv->test_bridges[i]))
+ return ERR_CAST(priv->test_bridges[i]);
+
+ priv->test_bridges[i]->data = priv;
+ }
+
+ priv->plane = drm_kunit_helper_create_primary_plane(test, drm, NULL, NULL,
+ NULL, 0, NULL);
+ if (IS_ERR(priv->plane))
+ return ERR_CAST(priv->plane);
+
+ priv->crtc = drm_kunit_helper_create_crtc(test, drm, priv->plane, NULL,
+ NULL, NULL);
+ if (IS_ERR(priv->crtc))
+ return ERR_CAST(priv->crtc);
+
+ enc = &priv->encoder;
+ ret = drmm_encoder_init(drm, enc, NULL, DRM_MODE_ENCODER_TMDS, NULL);
+ if (ret)
+ return ERR_PTR(ret);
+
+ enc->possible_crtcs = drm_crtc_mask(priv->crtc);
+
+ prev = NULL;
+ for (i = 0; i < num_bridges; i++) {
+ bridge = &priv->test_bridges[i]->bridge;
+ bridge->type = DRM_MODE_CONNECTOR_VIRTUAL;
+
+ if (bridge->funcs->hdmi_write_hdmi_infoframe) {
+ has_hdmi = true;
+ bridge->ops |= DRM_BRIDGE_OP_HDMI;
+ bridge->type = DRM_MODE_CONNECTOR_HDMIA;
+ bridge->vendor = "LNX";
+ bridge->product = "KUnit";
+ bridge->supported_formats = (BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420));
+ }
+
+ ret = drm_kunit_bridge_add(test, bridge);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ret = drm_bridge_attach(enc, bridge, prev, 0);
+ if (ret)
+ return ERR_PTR(ret);
+
+ prev = bridge;
+ }
+
+ priv->connector = drm_bridge_connector_init(drm, enc);
+ if (IS_ERR(priv->connector))
+ return ERR_CAST(priv->connector);
+
+ drm_connector_attach_encoder(priv->connector, enc);
+
+ drm_mode_config_reset(drm);
+
+ if (!has_hdmi)
+ return priv;
+
+ scoped_guard(mutex, &drm->mode_config.mutex) {
+ edid = drm_edid_alloc(test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz,
+ ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz));
+ if (!edid)
+ return ERR_PTR(-EINVAL);
+
+ drm_edid_connector_update(priv->connector, edid);
+ KUNIT_ASSERT_GT(test, drm_edid_connector_add_modes(priv->connector), 0);
+
+ ret = priv->connector->funcs->fill_modes(priv->connector, 4096, 4096);
+ }
+
+ return priv;
+}
+
/*
* Test that drm_bridge_get_current_state() returns the last committed
* state for an atomic bridge.
@@ -508,14 +867,442 @@ static struct kunit_suite drm_bridge_alloc_test_suite = {
.test_cases = drm_bridge_alloc_tests,
};
+/**
+ * drm_test_bridge_chain_verify_fmt - Verify bridge chain format selection
+ * @test: pointer to KUnit test object
+ * @priv: pointer to a &struct drm_bridge_chain_priv for this chain
+ * @expected: constant array of &struct fmt_tuple describing the expected
+ * input and output bus formats
+ * @num_expected: number of entries in @expected
+ *
+ * Runs the KUNIT_EXPECT clauses to verify the bridge chain format selection
+ * resulted in the expected formats. If %0 is given as a format in a
+ * &struct fmt_tuple, then it is understood to mean "any".
+ *
+ * Must be called with the modeset lock held.
+ */
+static void drm_test_bridge_chain_verify_fmt(struct kunit *test,
+ struct drm_bridge_chain_priv *priv,
+ const struct fmt_tuple *const expected,
+ const unsigned int num_expected)
+{
+ struct drm_bridge_state *bstate;
+ unsigned int i = 0;
+
+ drm_for_each_bridge_in_chain_scoped(&priv->encoder, bridge) {
+ KUNIT_ASSERT_LT(test, i, num_expected);
+
+ bstate = drm_bridge_get_current_state(bridge);
+ if (expected[i].in_fmt)
+ KUNIT_EXPECT_EQ(test, bstate->input_bus_cfg.format,
+ expected[i].in_fmt);
+ if (expected[i].out_fmt)
+ KUNIT_EXPECT_EQ(test, bstate->output_bus_cfg.format,
+ expected[i].out_fmt);
+
+ i++;
+ }
+
+ KUNIT_ASSERT_EQ_MSG(test, i, num_expected,
+ "Fewer bridges (%u) than expected (%u)\n", i, num_expected);
+}
+
+/*
+ * Test that constructs a bridge chain in which an RGB888 producer is chained to
+ * two bridges that will convert from RGB to YUV and from YUV to RGB respectively.
+ *
+ * The test requests an output color_format of RGB using the color_format property,
+ * so to satisfy this request, the bridge chain must take a detour over YUV.
+ */
+static void drm_test_bridge_rgb_yuv_rgb(struct kunit *test)
+{
+ static const struct drm_bridge_funcs *funcs[] = {
+ &rgb_producer_funcs,
+ &rgb8_to_yuv8_or_id_funcs,
+ &yuv8_to_rgb8_or_id_funcs,
+ };
+ static const struct fmt_tuple expected[] = {
+ { MEDIA_BUS_FMT_FIXED, MEDIA_BUS_FMT_RGB888_1X24 },
+ { MEDIA_BUS_FMT_RGB888_1X24, MEDIA_BUS_FMT_YUV8_1X24 },
+ { MEDIA_BUS_FMT_YUV8_1X24, MEDIA_BUS_FMT_RGB888_1X24 },
+ };
+ struct drm_connector_state *conn_state;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_bridge_chain_priv *priv;
+ struct drm_crtc_state *crtc_state;
+ struct drm_atomic_state *state;
+ struct drm_display_mode *mode;
+ int ret;
+
+ priv = drm_test_bridge_chain_init(test, ARRAY_SIZE(funcs), funcs);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+ state = drm_kunit_helper_atomic_state_alloc(test, &priv->drm, &ctx);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+retry_commit:
+ conn_state = drm_atomic_get_connector_state(state, priv->connector);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+
+ mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
+
+ conn_state->color_format = DRM_CONNECTOR_COLOR_FORMAT_RGB444;
+
+ ret = drm_atomic_set_crtc_for_connector(conn_state, priv->crtc);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry_commit;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ crtc_state = drm_atomic_get_crtc_state(state, priv->crtc);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+ ret = drm_atomic_set_mode_for_crtc(crtc_state, mode);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry_commit;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ crtc_state->enable = true;
+ crtc_state->active = true;
+
+ ret = drm_atomic_commit(state);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry_commit;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ drm_test_bridge_chain_verify_fmt(test, priv, expected, ARRAY_SIZE(expected));
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+}
+
+/*
+ * Test in which a bridge capable of producing RGB, YUV444 and YUV420 has to
+ * produce RGB and convert with a downstream bridge in the chain to reach the
+ * requested YUV444 color format, as no direct path exists between its YUV444
+ * and the last bridge.
+ *
+ * The rationale behind this test is to devise a scenario in which naively
+ * assuming any format the video processor can output, and the connector
+ * requests, is the right format to pick, does not work.
+ */
+static void drm_test_bridge_must_convert_to_yuv444(struct kunit *test)
+{
+ static const struct drm_bridge_funcs *funcs[] = {
+ &rgb_yuv444_yuv420_producer_funcs,
+ &rgb8_passthrough_funcs,
+ &rgb8_to_id_yuv8_or_yuv8_to_yuv422_yuv420_funcs,
+ &rgb8_yuv444_yuv422_passthrough_funcs,
+ };
+ static const struct fmt_tuple expected[] = {
+ { MEDIA_BUS_FMT_FIXED, MEDIA_BUS_FMT_RGB888_1X24 },
+ { MEDIA_BUS_FMT_RGB888_1X24, MEDIA_BUS_FMT_RGB888_1X24 },
+ { MEDIA_BUS_FMT_RGB888_1X24, MEDIA_BUS_FMT_YUV8_1X24 },
+ { MEDIA_BUS_FMT_YUV8_1X24, MEDIA_BUS_FMT_YUV8_1X24 },
+ };
+ struct drm_connector_state *conn_state;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_bridge_chain_priv *priv;
+ struct drm_crtc_state *crtc_state;
+ struct drm_atomic_state *state;
+ struct drm_display_mode *mode;
+ int ret;
+
+ priv = drm_test_bridge_chain_init(test, ARRAY_SIZE(funcs), funcs);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+ state = drm_kunit_helper_atomic_state_alloc(test, &priv->drm, &ctx);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+retry_commit:
+ conn_state = drm_atomic_get_connector_state(state, priv->connector);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+
+ mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
+
+ conn_state->color_format = DRM_CONNECTOR_COLOR_FORMAT_YCBCR444;
+
+ ret = drm_atomic_set_crtc_for_connector(conn_state, priv->crtc);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry_commit;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ crtc_state = drm_atomic_get_crtc_state(state, priv->crtc);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+ ret = drm_atomic_set_mode_for_crtc(crtc_state, mode);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry_commit;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ crtc_state->enable = true;
+ crtc_state->active = true;
+
+ ret = drm_atomic_commit(state);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry_commit;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ drm_test_bridge_chain_verify_fmt(test, priv, expected, ARRAY_SIZE(expected));
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+}
+
+/*
+ * Test which checks that no matter the order of bus formats returned by an
+ * HDMI bridge, RGB is preferred on DRM_CONNECTOR_COLOR_FORMAT_AUTO if it's
+ * available.
+ */
+static void drm_test_bridge_hdmi_auto_rgb(struct kunit *test)
+{
+ static const struct drm_bridge_funcs *funcs[] = {
+ &rgb_yuv444_yuv420_producer_funcs,
+ &yuv444_yuv422_rgb8_passthrough_hdmi_funcs,
+ };
+ static const struct fmt_tuple expected[] = {
+ { MEDIA_BUS_FMT_FIXED, MEDIA_BUS_FMT_RGB888_1X24 },
+ { MEDIA_BUS_FMT_RGB888_1X24, MEDIA_BUS_FMT_RGB888_1X24 },
+ };
+ struct drm_connector_state *conn_state;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_bridge_chain_priv *priv;
+ struct drm_crtc_state *crtc_state;
+ struct drm_atomic_state *state;
+ struct drm_display_mode *mode;
+ int ret;
+
+ priv = drm_test_bridge_chain_init(test, ARRAY_SIZE(funcs), funcs);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+ state = drm_kunit_helper_atomic_state_alloc(test, &priv->drm, &ctx);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+retry_commit:
+ conn_state = drm_atomic_get_connector_state(state, priv->connector);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+
+ mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
+
+ KUNIT_ASSERT_EQ(test, conn_state->color_format, DRM_CONNECTOR_COLOR_FORMAT_AUTO);
+
+ ret = drm_atomic_set_crtc_for_connector(conn_state, priv->crtc);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry_commit;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ crtc_state = drm_atomic_get_crtc_state(state, priv->crtc);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+ ret = drm_atomic_set_mode_for_crtc(crtc_state, mode);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry_commit;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ crtc_state->enable = true;
+ crtc_state->active = true;
+
+ ret = drm_atomic_commit(state);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry_commit;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, DRM_OUTPUT_COLOR_FORMAT_RGB444);
+
+ drm_test_bridge_chain_verify_fmt(test, priv, expected, ARRAY_SIZE(expected));
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+}
+
+/*
+ * Test which checks that DRM_CONNECTOR_COLOR_FORMAT_AUTO on non-HDMI connectors
+ * will result in the first bus format on the output to be picked.
+ */
+static void drm_test_bridge_auto_first(struct kunit *test)
+{
+ static const struct drm_bridge_funcs *funcs[] = {
+ &rgb_yuv444_yuv420_producer_funcs,
+ &yuv444_yuv422_rgb8_passthrough_funcs,
+ };
+ static const struct fmt_tuple expected[] = {
+ { MEDIA_BUS_FMT_FIXED, MEDIA_BUS_FMT_YUV8_1X24 },
+ { MEDIA_BUS_FMT_YUV8_1X24, MEDIA_BUS_FMT_YUV8_1X24 },
+ };
+ struct drm_connector_state *conn_state;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_bridge_chain_priv *priv;
+ struct drm_crtc_state *crtc_state;
+ struct drm_atomic_state *state;
+ struct drm_display_mode *mode;
+ int ret;
+
+ priv = drm_test_bridge_chain_init(test, ARRAY_SIZE(funcs), funcs);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+ state = drm_kunit_helper_atomic_state_alloc(test, &priv->drm, &ctx);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+retry_commit:
+ conn_state = drm_atomic_get_connector_state(state, priv->connector);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+
+ mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
+
+ KUNIT_ASSERT_EQ(test, conn_state->color_format, DRM_CONNECTOR_COLOR_FORMAT_AUTO);
+
+ ret = drm_atomic_set_crtc_for_connector(conn_state, priv->crtc);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry_commit;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ crtc_state = drm_atomic_get_crtc_state(state, priv->crtc);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+ ret = drm_atomic_set_mode_for_crtc(crtc_state, mode);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry_commit;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ crtc_state->enable = true;
+ crtc_state->active = true;
+
+ ret = drm_atomic_commit(state);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry_commit;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ drm_test_bridge_chain_verify_fmt(test, priv, expected, ARRAY_SIZE(expected));
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+}
+
+/*
+ * Test which checks that in a configuration of bridge chains where an RGB
+ * producer is hooked to a YUV444-only pass-through, the atomic commit fails as
+ * the bridge format selection cannot find a valid sequence of bus formats.
+ */
+static void drm_test_bridge_rgb_yuv_no_path(struct kunit *test)
+{
+ static const struct drm_bridge_funcs *funcs[] = {
+ &rgb_producer_funcs,
+ &yuv8_passthrough_funcs,
+ &rgb8_yuv444_yuv422_passthrough_funcs,
+ };
+ struct drm_connector_state *conn_state;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_bridge_chain_priv *priv;
+ struct drm_crtc_state *crtc_state;
+ struct drm_atomic_state *state;
+ struct drm_display_mode *mode;
+ int ret;
+
+ priv = drm_test_bridge_chain_init(test, ARRAY_SIZE(funcs), funcs);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+ state = drm_kunit_helper_atomic_state_alloc(test, &priv->drm, &ctx);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+retry_commit:
+ conn_state = drm_atomic_get_connector_state(state, priv->connector);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+
+ mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
+
+ ret = drm_atomic_set_crtc_for_connector(conn_state, priv->crtc);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry_commit;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ crtc_state = drm_atomic_get_crtc_state(state, priv->crtc);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+ ret = drm_atomic_set_mode_for_crtc(crtc_state, mode);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry_commit;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ crtc_state->enable = true;
+ crtc_state->active = true;
+
+ ret = drm_atomic_commit(state);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry_commit;
+ }
+ KUNIT_EXPECT_EQ(test, ret, -ENOTSUPP);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+}
+
+static struct kunit_case drm_bridge_bus_fmt_tests[] = {
+ KUNIT_CASE(drm_test_bridge_rgb_yuv_rgb),
+ KUNIT_CASE(drm_test_bridge_must_convert_to_yuv444),
+ KUNIT_CASE(drm_test_bridge_hdmi_auto_rgb),
+ KUNIT_CASE(drm_test_bridge_auto_first),
+ KUNIT_CASE(drm_test_bridge_rgb_yuv_no_path),
+ { }
+};
+
+static struct kunit_suite drm_bridge_bus_fmt_test_suite = {
+ .name = "drm_bridge_bus_fmt",
+ .test_cases = drm_bridge_bus_fmt_tests,
+};
+
kunit_test_suites(
&drm_bridge_get_current_state_test_suite,
&drm_bridge_helper_reset_crtc_test_suite,
&drm_bridge_alloc_test_suite,
+ &drm_bridge_bus_fmt_test_suite,
);
MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
MODULE_AUTHOR("Luca Ceresoli <luca.ceresoli@bootlin.com>");
+MODULE_AUTHOR("Nicolas Frattaroli <nicolas.frattaroli@collabora.com>");
MODULE_DESCRIPTION("Kunit test for drm_bridge functions");
MODULE_LICENSE("GPL");
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread* [PATCH v11 21/22] drm/tests: bridge: Add test for HDMI output bus formats helper
2026-03-24 16:01 [PATCH v11 00/22] Add new general DRM property "color format" Nicolas Frattaroli
` (19 preceding siblings ...)
2026-03-24 16:01 ` [PATCH v11 20/22] drm/tests: bridge: Add KUnit tests for bridge chain format selection Nicolas Frattaroli
@ 2026-03-24 16:01 ` Nicolas Frattaroli
2026-03-24 16:01 ` [PATCH v11 22/22] drm/bridge: Document bridge chain format selection Nicolas Frattaroli
21 siblings, 0 replies; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-24 16:01 UTC (permalink / raw)
To: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc,
Nicolas Frattaroli
The common atomic_get_output_bus_fmts helper for HDMI bridge connectors,
called drm_atomic_helper_bridge_get_hdmi_output_bus_fmts, should return
an array of output bus formats depending on the supported formats of the
connector, and the current output BPC.
Add a test to exercise some of this helper.
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/tests/drm_bridge_test.c | 184 ++++++++++++++++++++++++++++++++
1 file changed, 184 insertions(+)
diff --git a/drivers/gpu/drm/tests/drm_bridge_test.c b/drivers/gpu/drm/tests/drm_bridge_test.c
index cb821c606070..d9bd930b1197 100644
--- a/drivers/gpu/drm/tests/drm_bridge_test.c
+++ b/drivers/gpu/drm/tests/drm_bridge_test.c
@@ -5,6 +5,7 @@
#include <linux/cleanup.h>
#include <linux/media-bus-format.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_atomic_uapi.h>
#include <drm/drm_bridge.h>
@@ -118,6 +119,28 @@ static const struct drm_bridge_funcs drm_test_bridge_atomic_funcs = {
.atomic_reset = drm_atomic_helper_bridge_reset,
};
+static int dummy_clear_infoframe(struct drm_bridge *bridge)
+{
+ return 0;
+}
+
+static int dummy_write_infoframe(struct drm_bridge *bridge, const u8 *buffer,
+ size_t len)
+{
+ return 0;
+}
+
+static const struct drm_bridge_funcs drm_test_bridge_bus_fmts_funcs = {
+ .atomic_get_output_bus_fmts = drm_atomic_helper_bridge_get_hdmi_output_bus_fmts,
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+ .atomic_reset = drm_atomic_helper_bridge_reset,
+ .hdmi_write_avi_infoframe = dummy_write_infoframe,
+ .hdmi_write_hdmi_infoframe = dummy_write_infoframe,
+ .hdmi_clear_avi_infoframe = dummy_clear_infoframe,
+ .hdmi_clear_hdmi_infoframe = dummy_clear_infoframe,
+};
+
/**
* struct fmt_tuple - a tuple of input/output MEDIA_BUS_FMT_*
*/
@@ -539,6 +562,83 @@ drm_test_bridge_chain_init(struct kunit *test, unsigned int num_bridges,
return priv;
}
+static struct drm_bridge_init_priv *
+drm_test_bridge_hdmi_init(struct kunit *test, const struct drm_bridge_funcs *funcs,
+ unsigned int supported_formats, int max_bpc)
+{
+ struct drm_bridge_init_priv *priv;
+ struct drm_encoder *enc;
+ struct drm_bridge *bridge;
+ struct drm_device *drm;
+ struct device *dev;
+ int ret;
+
+ dev = drm_kunit_helper_alloc_device(test);
+ if (IS_ERR(dev))
+ return ERR_CAST(dev);
+
+ priv = drm_kunit_helper_alloc_drm_device(test, dev,
+ struct drm_bridge_init_priv, drm,
+ DRIVER_MODESET | DRIVER_ATOMIC);
+ if (IS_ERR(priv))
+ return ERR_CAST(priv);
+
+ priv->test_bridge = devm_drm_bridge_alloc(dev, struct drm_bridge_priv, bridge, funcs);
+ if (IS_ERR(priv->test_bridge))
+ return ERR_CAST(priv->test_bridge);
+
+ priv->test_bridge->data = priv;
+
+ drm = &priv->drm;
+ priv->plane = drm_kunit_helper_create_primary_plane(test, drm,
+ NULL,
+ NULL,
+ NULL, 0,
+ NULL);
+ if (IS_ERR(priv->plane))
+ return ERR_CAST(priv->plane);
+
+ priv->crtc = drm_kunit_helper_create_crtc(test, drm,
+ priv->plane, NULL,
+ NULL,
+ NULL);
+ if (IS_ERR(priv->crtc))
+ return ERR_CAST(priv->crtc);
+
+ enc = &priv->encoder;
+ ret = drmm_encoder_init(drm, enc, NULL, DRM_MODE_ENCODER_TMDS, NULL);
+ if (ret)
+ return ERR_PTR(ret);
+
+ enc->possible_crtcs = drm_crtc_mask(priv->crtc);
+
+ bridge = &priv->test_bridge->bridge;
+ bridge->type = DRM_MODE_CONNECTOR_HDMIA;
+ bridge->supported_formats = supported_formats;
+ bridge->max_bpc = max_bpc;
+ bridge->ops |= DRM_BRIDGE_OP_HDMI;
+ bridge->vendor = "LNX";
+ bridge->product = "KUnit";
+
+ ret = drm_kunit_bridge_add(test, bridge);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ret = drm_bridge_attach(enc, bridge, NULL, 0);
+ if (ret)
+ return ERR_PTR(ret);
+
+ priv->connector = drm_bridge_connector_init(drm, enc);
+ if (IS_ERR(priv->connector))
+ return ERR_CAST(priv->connector);
+
+ drm_connector_attach_encoder(priv->connector, enc);
+
+ drm_mode_config_reset(drm);
+
+ return priv;
+}
+
/*
* Test that drm_bridge_get_current_state() returns the last committed
* state for an atomic bridge.
@@ -786,10 +886,94 @@ static void drm_test_drm_bridge_helper_reset_crtc_legacy(struct kunit *test)
KUNIT_EXPECT_EQ(test, bridge_priv->disable_count, 1);
}
+/*
+ * Test that a bridge using the drm_atomic_helper_bridge_get_hdmi_output_bus_fmts()
+ * function for &drm_bridge_funcs.atomic_get_output_bus_fmts behaves as expected
+ * for an HDMI connector bridge. Does so by creating an HDMI bridge connector
+ * with RGB444, YCBCR444, and YCBCR420 (but not YCBCR422) as supported formats,
+ * sets the output depth to 8 bits per component, and then validates the returned
+ * list of bus formats.
+ */
+static void drm_test_drm_bridge_helper_hdmi_output_bus_fmts(struct kunit *test)
+{
+ struct drm_connector_state *conn_state;
+ struct drm_bridge_state *bridge_state;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_bridge_init_priv *priv;
+ struct drm_crtc_state *crtc_state;
+ struct drm_atomic_state *state;
+ struct drm_display_mode *mode;
+ unsigned int num_output_fmts;
+ struct drm_bridge *bridge;
+ u32 *out_bus_fmts;
+ int ret;
+
+ priv = drm_test_bridge_hdmi_init(test, &drm_test_bridge_bus_fmts_funcs,
+ BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420),
+ 12);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
+
+ bridge = &priv->test_bridge->bridge;
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+ state = drm_kunit_helper_atomic_state_alloc(test, &priv->drm, &ctx);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+retry_commit:
+ conn_state = drm_atomic_get_connector_state(state, priv->connector);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+
+ conn_state->hdmi.output_bpc = 8;
+
+ mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
+
+ ret = drm_atomic_set_crtc_for_connector(conn_state, priv->crtc);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry_commit;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ crtc_state = drm_atomic_get_crtc_state(state, priv->crtc);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+ ret = drm_atomic_set_mode_for_crtc(crtc_state, mode);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry_commit;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ crtc_state->enable = true;
+ crtc_state->active = true;
+
+ bridge_state = drm_atomic_get_bridge_state(state, bridge);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bridge_state);
+
+ out_bus_fmts = bridge->funcs->atomic_get_output_bus_fmts(
+ bridge, bridge_state, crtc_state, conn_state, &num_output_fmts);
+ KUNIT_EXPECT_NOT_NULL(test, out_bus_fmts);
+ KUNIT_EXPECT_EQ(test, num_output_fmts, 3);
+
+ KUNIT_EXPECT_EQ(test, out_bus_fmts[0], MEDIA_BUS_FMT_RGB888_1X24);
+ KUNIT_EXPECT_EQ(test, out_bus_fmts[1], MEDIA_BUS_FMT_YUV8_1X24);
+ KUNIT_EXPECT_EQ(test, out_bus_fmts[2], MEDIA_BUS_FMT_UYYVYY8_0_5X24);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+
+ kfree(out_bus_fmts);
+}
+
static struct kunit_case drm_bridge_helper_reset_crtc_tests[] = {
KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_atomic),
KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_atomic_disabled),
KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_legacy),
+ KUNIT_CASE(drm_test_drm_bridge_helper_hdmi_output_bus_fmts),
{ }
};
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread* [PATCH v11 22/22] drm/bridge: Document bridge chain format selection
2026-03-24 16:01 [PATCH v11 00/22] Add new general DRM property "color format" Nicolas Frattaroli
` (20 preceding siblings ...)
2026-03-24 16:01 ` [PATCH v11 21/22] drm/tests: bridge: Add test for HDMI output bus formats helper Nicolas Frattaroli
@ 2026-03-24 16:01 ` Nicolas Frattaroli
21 siblings, 0 replies; 48+ messages in thread
From: Nicolas Frattaroli @ 2026-03-24 16:01 UTC (permalink / raw)
To: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc,
Nicolas Frattaroli
The bridge chain format selection behaviour was, until now,
undocumented. With the addition of the "color format" DRM property, it's
not sufficiently complex enough that documentation is warranted,
especially for driver authors trying to do the right thing.
Add a high-level overview of how the process is supposed to work, and
mention what the display driver is supposed to do if it wants to make
use of this functionality.
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
Documentation/gpu/drm-kms-helpers.rst | 6 ++++++
drivers/gpu/drm/drm_bridge.c | 40 +++++++++++++++++++++++++++++++++++
2 files changed, 46 insertions(+)
diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst
index 781129f78b06..47c4f593cf9d 100644
--- a/Documentation/gpu/drm-kms-helpers.rst
+++ b/Documentation/gpu/drm-kms-helpers.rst
@@ -181,6 +181,12 @@ Bridge Operations
.. kernel-doc:: drivers/gpu/drm/drm_bridge.c
:doc: bridge operations
+Bridge Chain Format Selection
+-----------------------------
+
+.. kernel-doc:: drivers/gpu/drm/drm_bridge.c
+ :doc: bridge chain format selection
+
Bridge Connector Helper
-----------------------
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 9ee3a8c25510..188606a34313 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -198,6 +198,46 @@
* driver.
*/
+/**
+ * DOC: bridge chain format selection
+ *
+ * A bridge chain, from display output processor to connector, may contain
+ * bridges capable of converting between bus formats on their inputs, and
+ * output formats on their outputs. For example, a bridge may be able to convert
+ * from RGB to YCbCr 4:4:4, and pass through YCbCr 4:2:0 as-is, but not convert
+ * from RGB to YCbCr 4:2:0. This means not all input formats map to all output
+ * formats.
+ *
+ * Further adding to this, a desired output color format, as specified with the
+ * "color format" DRM property, might not correspond 1:1 to what the display
+ * driver should set at its output. The bridge chain it feeds into may only be
+ * able to reach the desired output format, if a conversion from a different
+ * starting format is performed.
+ *
+ * To deal with this complexity, the recursive bridge chain bus format selection
+ * logic starts with the last bridge in the chain, usually the connector, and
+ * then recursively walks the chain of bridges backwards to the first bridge,
+ * trying to find a path.
+ *
+ * For a display driver to work in such a scenario, it should read the first
+ * bridge's bridge state to figure out which bus format the chain resolved to.
+ * If the first bridge's input format resolved to %MEDIA_BUS_FMT_FIXED, then its
+ * output format should be used.
+ *
+ * Special handling is done for HDMI as it relates to format selection. Instead
+ * of directly using the "color format" DRM property for bridge chains that end
+ * in HDMI bridges, the bridge chain format selection logic will trust the logic
+ * that set the HDMI output format. For the common HDMI state helper
+ * functionality, this means that %DRM_CONNECTOR_COLOR_FORMAT_AUTO will allow
+ * fallbacks to YCBCr 4:2:0 if the bandwidth requirements would otherwise be too
+ * high but the mode and connector allow it.
+ *
+ * For bridge chains that do not end in an HDMI bridge,
+ * %DRM_CONNECTOR_COLOR_FORMAT_AUTO will be satisfied with the first output
+ * format on the last bridge for which it can find a path back to the first
+ * bridge.
+ */
+
/* Protect bridge_list and bridge_lingering_list */
static DEFINE_MUTEX(bridge_lock);
static LIST_HEAD(bridge_list);
--
2.53.0
^ permalink raw reply related [flat|nested] 48+ messages in thread