diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 9e9c03287869b44300ae4326c88aaa58738e3e66..3c7ef2cc3b8b12194472f16d18826e3ea18c9aa2 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -2389,17 +2389,45 @@ static void compute_m_n(u32 *ret_m, u32 *ret_n, intel_reduce_m_n_ratio(ret_m, ret_n); } +static void +add_bw_alloc_overhead(int link_clock, int bw_overhead, + int pixel_data_rate, int link_data_rate, + u32 *data_m, u32 *data_n) +{ + bool is_uhbr = intel_dp_is_uhbr_rate(link_clock); + int ch_coding_efficiency = + drm_dp_bw_channel_coding_efficiency(is_uhbr); + + /* + * TODO: adjust for actual UHBR channel coding efficiency and BW + * overhead. + */ + if (is_uhbr) { + *data_m = pixel_data_rate; + *data_n = link_data_rate * 8 / 10; + return; + } + + *data_m = DIV_ROUND_UP_ULL(mul_u32_u32(pixel_data_rate, bw_overhead), + 1000000); + *data_n = DIV_ROUND_DOWN_ULL(mul_u32_u32(link_data_rate, ch_coding_efficiency), + 1000000); +} + void intel_link_compute_m_n(u16 bits_per_pixel, int nlanes, int pixel_clock, int link_clock, - struct intel_link_m_n *m_n, - bool fec_enable) + int bw_overhead, + struct intel_link_m_n *m_n) { u32 data_clock = bits_per_pixel * pixel_clock; + u32 data_m; + u32 data_n; - if (fec_enable) - data_clock = intel_dp_mode_to_fec_clock(data_clock); - + add_bw_alloc_overhead(link_clock, bw_overhead, + data_clock, + link_clock * 10 * nlanes, + &data_m, &data_n); /* * Windows/BIOS uses fixed M/N values always. Follow suit. * @@ -2409,7 +2437,7 @@ intel_link_compute_m_n(u16 bits_per_pixel, int nlanes, */ m_n->tu = 64; compute_m_n(&m_n->data_m, &m_n->data_n, - data_clock, link_clock * nlanes * 8, + data_m, data_n, 0x8000000); compute_m_n(&m_n->link_m, &m_n->link_n, diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index cae2a3b12e20d208d81b6245bf3c66590d9b197f..6d0636acb725088d760e6d9660504234605e1073 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -394,8 +394,8 @@ 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, - struct intel_link_m_n *m_n, - bool fec_enable); + 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 diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 6186926f865ef71c2444dc8a5de2b9d65e8a86a2..4dc923bc4c97a351e9330c706b18baf92bd46a72 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -121,10 +121,15 @@ bool intel_dp_is_edp(struct intel_dp *intel_dp) static void intel_dp_unset_edid(struct intel_dp *intel_dp); +bool intel_dp_is_uhbr_rate(int rate) +{ + return rate >= 1000000; +} + /* Is link rate UHBR and thus 128b/132b? */ bool intel_dp_is_uhbr(const struct intel_crtc_state *crtc_state) { - return crtc_state->port_clock >= 1000000; + return intel_dp_is_uhbr_rate(crtc_state->port_clock); } static void intel_dp_set_default_sink_rates(struct intel_dp *intel_dp) @@ -684,6 +689,20 @@ u32 intel_dp_mode_to_fec_clock(u32 mode_clock) 1000000U); } +int intel_dp_bw_fec_overhead(bool fec_enabled) +{ + /* + * TODO: Calculate the actual overhead for a given mode. + * The hard-coded 1/0.972261=2.853% overhead factor + * corresponds (for instance) to the 8b/10b DP FEC 2.4% + + * 0.453% DSC overhead. This is enough for a 3840 width mode, + * which has a DSC overhead of up to ~0.2%, but may not be + * enough for a 1024 width mode where this is ~0.8% (on a 4 + * lane DP link, with 2 DSC slices and 8 bpp color depth). + */ + return fec_enabled ? DP_DSC_FEC_OVERHEAD_FACTOR : 1000000; +} + static int small_joiner_ram_size_bits(struct drm_i915_private *i915) { @@ -2655,8 +2674,9 @@ intel_dp_drrs_compute_config(struct intel_connector *connector, pixel_clock /= pipe_config->splitter.link_count; intel_link_compute_m_n(link_bpp, pipe_config->lane_count, pixel_clock, - pipe_config->port_clock, &pipe_config->dp_m2_n2, - pipe_config->fec_enable); + pipe_config->port_clock, + intel_dp_bw_fec_overhead(pipe_config->fec_enable), + &pipe_config->dp_m2_n2); /* FIXME: abstract this better */ if (pipe_config->splitter.enable) @@ -2837,8 +2857,8 @@ intel_dp_compute_config(struct intel_encoder *encoder, pipe_config->lane_count, adjusted_mode->crtc_clock, pipe_config->port_clock, - &pipe_config->dp_m_n, - pipe_config->fec_enable); + intel_dp_bw_fec_overhead(pipe_config->fec_enable), + &pipe_config->dp_m_n); /* FIXME: abstract this better */ if (pipe_config->splitter.enable) diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 0258580a6aadcc2f2a26835aa62bfeb662697c16..2080575fef69a6cfc1d018e81dad3af10d728148 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -77,6 +77,7 @@ void intel_dp_audio_compute_config(struct intel_encoder *encoder, struct drm_connector_state *conn_state); bool intel_dp_has_hdmi_sink(struct intel_dp *intel_dp); bool intel_dp_is_edp(struct intel_dp *intel_dp); +bool intel_dp_is_uhbr_rate(int rate); bool intel_dp_is_uhbr(const struct intel_crtc_state *crtc_state); bool intel_dp_is_port_edp(struct drm_i915_private *dev_priv, enum port port); enum irqreturn intel_dp_hpd_pulse(struct intel_digital_port *dig_port, @@ -137,6 +138,7 @@ static inline unsigned int intel_dp_unused_lane_mask(int lane_count) } u32 intel_dp_mode_to_fec_clock(u32 mode_clock); +int intel_dp_bw_fec_overhead(bool fec_enabled); bool intel_dp_supports_fec(struct intel_dp *intel_dp, const struct intel_connector *connector, diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 28db1775d3a5d2a50b84f3b88721c939c30ae41f..1f6fbab7d4ada4c27a4238937f31a5175fec12db 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -180,8 +180,8 @@ static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder, crtc_state->lane_count, adjusted_mode->crtc_clock, crtc_state->port_clock, - &crtc_state->dp_m_n, - crtc_state->fec_enable); + intel_dp_bw_fec_overhead(crtc_state->fec_enable), + &crtc_state->dp_m_n); crtc_state->dp_m_n.tu = slots; return 0; @@ -275,8 +275,8 @@ static int intel_dp_dsc_mst_compute_link_config(struct intel_encoder *encoder, crtc_state->lane_count, adjusted_mode->crtc_clock, crtc_state->port_clock, - &crtc_state->dp_m_n, - crtc_state->fec_enable); + intel_dp_bw_fec_overhead(crtc_state->fec_enable), + &crtc_state->dp_m_n); crtc_state->dp_m_n.tu = slots; return 0; diff --git a/drivers/gpu/drm/i915/display/intel_fdi.c b/drivers/gpu/drm/i915/display/intel_fdi.c index e6429dfebe159b9dadf450befb0090e33f10e708..1d87fbc1e81383dee16d5547ac266fc2d04423fa 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.c +++ b/drivers/gpu/drm/i915/display/intel_fdi.c @@ -10,6 +10,7 @@ #include "intel_crtc.h" #include "intel_ddi.h" #include "intel_de.h" +#include "intel_dp.h" #include "intel_display_types.h" #include "intel_fdi.h" #include "intel_fdi_regs.h" @@ -339,7 +340,9 @@ int ilk_fdi_compute_config(struct intel_crtc *crtc, pipe_config->fdi_lanes = lane; intel_link_compute_m_n(pipe_config->pipe_bpp, lane, fdi_dotclock, - link_bw, &pipe_config->fdi_m_n, false); + link_bw, + intel_dp_bw_fec_overhead(false), + &pipe_config->fdi_m_n); return 0; }