From 3ae279210eeff7d31db38e77b3b75053f5bef0d4 Mon Sep 17 00:00:00 2001 From: Damon Ding Date: Wed, 15 Jan 2025 11:57:34 +0800 Subject: [PATCH] drm/bridge: analogix_dp: add support for ASSR mode According to the eDP v1.3 chapter 3.6 Table 3-15, Alternative Scramble Seed Reset(ASSR) is a recommended way for eDP Sink devices to support Display Authentication and Content Protection as Method 3a, while Method 1 HDCP is normally not expected in an eDP Sink device. In addition, the ASSR support capability should be the bit 0 of DPCD register 0000Dh according to the eDP v1.4 'Revision History' table 2: ...... Table 3-4: Corrected reference to DPCD Address 0000Dh, bit 0 (was bit 4) ...... Change-Id: Iafad97755fd4c9e688c47164d099b290af905036 Signed-off-by: Damon Ding --- .../drm/bridge/analogix/analogix_dp_core.c | 46 +++++++++++++++++++ .../drm/bridge/analogix/analogix_dp_core.h | 3 ++ .../gpu/drm/bridge/analogix/analogix_dp_reg.c | 24 ++++++++++ .../gpu/drm/bridge/analogix/analogix_dp_reg.h | 5 ++ 4 files changed, 78 insertions(+) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 6ac47ad2cc36..d253ebcf3ce4 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -341,6 +341,43 @@ static bool analogix_dp_get_vrr_capable(struct analogix_dp_device *dp) return true; } +static int analogix_dp_enable_sink_to_assr_mode(struct analogix_dp_device *dp, bool enable) +{ + u8 data; + int ret; + + ret = drm_dp_dpcd_readb(&dp->aux, DP_EDP_CONFIGURATION_SET, &data); + if (ret != 1) + return ret; + + if (enable) + ret = drm_dp_dpcd_writeb(&dp->aux, DP_EDP_CONFIGURATION_SET, + data | DP_ALTERNATE_SCRAMBLER_RESET_ENABLE); + else + ret = drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET, + data & ~DP_ALTERNATE_SCRAMBLER_RESET_ENABLE); + + return ret < 0 ? ret : 0; +} + +static int analogix_dp_set_assr_mode(struct analogix_dp_device *dp) +{ + bool assr_en; + int ret; + + assr_en = drm_dp_alternate_scrambler_reset_cap(dp->dpcd); + + ret = analogix_dp_enable_sink_to_assr_mode(dp, assr_en); + if (ret < 0) + return ret; + + analogix_dp_enable_assr_mode(dp, assr_en); + + dp->link_train.assr = assr_en; + + return 0; +} + static int analogix_dp_link_start(struct analogix_dp_device *dp) { u8 buf[4]; @@ -380,6 +417,13 @@ static int analogix_dp_link_start(struct analogix_dp_device *dp) if (retval < 0) return retval; + /* set ASSR if available */ + retval = analogix_dp_set_assr_mode(dp); + if (retval < 0) { + dev_err(dp->dev, "failed to set assr mode\n"); + return retval; + } + /* set enhanced mode if available */ retval = analogix_dp_set_enhanced_mode(dp); if (retval < 0) { @@ -908,6 +952,7 @@ static int analogix_dp_fast_link_train(struct analogix_dp_device *dp) analogix_dp_set_link_bandwidth(dp, dp->link_train.link_rate); analogix_dp_set_lane_count(dp, dp->link_train.lane_count); analogix_dp_set_lane_link_training(dp); + analogix_dp_enable_assr_mode(dp, dp->link_train.assr); analogix_dp_enable_enhanced_mode(dp, dp->link_train.enhanced_framing); /* source Set training pattern 1 */ @@ -2392,6 +2437,7 @@ static void analogix_dp_link_train_restore(struct analogix_dp_device *dp) dp->link_train.link_rate = link_rate; dp->link_train.lane_count = lane_count; + dp->link_train.assr = analogix_dp_get_assr_mode(dp); dp->link_train.enhanced_framing = analogix_dp_get_enhanced_mode(dp); dp->link_train.ssc = !!(spread & DP_MAX_DOWNSPREAD_0_5); diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index 2b2883029c5b..915bf6969ca1 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -160,6 +160,7 @@ struct link_train { u8 training_lane[4]; bool ssc; bool enhanced_framing; + bool assr; enum link_training_state lt_state; }; @@ -279,5 +280,7 @@ void analogix_dp_init(struct analogix_dp_device *dp); void analogix_dp_irq_handler(struct analogix_dp_device *dp); void analogix_dp_phy_test(struct analogix_dp_device *dp); void analogix_dp_check_device_service_irq(struct analogix_dp_device *dp); +void analogix_dp_enable_assr_mode(struct analogix_dp_device *dp, bool enable); +bool analogix_dp_get_assr_mode(struct analogix_dp_device *dp); #endif /* _ANALOGIX_DP_CORE_H */ diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index e72524eab4c2..5b58f8219ccc 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -1390,3 +1390,27 @@ void analogix_dp_init(struct analogix_dp_device *dp) analogix_dp_init_hpd(dp); analogix_dp_init_aux(dp); } + +void analogix_dp_enable_assr_mode(struct analogix_dp_device *dp, bool enable) +{ + u32 reg; + + if (enable) { + reg = analogix_dp_read(dp, ANALOGIX_DP_LINK_POLICY); + reg |= ALTERNATE_SR_ENABLE; + analogix_dp_write(dp, ANALOGIX_DP_LINK_POLICY, reg); + } else { + reg = analogix_dp_read(dp, ANALOGIX_DP_LINK_POLICY); + reg &= ~ALTERNATE_SR_ENABLE; + analogix_dp_write(dp, ANALOGIX_DP_LINK_POLICY, reg); + } +} + +bool analogix_dp_get_assr_mode(struct analogix_dp_device *dp) +{ + u32 reg; + + reg = analogix_dp_read(dp, ANALOGIX_DP_LINK_POLICY); + + return !!(reg & ALTERNATE_SR_ENABLE); +} diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h index 0a368b1722ec..a14305148ce5 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h @@ -146,6 +146,8 @@ #define ANALOGIX_DP_CRC_CON 0x890 #define ANALOGIX_DP_I2S_CTRL 0x9C8 +#define ANALOGIX_DP_LINK_POLICY 0x9D8 + /* ANALOGIX_DP_TX_SW_RESET */ #define RESET_DP_TX (0x1 << 0) @@ -515,4 +517,7 @@ /* ANALOGIX_DP_I2S_CTRL */ #define I2S_EN (0x1 << 4) +/* ANALOGIX_DP_LINK_POLICY */ +#define ALTERNATE_SR_ENABLE (0x1 << 7) + #endif /* _ANALOGIX_DP_REG_H */