diff --git a/drivers/gpu/drm/display/drm_scdc_helper.c b/drivers/gpu/drm/display/drm_scdc_helper.c index 1e7c41d4f926..74388481fc55 100644 --- a/drivers/gpu/drm/display/drm_scdc_helper.c +++ b/drivers/gpu/drm/display/drm_scdc_helper.c @@ -22,12 +22,13 @@ */ #include -#include -#include -#include #include #include +#include +#include +#include #include +#include #include #include @@ -306,6 +307,49 @@ bool drm_scdc_set_high_tmds_clock_ratio(struct drm_connector *connector, } EXPORT_SYMBOL(drm_scdc_set_high_tmds_clock_ratio); +/** + * drm_scdc_set_source_version - set SCDC source version on the sink + * @connector: connector + * @ver: source version to advertise (per spec, 1) + * + * Reads the sink version for diagnostics and as a guard, then writes + * the source version unless the sink reports version 0. + * + * Returns: + * 0 on success or when skipped; a negative error code when either + * the read or the write failed. + */ +int drm_scdc_set_source_version(struct drm_connector *connector, u8 ver) +{ + u8 sink_ver; + int ret; + + ret = drm_scdc_readb(connector->ddc, SCDC_SINK_VERSION, &sink_ver); + if (ret) { + drm_scdc_dbg(connector, "Failed to read SCDC_SINK_VERSION: %d\n", ret); + return ret; + } + + drm_scdc_dbg(connector, "Sink reported SCDC ver. %u\n", sink_ver); + + /* + * Only advertise our source version to sinks that report a + * non-zero sink version. A sink reporting version 0 is either + * not SCDC-version-aware or non-conformant; writing the source + * version gains nothing and may upset broken hardware. + */ + if (sink_ver) { + ret = drm_scdc_writeb(connector->ddc, SCDC_SOURCE_VERSION, + min_t(u8, sink_ver, ver)); + if (ret) + drm_scdc_dbg(connector, + "Failed to write SCDC_SOURCE_VERSION: %d\n", ret); + } + + return ret; +} +EXPORT_SYMBOL(drm_scdc_set_source_version); + static void drm_scdc_parse_status0_flags(u8 val, struct drm_scdc_status_flags *flags) { diff --git a/include/drm/display/drm_scdc_helper.h b/include/drm/display/drm_scdc_helper.h index a3b20adaac7e..6a8be1f16ce0 100644 --- a/include/drm/display/drm_scdc_helper.h +++ b/include/drm/display/drm_scdc_helper.h @@ -168,6 +168,8 @@ bool drm_scdc_get_scrambling_status(struct drm_connector *connector); bool drm_scdc_set_scrambling(struct drm_connector *connector, bool enable); bool drm_scdc_set_high_tmds_clock_ratio(struct drm_connector *connector, bool set); +int drm_scdc_set_source_version(struct drm_connector *connector, u8 ver); + int drm_scdc_read_state(struct drm_connector *connector, struct drm_scdc_state *state); void drm_scdc_debugfs_init(struct drm_connector *connector, struct dentry *root);