Commit d7ad116f authored by Wyon Bi's avatar Wyon Bi Committed by Tao Huang
Browse files

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: default avatarWyon Bi <bivvy.bi@rock-chips.com>
parent 790f6698
......@@ -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;
......
......@@ -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 */
......@@ -15,6 +15,7 @@
#include <linux/gpio/consumer.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/phy/phy.h>
#include <drm/bridge/analogix_dp.h>
......@@ -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)
......
......@@ -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);
......
......@@ -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 *);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment