diff --git a/drivers/video/drm/analogix_dp.c b/drivers/video/drm/analogix_dp.c index 1b32bf3a18..46b080ed0a 100644 --- a/drivers/video/drm/analogix_dp.c +++ b/drivers/video/drm/analogix_dp.c @@ -27,13 +27,15 @@ * @lcdsel_grf_reg: grf register offset of lcdc select * @lcdsel_big: reg value of selecting vop big for eDP * @lcdsel_lit: reg value of selecting vop little for eDP + * @chip_type: specific chip type + * @ssc: check if SSC is supported by source */ struct rockchip_dp_chip_data { u32 lcdsel_grf_reg; u32 lcdsel_big; u32 lcdsel_lit; u32 chip_type; - bool has_vop_sel; + bool ssc; }; static void @@ -105,6 +107,14 @@ static int analogix_dp_link_start(struct analogix_dp_device *dp) if (retval) 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 = analogix_dp_write_bytes_to_dpcd(dp, DP_DOWNSPREAD_CTRL, + 2, buf); + if (retval < 0) + return retval; + /* Set TX voltage-swing and pre-emphasis to minimum */ for (lane = 0; lane < lane_count; lane++) dp->link_train.training_lane[lane] = @@ -397,6 +407,8 @@ static int analogix_dp_init_training(struct analogix_dp_device *dp, enum link_lane_count_type max_lane, int max_rate) { + u8 dpcd; + /* * MACRO_RST must be applied after the PLL_LOCK to avoid * the DP inter pair skew issue for at least 10 us @@ -425,6 +437,9 @@ static int analogix_dp_init_training(struct analogix_dp_device *dp, if (dp->link_train.link_rate > max_rate) dp->link_train.link_rate = max_rate; + analogix_dp_read_byte_from_dpcd(dp, DP_MAX_DOWNSPREAD, &dpcd); + dp->link_train.ssc = !!(dpcd & DP_MAX_DOWNSPREAD_0_5); + /* All DP analog module power up */ analogix_dp_set_analog_power_down(dp, POWER_ALL, 0); @@ -721,14 +736,15 @@ static int analogix_dp_connector_init(struct display_state *state) struct analogix_dp_device *dp = dev_get_priv(conn_state->dev); conn_state->type = DRM_MODE_CONNECTOR_eDP; + conn_state->output_if |= VOP_OUTPUT_IF_eDP0; conn_state->output_mode = ROCKCHIP_OUT_MODE_AAAA; conn_state->color_space = V4L2_COLORSPACE_DEFAULT; - /* eDP software reset request */ - reset_assert(&dp->reset); + reset_assert_bulk(&dp->resets); udelay(1); - reset_deassert(&dp->reset); + reset_deassert_bulk(&dp->resets); + generic_phy_power_on(&dp->phy); analogix_dp_init_dp(dp); return 0; @@ -762,13 +778,13 @@ static int analogix_dp_connector_enable(struct display_state *state) u32 val; int ret; - if (pdata->has_vop_sel) { + if (pdata->lcdsel_grf_reg) { if (crtc_state->crtc_id) val = pdata->lcdsel_lit; else val = pdata->lcdsel_big; - writel(val, dp->grf + pdata->lcdsel_grf_reg); + writel(val, syscon_get_first_range(ROCKCHIP_SYSCON_GRF) + pdata->lcdsel_grf_reg); } switch (conn_state->bpc) { @@ -840,11 +856,8 @@ static int analogix_dp_probe(struct udevice *dev) int ret; dp->reg_base = dev_read_addr_ptr(dev); - dp->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); - if (IS_ERR(dp->grf)) - return PTR_ERR(dp->grf); - ret = reset_get_by_name(dev, "dp", &dp->reset); + ret = reset_get_bulk(dev, &dp->resets); if (ret) { dev_err(dev, "failed to get reset control: %d\n", ret); return ret; @@ -857,10 +870,13 @@ static int analogix_dp_probe(struct udevice *dev) return ret; } + generic_phy_get_by_name(dev, "dp", &dp->phy); + dp->force_hpd = dev_read_bool(dev, "force-hpd"); dp->plat_data.dev_type = ROCKCHIP_DP; dp->plat_data.subdev_type = pdata->chip_type; + dp->plat_data.ssc = pdata->ssc; /* * Like Rockchip DisplayPort TRM indicate that "Main link * containing 4 physical lanes of 2.7/1.62 Gbps/lane". @@ -878,7 +894,6 @@ static const struct rockchip_dp_chip_data rk3288_edp_platform_data = { .lcdsel_big = 0 | BIT(21), .lcdsel_lit = BIT(5) | BIT(21), .chip_type = RK3288_DP, - .has_vop_sel = true, }; static const struct rockchip_connector rk3288_edp_driver_data = { @@ -888,7 +903,6 @@ static const struct rockchip_connector rk3288_edp_driver_data = { static const struct rockchip_dp_chip_data rk3368_edp_platform_data = { .chip_type = RK3368_EDP, - .has_vop_sel = false, }; static const struct rockchip_connector rk3368_edp_driver_data = { @@ -901,7 +915,6 @@ static const struct rockchip_dp_chip_data rk3399_edp_platform_data = { .lcdsel_big = 0 | BIT(21), .lcdsel_lit = BIT(5) | BIT(21), .chip_type = RK3399_EDP, - .has_vop_sel = true, }; static const struct rockchip_connector rk3399_edp_driver_data = { @@ -909,6 +922,16 @@ static const struct rockchip_connector rk3399_edp_driver_data = { .data = &rk3399_edp_platform_data, }; +static const struct rockchip_dp_chip_data rk3568_edp_platform_data = { + .chip_type = RK3568_EDP, + .ssc = true, +}; + +static const struct rockchip_connector rk3568_edp_driver_data = { + .funcs = &analogix_dp_connector_funcs, + .data = &rk3568_edp_platform_data, +}; + static const struct udevice_id analogix_dp_ids[] = { { .compatible = "rockchip,rk3288-dp", @@ -919,6 +942,9 @@ static const struct udevice_id analogix_dp_ids[] = { }, { .compatible = "rockchip,rk3399-edp", .data = (ulong)&rk3399_edp_driver_data, + }, { + .compatible = "rockchip,rk3568-edp", + .data = (ulong)&rk3568_edp_driver_data, }, {} }; diff --git a/drivers/video/drm/analogix_dp.h b/drivers/video/drm/analogix_dp.h index 8245b1ed9d..c7f8d49668 100644 --- a/drivers/video/drm/analogix_dp.h +++ b/drivers/video/drm/analogix_dp.h @@ -7,6 +7,7 @@ #ifndef __DRM_ANALOGIX_DP_H__ #define __DRM_ANALOGIX_DP_H__ +#include #include #include @@ -515,6 +516,7 @@ struct link_train { u8 link_rate; u8 lane_count; u8 training_lane[4]; + bool ssc; enum link_training_state lt_state; }; @@ -528,18 +530,20 @@ enum analogix_dp_sub_devtype { RK3288_DP, RK3368_EDP, RK3399_EDP, + RK3568_EDP, }; struct analogix_dp_plat_data { enum analogix_dp_devtype dev_type; enum analogix_dp_sub_devtype subdev_type; + bool ssc; }; struct analogix_dp_device { struct udevice *dev; void *reg_base; - void *grf; - struct reset_ctl reset; + struct phy phy; + struct reset_ctl_bulk resets; struct gpio_desc hpd_gpio; bool force_hpd; struct video_info video_info; @@ -628,5 +632,6 @@ int analogix_dp_is_video_stream_on(struct analogix_dp_device *dp); void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp); void analogix_dp_enable_scrambling(struct analogix_dp_device *dp); void analogix_dp_disable_scrambling(struct analogix_dp_device *dp); +bool analogix_dp_ssc_supported(struct analogix_dp_device *dp); #endif /* __DRM_ANALOGIX_DP__ */ diff --git a/drivers/video/drm/analogix_dp_reg.c b/drivers/video/drm/analogix_dp_reg.c index f129a37921..e27d60a9ea 100644 --- a/drivers/video/drm/analogix_dp_reg.c +++ b/drivers/video/drm/analogix_dp_reg.c @@ -906,8 +906,15 @@ int analogix_dp_read_bytes_from_i2c(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; @@ -915,6 +922,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 = generic_phy_configure(&dp->phy, &phy_cfg); + if (ret) { + 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 * DP_TIMEOUT_LOOP_COUNT); @@ -934,10 +955,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 = generic_phy_configure(&dp->phy, &phy_cfg); + if (ret) { + 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) @@ -950,12 +984,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]); + + 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 = generic_phy_configure(&dp->phy, &phy_cfg); + if (ret) { + 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)