drm/radeon: fix dp link rate selection (v2)
[ Upstream commit 092c96a8ab9d1bd60ada2ed385cc364ce084180e ] 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: Tom St Denis <tom.stdenis@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Sasha Levin <alexander.levin@verizon.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
8844e74f8e
commit
724457fa1c
@ -302,77 +302,31 @@ static int convert_bpc_to_bpp(int bpc)
|
||||
return bpc * 3;
|
||||
}
|
||||
|
||||
/* get the max pix clock supported by the link rate and lane num */
|
||||
static int dp_get_max_dp_pix_clock(int link_rate,
|
||||
int lane_num,
|
||||
int bpp)
|
||||
{
|
||||
return (link_rate * lane_num * 8) / bpp;
|
||||
}
|
||||
|
||||
/***** radeon specific DP functions *****/
|
||||
|
||||
int radeon_dp_get_max_link_rate(struct drm_connector *connector,
|
||||
const u8 dpcd[DP_DPCD_SIZE])
|
||||
{
|
||||
int max_link_rate;
|
||||
|
||||
if (radeon_connector_is_dp12_capable(connector))
|
||||
max_link_rate = min(drm_dp_max_link_rate(dpcd), 540000);
|
||||
else
|
||||
max_link_rate = min(drm_dp_max_link_rate(dpcd), 270000);
|
||||
|
||||
return max_link_rate;
|
||||
}
|
||||
|
||||
/* First get the min lane# when low rate is used according to pixel clock
|
||||
* (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 radeon_dp_get_dp_lane_number(struct drm_connector *connector,
|
||||
const u8 dpcd[DP_DPCD_SIZE],
|
||||
int pix_clock)
|
||||
int radeon_dp_get_dp_link_config(struct drm_connector *connector,
|
||||
const u8 dpcd[DP_DPCD_SIZE],
|
||||
unsigned pix_clock,
|
||||
unsigned *dp_lanes, unsigned *dp_rate)
|
||||
{
|
||||
int bpp = convert_bpc_to_bpp(radeon_get_monitor_bpc(connector));
|
||||
int max_link_rate = radeon_dp_get_max_link_rate(connector, dpcd);
|
||||
int max_lane_num = drm_dp_max_lane_count(dpcd);
|
||||
int lane_num;
|
||||
int max_dp_pix_clock;
|
||||
static const unsigned link_rates[3] = { 162000, 270000, 540000 };
|
||||
unsigned max_link_rate = drm_dp_max_link_rate(dpcd);
|
||||
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 = dp_get_max_dp_pix_clock(max_link_rate, lane_num, bpp);
|
||||
if (pix_clock <= max_dp_pix_clock)
|
||||
break;
|
||||
for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) {
|
||||
for (i = 0; i < ARRAY_SIZE(link_rates) && link_rates[i] <= max_link_rate; i++) {
|
||||
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 radeon_dp_get_dp_link_clock(struct drm_connector *connector,
|
||||
const u8 dpcd[DP_DPCD_SIZE],
|
||||
int pix_clock)
|
||||
{
|
||||
int bpp = convert_bpc_to_bpp(radeon_get_monitor_bpc(connector));
|
||||
int lane_num, max_pix_clock;
|
||||
|
||||
if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) ==
|
||||
ENCODER_OBJECT_ID_NUTMEG)
|
||||
return 270000;
|
||||
|
||||
lane_num = radeon_dp_get_dp_lane_number(connector, dpcd, pix_clock);
|
||||
max_pix_clock = dp_get_max_dp_pix_clock(162000, lane_num, bpp);
|
||||
if (pix_clock <= max_pix_clock)
|
||||
return 162000;
|
||||
max_pix_clock = dp_get_max_dp_pix_clock(270000, lane_num, bpp);
|
||||
if (pix_clock <= max_pix_clock)
|
||||
return 270000;
|
||||
if (radeon_connector_is_dp12_capable(connector)) {
|
||||
max_pix_clock = dp_get_max_dp_pix_clock(540000, lane_num, bpp);
|
||||
if (pix_clock <= max_pix_clock)
|
||||
return 540000;
|
||||
}
|
||||
|
||||
return radeon_dp_get_max_link_rate(connector, dpcd);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static u8 radeon_dp_encoder_service(struct radeon_device *rdev,
|
||||
@ -491,6 +445,7 @@ void radeon_dp_set_link_config(struct drm_connector *connector,
|
||||
{
|
||||
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
|
||||
struct radeon_connector_atom_dig *dig_connector;
|
||||
int ret;
|
||||
|
||||
if (!radeon_connector->con_priv)
|
||||
return;
|
||||
@ -498,10 +453,14 @@ void radeon_dp_set_link_config(struct drm_connector *connector,
|
||||
|
||||
if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
|
||||
(dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
|
||||
dig_connector->dp_clock =
|
||||
radeon_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);
|
||||
dig_connector->dp_lane_count =
|
||||
radeon_dp_get_dp_lane_number(connector, dig_connector->dpcd, mode->clock);
|
||||
ret = radeon_dp_get_dp_link_config(connector, dig_connector->dpcd,
|
||||
mode->clock,
|
||||
&dig_connector->dp_lane_count,
|
||||
&dig_connector->dp_clock);
|
||||
if (ret) {
|
||||
dig_connector->dp_clock = 0;
|
||||
dig_connector->dp_lane_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -510,7 +469,8 @@ int radeon_dp_mode_valid_helper(struct drm_connector *connector,
|
||||
{
|
||||
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
|
||||
struct radeon_connector_atom_dig *dig_connector;
|
||||
int dp_clock;
|
||||
unsigned dp_clock, dp_lanes;
|
||||
int ret;
|
||||
|
||||
if ((mode->clock > 340000) &&
|
||||
(!radeon_connector_is_dp12_capable(connector)))
|
||||
@ -520,8 +480,12 @@ int radeon_dp_mode_valid_helper(struct drm_connector *connector,
|
||||
return MODE_CLOCK_HIGH;
|
||||
dig_connector = radeon_connector->con_priv;
|
||||
|
||||
dp_clock =
|
||||
radeon_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);
|
||||
ret = radeon_dp_get_dp_link_config(connector, dig_connector->dpcd,
|
||||
mode->clock,
|
||||
&dp_lanes,
|
||||
&dp_clock);
|
||||
if (ret)
|
||||
return MODE_CLOCK_HIGH;
|
||||
|
||||
if ((dp_clock == 540000) &&
|
||||
(!radeon_connector_is_dp12_capable(connector)))
|
||||
|
@ -525,11 +525,17 @@ static bool radeon_mst_mode_fixup(struct drm_encoder *encoder,
|
||||
drm_mode_set_crtcinfo(adjusted_mode, 0);
|
||||
{
|
||||
struct radeon_connector_atom_dig *dig_connector;
|
||||
int ret;
|
||||
|
||||
dig_connector = mst_enc->connector->con_priv;
|
||||
dig_connector->dp_lane_count = drm_dp_max_lane_count(dig_connector->dpcd);
|
||||
dig_connector->dp_clock = radeon_dp_get_max_link_rate(&mst_enc->connector->base,
|
||||
dig_connector->dpcd);
|
||||
ret = radeon_dp_get_dp_link_config(&mst_enc->connector->base,
|
||||
dig_connector->dpcd, adjusted_mode->clock,
|
||||
&dig_connector->dp_lane_count,
|
||||
&dig_connector->dp_clock);
|
||||
if (ret) {
|
||||
dig_connector->dp_lane_count = 0;
|
||||
dig_connector->dp_clock = 0;
|
||||
}
|
||||
DRM_DEBUG_KMS("dig clock %p %d %d\n", dig_connector,
|
||||
dig_connector->dp_lane_count, dig_connector->dp_clock);
|
||||
}
|
||||
|
@ -757,8 +757,10 @@ extern u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector);
|
||||
extern bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector);
|
||||
extern int radeon_dp_get_panel_mode(struct drm_encoder *encoder,
|
||||
struct drm_connector *connector);
|
||||
int radeon_dp_get_max_link_rate(struct drm_connector *connector,
|
||||
const u8 *dpcd);
|
||||
extern int radeon_dp_get_dp_link_config(struct drm_connector *connector,
|
||||
const u8 *dpcd,
|
||||
unsigned pix_clock,
|
||||
unsigned *dp_lanes, unsigned *dp_rate);
|
||||
extern void radeon_dp_set_rx_power_state(struct drm_connector *connector,
|
||||
u8 power_state);
|
||||
extern void radeon_dp_aux_init(struct radeon_connector *radeon_connector);
|
||||
|
Loading…
x
Reference in New Issue
Block a user