diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_display.c')
| -rw-r--r-- | drivers/gpu/drm/i915/display/intel_display.c | 629 | 
1 files changed, 258 insertions, 371 deletions
| diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 28d85e1e858e..b10aad15a63d 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -48,6 +48,7 @@  #include "g4x_dp.h"  #include "g4x_hdmi.h"  #include "hsw_ips.h" +#include "i915_config.h"  #include "i915_drv.h"  #include "i915_reg.h"  #include "i915_utils.h" @@ -72,10 +73,10 @@  #include "intel_dp.h"  #include "intel_dp_link_training.h"  #include "intel_dp_mst.h" -#include "intel_dpio_phy.h"  #include "intel_dpll.h"  #include "intel_dpll_mgr.h"  #include "intel_dpt.h" +#include "intel_dpt_common.h"  #include "intel_drrs.h"  #include "intel_dsb.h"  #include "intel_dsi.h" @@ -193,12 +194,9 @@ static bool is_hdr_mode(const struct intel_crtc_state *crtc_state)  static void  skl_wa_827(struct drm_i915_private *dev_priv, enum pipe pipe, bool enable)  { -	if (enable) -		intel_de_rmw(dev_priv, CLKGATE_DIS_PSL(pipe), -			     0, DUPS1_GATING_DIS | DUPS2_GATING_DIS); -	else -		intel_de_rmw(dev_priv, CLKGATE_DIS_PSL(pipe), -			     DUPS1_GATING_DIS | DUPS2_GATING_DIS, 0); +	intel_de_rmw(dev_priv, CLKGATE_DIS_PSL(pipe), +		     DUPS1_GATING_DIS | DUPS2_GATING_DIS, +		     enable ? DUPS1_GATING_DIS | DUPS2_GATING_DIS : 0);  }  /* Wa_2006604312:icl,ehl */ @@ -206,10 +204,9 @@ static void  icl_wa_scalerclkgating(struct drm_i915_private *dev_priv, enum pipe pipe,  		       bool enable)  { -	if (enable) -		intel_de_rmw(dev_priv, CLKGATE_DIS_PSL(pipe), 0, DPFR_GATING_DIS); -	else -		intel_de_rmw(dev_priv, CLKGATE_DIS_PSL(pipe), DPFR_GATING_DIS, 0); +	intel_de_rmw(dev_priv, CLKGATE_DIS_PSL(pipe), +		     DPFR_GATING_DIS, +		     enable ? DPFR_GATING_DIS : 0);  }  /* Wa_1604331009:icl,jsl,ehl */ @@ -217,7 +214,8 @@ static void  icl_wa_cursorclkgating(struct drm_i915_private *dev_priv, enum pipe pipe,  		       bool enable)  { -	intel_de_rmw(dev_priv, CLKGATE_DIS_PSL(pipe), CURSOR_GATING_DIS, +	intel_de_rmw(dev_priv, CLKGATE_DIS_PSL(pipe), +		     CURSOR_GATING_DIS,  		     enable ? CURSOR_GATING_DIS : 0);  } @@ -397,7 +395,6 @@ void intel_enable_transcoder(const struct intel_crtc_state *new_crtc_state)  	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);  	enum transcoder cpu_transcoder = new_crtc_state->cpu_transcoder;  	enum pipe pipe = crtc->pipe; -	i915_reg_t reg;  	u32 val;  	drm_dbg_kms(&dev_priv->drm, "enabling pipe %c\n", pipe_name(pipe)); @@ -430,16 +427,16 @@ void intel_enable_transcoder(const struct intel_crtc_state *new_crtc_state)  		intel_de_rmw(dev_priv, PIPE_ARB_CTL(pipe),  			     0, PIPE_ARB_USE_PROG_SLOTS); -	reg = TRANSCONF(cpu_transcoder); -	val = intel_de_read(dev_priv, reg); +	val = intel_de_read(dev_priv, TRANSCONF(cpu_transcoder));  	if (val & TRANSCONF_ENABLE) {  		/* we keep both pipes enabled on 830 */  		drm_WARN_ON(&dev_priv->drm, !IS_I830(dev_priv));  		return;  	} -	intel_de_write(dev_priv, reg, val | TRANSCONF_ENABLE); -	intel_de_posting_read(dev_priv, reg); +	intel_de_write(dev_priv, TRANSCONF(cpu_transcoder), +		       val | TRANSCONF_ENABLE); +	intel_de_posting_read(dev_priv, TRANSCONF(cpu_transcoder));  	/*  	 * Until the pipe starts PIPEDSL reads will return a stale value, @@ -458,7 +455,6 @@ void intel_disable_transcoder(const struct intel_crtc_state *old_crtc_state)  	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);  	enum transcoder cpu_transcoder = old_crtc_state->cpu_transcoder;  	enum pipe pipe = crtc->pipe; -	i915_reg_t reg;  	u32 val;  	drm_dbg_kms(&dev_priv->drm, "disabling pipe %c\n", pipe_name(pipe)); @@ -469,8 +465,7 @@ void intel_disable_transcoder(const struct intel_crtc_state *old_crtc_state)  	 */  	assert_planes_disabled(crtc); -	reg = TRANSCONF(cpu_transcoder); -	val = intel_de_read(dev_priv, reg); +	val = intel_de_read(dev_priv, TRANSCONF(cpu_transcoder));  	if ((val & TRANSCONF_ENABLE) == 0)  		return; @@ -485,14 +480,12 @@ void intel_disable_transcoder(const struct intel_crtc_state *old_crtc_state)  	if (!IS_I830(dev_priv))  		val &= ~TRANSCONF_ENABLE; -	if (DISPLAY_VER(dev_priv) >= 14) -		intel_de_rmw(dev_priv, MTL_CHICKEN_TRANS(cpu_transcoder), -			     FECSTALL_DIS_DPTSTREAM_DPTTG, 0); -	else if (DISPLAY_VER(dev_priv) >= 12) -		intel_de_rmw(dev_priv, CHICKEN_TRANS(cpu_transcoder), +	intel_de_write(dev_priv, TRANSCONF(cpu_transcoder), val); + +	if (DISPLAY_VER(dev_priv) >= 12) +		intel_de_rmw(dev_priv, hsw_chicken_trans_reg(dev_priv, cpu_transcoder),  			     FECSTALL_DIS_DPTSTREAM_DPTTG, 0); -	intel_de_write(dev_priv, reg, val);  	if ((val & TRANSCONF_ENABLE) == 0)  		intel_wait_for_pipe_off(old_crtc_state);  } @@ -896,6 +889,48 @@ static bool needs_async_flip_vtd_wa(const struct intel_crtc_state *crtc_state)  		(DISPLAY_VER(i915) == 9 || IS_BROADWELL(i915) || IS_HASWELL(i915));  } +static void intel_encoders_audio_enable(struct intel_atomic_state *state, +					struct intel_crtc *crtc) +{ +	const struct intel_crtc_state *crtc_state = +		intel_atomic_get_new_crtc_state(state, crtc); +	const struct drm_connector_state *conn_state; +	struct drm_connector *conn; +	int i; + +	for_each_new_connector_in_state(&state->base, conn, conn_state, i) { +		struct intel_encoder *encoder = +			to_intel_encoder(conn_state->best_encoder); + +		if (conn_state->crtc != &crtc->base) +			continue; + +		if (encoder->audio_enable) +			encoder->audio_enable(encoder, crtc_state, conn_state); +	} +} + +static void intel_encoders_audio_disable(struct intel_atomic_state *state, +					 struct intel_crtc *crtc) +{ +	const struct intel_crtc_state *old_crtc_state = +		intel_atomic_get_old_crtc_state(state, crtc); +	const struct drm_connector_state *old_conn_state; +	struct drm_connector *conn; +	int i; + +	for_each_old_connector_in_state(&state->base, conn, old_conn_state, i) { +		struct intel_encoder *encoder = +			to_intel_encoder(old_conn_state->best_encoder); + +		if (old_conn_state->crtc != &crtc->base) +			continue; + +		if (encoder->audio_disable) +			encoder->audio_disable(encoder, old_crtc_state, old_conn_state); +	} +} +  #define is_enabling(feature, old_crtc_state, new_crtc_state) \  	((!(old_crtc_state)->feature || intel_crtc_needs_modeset(new_crtc_state)) && \  	 (new_crtc_state)->feature) @@ -906,12 +941,18 @@ static bool needs_async_flip_vtd_wa(const struct intel_crtc_state *crtc_state)  static bool planes_enabling(const struct intel_crtc_state *old_crtc_state,  			    const struct intel_crtc_state *new_crtc_state)  { +	if (!new_crtc_state->hw.active) +		return false; +  	return is_enabling(active_planes, old_crtc_state, new_crtc_state);  }  static bool planes_disabling(const struct intel_crtc_state *old_crtc_state,  			     const struct intel_crtc_state *new_crtc_state)  { +	if (!old_crtc_state->hw.active) +		return false; +  	return is_disabling(active_planes, old_crtc_state, new_crtc_state);  } @@ -928,6 +969,9 @@ static bool vrr_params_changed(const struct intel_crtc_state *old_crtc_state,  static bool vrr_enabling(const struct intel_crtc_state *old_crtc_state,  			 const struct intel_crtc_state *new_crtc_state)  { +	if (!new_crtc_state->hw.active) +		return false; +  	return is_enabling(vrr.enable, old_crtc_state, new_crtc_state) ||  		(new_crtc_state->vrr.enable &&  		 (new_crtc_state->update_m_n || new_crtc_state->update_lrr || @@ -937,12 +981,37 @@ static bool vrr_enabling(const struct intel_crtc_state *old_crtc_state,  static bool vrr_disabling(const struct intel_crtc_state *old_crtc_state,  			  const struct intel_crtc_state *new_crtc_state)  { +	if (!old_crtc_state->hw.active) +		return false; +  	return is_disabling(vrr.enable, old_crtc_state, new_crtc_state) ||  		(old_crtc_state->vrr.enable &&  		 (new_crtc_state->update_m_n || new_crtc_state->update_lrr ||  		  vrr_params_changed(old_crtc_state, new_crtc_state)));  } +static bool audio_enabling(const struct intel_crtc_state *old_crtc_state, +			   const struct intel_crtc_state *new_crtc_state) +{ +	if (!new_crtc_state->hw.active) +		return false; + +	return is_enabling(has_audio, old_crtc_state, new_crtc_state) || +		(new_crtc_state->has_audio && +		 memcmp(old_crtc_state->eld, new_crtc_state->eld, MAX_ELD_BYTES) != 0); +} + +static bool audio_disabling(const struct intel_crtc_state *old_crtc_state, +			    const struct intel_crtc_state *new_crtc_state) +{ +	if (!old_crtc_state->hw.active) +		return false; + +	return is_disabling(has_audio, old_crtc_state, new_crtc_state) || +		(old_crtc_state->has_audio && +		 memcmp(old_crtc_state->eld, new_crtc_state->eld, MAX_ELD_BYTES) != 0); +} +  #undef is_disabling  #undef is_enabling @@ -983,6 +1052,9 @@ static void intel_post_plane_update(struct intel_atomic_state *state,  	if (intel_crtc_needs_color_update(new_crtc_state))  		intel_color_post_update(new_crtc_state); + +	if (audio_enabling(old_crtc_state, new_crtc_state)) +		intel_encoders_audio_enable(state, crtc);  }  static void intel_crtc_enable_flip_done(struct intel_atomic_state *state, @@ -1066,6 +1138,9 @@ static void intel_pre_plane_update(struct intel_atomic_state *state,  		intel_crtc_update_active_timings(old_crtc_state, false);  	} +	if (audio_disabling(old_crtc_state, new_crtc_state)) +		intel_encoders_audio_disable(state, crtc); +  	intel_drrs_deactivate(old_crtc_state);  	intel_psr_pre_plane_update(state, crtc); @@ -1501,12 +1576,9 @@ static void hsw_set_linetime_wm(const struct intel_crtc_state *crtc_state)  static void hsw_set_frame_start_delay(const struct intel_crtc_state *crtc_state)  {  	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); -	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); -	enum transcoder transcoder = crtc_state->cpu_transcoder; -	i915_reg_t reg = DISPLAY_VER(dev_priv) >= 14 ? MTL_CHICKEN_TRANS(transcoder) : -			 CHICKEN_TRANS(transcoder); +	struct drm_i915_private *i915 = to_i915(crtc->base.dev); -	intel_de_rmw(dev_priv, reg, +	intel_de_rmw(i915, hsw_chicken_trans_reg(i915, crtc_state->cpu_transcoder),  		     HSW_FRAME_START_DELAY_MASK,  		     HSW_FRAME_START_DELAY(crtc_state->framestart_delay - 1));  } @@ -1784,31 +1856,31 @@ bool intel_phy_is_combo(struct drm_i915_private *dev_priv, enum phy phy)  bool intel_phy_is_tc(struct drm_i915_private *dev_priv, enum phy phy)  { +	/* +	 * DG2's "TC1", although TC-capable output, doesn't share the same flow +	 * as other platforms on the display engine side and rather rely on the +	 * SNPS PHY, that is programmed separately +	 */  	if (IS_DG2(dev_priv)) -		/* DG2's "TC1" output uses a SNPS PHY */  		return false; -	else if (IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER_FULL(dev_priv) == IP_VER(14, 0)) + +	if (DISPLAY_VER(dev_priv) >= 13)  		return phy >= PHY_F && phy <= PHY_I;  	else if (IS_TIGERLAKE(dev_priv))  		return phy >= PHY_D && phy <= PHY_I;  	else if (IS_ICELAKE(dev_priv))  		return phy >= PHY_C && phy <= PHY_F; -	else -		return false; + +	return false;  }  bool intel_phy_is_snps(struct drm_i915_private *dev_priv, enum phy phy)  { -	if (phy == PHY_NONE) -		return false; -	else if (IS_DG2(dev_priv)) -		/* -		 * All four "combo" ports and the TC1 port (PHY E) use -		 * Synopsis PHYs. -		 */ -		return phy <= PHY_E; - -	return false; +	/* +	 * For DG2, and for DG2 only, all four "combo" ports and the TC1 port +	 * (PHY E) use Synopsis PHYs. See intel_phy_is_tc(). +	 */ +	return IS_DG2(dev_priv) && phy > PHY_NONE && phy <= PHY_E;  }  enum phy intel_port_to_phy(struct drm_i915_private *i915, enum port port) @@ -2397,15 +2469,15 @@ static void compute_m_n(u32 *ret_m, u32 *ret_n,  }  void -intel_link_compute_m_n(u16 bits_per_pixel, int nlanes, +intel_link_compute_m_n(u16 bits_per_pixel_x16, 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; - -	if (fec_enable) -		data_clock = intel_dp_mode_to_fec_clock(data_clock); +	u32 link_symbol_clock = intel_dp_link_symbol_clock(link_clock); +	u32 data_m = intel_dp_effective_data_rate(pixel_clock, bits_per_pixel_x16, +						  bw_overhead); +	u32 data_n = intel_dp_max_data_rate(link_clock, nlanes);  	/*  	 * Windows/BIOS uses fixed M/N values always. Follow suit. @@ -2416,11 +2488,11 @@ 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, -		    pixel_clock, link_clock, +		    pixel_clock, link_symbol_clock,  		    0x80000);  } @@ -2555,7 +2627,7 @@ static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_sta  		crtc_vblank_start = 1;  	} -	if (DISPLAY_VER(dev_priv) > 3) +	if (DISPLAY_VER(dev_priv) >= 4)  		intel_de_write(dev_priv, TRANS_VSYNCSHIFT(cpu_transcoder),  			       vsyncshift); @@ -2838,67 +2910,6 @@ static void i9xx_get_pfit_config(struct intel_crtc_state *crtc_state)  		intel_de_read(dev_priv, PFIT_PGM_RATIOS);  } -static void vlv_crtc_clock_get(struct intel_crtc *crtc, -			       struct intel_crtc_state *pipe_config) -{ -	struct drm_device *dev = crtc->base.dev; -	struct drm_i915_private *dev_priv = to_i915(dev); -	enum pipe pipe = crtc->pipe; -	struct dpll clock; -	u32 mdiv; -	int refclk = 100000; - -	/* In case of DSI, DPLL will not be used */ -	if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) == 0) -		return; - -	vlv_dpio_get(dev_priv); -	mdiv = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW3(pipe)); -	vlv_dpio_put(dev_priv); - -	clock.m1 = (mdiv >> DPIO_M1DIV_SHIFT) & 7; -	clock.m2 = mdiv & DPIO_M2DIV_MASK; -	clock.n = (mdiv >> DPIO_N_SHIFT) & 0xf; -	clock.p1 = (mdiv >> DPIO_P1_SHIFT) & 7; -	clock.p2 = (mdiv >> DPIO_P2_SHIFT) & 0x1f; - -	pipe_config->port_clock = vlv_calc_dpll_params(refclk, &clock); -} - -static void chv_crtc_clock_get(struct intel_crtc *crtc, -			       struct intel_crtc_state *pipe_config) -{ -	struct drm_device *dev = crtc->base.dev; -	struct drm_i915_private *dev_priv = to_i915(dev); -	enum pipe pipe = crtc->pipe; -	enum dpio_channel port = vlv_pipe_to_channel(pipe); -	struct dpll clock; -	u32 cmn_dw13, pll_dw0, pll_dw1, pll_dw2, pll_dw3; -	int refclk = 100000; - -	/* In case of DSI, DPLL will not be used */ -	if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) == 0) -		return; - -	vlv_dpio_get(dev_priv); -	cmn_dw13 = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW13(port)); -	pll_dw0 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW0(port)); -	pll_dw1 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW1(port)); -	pll_dw2 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW2(port)); -	pll_dw3 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW3(port)); -	vlv_dpio_put(dev_priv); - -	clock.m1 = (pll_dw1 & 0x7) == DPIO_CHV_M1_DIV_BY_2 ? 2 : 0; -	clock.m2 = (pll_dw0 & 0xff) << 22; -	if (pll_dw3 & DPIO_CHV_FRAC_DIV_EN) -		clock.m2 |= pll_dw2 & 0x3fffff; -	clock.n = (pll_dw1 >> DPIO_CHV_N_DIV_SHIFT) & 0xf; -	clock.p1 = (cmn_dw13 >> DPIO_CHV_P1_DIV_SHIFT) & 0x7; -	clock.p2 = (cmn_dw13 >> DPIO_CHV_P2_DIV_SHIFT) & 0x1f; - -	pipe_config->port_clock = chv_calc_dpll_params(refclk, &clock); -} -  static enum intel_output_format  bdw_get_pipe_misc_output_format(struct intel_crtc *crtc)  { @@ -3156,7 +3167,7 @@ static void bdw_set_pipe_misc(const struct intel_crtc_state *crtc_state)  		break;  	case 36:  		/* Port output 12BPC defined for ADLP+ */ -		if (DISPLAY_VER(dev_priv) > 12) +		if (DISPLAY_VER(dev_priv) >= 13)  			val |= PIPE_MISC_BPC_12_ADLP;  		break;  	default: @@ -3213,7 +3224,7 @@ int bdw_get_pipe_misc_bpp(struct intel_crtc *crtc)  	 * MIPI DSI HW readout.  	 */  	case PIPE_MISC_BPC_12_ADLP: -		if (DISPLAY_VER(dev_priv) > 12) +		if (DISPLAY_VER(dev_priv) >= 13)  			return 36;  		fallthrough;  	default: @@ -3735,8 +3746,8 @@ static bool hsw_get_pipe_config(struct intel_crtc *crtc,  	if (!active)  		goto out; -	intel_dsc_get_config(pipe_config);  	intel_bigjoiner_get_config(pipe_config); +	intel_dsc_get_config(pipe_config);  	if (!transcoder_is_dsi(pipe_config->cpu_transcoder) ||  	    DISPLAY_VER(dev_priv) >= 11) @@ -3790,9 +3801,7 @@ static bool hsw_get_pipe_config(struct intel_crtc *crtc,  	}  	if (!transcoder_is_dsi(pipe_config->cpu_transcoder)) { -		tmp = intel_de_read(dev_priv, DISPLAY_VER(dev_priv) >= 14 ? -				    MTL_CHICKEN_TRANS(pipe_config->cpu_transcoder) : -				    CHICKEN_TRANS(pipe_config->cpu_transcoder)); +		tmp = intel_de_read(dev_priv, hsw_chicken_trans_reg(dev_priv, pipe_config->cpu_transcoder));  		pipe_config->framestart_delay = REG_FIELD_GET(HSW_FRAME_START_DELAY_MASK, tmp) + 1;  	} else { @@ -3821,133 +3830,27 @@ bool intel_crtc_get_pipe_config(struct intel_crtc_state *crtc_state)  	return true;  } -static int i9xx_pll_refclk(struct drm_device *dev, -			   const struct intel_crtc_state *pipe_config) -{ -	struct drm_i915_private *dev_priv = to_i915(dev); -	u32 dpll = pipe_config->dpll_hw_state.dpll; - -	if ((dpll & PLL_REF_INPUT_MASK) == PLLB_REF_INPUT_SPREADSPECTRUMIN) -		return dev_priv->display.vbt.lvds_ssc_freq; -	else if (HAS_PCH_SPLIT(dev_priv)) -		return 120000; -	else if (DISPLAY_VER(dev_priv) != 2) -		return 96000; -	else -		return 48000; -} - -/* Returns the clock of the currently programmed mode of the given pipe. */ -void i9xx_crtc_clock_get(struct intel_crtc *crtc, -			 struct intel_crtc_state *pipe_config) -{ -	struct drm_device *dev = crtc->base.dev; -	struct drm_i915_private *dev_priv = to_i915(dev); -	u32 dpll = pipe_config->dpll_hw_state.dpll; -	u32 fp; -	struct dpll clock; -	int port_clock; -	int refclk = i9xx_pll_refclk(dev, pipe_config); - -	if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) -		fp = pipe_config->dpll_hw_state.fp0; -	else -		fp = pipe_config->dpll_hw_state.fp1; - -	clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT; -	if (IS_PINEVIEW(dev_priv)) { -		clock.n = ffs((fp & FP_N_PINEVIEW_DIV_MASK) >> FP_N_DIV_SHIFT) - 1; -		clock.m2 = (fp & FP_M2_PINEVIEW_DIV_MASK) >> FP_M2_DIV_SHIFT; -	} else { -		clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT; -		clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT; -	} - -	if (DISPLAY_VER(dev_priv) != 2) { -		if (IS_PINEVIEW(dev_priv)) -			clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW) >> -				DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW); -		else -			clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK) >> -			       DPLL_FPA01_P1_POST_DIV_SHIFT); - -		switch (dpll & DPLL_MODE_MASK) { -		case DPLLB_MODE_DAC_SERIAL: -			clock.p2 = dpll & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 ? -				5 : 10; -			break; -		case DPLLB_MODE_LVDS: -			clock.p2 = dpll & DPLLB_LVDS_P2_CLOCK_DIV_7 ? -				7 : 14; -			break; -		default: -			drm_dbg_kms(&dev_priv->drm, -				    "Unknown DPLL mode %08x in programmed " -				    "mode\n", (int)(dpll & DPLL_MODE_MASK)); -			return; -		} - -		if (IS_PINEVIEW(dev_priv)) -			port_clock = pnv_calc_dpll_params(refclk, &clock); -		else -			port_clock = i9xx_calc_dpll_params(refclk, &clock); -	} else { -		enum pipe lvds_pipe; - -		if (IS_I85X(dev_priv) && -		    intel_lvds_port_enabled(dev_priv, LVDS, &lvds_pipe) && -		    lvds_pipe == crtc->pipe) { -			u32 lvds = intel_de_read(dev_priv, LVDS); - -			clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >> -				       DPLL_FPA01_P1_POST_DIV_SHIFT); - -			if (lvds & LVDS_CLKB_POWER_UP) -				clock.p2 = 7; -			else -				clock.p2 = 14; -		} else { -			if (dpll & PLL_P1_DIVIDE_BY_TWO) -				clock.p1 = 2; -			else { -				clock.p1 = ((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830) >> -					    DPLL_FPA01_P1_POST_DIV_SHIFT) + 2; -			} -			if (dpll & PLL_P2_DIVIDE_BY_4) -				clock.p2 = 4; -			else -				clock.p2 = 2; -		} - -		port_clock = i9xx_calc_dpll_params(refclk, &clock); -	} - -	/* -	 * This value includes pixel_multiplier. We will use -	 * port_clock to compute adjusted_mode.crtc_clock in the -	 * encoder's get_config() function. -	 */ -	pipe_config->port_clock = port_clock; -} -  int intel_dotclock_calculate(int link_freq,  			     const struct intel_link_m_n *m_n)  {  	/* -	 * The calculation for the data clock is: +	 * The calculation for the data clock -> pixel clock is:  	 * pixel_clock = ((m/n)*(link_clock * nr_lanes))/bpp  	 * But we want to avoid losing precison if possible, so:  	 * pixel_clock = ((m * link_clock * nr_lanes)/(n*bpp))  	 * -	 * and the link clock is simpler: -	 * link_clock = (m * link_clock) / n +	 * and for link freq (10kbs units) -> pixel clock it is: +	 * link_symbol_clock = link_freq * 10 / link_symbol_size +	 * pixel_clock = (m * link_symbol_clock) / n +	 *    or for more precision: +	 * pixel_clock = (m * link_freq * 10) / (n * link_symbol_size)  	 */  	if (!m_n->link_n)  		return 0; -	return DIV_ROUND_UP_ULL(mul_u32_u32(m_n->link_m, link_freq), -				m_n->link_n); +	return DIV_ROUND_UP_ULL(mul_u32_u32(m_n->link_m, link_freq * 10), +				m_n->link_n * intel_dp_link_symbol_size(link_freq));  }  int intel_crtc_dotclock(const struct intel_crtc_state *pipe_config) @@ -4679,6 +4582,7 @@ intel_modeset_pipe_config(struct intel_atomic_state *state,  	if (ret)  		return ret; +	crtc_state->fec_enable = limits->force_fec_pipes & BIT(crtc->pipe);  	crtc_state->max_link_bpp_x16 = limits->max_bpp_x16[crtc->pipe];  	if (crtc_state->pipe_bpp > to_bpp_int(crtc_state->max_link_bpp_x16)) { @@ -5019,6 +4923,8 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,  #define PIPE_CONF_CHECK_X(name) do { \  	if (current_config->name != pipe_config->name) { \ +		BUILD_BUG_ON_MSG(__same_type(current_config->name, bool), \ +				 __stringify(name) " is bool");	\  		pipe_config_mismatch(fastset, crtc, __stringify(name), \  				     "(expected 0x%08x, found 0x%08x)", \  				     current_config->name, \ @@ -5029,6 +4935,8 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,  #define PIPE_CONF_CHECK_X_WITH_MASK(name, mask) do { \  	if ((current_config->name & (mask)) != (pipe_config->name & (mask))) { \ +		BUILD_BUG_ON_MSG(__same_type(current_config->name, bool), \ +				 __stringify(name) " is bool");	\  		pipe_config_mismatch(fastset, crtc, __stringify(name), \  				     "(expected 0x%08x, found 0x%08x)", \  				     current_config->name & (mask), \ @@ -5039,6 +4947,8 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,  #define PIPE_CONF_CHECK_I(name) do { \  	if (current_config->name != pipe_config->name) { \ +		BUILD_BUG_ON_MSG(__same_type(current_config->name, bool), \ +				 __stringify(name) " is bool");	\  		pipe_config_mismatch(fastset, crtc, __stringify(name), \  				     "(expected %i, found %i)", \  				     current_config->name, \ @@ -5049,6 +4959,8 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,  #define PIPE_CONF_CHECK_BOOL(name) do { \  	if (current_config->name != pipe_config->name) { \ +		BUILD_BUG_ON_MSG(!__same_type(current_config->name, bool), \ +				 __stringify(name) " is not bool");	\  		pipe_config_mismatch(fastset, crtc,  __stringify(name), \  				     "(expected %s, found %s)", \  				     str_yes_no(current_config->name), \ @@ -5057,23 +4969,6 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,  	} \  } while (0) -/* - * Checks state where we only read out the enabling, but not the entire - * state itself (like full infoframes or ELD for audio). These states - * require a full modeset on bootup to fix up. - */ -#define PIPE_CONF_CHECK_BOOL_INCOMPLETE(name) do { \ -	if (!fixup_inherited || (!current_config->name && !pipe_config->name)) { \ -		PIPE_CONF_CHECK_BOOL(name); \ -	} else { \ -		pipe_config_mismatch(fastset, crtc, __stringify(name), \ -				     "unable to verify whether state matches exactly, forcing modeset (expected %s, found %s)", \ -				     str_yes_no(current_config->name), \ -				     str_yes_no(pipe_config->name)); \ -		ret = false; \ -	} \ -} while (0) -  #define PIPE_CONF_CHECK_P(name) do { \  	if (current_config->name != pipe_config->name) { \  		pipe_config_mismatch(fastset, crtc, __stringify(name), \ @@ -5204,8 +5099,8 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,  #define PIPE_CONF_QUIRK(quirk) \  	((current_config->quirks | pipe_config->quirks) & (quirk)) -	PIPE_CONF_CHECK_I(hw.enable); -	PIPE_CONF_CHECK_I(hw.active); +	PIPE_CONF_CHECK_BOOL(hw.enable); +	PIPE_CONF_CHECK_BOOL(hw.active);  	PIPE_CONF_CHECK_I(cpu_transcoder);  	PIPE_CONF_CHECK_I(mst_master_transcoder); @@ -5261,8 +5156,10 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,  	PIPE_CONF_CHECK_BOOL(enhanced_framing);  	PIPE_CONF_CHECK_BOOL(fec_enable); -	PIPE_CONF_CHECK_BOOL_INCOMPLETE(has_audio); -	PIPE_CONF_CHECK_BUFFER(eld, MAX_ELD_BYTES); +	if (!fastset) { +		PIPE_CONF_CHECK_BOOL(has_audio); +		PIPE_CONF_CHECK_BUFFER(eld, MAX_ELD_BYTES); +	}  	PIPE_CONF_CHECK_X(gmch_pfit.control);  	/* pfit ratios are autocomputed by the hw on gen4+ */ @@ -5412,9 +5309,9 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,  	PIPE_CONF_CHECK_I(dsc.config.second_line_bpg_offset);  	PIPE_CONF_CHECK_I(dsc.config.nsl_bpg_offset); -	PIPE_CONF_CHECK_I(dsc.compression_enable); -	PIPE_CONF_CHECK_I(dsc.dsc_split); -	PIPE_CONF_CHECK_I(dsc.compressed_bpp); +	PIPE_CONF_CHECK_BOOL(dsc.compression_enable); +	PIPE_CONF_CHECK_BOOL(dsc.dsc_split); +	PIPE_CONF_CHECK_I(dsc.compressed_bpp_x16);  	PIPE_CONF_CHECK_BOOL(splitter.enable);  	PIPE_CONF_CHECK_I(splitter.link_count); @@ -5432,7 +5329,6 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config,  #undef PIPE_CONF_CHECK_X  #undef PIPE_CONF_CHECK_I  #undef PIPE_CONF_CHECK_BOOL -#undef PIPE_CONF_CHECK_BOOL_INCOMPLETE  #undef PIPE_CONF_CHECK_P  #undef PIPE_CONF_CHECK_FLAGS  #undef PIPE_CONF_CHECK_COLOR_LUT @@ -5523,6 +5419,16 @@ int intel_modeset_pipes_in_mask_early(struct intel_atomic_state *state,  	return 0;  } +static void +intel_crtc_flag_modeset(struct intel_crtc_state *crtc_state) +{ +	crtc_state->uapi.mode_changed = true; + +	crtc_state->update_pipe = false; +	crtc_state->update_m_n = false; +	crtc_state->update_lrr = false; +} +  /**   * intel_modeset_all_pipes_late - force a full modeset on all pipes   * @state: intel atomic state @@ -5556,9 +5462,8 @@ int intel_modeset_all_pipes_late(struct intel_atomic_state *state,  		if (ret)  			return ret; -		crtc_state->update_pipe = false; -		crtc_state->update_m_n = false; -		crtc_state->update_lrr = false; +		intel_crtc_flag_modeset(crtc_state); +  		crtc_state->update_planes |= crtc_state->active_planes;  		crtc_state->async_flip_planes = 0;  		crtc_state->do_async_flip = false; @@ -5671,17 +5576,17 @@ static void intel_crtc_check_fastset(const struct intel_crtc_state *old_crtc_sta  	else  		new_crtc_state->uapi.mode_changed = false; -	if (intel_crtc_needs_modeset(new_crtc_state) || -	    intel_compare_link_m_n(&old_crtc_state->dp_m_n, +	if (intel_compare_link_m_n(&old_crtc_state->dp_m_n,  				   &new_crtc_state->dp_m_n))  		new_crtc_state->update_m_n = false; -	if (intel_crtc_needs_modeset(new_crtc_state) || -	    (old_crtc_state->hw.adjusted_mode.crtc_vtotal == new_crtc_state->hw.adjusted_mode.crtc_vtotal && +	if ((old_crtc_state->hw.adjusted_mode.crtc_vtotal == new_crtc_state->hw.adjusted_mode.crtc_vtotal &&  	     old_crtc_state->hw.adjusted_mode.crtc_vblank_end == new_crtc_state->hw.adjusted_mode.crtc_vblank_end))  		new_crtc_state->update_lrr = false; -	if (!intel_crtc_needs_modeset(new_crtc_state)) +	if (intel_crtc_needs_modeset(new_crtc_state)) +		intel_crtc_flag_modeset(new_crtc_state); +	else  		new_crtc_state->update_pipe = true;  } @@ -6021,6 +5926,17 @@ static int intel_async_flip_check_uapi(struct intel_atomic_state *state,  		return -EINVAL;  	} +	/* +	 * FIXME: Bigjoiner+async flip is busted currently. +	 * Remove this check once the issues are fixed. +	 */ +	if (new_crtc_state->bigjoiner_pipes) { +		drm_dbg_kms(&i915->drm, +			    "[CRTC:%d:%s] async flip disallowed with bigjoiner\n", +			    crtc->base.base.id, crtc->base.name); +		return -EINVAL; +	} +  	for_each_oldnew_intel_plane_in_state(state, plane, old_plane_state,  					     new_plane_state, i) {  		if (plane->pipe != crtc->pipe) @@ -6453,15 +6369,14 @@ int intel_atomic_check(struct drm_device *dev,  		if (!new_crtc_state->hw.enable || intel_crtc_needs_modeset(new_crtc_state))  			continue; +		if (intel_dp_mst_crtc_needs_modeset(state, crtc)) +			intel_crtc_flag_modeset(new_crtc_state); +  		if (intel_dp_mst_is_slave_trans(new_crtc_state)) {  			enum transcoder master = new_crtc_state->mst_master_transcoder; -			if (intel_cpu_transcoders_need_modeset(state, BIT(master))) { -				new_crtc_state->uapi.mode_changed = true; -				new_crtc_state->update_pipe = false; -				new_crtc_state->update_m_n = false; -				new_crtc_state->update_lrr = false; -			} +			if (intel_cpu_transcoders_need_modeset(state, BIT(master))) +				intel_crtc_flag_modeset(new_crtc_state);  		}  		if (is_trans_port_sync_mode(new_crtc_state)) { @@ -6470,21 +6385,13 @@ int intel_atomic_check(struct drm_device *dev,  			if (new_crtc_state->master_transcoder != INVALID_TRANSCODER)  				trans |= BIT(new_crtc_state->master_transcoder); -			if (intel_cpu_transcoders_need_modeset(state, trans)) { -				new_crtc_state->uapi.mode_changed = true; -				new_crtc_state->update_pipe = false; -				new_crtc_state->update_m_n = false; -				new_crtc_state->update_lrr = false; -			} +			if (intel_cpu_transcoders_need_modeset(state, trans)) +				intel_crtc_flag_modeset(new_crtc_state);  		}  		if (new_crtc_state->bigjoiner_pipes) { -			if (intel_pipes_need_modeset(state, new_crtc_state->bigjoiner_pipes)) { -				new_crtc_state->uapi.mode_changed = true; -				new_crtc_state->update_pipe = false; -				new_crtc_state->update_m_n = false; -				new_crtc_state->update_lrr = false; -			} +			if (intel_pipes_need_modeset(state, new_crtc_state->bigjoiner_pipes)) +				intel_crtc_flag_modeset(new_crtc_state);  		}  	} @@ -6505,10 +6412,6 @@ int intel_atomic_check(struct drm_device *dev,  		goto fail;  	} -	ret = drm_dp_mst_atomic_check(&state->base); -	if (ret) -		goto fail; -  	ret = intel_atomic_check_planes(state);  	if (ret)  		goto fail; @@ -6744,8 +6647,8 @@ static void intel_enable_crtc(struct intel_atomic_state *state,  	intel_crtc_enable_pipe_crc(crtc);  } -static void intel_update_crtc(struct intel_atomic_state *state, -			      struct intel_crtc *crtc) +static void intel_pre_update_crtc(struct intel_atomic_state *state, +				  struct intel_crtc *crtc)  {  	struct drm_i915_private *i915 = to_i915(state->base.dev);  	const struct intel_crtc_state *old_crtc_state = @@ -6787,6 +6690,15 @@ static void intel_update_crtc(struct intel_atomic_state *state,  		intel_color_commit_noarm(new_crtc_state);  	intel_crtc_planes_update_noarm(state, crtc); +} + +static void intel_update_crtc(struct intel_atomic_state *state, +			      struct intel_crtc *crtc) +{ +	const struct intel_crtc_state *old_crtc_state = +		intel_atomic_get_old_crtc_state(state, crtc); +	struct intel_crtc_state *new_crtc_state = +		intel_atomic_get_new_crtc_state(state, crtc);  	/* Perform vblank evasion around commit operation */  	intel_pipe_update_start(state, crtc); @@ -6815,7 +6727,7 @@ static void intel_update_crtc(struct intel_atomic_state *state,  	 * valid pipe configuration from the BIOS we need to take care  	 * of enabling them on the CRTC's first fastset.  	 */ -	if (intel_crtc_needs_fastset(new_crtc_state) && !modeset && +	if (intel_crtc_needs_fastset(new_crtc_state) &&  	    old_crtc_state->inherited)  		intel_crtc_arm_fifo_underrun(crtc, new_crtc_state);  } @@ -6853,10 +6765,11 @@ static void intel_commit_modeset_disables(struct intel_atomic_state *state)  		if (!intel_crtc_needs_modeset(new_crtc_state))  			continue; +		intel_pre_plane_update(state, crtc); +  		if (!old_crtc_state->hw.active)  			continue; -		intel_pre_plane_update(state, crtc);  		intel_crtc_disable_planes(state, crtc);  	} @@ -6910,6 +6823,13 @@ static void intel_commit_modeset_enables(struct intel_atomic_state *state)  			continue;  		intel_enable_crtc(state, crtc); +		intel_pre_update_crtc(state, crtc); +	} + +	for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { +		if (!new_crtc_state->hw.active) +			continue; +  		intel_update_crtc(state, crtc);  	}  } @@ -6947,6 +6867,15 @@ static void skl_commit_modeset_enables(struct intel_atomic_state *state)  	 * So first lets enable all pipes that do not need a fullmodeset as  	 * those don't have any external dependency.  	 */ +	for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { +		enum pipe pipe = crtc->pipe; + +		if ((update_pipes & BIT(pipe)) == 0) +			continue; + +		intel_pre_update_crtc(state, crtc); +	} +  	while (update_pipes) {  		for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,  						    new_crtc_state, i) { @@ -7023,6 +6952,15 @@ static void skl_commit_modeset_enables(struct intel_atomic_state *state)  		if ((update_pipes & BIT(pipe)) == 0)  			continue; +		intel_pre_update_crtc(state, crtc); +	} + +	for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { +		enum pipe pipe = crtc->pipe; + +		if ((update_pipes & BIT(pipe)) == 0) +			continue; +  		drm_WARN_ON(&dev_priv->drm, skl_ddb_allocation_overlaps(&new_crtc_state->wm.skl.ddb,  									entries, I915_MAX_PIPES, pipe)); @@ -7036,49 +6974,24 @@ static void skl_commit_modeset_enables(struct intel_atomic_state *state)  	drm_WARN_ON(&dev_priv->drm, update_pipes);  } -static void intel_atomic_helper_free_state(struct drm_i915_private *dev_priv) -{ -	struct intel_atomic_state *state, *next; -	struct llist_node *freed; - -	freed = llist_del_all(&dev_priv->display.atomic_helper.free_list); -	llist_for_each_entry_safe(state, next, freed, freed) -		drm_atomic_state_put(&state->base); -} - -void intel_atomic_helper_free_state_worker(struct work_struct *work) -{ -	struct drm_i915_private *dev_priv = -		container_of(work, typeof(*dev_priv), display.atomic_helper.free_work); - -	intel_atomic_helper_free_state(dev_priv); -} -  static void intel_atomic_commit_fence_wait(struct intel_atomic_state *intel_state)  { -	struct wait_queue_entry wait_fence, wait_reset; -	struct drm_i915_private *dev_priv = to_i915(intel_state->base.dev); - -	init_wait_entry(&wait_fence, 0); -	init_wait_entry(&wait_reset, 0); -	for (;;) { -		prepare_to_wait(&intel_state->commit_ready.wait, -				&wait_fence, TASK_UNINTERRUPTIBLE); -		prepare_to_wait(bit_waitqueue(&to_gt(dev_priv)->reset.flags, -					      I915_RESET_MODESET), -				&wait_reset, TASK_UNINTERRUPTIBLE); - +	struct drm_i915_private *i915 = to_i915(intel_state->base.dev); +	struct drm_plane *plane; +	struct drm_plane_state *new_plane_state; +	int ret, i; -		if (i915_sw_fence_done(&intel_state->commit_ready) || -		    test_bit(I915_RESET_MODESET, &to_gt(dev_priv)->reset.flags)) -			break; +	for_each_new_plane_in_state(&intel_state->base, plane, new_plane_state, i) { +		if (new_plane_state->fence) { +			ret = dma_fence_wait_timeout(new_plane_state->fence, false, +						     i915_fence_timeout(i915)); +			if (ret <= 0) +				break; -		schedule(); +			dma_fence_put(new_plane_state->fence); +			new_plane_state->fence = NULL; +		}  	} -	finish_wait(&intel_state->commit_ready.wait, &wait_fence); -	finish_wait(bit_waitqueue(&to_gt(dev_priv)->reset.flags, -				  I915_RESET_MODESET), -		    &wait_reset);  }  static void intel_atomic_cleanup_work(struct work_struct *work) @@ -7096,8 +7009,6 @@ static void intel_atomic_cleanup_work(struct work_struct *work)  	drm_atomic_helper_cleanup_planes(&i915->drm, &state->base);  	drm_atomic_helper_commit_cleanup_done(&state->base);  	drm_atomic_state_put(&state->base); - -	intel_atomic_helper_free_state(i915);  }  static void intel_atomic_prepare_plane_clear_colors(struct intel_atomic_state *state) @@ -7370,32 +7281,6 @@ static void intel_atomic_commit_work(struct work_struct *work)  	intel_atomic_commit_tail(state);  } -static int -intel_atomic_commit_ready(struct i915_sw_fence *fence, -			  enum i915_sw_fence_notify notify) -{ -	struct intel_atomic_state *state = -		container_of(fence, struct intel_atomic_state, commit_ready); - -	switch (notify) { -	case FENCE_COMPLETE: -		/* we do blocking waits in the worker, nothing to do here */ -		break; -	case FENCE_FREE: -		{ -			struct drm_i915_private *i915 = to_i915(state->base.dev); -			struct intel_atomic_helper *helper = -				&i915->display.atomic_helper; - -			if (llist_add(&state->freed, &helper->free_list)) -				queue_work(i915->unordered_wq, &helper->free_work); -			break; -		} -	} - -	return NOTIFY_DONE; -} -  static void intel_atomic_track_fbs(struct intel_atomic_state *state)  {  	struct intel_plane_state *old_plane_state, *new_plane_state; @@ -7418,10 +7303,6 @@ int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *_state,  	state->wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); -	drm_atomic_state_get(&state->base); -	i915_sw_fence_init(&state->commit_ready, -			   intel_atomic_commit_ready); -  	/*  	 * The intel_legacy_cursor_update() fast path takes care  	 * of avoiding the vblank waits for simple cursor @@ -7454,7 +7335,6 @@ int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *_state,  	if (ret) {  		drm_dbg_atomic(&dev_priv->drm,  			       "Preparing state failed with %i\n", ret); -		i915_sw_fence_commit(&state->commit_ready);  		intel_runtime_pm_put(&dev_priv->runtime_pm, state->wakeref);  		return ret;  	} @@ -7470,12 +7350,10 @@ int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *_state,  		struct intel_crtc *crtc;  		int i; -		i915_sw_fence_commit(&state->commit_ready); -  		for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i)  			intel_color_cleanup_commit(new_crtc_state); -		drm_atomic_helper_cleanup_planes(dev, &state->base); +		drm_atomic_helper_unprepare_planes(dev, &state->base);  		intel_runtime_pm_put(&dev_priv->runtime_pm, state->wakeref);  		return ret;  	} @@ -7485,7 +7363,6 @@ int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *_state,  	drm_atomic_state_get(&state->base);  	INIT_WORK(&state->base.commit_work, intel_atomic_commit_work); -	i915_sw_fence_commit(&state->commit_ready);  	if (nonblock && state->modeset) {  		queue_work(dev_priv->display.wq.modeset, &state->base.commit_work);  	} else if (nonblock) { @@ -7856,6 +7733,16 @@ enum drm_mode_status intel_mode_valid(struct drm_device *dev,  	    mode->vtotal > vtotal_max)  		return MODE_V_ILLEGAL; +	return MODE_OK; +} + +enum drm_mode_status intel_cpu_transcoder_mode_valid(struct drm_i915_private *dev_priv, +						     const struct drm_display_mode *mode) +{ +	/* +	 * Additional transcoder timing limits, +	 * excluding BXT/GLK DSI transcoders. +	 */  	if (DISPLAY_VER(dev_priv) >= 5) {  		if (mode->hdisplay < 64 ||  		    mode->htotal - mode->hdisplay < 32) @@ -7875,7 +7762,7 @@ enum drm_mode_status intel_mode_valid(struct drm_device *dev,  	 * Cantiga+ cannot handle modes with a hsync front porch of 0.  	 * WaPruneModeWithIncorrectHsyncOffset:ctg,elk,ilk,snb,ivb,vlv,hsw.  	 */ -	if ((DISPLAY_VER(dev_priv) > 4 || IS_G4X(dev_priv)) && +	if ((DISPLAY_VER(dev_priv) >= 5 || IS_G4X(dev_priv)) &&  	    mode->hsync_start == mode->hdisplay)  		return MODE_H_ILLEGAL; | 
