From 0173eec2951aee969c6f06aa3d53d40a710ec876 Mon Sep 17 00:00:00 2001 From: Wyon Bi Date: Wed, 23 Sep 2020 14:25:25 +0800 Subject: [PATCH] drm/rockchip: analogix_dp: Add support for rk3568 This patch adds support for Analogix eDP TX IP used on RK3568 SoC. Change-Id: Ieb89906cba5bc569ed8c476fecd00f6035a7f582 Signed-off-by: Wyon Bi --- .../drm/bridge/analogix/analogix_dp_core.c | 13 ++++ .../drm/bridge/analogix/analogix_dp_core.h | 2 + .../gpu/drm/bridge/analogix/analogix_dp_reg.c | 69 +++++++++++++++++++ .../gpu/drm/rockchip/analogix_dp-rockchip.c | 44 ++++++++++-- include/drm/bridge/analogix_dp.h | 11 ++- 5 files changed, 134 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 799dc606c7b9..6cc6e9cf061b 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -257,6 +257,14 @@ static int analogix_dp_link_start(struct analogix_dp_device *dp) retval = drm_dp_dpcd_write(&dp->aux, DP_LINK_BW_SET, buf, 2); if (retval < 0) return retval; + + /* Spread AMP if required, enable 8b/10b coding */ + buf[0] = analogix_dp_ssc_supported(dp) ? DP_SPREAD_AMP_0_5 : 0; + buf[1] = DP_SET_ANSI_8B10B; + retval = drm_dp_dpcd_write(&dp->aux, DP_DOWNSPREAD_CTRL, buf, 2); + if (retval < 0) + return retval; + /* set enhanced mode if available */ retval = analogix_dp_set_enhanced_mode(dp); if (retval < 0) { @@ -559,6 +567,7 @@ static int analogix_dp_full_link_train(struct analogix_dp_device *dp, { int retval = 0; bool training_finished = false; + u8 dpcd; /* * MACRO_RST must be applied after the PLL_LOCK to avoid @@ -584,6 +593,9 @@ static int analogix_dp_full_link_train(struct analogix_dp_device *dp, dp->link_train.lane_count = (u8)LANE_COUNT1; } + drm_dp_dpcd_readb(&dp->aux, DP_MAX_DOWNSPREAD, &dpcd); + dp->link_train.ssc = !!(dpcd & DP_MAX_DOWNSPREAD_0_5); + /* Setup TX lane count & rate */ if (dp->link_train.lane_count > max_lanes) dp->link_train.lane_count = max_lanes; @@ -1515,6 +1527,7 @@ static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp) switch (dp->plat_data->dev_type) { case RK3288_DP: case RK3399_EDP: + case RK3568_EDP: /* * Like Rk3288 DisplayPort TRM indicate that "Main link * containing 4 physical lanes of 2.7/1.62 Gbps/lane". diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index 55efe12370c6..2b0294779a62 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -153,6 +153,7 @@ struct link_train { u8 link_rate; u8 lane_count; u8 training_lane[4]; + bool ssc; enum link_training_state lt_state; }; @@ -243,5 +244,6 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, struct drm_dp_aux_msg *msg); void analogix_dp_set_video_format(struct analogix_dp_device *dp); void analogix_dp_video_bist_enable(struct analogix_dp_device *dp); +bool analogix_dp_ssc_supported(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 8031bc4fc81b..08eadcbeb346 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -530,6 +531,12 @@ void analogix_dp_enable_sw_function(struct analogix_dp_device *dp) analogix_dp_write(dp, ANALOGIX_DP_FUNC_EN_1, reg); } +bool analogix_dp_ssc_supported(struct analogix_dp_device *dp) +{ + /* Check if SSC is supported by both sides */ + return dp->plat_data->ssc && dp->link_train.ssc; +} + void analogix_dp_set_link_bandwidth(struct analogix_dp_device *dp, u32 bwtype) { u32 reg, status; @@ -539,6 +546,24 @@ void analogix_dp_set_link_bandwidth(struct analogix_dp_device *dp, u32 bwtype) if ((bwtype == DP_LINK_BW_2_7) || (bwtype == DP_LINK_BW_1_62)) analogix_dp_write(dp, ANALOGIX_DP_LINK_BW_SET, reg); + if (dp->phy) { + union phy_configure_opts phy_cfg = {0}; + + phy_cfg.dp.lanes = dp->link_train.lane_count; + phy_cfg.dp.link_rate = + drm_dp_bw_code_to_link_rate(dp->link_train.link_rate) / 100; + phy_cfg.dp.ssc = analogix_dp_ssc_supported(dp); + phy_cfg.dp.set_lanes = false; + phy_cfg.dp.set_rate = true; + phy_cfg.dp.set_voltages = false; + ret = phy_configure(dp->phy, &phy_cfg); + if (ret && ret != -EOPNOTSUPP) { + dev_err(dp->dev, "%s: phy_configure failed: %d\n", + __func__, ret); + return; + } + } + ret = readx_poll_timeout(analogix_dp_get_pll_lock_status, dp, status, status != PLL_UNLOCKED, 120, 120 * DP_TIMEOUT_LOOP_COUNT); @@ -559,9 +584,25 @@ void analogix_dp_get_link_bandwidth(struct analogix_dp_device *dp, u32 *bwtype) void analogix_dp_set_lane_count(struct analogix_dp_device *dp, u32 count) { u32 reg; + int ret; reg = count; analogix_dp_write(dp, ANALOGIX_DP_LANE_COUNT_SET, reg); + + if (dp->phy) { + union phy_configure_opts phy_cfg = {0}; + + phy_cfg.dp.lanes = dp->link_train.lane_count; + phy_cfg.dp.set_lanes = true; + phy_cfg.dp.set_rate = false; + phy_cfg.dp.set_voltages = false; + ret = phy_configure(dp->phy, &phy_cfg); + if (ret && ret != -EOPNOTSUPP) { + dev_err(dp->dev, "%s: phy_configure() failed: %d\n", + __func__, ret); + return; + } + } } void analogix_dp_get_lane_count(struct analogix_dp_device *dp, u32 *count) @@ -575,11 +616,39 @@ void analogix_dp_get_lane_count(struct analogix_dp_device *dp, u32 *count) void analogix_dp_set_lane_link_training(struct analogix_dp_device *dp) { u8 lane; + int ret; for (lane = 0; lane < dp->link_train.lane_count; lane++) analogix_dp_write(dp, ANALOGIX_DP_LN0_LINK_TRAINING_CTL + 4 * lane, dp->link_train.training_lane[lane]); + + if (dp->phy) { + union phy_configure_opts phy_cfg = {0}; + + for (lane = 0; lane < dp->link_train.lane_count; lane++) { + u8 training_lane = dp->link_train.training_lane[lane]; + u8 vs, pe; + + vs = (training_lane & DP_TRAIN_VOLTAGE_SWING_MASK) >> + DP_TRAIN_VOLTAGE_SWING_SHIFT; + pe = (training_lane & DP_TRAIN_PRE_EMPHASIS_MASK) >> + DP_TRAIN_PRE_EMPHASIS_SHIFT; + phy_cfg.dp.voltage[lane] = vs; + phy_cfg.dp.pre[lane] = pe; + } + + phy_cfg.dp.lanes = dp->link_train.lane_count; + phy_cfg.dp.set_lanes = false; + phy_cfg.dp.set_rate = false; + phy_cfg.dp.set_voltages = true; + ret = phy_configure(dp->phy, &phy_cfg); + if (ret && ret != -EOPNOTSUPP) { + dev_err(dp->dev, "%s: phy_configure() failed: %d\n", + __func__, ret); + return; + } + } } u32 analogix_dp_get_lane_link_training(struct analogix_dp_device *dp, u8 lane) diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 24c674152eeb..4d5d14d85280 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -16,6 +16,7 @@ #include #include +#include #include