mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 18:41:58 +09:00
drm/bridge: analogix_dp: add support to parse link rate for eDP v1.4
As Table 4-23 in eDP v1.4 spec, the link rate can be read from SUPPORTED_LINK_RATES(0x00010h through 0x0001fh), which is required for sink devices. Signed-off-by: Damon Ding <damon.ding@rock-chips.com> Change-Id: Ibff01e7eee16be735b5f4b10c6ef51e9b2954274
This commit is contained in:
@@ -335,16 +335,22 @@ static int analogix_dp_link_start(struct analogix_dp_device *dp)
|
||||
for (lane = 0; lane < lane_count; lane++)
|
||||
dp->link_train.cr_loop[lane] = 0;
|
||||
|
||||
/* Set link rate and count as you want to establish*/
|
||||
/* Set link rate and count as you want to establish */
|
||||
analogix_dp_set_link_bandwidth(dp, dp->link_train.link_rate);
|
||||
analogix_dp_set_lane_count(dp, dp->link_train.lane_count);
|
||||
|
||||
/* Setup RX configuration */
|
||||
buf[0] = dp->link_train.link_rate;
|
||||
buf[1] = dp->link_train.lane_count;
|
||||
retval = drm_dp_dpcd_write(&dp->aux, DP_LINK_BW_SET, buf, 2);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
if (dp->nr_link_rate_table) {
|
||||
/* Setup DP_LINK_RATE_SET for eDP 1.4 and later */
|
||||
drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET, dp->link_train.lane_count);
|
||||
drm_dp_dpcd_writeb(&dp->aux, DP_LINK_RATE_SET, dp->link_rate_select);
|
||||
} else {
|
||||
/* Setup DP_LINK_BW_SET for eDP 1.3 and earlier */
|
||||
buf[0] = dp->link_train.link_rate;
|
||||
buf[1] = dp->link_train.lane_count;
|
||||
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;
|
||||
@@ -648,23 +654,133 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool analogix_dp_link_config_validate(u8 link_rate, u8 lane_count)
|
||||
{
|
||||
switch (link_rate) {
|
||||
case DP_LINK_BW_1_62:
|
||||
case DP_LINK_BW_2_7:
|
||||
case DP_LINK_BW_5_4:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (lane_count) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static u8 analogix_dp_select_link_rate_from_table(struct analogix_dp_device *dp)
|
||||
{
|
||||
int i;
|
||||
u8 bw_code;
|
||||
u32 max_link_rate = drm_dp_bw_code_to_link_rate(dp->video_info.max_link_rate);
|
||||
|
||||
for (i = 0; i < dp->nr_link_rate_table; i++) {
|
||||
bw_code = drm_dp_link_rate_to_bw_code(dp->link_rate_table[i]);
|
||||
|
||||
if (!analogix_dp_bandwidth_ok(dp, &dp->video_info.mode, dp->link_rate_table[i],
|
||||
dp->link_train.lane_count))
|
||||
continue;
|
||||
|
||||
if (dp->link_rate_table[i] <= max_link_rate &&
|
||||
analogix_dp_link_config_validate(bw_code, dp->link_train.lane_count)) {
|
||||
dp->link_rate_select = i;
|
||||
return bw_code;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int analogix_dp_select_rx_bandwidth(struct analogix_dp_device *dp)
|
||||
{
|
||||
if (dp->nr_link_rate_table)
|
||||
/*
|
||||
* Select the smallest one among link rates which meet
|
||||
* the bandwidth requirement for eDP 1.4 and later.
|
||||
*/
|
||||
dp->link_train.link_rate = analogix_dp_select_link_rate_from_table(dp);
|
||||
else
|
||||
/*
|
||||
* Select the smaller one between rx DP_MAX_LINK_RATE
|
||||
* and the max link rate supported by the platform.
|
||||
*/
|
||||
dp->link_train.link_rate = min_t(u32, dp->link_train.link_rate,
|
||||
dp->video_info.max_link_rate);
|
||||
if (!dp->link_train.link_rate)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int analogix_dp_init_link_rate_table(struct analogix_dp_device *dp)
|
||||
{
|
||||
__le16 link_rate_table[DP_MAX_SUPPORTED_RATES];
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
ret = drm_dp_dpcd_read(&dp->aux, DP_SUPPORTED_LINK_RATES, link_rate_table,
|
||||
sizeof(link_rate_table));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(link_rate_table); i++) {
|
||||
int val = le16_to_cpu(link_rate_table[i]);
|
||||
|
||||
if (val == 0)
|
||||
break;
|
||||
|
||||
/* Convert to the link_rate as drm_dp_bw_code_to_link_rate() */
|
||||
dp->link_rate_table[i] = (val * 20);
|
||||
}
|
||||
dp->nr_link_rate_table = i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int analogix_dp_get_max_rx_bandwidth(struct analogix_dp_device *dp,
|
||||
u8 *bandwidth)
|
||||
{
|
||||
u8 data;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* For DP rev.1.1, Maximum link rate of Main Link lanes
|
||||
* 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps
|
||||
* For DP rev.1.2, Maximum link rate of Main Link lanes
|
||||
* 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps, 0x14 = 5.4Gbps
|
||||
*/
|
||||
ret = drm_dp_dpcd_readb(&dp->aux, DP_MAX_LINK_RATE, &data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = drm_dp_dpcd_readb(&dp->aux, DP_EDP_DPCD_REV, &data);
|
||||
if (ret == 1 && data >= DP_EDP_14) {
|
||||
u32 max_link_rate;
|
||||
|
||||
*bandwidth = data;
|
||||
/* As the Table 4-23 in eDP 1.4 spec, the link rate table is required */
|
||||
if (!dp->nr_link_rate_table) {
|
||||
dev_info(dp->dev, "eDP version: 0x%02x supports link rate table\n", data);
|
||||
|
||||
ret = analogix_dp_init_link_rate_table(dp);
|
||||
if (ret) {
|
||||
dev_err(dp->dev, "failed to read link rate table: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
max_link_rate = dp->link_rate_table[dp->nr_link_rate_table - 1];
|
||||
*bandwidth = drm_dp_link_rate_to_bw_code(max_link_rate);
|
||||
} else {
|
||||
/*
|
||||
* For DP rev.1.1, Maximum link rate of Main Link lanes
|
||||
* 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps
|
||||
* For DP rev.1.2, Maximum link rate of Main Link lanes
|
||||
* 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps, 0x14 = 5.4Gbps
|
||||
*/
|
||||
ret = drm_dp_dpcd_readb(&dp->aux, DP_MAX_LINK_RATE, &data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*bandwidth = data;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -702,9 +818,14 @@ static int analogix_dp_full_link_train(struct analogix_dp_device *dp,
|
||||
*/
|
||||
analogix_dp_reset_macro(dp);
|
||||
|
||||
/* Setup TX lane count & rate */
|
||||
/* Setup TX lane count */
|
||||
dp->link_train.lane_count = min_t(u32, dp->link_train.lane_count, max_lanes);
|
||||
dp->link_train.link_rate = min_t(u32, dp->link_train.link_rate, max_rate);
|
||||
|
||||
/* Setup TX lane rate */
|
||||
if (analogix_dp_select_rx_bandwidth(dp)) {
|
||||
dev_err(dp->dev, "Select rx bandwidth failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!analogix_dp_bandwidth_ok(dp, &video->mode,
|
||||
drm_dp_bw_code_to_link_rate(dp->link_train.link_rate),
|
||||
@@ -1923,29 +2044,6 @@ static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge,
|
||||
video->interlaced = true;
|
||||
}
|
||||
|
||||
static bool analogix_dp_link_config_validate(u8 link_rate, u8 lane_count)
|
||||
{
|
||||
switch (link_rate) {
|
||||
case DP_LINK_BW_1_62:
|
||||
case DP_LINK_BW_2_7:
|
||||
case DP_LINK_BW_5_4:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (lane_count) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static enum drm_mode_status
|
||||
analogix_dp_bridge_mode_valid(struct drm_bridge *bridge,
|
||||
const struct drm_display_info *info,
|
||||
|
||||
@@ -182,6 +182,9 @@ struct analogix_dp_device {
|
||||
struct link_train link_train;
|
||||
struct phy *phy;
|
||||
int dpms_mode;
|
||||
int nr_link_rate_table;
|
||||
int link_rate_table[DP_MAX_SUPPORTED_RATES];
|
||||
int link_rate_select;
|
||||
struct gpio_desc *hpd_gpiod;
|
||||
bool force_hpd;
|
||||
bool fast_train_enable;
|
||||
|
||||
Reference in New Issue
Block a user