Skip to content

Commit 092c96a

Browse files
committed
drm/radeon: 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: Tom St Denis <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
1 parent 41869c1 commit 092c96a

File tree

3 files changed

+49
-77
lines changed

3 files changed

+49
-77
lines changed

drivers/gpu/drm/radeon/atombios_dp.c

Lines changed: 36 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -302,77 +302,31 @@ static int convert_bpc_to_bpp(int bpc)
302302
return bpc * 3;
303303
}
304304

305-
/* get the max pix clock supported by the link rate and lane num */
306-
static int dp_get_max_dp_pix_clock(int link_rate,
307-
int lane_num,
308-
int bpp)
309-
{
310-
return (link_rate * lane_num * 8) / bpp;
311-
}
312-
313305
/***** radeon specific DP functions *****/
314306

315-
int radeon_dp_get_max_link_rate(struct drm_connector *connector,
316-
const u8 dpcd[DP_DPCD_SIZE])
317-
{
318-
int max_link_rate;
319-
320-
if (radeon_connector_is_dp12_capable(connector))
321-
max_link_rate = min(drm_dp_max_link_rate(dpcd), 540000);
322-
else
323-
max_link_rate = min(drm_dp_max_link_rate(dpcd), 270000);
324-
325-
return max_link_rate;
326-
}
327-
328-
/* First get the min lane# when low rate is used according to pixel clock
329-
* (prefer low rate), second check max lane# supported by DP panel,
330-
* if the max lane# < low rate lane# then use max lane# instead.
331-
*/
332-
static int radeon_dp_get_dp_lane_number(struct drm_connector *connector,
333-
const u8 dpcd[DP_DPCD_SIZE],
334-
int pix_clock)
335-
{
336-
int bpp = convert_bpc_to_bpp(radeon_get_monitor_bpc(connector));
337-
int max_link_rate = radeon_dp_get_max_link_rate(connector, dpcd);
338-
int max_lane_num = drm_dp_max_lane_count(dpcd);
339-
int lane_num;
340-
int max_dp_pix_clock;
341-
342-
for (lane_num = 1; lane_num < max_lane_num; lane_num <<= 1) {
343-
max_dp_pix_clock = dp_get_max_dp_pix_clock(max_link_rate, lane_num, bpp);
344-
if (pix_clock <= max_dp_pix_clock)
345-
break;
346-
}
347-
348-
return lane_num;
349-
}
350-
351-
static int radeon_dp_get_dp_link_clock(struct drm_connector *connector,
352-
const u8 dpcd[DP_DPCD_SIZE],
353-
int pix_clock)
307+
int radeon_dp_get_dp_link_config(struct drm_connector *connector,
308+
const u8 dpcd[DP_DPCD_SIZE],
309+
unsigned pix_clock,
310+
unsigned *dp_lanes, unsigned *dp_rate)
354311
{
355312
int bpp = convert_bpc_to_bpp(radeon_get_monitor_bpc(connector));
356-
int lane_num, max_pix_clock;
357-
358-
if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) ==
359-
ENCODER_OBJECT_ID_NUTMEG)
360-
return 270000;
361-
362-
lane_num = radeon_dp_get_dp_lane_number(connector, dpcd, pix_clock);
363-
max_pix_clock = dp_get_max_dp_pix_clock(162000, lane_num, bpp);
364-
if (pix_clock <= max_pix_clock)
365-
return 162000;
366-
max_pix_clock = dp_get_max_dp_pix_clock(270000, lane_num, bpp);
367-
if (pix_clock <= max_pix_clock)
368-
return 270000;
369-
if (radeon_connector_is_dp12_capable(connector)) {
370-
max_pix_clock = dp_get_max_dp_pix_clock(540000, lane_num, bpp);
371-
if (pix_clock <= max_pix_clock)
372-
return 540000;
313+
static const unsigned link_rates[3] = { 162000, 270000, 540000 };
314+
unsigned max_link_rate = drm_dp_max_link_rate(dpcd);
315+
unsigned max_lane_num = drm_dp_max_lane_count(dpcd);
316+
unsigned lane_num, i, max_pix_clock;
317+
318+
for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) {
319+
for (i = 0; i < ARRAY_SIZE(link_rates) && link_rates[i] <= max_link_rate; i++) {
320+
max_pix_clock = (lane_num * link_rates[i] * 8) / bpp;
321+
if (max_pix_clock >= pix_clock) {
322+
*dp_lanes = lane_num;
323+
*dp_rate = link_rates[i];
324+
return 0;
325+
}
326+
}
373327
}
374328

375-
return radeon_dp_get_max_link_rate(connector, dpcd);
329+
return -EINVAL;
376330
}
377331

378332
static u8 radeon_dp_encoder_service(struct radeon_device *rdev,
@@ -491,17 +445,22 @@ void radeon_dp_set_link_config(struct drm_connector *connector,
491445
{
492446
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
493447
struct radeon_connector_atom_dig *dig_connector;
448+
int ret;
494449

495450
if (!radeon_connector->con_priv)
496451
return;
497452
dig_connector = radeon_connector->con_priv;
498453

499454
if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
500455
(dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
501-
dig_connector->dp_clock =
502-
radeon_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);
503-
dig_connector->dp_lane_count =
504-
radeon_dp_get_dp_lane_number(connector, dig_connector->dpcd, mode->clock);
456+
ret = radeon_dp_get_dp_link_config(connector, dig_connector->dpcd,
457+
mode->clock,
458+
&dig_connector->dp_lane_count,
459+
&dig_connector->dp_clock);
460+
if (ret) {
461+
dig_connector->dp_clock = 0;
462+
dig_connector->dp_lane_count = 0;
463+
}
505464
}
506465
}
507466

@@ -510,7 +469,8 @@ int radeon_dp_mode_valid_helper(struct drm_connector *connector,
510469
{
511470
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
512471
struct radeon_connector_atom_dig *dig_connector;
513-
int dp_clock;
472+
unsigned dp_clock, dp_lanes;
473+
int ret;
514474

515475
if ((mode->clock > 340000) &&
516476
(!radeon_connector_is_dp12_capable(connector)))
@@ -520,8 +480,12 @@ int radeon_dp_mode_valid_helper(struct drm_connector *connector,
520480
return MODE_CLOCK_HIGH;
521481
dig_connector = radeon_connector->con_priv;
522482

523-
dp_clock =
524-
radeon_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);
483+
ret = radeon_dp_get_dp_link_config(connector, dig_connector->dpcd,
484+
mode->clock,
485+
&dp_lanes,
486+
&dp_clock);
487+
if (ret)
488+
return MODE_CLOCK_HIGH;
525489

526490
if ((dp_clock == 540000) &&
527491
(!radeon_connector_is_dp12_capable(connector)))

drivers/gpu/drm/radeon/radeon_dp_mst.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -525,11 +525,17 @@ static bool radeon_mst_mode_fixup(struct drm_encoder *encoder,
525525
drm_mode_set_crtcinfo(adjusted_mode, 0);
526526
{
527527
struct radeon_connector_atom_dig *dig_connector;
528+
int ret;
528529

529530
dig_connector = mst_enc->connector->con_priv;
530-
dig_connector->dp_lane_count = drm_dp_max_lane_count(dig_connector->dpcd);
531-
dig_connector->dp_clock = radeon_dp_get_max_link_rate(&mst_enc->connector->base,
532-
dig_connector->dpcd);
531+
ret = radeon_dp_get_dp_link_config(&mst_enc->connector->base,
532+
dig_connector->dpcd, adjusted_mode->clock,
533+
&dig_connector->dp_lane_count,
534+
&dig_connector->dp_clock);
535+
if (ret) {
536+
dig_connector->dp_lane_count = 0;
537+
dig_connector->dp_clock = 0;
538+
}
533539
DRM_DEBUG_KMS("dig clock %p %d %d\n", dig_connector,
534540
dig_connector->dp_lane_count, dig_connector->dp_clock);
535541
}

drivers/gpu/drm/radeon/radeon_mode.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -756,8 +756,10 @@ extern u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector);
756756
extern bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector);
757757
extern int radeon_dp_get_panel_mode(struct drm_encoder *encoder,
758758
struct drm_connector *connector);
759-
int radeon_dp_get_max_link_rate(struct drm_connector *connector,
760-
const u8 *dpcd);
759+
extern int radeon_dp_get_dp_link_config(struct drm_connector *connector,
760+
const u8 *dpcd,
761+
unsigned pix_clock,
762+
unsigned *dp_lanes, unsigned *dp_rate);
761763
extern void radeon_dp_set_rx_power_state(struct drm_connector *connector,
762764
u8 power_state);
763765
extern void radeon_dp_aux_init(struct radeon_connector *radeon_connector);

0 commit comments

Comments
 (0)