summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c90
1 files 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 @@ cleanup:
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);