From d7ad116fb30d11d110aeb880754cf27f34c45c40 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 | 63 ++++++++++++++++++- .../gpu/drm/rockchip/analogix_dp-rockchip.c | 31 +++++++-- include/drm/bridge/analogix_dp.h | 12 +++- 5 files changed, 113 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index c84d16b529a1..d447081198f3 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -341,6 +341,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) { @@ -643,6 +651,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 @@ -668,6 +677,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; @@ -1419,6 +1431,7 @@ static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp) case RK3288_DP: case RK3368_EDP: case RK3399_EDP: + case RK3568_EDP: video_info->max_link_rate = 0x0A; video_info->max_lane_count = 0x04; break; diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index af7cbb1997d6..923d297c6528 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -157,6 +157,7 @@ struct link_train { u8 link_rate; u8 lane_count; u8 training_lane[4]; + bool ssc; enum link_training_state lt_state; }; @@ -246,5 +247,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 ec96903b885a..16e6ba2bafad 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -617,8 +618,15 @@ int analogix_dp_write_byte_to_dpcd(struct analogix_dp_device *dp, return retval; } +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) { + union phy_configure_opts phy_cfg; u32 reg, status; int ret; @@ -626,6 +634,20 @@ 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); + 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); @@ -645,10 +667,23 @@ 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) { + union phy_configure_opts phy_cfg; u32 reg; + int ret; reg = count; analogix_dp_write(dp, ANALOGIX_DP_LANE_COUNT_SET, reg); + + 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) @@ -661,12 +696,36 @@ 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) { + union phy_configure_opts phy_cfg; u8 lane; + int ret; + + for (lane = 0; lane < dp->link_train.lane_count; lane++) { + u8 training_lane = dp->link_train.training_lane[lane]; + u8 vs, pe; - 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]); + training_lane); + + vs = (training_lane >> DP_TRAIN_VOLTAGE_SWING_SHIFT) & + DP_TRAIN_VOLTAGE_SWING_MASK; + pe = (training_lane >> DP_TRAIN_PRE_EMPHASIS_SHIFT) & + DP_TRAIN_PRE_EMPHASIS_MASK; + 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 97450ac029ca..03936efe0e96 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -62,6 +62,7 @@ struct rockchip_dp_chip_data { u32 lcdsel_big; u32 lcdsel_lit; u32 chip_type; + bool ssc; }; struct rockchip_dp_device { @@ -74,6 +75,7 @@ struct rockchip_dp_device { struct clk *grfclk; struct regmap *grf; struct reset_control *rst; + struct reset_control *apb_reset; struct regulator *vcc_supply; struct regulator *vccio_supply; @@ -113,6 +115,10 @@ static int rockchip_dp_pre_init(struct rockchip_dp_device *dp) usleep_range(10, 20); reset_control_deassert(dp->rst); + reset_control_assert(dp->apb_reset); + usleep_range(10, 20); + reset_control_deassert(dp->apb_reset); + return 0; } @@ -256,6 +262,7 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder, s->output_mode = ROCKCHIP_OUT_MODE_AAAA; s->output_type = DRM_MODE_CONNECTOR_eDP; + s->output_if |= VOP_OUTPUT_IF_eDP0; s->output_bpc = di->bpc; if (di->num_bus_formats) s->bus_format = di->bus_formats[0]; @@ -323,10 +330,12 @@ static int rockchip_dp_of_probe(struct rockchip_dp_device *dp) struct device_node *np = dev->of_node; int ret = 0; - dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); - if (IS_ERR(dp->grf)) { - DRM_DEV_ERROR(dev, "failed to get rockchip,grf property\n"); - return PTR_ERR(dp->grf); + if (of_property_read_bool(np, "rockchip,grf")) { + dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); + if (IS_ERR(dp->grf)) { + DRM_DEV_ERROR(dev, "failed to get rockchip,grf\n"); + return PTR_ERR(dp->grf); + } } dp->grfclk = devm_clk_get(dev, "grf"); @@ -351,6 +360,12 @@ static int rockchip_dp_of_probe(struct rockchip_dp_device *dp) return PTR_ERR(dp->rst); } + dp->apb_reset = devm_reset_control_get_optional(dev, "apb"); + if (IS_ERR(dp->apb_reset)) { + DRM_DEV_ERROR(dev, "failed to get apb reset control\n"); + return PTR_ERR(dp->apb_reset); + } + dp->vcc_supply = devm_regulator_get_optional(dev, "vcc"); if (IS_ERR(dp->vcc_supply)) { if (PTR_ERR(dp->vcc_supply) != -ENODEV) { @@ -422,7 +437,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, } dp->plat_data.encoder = &dp->encoder; - + dp->plat_data.ssc = dp->data->ssc; dp->plat_data.dev_type = dp->data->chip_type; dp->plat_data.power_on_start = rockchip_dp_poweron_start; dp->plat_data.power_on_end = rockchip_dp_poweron_end; @@ -571,10 +586,16 @@ static const struct rockchip_dp_chip_data rk3288_dp = { .chip_type = RK3288_DP, }; +static const struct rockchip_dp_chip_data rk3568_edp = { + .chip_type = RK3568_EDP, + .ssc = true, +}; + static const struct of_device_id rockchip_dp_dt_ids[] = { {.compatible = "rockchip,rk3288-dp", .data = &rk3288_dp }, {.compatible = "rockchip,rk3368-edp", .data = &rk3368_edp }, {.compatible = "rockchip,rk3399-edp", .data = &rk3399_edp }, + {.compatible = "rockchip,rk3568-edp", .data = &rk3568_edp }, {} }; MODULE_DEVICE_TABLE(of, rockchip_dp_dt_ids); diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h index 4dd3ddd52b5b..c95ec66468da 100644 --- a/include/drm/bridge/analogix_dp.h +++ b/include/drm/bridge/analogix_dp.h @@ -20,11 +20,20 @@ enum analogix_dp_devtype { RK3288_DP, RK3368_EDP, RK3399_EDP, + RK3568_EDP, }; static inline bool is_rockchip(enum analogix_dp_devtype type) { - return type == RK3288_DP || type == RK3399_EDP || type == RK3368_EDP; + switch (type) { + case RK3288_DP: + case RK3368_EDP: + case RK3399_EDP: + case RK3568_EDP: + return true; + default: + return false; + } } struct analogix_dp_plat_data { @@ -33,6 +42,7 @@ struct analogix_dp_plat_data { struct drm_encoder *encoder; struct drm_connector *connector; bool skip_connector; + bool ssc; int (*power_on_start)(struct analogix_dp_plat_data *); int (*power_on_end)(struct analogix_dp_plat_data *);