Commit 41869c1c authored by Alex Deucher's avatar Alex Deucher

drm/amdgpu: fix dp link rate selection (v2)

Need to properly handle the max link rate in the dpcd.
This prevents some cases where 5.4 Ghz is selected when
it shouldn't be.

v2: simplify logic, add array bounds check
Reviewed-by: default avatarTom St Denis <tom.stdenis@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent b24c683a
...@@ -243,7 +243,7 @@ static void amdgpu_atombios_dp_get_adjust_train(const u8 link_status[DP_LINK_STA ...@@ -243,7 +243,7 @@ static void amdgpu_atombios_dp_get_adjust_train(const u8 link_status[DP_LINK_STA
/* convert bits per color to bits per pixel */ /* convert bits per color to bits per pixel */
/* get bpc from the EDID */ /* get bpc from the EDID */
static int amdgpu_atombios_dp_convert_bpc_to_bpp(int bpc) static unsigned amdgpu_atombios_dp_convert_bpc_to_bpp(int bpc)
{ {
if (bpc == 0) if (bpc == 0)
return 24; return 24;
...@@ -251,64 +251,32 @@ static int amdgpu_atombios_dp_convert_bpc_to_bpp(int bpc) ...@@ -251,64 +251,32 @@ static int amdgpu_atombios_dp_convert_bpc_to_bpp(int bpc)
return bpc * 3; return bpc * 3;
} }
/* get the max pix clock supported by the link rate and lane num */
static int amdgpu_atombios_dp_get_max_dp_pix_clock(int link_rate,
int lane_num,
int bpp)
{
return (link_rate * lane_num * 8) / bpp;
}
/***** amdgpu specific DP functions *****/ /***** amdgpu specific DP functions *****/
/* First get the min lane# when low rate is used according to pixel clock static int amdgpu_atombios_dp_get_dp_link_config(struct drm_connector *connector,
* (prefer low rate), second check max lane# supported by DP panel,
* if the max lane# < low rate lane# then use max lane# instead.
*/
static int amdgpu_atombios_dp_get_dp_lane_number(struct drm_connector *connector,
const u8 dpcd[DP_DPCD_SIZE], const u8 dpcd[DP_DPCD_SIZE],
int pix_clock) unsigned pix_clock,
unsigned *dp_lanes, unsigned *dp_rate)
{ {
int bpp = amdgpu_atombios_dp_convert_bpc_to_bpp(amdgpu_connector_get_monitor_bpc(connector)); unsigned bpp =
int max_link_rate = drm_dp_max_link_rate(dpcd); amdgpu_atombios_dp_convert_bpc_to_bpp(amdgpu_connector_get_monitor_bpc(connector));
int max_lane_num = drm_dp_max_lane_count(dpcd); static const unsigned link_rates[3] = { 162000, 270000, 540000 };
int lane_num; unsigned max_link_rate = drm_dp_max_link_rate(dpcd);
int max_dp_pix_clock; unsigned max_lane_num = drm_dp_max_lane_count(dpcd);
unsigned lane_num, i, max_pix_clock;
for (lane_num = 1; lane_num < max_lane_num; lane_num <<= 1) {
max_dp_pix_clock = amdgpu_atombios_dp_get_max_dp_pix_clock(max_link_rate, lane_num, bpp); for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) {
if (pix_clock <= max_dp_pix_clock) for (i = 0; i < ARRAY_SIZE(link_rates) && link_rates[i] <= max_link_rate; i++) {
break; max_pix_clock = (lane_num * link_rates[i] * 8) / bpp;
if (max_pix_clock >= pix_clock) {
*dp_lanes = lane_num;
*dp_rate = link_rates[i];
return 0;
}
} }
return lane_num;
}
static int amdgpu_atombios_dp_get_dp_link_clock(struct drm_connector *connector,
const u8 dpcd[DP_DPCD_SIZE],
int pix_clock)
{
int bpp = amdgpu_atombios_dp_convert_bpc_to_bpp(amdgpu_connector_get_monitor_bpc(connector));
int lane_num, max_pix_clock;
if (amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector) ==
ENCODER_OBJECT_ID_NUTMEG)
return 270000;
lane_num = amdgpu_atombios_dp_get_dp_lane_number(connector, dpcd, pix_clock);
max_pix_clock = amdgpu_atombios_dp_get_max_dp_pix_clock(162000, lane_num, bpp);
if (pix_clock <= max_pix_clock)
return 162000;
max_pix_clock = amdgpu_atombios_dp_get_max_dp_pix_clock(270000, lane_num, bpp);
if (pix_clock <= max_pix_clock)
return 270000;
if (amdgpu_connector_is_dp12_capable(connector)) {
max_pix_clock = amdgpu_atombios_dp_get_max_dp_pix_clock(540000, lane_num, bpp);
if (pix_clock <= max_pix_clock)
return 540000;
} }
return drm_dp_max_link_rate(dpcd); return -EINVAL;
} }
static u8 amdgpu_atombios_dp_encoder_service(struct amdgpu_device *adev, static u8 amdgpu_atombios_dp_encoder_service(struct amdgpu_device *adev,
...@@ -422,6 +390,7 @@ void amdgpu_atombios_dp_set_link_config(struct drm_connector *connector, ...@@ -422,6 +390,7 @@ void amdgpu_atombios_dp_set_link_config(struct drm_connector *connector,
{ {
struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
struct amdgpu_connector_atom_dig *dig_connector; struct amdgpu_connector_atom_dig *dig_connector;
int ret;
if (!amdgpu_connector->con_priv) if (!amdgpu_connector->con_priv)
return; return;
...@@ -429,10 +398,14 @@ void amdgpu_atombios_dp_set_link_config(struct drm_connector *connector, ...@@ -429,10 +398,14 @@ void amdgpu_atombios_dp_set_link_config(struct drm_connector *connector,
if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
(dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) { (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
dig_connector->dp_clock = ret = amdgpu_atombios_dp_get_dp_link_config(connector, dig_connector->dpcd,
amdgpu_atombios_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock); mode->clock,
dig_connector->dp_lane_count = &dig_connector->dp_lane_count,
amdgpu_atombios_dp_get_dp_lane_number(connector, dig_connector->dpcd, mode->clock); &dig_connector->dp_clock);
if (ret) {
dig_connector->dp_clock = 0;
dig_connector->dp_lane_count = 0;
}
} }
} }
...@@ -441,14 +414,17 @@ int amdgpu_atombios_dp_mode_valid_helper(struct drm_connector *connector, ...@@ -441,14 +414,17 @@ int amdgpu_atombios_dp_mode_valid_helper(struct drm_connector *connector,
{ {
struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
struct amdgpu_connector_atom_dig *dig_connector; struct amdgpu_connector_atom_dig *dig_connector;
int dp_clock; unsigned dp_lanes, dp_clock;
int ret;
if (!amdgpu_connector->con_priv) if (!amdgpu_connector->con_priv)
return MODE_CLOCK_HIGH; return MODE_CLOCK_HIGH;
dig_connector = amdgpu_connector->con_priv; dig_connector = amdgpu_connector->con_priv;
dp_clock = ret = amdgpu_atombios_dp_get_dp_link_config(connector, dig_connector->dpcd,
amdgpu_atombios_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock); mode->clock, &dp_lanes, &dp_clock);
if (ret)
return MODE_CLOCK_HIGH;
if ((dp_clock == 540000) && if ((dp_clock == 540000) &&
(!amdgpu_connector_is_dp12_capable(connector))) (!amdgpu_connector_is_dp12_capable(connector)))
......
Markdown is supported
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