From nobody Thu Mar 19 05:20:15 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 279212566D3; Thu, 5 Mar 2026 14:21:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772720483; cv=pass; b=nh9WAqFC6fnVtewxUmok6j9trb5E8s5hGml+oQTz7uAfio89cjzk6Gr0PTGRdE2suOxEtywavVD7RJrZs33PHaT2q/lbwjFIk1H9tqIE8HswUCBkAEjD1QAbmaJ70u1PetQe6iB6PyiDM/Fia2YiDH5Apdau8opRJJwv6Sv9Jsc= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772720483; c=relaxed/simple; bh=aPJ6IvIhz1BgQE3G2/pi+b0hd7MOg80HXrNr1ggjFzc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=sxhKImw0mZspCjEg4r74yVw2TCcYuDQbJ4cCOmcY/T7g/FrTkwlvHHTLChcHMARwZ4vJIy0WEG45MLwgooNhTGzPascNM12aB/LBShBAW6l8di/rXImU5stJLF793GfMY3NtlXuLLy5aVefqknNONzbuy3MjHzMCkIN4PbjQ0as= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b=hy06T9Ch; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=collabora.com header.i=nicolas.frattaroli@collabora.com header.b="hy06T9Ch" ARC-Seal: i=1; a=rsa-sha256; t=1772720427; cv=none; d=zohomail.com; s=zohoarc; b=kE1gkYIy4roB7Zqx6C0hPAB8EnLR09rtZFvkeznCqbAa14wqu0BflrUfYIhNbSGQusSGjPuDFijVaxKgYK0JW8NR+9/eEBHMXCEDmBwQhUKsiA8z6PrFW3nVRUNOV3QKADb6PNLxvflHA4QjZaVtPyLUtO83Y6uf/qqS91wgVAs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1772720427; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:Subject:To:To:Message-Id:Reply-To; bh=1GYBntpDRl1K9/KJsuLXL9DarNNNt6t+bGGjopojHHU=; b=jnlP2aLHefduuOf68GW98eMAtIHkXFavv/1MJ9DbyghpJSS72wEQBUEiVijzyBQg3MndgaEafDAuvt2JoANXPoVWC5Iw0qd3H/iAJCjwt/9siP0y/ZMST4iDVVnk6WXGSn6crRbgjTaKvxH5K+dvowBOnJZEyhP2P0rzGg9tDwI= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=collabora.com; spf=pass smtp.mailfrom=nicolas.frattaroli@collabora.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1772720427; s=zohomail; d=collabora.com; i=nicolas.frattaroli@collabora.com; h=From:From:Date:Date:Subject:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Message-Id:Message-Id:References:In-Reply-To:To:To:Cc:Cc:Reply-To; bh=1GYBntpDRl1K9/KJsuLXL9DarNNNt6t+bGGjopojHHU=; b=hy06T9ChiZe1ouMxO2gqIcCP8Dx+SjwWGt08Un9yX/uRSAB67wy8ikvum1SznSef QsQg6317b21peo26LGII0GAsvo2fUSMix/AW8aftPVbYfA8tDieAD/Ou66skxOg6viA cfikXI53XmNfr9teCmYZo/45t2nSJL55Vcs7VOpc= Received: by mx.zohomail.com with SMTPS id 1772720426504290.57315155882134; Thu, 5 Mar 2026 06:20:26 -0800 (PST) From: Nicolas Frattaroli Date: Thu, 05 Mar 2026 15:19:29 +0100 Subject: [PATCH v10 03/22] drm: Add new general DRM property "color format" Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260305-color-format-v10-3-a58c68a11868@collabora.com> References: <20260305-color-format-v10-0-a58c68a11868@collabora.com> In-Reply-To: <20260305-color-format-v10-0-a58c68a11868@collabora.com> To: Harry Wentland , Leo Li , Rodrigo Siqueira , Alex Deucher , =?utf-8?q?Christian_K=C3=B6nig?= , David Airlie , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Andy Yan , Jani Nikula , Rodrigo Vivi , Joonas Lahtinen , Tvrtko Ursulin , Dmitry Baryshkov , Sascha Hauer , Rob Herring , Jonathan Corbet , Shuah Khan Cc: kernel@collabora.com, amd-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-rockchip@lists.infradead.org, intel-gfx@lists.freedesktop.org, intel-xe@lists.freedesktop.org, linux-doc@vger.kernel.org, Nicolas Frattaroli , Werner Sembach , Andri Yngvason , Marius Vlad X-Mailer: b4 0.14.3 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 Signed-off-by: Werner Sembach Co-developed-by: Andri Yngvason Signed-off-by: Andri Yngvason Signed-off-by: Marius Vlad Signed-off-by: Nicolas Frattaroli Reviewed-by: Maxime Ripard --- 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_atom= ic_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 !=3D new_connector_state->max_requested_bpc) new_crtc_state->connectors_changed =3D true; + + if (old_connector_state->color_format !=3D + new_connector_state->color_format) + new_crtc_state->connectors_changed =3D true; + } =20 if (funcs->atomic_check) diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic= _uapi.c index 87de41fb4459..e7ce79bb161e 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -931,6 +931,15 @@ static int drm_atomic_connector_set_property(struct dr= m_connector *connector, state->privacy_screen_sw_state =3D val; } else if (property =3D=3D connector->broadcast_rgb_property) { state->hdmi.broadcast_rgb =3D val; + } else if (property =3D=3D 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 =3D val; } else if (connector->funcs->atomic_set_property) { return connector->funcs->atomic_set_property(connector, state, property, val); @@ -1016,6 +1025,8 @@ drm_atomic_connector_get_property(struct drm_connecto= r *connector, *val =3D state->privacy_screen_sw_state; } else if (property =3D=3D connector->broadcast_rgb_property) { *val =3D state->hdmi.broadcast_rgb; + } else if (property =3D=3D connector->color_format_property) { + *val =3D 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_connecto= r.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 =3D BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65) | BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER); =20 +static const u32 hdmi_colorformats =3D + 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 =3D + 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/Color= imetry * 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); =20 +/** + * drm_connector_attach_color_format_property - create and attach color fo= rmat 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 *conne= ctor, + unsigned long supported_color_formats) +{ + struct drm_device *dev =3D connector->dev; + struct drm_prop_enum_list enum_list[DRM_CONNECTOR_COLOR_FORMAT_COUNT]; + unsigned int i =3D 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 =3D "AUTO"; + enum_list[0].type =3D DRM_CONNECTOR_COLOR_FORMAT_AUTO; + + for_each_set_bit(fmt, &supported_color_formats, DRM_OUTPUT_COLOR_FORMAT_C= OUNT) { + switch (fmt) { + case DRM_OUTPUT_COLOR_FORMAT_RGB444: + enum_list[++i].type =3D DRM_CONNECTOR_COLOR_FORMAT_RGB444; + break; + case DRM_OUTPUT_COLOR_FORMAT_YCBCR444: + enum_list[++i].type =3D DRM_CONNECTOR_COLOR_FORMAT_YCBCR444; + break; + case DRM_OUTPUT_COLOR_FORMAT_YCBCR422: + enum_list[++i].type =3D DRM_CONNECTOR_COLOR_FORMAT_YCBCR422; + break; + case DRM_OUTPUT_COLOR_FORMAT_YCBCR420: + enum_list[++i].type =3D 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 =3D drm_hdmi_connector_get_output_format_name(fmt); + } + + connector->color_format_property =3D + 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_prop= erty, + 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 ch= anged * @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 subsampli= ng) + * @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 =3D 0, DRM_OUTPUT_COLOR_FORMAT_YCBCR444, DRM_OUTPUT_COLOR_FORMAT_YCBCR422, DRM_OUTPUT_COLOR_FORMAT_YCBCR420, + DRM_OUTPUT_COLOR_FORMAT_COUNT, }; =20 +/** + * enum drm_connector_color_format - Connector Color Format Request + * + * This enum, unlike &enum drm_output_color_format, is used to specify req= uests + * for a specific color format on a connector through the DRM "color forma= t" + * 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 =3D 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_fo= rmat + * + * Checks whether the passed in value of @fmt is one of the allowable valu= es 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= ); =20 @@ -1129,6 +1217,13 @@ struct drm_connector_state { */ enum drm_colorspace colorspace; =20 + /** + * @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; =20 + /** + * @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_co= nnector *connector, struct drm_encoder *encoder); const char *drm_get_colorspace_name(enum drm_colorspace colorspace); =20 +int drm_connector_attach_color_format_property(struct drm_connector *conne= ctor, + unsigned long supported_color_formats); + /** * drm_for_each_connector_iter - connector_list iterator macro * @connector: &struct drm_connector pointer used as cursor --=20 2.53.0