All the drivers that implement the HDMI scrambling setup (dw-hdmi, i915, tegra, vc4) duplicate the same logic to see if the TMDS ratio or the scrambling state needs to be modified depending on the current connector state and CRTC mode. Since it's basically the same logic everywhere, let's put these two informations in the connector state, and filled by a atomic_check helper so that drivers can just use it. Signed-off-by: Maxime Ripard <maxime@xxxxxxxxxx> --- drivers/gpu/drm/drm_atomic_state_helper.c | 58 +++++++++++++++++++++++ include/drm/drm_atomic_state_helper.h | 3 ++ include/drm/drm_connector.h | 25 ++++++++++ 3 files changed, 86 insertions(+) diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c index ddcf5c2c8e6a..08dfb2d1bf9b 100644 --- a/drivers/gpu/drm/drm_atomic_state_helper.c +++ b/drivers/gpu/drm/drm_atomic_state_helper.c @@ -454,6 +454,64 @@ void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector) } EXPORT_SYMBOL(drm_atomic_helper_connector_tv_reset); +/** + * drm_atomic_helper_connector_hdmi_check - Checks the state of an HDMI connector + * @connector: DRM connector + * @state: DRM atomic state to check + * + * Checks that an HDMI connector state is sane, and sets the various + * HDMI-specific flags in drm_connector_state related to HDMI support. + * + * Returns: + * 0 on success, a negative error code otherwise. + */ +int drm_atomic_helper_connector_hdmi_check(struct drm_connector *connector, + struct drm_atomic_state *state) +{ + struct drm_connector_state *conn_state = drm_atomic_get_new_connector_state(state, + connector); + struct drm_display_info *info = &connector->display_info; + const struct drm_display_mode *mode; + struct drm_crtc_state *crtc_state; + struct drm_crtc *crtc; + bool required; + + if (!conn_state) + return -EINVAL; + + crtc = conn_state->crtc; + if (!crtc) + return -EINVAL; + + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + mode = &crtc_state->mode; + crtc_state->connectors_changed = true; + conn_state->hdmi_needs_scrambling = false; + conn_state->hdmi_needs_high_tmds_ratio = false; + + if (!info->is_hdmi) + return 0; + + if (!info->hdmi.scdc.supported) + return 0; + + required = drm_mode_hdmi_requires_scrambling(mode, conn_state->max_bpc); + if (required && !info->hdmi.scdc.scrambling.supported) + return -EINVAL; + + if (info->hdmi.scdc.scrambling.low_rates || required) + conn_state->hdmi_needs_scrambling = true; + + if (required) + conn_state->hdmi_needs_high_tmds_ratio = true; + + return 0; +} +EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_check); + /** * __drm_atomic_helper_connector_duplicate_state - copy atomic connector state * @connector: connector object diff --git a/include/drm/drm_atomic_state_helper.h b/include/drm/drm_atomic_state_helper.h index 3f8f1d627f7c..3d3d1ff355f4 100644 --- a/include/drm/drm_atomic_state_helper.h +++ b/include/drm/drm_atomic_state_helper.h @@ -26,6 +26,7 @@ #include <linux/types.h> +struct drm_atomic_state; struct drm_bridge; struct drm_bridge_state; struct drm_crtc; @@ -71,6 +72,8 @@ void __drm_atomic_helper_connector_reset(struct drm_connector *connector, struct drm_connector_state *conn_state); void drm_atomic_helper_connector_reset(struct drm_connector *connector); void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector); +int drm_atomic_helper_connector_hdmi_check(struct drm_connector *connector, + struct drm_atomic_state *state); void __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector, struct drm_connector_state *state); diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index b501d0badaea..02c6f9f0d4f7 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -830,6 +830,31 @@ struct drm_connector_state { * DRM blob property for HDR output metadata */ struct drm_property_blob *hdr_output_metadata; + + /** + * @hdmi_needs_scrambling: + * + * Only relevant for HDMI sink. Tracks whether the scrambling + * should be turned on for the current sink and mode. + * + * Drivers needing this should use + * drm_atomic_helper_connector_hdmi_check() and use the value + * set here to enable or disable their scrambler. + */ + bool hdmi_needs_scrambling; + + /** + * @hdmi_needs_high_tmds_ratio: + * + * Only relevant for HDMI sink. Tracks whether the TMDS clock + * ratio should be 1/10 of the pixel clock (false), or 1/40 + * (true). + * + * Drivers needing this should use + * drm_atomic_helper_connector_hdmi_check() and use the value + * set here to enable or disable their scrambler. + */ + bool hdmi_needs_high_tmds_ratio; }; /** -- 2.33.1