Skip to content

Commit e398d7c

Browse files
ShawnCLeeLyude
authored andcommitted
drm/i915/mst: filter out the display mode exceed sink's capability
So far, max dot clock rate for MST mode rely on physcial bandwidth limitation. It would caused compatibility issue if source display resolution exceed MST hub output ability. For example, source DUT had DP 1.2 output capability. And MST docking just support HDMI 1.4 spec. When a HDMI 2.0 monitor connected. Source would retrieve EDID from external and get max resolution 4k@60fps. DP 1.2 can support 4K@60fps because it did not surpass DP physical bandwidth limitation. Do modeset to 4k@60fps, source output display data but MST docking can't output HDMI properly due to this resolution already over HDMI 1.4 spec. Refer to commit <fcf463807596> ("drm/dp_mst: Use full_pbn instead of available_pbn for bandwidth checks"). Source driver should refer to full_pbn to evaluate sink output capability. And filter out the resolution surpass sink output limitation. Changes since v1: * Using mgr->base.lock to protect full_pbn. Changes since v2: * Add ctx lock. Changes since v3: * s/intel_dp_mst_mode_clock_exceed_pbn_bandwidth/ intel_dp_mst_mode_clock_exceeds_pbn_bw/ * Use the new drm_connector_helper_funcs.mode_valid_ctx to properly pipe down the drm_modeset_acquire_ctx that the probe helpers are using, so we can safely grab &mgr->base.lock without deadlocking Changes since v4: * Move drm_dp_calc_pbn_mode(mode->clock, bpp, false) > port->full_pbn check * Fix the bpp we use in drm_dp_calc_pbn_mode() * Drop leftover (!mgr) check * Don't check for if full_pbn is unset. To be clear - it _can_ be unset, but if it is then it's certainly a bug in DRM or a non-compliant sink as full_pbn should always be populated by the time we call ->mode_valid_ctx. We should workaround non-compliant sinks with full_pbn=0, but that should happen in the DP MST helpers so we can estimate the full_pbn value as best we can. Tested-by: Imre Deak <[email protected]> Reviewed-by: Imre Deak <[email protected]> Cc: Manasi Navare <[email protected]> Cc: Jani Nikula <[email protected]> Cc: Ville Syrjala <[email protected]> Cc: Cooper Chiou <[email protected]> Co-developed-by: Lyude Paul <[email protected]> Signed-off-by: Lee Shawn C <[email protected]> Signed-off-by: Lyude Paul <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 1c26b8e commit e398d7c

File tree

1 file changed

+38
-17
lines changed

1 file changed

+38
-17
lines changed

drivers/gpu/drm/i915/display/intel_dp_mst.c

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -639,39 +639,60 @@ static int intel_dp_mst_get_modes(struct drm_connector *connector)
639639
return intel_dp_mst_get_ddc_modes(connector);
640640
}
641641

642-
static enum drm_mode_status
643-
intel_dp_mst_mode_valid(struct drm_connector *connector,
644-
struct drm_display_mode *mode)
642+
static int
643+
intel_dp_mst_mode_valid_ctx(struct drm_connector *connector,
644+
struct drm_display_mode *mode,
645+
struct drm_modeset_acquire_ctx *ctx,
646+
enum drm_mode_status *status)
645647
{
646648
struct drm_i915_private *dev_priv = to_i915(connector->dev);
647649
struct intel_connector *intel_connector = to_intel_connector(connector);
648650
struct intel_dp *intel_dp = intel_connector->mst_port;
651+
struct drm_dp_mst_topology_mgr *mgr = &intel_dp->mst_mgr;
652+
struct drm_dp_mst_port *port = intel_connector->port;
653+
const int min_bpp = 18;
649654
int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
650655
int max_rate, mode_rate, max_lanes, max_link_clock;
656+
int ret;
651657

652-
if (drm_connector_is_unregistered(connector))
653-
return MODE_ERROR;
658+
if (drm_connector_is_unregistered(connector)) {
659+
*status = MODE_ERROR;
660+
return 0;
661+
}
654662

655-
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
656-
return MODE_NO_DBLESCAN;
663+
if (mode->flags & DRM_MODE_FLAG_DBLSCAN) {
664+
*status = MODE_NO_DBLESCAN;
665+
return 0;
666+
}
657667

658668
max_link_clock = intel_dp_max_link_rate(intel_dp);
659669
max_lanes = intel_dp_max_lane_count(intel_dp);
660670

661671
max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes);
662-
mode_rate = intel_dp_link_required(mode->clock, 18);
672+
mode_rate = intel_dp_link_required(mode->clock, min_bpp);
663673

664-
/* TODO - validate mode against available PBN for link */
665-
if (mode->clock < 10000)
666-
return MODE_CLOCK_LOW;
674+
ret = drm_modeset_lock(&mgr->base.lock, ctx);
675+
if (ret)
676+
return ret;
667677

668-
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
669-
return MODE_H_ILLEGAL;
678+
if (mode_rate > max_rate || mode->clock > max_dotclk ||
679+
drm_dp_calc_pbn_mode(mode->clock, min_bpp, false) > port->full_pbn) {
680+
*status = MODE_CLOCK_HIGH;
681+
return 0;
682+
}
683+
684+
if (mode->clock < 10000) {
685+
*status = MODE_CLOCK_LOW;
686+
return 0;
687+
}
670688

671-
if (mode_rate > max_rate || mode->clock > max_dotclk)
672-
return MODE_CLOCK_HIGH;
689+
if (mode->flags & DRM_MODE_FLAG_DBLCLK) {
690+
*status = MODE_H_ILLEGAL;
691+
return 0;
692+
}
673693

674-
return intel_mode_valid_max_plane_size(dev_priv, mode);
694+
*status = intel_mode_valid_max_plane_size(dev_priv, mode);
695+
return 0;
675696
}
676697

677698
static struct drm_encoder *intel_mst_atomic_best_encoder(struct drm_connector *connector,
@@ -700,7 +721,7 @@ intel_dp_mst_detect(struct drm_connector *connector,
700721

701722
static const struct drm_connector_helper_funcs intel_dp_mst_connector_helper_funcs = {
702723
.get_modes = intel_dp_mst_get_modes,
703-
.mode_valid = intel_dp_mst_mode_valid,
724+
.mode_valid_ctx = intel_dp_mst_mode_valid_ctx,
704725
.atomic_best_encoder = intel_mst_atomic_best_encoder,
705726
.atomic_check = intel_dp_mst_atomic_check,
706727
.detect_ctx = intel_dp_mst_detect,

0 commit comments

Comments
 (0)