diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index c34d716aa64c..2276b0a78268 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -161,7 +161,7 @@ analogix_dp_set_lane_lane_pre_emphasis(struct analogix_dp_device *dp, static int analogix_dp_link_start(struct analogix_dp_device *dp) { - u8 buf[4]; + u8 buf[4], dpcd = 0; int lane, lane_count, pll_tries, retval; lane_count = dp->link_train.lane_count; @@ -183,6 +183,30 @@ static int analogix_dp_link_start(struct analogix_dp_device *dp) if (retval < 0) return retval; + /* possibly enable downspread on the sink */ + retval = drm_dp_dpcd_readb(&dp->aux, DP_MAX_DOWNSPREAD, &dpcd); + if (retval < 0) + return retval; + + if (dpcd & DP_MAX_DOWNSPREAD_0_5) { + DRM_DEV_INFO(dp->dev, "Enable downspread on the sink\n"); + + analogix_dp_ssc_enable(dp); + + retval = drm_dp_dpcd_writeb(&dp->aux, DP_DOWNSPREAD_CTRL, + DP_SPREAD_AMP_0_5); + if (retval < 0) + return retval; + } else { + DRM_DEV_INFO(dp->dev, "Disable downspread on the sink\n"); + + analogix_dp_ssc_disable(dp); + + retval = drm_dp_dpcd_writeb(&dp->aux, DP_DOWNSPREAD_CTRL, 0); + if (retval < 0) + return retval; + } + /* Set TX pre-emphasis to minimum */ for (lane = 0; lane < lane_count; lane++) analogix_dp_set_lane_lane_pre_emphasis(dp, diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index 7d566136d384..85b2dde04755 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -251,4 +251,6 @@ void analogix_dp_set_video_format(struct analogix_dp_device *dp); void analogix_dp_video_bist_enable(struct analogix_dp_device *dp); ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, struct drm_dp_aux_msg *msg); +void analogix_dp_ssc_enable(struct analogix_dp_device *dp); +void analogix_dp_ssc_disable(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 a0c3247c0aaa..ad5c6505884f 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -1076,3 +1076,29 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, return num_transferred; } + +void analogix_dp_ssc_enable(struct analogix_dp_device *dp) +{ + u8 reg; + + /* 4500ppm */ + writel(0x19, dp->reg_base + ANALOIGX_DP_SSC_REG); + /* + * To apply updated SSC parameters into SSC operation, + * firmware must disable and enable this bit. + */ + reg = readl(dp->reg_base + ANALOGIX_DP_FUNC_EN_2); + reg |= SSC_FUNC_EN_N; + writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_2); + reg &= ~SSC_FUNC_EN_N; + writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_2); +} + +void analogix_dp_ssc_disable(struct analogix_dp_device *dp) +{ + u8 reg; + + reg = readl(dp->reg_base + ANALOGIX_DP_FUNC_EN_2); + reg |= SSC_FUNC_EN_N; + writel(reg, dp->reg_base + ANALOGIX_DP_FUNC_EN_2); +} diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h index bbb312fc8094..0598ec649a1a 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h @@ -46,6 +46,7 @@ #define ANALOGIX_DP_PLL_REG_4 0x9ec #define ANALOGIX_DP_PLL_REG_5 0xa00 +#define ANALOIGX_DP_SSC_REG 0x104 #define ANALOGIX_DP_PD 0x12c #define ANALOGIX_DP_LANE_MAP 0x35C