video/drm: analogix_dp: Add support for rk3568

This patch adds support for Analogix eDP TX IP used on RK3568 SoC.

Signed-off-by: Wyon Bi <bivvy.bi@rock-chips.com>
Change-Id: Ia48f1f99f336d4d98d5fba4e5fd15a35bdbaf373
This commit is contained in:
Wyon Bi 2020-12-10 03:27:32 +00:00
parent c5b1fb658e
commit 699c29a5d8
3 changed files with 105 additions and 16 deletions

View File

@ -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,
},
{}
};

View File

@ -7,6 +7,7 @@
#ifndef __DRM_ANALOGIX_DP_H__
#define __DRM_ANALOGIX_DP_H__
#include <generic-phy.h>
#include <reset.h>
#include <drm/drm_dp_helper.h>
@ -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__ */

View File

@ -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)