diff options
| author | Dmitry Torokhov <[email protected]> | 2023-05-01 15:20:08 -0700 | 
|---|---|---|
| committer | Dmitry Torokhov <[email protected]> | 2023-05-01 15:20:08 -0700 | 
| commit | 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e (patch) | |
| tree | d57f3a63479a07b4e0cece029886e76e04feb984 /drivers/gpu/drm/i915/display/intel_dp_mst.c | |
| parent | 5dc63e56a9cf8df0b59c234a505a1653f1bdf885 (diff) | |
| parent | 53bea86b5712c7491bb3dae12e271666df0a308c (diff) | |
Merge branch 'next' into for-linus
Prepare input updates for 6.4 merge window.
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_dp_mst.c')
| -rw-r--r-- | drivers/gpu/drm/i915/display/intel_dp_mst.c | 310 | 
1 files changed, 291 insertions, 19 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 4077a979a924..054a009e800d 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -45,10 +45,14 @@  #include "intel_hotplug.h"  #include "skl_scaler.h" -static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder, -					    struct intel_crtc_state *crtc_state, -					    struct drm_connector_state *conn_state, -					    struct link_config_limits *limits) +static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder, +						struct intel_crtc_state *crtc_state, +						int max_bpp, +						int min_bpp, +						struct link_config_limits *limits, +						struct drm_connector_state *conn_state, +						int step, +						bool dsc)  {  	struct drm_atomic_state *state = crtc_state->uapi.state;  	struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder); @@ -60,6 +64,7 @@ static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder,  	const struct drm_display_mode *adjusted_mode =  		&crtc_state->hw.adjusted_mode;  	int bpp, slots = -EINVAL; +	int ret = 0;  	mst_state = drm_atomic_get_mst_topology_state(state, &intel_dp->mst_mgr);  	if (IS_ERR(mst_state)) @@ -71,30 +76,68 @@ static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder,  	// TODO: Handle pbn_div changes by adding a new MST helper  	if (!mst_state->pbn_div) {  		mst_state->pbn_div = drm_dp_get_vc_payload_bw(&intel_dp->mst_mgr, -							      limits->max_rate, -							      limits->max_lane_count); +							      crtc_state->port_clock, +							      crtc_state->lane_count);  	} -	for (bpp = limits->max_bpp; bpp >= limits->min_bpp; bpp -= 2 * 3) { -		crtc_state->pipe_bpp = bpp; - +	for (bpp = max_bpp; bpp >= min_bpp; bpp -= step) {  		crtc_state->pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock, -						       crtc_state->pipe_bpp, -						       false); +						       dsc ? bpp << 4 : bpp, +						       dsc); + +		drm_dbg_kms(&i915->drm, "Trying bpp %d\n", bpp); +  		slots = drm_dp_atomic_find_time_slots(state, &intel_dp->mst_mgr, -						      connector->port, crtc_state->pbn); +						      connector->port, +						      crtc_state->pbn);  		if (slots == -EDEADLK)  			return slots; -		if (slots >= 0) -			break; + +		if (slots >= 0) { +			ret = drm_dp_mst_atomic_check(state); +			/* +			 * If we got slots >= 0 and we can fit those based on check +			 * then we can exit the loop. Otherwise keep trying. +			 */ +			if (!ret) +				break; +		}  	} +	/* Despite slots are non-zero, we still failed the atomic check */ +	if (ret && slots >= 0) +		slots = ret; +  	if (slots < 0) {  		drm_dbg_kms(&i915->drm, "failed finding vcpi slots:%d\n",  			    slots); -		return slots; +	} else { +		if (!dsc) +			crtc_state->pipe_bpp = bpp; +		else +			crtc_state->dsc.compressed_bpp = bpp; +		drm_dbg_kms(&i915->drm, "Got %d slots for pipe bpp %d dsc %d\n", slots, bpp, dsc);  	} +	return slots; +} + +static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder, +					    struct intel_crtc_state *crtc_state, +					    struct drm_connector_state *conn_state, +					    struct link_config_limits *limits) +{ +	const struct drm_display_mode *adjusted_mode = +		&crtc_state->hw.adjusted_mode; +	int slots = -EINVAL; + +	slots = intel_dp_mst_find_vcpi_slots_for_bpp(encoder, crtc_state, limits->max_bpp, +						     limits->min_bpp, limits, +						     conn_state, 2 * 3, false); + +	if (slots < 0) +		return slots; +  	intel_link_compute_m_n(crtc_state->pipe_bpp,  			       crtc_state->lane_count,  			       adjusted_mode->crtc_clock, @@ -106,6 +149,99 @@ static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder,  	return 0;  } +static int intel_dp_dsc_mst_compute_link_config(struct intel_encoder *encoder, +						struct intel_crtc_state *crtc_state, +						struct drm_connector_state *conn_state, +						struct link_config_limits *limits) +{ +	struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder); +	struct intel_dp *intel_dp = &intel_mst->primary->dp; +	struct intel_connector *connector = +		to_intel_connector(conn_state->connector); +	struct drm_i915_private *i915 = to_i915(connector->base.dev); +	const struct drm_display_mode *adjusted_mode = +		&crtc_state->hw.adjusted_mode; +	int slots = -EINVAL; +	int i, num_bpc; +	u8 dsc_bpc[3] = {0}; +	int min_bpp, max_bpp, sink_min_bpp, sink_max_bpp; +	u8 dsc_max_bpc; +	bool need_timeslot_recalc = false; +	u32 last_compressed_bpp; + +	/* Max DSC Input BPC for ICL is 10 and for TGL+ is 12 */ +	if (DISPLAY_VER(i915) >= 12) +		dsc_max_bpc = min_t(u8, 12, conn_state->max_requested_bpc); +	else +		dsc_max_bpc = min_t(u8, 10, conn_state->max_requested_bpc); + +	max_bpp = min_t(u8, dsc_max_bpc * 3, limits->max_bpp); +	min_bpp = limits->min_bpp; + +	num_bpc = drm_dp_dsc_sink_supported_input_bpcs(intel_dp->dsc_dpcd, +						       dsc_bpc); + +	drm_dbg_kms(&i915->drm, "DSC Source supported min bpp %d max bpp %d\n", +		    min_bpp, max_bpp); + +	sink_max_bpp = dsc_bpc[0] * 3; +	sink_min_bpp = sink_max_bpp; + +	for (i = 1; i < num_bpc; i++) { +		if (sink_min_bpp > dsc_bpc[i] * 3) +			sink_min_bpp = dsc_bpc[i] * 3; +		if (sink_max_bpp < dsc_bpc[i] * 3) +			sink_max_bpp = dsc_bpc[i] * 3; +	} + +	drm_dbg_kms(&i915->drm, "DSC Sink supported min bpp %d max bpp %d\n", +		    sink_min_bpp, sink_max_bpp); + +	if (min_bpp < sink_min_bpp) +		min_bpp = sink_min_bpp; + +	if (max_bpp > sink_max_bpp) +		max_bpp = sink_max_bpp; + +	slots = intel_dp_mst_find_vcpi_slots_for_bpp(encoder, crtc_state, max_bpp, +						     min_bpp, limits, +						     conn_state, 2 * 3, true); + +	if (slots < 0) +		return slots; + +	last_compressed_bpp = crtc_state->dsc.compressed_bpp; + +	crtc_state->dsc.compressed_bpp = intel_dp_dsc_nearest_valid_bpp(i915, +									last_compressed_bpp, +									crtc_state->pipe_bpp); + +	if (crtc_state->dsc.compressed_bpp != last_compressed_bpp) +		need_timeslot_recalc = true; + +	/* +	 * Apparently some MST hubs dislike if vcpi slots are not matching precisely +	 * the actual compressed bpp we use. +	 */ +	if (need_timeslot_recalc) { +		slots = intel_dp_mst_find_vcpi_slots_for_bpp(encoder, crtc_state, +							     crtc_state->dsc.compressed_bpp, +							     crtc_state->dsc.compressed_bpp, +							     limits, conn_state, 2 * 3, true); +		if (slots < 0) +			return slots; +	} + +	intel_link_compute_m_n(crtc_state->pipe_bpp, +			       crtc_state->lane_count, +			       adjusted_mode->crtc_clock, +			       crtc_state->port_clock, +			       &crtc_state->dp_m_n, +			       crtc_state->fec_enable); +	crtc_state->dp_m_n.tu = slots; + +	return 0; +}  static int intel_dp_mst_update_slots(struct intel_encoder *encoder,  				     struct intel_crtc_state *crtc_state,  				     struct drm_connector_state *conn_state) @@ -182,6 +318,29 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder,  	ret = intel_dp_mst_compute_link_config(encoder, pipe_config,  					       conn_state, &limits); + +	if (ret == -EDEADLK) +		return ret; + +	/* enable compression if the mode doesn't fit available BW */ +	drm_dbg_kms(&dev_priv->drm, "Force DSC en = %d\n", intel_dp->force_dsc_en); +	if (ret || intel_dp->force_dsc_en) { +		/* +		 * Try to get at least some timeslots and then see, if +		 * we can fit there with DSC. +		 */ +		drm_dbg_kms(&dev_priv->drm, "Trying to find VCPI slots in DSC mode\n"); + +		ret = intel_dp_dsc_mst_compute_link_config(encoder, pipe_config, +							   conn_state, &limits); +		if (ret < 0) +			return ret; + +		ret = intel_dp_dsc_compute_config(intel_dp, pipe_config, +						  conn_state, &limits, +						  pipe_config->dp_m_n.tu, false); +	} +  	if (ret)  		return ret; @@ -365,8 +524,14 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state,  	struct intel_dp *intel_dp = &dig_port->dp;  	struct intel_connector *connector =  		to_intel_connector(old_conn_state->connector); -	struct drm_dp_mst_topology_state *mst_state = -		drm_atomic_get_mst_topology_state(&state->base, &intel_dp->mst_mgr); +	struct drm_dp_mst_topology_state *old_mst_state = +		drm_atomic_get_old_mst_topology_state(&state->base, &intel_dp->mst_mgr); +	struct drm_dp_mst_topology_state *new_mst_state = +		drm_atomic_get_new_mst_topology_state(&state->base, &intel_dp->mst_mgr); +	const struct drm_dp_mst_atomic_payload *old_payload = +		drm_atomic_get_mst_payload_state(old_mst_state, connector->port); +	struct drm_dp_mst_atomic_payload *new_payload = +		drm_atomic_get_mst_payload_state(new_mst_state, connector->port);  	struct drm_i915_private *i915 = to_i915(connector->base.dev);  	drm_dbg_kms(&i915->drm, "active links %d\n", @@ -374,8 +539,8 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state,  	intel_hdcp_disable(intel_mst->connector); -	drm_dp_remove_payload(&intel_dp->mst_mgr, mst_state, -			      drm_atomic_get_mst_payload_state(mst_state, connector->port)); +	drm_dp_remove_payload(&intel_dp->mst_mgr, new_mst_state, +			      old_payload, new_payload);  	intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state);  } @@ -692,6 +857,10 @@ intel_dp_mst_mode_valid_ctx(struct drm_connector *connector,  	int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;  	int max_rate, mode_rate, max_lanes, max_link_clock;  	int ret; +	bool dsc = false, bigjoiner = false; +	u16 dsc_max_output_bpp = 0; +	u8 dsc_slice_count = 0; +	int target_clock = mode->clock;  	if (drm_connector_is_unregistered(connector)) {  		*status = MODE_ERROR; @@ -729,6 +898,48 @@ intel_dp_mst_mode_valid_ctx(struct drm_connector *connector,  		return 0;  	} +	if (intel_dp_need_bigjoiner(intel_dp, mode->hdisplay, target_clock)) { +		bigjoiner = true; +		max_dotclk *= 2; +	} + +	if (DISPLAY_VER(dev_priv) >= 10 && +	    drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd)) { +		/* +		 * TBD pass the connector BPC, +		 * for now U8_MAX so that max BPC on that platform would be picked +		 */ +		int pipe_bpp = intel_dp_dsc_compute_bpp(intel_dp, U8_MAX); + +		if (drm_dp_sink_supports_fec(intel_dp->fec_capable)) { +			dsc_max_output_bpp = +				intel_dp_dsc_get_output_bpp(dev_priv, +							    max_link_clock, +							    max_lanes, +							    target_clock, +							    mode->hdisplay, +							    bigjoiner, +							    pipe_bpp, 64) >> 4; +			dsc_slice_count = +				intel_dp_dsc_get_slice_count(intel_dp, +							     target_clock, +							     mode->hdisplay, +							     bigjoiner); +		} + +		dsc = dsc_max_output_bpp && dsc_slice_count; +	} + +	/* +	 * Big joiner configuration needs DSC for TGL which is not true for +	 * XE_LPD where uncompressed joiner is supported. +	 */ +	if (DISPLAY_VER(dev_priv) < 13 && bigjoiner && !dsc) +		return MODE_CLOCK_HIGH; + +	if (mode_rate > max_rate && !dsc) +		return MODE_CLOCK_HIGH; +  	*status = intel_mode_valid_max_plane_size(dev_priv, mode, false);  	return 0;  } @@ -1018,3 +1229,64 @@ bool intel_dp_mst_is_slave_trans(const struct intel_crtc_state *crtc_state)  	return crtc_state->mst_master_transcoder != INVALID_TRANSCODER &&  	       crtc_state->mst_master_transcoder != crtc_state->cpu_transcoder;  } + +/** + * intel_dp_mst_add_topology_state_for_connector - add MST topology state for a connector + * @state: atomic state + * @connector: connector to add the state for + * @crtc: the CRTC @connector is attached to + * + * Add the MST topology state for @connector to @state. + * + * Returns 0 on success, negative error code on failure. + */ +static int +intel_dp_mst_add_topology_state_for_connector(struct intel_atomic_state *state, +					      struct intel_connector *connector, +					      struct intel_crtc *crtc) +{ +	struct drm_dp_mst_topology_state *mst_state; + +	if (!connector->mst_port) +		return 0; + +	mst_state = drm_atomic_get_mst_topology_state(&state->base, +						      &connector->mst_port->mst_mgr); +	if (IS_ERR(mst_state)) +		return PTR_ERR(mst_state); + +	mst_state->pending_crtc_mask |= drm_crtc_mask(&crtc->base); + +	return 0; +} + +/** + * intel_dp_mst_add_topology_state_for_crtc - add MST topology state for a CRTC + * @state: atomic state + * @crtc: CRTC to add the state for + * + * Add the MST topology state for @crtc to @state. + * + * Returns 0 on success, negative error code on failure. + */ +int intel_dp_mst_add_topology_state_for_crtc(struct intel_atomic_state *state, +					     struct intel_crtc *crtc) +{ +	struct drm_connector *_connector; +	struct drm_connector_state *conn_state; +	int i; + +	for_each_new_connector_in_state(&state->base, _connector, conn_state, i) { +		struct intel_connector *connector = to_intel_connector(_connector); +		int ret; + +		if (conn_state->crtc != &crtc->base) +			continue; + +		ret = intel_dp_mst_add_topology_state_for_connector(state, connector, crtc); +		if (ret) +			return ret; +	} + +	return 0; +}  |