* [PATCH v16 15/28] drm/rockchip: Add YUV422 output mode constants for VOP2
From: Nicolas Frattaroli @ 2026-05-23 19:43 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, Daniel Stone
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc, wayland-devel,
Nicolas Frattaroli, Andy Yan
In-Reply-To: <20260523-color-format-v16-0-24340c5e4732@collabora.com>
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>
Reviewed-by: Daniel Stone <daniel@fooishbar.org>
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.54.0
^ permalink raw reply related
* [PATCH v16 14/28] drm/i915/dp: Implement "color format" DRM property
From: Nicolas Frattaroli @ 2026-05-23 19:43 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, Daniel Stone
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc, wayland-devel,
Nicolas Frattaroli
In-Reply-To: <20260523-color-format-v16-0-24340c5e4732@collabora.com>
Implement the "color format" DRM property for DP. The values of the
property include RGB, YCbCr420, YCbCr444 and Auto. Auto will pick RGB,
with a fallback to YCbCr420.
The mask of supported formats by the source exposed by the property is
an optimistic scenario, as specific DFP-related caveats can't be
established before an EDID is present.
Should the explicitly requested color format not be supported by the
sink (or by the source in combination with the sink), then an error is
returned to userspace, so that it can make a better choice.
Reviewed-by: Daniel Stone <daniel@fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/i915/display/intel_dp.c | 61 ++++++++++++++++++++++++++++++---
1 file changed, 57 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 380933579178..041e40c3ae8a 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -3435,10 +3435,10 @@ intel_dp_compute_output_format(struct intel_encoder *encoder,
}
static int
-intel_dp_compute_formats(struct intel_encoder *encoder,
- struct intel_crtc_state *crtc_state,
- struct drm_connector_state *conn_state,
- bool respect_downstream_limits)
+intel_dp_compute_formats_auto(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state,
+ bool respect_downstream_limits)
{
struct intel_display *display = to_intel_display(encoder);
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
@@ -3474,6 +3474,34 @@ intel_dp_compute_formats(struct intel_encoder *encoder,
return ret;
}
+static int
+intel_dp_compute_formats(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state,
+ bool respect_downstream_limits)
+{
+ switch (conn_state->color_format) {
+ case DRM_CONNECTOR_COLOR_FORMAT_RGB444:
+ return intel_dp_compute_output_format(encoder, crtc_state, conn_state,
+ respect_downstream_limits,
+ INTEL_OUTPUT_FORMAT_RGB);
+ case DRM_CONNECTOR_COLOR_FORMAT_YCBCR444:
+ return intel_dp_compute_output_format(encoder, crtc_state, conn_state,
+ respect_downstream_limits,
+ INTEL_OUTPUT_FORMAT_YCBCR444);
+ case DRM_CONNECTOR_COLOR_FORMAT_YCBCR420:
+ return intel_dp_compute_output_format(encoder, crtc_state, conn_state,
+ respect_downstream_limits,
+ INTEL_OUTPUT_FORMAT_YCBCR420);
+ case DRM_CONNECTOR_COLOR_FORMAT_AUTO:
+ return intel_dp_compute_formats_auto(encoder, crtc_state, conn_state,
+ respect_downstream_limits);
+ default:
+ MISSING_CASE(conn_state->color_format);
+ return -EINVAL;
+ }
+}
+
void
intel_dp_audio_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config,
@@ -7027,6 +7055,29 @@ intel_dp_has_gamut_metadata_dip(struct intel_encoder *encoder)
return false;
}
+static void
+intel_dp_attach_color_format_property(struct intel_dp *intel_dp)
+{
+ struct intel_connector *connector = intel_dp->attached_connector;
+ struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+ unsigned long fmts = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444);
+ bool has_pcon = false;
+
+ if (!connector)
+ return;
+
+ if (dig_port && intel_bios_encoder_is_lspcon(dig_port->base.devdata))
+ has_pcon = true;
+
+ if (has_pcon || source_can_output(intel_dp, INTEL_OUTPUT_FORMAT_YCBCR420))
+ fmts |= BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
+
+ if (has_pcon || source_can_output(intel_dp, INTEL_OUTPUT_FORMAT_YCBCR444))
+ fmts |= BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444);
+
+ drm_connector_attach_color_format_property(&connector->base, fmts);
+}
+
static void
intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *_connector)
{
@@ -7059,6 +7110,8 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *_connec
if (HAS_VRR(display))
drm_connector_attach_vrr_capable_property(&connector->base);
+
+ intel_dp_attach_color_format_property(intel_dp);
}
static void
--
2.54.0
^ permalink raw reply related
* [PATCH v16 13/28] drm/i915/hdmi: Implement "color format" DRM property
From: Nicolas Frattaroli @ 2026-05-23 19:43 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, Daniel Stone
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc, wayland-devel,
Nicolas Frattaroli
In-Reply-To: <20260523-color-format-v16-0-24340c5e4732@collabora.com>
Implement the "color format" DRM property for HDMI. The values of the
property include RGB, YCbCr420, YCbCr444 and Auto. Auto will pick RGB,
with a fallback to YCbCr420.
The mask of supported formats by the source exposed by the property is
an optimistic scenario, as specific DFP-related caveats can't be
established before an EDID is present.
Should the explicitly requested color format not be supported by the
sink (or by the source in combination with the sink), then an error is
returned to userspace, so that it can make a better choice.
Reviewed-by: Daniel Stone <daniel@fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/i915/display/intel_hdmi.c | 52 ++++++++++++++++++++++++++++---
1 file changed, 48 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 6c6a3a0677fe..9e5d88f07262 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -2322,10 +2322,10 @@ static int intel_hdmi_compute_output_format(struct intel_encoder *encoder,
return intel_hdmi_compute_clock(encoder, crtc_state, respect_downstream_limits);
}
-static int intel_hdmi_compute_formats(struct intel_encoder *encoder,
- struct intel_crtc_state *crtc_state,
- const struct drm_connector_state *conn_state,
- bool respect_downstream_limits)
+static int intel_hdmi_compute_formats_auto(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state,
+ const struct drm_connector_state *conn_state,
+ bool respect_downstream_limits)
{
struct intel_display *display = to_intel_display(encoder);
struct intel_connector *connector = to_intel_connector(conn_state->connector);
@@ -2360,6 +2360,35 @@ static int intel_hdmi_compute_formats(struct intel_encoder *encoder,
return ret;
}
+static int intel_hdmi_compute_formats(struct intel_encoder *encoder,
+ struct intel_crtc_state *crtc_state,
+ const struct drm_connector_state *conn_state,
+ bool respect_downstream_limits)
+{
+ struct intel_connector *connector = to_intel_connector(conn_state->connector);
+
+ switch (conn_state->color_format) {
+ case DRM_CONNECTOR_COLOR_FORMAT_RGB444:
+ return intel_hdmi_compute_output_format(encoder, crtc_state, connector,
+ respect_downstream_limits,
+ INTEL_OUTPUT_FORMAT_RGB);
+ case DRM_CONNECTOR_COLOR_FORMAT_YCBCR444:
+ return intel_hdmi_compute_output_format(encoder, crtc_state, connector,
+ respect_downstream_limits,
+ INTEL_OUTPUT_FORMAT_YCBCR444);
+ case DRM_CONNECTOR_COLOR_FORMAT_YCBCR420:
+ return intel_hdmi_compute_output_format(encoder, crtc_state, connector,
+ respect_downstream_limits,
+ INTEL_OUTPUT_FORMAT_YCBCR420);
+ case DRM_CONNECTOR_COLOR_FORMAT_AUTO:
+ return intel_hdmi_compute_formats_auto(encoder, crtc_state, conn_state,
+ respect_downstream_limits);
+ default:
+ MISSING_CASE(conn_state->color_format);
+ return -EINVAL;
+ }
+}
+
static bool intel_hdmi_is_cloned(const struct intel_crtc_state *crtc_state)
{
return crtc_state->uapi.encoder_mask &&
@@ -2732,6 +2761,20 @@ static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs
.atomic_check = intel_hdmi_connector_atomic_check,
};
+static void
+intel_hdmi_attach_color_format_property(struct intel_connector *connector)
+{
+ unsigned long fmts = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444);
+
+ if (connector->base.ycbcr_420_allowed)
+ fmts |= BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
+
+ if (intel_hdmi_can_ycbcr444(connector))
+ fmts |= BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444);
+
+ drm_connector_attach_color_format_property(&connector->base, fmts);
+}
+
static void
intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *_connector)
{
@@ -2744,6 +2787,7 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *_
intel_attach_hdmi_colorspace_property(&connector->base);
drm_connector_attach_content_type_property(&connector->base);
+ intel_hdmi_attach_color_format_property(connector);
if (DISPLAY_VER(display) >= 10)
drm_connector_attach_hdr_output_metadata_property(&connector->base);
--
2.54.0
^ permalink raw reply related
* [PATCH v16 12/28] drm/i915/dp: Add YCBCR444 handling for sink formats
From: Nicolas Frattaroli @ 2026-05-23 19:43 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, Daniel Stone
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc, wayland-devel,
Nicolas Frattaroli
In-Reply-To: <20260523-color-format-v16-0-24340c5e4732@collabora.com>
In anticipation of userspace being able to explicitly select supported
sink formats, add handling of the YCBCR444 sink format. The AUTO path
does not choose this format, but with explicit format selection added to
the driver, it becomes a possibility.
Check for both source and sink support of YCBCR444 in
intel_dp_sink_format_valid.
Acked-by: Daniel Stone <daniel@fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/i915/display/intel_dp.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 1920d2f02666..380933579178 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -1344,6 +1344,16 @@ intel_dp_mode_valid_downstream(struct intel_connector *connector,
8, sink_format, true);
}
+static bool
+intel_dp_can_ycbcr444(struct intel_dp *intel_dp)
+{
+ if (source_can_output(intel_dp, INTEL_OUTPUT_FORMAT_YCBCR444) &&
+ !drm_dp_is_branch(intel_dp->dpcd))
+ return true;
+
+ return false;
+}
+
static enum drm_mode_status
intel_dp_sink_format_valid(struct intel_connector *connector,
const struct drm_display_mode *mode,
@@ -1362,6 +1372,16 @@ intel_dp_sink_format_valid(struct intel_connector *connector,
!drm_mode_is_420(info, mode))
return MODE_NO_420;
+ return MODE_OK;
+ case INTEL_OUTPUT_FORMAT_YCBCR444:
+ if (intel_dp->dfp.min_tmds_clock &&
+ !intel_dp_has_hdmi_sink(intel_dp))
+ return MODE_BAD;
+ if (!intel_dp_can_ycbcr444(intel_dp))
+ return MODE_BAD;
+ if (!(info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444)))
+ return MODE_BAD;
+
return MODE_OK;
case INTEL_OUTPUT_FORMAT_RGB:
return MODE_OK;
--
2.54.0
^ permalink raw reply related
* [PATCH v16 11/28] drm/i915/hdmi: Add YCBCR444 handling for sink formats
From: Nicolas Frattaroli @ 2026-05-23 19:43 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, Daniel Stone
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc, wayland-devel,
Nicolas Frattaroli
In-Reply-To: <20260523-color-format-v16-0-24340c5e4732@collabora.com>
In anticipation of userspace being able to explicitly select supported
sink formats, add handling of the YCBCR444 sink format. The AUTO path
does not choose this format, but with explicit format selection added to
the driver, it becomes a possibility.
Check for YCBCR444 support on the sink in sink_bpc_possible, and on the
source and sink in sink_format_valid.
Acked-by: Daniel Stone <daniel@fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/i915/display/intel_hdmi.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 9076c2b176ec..6c6a3a0677fe 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -1966,6 +1966,8 @@ static bool intel_hdmi_sink_bpc_possible(struct drm_connector *_connector,
if (sink_format == INTEL_OUTPUT_FORMAT_YCBCR420)
return hdmi->y420_dc_modes & DRM_EDID_YCBCR420_DC_36;
+ else if (sink_format == INTEL_OUTPUT_FORMAT_YCBCR444)
+ return info->edid_hdmi_ycbcr444_dc_modes & DRM_EDID_HDMI_DC_36;
else
return info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_36;
case 10:
@@ -1974,6 +1976,8 @@ static bool intel_hdmi_sink_bpc_possible(struct drm_connector *_connector,
if (sink_format == INTEL_OUTPUT_FORMAT_YCBCR420)
return hdmi->y420_dc_modes & DRM_EDID_YCBCR420_DC_30;
+ else if (sink_format == INTEL_OUTPUT_FORMAT_YCBCR444)
+ return info->edid_hdmi_ycbcr444_dc_modes & DRM_EDID_HDMI_DC_30;
else
return info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30;
case 8:
@@ -2021,6 +2025,17 @@ intel_hdmi_mode_clock_valid(struct drm_connector *_connector, int clock,
return status;
}
+static bool
+intel_hdmi_can_ycbcr444(struct intel_connector *connector)
+{
+ const struct intel_display *display = to_intel_display(connector);
+
+ if (!HAS_GMCH(display))
+ return true;
+
+ return false;
+}
+
static enum drm_mode_status
intel_hdmi_sink_format_valid(struct intel_connector *connector,
const struct drm_display_mode *mode,
@@ -2036,6 +2051,15 @@ intel_hdmi_sink_format_valid(struct intel_connector *connector,
!drm_mode_is_420(info, mode))
return MODE_NO_420;
+ return MODE_OK;
+ case INTEL_OUTPUT_FORMAT_YCBCR444:
+ if (!has_hdmi_sink)
+ return MODE_BAD;
+ if (!intel_hdmi_can_ycbcr444(connector))
+ return MODE_BAD;
+ if (!(info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444)))
+ return MODE_BAD;
+
return MODE_OK;
case INTEL_OUTPUT_FORMAT_RGB:
return MODE_OK;
--
2.54.0
^ permalink raw reply related
* [PATCH v16 10/28] drm/amdgpu: Implement "color format" DRM property
From: Nicolas Frattaroli @ 2026-05-23 19:43 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, Daniel Stone
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc, wayland-devel,
Nicolas Frattaroli, Werner Sembach, Andri Yngvason, Marius Vlad
In-Reply-To: <20260523-color-format-v16-0-24340c5e4732@collabora.com>
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>
Reviewed-by: Daniel Stone <daniel@fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 90 ++++++++++++++++++++---
1 file changed, 79 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 dfe97897127c..ece581609cf7 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6899,11 +6899,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)
@@ -6916,20 +6919,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(
@@ -8279,6 +8303,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,
@@ -8325,6 +8381,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,
@@ -9154,6 +9213,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,
@@ -9270,8 +9335,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);
--
2.54.0
^ permalink raw reply related
* [PATCH v16 09/28] drm/display: hdmi-state-helper: Try subsampling in mode_valid
From: Nicolas Frattaroli @ 2026-05-23 19:43 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, Daniel Stone
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc, wayland-devel,
Nicolas Frattaroli, Dmitry Baryshkov
In-Reply-To: <20260523-color-format-v16-0-24340c5e4732@collabora.com>
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>
Reviewed-by: Daniel Stone <daniel@fooishbar.org>
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 1c54e6feac61..acb9b4ada47e 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.54.0
^ permalink raw reply related
* [PATCH v16 08/28] drm/display: hdmi-state-helper: Act on color format DRM property
From: Nicolas Frattaroli @ 2026-05-23 19:43 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, Daniel Stone
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc, wayland-devel,
Nicolas Frattaroli, Dmitry Baryshkov
In-Reply-To: <20260523-color-format-v16-0-24340c5e4732@collabora.com>
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>
Reviewed-by: Daniel Stone <daniel@fooishbar.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 3ba47564caad..1c54e6feac61 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.54.0
^ permalink raw reply related
* [PATCH v16 07/28] drm/atomic-helper: Add HDMI bridge output bus formats helper
From: Nicolas Frattaroli @ 2026-05-23 19:43 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, Daniel Stone
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc, wayland-devel,
Nicolas Frattaroli, Dmitry Baryshkov
In-Reply-To: <20260523-color-format-v16-0-24340c5e4732@collabora.com>
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.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Daniel Stone <daniel@fooishbar.org>
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 3547f797a850..285aac3554df 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>
@@ -4107,3 +4108,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 b84152810abb..4cfeec70d648 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.54.0
^ permalink raw reply related
* [PATCH v16 06/28] drm/bridge: Act on the DRM color format property
From: Nicolas Frattaroli @ 2026-05-23 19:43 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, Daniel Stone
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc, wayland-devel,
Nicolas Frattaroli, Dmitry Baryshkov
In-Reply-To: <20260523-color-format-v16-0-24340c5e4732@collabora.com>
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. Call into the connector function to get
the connector state's connector color format. For bridge connectors
including an HDMI bridge, this will make use of whatever the HDMI
implementation set as output formats, and AUTO will never be part of the
rejection logic.
Reject any output bus formats that do not correspond to the requested
color format. DRM_CONNECTOR_COLOR_FORMAT_AUTO is always accepted as a
matching color format for a bus format, meaning that non-HDMI bridge
chains will end up picking the first bus format choice that works, as
has already been the case previously.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Daniel Stone <daniel@fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/drm_bridge.c | 64 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 63 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 687b36eea0c7..6ec8c23b36b5 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -1149,6 +1149,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.
@@ -1192,6 +1233,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;
@@ -1233,11 +1275,31 @@ drm_atomic_bridge_chain_select_bus_fmts(struct drm_bridge *bridge,
out_bus_fmts[0] = MEDIA_BUS_FMT_FIXED;
}
+ /*
+ * Instead of directly accessing conn_state.color_format, call into a
+ * connector function that allows connector implementations (e.g. for
+ * bridge connectors including HDMI bridges, where the HDMI helpers will
+ * have already chosen an appropriate output format) to override the
+ * selected format.
+ */
+ fmt = drm_connector_get_color_format(conn_state);
+
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;
+ }
}
kfree(out_bus_fmts);
--
2.54.0
^ permalink raw reply related
* [PATCH v16 05/28] drm/display: bridge_connector: Use HDMI color format for HDMI conns
From: Nicolas Frattaroli @ 2026-05-23 19:43 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, Daniel Stone
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc, wayland-devel,
Nicolas Frattaroli, Dmitry Baryshkov
In-Reply-To: <20260523-color-format-v16-0-24340c5e4732@collabora.com>
For bridge connectors which contain an HDMI bridge at some stage, the
HDMI state helpers' format selection logic should be involved.
Add an implementation for the drm_bridge_funcs color_format function,
which translates from the HDMI state's output format to a connector
format for bridge connectors involving an HDMI bridge, but return the
connector state's color_format member unchanged otherwise.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Daniel Stone <daniel@fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/display/drm_bridge_connector.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 649969fca141..19da5f668942 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -276,6 +276,29 @@ static void drm_bridge_connector_reset(struct drm_connector *connector)
connector->state);
}
+static enum drm_connector_color_format
+drm_bridge_connector_color_format(const struct drm_connector_state *conn_state)
+{
+ struct drm_bridge_connector *bridge_connector =
+ to_drm_bridge_connector(conn_state->connector);
+
+ if (bridge_connector->bridge_hdmi) {
+ switch (conn_state->hdmi.output_format) {
+ default:
+ case DRM_OUTPUT_COLOR_FORMAT_RGB444:
+ return DRM_CONNECTOR_COLOR_FORMAT_RGB444;
+ case DRM_OUTPUT_COLOR_FORMAT_YCBCR444:
+ return DRM_CONNECTOR_COLOR_FORMAT_YCBCR444;
+ case DRM_OUTPUT_COLOR_FORMAT_YCBCR422:
+ return DRM_CONNECTOR_COLOR_FORMAT_YCBCR422;
+ case DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
+ return DRM_CONNECTOR_COLOR_FORMAT_YCBCR420;
+ }
+ }
+
+ return conn_state->color_format;
+}
+
static const struct drm_connector_funcs drm_bridge_connector_funcs = {
.reset = drm_bridge_connector_reset,
.detect = drm_bridge_connector_detect,
@@ -285,6 +308,7 @@ static const struct drm_connector_funcs drm_bridge_connector_funcs = {
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.debugfs_init = drm_bridge_connector_debugfs_init,
.oob_hotplug_event = drm_bridge_connector_oob_hotplug_event,
+ .color_format = drm_bridge_connector_color_format,
};
/* -----------------------------------------------------------------------------
--
2.54.0
^ permalink raw reply related
* [PATCH v16 04/28] drm/connector: Let connectors have a say in their color format
From: Nicolas Frattaroli @ 2026-05-23 19:43 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, Daniel Stone
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc, wayland-devel,
Nicolas Frattaroli, Dmitry Baryshkov
In-Reply-To: <20260523-color-format-v16-0-24340c5e4732@collabora.com>
Add a function to get the connector color format from a connector state,
and a new function pointer in drm_connector_funcs to allow connectors to
override what connector color format it returns.
This is useful for the bridge chain recursive bus format selection code,
which does not wish to implement connector implementation specific
checks like whether it involves HDMI.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Daniel Stone <daniel@fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
drivers/gpu/drm/drm_connector.c | 16 ++++++++++++++++
include/drm/drm_connector.h | 12 ++++++++++++
2 files changed, 28 insertions(+)
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index a0fca522f18f..41a5ab1e563e 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -3685,6 +3685,22 @@ void drm_connector_oob_hotplug_event(struct fwnode_handle *connector_fwnode,
}
EXPORT_SYMBOL(drm_connector_oob_hotplug_event);
+/**
+ * drm_connector_get_color_format - Return connector color format of @conn_state
+ * @conn_state: pointer to the &struct drm_connector_state to go check
+ *
+ */
+enum drm_connector_color_format
+drm_connector_get_color_format(const struct drm_connector_state *conn_state)
+{
+ struct drm_connector *connector = conn_state->connector;
+
+ if (connector->funcs->color_format)
+ return connector->funcs->color_format(conn_state);
+
+ return conn_state->color_format;
+}
+EXPORT_SYMBOL(drm_connector_get_color_format);
/**
* DOC: Tile group
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 03e42c36175d..c9aad2bc8227 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1787,6 +1787,16 @@ struct drm_connector_funcs {
* Allows connectors to create connector-specific debugfs files.
*/
void (*debugfs_init)(struct drm_connector *connector, struct dentry *root);
+
+ /**
+ * @color_format:
+ *
+ * Allows connectors to return a connector color format other than
+ * @conn_state.color_format for purposes of e.g. display protocol
+ * specific helper logic having already mapped it to an output format.
+ */
+ enum drm_connector_color_format (*color_format)(
+ const struct drm_connector_state *conn_state);
};
/**
@@ -2603,6 +2613,8 @@ drm_connector_is_unregistered(struct drm_connector *connector)
void drm_connector_oob_hotplug_event(struct fwnode_handle *connector_fwnode,
enum drm_connector_status status);
+enum drm_connector_color_format
+drm_connector_get_color_format(const struct drm_connector_state *conn_state);
const char *drm_get_connector_type_name(unsigned int connector_type);
const char *drm_get_connector_status_name(enum drm_connector_status status);
const char *drm_get_subpixel_order_name(enum subpixel_order order);
--
2.54.0
^ permalink raw reply related
* [PATCH v16 03/28] drm: Add new general DRM property "color format"
From: Nicolas Frattaroli @ 2026-05-23 19:43 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, Daniel Stone
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc, wayland-devel,
Nicolas Frattaroli, Werner Sembach, Andri Yngvason, Marius Vlad
In-Reply-To: <20260523-color-format-v16-0-24340c5e4732@collabora.com>
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 string values for the new enum property are:
- "AUTO" (setup by default, driver internally picks the color format)
- "RGB"
- "YUV 4:4:4"
- "YUV 4:2:2"
- "YUV 4:2:0"
Drivers should advertise from this list the formats they support in an
optimistic best-case scenario. EDID data from the sink can then be used
in the kernel's atomic check phase to restrict this set of formats, as
well as by userspace to make a correct choice in the first place.
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>
Reviewed-by: Daniel Stone <daniel@fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
Documentation/gpu/drm-kms.rst | 6 ++
drivers/gpu/drm/drm_atomic_helper.c | 5 ++
drivers/gpu/drm/drm_atomic_uapi.c | 4 +
drivers/gpu/drm/drm_connector.c | 155 ++++++++++++++++++++++++++++++++++++
include/drm/drm_connector.h | 84 +++++++++++++++++++
5 files changed, 254 insertions(+)
diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst
index fa69a5450f96..2b6a96211cfc 100644
--- a/Documentation/gpu/drm-kms.rst
+++ b/Documentation/gpu/drm-kms.rst
@@ -604,6 +604,12 @@ Color Management Properties
.. kernel-doc:: drivers/gpu/drm/drm_color_mgmt.c
:doc: overview
+Color Format Property
+---------------------
+
+.. kernel-doc:: drivers/gpu/drm/drm_connector.c
+ :doc: Color format
+
Tile Group Property
-------------------
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 51f39edc31ed..3547f797a850 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 6441b55cc274..c7f80d90794c 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -935,6 +935,8 @@ 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) {
+ state->color_format = val;
} else if (connector->funcs->atomic_set_property) {
return connector->funcs->atomic_set_property(connector,
state, property, val);
@@ -1020,6 +1022,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 3fa4d2082cd7..a0fca522f18f 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
@@ -2935,6 +2947,149 @@ int drm_connector_attach_colorspace_property(struct drm_connector *connector)
}
EXPORT_SYMBOL(drm_connector_attach_colorspace_property);
+/**
+ * DOC: Color format
+ *
+ * The connector "color format" property allows userspace to request a specific
+ * color model on the output of the connector. Not all values listed by the
+ * property are guaranteed to work for every sink; rather, it is an optimistic
+ * listing of color formats that the source could output depending on
+ * circumstances.
+ *
+ * Whether it actually can output a certain color format is determined during
+ * the atomic check phase. Consequently, a userspace application that sets the
+ * color format to a value other than "AUTO" should check whether its atomic
+ * commit succeeded.
+ *
+ * Possible values for "color format":
+ *
+ * "AUTO":
+ * The driver or display protocol helpers should pick a suitable color
+ * format. All implementations of a specific display protocol will behave
+ * the same way with "AUTO", but different display protocols do not
+ * necessarily have the same "AUTO" semantics.
+ *
+ * For HDMI connectors, "AUTO" picks RGB, but falls back to YUV 4:2:0 if
+ * the bandwidth required for full-scale RGB is not available, or the mode
+ * is YUV 4:2:0-only, as long as the mode, source, and sink all support
+ * YUV 4:2:0.
+ * "RGB":
+ * RGB output format. The quantization range (limited/full) depends on the
+ * value of the "Broadcast RGB" property if it is present on the connector.
+ * "YUV 4:4:4":
+ * YUV 4:4:4 (a.k.a. YCbCr 4:4:4) output format. Chroma is not subsampled.
+ * The quantization range defaults to limited.
+ * "YUV 4:2:2":
+ * YUV 4:2:2 (a.k.a. YCbCr 4:2:2) output format. Chroma has half the
+ * horizontal resolution of Luma. The quantization range defaults to
+ * limited.
+ * "YUV 4:2:0":
+ * YUV 4:2:0 (a.k.a. YCbCr 4:2:0) output format. Chroma has half the
+ * horizontal and vertical resolution of Luma. The quantization range
+ * defaults to limited.
+ *
+ * A sink may only support some color formats in specific modes and at specific
+ * bit depths. The atomic modesetting API should be used to set a working
+ * configuration in one go, as an unsupported combination of parameters is
+ * rejected.
+ */
+
+/**
+ * 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 5ad62c207d00..03e42c36175d 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -571,12 +571,80 @@ 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. The
+ * quantization range depends on the value of the "Broadcast RGB"
+ * property if it is present on the connector.
+ */
+ DRM_CONNECTOR_COLOR_FORMAT_RGB444,
+
+ /**
+ * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR444: YCbCr 4:4:4 output format (ie.
+ * not subsampled). Quantization range is "Limited" by default.
+ */
+ DRM_CONNECTOR_COLOR_FORMAT_YCBCR444,
+
+ /**
+ * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR422: YCbCr 4:2:2 output format (ie.
+ * with horizontal subsampling). Quantization range is "Limited" by
+ * default.
+ */
+ DRM_CONNECTOR_COLOR_FORMAT_YCBCR422,
+
+ /**
+ * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR420: YCbCr 4:2:0 output format (ie.
+ * with horizontal and vertical subsampling). Quantization range is
+ * "Limited" by default.
+ */
+ 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,
};
const char *
@@ -1167,6 +1235,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
*
@@ -2165,6 +2240,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:
*
@@ -2648,6 +2729,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.54.0
^ permalink raw reply related
* [PATCH v16 00/28] Add new general DRM property "color format"
From: Nicolas Frattaroli @ 2026-05-23 19:43 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, Daniel Stone
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc, wayland-devel,
Nicolas Frattaroli, Werner Sembach, Andri Yngvason,
Cristian Ciocaltea, Marius Vlad, Dmitry Baryshkov, Andy Yan
Hello,
this is a follow-up to
https://lore.kernel.org/all/20250911130739.4936-1-marius.vlad@collabora.com/
which in of itself is a follow-up to
https://lore.kernel.org/dri-devel/20240115160554.720247-1-andri@yngvason.is/ where
a new DRM connector property has been added allowing users to
force a particular color format.
That in turn was actually also a follow-up from Werner Sembach's posted at
https://lore.kernel.org/dri-devel/20210630151018.330354-1-wse@tuxedocomputers.com/
As the number of cooks have reached critical mass, I'm hoping I'll be
the last person to touch this particular series.
We have an implementation in Weston at
https://gitlab.freedesktop.org/wayland/weston/-/merge_requests/1825 that
adds support for this property. This patch series has been tested
against that MR on i915 (HDMI, DP), amdgpu (HDMI, DP) and on rockchip
(HDMI).
You can also manually test this with modetest like so, but beware that
this is a non-atomic invocation, so testing YUV420 like this will result
in weird outcomes if only some of the modes support YUV420:
$ modetest -s 115:1920x1080-60@NV12 -w 115:'color format':4
where 115 is the connector ID and '4' is the enum value for a particular
color format.
General notes on the approach taken by me: instead of silently switching
to a different format than was explicitly requested, or even worse,
outputting something to the sink the sink doesn't support, bubble up an
error to userspace instead. "color format" is a "I want this" type
property, not a "force this" type property, i.e. the kernel will respect
the limits imposed by the hardware.
Things I've tested:
- HDMI (YCbCr 4:4:4 + YCbCr 4:2:2 (8-bit) + RGB + Auto) on RK3588
- HDMI (YCbCr 4:4:4 + YCbCr 4:2:2 (8-bit) + RGB + Auto) on RK3576
- HDMI (YCbCr 4:4:4, YCbCr 4:2:0, RGB, Auto) + DP (YCbCr 4:4:4, RGB,
Auto) on Intel N97 (i915).
- HDMI (YCbCr 4:4:4, YCbCr 4:2:2, YCbCr 4:2:0, RGB, Auto) + DP (YCbCr
4:4:4, RGB, Auto) on an AMD Radeon RX 550 (amdgpu).
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
Changes in v16:
- drm/i915/dp: Don't check for dfp conversion to determine ycbcr444
output capability
- drm/i915/dp: Replicate intel_dp_has_hdmi_sink check for YCBCR444 as well
- drm/i915/dp: Reorder formats and checks in sink_format_valid
- drm/i915/hdmi: Fix inverted HAS_GMCH check for YCBCR444 capability
- drm/i915/hdmi: Add has_hdmi_sink check to YCBCR444 sink_format_valid
- drm/i915/hdmi: Reorder formats in sink_format_valid
- drm/i915/hdmi: Drop documentation for internal function
- Link to v15: https://patch.msgid.link/20260522-color-format-v15-0-21fb136c9df2@collabora.com
Changes in v15:
- Drop redundant drm_connector_color_format_valid() function
- dw-hdmi-qp-rockchip: make dw_hdmi_qp_rockchip_get_vop_format()'s
return type int, check bstate for IS_ERR rather than NULL, and pass up
error codes to caller
- rebase onto recent drm-tip, necessitating
s/drm_atomic_state/drm_atomic_commit/ in the KUnit tests
- Link to v14: https://patch.msgid.link/20260423-color-format-v14-0-449a419ccbd4@collabora.com
Changes in v14:
- i915: Check for source support of YCbCr444 in both the sink format
validation and when registering the properites on the connectors.
- i915: Split HDMI and DP implementations into separate patches, with
their own supported color formats masks.
- Link to v13: https://patch.msgid.link/20260413-color-format-v13-0-ab37d4dfba48@collabora.com
Changes in v13:
- Introduce a new drm_connector_funcs member that returns the
connector state's color format with additional bells and whistles.
- Implement this new func in drm_bridge_connector to return whatever the
HDMI implementation did if an HDMI bridge is present.
- Call into the drm_connector.h function wrapping this new func in the
recursive bridge chain bus format selection code.
- Link to v12: https://patch.msgid.link/20260409-color-format-v12-0-ce84e1817a27@collabora.com
Changes in v12:
- Rebase on top of Ville's i915 format selection cleanup series
- i915: Reimplement based on new format selection code. Drop the DP-MST
implementation, as sinks with different sets of supported formats
complicate the matter.
- Adjust documentation on drm_connector_color_format enum values to
mention quantization ranges.
- Add documentation to drm-kms page to document the string values for
the property. Mostly the same documentation as the enum values, but
from a more userspace-centric perspective. This is done in the patch
that introduces the property, but I didn't drop the existing R-b as
it isn't a functional change.
- Update documentation of "colorspace" property to mention that "color
format" property controls the output format.
- amdgpu: Remove property from DP-MST, as it's unclear whether it'd work
properly with sinks that have different sets of supported formats
- Link to v11: https://patch.msgid.link/20260324-color-format-v11-0-605559af4fb4@collabora.com
Changes in v11:
- amdgpu: fix property registration on DP-MST
- i915: fix property registration on DP-MST
- rebase on drm-tip, which includes Maxime's refactor series that was
previously declared a dependency of this series
- Link to v10: https://lore.kernel.org/r/20260305-color-format-v10-0-a58c68a11868@collabora.com
Changes in v10:
- Make DRM_OUTPUT_COLOR_FORMAT_COUNT and
DRM_CONNECTOR_COLOR_FORMAT_COUNT part of the enum definition (thanks
to Maxime)
- Preemptively avoid the warning that would be generated by the
enumification of DRM_OUTPUT_COLOR_FORMAT_COUNT by modifying the
problematic switch statement in drm_hdmi_state_helper's
sink_supports_format_bpc.
- drm/bridge: Change HDMI check from checking for the last bridge having
a DRM_BRIDGE_OP_HDMI in ops to checking if last_bridge->type is HDMIA.
This is not quite the suggestion Dmitry had, but according to the
documentation of the drm_bridge.type member, and the
display-connector.c code, it should be correct.
- Combine drm_mode_create_color_format_property and
drm_connector_attach_color_format_property into one function named the
latter. (thanks to Dmitry Baryshkov)
- Change author of 'drm: Add new general DRM property "color format"'
to myself as it has by now changed quite a bit, and add Andri and
Werner as Co-developed-by, as per Andri's suggestion.
- hdmi-state-helper: Rework hdmi_compute_config to make code flow more
obvious, and drop Dmitry's R-b as a consequence (thanks to Maxime)
- Move dw-hdmi-qp's atomic_get_output_bus_fmts into
drm_bridge_helper.c, along with kernel doc string (thanks to Dmitry)
- Future-proof the aforementioned get_output_bus_fmts use of hweight8 on
the supported_formats bitmask with a BUILD_BUG_ON.
- Add a KUnit test for the HDMI output bus formats helper
- Link to v9: https://lore.kernel.org/r/20260227-color-format-v9-0-658c3b9db7ef@collabora.com
Changes in v9:
- Document what the "AUTO" behaviour is in the color format enum (thanks
to Maxime)
- drm/bridge: dw-hdmi-qp: Fix a rebase oopsie that reintroduced some
functions that were dropped. (thanks to Cristian)
- drm/bridge: Shuffle "1:1" in the bridge fmt selection docs to earlier
in the sentence. (thanks to Randy Dunlap)
- i915: Check chosen output format against requested format for dp-mst
- All color format driver implementations: rebase and rework on top of
Maxime's series
- As part of this rework, rename drm_color_format_enum to
drm_connector_color_format
- drm kunit tests: rework for the new enums. Changes were trivial, so
trailers were kept
- Link to v8: https://lore.kernel.org/r/20260216-color-format-v8-0-5722ce175dd5@collabora.com
Changes in v8:
- Drop "drm/rockchip: vop2: Fix YUV444 output", as the original problem
could not be reproduced anymore, and the justification did not make
sense.
- Remove the 12-bit format from "drm/rockchip: vop2: Recognise 10/12-bit
YUV422 as YUV formats".
- Refactor to keep the original DRM_COLOR_FORMAT bitshifted defines
as-is, but introduce a new drm_color_format_enum enum.
- Adjust conversion functions for the newly refactored enum, ensuring
they only return valid enum values, and only convert in directions
that open up no error value cans of worms.
- Rework the property uapi code for the newly refactored enum, since
it no longer needs to do any bitshifting or ffs().
- Rework all the device drivers for the new enum.
- Rework all the tests for the refactored enum.
- Rework the hdmi state helper for the new enum, and also make it more
explicit about the auto behaviour by not relying on a conversion
function to map AUTO to RGB, but do this in the framework itself.
- rockchip dw_hdmi_qp: Fix the GRF value to check for color >= 0 instead
of color > 0, as the latter broke switching back to RGB.
- Rebase onto a recent drm-tip. This necessitated blindly reworking some
of the i915 dp-mst code.
- Drop the __maybe_unused edid test patch, as I could no longer
reproduce the build warnings I added it for. I blame ghosts.
- drm_bridge tests: remove "destroyed" member from struct
drm_bridge_chain_priv and all associated code, as it was not used in
any test.
- Link to v7: https://lore.kernel.org/r/20260121-color-format-v7-0-ef790dae780c@collabora.com
Changes in v7:
- Fix drm_bridge kunit test build failure caused by rebasing across an
API change.
- Make compilers shut up about unused EDID definitions in the test
suites.
- Empty line checkpatch fixes that b4 prep --check didn't catch.
- Link to v6: https://lore.kernel.org/r/20260121-color-format-v6-0-7b81a771cd0b@collabora.com
Changes in v6:
- Checkpatch fixes
- Add drm_bridge.c kerneldoc fix patch to b4 deps so the kernel docs
required for every contribution to the subsystem can be built
- dw-hdmi-qp core has gained the atomic_get_output_bus_fmts bridge func,
which allows it to participate in the drm_bridge chain recursive format
selection code properly.
- The Rockchip dw-hdmi-qp integration now no longer reimplements the
color format logic (improperly), but reads the bus format of the first
bridge as set by the recursive bridge format selection. If the input
format is FIXED, it'll use the output format. Otherwise, the input
format is used.
- In the synopsys drivers, YUV422 uses the same bus format as the non-qp
hdmi encoder driver. Probably correcter this way. The Rockchip vop2
is_yuv function has been extended to recognise this format as well.
- KUnit tests for drm_bridge chains are now included, which exercise the
chain's recursive bus format selection.
- On HDMI connectors, the drm_bridge bus format selection will try to target
the color format that the HDMI layer came up with. This means the AUTO
logic is not duplicated for HDMI connectors.
- The enum conversion function commit gained a function for converting
from hdmi_colorspace to drm_color_format, and its author changed as no
original code remains anyway. Marius is still included as a
Co-developer.
- Some tests for the HDMI state helper's mode_valid have been written.
They are incomplete as we lack a test EDID for a 420-also mode that
would violate the clock constraints on RGB. I hacked one together with
a hex editor, but it reports a too high of a clock rate, and there's
no EDID editor I could find which supports these extension blocks.
- The color_format KUnit tests have been more heavily parameterised, the
auto case absorbed into other tests, and the comments around them
rewritten.
- Add a few paragraphs of documentation that explain the bridge format
selection, and how to make use of it in a display driver.
- Link to v5: https://lore.kernel.org/r/20251128-color-format-v5-0-63e82f1db1e1@collabora.com
Changes in v5:
- Rebase onto drm-tip
- Drop DRM_MODE_COLOR_FORMAT_* as an enum
- Unify DRM_COLOR_FORMAT_NONE and DRM_COLOR_FORMAT_AUTO, with AUTO being
0. This makes conversion and general logic much easier.
- Adjust the drm_color_format enum to not needlessly renumber the
existing defines, as it doesn't need to correspond to how HDMI numbers
them.
- Make the DRM-to-HDMI conversion function static inline __pure, because
the assembly it generates is tiny, and the function is pure.
- Don't accept nothing as the list of supported color formats for
registration of the property.
- Drop the per-connector variants of the color format registration
function, as it's not needed.
- drm_hdmi_state_helper: Fix mode_valid rejecting 420-only modes.
- drm_hdmi_state_helper: Only fall back to YUV420 with
DRM_COLOR_FORMAT_AUTO.
- drm_hdmi_state_helper: Remove redundant AUTO->RGB condition, as the
conversion already does this.
- Add KUnit tests for hdmi_compute_config.
- drm/bridge: Refactor bus_format_is_color_fmt and add a few more YUV422
formats.
- Register the color format property in drmm_connector_hdmi_init based
on the supported HDMI formats passed to it. This means rockchip
dw_hdmi_qp no longer needs to register it.
- amdgpu: Simplify YUV420 logic
- amdgpu: Don't try to pick YUV444 on YUV420-only modes
- i915: Try to make behaviour more or less the same as that of the drm
hdmi state helper.
- rockchip dw_hdmi_qp: Set supported HDMI formats
- rockchip dw_hdmi_qp: Set the right VO GRF values depending on color
format.
- rockchip dw_hdmi_qp: Act on the color format property in this driver,
rather than in VOP2, by setting the bus_format appropriately.
- rockchip VOP2: Can the BCSH-based implementation. BCSH isn't available
on all video ports of the hardware, and the code was extremely
suspect. Instead, plug into the existing YUV-to-RGB/RGB-to-YUV code,
which can be done now that the HDMI driver sets the bus format.
- A whole bunch of Rockchip VOP2 fixes.
- Link to v4: https://lore.kernel.org/r/20251117-color-format-v4-0-0ded72bd1b00@collabora.com
Changes in v4:
- Rebase onto next-20251117
- Get rid of HDMI_COLORSPACE_AUTO
- Split hdmi_compute_config change into separate patch
- Add missing symbol export for color_format_to_hdmi_colorspace to fix
builds in certain configurations
- Drop "drm: Pass supported color formats straight onto drm_bridge"
- Make dw-hdmi-qp set the platform data's supported color formats as
the bridge's supported HDMI color formats
- drm_hdmi_state_helper: pass requested color format to
hdmi_compute_format_bpc if set.
- drm_bridge: limit the bus formats to those explicitly requested with
the color format property during the atomic bridge check call,
specifically in drm_atomic_bridge_chain_select_bus_fmts.
- i915: Remove INTEL_OUTPUT_FORMAT_AUTO, as automatic format selection
does not need to involve the hardware state
- i915: Deduplicate ntel_output_format_to_drm_color_format code by
moving it as a static inline __pure function into a shared header
- i915: rework logic in HDMI, DP and DP-MST output config functions to
remove redundant locals, simplify execution flow, and return an error
to userspace if an explicit color_format request can't be satisfied.
- i915: assign myself as the author and make the others Co-developers,
so that they don't get the blame for any of my bugs.
- amdgpu: refactor fill_stream_properties_from_drm_display_mode to
improve readability and ensure that impossible color format requests
get bubbled up to userspace as errors
- amdgpu: don't pick YUV444 over RGB.
- amdgpu: assign authorship to myself, with others as Co-developers, as
logic was modified and the blame should fall on me
- dw_hdmi_qp-rockchip: set the supported color formats platform data
member
- rockchip: remove drm property registration for rk3066_hdmi and
inno_hdmi. None of the platforms that use these use vop2 as the
video output processor.
- Link to v3: https://lore.kernel.org/all/20250911130739.4936-1-marius.vlad@collabora.com/
Changes in v3 by mvlad compared to Andri's v2 series:
- renamed the property to just 'color format'
- the property is added dynamically similar to the Colorspace property
- a key point from previous comments was that drivers should advertise
the color formats they support and userspace would query EDID and
perform an intersection from those color formats which users can
further use. With this patch set each driver that adds this property
has such list of hard-coded color formats, but fundamentally the idea
is that driver can query the HW and do that on its own. The
infrastructure is now in place to allow to do that
- by default the 'AUTO' color format is set. With this patch series that
has been introduced as a fallback to RGB. Drivers could further
customize this behavour and could perform additional checks on the sink
to pick another suitable color format they'd like for AUTO
- drm_bridge bridge code has been improved to allow initialization with
the same color formats list as the DRM connector property. Similarly, bpc
pick-up now takes the color format into consideration when deciding
which bpc to choose from
- The new DRM color format re-uses HDMI_COLORPSACE enum and provides an
enum translations between the two to avoid touching all other drivers that
use HDMI_COLORPSACE enum. I believe at this point that this allows the
least amount of disruption and avoids a massive bike shedding around
that part
- a rockchip implementation has been by my colleague Derek Foreman
- YUV444 color format has been added in i915
- address comment about "Remove unnecessary SIGNAL_TYPE_HDMI_TYPE_A
check" where aconnector might be invalid
- Link to v2: https://lore.kernel.org/dri-devel/20240115160554.720247-1-andri@yngvason.is/
---
Nicolas Frattaroli (27):
drm/display: hdmi-state-helper: Use default case for unsupported formats
drm: Add new general DRM property "color format"
drm/connector: Let connectors have a say in their color format
drm/display: bridge_connector: Use HDMI color format for HDMI conns
drm/bridge: Act on the DRM color format property
drm/atomic-helper: Add HDMI bridge output bus formats helper
drm/display: hdmi-state-helper: Act on color format DRM property
drm/display: hdmi-state-helper: Try subsampling in mode_valid
drm/amdgpu: Implement "color format" DRM property
drm/i915/hdmi: Add YCBCR444 handling for sink formats
drm/i915/dp: Add YCBCR444 handling for sink formats
drm/i915/hdmi: Implement "color format" DRM property
drm/i915/dp: Implement "color format" DRM property
drm/rockchip: Add YUV422 output mode constants for VOP2
drm/rockchip: vop2: Add RK3576 to the RG swap special case
drm/rockchip: vop2: Recognise 10-bit YUV422 as YUV format
drm/rockchip: vop2: Set correct output format for RK3576 YUV422
drm/bridge: dw-hdmi-qp: Use common HDMI output bus fmts helper
drm/rockchip: dw_hdmi_qp: Implement "color format" DRM property
drm/rockchip: dw_hdmi_qp: Set supported_formats platdata
drm/connector: Register color format property on HDMI connectors
drm/tests: hdmi: Add tests for the color_format property
drm/tests: hdmi: Add tests for HDMI helper's mode_valid
drm/tests: bridge: Add KUnit tests for bridge chain format selection
drm/tests: bridge: Add test for HDMI output bus formats helper
drm/bridge: Document bridge chain format selection
drm/connector: Update docs of "colorspace" for color format prop
Werner Sembach (1):
drm/amd/display: Remove unnecessary SIGNAL_TYPE_HDMI_TYPE_A check
Documentation/gpu/drm-kms-helpers.rst | 6 +
Documentation/gpu/drm-kms.rst | 6 +
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 91 +-
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 1 +
drivers/gpu/drm/display/drm_bridge_connector.c | 24 +
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 53 +-
drivers/gpu/drm/drm_atomic_helper.c | 86 ++
drivers/gpu/drm/drm_atomic_uapi.c | 4 +
drivers/gpu/drm/drm_bridge.c | 104 ++-
drivers/gpu/drm/drm_connector.c | 178 +++-
drivers/gpu/drm/i915/display/intel_dp.c | 81 +-
drivers/gpu/drm/i915/display/intel_hdmi.c | 76 +-
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 111 ++-
drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 4 +
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 21 +-
drivers/gpu/drm/tests/drm_bridge_test.c | 971 +++++++++++++++++++++
drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 345 ++++++++
include/drm/drm_atomic_helper.h | 7 +
include/drm/drm_connector.h | 96 ++
19 files changed, 2228 insertions(+), 37 deletions(-)
---
base-commit: 8345929e243a7114bc17c48d0ff01923d2daae76
change-id: 20251028-color-format-49fd202b7183
Best regards,
--
Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
^ permalink raw reply
* [PATCH v16 02/28] drm/display: hdmi-state-helper: Use default case for unsupported formats
From: Nicolas Frattaroli @ 2026-05-23 19:43 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, Daniel Stone
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc, wayland-devel,
Nicolas Frattaroli, Cristian Ciocaltea
In-Reply-To: <20260523-color-format-v16-0-24340c5e4732@collabora.com>
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>
Reviewed-by: Daniel Stone <daniel@fooishbar.org>
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 4867edbf2622..3ba47564caad 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.54.0
^ permalink raw reply related
* [PATCH v16 01/28] drm/amd/display: Remove unnecessary SIGNAL_TYPE_HDMI_TYPE_A check
From: Nicolas Frattaroli @ 2026-05-23 19:43 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, Daniel Stone
Cc: kernel, amd-gfx, dri-devel, linux-kernel, linux-arm-kernel,
linux-rockchip, intel-gfx, intel-xe, linux-doc, wayland-devel,
Nicolas Frattaroli, Werner Sembach, Andri Yngvason
In-Reply-To: <20260523-color-format-v16-0-24340c5e4732@collabora.com>
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>
Reviewed-by: Daniel Stone <daniel@fooishbar.org>
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 ba7f98a87808..dfe97897127c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6917,12 +6917,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.54.0
^ permalink raw reply related
* [PATCH 0/3] AF_ALG: Remove support for AIO and old-style drivers
From: Demi Marie Obenour via B4 Relay @ 2026-05-23 19:43 UTC (permalink / raw)
To: Herbert Xu, David S. Miller, Eric Dumazet, Kuniyuki Iwashima,
Paolo Abeni, Willem de Bruijn, Jens Axboe, Jakub Kicinski,
Simon Horman, Peter Zijlstra, Ingo Molnar,
Arnaldo Carvalho de Melo, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
James Clark, Jonathan Corbet, Shuah Khan, Eric Biggers,
Ard Biesheuvel
Cc: linux-crypto, linux-kernel, io-uring, netdev, linux-perf-users,
linux-doc, Demi Marie Obenour
AF_ALG is a deprecated API only useful for compatibility with existing
userspace. It has had a lot of vulnerabilities, including the infamous
CopyFail.
Rip out support for offload drivers, which tend to be buggy. Also rip
out support for AIO, which actually bloats the entire socket subsystem.
Only compile-tested.
Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
---
Demi Marie Obenour (3):
net: Remove support for AIO on sockets
AF_ALG: Drop support for off-CPU cryptography
AF_ALG: Document that it is *always* slower
Documentation/crypto/userspace-if.rst | 26 ++++++++--
crypto/af_alg.c | 35 ++------------
crypto/algif_aead.c | 43 ++++-------------
crypto/algif_hash.c | 4 +-
crypto/algif_rng.c | 4 +-
crypto/algif_skcipher.c | 66 ++++++--------------------
include/crypto/if_alg.h | 19 ++++++--
include/linux/socket.h | 1 -
io_uring/net.c | 1 -
net/compat.c | 1 -
net/socket.c | 7 +--
tools/perf/trace/beauty/include/linux/socket.h | 1 -
12 files changed, 70 insertions(+), 138 deletions(-)
---
base-commit: 49e05bb00f2e8168695f7af4d694c39e1423e8a2
change-id: 20260502-af-alg-harden-900849451653
Best regards,
--
Demi Marie Obenour <demiobenour@gmail.com>
^ permalink raw reply
* [PATCH 2/3] AF_ALG: Drop support for off-CPU cryptography
From: Demi Marie Obenour via B4 Relay @ 2026-05-23 19:43 UTC (permalink / raw)
To: Herbert Xu, David S. Miller, Eric Dumazet, Kuniyuki Iwashima,
Paolo Abeni, Willem de Bruijn, Jens Axboe, Jakub Kicinski,
Simon Horman, Peter Zijlstra, Ingo Molnar,
Arnaldo Carvalho de Melo, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
James Clark, Jonathan Corbet, Shuah Khan, Eric Biggers,
Ard Biesheuvel
Cc: linux-crypto, linux-kernel, io-uring, netdev, linux-perf-users,
linux-doc, Demi Marie Obenour
In-Reply-To: <20260523-af-alg-harden-v1-0-c76755c3a5c5@gmail.com>
From: Demi Marie Obenour <demiobenour@gmail.com>
AF_ALG is deprecated and exposed to unprivileged userspace. Only
use the least buggy algorithm implementations: the pure software ones.
This removes one of the main advantages of AF_ALG, which is the
ability to use it with off-CPU accelerators. However, using off-CPU
accelerators has huge overheads, both in performance and attack surface.
I have yet to see real-world, performance-critical workloads where using
an accelerator via AF_ALG is actually a win over doing cryptography in
userspace.
If using an off-CPU accelerator really does turn out to be a win, a new
API should be developed that is actually a good fit for it.
Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
---
Documentation/crypto/userspace-if.rst | 7 ++++++-
crypto/af_alg.c | 2 +-
crypto/algif_aead.c | 4 ++--
crypto/algif_hash.c | 4 ++--
crypto/algif_rng.c | 4 ++--
crypto/algif_skcipher.c | 4 ++--
include/crypto/if_alg.h | 14 +++++++++++++-
7 files changed, 28 insertions(+), 11 deletions(-)
diff --git a/Documentation/crypto/userspace-if.rst b/Documentation/crypto/userspace-if.rst
index ea1b1b3f4049fd4673528dc2a6234f6376a3489f..b31117d4415dda6ad6ca36275e615bec7df9552e 100644
--- a/Documentation/crypto/userspace-if.rst
+++ b/Documentation/crypto/userspace-if.rst
@@ -9,7 +9,8 @@ symmetric cipher, AEAD, and RNG algorithms that are implemented in kernel-mode
code.
AF_ALG is insecure and is deprecated. Originally added to the kernel in 2010,
-most kernel developers now consider it to be a mistake.
+most kernel developers now consider it to be a mistake. Support for hardware
+accelerators, which was the original purpose of AF_ALG, has been removed.
AF_ALG continues to be supported only for backwards compatibility. On systems
where no programs using AF_ALG remain, the support for it should be disabled by
@@ -59,6 +60,10 @@ Some of the examples include:
- CVE-2013-7421
- CVE-2011-4081
+Hardware accelerator drivers are frequently buggy. To reduce attack surface,
+AF_ALG now only provides access to algorithms implemented in software. This
+means that AF_ALG no longer fulfills its original purpose.
+
It is recommended that, whenever possible, userspace programs be migrated to
userspace crypto code (which again, is what is normally used anyway) and
``CONFIG_CRYPTO_USER_API_*`` be disabled. On systems that use SELinux, SELinux
diff --git a/crypto/af_alg.c b/crypto/af_alg.c
index 8ccf7a737cd6ca9a5d5bf47050c9afea0dfd61bf..cce000e8590e469927b5a5a0ceccfdf0ef54633d 100644
--- a/crypto/af_alg.c
+++ b/crypto/af_alg.c
@@ -181,7 +181,7 @@ static int alg_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int add
if (IS_ERR(type))
return PTR_ERR(type);
- private = type->bind(sa->salg_name, sa->salg_feat, sa->salg_mask);
+ private = type->bind(sa->salg_name);
if (IS_ERR(private)) {
module_put(type->owner);
return PTR_ERR(private);
diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c
index 60f06597cb0b13036bc975641a0b02ea8a41ad03..787aac8aeb24eed128f08345ba730478113919b3 100644
--- a/crypto/algif_aead.c
+++ b/crypto/algif_aead.c
@@ -342,9 +342,9 @@ static struct proto_ops algif_aead_ops_nokey = {
.poll = af_alg_poll,
};
-static void *aead_bind(const char *name, u32 type, u32 mask)
+static void *aead_bind(const char *name)
{
- return crypto_alloc_aead(name, type, mask);
+ return crypto_alloc_aead(name, 0, AF_ALG_CRYPTOAPI_MASK);
}
static void aead_release(void *private)
diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c
index 4d3dfc60a16a6d8b677d903d209df18d67202c98..5452ad6c15069c3cb0ff78fe58868fe7ce4b0fc3 100644
--- a/crypto/algif_hash.c
+++ b/crypto/algif_hash.c
@@ -380,9 +380,9 @@ static struct proto_ops algif_hash_ops_nokey = {
.accept = hash_accept_nokey,
};
-static void *hash_bind(const char *name, u32 type, u32 mask)
+static void *hash_bind(const char *name)
{
- return crypto_alloc_ahash(name, type, mask);
+ return crypto_alloc_ahash(name, 0, AF_ALG_CRYPTOAPI_MASK);
}
static void hash_release(void *private)
diff --git a/crypto/algif_rng.c b/crypto/algif_rng.c
index a9fb492e929a70c94476f296f5f5e7c42f0313b7..4dfe7899f8fa4ce82d5f2236297230fb44bc35d6 100644
--- a/crypto/algif_rng.c
+++ b/crypto/algif_rng.c
@@ -197,7 +197,7 @@ static struct proto_ops __maybe_unused algif_rng_test_ops = {
.sendmsg = rng_test_sendmsg,
};
-static void *rng_bind(const char *name, u32 type, u32 mask)
+static void *rng_bind(const char *name)
{
struct rng_parent_ctx *pctx;
struct crypto_rng *rng;
@@ -206,7 +206,7 @@ static void *rng_bind(const char *name, u32 type, u32 mask)
if (!pctx)
return ERR_PTR(-ENOMEM);
- rng = crypto_alloc_rng(name, type, mask);
+ rng = crypto_alloc_rng(name, 0, AF_ALG_CRYPTOAPI_MASK);
if (IS_ERR(rng)) {
kfree(pctx);
return ERR_CAST(rng);
diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c
index 9dbccabd87b13920c27aff5a450a235cc6a27d59..df20bdfe1f1f4e453782dee3b743dd1939ab4c6c 100644
--- a/crypto/algif_skcipher.c
+++ b/crypto/algif_skcipher.c
@@ -307,9 +307,9 @@ static struct proto_ops algif_skcipher_ops_nokey = {
.poll = af_alg_poll,
};
-static void *skcipher_bind(const char *name, u32 type, u32 mask)
+static void *skcipher_bind(const char *name)
{
- return crypto_alloc_skcipher(name, type, mask);
+ return crypto_alloc_skcipher(name, 0, AF_ALG_CRYPTOAPI_MASK);
}
static void skcipher_release(void *private)
diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h
index 62867daca47d76c9ea1a7ed233188788c5f6c3c0..7643ba954125aba0c06aaf19de087985325885ad 100644
--- a/include/crypto/if_alg.h
+++ b/include/crypto/if_alg.h
@@ -41,7 +41,7 @@ struct af_alg_control {
};
struct af_alg_type {
- void *(*bind)(const char *name, u32 type, u32 mask);
+ void *(*bind)(const char *name);
void (*release)(void *private);
int (*setkey)(void *private, const u8 *key, unsigned int keylen);
int (*setentropy)(void *private, sockptr_t entropy, unsigned int len);
@@ -243,4 +243,16 @@ int af_alg_get_rsgl(struct sock *sk, struct msghdr *msg, int flags,
struct af_alg_async_req *areq, size_t maxsize,
size_t *outlen);
+/*
+ * Mask used to disable unsupported algorithm implementations.
+ *
+ * This is the same as FSCRYPT_CRYPTOAPI_MASK in fs/crypto/fscrypt_private.h.
+ * In additions to the motivations there, this API is exposed to userspace
+ * that might not be fully trusted.
+ */
+#define AF_ALG_CRYPTOAPI_MASK \
+ (CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY | \
+ CRYPTO_ALG_KERN_DRIVER_ONLY)
+
+
#endif /* _CRYPTO_IF_ALG_H */
--
2.54.0
^ permalink raw reply related
* [PATCH 3/3] AF_ALG: Document that it is *always* slower
From: Demi Marie Obenour via B4 Relay @ 2026-05-23 19:43 UTC (permalink / raw)
To: Herbert Xu, David S. Miller, Eric Dumazet, Kuniyuki Iwashima,
Paolo Abeni, Willem de Bruijn, Jens Axboe, Jakub Kicinski,
Simon Horman, Peter Zijlstra, Ingo Molnar,
Arnaldo Carvalho de Melo, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
James Clark, Jonathan Corbet, Shuah Khan, Eric Biggers,
Ard Biesheuvel
Cc: linux-crypto, linux-kernel, io-uring, netdev, linux-perf-users,
linux-doc, Demi Marie Obenour
In-Reply-To: <20260523-af-alg-harden-v1-0-c76755c3a5c5@gmail.com>
From: Demi Marie Obenour <demiobenour@gmail.com>
Without support for zero-copy or off-CPU offloads, AF_ALG is always
slower than software cryptography. Its only advantage is that it might
save code size. However, this is largely mitigated by lightweight
userspace cryptographic libraries.
Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
---
Documentation/crypto/userspace-if.rst | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/Documentation/crypto/userspace-if.rst b/Documentation/crypto/userspace-if.rst
index b31117d4415dda6ad6ca36275e615bec7df9552e..ab93300c8e04524469f284704c7c5ed582fdcbc0 100644
--- a/Documentation/crypto/userspace-if.rst
+++ b/Documentation/crypto/userspace-if.rst
@@ -28,8 +28,8 @@ functionality than that. It actually provides access to all software algorithms.
This includes arbitrary compositions of different algorithms created via a
complex template system, as well as algorithms that only make sense as internal
-implementation details of other algorithms. It also includes full zero-copy
-support, which is difficult for the kernel to implement securely.
+implementation details of other algorithms. In the past, it also included full
+zero-copy support, which was difficult for the kernel to implement securely.
Ultimately, these algorithms are just math computations. They use the same
instructions that userspace programs already have access to, just accessed in a
@@ -38,6 +38,21 @@ much more convoluted and less efficient way.
Indeed, userspace code is nearly always what is being used anyway. These same
algorithms are widely implemented in userspace crypto libraries.
+Even when zero-copy and off-CPU accelerators were supported, AF_ALG was usually
+much slower than optimized software cryptography in userspace. This was
+especially true for the small message sizes usually seen in performance-critical
+workloads. While it was possible to demonstrate performance wins for hashing
+large files on embedded devices, it is hard to imagine a situation where this
+would be performance-critical.
+
+Nowadays, AF_ALG no longer supports zero-copy or off-CPU accelerators.
+Therefore, it is *always* slower than an optimized userspace implementation,
+even for large messages. The only possible advantage left is that it avoids
+duplicating code between kernel and userspace. However, userspace
+implementations, especially hardware-accelerated ones, do not need to be large.
+Just because OpenSSL is huge does not mean that all userspace cryptography
+libraries are.
+
Meanwhile, AF_ALG hasn't been withstanding modern vulnerability discovery tools
such as syzbot and large language models. It receives a steady stream of CVEs.
Some of the examples include:
--
2.54.0
^ permalink raw reply related
* [PATCH 1/3] net: Remove support for AIO on sockets
From: Demi Marie Obenour via B4 Relay @ 2026-05-23 19:43 UTC (permalink / raw)
To: Herbert Xu, David S. Miller, Eric Dumazet, Kuniyuki Iwashima,
Paolo Abeni, Willem de Bruijn, Jens Axboe, Jakub Kicinski,
Simon Horman, Peter Zijlstra, Ingo Molnar,
Arnaldo Carvalho de Melo, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
James Clark, Jonathan Corbet, Shuah Khan, Eric Biggers,
Ard Biesheuvel
Cc: linux-crypto, linux-kernel, io-uring, netdev, linux-perf-users,
linux-doc, Demi Marie Obenour
In-Reply-To: <20260523-af-alg-harden-v1-0-c76755c3a5c5@gmail.com>
From: Demi Marie Obenour <demiobenour@gmail.com>
The only user of msg->msg_iocb was AF_ALG, but that's deprecated.
It can be removed entirely at the cost of only supporting synchronous
operations. This doesn't break userspace, which will silently block
(for a bounded amount of time) in io_submit instead of operating
asynchronously.
This also makes struct msghdr smaller, helping every other caller of
sendmsg().
Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
---
crypto/af_alg.c | 33 +-------------
crypto/algif_aead.c | 39 ++++------------
crypto/algif_skcipher.c | 62 +++++---------------------
include/crypto/if_alg.h | 5 +--
include/linux/socket.h | 1 -
io_uring/net.c | 1 -
net/compat.c | 1 -
net/socket.c | 7 +--
tools/perf/trace/beauty/include/linux/socket.h | 1 -
9 files changed, 25 insertions(+), 125 deletions(-)
diff --git a/crypto/af_alg.c b/crypto/af_alg.c
index 48c53f488e0fd30818e72439fe0c0d7e4cee1432..8ccf7a737cd6ca9a5d5bf47050c9afea0dfd61bf 100644
--- a/crypto/af_alg.c
+++ b/crypto/af_alg.c
@@ -1085,35 +1085,6 @@ void af_alg_free_resources(struct af_alg_async_req *areq)
}
EXPORT_SYMBOL_GPL(af_alg_free_resources);
-/**
- * af_alg_async_cb - AIO callback handler
- * @data: async request completion data
- * @err: if non-zero, error result to be returned via ki_complete();
- * otherwise return the AIO output length via ki_complete().
- *
- * This handler cleans up the struct af_alg_async_req upon completion of the
- * AIO operation.
- *
- * The number of bytes to be generated with the AIO operation must be set
- * in areq->outlen before the AIO callback handler is invoked.
- */
-void af_alg_async_cb(void *data, int err)
-{
- struct af_alg_async_req *areq = data;
- struct sock *sk = areq->sk;
- struct kiocb *iocb = areq->iocb;
- unsigned int resultlen;
-
- /* Buffer size written by crypto operation. */
- resultlen = areq->outlen;
-
- af_alg_free_resources(areq);
- sock_put(sk);
-
- iocb->ki_complete(iocb, err ? err : (int)resultlen);
-}
-EXPORT_SYMBOL_GPL(af_alg_async_cb);
-
/**
* af_alg_poll - poll system call handler
* @file: file pointer
@@ -1154,8 +1125,8 @@ struct af_alg_async_req *af_alg_alloc_areq(struct sock *sk,
struct af_alg_ctx *ctx = alg_sk(sk)->private;
struct af_alg_async_req *areq;
- /* Only one AIO request can be in flight. */
- if (ctx->inflight)
+ /* Only one request can be in flight. */
+ if (WARN_ON_ONCE(ctx->inflight))
return ERR_PTR(-EBUSY);
areq = sock_kmalloc(sk, areqlen, GFP_KERNEL);
diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c
index c6c2ce21895dd7df51dc825ed886ba7e1aa37130..60f06597cb0b13036bc975641a0b02ea8a41ad03 100644
--- a/crypto/algif_aead.c
+++ b/crypto/algif_aead.c
@@ -197,37 +197,14 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg,
aead_request_set_ad(&areq->cra_u.aead_req, ctx->aead_assoclen);
aead_request_set_tfm(&areq->cra_u.aead_req, tfm);
- if (msg->msg_iocb && !is_sync_kiocb(msg->msg_iocb)) {
- /* AIO operation */
- sock_hold(sk);
- areq->iocb = msg->msg_iocb;
-
- /* Remember output size that will be generated. */
- areq->outlen = outlen;
-
- aead_request_set_callback(&areq->cra_u.aead_req,
- CRYPTO_TFM_REQ_MAY_SLEEP,
- af_alg_async_cb, areq);
- err = ctx->enc ? crypto_aead_encrypt(&areq->cra_u.aead_req) :
- crypto_aead_decrypt(&areq->cra_u.aead_req);
-
- /* AIO operation in progress */
- if (err == -EINPROGRESS)
- return -EIOCBQUEUED;
-
- sock_put(sk);
- } else {
- /* Synchronous operation */
- aead_request_set_callback(&areq->cra_u.aead_req,
- CRYPTO_TFM_REQ_MAY_SLEEP |
- CRYPTO_TFM_REQ_MAY_BACKLOG,
- crypto_req_done, &ctx->wait);
- err = crypto_wait_req(ctx->enc ?
- crypto_aead_encrypt(&areq->cra_u.aead_req) :
- crypto_aead_decrypt(&areq->cra_u.aead_req),
- &ctx->wait);
- }
-
+ aead_request_set_callback(&areq->cra_u.aead_req,
+ CRYPTO_TFM_REQ_MAY_SLEEP |
+ CRYPTO_TFM_REQ_MAY_BACKLOG,
+ crypto_req_done, &ctx->wait);
+ err = crypto_wait_req(ctx->enc ?
+ crypto_aead_encrypt(&areq->cra_u.aead_req) :
+ crypto_aead_decrypt(&areq->cra_u.aead_req),
+ &ctx->wait);
free:
af_alg_free_resources(areq);
diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c
index ba0a17fd95aca22aa58ebf510c7d9b5f0cea2c2e..9dbccabd87b13920c27aff5a450a235cc6a27d59 100644
--- a/crypto/algif_skcipher.c
+++ b/crypto/algif_skcipher.c
@@ -79,20 +79,6 @@ static int algif_skcipher_export(struct sock *sk, struct skcipher_request *req)
return err;
}
-static void algif_skcipher_done(void *data, int err)
-{
- struct af_alg_async_req *areq = data;
- struct sock *sk = areq->sk;
-
- if (err)
- goto out;
-
- err = algif_skcipher_export(sk, &areq->cra_u.skcipher_req);
-
-out:
- af_alg_async_cb(data, err);
-}
-
static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg,
size_t ignored, int flags)
{
@@ -171,43 +157,19 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg,
cflags |= CRYPTO_SKCIPHER_REQ_CONT;
}
- if (msg->msg_iocb && !is_sync_kiocb(msg->msg_iocb)) {
- /* AIO operation */
- sock_hold(sk);
- areq->iocb = msg->msg_iocb;
+ skcipher_request_set_callback(&areq->cra_u.skcipher_req,
+ cflags |
+ CRYPTO_TFM_REQ_MAY_SLEEP |
+ CRYPTO_TFM_REQ_MAY_BACKLOG,
+ crypto_req_done, &ctx->wait);
+ err = crypto_wait_req(ctx->enc ?
+ crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) :
+ crypto_skcipher_decrypt(&areq->cra_u.skcipher_req),
+ &ctx->wait);
- /* Remember output size that will be generated. */
- areq->outlen = len;
-
- skcipher_request_set_callback(&areq->cra_u.skcipher_req,
- cflags |
- CRYPTO_TFM_REQ_MAY_SLEEP,
- algif_skcipher_done, areq);
- err = ctx->enc ?
- crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) :
- crypto_skcipher_decrypt(&areq->cra_u.skcipher_req);
-
- /* AIO operation in progress */
- if (err == -EINPROGRESS)
- return -EIOCBQUEUED;
-
- sock_put(sk);
- } else {
- /* Synchronous operation */
- skcipher_request_set_callback(&areq->cra_u.skcipher_req,
- cflags |
- CRYPTO_TFM_REQ_MAY_SLEEP |
- CRYPTO_TFM_REQ_MAY_BACKLOG,
- crypto_req_done, &ctx->wait);
- err = crypto_wait_req(ctx->enc ?
- crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) :
- crypto_skcipher_decrypt(&areq->cra_u.skcipher_req),
- &ctx->wait);
-
- if (!err)
- err = algif_skcipher_export(
- sk, &areq->cra_u.skcipher_req);
- }
+ if (!err)
+ err = algif_skcipher_export(
+ sk, &areq->cra_u.skcipher_req);
free:
af_alg_free_resources(areq);
diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h
index 0cc8fa749f68d2356789f72771c9e550b79e0b3d..62867daca47d76c9ea1a7ed233188788c5f6c3c0 100644
--- a/include/crypto/if_alg.h
+++ b/include/crypto/if_alg.h
@@ -80,7 +80,6 @@ struct af_alg_rsgl {
/**
* struct af_alg_async_req - definition of crypto request
- * @iocb: IOCB for AIO operations
* @sk: Socket the request is associated with
* @first_rsgl: First RX SG
* @last_rsgl: Pointer to last RX SG
@@ -92,7 +91,6 @@ struct af_alg_rsgl {
* @cra_u: Cipher request
*/
struct af_alg_async_req {
- struct kiocb *iocb;
struct sock *sk;
struct af_alg_rsgl first_rsgl;
@@ -138,7 +136,7 @@ struct af_alg_async_req {
* @write: True if we are in the middle of a write.
* @init: True if metadata has been sent.
* @len: Length of memory allocated for this data structure.
- * @inflight: Non-zero when AIO requests are in flight.
+ * @inflight: Non-zero when requests are in flight, for debugging only.
*/
struct af_alg_ctx {
struct list_head tsgl_list;
@@ -237,7 +235,6 @@ int af_alg_wait_for_data(struct sock *sk, unsigned flags, unsigned min);
int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size,
unsigned int ivsize);
void af_alg_free_resources(struct af_alg_async_req *areq);
-void af_alg_async_cb(void *data, int err);
__poll_t af_alg_poll(struct file *file, struct socket *sock,
poll_table *wait);
struct af_alg_async_req *af_alg_alloc_areq(struct sock *sk,
diff --git a/include/linux/socket.h b/include/linux/socket.h
index ec4a0a0257939a5363c55bed3ccb20182965b2e3..3ffdfe184b23d0a739e095407e956885d116c299 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -89,7 +89,6 @@ struct msghdr {
bool msg_get_inq : 1;/* return INQ after receive */
unsigned int msg_flags; /* flags on received message */
__kernel_size_t msg_controllen; /* ancillary data buffer length */
- struct kiocb *msg_iocb; /* ptr to iocb for async requests */
struct ubuf_info *msg_ubuf;
int (*sg_from_iter)(struct sk_buff *skb,
struct iov_iter *from, size_t length);
diff --git a/io_uring/net.c b/io_uring/net.c
index 30cd22c0b934b97ce6e265756b24daca7d398361..22100933966af547dfe6a52e69fc6882b4197234 100644
--- a/io_uring/net.c
+++ b/io_uring/net.c
@@ -771,7 +771,6 @@ static int io_recvmsg_prep_setup(struct io_kiocb *req)
kmsg->msg.msg_control = NULL;
kmsg->msg.msg_get_inq = 1;
kmsg->msg.msg_controllen = 0;
- kmsg->msg.msg_iocb = NULL;
kmsg->msg.msg_ubuf = NULL;
if (req->flags & REQ_F_BUFFER_SELECT)
diff --git a/net/compat.c b/net/compat.c
index 2c9bd0edac997bc8c6ebd1bc8b92d8437ff32ea4..d68cf9c3aad5f7f1de84edbfffcf99d71e89292a 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -75,7 +75,6 @@ int __get_compat_msghdr(struct msghdr *kmsg,
if (msg->msg_iovlen > UIO_MAXIOV)
return -EMSGSIZE;
- kmsg->msg_iocb = NULL;
kmsg->msg_ubuf = NULL;
return 0;
}
diff --git a/net/socket.c b/net/socket.c
index 22a412fdec079cf8fd829a15236de9daea09d2f2..9785363858cef0c4e6f0efc45b17c3d2add5a53c 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1213,8 +1213,7 @@ static ssize_t sock_read_iter(struct kiocb *iocb, struct iov_iter *to)
{
struct file *file = iocb->ki_filp;
struct socket *sock = file->private_data;
- struct msghdr msg = {.msg_iter = *to,
- .msg_iocb = iocb};
+ struct msghdr msg = {.msg_iter = *to};
ssize_t res;
if (file->f_flags & O_NONBLOCK || (iocb->ki_flags & IOCB_NOWAIT))
@@ -1235,8 +1234,7 @@ static ssize_t sock_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
struct file *file = iocb->ki_filp;
struct socket *sock = file->private_data;
- struct msghdr msg = {.msg_iter = *from,
- .msg_iocb = iocb};
+ struct msghdr msg = {.msg_iter = *from};
ssize_t res;
if (iocb->ki_pos != 0)
@@ -2612,7 +2610,6 @@ int __copy_msghdr(struct msghdr *kmsg,
if (msg->msg_iovlen > UIO_MAXIOV)
return -EMSGSIZE;
- kmsg->msg_iocb = NULL;
kmsg->msg_ubuf = NULL;
return 0;
}
diff --git a/tools/perf/trace/beauty/include/linux/socket.h b/tools/perf/trace/beauty/include/linux/socket.h
index ec715ad4bf25f5f759d2cab3c6b796fed84df932..2a0a50fd66f41589f2699f7288a143873ce1bba6 100644
--- a/tools/perf/trace/beauty/include/linux/socket.h
+++ b/tools/perf/trace/beauty/include/linux/socket.h
@@ -89,7 +89,6 @@ struct msghdr {
bool msg_get_inq : 1;/* return INQ after receive */
unsigned int msg_flags; /* flags on received message */
__kernel_size_t msg_controllen; /* ancillary data buffer length */
- struct kiocb *msg_iocb; /* ptr to iocb for async requests */
struct ubuf_info *msg_ubuf;
int (*sg_from_iter)(struct sk_buff *skb,
struct iov_iter *from, size_t length);
--
2.54.0
^ permalink raw reply related
* Re: [PATCH v5 00/21] nfsd: add support for CB_NOTIFY callbacks in directory delegations
From: Chuck Lever @ 2026-05-23 17:00 UTC (permalink / raw)
To: NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey,
Trond Myklebust, Anna Schumaker, Jonathan Corbet, Shuah Khan,
Jeff Layton
Cc: Chuck Lever, Steven Rostedt, Alexander Aring, Amir Goldstein,
Jan Kara, Alexander Viro, Christian Brauner, Calum Mackay,
linux-kernel, linux-doc, linux-nfs
In-Reply-To: <20260522-dir-deleg-v5-0-542cddfad576@kernel.org>
From: Chuck Lever <chuck.lever@oracle.com>
On Fri, 22 May 2026 15:42:05 -0400, Jeff Layton wrote:
> This patchset builds on the directory delegation work we did a few
> months ago, to add support for CB_NOTIFY callbacks for some events. In
> particular, creates, unlinks and renames. The server also sends updated
> directory attributes in the notifications. With this support, the client
> can register interest in a directory and get notifications about changes
> within it without losing its lease.
>
> [...]
Applied to nfsd-testing, thanks!
[01/21] nfsd: check fl_lmops in nfsd_breaker_owns_lease()
commit: 106d7871db32223d589617d9be914ff2ba51727a
[02/21] nfsd: add protocol support for CB_NOTIFY
commit: 06688aedf70b8da555a5c1d9f7feb786eb329eb4
[03/21] nfs_common: add new NOTIFY4_* flags proposed in RFC8881bis
commit: 1bdad6b6988d15ae56c97a94802cb2a603492a30
[04/21] nfsd: allow nfsd to get a dir lease with an ignore mask
commit: 6d767c6080b49d8c3d0a4971d5c30d0ad9345622
[05/21] nfsd: update the fsnotify mark when setting or removing a dir delegation
commit: b8d98337e97ca91b057abf2374dbd2a846663f68
[06/21] nfsd: make nfsd4_callback_ops->prepare operation bool return
commit: 35b3e3c47909fba5ad04349fb6ba3287c2c70d81
[07/21] nfsd: add callback encoding and decoding linkages for CB_NOTIFY
commit: 920a750c30c51ac7a884fbe93e9dc42b2ba37992
[08/21] nfsd: use RCU to protect fi_deleg_file
commit: 1b21b493326b3a782c7f0ede6d8cd47b9af662d1
[09/21] nfsd: add data structures for handling CB_NOTIFY
commit: c1810ecdb4e5c9205a6c88c86cf61689115d696f
[10/21] nfsd: add notification handlers for dir events
commit: e38c39f77041388190ebdcde9230371c180769a0
[11/21] nfsd: add tracepoint to dir_event handler
commit: cc1687d186b0542390badca86c6a87e17c95b378
[12/21] nfsd: apply the notify mask to the delegation when requested
commit: 552de5c66f1cd234bff61b5afc802cbb58928e36
[13/21] nfsd: add helper to marshal a fattr4 from completed args
commit: c452947ca425c5e5bb21382f58db015df37bb007
[14/21] nfsd: allow nfsd4_encode_fattr4_change() to work with no export
commit: ae845b96ebda28672ae1ea1ade51954cea62c2c8
[15/21] nfsd: send basic file attributes in CB_NOTIFY
commit: 259bcf6151f873f5476412140fd423a96dca7302
[16/21] nfsd: allow encoding a filehandle into fattr4 without a svc_fh
commit: 772fb85f866cb7e90a1603052416122ccdd48403
[17/21] nfsd: add a fi_connectable flag to struct nfs4_file
commit: 465b30cd8c24b04f2dcdf1e644ecae87cf847e8b
[18/21] nfsd: add the filehandle to returned attributes in CB_NOTIFY
commit: b146f3a075b320e76fccecc0dcebef7cd894364f
[19/21] nfsd: properly track requested child attributes
commit: 8a5ceb0668d694dd8370ee1d702800e730c862b7
[20/21] nfsd: track requested dir attributes
commit: 824c7f03f1fbeea6f92d0f4da7dca3ecad27cc3a
[21/21] nfsd: add support to CB_NOTIFY for dir attribute changes
commit: 9e0982d08e135a46aab2bd6d7fe8609c27a8806e
--
Chuck Lever <chuck.lever@oracle.com>
^ permalink raw reply
* Re: DEPT (the dependency tracker) as AI review prompt?
From: Yunseong Kim @ 2026-05-23 15:04 UTC (permalink / raw)
To: Harry Yoo, Yunseong Kim
Cc: Byungchul Park, linux-kernel, kernel_team, torvalds,
damien.lemoal, linux-ide, adilger.kernel, linux-ext4, mingo,
peterz, will, tglx, rostedt, joel, sashal, daniel.vetter,
duyuyang, johannes.berg, tj, tytso, willy, david, amir73il,
gregkh, kernel-team, linux-mm, akpm, mhocko, minchan, hannes,
vdavydov.dev, sj, jglisse, dennis, cl, penberg, rientjes, vbabka,
ngupta, linux-block, linux-fsdevel, jack, jlayton, dan.j.williams,
hch, djwong, dri-devel, rodrigosiqueiramelo, melissa.srw,
hamohammed.sa, harry.yoo, chris.p.wilson, gwan-gyeong.mun,
max.byungchul.park, boqun.feng, longman, yunseong.kim,
yeoreum.yun, netdev, matthew.brost, her0gyugyu, corbet,
catalin.marinas, bp, x86, hpa, luto, sumit.semwal, gustavo,
christian.koenig, andi.shyti, arnd, lorenzo.stoakes, Liam.Howlett,
rppt, surenb, mcgrof, petr.pavlu, da.gomez, samitolvanen, paulmck,
frederic, neeraj.upadhyay, joelagnelf, josh, urezki,
mathieu.desnoyers, jiangshanlai, qiang.zhang, juri.lelli,
vincent.guittot, dietmar.eggemann, bsegall, mgorman, vschneid,
chuck.lever, neil, okorniev, Dai.Ngo, tom, trondmy, anna, kees,
bigeasy, clrkwllms, mark.rutland, ada.coupriediaz,
kristina.martsenko, wangkefeng.wang, broonie, kevin.brodsky, dwmw,
shakeel.butt, ast, ziy, yuzhao, baolin.wang, usamaarif642,
joel.granados, richard.weiyang, geert+renesas, tim.c.chen, linux,
alexander.shishkin, lillian, chenhuacai, francesco,
guoweikang.kernel, link, jpoimboe, masahiroy, brauner,
thomas.weissschuh, oleg, mjguzik, andrii, wangfushuai, linux-doc,
linux-arm-kernel, linux-media, linaro-mm-sig, linux-i2c,
linux-arch, linux-modules, rcu, linux-nfs, linux-rt-devel,
2407018371, dakr, miguel.ojeda.sandonis, neilb, bagasdotme,
wsa+renesas, dave.hansen, geert, ojeda, alex.gaynor, gary,
bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross, rust-for-linux,
Chris Mason, Roman Gushchin, Josef Bacik
In-Reply-To: <0592b09b-a084-4d9d-bcbf-1b77e45226cf@kernel.org>
Hi Harry,
On 5/23/26 16:34, Harry Yoo wrote:
>
>
> On 5/23/26 11:00 PM, Yunseong Kim wrote:
>> I've previously experimented with running DEPT alongside syzkaller fuzzing,
>> and many hung tasks missed by lockdep are caught by DEPT, but the resulting
>> high volume of reports makes it easy for issues to get lost in the massive
>> log output. Sorting through that output manually is a huge bottleneck, so
>> leveraging a well-crafted AI prompt to triage the warnings and filter out
>> the false positives would be incredibly valuable.
>
> I mean both 1) detection of deadlock issues AND 2) false positive elimination with AI.
I completely agree. Implanting DEPT's model into an AI review prompt
is a great idea. As you suggested, the patterns we develop for the AI
could provide valuable feedback to enhance DEPT's itself.
> If the review prompt is only used to eliminate DEPT's false positives, I think that would be quite hard to get broad use.
>
> Someone would have to build out-of-tree DEPT, collect the reports, and then feed those back into the AI. I don't think building that kind of pipeline would actually work well in practice.
I also have a huge dept report of DEPT reports, and manually
reviewing all of them is makes me sigh. The constant kernel rebuilds
required for lockup testing every time are also quite expensive.
Thanks for the summary!
Best Regards,
Yunseong
^ permalink raw reply
* Re: DEPT (the dependency tracker) as AI review prompt?
From: Harry Yoo @ 2026-05-23 14:34 UTC (permalink / raw)
To: Yunseong Kim
Cc: Byungchul Park, linux-kernel, kernel_team, torvalds,
damien.lemoal, linux-ide, adilger.kernel, linux-ext4, mingo,
peterz, will, tglx, rostedt, joel, sashal, daniel.vetter,
duyuyang, johannes.berg, tj, tytso, willy, david, amir73il,
gregkh, kernel-team, linux-mm, akpm, mhocko, minchan, hannes,
vdavydov.dev, sj, jglisse, dennis, cl, penberg, rientjes, vbabka,
ngupta, linux-block, linux-fsdevel, jack, jlayton, dan.j.williams,
hch, djwong, dri-devel, rodrigosiqueiramelo, melissa.srw,
hamohammed.sa, harry.yoo, chris.p.wilson, gwan-gyeong.mun,
max.byungchul.park, boqun.feng, longman, yunseong.kim,
yeoreum.yun, netdev, matthew.brost, her0gyugyu, corbet,
catalin.marinas, bp, x86, hpa, luto, sumit.semwal, gustavo,
christian.koenig, andi.shyti, arnd, lorenzo.stoakes, Liam.Howlett,
rppt, surenb, mcgrof, petr.pavlu, da.gomez, samitolvanen, paulmck,
frederic, neeraj.upadhyay, joelagnelf, josh, urezki,
mathieu.desnoyers, jiangshanlai, qiang.zhang, juri.lelli,
vincent.guittot, dietmar.eggemann, bsegall, mgorman, vschneid,
chuck.lever, neil, okorniev, Dai.Ngo, tom, trondmy, anna, kees,
bigeasy, clrkwllms, mark.rutland, ada.coupriediaz,
kristina.martsenko, wangkefeng.wang, broonie, kevin.brodsky, dwmw,
shakeel.butt, ast, ziy, yuzhao, baolin.wang, usamaarif642,
joel.granados, richard.weiyang, geert+renesas, tim.c.chen, linux,
alexander.shishkin, lillian, chenhuacai, francesco,
guoweikang.kernel, link, jpoimboe, masahiroy, brauner,
thomas.weissschuh, oleg, mjguzik, andrii, wangfushuai, linux-doc,
linux-arm-kernel, linux-media, linaro-mm-sig, linux-i2c,
linux-arch, linux-modules, rcu, linux-nfs, linux-rt-devel,
2407018371, dakr, miguel.ojeda.sandonis, neilb, bagasdotme,
wsa+renesas, dave.hansen, geert, ojeda, alex.gaynor, gary,
bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross, rust-for-linux,
Chris Mason, Roman Gushchin, Josef Bacik, Yunseong Kim
In-Reply-To: <CA+7O06GxeDLR9RcKDN2i-Rgc4kgzz6BfF4b0XAH4tFx=A723Nw@mail.gmail.com>
On 5/23/26 11:00 PM, Yunseong Kim wrote:
> I've previously experimented with running DEPT alongside syzkaller fuzzing,
> and many hung tasks missed by lockdep are caught by DEPT, but the resulting
> high volume of reports makes it easy for issues to get lost in the massive
> log output. Sorting through that output manually is a huge bottleneck, so
> leveraging a well-crafted AI prompt to triage the warnings and filter out
> the false positives would be incredibly valuable.
I mean both 1) detection of deadlock issues AND 2) false positive
elimination with AI.
If the review prompt is only used to eliminate DEPT's false positives, I
think that would be quite hard to get broad use.
Someone would have to build out-of-tree DEPT, collect the reports, and
then feed those back into the AI. I don't think building that kind of
pipeline would actually work well in practice.
--
Cheers,
Harry / Hyeonggon
^ permalink raw reply
* Re: [PATCH 4/5] mm: enable map_anon_folio_pmd_nopf to handle unshare
From: kernel test robot @ 2026-05-23 14:25 UTC (permalink / raw)
To: Luka Bai, Luka Bai
Cc: oe-lkp, lkp, linux-mm, Jonathan Corbet, Shuah Khan, Andrew Morton,
David Hildenbrand, Lorenzo Stoakes, Zi Yan, Baolin Wang,
Liam R. Howlett, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan,
Michal Hocko, Jann Horn, Arnd Bergmann, Kairui Song, linux-kernel,
linux-arch, linux-doc, Luka Bai, oliver.sang
In-Reply-To: <20260501-thp_cow-v1-4-005377483738@tencent.com>
Hello,
kernel test robot noticed "BUG:kernel_NULL_pointer_dereference,address" on:
commit: 419ac88f7d747a174b48e12d2fd2178a128f54de ("[PATCH 4/5] mm: enable map_anon_folio_pmd_nopf to handle unshare")
url: https://github.com/intel-lab-lkp/linux/commits/Luka-Bai/mm-add-basic-madvise-helpers-and-branch-for-THP-setup/20260502-230731
patch link: https://lore.kernel.org/all/20260501-thp_cow-v1-4-005377483738@tencent.com/
patch subject: [PATCH 4/5] mm: enable map_anon_folio_pmd_nopf to handle unshare
in testcase: boot
config: x86_64-kexec
compiler: clang-20
test machine: qemu-system-x86_64 -enable-kvm -cpu SandyBridge -smp 2 -m 32G
(please refer to attached dmesg/kmsg for entire log/backtrace)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <oliver.sang@intel.com>
| Closes: https://lore.kernel.org/oe-lkp/202605231645.88096ca9-lkp@intel.com
[ 15.354503][ T37] BUG: kernel NULL pointer dereference, address: 0000000000000000
[ 15.355458][ T37] #PF: supervisor write access in kernel mode
[ 15.356077][ T37] #PF: error_code(0x0002) - not-present page
[ 15.356690][ T37] PGD 0 P4D 0
[ 15.357088][ T37] Oops: Oops: 0002 [#1] SMP PTI
[ 15.357612][ T37] CPU: 0 UID: 0 PID: 37 Comm: khugepaged Not tainted 7.1.0-rc1-00099-g419ac88f7d74 #1 PREEMPT(lazy)
[ 15.358688][ T37] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[ 15.362222][ T37] RIP: 0010:map_anon_folio_pmd_nopf (x86/include/asm/pgtable_64.h:79 x86/include/asm/pgtable.h:1210 huge_memory.c:1448)
[ 15.364849][ T37] Code: e0 ff 48 89 df 4c 89 f6 4c 89 c2 b9 01 00 00 00 e8 b7 a2 fa ff 48 89 df 4c 89 f6 e8 6c 93 f4 ff 4c 89 64 24 20 48 8b 44 24 20 <49> 89 07 48 89 df 31 f6 48 83 c4 28 5b 41 5c 41 5d 41 5e 41 5f 5d
All code
========
0: e0 ff loopne 0x1
2: 48 89 df mov %rbx,%rdi
5: 4c 89 f6 mov %r14,%rsi
8: 4c 89 c2 mov %r8,%rdx
b: b9 01 00 00 00 mov $0x1,%ecx
10: e8 b7 a2 fa ff call 0xfffffffffffaa2cc
15: 48 89 df mov %rbx,%rdi
18: 4c 89 f6 mov %r14,%rsi
1b: e8 6c 93 f4 ff call 0xfffffffffff4938c
20: 4c 89 64 24 20 mov %r12,0x20(%rsp)
25: 48 8b 44 24 20 mov 0x20(%rsp),%rax
2a:* 49 89 07 mov %rax,(%r15) <-- trapping instruction
2d: 48 89 df mov %rbx,%rdi
30: 31 f6 xor %esi,%esi
32: 48 83 c4 28 add $0x28,%rsp
36: 5b pop %rbx
37: 41 5c pop %r12
39: 41 5d pop %r13
3b: 41 5e pop %r14
3d: 41 5f pop %r15
3f: 5d pop %rbp
Code starting with the faulting instruction
===========================================
0: 49 89 07 mov %rax,(%r15)
3: 48 89 df mov %rbx,%rdi
6: 31 f6 xor %esi,%esi
8: 48 83 c4 28 add $0x28,%rsp
c: 5b pop %rbx
d: 41 5c pop %r12
f: 41 5d pop %r13
11: 41 5e pop %r14
13: 41 5f pop %r15
15: 5d pop %rbp
[ 15.372240][ T37] RSP: 0000:ffffc9000013fb70 EFLAGS: 00010282
[ 15.374712][ T37] RAX: 8000000143a000e7 RBX: ffffea00050e8000 RCX: 0000000000000000
[ 15.377932][ T37] RDX: 000000000000021f RSI: ffff88881fc271b0 RDI: ffff88881fc30640
[ 15.381250][ T37] RBP: 0000000000000000 R08: 0000000000071ce9 R09: 000000000000b2e9
[ 15.384563][ T37] R10: 0000000000000001 R11: 000000000000003f R12: 8000000143a000e7
[ 15.387726][ T37] R13: 8000000000000025 R14: ffff88810e098900 R15: 0000000000000000
[ 15.391175][ T37] FS: 0000000000000000(0000) GS:ffff88889c101000(0000) knlGS:0000000000000000
[ 15.394883][ T37] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 15.397492][ T37] CR2: 0000000000000000 CR3: 0000000163644000 CR4: 00000000000406f0
[ 15.400508][ T37] Call Trace:
[ 15.403414][ T37] <TASK>
[ 15.404723][ T37] ? lruvec_stat_mod_folio (memcontrol.c:993)
[ 15.406687][ T37] collapse_single_pmd (khugepaged.c:1411)
[ 15.408449][ T37] ? __pfx_wq_barrier_func (workqueue.c:1144)
[ 15.410197][ T37] ? __thp_vma_allowable_orders (huge_memory.c:124)
[ 15.412115][ T37] khugepaged (khugepaged.c:2901)
[ 15.413596][ T37] ? __pfx_khugepaged (khugepaged.c:3113)
[ 15.415388][ T37] kthread (kthread.c:436)
[ 15.416719][ T37] ? __pfx_kthread (kthread.c:1738)
[ 15.418155][ T37] ret_from_fork (x86/kernel/process.c:158)
[ 15.419600][ T37] ? __pfx_kthread (kthread.c:1738)
[ 15.421001][ T37] ret_from_fork_asm (x86/entry/entry_64.S:245)
[ 15.422510][ T37] </TASK>
[ 15.423538][ T37] Modules linked in: sr_mod cdrom sg ata_generic fuse
[ 15.425454][ T37] CR2: 0000000000000000
[ 15.426674][ T37] ---[ end trace 0000000000000000 ]---
[ 15.428142][ T37] RIP: 0010:map_anon_folio_pmd_nopf (x86/include/asm/pgtable_64.h:79 x86/include/asm/pgtable.h:1210 huge_memory.c:1448)
[ 15.429793][ T37] Code: e0 ff 48 89 df 4c 89 f6 4c 89 c2 b9 01 00 00 00 e8 b7 a2 fa ff 48 89 df 4c 89 f6 e8 6c 93 f4 ff 4c 89 64 24 20 48 8b 44 24 20 <49> 89 07 48 89 df 31 f6 48 83 c4 28 5b 41 5c 41 5d 41 5e 41 5f 5d
All code
========
0: e0 ff loopne 0x1
2: 48 89 df mov %rbx,%rdi
5: 4c 89 f6 mov %r14,%rsi
8: 4c 89 c2 mov %r8,%rdx
b: b9 01 00 00 00 mov $0x1,%ecx
10: e8 b7 a2 fa ff call 0xfffffffffffaa2cc
15: 48 89 df mov %rbx,%rdi
18: 4c 89 f6 mov %r14,%rsi
1b: e8 6c 93 f4 ff call 0xfffffffffff4938c
20: 4c 89 64 24 20 mov %r12,0x20(%rsp)
25: 48 8b 44 24 20 mov 0x20(%rsp),%rax
2a:* 49 89 07 mov %rax,(%r15) <-- trapping instruction
2d: 48 89 df mov %rbx,%rdi
30: 31 f6 xor %esi,%esi
32: 48 83 c4 28 add $0x28,%rsp
36: 5b pop %rbx
37: 41 5c pop %r12
39: 41 5d pop %r13
3b: 41 5e pop %r14
3d: 41 5f pop %r15
3f: 5d pop %rbp
Code starting with the faulting instruction
===========================================
0: 49 89 07 mov %rax,(%r15)
3: 48 89 df mov %rbx,%rdi
6: 31 f6 xor %esi,%esi
8: 48 83 c4 28 add $0x28,%rsp
c: 5b pop %rbx
d: 41 5c pop %r12
f: 41 5d pop %r13
11: 41 5e pop %r14
13: 41 5f pop %r15
15: 5d pop %rbp
The kernel config and materials to reproduce are available at:
https://download.01.org/0day-ci/archive/20260523/202605231645.88096ca9-lkp@intel.com
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH v4 2/4] hwmon: (pmbus/tps25990): Rework TPS25990 direct conversion handling
From: Guenter Roeck @ 2026-05-23 14:17 UTC (permalink / raw)
To: Stoyan Bogdanov, jbrunet, robh, krzk+dt, conor+dt, corbet, skhan
Cc: linux-hwmon, devicetree, linux-doc, linux-kernel
In-Reply-To: <20260522082349.2749970-3-sbogdanov@baylibre.com>
On 5/22/26 01:23, Stoyan Bogdanov wrote:
> Rework the existing implementation of direct format conversion for
> TPS25990 non-standard parameters to improve code reusability and
> integration with the PMBus direct conversion helpers.
>
> Changes include:
> - Add an enum describing the supported parameters
> - Add structure to hold m, b, R per-device coefficients
> - Add data structures for pmbus_driver_info and local direct values
> - Use the generic PMBus conversion helpers:
> pmbus_reg2data_direct_calc()
> pmbus_data2reg_direct_calc()
> - Replace previously used defines with structured data
>
> This reduces duplicated conversion logic and makes handling of
> non-standard parameters more maintainable.
>
> Signed-off-by: Stoyan Bogdanov <sbogdanov@baylibre.com>
> ---
> drivers/hwmon/pmbus/tps25990.c | 197 +++++++++++++++++++++------------
> 1 file changed, 127 insertions(+), 70 deletions(-)
>
> diff --git a/drivers/hwmon/pmbus/tps25990.c b/drivers/hwmon/pmbus/tps25990.c
> index 05c6288ecafc..1e252844217b 100644
> --- a/drivers/hwmon/pmbus/tps25990.c
> +++ b/drivers/hwmon/pmbus/tps25990.c
> @@ -36,17 +36,63 @@
> #define TPS25990_UNLOCKED BIT(7)
>
> #define TPS25990_8B_SHIFT 2
> -#define TPS25990_VIN_OVF_NUM 525100
> -#define TPS25990_VIN_OVF_DIV 10163
> -#define TPS25990_VIN_OVF_OFF 155
> -#define TPS25990_IIN_OCF_NUM 953800
> -#define TPS25990_IIN_OCF_DIV 129278
> -#define TPS25990_IIN_OCF_OFF 157
>
> #define PK_MIN_AVG_RST_MASK (PK_MIN_AVG_RST_PEAK | \
> PK_MIN_AVG_RST_AVG | \
> PK_MIN_AVG_RST_MIN)
>
> +enum chips {
> + tps25990,
> +};
> +
> +enum tps25990_parameters {
> + TPS25990_VIN_OVF = 0, /* VIN over volatage fault */
> + TPS25990_IIN_OCF, /* IIN Over currect fault */
> + TPS25990_DIRECT_VALUES_COUNT,
> +};
> +
> +struct tps25990_local_direct_value {
> + int m[TPS25990_DIRECT_VALUES_COUNT]; /* mantissa */
> + int b[TPS25990_DIRECT_VALUES_COUNT]; /* offset */
> + int R[TPS25990_DIRECT_VALUES_COUNT]; /* exponent */
> +};
> +
> +struct tps25990_data {
> + struct pmbus_driver_info info;
> + struct tps25990_local_direct_value info_local;
> +};
> +
> +static s64 tps25990_reg2data_direct(struct i2c_client *client, int param, s32 raw)
> +{
> + struct pmbus_driver_info *info = i2c_get_clientdata(client);
> + struct tps25990_data *data = container_of(info, struct tps25990_data, info);
> + struct tps25990_local_direct_value *info_local = &data->info_local;
> + s64 b, val;
> + s32 m, R;
> +
> + val = (s16)raw;
> + m = info_local->m[param];
> + b = info_local->b[param];
> + R = info_local->R[param];
> +
> + return pmbus_reg2data_direct_calc(val, b, m, R);
> +}
> +
> +static u16 tps25990_data2reg_direct(struct i2c_client *client, int param, s64 val)
> +{
> + struct pmbus_driver_info *info = i2c_get_clientdata(client);
> + struct tps25990_data *data = container_of(info, struct tps25990_data, info);
> + struct tps25990_local_direct_value *info_local = &data->info_local;
> + s32 m, R;
> + s64 b;
> +
> + m = info_local->m[param];
> + b = info_local->b[param];
> + R = info_local->R[param];
> +
> + return pmbus_data2reg_direct_calc(val, b, m, R);
> +}
> +
> /*
> * Arbitrary default Rimon value: 1kOhm
> * This correspond to an overcurrent limit of 55A, close to the specified limit
> @@ -184,9 +230,7 @@ static int tps25990_read_word_data(struct i2c_client *client,
> ret = pmbus_read_word_data(client, page, phase, reg);
> if (ret < 0)
> break;
> - ret = DIV_ROUND_CLOSEST(ret * TPS25990_VIN_OVF_NUM,
> - TPS25990_VIN_OVF_DIV);
> - ret += TPS25990_VIN_OVF_OFF;
> + ret = tps25990_reg2data_direct(client, TPS25990_VIN_OVF, ret);
The result is again evaluated by the PMBus core as direct register value,
not as calculated fault limit. I don't think this works as expected.
This isn't about converting a register value to a voltage, it is about
converting one direct format into another. Using (or trying to use)
reg2data_direct is at the very least misleading, if not completely wrong.
The m/b/R parameters below are the coefficients from the datasheet to convert
the register values into voltages. The PMBus core will take that value and
convert it again into a voltage, this time using the m/b/R coefficients
for input voltages. This can not be correct. To be technically correct,
the core would have to convert the register value to a voltage using one
set of m/b/R coefficients and then convert it back to direct format using
the other set of m/b/R coefficients. The current code does that by adjusting
the values directly. I don't think changing is really beneficial. If anything,
documenting it would be more helpful.
Thanks,
Guenter
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox