diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_ddi.c')
| -rw-r--r-- | drivers/gpu/drm/i915/display/intel_ddi.c | 225 | 
1 files changed, 171 insertions, 54 deletions
| diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 9151d5add960..12a29363e5df 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -25,6 +25,7 @@   *   */ +#include <linux/iopoll.h>  #include <linux/string_helpers.h>  #include <drm/display/drm_scdc_helper.h> @@ -2210,16 +2211,87 @@ static void intel_dp_sink_set_msa_timing_par_ignore_state(struct intel_dp *intel  }  static void intel_dp_sink_set_fec_ready(struct intel_dp *intel_dp, -					const struct intel_crtc_state *crtc_state) +					const struct intel_crtc_state *crtc_state, +					bool enable)  {  	struct drm_i915_private *i915 = dp_to_i915(intel_dp);  	if (!crtc_state->fec_enable)  		return; -	if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_FEC_CONFIGURATION, DP_FEC_READY) <= 0) -		drm_dbg_kms(&i915->drm, -			    "Failed to set FEC_READY in the sink\n"); +	if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_FEC_CONFIGURATION, +			       enable ? DP_FEC_READY : 0) <= 0) +		drm_dbg_kms(&i915->drm, "Failed to set FEC_READY to %s in the sink\n", +			    enable ? "enabled" : "disabled"); + +	if (enable && +	    drm_dp_dpcd_writeb(&intel_dp->aux, DP_FEC_STATUS, +			       DP_FEC_DECODE_EN_DETECTED | DP_FEC_DECODE_DIS_DETECTED) <= 0) +		drm_dbg_kms(&i915->drm, "Failed to clear FEC detected flags\n"); +} + +static int read_fec_detected_status(struct drm_dp_aux *aux) +{ +	int ret; +	u8 status; + +	ret = drm_dp_dpcd_readb(aux, DP_FEC_STATUS, &status); +	if (ret < 0) +		return ret; + +	return status; +} + +static void wait_for_fec_detected(struct drm_dp_aux *aux, bool enabled) +{ +	struct drm_i915_private *i915 = to_i915(aux->drm_dev); +	int mask = enabled ? DP_FEC_DECODE_EN_DETECTED : DP_FEC_DECODE_DIS_DETECTED; +	int status; +	int err; + +	err = readx_poll_timeout(read_fec_detected_status, aux, status, +				 status & mask || status < 0, +				 10000, 200000); + +	if (!err && status >= 0) +		return; + +	if (err == -ETIMEDOUT) +		drm_dbg_kms(&i915->drm, "Timeout waiting for FEC %s to get detected\n", +			    str_enabled_disabled(enabled)); +	else +		drm_dbg_kms(&i915->drm, "FEC detected status read error: %d\n", status); +} + +void intel_ddi_wait_for_fec_status(struct intel_encoder *encoder, +				   const struct intel_crtc_state *crtc_state, +				   bool enabled) +{ +	struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); +	struct intel_dp *intel_dp = enc_to_intel_dp(encoder); +	int ret; + +	if (!crtc_state->fec_enable) +		return; + +	if (enabled) +		ret = intel_de_wait_for_set(i915, dp_tp_status_reg(encoder, crtc_state), +					    DP_TP_STATUS_FEC_ENABLE_LIVE, 1); +	else +		ret = intel_de_wait_for_clear(i915, dp_tp_status_reg(encoder, crtc_state), +					      DP_TP_STATUS_FEC_ENABLE_LIVE, 1); + +	if (ret) +		drm_err(&i915->drm, +			"Timeout waiting for FEC live state to get %s\n", +			str_enabled_disabled(enabled)); + +	/* +	 * At least the Synoptics MST hub doesn't set the detected flag for +	 * FEC decoding disabling so skip waiting for that. +	 */ +	if (enabled) +		wait_for_fec_detected(&intel_dp->aux, enabled);  }  static void intel_ddi_enable_fec(struct intel_encoder *encoder, @@ -2234,8 +2306,8 @@ static void intel_ddi_enable_fec(struct intel_encoder *encoder,  		     0, DP_TP_CTL_FEC_ENABLE);  } -static void intel_ddi_disable_fec_state(struct intel_encoder *encoder, -					const struct intel_crtc_state *crtc_state) +static void intel_ddi_disable_fec(struct intel_encoder *encoder, +				  const struct intel_crtc_state *crtc_state)  {  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); @@ -2466,13 +2538,17 @@ static void mtl_ddi_pre_enable_dp(struct intel_atomic_state *state,  		intel_dp_set_power(intel_dp, DP_SET_POWER_D0);  	intel_dp_configure_protocol_converter(intel_dp, crtc_state); -	intel_dp_sink_set_decompression_state(intel_dp, crtc_state, true); +	if (!is_mst) +		intel_dp_sink_enable_decompression(state, +						   to_intel_connector(conn_state->connector), +						   crtc_state); +  	/*  	 * DDI FEC: "anticipates enabling FEC encoding sets the FEC_READY bit  	 * in the FEC_CONFIGURATION register to 1 before initiating link  	 * training  	 */ -	intel_dp_sink_set_fec_ready(intel_dp, crtc_state); +	intel_dp_sink_set_fec_ready(intel_dp, crtc_state, true);  	intel_dp_check_frl_training(intel_dp);  	intel_dp_pcon_dsc_configure(intel_dp, crtc_state); @@ -2505,7 +2581,8 @@ static void mtl_ddi_pre_enable_dp(struct intel_atomic_state *state,  	/* 6.o Configure and enable FEC if needed */  	intel_ddi_enable_fec(encoder, crtc_state); -	intel_dsc_dp_pps_write(encoder, crtc_state); +	if (!is_mst) +		intel_dsc_dp_pps_write(encoder, crtc_state);  }  static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state, @@ -2616,13 +2693,16 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state,  		intel_dp_set_power(intel_dp, DP_SET_POWER_D0);  	intel_dp_configure_protocol_converter(intel_dp, crtc_state); -	intel_dp_sink_set_decompression_state(intel_dp, crtc_state, true); +	if (!is_mst) +		intel_dp_sink_enable_decompression(state, +						   to_intel_connector(conn_state->connector), +						   crtc_state);  	/*  	 * DDI FEC: "anticipates enabling FEC encoding sets the FEC_READY bit  	 * in the FEC_CONFIGURATION register to 1 before initiating link  	 * training  	 */ -	intel_dp_sink_set_fec_ready(intel_dp, crtc_state); +	intel_dp_sink_set_fec_ready(intel_dp, crtc_state, true);  	intel_dp_check_frl_training(intel_dp);  	intel_dp_pcon_dsc_configure(intel_dp, crtc_state); @@ -2643,7 +2723,8 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state,  	/* 7.l Configure and enable FEC if needed */  	intel_ddi_enable_fec(encoder, crtc_state); -	intel_dsc_dp_pps_write(encoder, crtc_state); +	if (!is_mst) +		intel_dsc_dp_pps_write(encoder, crtc_state);  }  static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state, @@ -2695,9 +2776,11 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state,  	if (!is_mst)  		intel_dp_set_power(intel_dp, DP_SET_POWER_D0);  	intel_dp_configure_protocol_converter(intel_dp, crtc_state); -	intel_dp_sink_set_decompression_state(intel_dp, crtc_state, -					      true); -	intel_dp_sink_set_fec_ready(intel_dp, crtc_state); +	if (!is_mst) +		intel_dp_sink_enable_decompression(state, +						   to_intel_connector(conn_state->connector), +						   crtc_state); +	intel_dp_sink_set_fec_ready(intel_dp, crtc_state, true);  	intel_dp_start_link_train(intel_dp, crtc_state);  	if ((port != PORT_A || DISPLAY_VER(dev_priv) >= 9) &&  	    !is_trans_port_sync_mode(crtc_state)) @@ -2705,10 +2788,10 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state,  	intel_ddi_enable_fec(encoder, crtc_state); -	if (!is_mst) +	if (!is_mst) {  		intel_ddi_enable_transcoder_clock(encoder, crtc_state); - -	intel_dsc_dp_pps_write(encoder, crtc_state); +		intel_dsc_dp_pps_write(encoder, crtc_state); +	}  }  static void intel_ddi_pre_enable_dp(struct intel_atomic_state *state, @@ -2717,10 +2800,15 @@ static void intel_ddi_pre_enable_dp(struct intel_atomic_state *state,  				    const struct drm_connector_state *conn_state)  {  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); +	struct intel_dp *intel_dp = enc_to_intel_dp(encoder); -	if (HAS_DP20(dev_priv)) +	if (HAS_DP20(dev_priv)) {  		intel_dp_128b132b_sdp_crc16(enc_to_intel_dp(encoder),  					    crtc_state); +		if (crtc_state->has_panel_replay) +			drm_dp_dpcd_writeb(&intel_dp->aux, PANEL_REPLAY_CONFIG, +					   DP_PANEL_REPLAY_ENABLE); +	}  	if (DISPLAY_VER(dev_priv) >= 14)  		mtl_ddi_pre_enable_dp(state, encoder, crtc_state, conn_state); @@ -2866,8 +2954,7 @@ static void disable_ddi_buf(struct intel_encoder *encoder,  		intel_de_rmw(dev_priv, dp_tp_ctl_reg(encoder, crtc_state),  			     DP_TP_CTL_ENABLE, 0); -	/* Disable FEC in DP Sink */ -	intel_ddi_disable_fec_state(encoder, crtc_state); +	intel_ddi_disable_fec(encoder, crtc_state);  	if (wait)  		intel_wait_ddi_buf_idle(dev_priv, port); @@ -2882,10 +2969,12 @@ static void intel_disable_ddi_buf(struct intel_encoder *encoder,  		mtl_disable_ddi_buf(encoder, crtc_state);  		/* 3.f Disable DP_TP_CTL FEC Enable if it is needed */ -		intel_ddi_disable_fec_state(encoder, crtc_state); +		intel_ddi_disable_fec(encoder, crtc_state);  	} else {  		disable_ddi_buf(encoder, crtc_state);  	} + +	intel_ddi_wait_for_fec_status(encoder, crtc_state, false);  }  static void intel_ddi_post_disable_dp(struct intel_atomic_state *state, @@ -2925,6 +3014,8 @@ static void intel_ddi_post_disable_dp(struct intel_atomic_state *state,  	intel_disable_ddi_buf(encoder, old_crtc_state); +	intel_dp_sink_set_fec_ready(intel_dp, old_crtc_state, false); +  	/*  	 * From TGL spec: "If single stream or multi-stream master transcoder:  	 * Configure Transcoder Clock select to direct no clock to the @@ -3110,11 +3201,18 @@ static void intel_enable_ddi_dp(struct intel_atomic_state *state,  	if (!dig_port->lspcon.active || intel_dp_has_hdmi_sink(&dig_port->dp))  		intel_dp_set_infoframes(encoder, true, crtc_state, conn_state); -	intel_audio_codec_enable(encoder, crtc_state, conn_state); -  	trans_port_sync_stop_link_train(state, encoder, crtc_state);  } +/* FIXME bad home for this function */ +i915_reg_t hsw_chicken_trans_reg(struct drm_i915_private *i915, +				 enum transcoder cpu_transcoder) +{ +	return DISPLAY_VER(i915) >= 14 ? +		MTL_CHICKEN_TRANS(cpu_transcoder) : +		CHICKEN_TRANS(cpu_transcoder); +} +  static i915_reg_t  gen9_chicken_trans_reg_by_port(struct drm_i915_private *dev_priv,  			       enum port port) @@ -3233,8 +3331,6 @@ static void intel_enable_ddi_hdmi(struct intel_atomic_state *state,  	intel_de_write(dev_priv, DDI_BUF_CTL(port), buf_ctl);  	intel_wait_ddi_buf_active(dev_priv, port); - -	intel_audio_codec_enable(encoder, crtc_state, conn_state);  }  static void intel_enable_ddi(struct intel_atomic_state *state, @@ -3252,6 +3348,8 @@ static void intel_enable_ddi(struct intel_atomic_state *state,  	intel_enable_transcoder(crtc_state); +	intel_ddi_wait_for_fec_status(encoder, crtc_state, true); +  	intel_crtc_vblank_on(crtc_state);  	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) @@ -3259,10 +3357,8 @@ static void intel_enable_ddi(struct intel_atomic_state *state,  	else  		intel_enable_ddi_dp(state, encoder, crtc_state, conn_state); -	/* Enable hdcp if it's desired */ -	if (conn_state->content_protection == -	    DRM_MODE_CONTENT_PROTECTION_DESIRED) -		intel_hdcp_enable(state, encoder, crtc_state, conn_state); +	intel_hdcp_enable(state, encoder, crtc_state, conn_state); +  }  static void intel_disable_ddi_dp(struct intel_atomic_state *state, @@ -3271,16 +3367,16 @@ static void intel_disable_ddi_dp(struct intel_atomic_state *state,  				 const struct drm_connector_state *old_conn_state)  {  	struct intel_dp *intel_dp = enc_to_intel_dp(encoder); +	struct intel_connector *connector = +		to_intel_connector(old_conn_state->connector);  	intel_dp->link_trained = false; -	intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); -  	intel_psr_disable(intel_dp, old_crtc_state);  	intel_edp_backlight_off(old_conn_state);  	/* Disable the decompression in DP Sink */ -	intel_dp_sink_set_decompression_state(intel_dp, old_crtc_state, -					      false); +	intel_dp_sink_disable_decompression(state, +					    connector, old_crtc_state);  	/* Disable Ignore_MSA bit in DP Sink */  	intel_dp_sink_set_msa_timing_par_ignore_state(intel_dp, old_crtc_state,  						      false); @@ -3294,8 +3390,6 @@ static void intel_disable_ddi_hdmi(struct intel_atomic_state *state,  	struct drm_i915_private *i915 = to_i915(encoder->base.dev);  	struct drm_connector *connector = old_conn_state->connector; -	intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); -  	if (!intel_hdmi_handle_sink_scrambling(encoder, connector,  					       false, false))  		drm_dbg_kms(&i915->drm, @@ -3578,16 +3672,42 @@ static bool intel_ddi_is_audio_enabled(struct drm_i915_private *dev_priv,  		AUDIO_OUTPUT_ENABLE(cpu_transcoder);  } -void intel_ddi_compute_min_voltage_level(struct drm_i915_private *dev_priv, -					 struct intel_crtc_state *crtc_state) +static int tgl_ddi_min_voltage_level(const struct intel_crtc_state *crtc_state) +{ +	if (crtc_state->port_clock > 594000) +		return 2; +	else +		return 0; +} + +static int jsl_ddi_min_voltage_level(const struct intel_crtc_state *crtc_state) +{ +	if (crtc_state->port_clock > 594000) +		return 3; +	else +		return 0; +} + +static int icl_ddi_min_voltage_level(const struct intel_crtc_state *crtc_state) +{ +	if (crtc_state->port_clock > 594000) +		return 1; +	else +		return 0; +} + +void intel_ddi_compute_min_voltage_level(struct intel_crtc_state *crtc_state)  { -	if (DISPLAY_VER(dev_priv) >= 12 && crtc_state->port_clock > 594000) -		crtc_state->min_voltage_level = 2; -	else if ((IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) && -		 crtc_state->port_clock > 594000) -		crtc_state->min_voltage_level = 3; -	else if (DISPLAY_VER(dev_priv) >= 11 && crtc_state->port_clock > 594000) -		crtc_state->min_voltage_level = 1; +	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + +	if (DISPLAY_VER(dev_priv) >= 14) +		crtc_state->min_voltage_level = icl_ddi_min_voltage_level(crtc_state); +	else if (DISPLAY_VER(dev_priv) >= 12) +		crtc_state->min_voltage_level = tgl_ddi_min_voltage_level(crtc_state); +	else if (IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) +		crtc_state->min_voltage_level = jsl_ddi_min_voltage_level(crtc_state); +	else if (DISPLAY_VER(dev_priv) >= 11) +		crtc_state->min_voltage_level = icl_ddi_min_voltage_level(crtc_state);  }  static enum transcoder bdw_transcoder_master_readout(struct drm_i915_private *dev_priv, @@ -3801,7 +3921,7 @@ static void intel_ddi_get_config(struct intel_encoder *encoder,  		pipe_config->lane_lat_optim_mask =  			bxt_ddi_phy_get_lane_lat_optim_mask(encoder); -	intel_ddi_compute_min_voltage_level(dev_priv, pipe_config); +	intel_ddi_compute_min_voltage_level(pipe_config);  	intel_hdmi_read_gcp_infoframe(encoder, pipe_config); @@ -3854,18 +3974,13 @@ void intel_ddi_get_clock(struct intel_encoder *encoder,  static void mtl_ddi_get_config(struct intel_encoder *encoder,  			       struct intel_crtc_state *crtc_state)  { -	struct drm_i915_private *i915 = to_i915(encoder->base.dev); -	enum phy phy = intel_port_to_phy(i915, encoder->port);  	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);  	if (intel_tc_port_in_tbt_alt_mode(dig_port)) {  		crtc_state->port_clock = intel_mtl_tbt_calc_port_clock(encoder); -	} else if (intel_is_c10phy(i915, phy)) { -		intel_c10pll_readout_hw_state(encoder, &crtc_state->cx0pll_state.c10); -		crtc_state->port_clock = intel_c10pll_calc_port_clock(encoder, &crtc_state->cx0pll_state.c10);  	} else { -		intel_c20pll_readout_hw_state(encoder, &crtc_state->cx0pll_state.c20); -		crtc_state->port_clock = intel_c20pll_calc_port_clock(encoder, &crtc_state->cx0pll_state.c20); +		intel_cx0pll_readout_hw_state(encoder, &crtc_state->cx0pll_state); +		crtc_state->port_clock = intel_cx0pll_calc_port_clock(encoder, &crtc_state->cx0pll_state);  	}  	intel_ddi_get_config(encoder, crtc_state); @@ -4086,7 +4201,7 @@ static int intel_ddi_compute_config(struct intel_encoder *encoder,  		pipe_config->lane_lat_optim_mask =  			bxt_ddi_phy_calc_lane_lat_optim_mask(pipe_config->lane_count); -	intel_ddi_compute_min_voltage_level(dev_priv, pipe_config); +	intel_ddi_compute_min_voltage_level(pipe_config);  	return 0;  } @@ -4844,6 +4959,8 @@ void intel_ddi_init(struct drm_i915_private *dev_priv,  	encoder->post_pll_disable = intel_ddi_post_pll_disable;  	encoder->post_disable = intel_ddi_post_disable;  	encoder->update_pipe = intel_ddi_update_pipe; +	encoder->audio_enable = intel_audio_codec_enable; +	encoder->audio_disable = intel_audio_codec_disable;  	encoder->get_hw_state = intel_ddi_get_hw_state;  	encoder->sync_state = intel_ddi_sync_state;  	encoder->initial_fastset_check = intel_ddi_initial_fastset_check; | 
