@@ -2658,8 +2658,15 @@ static void compute_m_n(u32 *ret_m, u32 *ret_n,
intel_reduce_m_n_ratio(ret_m, ret_n);
}
-void
-intel_link_compute_m_n(u16 bits_per_pixel_x16, int nlanes,
+static int
+get_max_link_m_n_ratio(void)
+{
+ return 10;
+}
+
+int
+intel_link_compute_m_n(struct intel_display *display,
+ u16 bits_per_pixel_x16, int nlanes,
int pixel_clock, int link_clock,
int bw_overhead,
struct intel_link_m_n *m_n)
@@ -2668,6 +2675,7 @@ intel_link_compute_m_n(u16 bits_per_pixel_x16, int nlanes,
u32 data_m = intel_dp_effective_data_rate(pixel_clock, bits_per_pixel_x16,
bw_overhead);
u32 data_n = drm_dp_max_dprx_data_rate(link_clock, nlanes);
+ int link_m_n_ratio, max_link_m_n_ratio;
/*
* Windows/BIOS uses fixed M/N values always. Follow suit.
@@ -2684,6 +2692,26 @@ intel_link_compute_m_n(u16 bits_per_pixel_x16, int nlanes,
compute_m_n(&m_n->link_m, &m_n->link_n,
pixel_clock, link_symbol_clock,
0x80000);
+
+ if (DISPLAY_VER(display) < 12)
+ return 0;
+
+ /* Check for Link M/N ratio for Display >= 12 */
+ max_link_m_n_ratio = get_max_link_m_n_ratio();
+
+ if (!m_n->link_n)
+ return -EINVAL;
+
+ link_m_n_ratio = DIV_ROUND_UP(m_n->link_m, m_n->link_n);
+
+ if (link_m_n_ratio > max_link_m_n_ratio) {
+ drm_dbg_kms(display->drm,
+ "Cannot support Link_m/Link_n ratio : %d > %d\n",
+ link_m_n_ratio, max_link_m_n_ratio);
+ return -EINVAL;
+ }
+
+ return 0;
}
void intel_panel_sanitize_ssc(struct drm_i915_private *dev_priv)
@@ -420,10 +420,11 @@ int intel_atomic_add_affected_planes(struct intel_atomic_state *state,
struct intel_crtc *crtc);
u8 intel_calc_active_pipes(struct intel_atomic_state *state,
u8 active_pipes);
-void intel_link_compute_m_n(u16 bpp, int nlanes,
- int pixel_clock, int link_clock,
- int bw_overhead,
- struct intel_link_m_n *m_n);
+int intel_link_compute_m_n(struct intel_display *display,
+ u16 bpp, int nlanes,
+ int pixel_clock, int link_clock,
+ int bw_overhead,
+ struct intel_link_m_n *m_n);
u32 intel_plane_fb_max_stride(struct drm_i915_private *dev_priv,
u32 pixel_format, u64 modifier);
enum drm_mode_status
@@ -2890,15 +2890,17 @@ static bool can_enable_drrs(struct intel_connector *connector,
intel_panel_drrs_type(connector) == DRRS_TYPE_SEAMLESS;
}
-static void
+static int
intel_dp_drrs_compute_config(struct intel_connector *connector,
struct intel_crtc_state *pipe_config,
int link_bpp_x16)
{
struct drm_i915_private *i915 = to_i915(connector->base.dev);
+ struct intel_display *display = to_intel_display(connector);
const struct drm_display_mode *downclock_mode =
intel_panel_downclock_mode(connector, &pipe_config->hw.adjusted_mode);
int pixel_clock;
+ int ret;
/*
* FIXME all joined pipes share the same transcoder.
@@ -2910,7 +2912,7 @@ intel_dp_drrs_compute_config(struct intel_connector *connector,
if (!can_enable_drrs(connector, pipe_config, downclock_mode)) {
if (intel_cpu_transcoder_has_m2_n2(i915, pipe_config->cpu_transcoder))
intel_zero_m_n(&pipe_config->dp_m2_n2);
- return;
+ return 0;
}
if (IS_IRONLAKE(i915) || IS_SANDYBRIDGE(i915) || IS_IVYBRIDGE(i915))
@@ -2922,14 +2924,18 @@ intel_dp_drrs_compute_config(struct intel_connector *connector,
if (pipe_config->splitter.enable)
pixel_clock /= pipe_config->splitter.link_count;
- intel_link_compute_m_n(link_bpp_x16, pipe_config->lane_count, pixel_clock,
- pipe_config->port_clock,
- intel_dp_bw_fec_overhead(pipe_config->fec_enable),
- &pipe_config->dp_m2_n2);
+ ret = intel_link_compute_m_n(display, link_bpp_x16, pipe_config->lane_count, pixel_clock,
+ pipe_config->port_clock,
+ intel_dp_bw_fec_overhead(pipe_config->fec_enable),
+ &pipe_config->dp_m2_n2);
+ if (ret)
+ return ret;
/* FIXME: abstract this better */
if (pipe_config->splitter.enable)
pipe_config->dp_m2_n2.data_m *= pipe_config->splitter.link_count;
+
+ return 0;
}
static bool intel_dp_has_audio(struct intel_encoder *encoder,
@@ -3052,6 +3058,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
struct drm_connector_state *conn_state)
{
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ struct intel_display *display = to_intel_display(encoder);
struct intel_atomic_state *state = to_intel_atomic_state(conn_state->state);
struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
@@ -3133,12 +3140,14 @@ intel_dp_compute_config(struct intel_encoder *encoder,
intel_dp_audio_compute_config(encoder, pipe_config, conn_state);
- intel_link_compute_m_n(link_bpp_x16,
- pipe_config->lane_count,
- adjusted_mode->crtc_clock,
- pipe_config->port_clock,
- intel_dp_bw_fec_overhead(pipe_config->fec_enable),
- &pipe_config->dp_m_n);
+ ret = intel_link_compute_m_n(display, link_bpp_x16,
+ pipe_config->lane_count,
+ adjusted_mode->crtc_clock,
+ pipe_config->port_clock,
+ intel_dp_bw_fec_overhead(pipe_config->fec_enable),
+ &pipe_config->dp_m_n);
+ if (ret)
+ return ret;
/* FIXME: abstract this better */
if (pipe_config->splitter.enable)
@@ -3151,7 +3160,11 @@ intel_dp_compute_config(struct intel_encoder *encoder,
intel_dp_compute_as_sdp(intel_dp, pipe_config);
intel_psr_compute_config(intel_dp, pipe_config, conn_state);
intel_alpm_lobf_compute_config(intel_dp, pipe_config, conn_state);
- intel_dp_drrs_compute_config(connector, pipe_config, link_bpp_x16);
+
+ ret = intel_dp_drrs_compute_config(connector, pipe_config, link_bpp_x16);
+ if (ret)
+ return ret;
+
intel_dp_compute_vsc_sdp(intel_dp, pipe_config, conn_state);
intel_dp_compute_hdr_metadata_infoframe_sdp(intel_dp, pipe_config, conn_state);
@@ -125,23 +125,28 @@ static int intel_dp_mst_bw_overhead(const struct intel_crtc_state *crtc_state,
return max(overhead, intel_dp_bw_fec_overhead(crtc_state->fec_enable));
}
-static void intel_dp_mst_compute_m_n(const struct intel_crtc_state *crtc_state,
- const struct intel_connector *connector,
- int overhead,
- int bpp_x16,
- struct intel_link_m_n *m_n)
+static int intel_dp_mst_compute_m_n(const struct intel_crtc_state *crtc_state,
+ const struct intel_connector *connector,
+ int overhead,
+ int bpp_x16,
+ struct intel_link_m_n *m_n)
{
const struct drm_display_mode *adjusted_mode =
&crtc_state->hw.adjusted_mode;
+ struct intel_display *display = to_intel_display(connector);
+ int ret;
/* TODO: Check WA 14013163432 to set data M/N for full BW utilization. */
- intel_link_compute_m_n(bpp_x16, crtc_state->lane_count,
- adjusted_mode->crtc_clock,
- crtc_state->port_clock,
- overhead,
- m_n);
+ ret = intel_link_compute_m_n(display, bpp_x16, crtc_state->lane_count,
+ adjusted_mode->crtc_clock,
+ crtc_state->port_clock,
+ overhead, m_n);
+ if (ret)
+ return ret;
m_n->tu = DIV_ROUND_UP_ULL(mul_u32_u32(m_n->data_m, 64), m_n->data_n);
+
+ return ret;
}
static int intel_dp_mst_calc_pbn(int pixel_clock, int bpp_x16, int bw_overhead)
@@ -223,10 +228,11 @@ static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder,
remote_bw_overhead = intel_dp_mst_bw_overhead(crtc_state, connector,
true, dsc, link_bpp_x16);
- intel_dp_mst_compute_m_n(crtc_state, connector,
- local_bw_overhead,
- link_bpp_x16,
- &crtc_state->dp_m_n);
+ if (!intel_dp_mst_compute_m_n(crtc_state, connector,
+ local_bw_overhead,
+ link_bpp_x16,
+ &crtc_state->dp_m_n))
+ continue;
/*
* The TU size programmed to the HW determines which slots in
@@ -325,8 +325,9 @@ int ilk_fdi_compute_config(struct intel_crtc *crtc,
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *i915 = to_i915(dev);
+ struct intel_display *display = to_intel_display(pipe_config);
const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
- int lane, link_bw, fdi_dotclock;
+ int lane, link_bw, fdi_dotclock, ret;
/* FDI is a binary signal running at ~2.7GHz, encoding
* each output octet as 10 bits. The actual frequency
@@ -344,13 +345,13 @@ int ilk_fdi_compute_config(struct intel_crtc *crtc,
pipe_config->fdi_lanes = lane;
- intel_link_compute_m_n(fxp_q4_from_int(pipe_config->pipe_bpp),
- lane, fdi_dotclock,
- link_bw,
- intel_dp_bw_fec_overhead(false),
- &pipe_config->fdi_m_n);
+ ret = intel_link_compute_m_n(display, fxp_q4_from_int(pipe_config->pipe_bpp),
+ lane, fdi_dotclock,
+ link_bw,
+ intel_dp_bw_fec_overhead(false),
+ &pipe_config->fdi_m_n);
- return 0;
+ return ret;
}
static int intel_fdi_atomic_check_bw(struct intel_atomic_state *state,
As per Bspec:49266 for DISPLAY > 12 which support higher link rates have a limitation: If the CEILING( Link M / Link N ) ratio is greater than 10.0, then hardware cannot support the given resolution / refresh rate at the given configuration. Modify the helper to compute m_n, to check for the max link_m/n ratio for the given platforms, and return error code in case the resolution/refresh rate is not supported. Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com> --- drivers/gpu/drm/i915/display/intel_display.c | 32 +++++++++++++++- drivers/gpu/drm/i915/display/intel_display.h | 9 +++-- drivers/gpu/drm/i915/display/intel_dp.c | 39 +++++++++++++------- drivers/gpu/drm/i915/display/intel_dp_mst.c | 34 ++++++++++------- drivers/gpu/drm/i915/display/intel_fdi.c | 15 ++++---- 5 files changed, 89 insertions(+), 40 deletions(-)