linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 1/2] drm/connector: Add "pixel_encoding" to switch between RGB & YUV color output modes
       [not found] <20250825184001.6524-1-wiagn233@outlook.com>
@ 2025-08-25 18:40 ` Shengyu Qu
  2025-08-25 18:40 ` [PATCH v2 2/2] drm/amdgpu: Add "pixel_encoding" DRM connector property support for amdgpu Shengyu Qu
  1 sibling, 0 replies; 2+ messages in thread
From: Shengyu Qu @ 2025-08-25 18:40 UTC (permalink / raw)
  To: alexander.deucher, christian.koenig, airlied, simona,
	harry.wentland, sunpeng.li, siqueira, maarten.lankhorst, mripard,
	tzimmermann, contact, lijo.lazar, jesse.zhang, tim.huang,
	dark_sylinc, mario.limonciello, alex.hung, aurabindo.pillai,
	sunil.khatri, chiahsuan.chung, mwen, Roman.Li, Wayne.Lin,
	dominik.kaszewski, alvin.lee2, Aric.Cyr, Austin.Zheng, Sung.Lee,
	PeiChen.Huang, dillon.varone, Richard.Chiang, ryanseto, linux,
	haoping.liu, Relja.Vojvodic, Yihan.Zhu, Samson.Tam, amd-gfx,
	dri-devel, linux-kernel, wayland-devel
  Cc: Shengyu Qu

This patch adds "pixel_encoding" connector property, which allows user to
switch to different pixel encodings. This is useful and could solve some
problems that auto switch would do something wrong(Basically because of
wrong EDID info).

Supported encodings are: "auto" (0) (Default and original behavior), "rgb"
(1), "ycbcr444" (2), "ycbcr422" (4), and "ycbcr420" (8).

Signed-off-by: Matias N. Goldberg <dark_sylinc@yahoo.com.ar>
Signed-off-by: Rafael Carvalho <contact@rafaelrc.com>
Signed-off-by: Shengyu Qu <wiagn233@outlook.com>
---
 drivers/gpu/drm/drm_modes.c | 32 ++++++++++++++++++++++++++++++++
 include/drm/drm_connector.h |  7 +++++++
 2 files changed, 39 insertions(+)

diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index e72f855fc495..ac2265e71b00 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -2162,6 +2162,35 @@ static int drm_mode_parse_tv_mode(const char *delim,
 	return 0;
 }
 
+static int drm_mode_parse_pixel_encoding(const char *delim,
+					 struct drm_cmdline_mode *mode)
+{
+	const char *value;
+
+	if (*delim != '=')
+		return -EINVAL;
+
+	value = delim + 1;
+	delim = strchr(value, ',');
+	if (!delim)
+		delim = value + strlen(value);
+
+	if (!strncmp(value, "auto", delim - value))
+		mode->pixel_encoding = 0;
+	else if (!strncmp(value, "rgb", delim - value))
+		mode->pixel_encoding = DRM_COLOR_FORMAT_RGB444;
+	else if (!strncmp(value, "ycbcr444", delim - value))
+		mode->pixel_encoding = DRM_COLOR_FORMAT_YCBCR444;
+	else if (!strncmp(value, "ycbcr422", delim - value))
+		mode->pixel_encoding = DRM_COLOR_FORMAT_YCBCR422;
+	else if (!strncmp(value, "ycbcr420", delim - value))
+		mode->pixel_encoding = DRM_COLOR_FORMAT_YCBCR420;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
 static int drm_mode_parse_cmdline_options(const char *str,
 					  bool freestanding,
 					  const struct drm_connector *connector,
@@ -2234,6 +2263,9 @@ static int drm_mode_parse_cmdline_options(const char *str,
 		} else if (!strncmp(option, "tv_mode", delim - option)) {
 			if (drm_mode_parse_tv_mode(delim, mode))
 				return -EINVAL;
+		} else if (!strncmp(option, "pixel_encoding", delim - option)) {
+			if (drm_mode_parse_pixel_encoding(delim, mode))
+				return -EINVAL;
 		} else {
 			return -EINVAL;
 		}
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index f13d597370a3..fdaa86d25d6d 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1723,6 +1723,13 @@ struct drm_cmdline_mode {
 	 * Did the mode have a preferred TV mode?
 	 */
 	bool tv_mode_specified;
+
+	/**
+	 * @pixel_encoding:
+	 *
+	 * Output pixel format encoding.
+	 */
+	unsigned int pixel_encoding;
 };
 
 /**
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* [PATCH v2 2/2] drm/amdgpu: Add "pixel_encoding" DRM connector property support for amdgpu
       [not found] <20250825184001.6524-1-wiagn233@outlook.com>
  2025-08-25 18:40 ` [PATCH v2 1/2] drm/connector: Add "pixel_encoding" to switch between RGB & YUV color output modes Shengyu Qu
@ 2025-08-25 18:40 ` Shengyu Qu
  1 sibling, 0 replies; 2+ messages in thread
From: Shengyu Qu @ 2025-08-25 18:40 UTC (permalink / raw)
  To: alexander.deucher, christian.koenig, airlied, simona,
	harry.wentland, sunpeng.li, siqueira, maarten.lankhorst, mripard,
	tzimmermann, contact, lijo.lazar, jesse.zhang, tim.huang,
	dark_sylinc, mario.limonciello, alex.hung, aurabindo.pillai,
	sunil.khatri, chiahsuan.chung, mwen, Roman.Li, Wayne.Lin,
	dominik.kaszewski, alvin.lee2, Aric.Cyr, Austin.Zheng, Sung.Lee,
	PeiChen.Huang, dillon.varone, Richard.Chiang, ryanseto, linux,
	haoping.liu, Relja.Vojvodic, Yihan.Zhu, Samson.Tam, amd-gfx,
	dri-devel, linux-kernel, wayland-devel
  Cc: Shengyu Qu

This patch adds support for "pixel_encoding" connector property to amdgpu,
also adds a module parameter for the driver to force override initial
output pixel format encoding.

usage: amdgpu.pixel_encoding=<encoding> or
amdgpu.pixel_encoding=<monitor>:<encoding>,<monitor>:<encoding>

Supported encodings are: "auto" (0) (Default and original behavior), "rgb"
(1), "ycbcr444" (2), "ycbcr422" (4), and "ycbcr420" (8).

Signed-off-by: Matias N. Goldberg <dark_sylinc@yahoo.com.ar>
Signed-off-by: Rafael Carvalho <contact@rafaelrc.com>
Signed-off-by: Shengyu Qu <wiagn233@outlook.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_display.c   |  36 +++
 drivers/gpu/drm/amd/amdgpu/amdgpu_display.h   |   3 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h      |   2 +
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 273 +++++++++++++++++-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   1 +
 drivers/gpu/drm/amd/display/dc/core/dc.c      |   8 +
 drivers/gpu/drm/amd/display/dc/dc_stream.h    |   2 +
 7 files changed, 314 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
index 9e463d3ee927..89c173649615 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
@@ -1363,6 +1363,34 @@ static const struct drm_prop_enum_list amdgpu_dither_enum_list[] = {
 	{ AMDGPU_FMT_DITHER_ENABLE, "on" },
 };
 
+static const struct drm_prop_enum_list amdgpu_user_pixenc_list[] = {
+	{ 0, "auto" },
+	{ DRM_COLOR_FORMAT_RGB444, "rgb" },
+	{ DRM_COLOR_FORMAT_YCBCR444, "ycbcr444" },
+	{ DRM_COLOR_FORMAT_YCBCR422, "ycbcr422" },
+	{ DRM_COLOR_FORMAT_YCBCR420, "ycbcr420" },
+};
+
+bool amdgpu_user_pixenc_from_name(
+	unsigned int *user_pixenc,
+	const char *pixenc_name)
+{
+	bool found = false;
+
+	if (pixenc_name && (*pixenc_name != '\0')) {
+		const int sz = ARRAY_SIZE(amdgpu_user_pixenc_list);
+		int i;
+
+		for (i = 0; !found && i < sz; ++i) {
+			if (strcmp(pixenc_name, amdgpu_user_pixenc_list[i].name) == 0) {
+				*user_pixenc = amdgpu_user_pixenc_list[i].type;
+				found = true;
+			}
+		}
+	}
+	return found;
+}
+
 int amdgpu_display_modeset_create_props(struct amdgpu_device *adev)
 {
 	int sz;
@@ -1409,6 +1437,14 @@ int amdgpu_display_modeset_create_props(struct amdgpu_device *adev)
 					 "dither",
 					 amdgpu_dither_enum_list, sz);
 
+	sz = ARRAY_SIZE(amdgpu_user_pixenc_list);
+	adev->mode_info.pixel_encoding_property =
+		drm_property_create_enum(adev_to_drm(adev), 0,
+			"pixel encoding",
+			amdgpu_user_pixenc_list, sz);
+	if (!adev->mode_info.pixel_encoding_property)
+		return -ENOMEM;
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.h
index dfa0d642ac16..4c4f607d1b68 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.h
@@ -54,4 +54,7 @@ int amdgpu_display_resume_helper(struct amdgpu_device *adev);
 int amdgpu_display_get_scanout_buffer(struct drm_plane *plane,
 				      struct drm_scanout_buffer *sb);
 
+bool amdgpu_user_pixenc_from_name(unsigned int *user_pixenc,
+				  const char *pixenc_name);
+
 #endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
index 6da4f946cac0..e56a772376a1 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -326,6 +326,8 @@ struct amdgpu_mode_info {
 	struct drm_property *audio_property;
 	/* FMT dithering */
 	struct drm_property *dither_property;
+	/* output pixel format encoding override */
+	struct drm_property *pixel_encoding_property;
 	/* hardcoded DFP edid from BIOS */
 	const struct drm_edid *bios_hardcoded_edid;
 
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 b944abea306d..76525b8b7e1e 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -176,6 +176,14 @@ static void reset_freesync_config_for_crtc(struct dm_crtc_state *new_crtc_state)
 static struct amdgpu_i2c_adapter *
 create_i2c(struct ddc_service *ddc_service, bool oem);
 
+/**
+ * DOC: pixel_encoding (string)
+ * Specify the initial output pixel format encoding used by a connector.
+ */
+static char amdgpu_pixel_encoding[MAX_INPUT];
+MODULE_PARM_DESC(pixel_encoding, "Override pixel encoding");
+module_param_string(pixel_encoding, amdgpu_pixel_encoding, sizeof(amdgpu_pixel_encoding), 0444);
+
 static enum drm_mode_subconnector get_subconnector_type(struct dc_link *link)
 {
 	switch (link->dpcd_caps.dongle_type) {
@@ -6368,6 +6376,119 @@ static bool adjust_colour_depth_from_display_info(
 	return false;
 }
 
+/* convert an pixel encoding property value to a dc_pixel_encoding */
+static bool drm_prop_to_dc_pixel_encoding(
+	enum dc_pixel_encoding *dc_pixenc,
+	unsigned int propval)
+{
+	bool ret = false;
+
+	switch (propval) {
+	case 0:
+		*dc_pixenc = PIXEL_ENCODING_UNDEFINED;
+		ret = true;
+		break;
+	case DRM_COLOR_FORMAT_RGB444:
+		*dc_pixenc = PIXEL_ENCODING_RGB;
+		ret = true;
+		break;
+	case DRM_COLOR_FORMAT_YCBCR444:
+		*dc_pixenc = PIXEL_ENCODING_YCBCR444;
+		ret = true;
+		break;
+	case DRM_COLOR_FORMAT_YCBCR422:
+		*dc_pixenc = PIXEL_ENCODING_YCBCR422;
+		ret = true;
+		break;
+	case DRM_COLOR_FORMAT_YCBCR420:
+		*dc_pixenc = PIXEL_ENCODING_YCBCR420;
+		ret = true;
+		break;
+	default:
+		break;
+	}
+	return ret;
+}
+
+/* convert an dc_pixel_encoding to a pixel encoding property value */
+static unsigned int dc_pixel_encoding_to_drm_prop(
+	enum dc_pixel_encoding pixel_encoding)
+{
+	unsigned int propval = 0;
+
+	switch (pixel_encoding) {
+	case PIXEL_ENCODING_RGB:
+		propval = DRM_COLOR_FORMAT_RGB444;
+		break;
+	case PIXEL_ENCODING_YCBCR444:
+		propval = DRM_COLOR_FORMAT_YCBCR444;
+		break;
+	case PIXEL_ENCODING_YCBCR420:
+		propval = DRM_COLOR_FORMAT_YCBCR420;
+		break;
+	default:
+		break;
+	}
+	return propval;
+}
+
+/*
+ * Tries to read 'pixel_encoding' from the pixel_encoding DRM property on
+ * 'state'. Returns true if a supported, acceptable, non-undefined value is
+ * found; false otherwise. Only modifies 'pixel_encoding' if returning true.
+ */
+bool get_connector_state_pixel_encoding(
+	enum dc_pixel_encoding *pixel_encoding,
+	const struct drm_connector_state *state,
+	const struct drm_display_info *info,
+	const struct drm_display_mode *mode_in)
+{
+	bool ret = false;
+	struct dm_connector_state *dm_state;
+
+	dm_state = to_dm_connector_state(state);
+	if (!dm_state)
+		return false;
+
+	/* check encoding is supported */
+	switch (dm_state->pixel_encoding) {
+	case PIXEL_ENCODING_RGB:
+		ret = (info->color_formats & DRM_COLOR_FORMAT_RGB444);
+		break;
+	case PIXEL_ENCODING_YCBCR444:
+		ret = (info->color_formats & DRM_COLOR_FORMAT_YCBCR444);
+		break;
+	case PIXEL_ENCODING_YCBCR420:
+		ret = drm_mode_is_420(info, mode_in);
+		break;
+	default:
+		break;
+	}
+
+	if (ret)
+		*pixel_encoding = dm_state->pixel_encoding;
+
+	return ret;
+}
+
+/*
+ * Writes 'pixel_encoding' to the pixel_encoding DRM property on 'state', if
+ * the enum value is valid and supported; otherwise writes
+ * PIXEL_ENCODING_UNDEFINED which corresponds to the "auto" property state.
+ */
+void set_connector_state_pixel_encoding(
+	const struct drm_connector_state *state,
+	enum dc_pixel_encoding pixel_encoding)
+{
+	struct dm_connector_state *dm_state;
+
+	dm_state = to_dm_connector_state(state);
+	if (!dm_state)
+		return;
+
+	dm_state->pixel_encoding = pixel_encoding;
+}
+
 static void fill_stream_properties_from_drm_display_mode(
 	struct dc_stream_state *stream,
 	const struct drm_display_mode *mode_in,
@@ -6393,19 +6514,23 @@ 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)
+
+	if (!get_connector_state_pixel_encoding(&timing_out->pixel_encoding,
+		connector_state, info, mode_in)) {
+		/* auto-select a pixel encoding */
+		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)
+			timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
+		else if (drm_mode_is_420_also(info, mode_in)
 			&& aconnector
 			&& aconnector->force_yuv420_output)
-		timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
-	else if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCBCR444)
-			&& stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
-		timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR444;
-	else
-		timing_out->pixel_encoding = PIXEL_ENCODING_RGB;
+			timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
+		else if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCBCR444)
+				&& stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
+			timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR444;
+		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(
@@ -6479,6 +6604,9 @@ static void fill_stream_properties_from_drm_display_mode(
 		}
 	}
 
+	/* write back final choice of pixel encoding */
+	set_connector_state_pixel_encoding(connector_state, timing_out->pixel_encoding);
+
 	stream->output_color_space = get_output_color_space(timing_out, connector_state);
 	stream->content_type = get_output_content_type(connector_state);
 }
@@ -7181,6 +7309,9 @@ int amdgpu_dm_connector_atomic_set_property(struct drm_connector *connector,
 	} else if (property == adev->mode_info.underscan_property) {
 		dm_new_state->underscan_enable = val;
 		ret = 0;
+	} else if (property == adev->mode_info.pixel_encoding_property) {
+		if (drm_prop_to_dc_pixel_encoding(&dm_new_state->pixel_encoding, val))
+			ret = 0;
 	}
 
 	return ret;
@@ -7223,6 +7354,9 @@ int amdgpu_dm_connector_atomic_get_property(struct drm_connector *connector,
 	} else if (property == adev->mode_info.underscan_property) {
 		*val = dm_state->underscan_enable;
 		ret = 0;
+	} else if (property == adev->mode_info.pixel_encoding_property) {
+		*val = dc_pixel_encoding_to_drm_prop(dm_state->pixel_encoding);
+		ret = 0;
 	}
 
 	return ret;
@@ -7367,6 +7501,48 @@ static void amdgpu_dm_connector_destroy(struct drm_connector *connector)
 	kfree(connector);
 }
 
+/*
+ * Returns the default pixel encoding, depending on the pixel_encoding
+ * module parameter if given.
+ */
+static enum dc_pixel_encoding pixel_encoding_reset(
+	const struct drm_connector *connector)
+{
+	char *param_str = NULL;
+	char *param_str_ptr = NULL;
+	char *param_item = NULL;
+	char *param_item_sep = NULL;
+	char *pixenc_mode = NULL;
+	unsigned int user_pixenc;
+	enum dc_pixel_encoding pixel_encoding = PIXEL_ENCODING_UNDEFINED;
+
+	/* default in absence of module param */
+	if (*amdgpu_pixel_encoding == '\0')
+		return PIXEL_ENCODING_UNDEFINED;
+
+	/* decode param string */
+	param_str = kstrdup(amdgpu_pixel_encoding, GFP_KERNEL);
+	param_str_ptr = param_str;
+	while ((param_item = strsep(&param_str_ptr, ","))) {
+		param_item_sep = strchr(param_item, ':');
+		if (param_item_sep) {
+			if (!strncmp(connector->name, param_item,
+				   param_item_sep - param_item)) {
+				pixenc_mode = param_item_sep + 1;
+				break;
+			}
+		} else
+			pixenc_mode = param_item;
+	}
+
+	/* compare mode string and set */
+	if (amdgpu_user_pixenc_from_name(&user_pixenc, pixenc_mode))
+		drm_prop_to_dc_pixel_encoding(&pixel_encoding, user_pixenc);
+
+	kfree(param_str);
+	return pixel_encoding;
+}
+
 void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector)
 {
 	struct dm_connector_state *state =
@@ -7395,6 +7571,24 @@ void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector)
 				state->abm_level = amdgpu_dm_abm_level;
 		}
 
+		switch (connector->cmdline_mode.pixel_encoding) {
+		case DRM_COLOR_FORMAT_RGB444:
+			state->pixel_encoding = PIXEL_ENCODING_RGB;
+			break;
+		case DRM_COLOR_FORMAT_YCBCR444:
+			state->pixel_encoding = PIXEL_ENCODING_YCBCR444;
+			break;
+		case DRM_COLOR_FORMAT_YCBCR422:
+			state->pixel_encoding = PIXEL_ENCODING_YCBCR422;
+			break;
+		case DRM_COLOR_FORMAT_YCBCR420:
+			state->pixel_encoding = PIXEL_ENCODING_YCBCR420;
+			break;
+		default:
+			break;
+		}
+
+		state->pixel_encoding = pixel_encoding_reset(connector);
 		__drm_atomic_helper_connector_reset(connector, &state->base);
 	}
 }
@@ -7421,6 +7615,7 @@ amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector *connector)
 	new_state->underscan_vborder = state->underscan_vborder;
 	new_state->vcpi_slots = state->vcpi_slots;
 	new_state->pbn = state->pbn;
+	new_state->pixel_encoding = state->pixel_encoding;
 	return &new_state->base;
 }
 
@@ -8552,6 +8747,12 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
 
 		if (adev->dm.hdcp_workqueue)
 			drm_connector_attach_content_protection_property(&aconnector->base, true);
+
+		if (adev->mode_info.pixel_encoding_property) {
+			drm_object_attach_property(&aconnector->base.base,
+				adev->mode_info.pixel_encoding_property, 0);
+			DRM_DEBUG_DRIVER("amdgpu: attached pixel encoding drm property");
+		}
 	}
 
 	if (connector_type == DRM_MODE_CONNECTOR_eDP) {
@@ -9833,6 +10034,38 @@ static void amdgpu_dm_commit_audio(struct drm_device *dev,
 	}
 }
 
+static void update_stream_for_pixel_encoding(
+	struct dc_stream_update *stream_update,
+	struct drm_connector *connector,
+	struct dm_crtc_state *dm_old_crtc_state,
+	struct dm_crtc_state *dm_new_crtc_state,
+	struct dm_connector_state *dm_new_con_state)
+{
+	struct amdgpu_dm_connector *aconnector =
+		to_amdgpu_dm_connector(connector);
+	struct dc_stream_state *new_stream = NULL;
+
+	if (aconnector)
+		new_stream = create_validate_stream_for_sink(
+			aconnector,
+			&dm_new_crtc_state->base.mode,
+			dm_new_con_state,
+			dm_old_crtc_state->stream);
+	if (new_stream) {
+		dm_new_crtc_state->stream->timing =
+			new_stream->timing;
+		stream_update->timing_for_pixel_encoding =
+			&dm_new_crtc_state->stream->timing;
+
+		dm_new_crtc_state->stream->output_color_space =
+			new_stream->output_color_space;
+		stream_update->output_color_space =
+			&dm_new_crtc_state->stream->output_color_space;
+
+		dc_stream_release(new_stream);
+	}
+}
+
 /*
  * amdgpu_dm_crtc_copy_transient_flags - copy mirrored flags from DRM to DC
  * @crtc_state: the DRM CRTC state
@@ -10316,6 +10549,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
 		struct dc_info_packet hdr_packet;
 		struct dc_stream_status *status = NULL;
 		bool abm_changed, hdr_changed, scaling_changed, output_color_space_changed = false;
+		bool pixenc_changed;
 
 		memset(&stream_update, 0, sizeof(stream_update));
 
@@ -10345,7 +10579,11 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
 		hdr_changed =
 			!drm_connector_atomic_hdr_metadata_equal(old_con_state, new_con_state);
 
-		if (!scaling_changed && !abm_changed && !hdr_changed && !output_color_space_changed)
+		pixenc_changed = dm_new_con_state->pixel_encoding !=
+			dm_old_con_state->pixel_encoding;
+
+		if (!scaling_changed && !abm_changed && !hdr_changed &&
+			!output_color_space_changed && !pixenc_changed)
 			continue;
 
 		stream_update.stream = dm_new_crtc_state->stream;
@@ -10375,6 +10613,13 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
 			stream_update.hdr_static_metadata = &hdr_packet;
 		}
 
+		if (pixenc_changed) {
+			update_stream_for_pixel_encoding(&stream_update,
+				connector,
+				dm_old_crtc_state, dm_new_crtc_state,
+				dm_new_con_state);
+		}
+
 		status = dc_stream_get_status(dm_new_crtc_state->stream);
 
 		if (WARN_ON(!status))
@@ -11922,6 +12167,12 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
 		if (dm_old_con_state->abm_level != dm_new_con_state->abm_level ||
 		    dm_old_con_state->scaling != dm_new_con_state->scaling)
 			new_crtc_state->connectors_changed = true;
+
+		if (dm_old_con_state->pixel_encoding !=
+		    dm_new_con_state->pixel_encoding) {
+			new_crtc_state->connectors_changed = true;
+			new_crtc_state->mode_changed = true;
+		}
 	}
 
 	if (dc_resource_is_dsc_encoding_supported(dc)) {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index cbd107493f8a..0ef6050182b2 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -987,6 +987,7 @@ struct dm_connector_state {
 	uint8_t abm_level;
 	int vcpi_slots;
 	uint64_t pbn;
+	enum dc_pixel_encoding pixel_encoding;
 };
 
 #define to_dm_connector_state(x)\
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index c30d9ee51c83..6ed03dbc6c4d 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -2993,6 +2993,11 @@ static enum surface_update_type check_update_surfaces_for_stream(
 		if (stream_update->output_csc_transform)
 			su_flags->bits.out_csc = 1;
 
+		if (stream_update->timing_for_pixel_encoding) {
+			su_flags->bits.pixel_encoding = 1;
+			elevate_update_type(&overall_type, UPDATE_TYPE_FULL);
+		}
+
 		/* Output transfer function changes do not require bandwidth recalculation,
 		 * so don't trigger a full update
 		 */
@@ -3347,6 +3352,8 @@ static void copy_stream_update_to_stream(struct dc *dc,
 			update->dsc_config = NULL;
 		}
 	}
+	if (update->timing_for_pixel_encoding)
+		stream->timing = *update->timing_for_pixel_encoding;
 	if (update->scaler_sharpener_update)
 		stream->scaler_sharpener_update = *update->scaler_sharpener_update;
 	if (update->sharpening_required)
@@ -3600,6 +3607,7 @@ static void commit_planes_do_stream_update(struct dc *dc,
 					stream_update->vsc_infopacket ||
 					stream_update->vsp_infopacket ||
 					stream_update->hfvsif_infopacket ||
+					stream_update->timing_for_pixel_encoding ||
 					stream_update->adaptive_sync_infopacket ||
 					stream_update->vtem_infopacket) {
 				resource_build_info_frame(pipe_ctx);
diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h
index 5fc6fea211de..3e1a46291dfe 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_stream.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h
@@ -144,6 +144,7 @@ union stream_update_flags {
 		uint32_t mst_bw : 1;
 		uint32_t crtc_timing_adjust : 1;
 		uint32_t fams_changed : 1;
+		uint32_t pixel_encoding : 1;
 		uint32_t scaler_sharpener : 1;
 		uint32_t sharpening_required : 1;
 	} bits;
@@ -352,6 +353,7 @@ struct dc_stream_update {
 	struct dc_mst_stream_bw_update *mst_bw_update;
 	struct dc_transfer_func *func_shaper;
 	struct dc_3dlut *lut3d_func;
+	struct dc_crtc_timing *timing_for_pixel_encoding;
 
 	struct test_pattern *pending_test_pattern;
 	struct dc_crtc_timing_adjust *crtc_timing_adjust;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2025-08-25 18:40 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20250825184001.6524-1-wiagn233@outlook.com>
2025-08-25 18:40 ` [PATCH v2 1/2] drm/connector: Add "pixel_encoding" to switch between RGB & YUV color output modes Shengyu Qu
2025-08-25 18:40 ` [PATCH v2 2/2] drm/amdgpu: Add "pixel_encoding" DRM connector property support for amdgpu Shengyu Qu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).