So after some playing about I've managed to make a patch that:
1) Outputs YCbCr 4:2:0 @ 36-bit for 4K resolution
2) Outputs YCbCr 4:4:4 @ 36-bit for 1920x1080
It should still fall back to RGB if those modes are not supported. To detect if the resolution is 4K and to switch to 4:2:0 I've used the clock value and if over 500MHz assume it must be 4K, maybe a better way of doing that but it works.
Odd but for some reason Intel has no support for YCbCr 4:2:2 in the i915 driver.
The patch file created against the source 12.0.1 is below in case anyone finds it useful.
Display Spoiler
Git
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index bc975918e0..066a056a54 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -2011,12 +2011,13 @@ intel_hdmi_mode_valid(struct drm_connector *connector,
if (clock > 600000)
return MODE_CLOCK_HIGH;
- ycbcr_420_only = drm_mode_is_420_only(&connector->display_info, mode);
+ ycbcr_420_only = drm_mode_is_420_only(&connector->display_info, mode) || clock > 500000;
+
if (ycbcr_420_only)
sink_format = INTEL_OUTPUT_FORMAT_YCBCR420;
else
- sink_format = INTEL_OUTPUT_FORMAT_RGB;
+ sink_format = INTEL_OUTPUT_FORMAT_YCBCR444;
status = intel_hdmi_mode_clock_valid(connector, clock, has_hdmi_sink, sink_format);
if (status != MODE_OK) {
@@ -2199,7 +2200,7 @@ intel_hdmi_sink_format(const struct intel_crtc_state *crtc_state,
if (connector->base.ycbcr_420_allowed && ycbcr_420_output)
return INTEL_OUTPUT_FORMAT_YCBCR420;
else
- return INTEL_OUTPUT_FORMAT_RGB;
+ return INTEL_OUTPUT_FORMAT_YCBCR444;
}
static enum intel_output_format
@@ -2217,8 +2218,9 @@ static int intel_hdmi_compute_output_format(struct intel_encoder *encoder,
const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
const struct drm_display_info *info = &connector->base.display_info;
struct drm_i915_private *i915 = to_i915(connector->base.dev);
- bool ycbcr_420_only = drm_mode_is_420_only(info, adjusted_mode);
- int ret;
+ int clock = adjusted_mode->clock;
+ bool ycbcr_420_only = drm_mode_is_420_only(info, adjusted_mode) || clock > 500000;
+ int ret;
crtc_state->sink_format =
intel_hdmi_sink_format(crtc_state, connector, ycbcr_420_only);
@@ -2298,7 +2300,7 @@ int intel_hdmi_compute_config(struct intel_encoder *encoder,
adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
return -EINVAL;
- pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
+ pipe_config->output_format = INTEL_OUTPUT_FORMAT_YCBCR444;
if (pipe_config->has_hdmi_sink)
pipe_config->has_infoframe = true;
Display More