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:
parent
c5b1fb658e
commit
699c29a5d8
|
|
@ -27,13 +27,15 @@
|
||||||
* @lcdsel_grf_reg: grf register offset of lcdc select
|
* @lcdsel_grf_reg: grf register offset of lcdc select
|
||||||
* @lcdsel_big: reg value of selecting vop big for eDP
|
* @lcdsel_big: reg value of selecting vop big for eDP
|
||||||
* @lcdsel_lit: reg value of selecting vop little 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 {
|
struct rockchip_dp_chip_data {
|
||||||
u32 lcdsel_grf_reg;
|
u32 lcdsel_grf_reg;
|
||||||
u32 lcdsel_big;
|
u32 lcdsel_big;
|
||||||
u32 lcdsel_lit;
|
u32 lcdsel_lit;
|
||||||
u32 chip_type;
|
u32 chip_type;
|
||||||
bool has_vop_sel;
|
bool ssc;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -105,6 +107,14 @@ static int analogix_dp_link_start(struct analogix_dp_device *dp)
|
||||||
if (retval)
|
if (retval)
|
||||||
return 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 */
|
/* Set TX voltage-swing and pre-emphasis to minimum */
|
||||||
for (lane = 0; lane < lane_count; lane++)
|
for (lane = 0; lane < lane_count; lane++)
|
||||||
dp->link_train.training_lane[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,
|
enum link_lane_count_type max_lane,
|
||||||
int max_rate)
|
int max_rate)
|
||||||
{
|
{
|
||||||
|
u8 dpcd;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MACRO_RST must be applied after the PLL_LOCK to avoid
|
* MACRO_RST must be applied after the PLL_LOCK to avoid
|
||||||
* the DP inter pair skew issue for at least 10 us
|
* 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)
|
if (dp->link_train.link_rate > max_rate)
|
||||||
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 */
|
/* All DP analog module power up */
|
||||||
analogix_dp_set_analog_power_down(dp, POWER_ALL, 0);
|
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);
|
struct analogix_dp_device *dp = dev_get_priv(conn_state->dev);
|
||||||
|
|
||||||
conn_state->type = DRM_MODE_CONNECTOR_eDP;
|
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->output_mode = ROCKCHIP_OUT_MODE_AAAA;
|
||||||
conn_state->color_space = V4L2_COLORSPACE_DEFAULT;
|
conn_state->color_space = V4L2_COLORSPACE_DEFAULT;
|
||||||
|
|
||||||
/* eDP software reset request */
|
reset_assert_bulk(&dp->resets);
|
||||||
reset_assert(&dp->reset);
|
|
||||||
udelay(1);
|
udelay(1);
|
||||||
reset_deassert(&dp->reset);
|
reset_deassert_bulk(&dp->resets);
|
||||||
|
|
||||||
|
generic_phy_power_on(&dp->phy);
|
||||||
analogix_dp_init_dp(dp);
|
analogix_dp_init_dp(dp);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -762,13 +778,13 @@ static int analogix_dp_connector_enable(struct display_state *state)
|
||||||
u32 val;
|
u32 val;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (pdata->has_vop_sel) {
|
if (pdata->lcdsel_grf_reg) {
|
||||||
if (crtc_state->crtc_id)
|
if (crtc_state->crtc_id)
|
||||||
val = pdata->lcdsel_lit;
|
val = pdata->lcdsel_lit;
|
||||||
else
|
else
|
||||||
val = pdata->lcdsel_big;
|
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) {
|
switch (conn_state->bpc) {
|
||||||
|
|
@ -840,11 +856,8 @@ static int analogix_dp_probe(struct udevice *dev)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dp->reg_base = dev_read_addr_ptr(dev);
|
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) {
|
if (ret) {
|
||||||
dev_err(dev, "failed to get reset control: %d\n", ret);
|
dev_err(dev, "failed to get reset control: %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -857,10 +870,13 @@ static int analogix_dp_probe(struct udevice *dev)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
generic_phy_get_by_name(dev, "dp", &dp->phy);
|
||||||
|
|
||||||
dp->force_hpd = dev_read_bool(dev, "force-hpd");
|
dp->force_hpd = dev_read_bool(dev, "force-hpd");
|
||||||
|
|
||||||
dp->plat_data.dev_type = ROCKCHIP_DP;
|
dp->plat_data.dev_type = ROCKCHIP_DP;
|
||||||
dp->plat_data.subdev_type = pdata->chip_type;
|
dp->plat_data.subdev_type = pdata->chip_type;
|
||||||
|
dp->plat_data.ssc = pdata->ssc;
|
||||||
/*
|
/*
|
||||||
* Like Rockchip DisplayPort TRM indicate that "Main link
|
* Like Rockchip DisplayPort TRM indicate that "Main link
|
||||||
* containing 4 physical lanes of 2.7/1.62 Gbps/lane".
|
* 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_big = 0 | BIT(21),
|
||||||
.lcdsel_lit = BIT(5) | BIT(21),
|
.lcdsel_lit = BIT(5) | BIT(21),
|
||||||
.chip_type = RK3288_DP,
|
.chip_type = RK3288_DP,
|
||||||
.has_vop_sel = true,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct rockchip_connector rk3288_edp_driver_data = {
|
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 = {
|
static const struct rockchip_dp_chip_data rk3368_edp_platform_data = {
|
||||||
.chip_type = RK3368_EDP,
|
.chip_type = RK3368_EDP,
|
||||||
.has_vop_sel = false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct rockchip_connector rk3368_edp_driver_data = {
|
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_big = 0 | BIT(21),
|
||||||
.lcdsel_lit = BIT(5) | BIT(21),
|
.lcdsel_lit = BIT(5) | BIT(21),
|
||||||
.chip_type = RK3399_EDP,
|
.chip_type = RK3399_EDP,
|
||||||
.has_vop_sel = true,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct rockchip_connector rk3399_edp_driver_data = {
|
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,
|
.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[] = {
|
static const struct udevice_id analogix_dp_ids[] = {
|
||||||
{
|
{
|
||||||
.compatible = "rockchip,rk3288-dp",
|
.compatible = "rockchip,rk3288-dp",
|
||||||
|
|
@ -919,6 +942,9 @@ static const struct udevice_id analogix_dp_ids[] = {
|
||||||
}, {
|
}, {
|
||||||
.compatible = "rockchip,rk3399-edp",
|
.compatible = "rockchip,rk3399-edp",
|
||||||
.data = (ulong)&rk3399_edp_driver_data,
|
.data = (ulong)&rk3399_edp_driver_data,
|
||||||
|
}, {
|
||||||
|
.compatible = "rockchip,rk3568-edp",
|
||||||
|
.data = (ulong)&rk3568_edp_driver_data,
|
||||||
},
|
},
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#ifndef __DRM_ANALOGIX_DP_H__
|
#ifndef __DRM_ANALOGIX_DP_H__
|
||||||
#define __DRM_ANALOGIX_DP_H__
|
#define __DRM_ANALOGIX_DP_H__
|
||||||
|
|
||||||
|
#include <generic-phy.h>
|
||||||
#include <reset.h>
|
#include <reset.h>
|
||||||
|
|
||||||
#include <drm/drm_dp_helper.h>
|
#include <drm/drm_dp_helper.h>
|
||||||
|
|
@ -515,6 +516,7 @@ struct link_train {
|
||||||
u8 link_rate;
|
u8 link_rate;
|
||||||
u8 lane_count;
|
u8 lane_count;
|
||||||
u8 training_lane[4];
|
u8 training_lane[4];
|
||||||
|
bool ssc;
|
||||||
|
|
||||||
enum link_training_state lt_state;
|
enum link_training_state lt_state;
|
||||||
};
|
};
|
||||||
|
|
@ -528,18 +530,20 @@ enum analogix_dp_sub_devtype {
|
||||||
RK3288_DP,
|
RK3288_DP,
|
||||||
RK3368_EDP,
|
RK3368_EDP,
|
||||||
RK3399_EDP,
|
RK3399_EDP,
|
||||||
|
RK3568_EDP,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct analogix_dp_plat_data {
|
struct analogix_dp_plat_data {
|
||||||
enum analogix_dp_devtype dev_type;
|
enum analogix_dp_devtype dev_type;
|
||||||
enum analogix_dp_sub_devtype subdev_type;
|
enum analogix_dp_sub_devtype subdev_type;
|
||||||
|
bool ssc;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct analogix_dp_device {
|
struct analogix_dp_device {
|
||||||
struct udevice *dev;
|
struct udevice *dev;
|
||||||
void *reg_base;
|
void *reg_base;
|
||||||
void *grf;
|
struct phy phy;
|
||||||
struct reset_ctl reset;
|
struct reset_ctl_bulk resets;
|
||||||
struct gpio_desc hpd_gpio;
|
struct gpio_desc hpd_gpio;
|
||||||
bool force_hpd;
|
bool force_hpd;
|
||||||
struct video_info video_info;
|
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_config_video_slave_mode(struct analogix_dp_device *dp);
|
||||||
void analogix_dp_enable_scrambling(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);
|
void analogix_dp_disable_scrambling(struct analogix_dp_device *dp);
|
||||||
|
bool analogix_dp_ssc_supported(struct analogix_dp_device *dp);
|
||||||
|
|
||||||
#endif /* __DRM_ANALOGIX_DP__ */
|
#endif /* __DRM_ANALOGIX_DP__ */
|
||||||
|
|
|
||||||
|
|
@ -906,8 +906,15 @@ int analogix_dp_read_bytes_from_i2c(struct analogix_dp_device *dp,
|
||||||
return retval;
|
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)
|
void analogix_dp_set_link_bandwidth(struct analogix_dp_device *dp, u32 bwtype)
|
||||||
{
|
{
|
||||||
|
union phy_configure_opts phy_cfg;
|
||||||
u32 reg, status;
|
u32 reg, status;
|
||||||
int ret;
|
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))
|
if ((bwtype == DP_LINK_BW_2_7) || (bwtype == DP_LINK_BW_1_62))
|
||||||
analogix_dp_write(dp, ANALOGIX_DP_LINK_BW_SET, reg);
|
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,
|
ret = readx_poll_timeout(analogix_dp_get_pll_lock_status, dp, status,
|
||||||
status != PLL_UNLOCKED,
|
status != PLL_UNLOCKED,
|
||||||
120 * DP_TIMEOUT_LOOP_COUNT);
|
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)
|
void analogix_dp_set_lane_count(struct analogix_dp_device *dp, u32 count)
|
||||||
{
|
{
|
||||||
|
union phy_configure_opts phy_cfg;
|
||||||
u32 reg;
|
u32 reg;
|
||||||
|
int ret;
|
||||||
|
|
||||||
reg = count;
|
reg = count;
|
||||||
analogix_dp_write(dp, ANALOGIX_DP_LANE_COUNT_SET, reg);
|
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)
|
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)
|
void analogix_dp_set_lane_link_training(struct analogix_dp_device *dp)
|
||||||
{
|
{
|
||||||
|
union phy_configure_opts phy_cfg;
|
||||||
u8 lane;
|
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_write(dp,
|
||||||
ANALOGIX_DP_LN0_LINK_TRAINING_CTL + 4 * lane,
|
ANALOGIX_DP_LN0_LINK_TRAINING_CTL + 4 * lane,
|
||||||
dp->link_train.training_lane[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)
|
u32 analogix_dp_get_lane_link_training(struct analogix_dp_device *dp, u8 lane)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue