diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_tc.c')
| -rw-r--r-- | drivers/gpu/drm/i915/display/intel_tc.c | 93 | 
1 files changed, 75 insertions, 18 deletions
| diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 3bc57579fe53..668ef139391b 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -23,6 +23,7 @@  #include "intel_modeset_lock.h"  #include "intel_tc.h" +#define DP_PIN_ASSIGNMENT_NONE	0x0  #define DP_PIN_ASSIGNMENT_C	0x3  #define DP_PIN_ASSIGNMENT_D	0x4  #define DP_PIN_ASSIGNMENT_E	0x5 @@ -66,6 +67,7 @@ struct intel_tc_port {  	enum tc_port_mode init_mode;  	enum phy_fia phy_fia;  	u8 phy_fia_idx; +	u8 max_lane_count;  };  static enum intel_display_power_domain @@ -307,6 +309,8 @@ static int lnl_tc_port_get_max_lane_count(struct intel_digital_port *dig_port)  		REG_FIELD_GET(TCSS_DDI_STATUS_PIN_ASSIGNMENT_MASK, val);  	switch (pin_assignment) { +	case DP_PIN_ASSIGNMENT_NONE: +		return 0;  	default:  		MISSING_CASE(pin_assignment);  		fallthrough; @@ -365,12 +369,12 @@ static int intel_tc_port_get_max_lane_count(struct intel_digital_port *dig_port)  	}  } -int intel_tc_port_max_lane_count(struct intel_digital_port *dig_port) +static int get_max_lane_count(struct intel_tc_port *tc)  { -	struct intel_display *display = to_intel_display(dig_port); -	struct intel_tc_port *tc = to_tc_port(dig_port); +	struct intel_display *display = to_intel_display(tc->dig_port); +	struct intel_digital_port *dig_port = tc->dig_port; -	if (!intel_encoder_is_tc(&dig_port->base) || tc->mode != TC_PORT_DP_ALT) +	if (tc->mode != TC_PORT_DP_ALT)  		return 4;  	assert_tc_cold_blocked(tc); @@ -384,6 +388,25 @@ int intel_tc_port_max_lane_count(struct intel_digital_port *dig_port)  	return intel_tc_port_get_max_lane_count(dig_port);  } +static void read_pin_configuration(struct intel_tc_port *tc) +{ +	tc->max_lane_count = get_max_lane_count(tc); +} + +int intel_tc_port_max_lane_count(struct intel_digital_port *dig_port) +{ +	struct intel_display *display = to_intel_display(dig_port); +	struct intel_tc_port *tc = to_tc_port(dig_port); + +	if (!intel_encoder_is_tc(&dig_port->base)) +		return 4; + +	if (DISPLAY_VER(display) < 20) +		return get_max_lane_count(tc); + +	return tc->max_lane_count; +} +  void intel_tc_port_set_fia_lane_count(struct intel_digital_port *dig_port,  				      int required_lanes)  { @@ -596,9 +619,12 @@ static void icl_tc_phy_get_hw_state(struct intel_tc_port *tc)  	tc_cold_wref = __tc_cold_block(tc, &domain);  	tc->mode = tc_phy_get_current_mode(tc); -	if (tc->mode != TC_PORT_DISCONNECTED) +	if (tc->mode != TC_PORT_DISCONNECTED) {  		tc->lock_wakeref = tc_cold_block(tc); +		read_pin_configuration(tc); +	} +  	__tc_cold_unblock(tc, domain, tc_cold_wref);  } @@ -656,8 +682,11 @@ static bool icl_tc_phy_connect(struct intel_tc_port *tc,  	tc->lock_wakeref = tc_cold_block(tc); -	if (tc->mode == TC_PORT_TBT_ALT) +	if (tc->mode == TC_PORT_TBT_ALT) { +		read_pin_configuration(tc); +  		return true; +	}  	if ((!tc_phy_is_ready(tc) ||  	     !icl_tc_phy_take_ownership(tc, true)) && @@ -668,6 +697,7 @@ static bool icl_tc_phy_connect(struct intel_tc_port *tc,  		goto out_unblock_tc_cold;  	} +	read_pin_configuration(tc);  	if (!tc_phy_verify_legacy_or_dp_alt_mode(tc, required_lanes))  		goto out_release_phy; @@ -858,9 +888,12 @@ static void adlp_tc_phy_get_hw_state(struct intel_tc_port *tc)  	port_wakeref = intel_display_power_get(display, port_power_domain);  	tc->mode = tc_phy_get_current_mode(tc); -	if (tc->mode != TC_PORT_DISCONNECTED) +	if (tc->mode != TC_PORT_DISCONNECTED) {  		tc->lock_wakeref = tc_cold_block(tc); +		read_pin_configuration(tc); +	} +  	intel_display_power_put(display, port_power_domain, port_wakeref);  } @@ -873,6 +906,9 @@ static bool adlp_tc_phy_connect(struct intel_tc_port *tc, int required_lanes)  	if (tc->mode == TC_PORT_TBT_ALT) {  		tc->lock_wakeref = tc_cold_block(tc); + +		read_pin_configuration(tc); +  		return true;  	} @@ -894,6 +930,8 @@ static bool adlp_tc_phy_connect(struct intel_tc_port *tc, int required_lanes)  	tc->lock_wakeref = tc_cold_block(tc); +	read_pin_configuration(tc); +  	if (!tc_phy_verify_legacy_or_dp_alt_mode(tc, required_lanes))  		goto out_unblock_tc_cold; @@ -1124,9 +1162,18 @@ static void xelpdp_tc_phy_get_hw_state(struct intel_tc_port *tc)  	tc_cold_wref = __tc_cold_block(tc, &domain);  	tc->mode = tc_phy_get_current_mode(tc); -	if (tc->mode != TC_PORT_DISCONNECTED) +	if (tc->mode != TC_PORT_DISCONNECTED) {  		tc->lock_wakeref = tc_cold_block(tc); +		read_pin_configuration(tc); +		/* +		 * Set a valid lane count value for a DP-alt sink which got +		 * disconnected. The driver can only disable the output on this PHY. +		 */ +		if (tc->max_lane_count == 0) +			tc->max_lane_count = 4; +	} +  	drm_WARN_ON(display->drm,  		    (tc->mode == TC_PORT_DP_ALT || tc->mode == TC_PORT_LEGACY) &&  		    !xelpdp_tc_phy_tcss_power_is_enabled(tc)); @@ -1138,14 +1185,19 @@ static bool xelpdp_tc_phy_connect(struct intel_tc_port *tc, int required_lanes)  {  	tc->lock_wakeref = tc_cold_block(tc); -	if (tc->mode == TC_PORT_TBT_ALT) +	if (tc->mode == TC_PORT_TBT_ALT) { +		read_pin_configuration(tc); +  		return true; +	}  	if (!xelpdp_tc_phy_enable_tcss_power(tc, true))  		goto out_unblock_tccold;  	xelpdp_tc_phy_take_ownership(tc, true); +	read_pin_configuration(tc); +  	if (!tc_phy_verify_legacy_or_dp_alt_mode(tc, required_lanes))  		goto out_release_phy; @@ -1226,14 +1278,19 @@ static void tc_phy_get_hw_state(struct intel_tc_port *tc)  	tc->phy_ops->get_hw_state(tc);  } -static bool tc_phy_is_ready_and_owned(struct intel_tc_port *tc, -				      bool phy_is_ready, bool phy_is_owned) +/* Is the PHY owned by display i.e. is it in legacy or DP-alt mode? */ +static bool tc_phy_owned_by_display(struct intel_tc_port *tc, +				    bool phy_is_ready, bool phy_is_owned)  {  	struct intel_display *display = to_intel_display(tc->dig_port); -	drm_WARN_ON(display->drm, phy_is_owned && !phy_is_ready); +	if (DISPLAY_VER(display) < 20) { +		drm_WARN_ON(display->drm, phy_is_owned && !phy_is_ready); -	return phy_is_ready && phy_is_owned; +		return phy_is_ready && phy_is_owned; +	} else { +		return phy_is_owned; +	}  }  static bool tc_phy_is_connected(struct intel_tc_port *tc, @@ -1244,7 +1301,7 @@ static bool tc_phy_is_connected(struct intel_tc_port *tc,  	bool phy_is_owned = tc_phy_is_owned(tc);  	bool is_connected; -	if (tc_phy_is_ready_and_owned(tc, phy_is_ready, phy_is_owned)) +	if (tc_phy_owned_by_display(tc, phy_is_ready, phy_is_owned))  		is_connected = port_pll_type == ICL_PORT_DPLL_MG_PHY;  	else  		is_connected = port_pll_type == ICL_PORT_DPLL_DEFAULT; @@ -1352,7 +1409,7 @@ tc_phy_get_current_mode(struct intel_tc_port *tc)  	phy_is_ready = tc_phy_is_ready(tc);  	phy_is_owned = tc_phy_is_owned(tc); -	if (!tc_phy_is_ready_and_owned(tc, phy_is_ready, phy_is_owned)) { +	if (!tc_phy_owned_by_display(tc, phy_is_ready, phy_is_owned)) {  		mode = get_tc_mode_in_phy_not_owned_state(tc, live_mode);  	} else {  		drm_WARN_ON(display->drm, live_mode == TC_PORT_TBT_ALT); @@ -1441,11 +1498,11 @@ static void intel_tc_port_reset_mode(struct intel_tc_port *tc,  	intel_display_power_flush_work(display);  	if (!intel_tc_cold_requires_aux_pw(dig_port)) {  		enum intel_display_power_domain aux_domain; -		bool aux_powered;  		aux_domain = intel_aux_power_domain(dig_port); -		aux_powered = intel_display_power_is_enabled(display, aux_domain); -		drm_WARN_ON(display->drm, aux_powered); +		if (intel_display_power_is_enabled(display, aux_domain)) +			drm_dbg_kms(display->drm, "Port %s: AUX unexpectedly powered\n", +				    tc->port_name);  	}  	tc_phy_disconnect(tc); | 
