diff --git a/include/libweston/backend-drm.h b/include/libweston/backend-drm.h index 02038e6f..548940ab 100644 --- a/include/libweston/backend-drm.h +++ b/include/libweston/backend-drm.h @@ -78,6 +78,20 @@ struct weston_drm_output_api { */ void (*set_seat)(struct weston_output *output, const char *seat); + + /** Set the "max bpc" KMS connector property + * + * The property is used for working around faulty sink hardware like + * monitors or media converters that mishandle the kernel driver + * chosen bits-per-channel on the physical link. When having trouble, + * try a lower value like 8. + * + * The value actually used in KMS is silently clamped to the range the + * KMS driver claims to support. The default value is 16. + * + * This can be set only while the output is disabled. + */ + void (*set_max_bpc)(struct weston_output *output, unsigned max_bpc); }; static inline const struct weston_drm_output_api * diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h index 60ab2352..3fc5f9b9 100644 --- a/libweston/backend-drm/drm-internal.h +++ b/libweston/backend-drm/drm-internal.h @@ -187,6 +187,7 @@ enum wdrm_connector_property { WDRM_CONNECTOR_HDCP_CONTENT_TYPE, WDRM_CONNECTOR_PANEL_ORIENTATION, WDRM_CONNECTOR_HDR_OUTPUT_METADATA, + WDRM_CONNECTOR_MAX_BPC, WDRM_CONNECTOR__COUNT }; @@ -559,6 +560,8 @@ struct drm_output { uint32_t hdr_output_metadata_blob_id; uint64_t ackd_color_outcome_serial; + unsigned max_bpc; + /* Plane being displayed directly on the CRTC */ struct drm_plane *scanout_plane; diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c index f06d8c72..ffb584ad 100644 --- a/libweston/backend-drm/drm.c +++ b/libweston/backend-drm/drm.c @@ -1389,6 +1389,17 @@ drm_output_set_seat(struct weston_output *base, seat ? seat : ""); } +static void +drm_output_set_max_bpc(struct weston_output *base, unsigned max_bpc) +{ + struct drm_output *output = to_drm_output(base); + + assert(output); + assert(!output->base.enabled); + + output->max_bpc = max_bpc; +} + static int drm_output_init_gamma_size(struct drm_output *output) { @@ -2278,6 +2289,7 @@ drm_output_create(struct weston_compositor *compositor, const char *name) output->device = device; output->crtc = NULL; + output->max_bpc = 16; output->gbm_format = DRM_FORMAT_INVALID; #ifdef BUILD_DRM_GBM output->gbm_bo_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING; @@ -3055,6 +3067,7 @@ static const struct weston_drm_output_api api = { drm_output_set_mode, drm_output_set_gbm_format, drm_output_set_seat, + drm_output_set_max_bpc, }; static struct drm_backend * diff --git a/libweston/backend-drm/kms.c b/libweston/backend-drm/kms.c index d1be5dbe..f6629a5d 100644 --- a/libweston/backend-drm/kms.c +++ b/libweston/backend-drm/kms.c @@ -146,6 +146,7 @@ const struct drm_property_info connector_props[] = { [WDRM_CONNECTOR_HDR_OUTPUT_METADATA] = { .name = "HDR_OUTPUT_METADATA", }, + [WDRM_CONNECTOR_MAX_BPC] = { .name = "max bpc", }, }; const struct drm_property_info crtc_props[] = { @@ -905,6 +906,30 @@ drm_connector_set_hdcp_property(struct drm_connector *connector, assert(ret == 0); } +static int +drm_connector_set_max_bpc(struct drm_connector *connector, + struct drm_output *output, + drmModeAtomicReq *req) +{ + const struct drm_property_info *info; + uint64_t max_bpc; + uint64_t a, b; + + if (!drm_connector_has_prop(connector, WDRM_CONNECTOR_MAX_BPC)) + return 0; + + info = &connector->props[WDRM_CONNECTOR_MAX_BPC]; + assert(info->flags & DRM_MODE_PROP_RANGE); + assert(info->num_range_values == 2); + a = info->range_values[0]; + b = info->range_values[1]; + assert(a <= b); + + max_bpc = MAX(a, MIN(output->max_bpc, b)); + return connector_add_prop(req, connector, + WDRM_CONNECTOR_MAX_BPC, max_bpc); +} + static int drm_output_apply_state_atomic(struct drm_output_state *state, drmModeAtomicReq *req, @@ -965,6 +990,8 @@ drm_output_apply_state_atomic(struct drm_output_state *state, WDRM_CONNECTOR_HDR_OUTPUT_METADATA, output->hdr_output_metadata_blob_id); } + + ret |= drm_connector_set_max_bpc(&head->connector, output, req); } if (ret != 0) {