brintos

brintos / linux-shallow public Read only

0
0
Text · 49.9 KiB · 6f2ee7d Raw
1905 lines · c
1// SPDX-License-Identifier: MIT2/*3 * Copyright © 2019 Intel Corporation4 */5 6#include "i915_drv.h"7#include "i915_reg.h"8#include "intel_atomic.h"9#include "intel_cx0_phy_regs.h"10#include "intel_ddi.h"11#include "intel_de.h"12#include "intel_display.h"13#include "intel_display_driver.h"14#include "intel_display_power_map.h"15#include "intel_display_types.h"16#include "intel_dkl_phy_regs.h"17#include "intel_dp.h"18#include "intel_dp_mst.h"19#include "intel_mg_phy_regs.h"20#include "intel_modeset_lock.h"21#include "intel_tc.h"22 23#define DP_PIN_ASSIGNMENT_C	0x324#define DP_PIN_ASSIGNMENT_D	0x425#define DP_PIN_ASSIGNMENT_E	0x526 27enum tc_port_mode {28	TC_PORT_DISCONNECTED,29	TC_PORT_TBT_ALT,30	TC_PORT_DP_ALT,31	TC_PORT_LEGACY,32};33 34struct intel_tc_port;35 36struct intel_tc_phy_ops {37	enum intel_display_power_domain (*cold_off_domain)(struct intel_tc_port *tc);38	u32 (*hpd_live_status)(struct intel_tc_port *tc);39	bool (*is_ready)(struct intel_tc_port *tc);40	bool (*is_owned)(struct intel_tc_port *tc);41	void (*get_hw_state)(struct intel_tc_port *tc);42	bool (*connect)(struct intel_tc_port *tc, int required_lanes);43	void (*disconnect)(struct intel_tc_port *tc);44	void (*init)(struct intel_tc_port *tc);45};46 47struct intel_tc_port {48	struct intel_digital_port *dig_port;49 50	const struct intel_tc_phy_ops *phy_ops;51 52	struct mutex lock;	/* protects the TypeC port mode */53	intel_wakeref_t lock_wakeref;54#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)55	enum intel_display_power_domain lock_power_domain;56#endif57	struct delayed_work disconnect_phy_work;58	struct delayed_work link_reset_work;59	int link_refcount;60	bool legacy_port:1;61	const char *port_name;62	enum tc_port_mode mode;63	enum tc_port_mode init_mode;64	enum phy_fia phy_fia;65	u8 phy_fia_idx;66};67 68static enum intel_display_power_domain69tc_phy_cold_off_domain(struct intel_tc_port *);70static u32 tc_phy_hpd_live_status(struct intel_tc_port *tc);71static bool tc_phy_is_ready(struct intel_tc_port *tc);72static bool tc_phy_wait_for_ready(struct intel_tc_port *tc);73static enum tc_port_mode tc_phy_get_current_mode(struct intel_tc_port *tc);74 75static const char *tc_port_mode_name(enum tc_port_mode mode)76{77	static const char * const names[] = {78		[TC_PORT_DISCONNECTED] = "disconnected",79		[TC_PORT_TBT_ALT] = "tbt-alt",80		[TC_PORT_DP_ALT] = "dp-alt",81		[TC_PORT_LEGACY] = "legacy",82	};83 84	if (WARN_ON(mode >= ARRAY_SIZE(names)))85		mode = TC_PORT_DISCONNECTED;86 87	return names[mode];88}89 90static struct intel_tc_port *to_tc_port(struct intel_digital_port *dig_port)91{92	return dig_port->tc;93}94 95static struct drm_i915_private *tc_to_i915(struct intel_tc_port *tc)96{97	return to_i915(tc->dig_port->base.base.dev);98}99 100static bool intel_tc_port_in_mode(struct intel_digital_port *dig_port,101				  enum tc_port_mode mode)102{103	struct intel_tc_port *tc = to_tc_port(dig_port);104 105	return intel_encoder_is_tc(&dig_port->base) && tc->mode == mode;106}107 108bool intel_tc_port_in_tbt_alt_mode(struct intel_digital_port *dig_port)109{110	return intel_tc_port_in_mode(dig_port, TC_PORT_TBT_ALT);111}112 113bool intel_tc_port_in_dp_alt_mode(struct intel_digital_port *dig_port)114{115	return intel_tc_port_in_mode(dig_port, TC_PORT_DP_ALT);116}117 118bool intel_tc_port_in_legacy_mode(struct intel_digital_port *dig_port)119{120	return intel_tc_port_in_mode(dig_port, TC_PORT_LEGACY);121}122 123bool intel_tc_port_handles_hpd_glitches(struct intel_digital_port *dig_port)124{125	struct intel_tc_port *tc = to_tc_port(dig_port);126 127	return intel_encoder_is_tc(&dig_port->base) && !tc->legacy_port;128}129 130/*131 * The display power domains used for TC ports depending on the132 * platform and TC mode (legacy, DP-alt, TBT):133 *134 * POWER_DOMAIN_DISPLAY_CORE:135 * --------------------------136 * ADLP/all modes:137 *   - TCSS/IOM access for PHY ready state.138 * ADLP+/all modes:139 *   - DE/north-,south-HPD ISR access for HPD live state.140 *141 * POWER_DOMAIN_PORT_DDI_LANES_<port>:142 * -----------------------------------143 * ICL+/all modes:144 *   - DE/DDI_BUF access for port enabled state.145 * ADLP/all modes:146 *   - DE/DDI_BUF access for PHY owned state.147 *148 * POWER_DOMAIN_AUX_USBC<TC port index>:149 * -------------------------------------150 * ICL/legacy mode:151 *   - TCSS/IOM,FIA access for PHY ready, owned and HPD live state152 *   - TCSS/PHY: block TC-cold power state for using the PHY AUX and153 *     main lanes.154 * ADLP/legacy, DP-alt modes:155 *   - TCSS/PHY: block TC-cold power state for using the PHY AUX and156 *     main lanes.157 *158 * POWER_DOMAIN_TC_COLD_OFF:159 * -------------------------160 * ICL/DP-alt, TBT mode:161 *   - TCSS/TBT: block TC-cold power state for using the (direct or162 *     TBT DP-IN) AUX and main lanes.163 *164 * TGL/all modes:165 *   - TCSS/IOM,FIA access for PHY ready, owned and HPD live state166 *   - TCSS/PHY: block TC-cold power state for using the (direct or167 *     TBT DP-IN) AUX and main lanes.168 *169 * ADLP/TBT mode:170 *   - TCSS/TBT: block TC-cold power state for using the (TBT DP-IN)171 *     AUX and main lanes.172 *173 * XELPDP+/all modes:174 *   - TCSS/IOM,FIA access for PHY ready, owned state175 *   - TCSS/PHY: block TC-cold power state for using the (direct or176 *     TBT DP-IN) AUX and main lanes.177 */178bool intel_tc_cold_requires_aux_pw(struct intel_digital_port *dig_port)179{180	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);181	struct intel_tc_port *tc = to_tc_port(dig_port);182 183	return tc_phy_cold_off_domain(tc) ==184	       intel_display_power_legacy_aux_domain(i915, dig_port->aux_ch);185}186 187static intel_wakeref_t188__tc_cold_block(struct intel_tc_port *tc, enum intel_display_power_domain *domain)189{190	struct drm_i915_private *i915 = tc_to_i915(tc);191 192	*domain = tc_phy_cold_off_domain(tc);193 194	return intel_display_power_get(i915, *domain);195}196 197static intel_wakeref_t198tc_cold_block(struct intel_tc_port *tc)199{200	enum intel_display_power_domain domain;201	intel_wakeref_t wakeref;202 203	wakeref = __tc_cold_block(tc, &domain);204#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)205	tc->lock_power_domain = domain;206#endif207	return wakeref;208}209 210static void211__tc_cold_unblock(struct intel_tc_port *tc, enum intel_display_power_domain domain,212		  intel_wakeref_t wakeref)213{214	struct drm_i915_private *i915 = tc_to_i915(tc);215 216	intel_display_power_put(i915, domain, wakeref);217}218 219static void220tc_cold_unblock(struct intel_tc_port *tc, intel_wakeref_t wakeref)221{222	enum intel_display_power_domain domain = tc_phy_cold_off_domain(tc);223 224#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)225	drm_WARN_ON(&tc_to_i915(tc)->drm, tc->lock_power_domain != domain);226#endif227	__tc_cold_unblock(tc, domain, wakeref);228}229 230static void231assert_display_core_power_enabled(struct intel_tc_port *tc)232{233	struct drm_i915_private *i915 = tc_to_i915(tc);234 235	drm_WARN_ON(&i915->drm,236		    !intel_display_power_is_enabled(i915, POWER_DOMAIN_DISPLAY_CORE));237}238 239static void240assert_tc_cold_blocked(struct intel_tc_port *tc)241{242	struct drm_i915_private *i915 = tc_to_i915(tc);243	bool enabled;244 245	enabled = intel_display_power_is_enabled(i915,246						 tc_phy_cold_off_domain(tc));247	drm_WARN_ON(&i915->drm, !enabled);248}249 250static enum intel_display_power_domain251tc_port_power_domain(struct intel_tc_port *tc)252{253	enum tc_port tc_port = intel_encoder_to_tc(&tc->dig_port->base);254 255	return POWER_DOMAIN_PORT_DDI_LANES_TC1 + tc_port - TC_PORT_1;256}257 258static void259assert_tc_port_power_enabled(struct intel_tc_port *tc)260{261	struct drm_i915_private *i915 = tc_to_i915(tc);262 263	drm_WARN_ON(&i915->drm,264		    !intel_display_power_is_enabled(i915, tc_port_power_domain(tc)));265}266 267static u32 intel_tc_port_get_lane_mask(struct intel_digital_port *dig_port)268{269	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);270	struct intel_tc_port *tc = to_tc_port(dig_port);271	u32 lane_mask;272 273	lane_mask = intel_de_read(i915, PORT_TX_DFLEXDPSP(tc->phy_fia));274 275	drm_WARN_ON(&i915->drm, lane_mask == 0xffffffff);276	assert_tc_cold_blocked(tc);277 278	lane_mask &= DP_LANE_ASSIGNMENT_MASK(tc->phy_fia_idx);279	return lane_mask >> DP_LANE_ASSIGNMENT_SHIFT(tc->phy_fia_idx);280}281 282u32 intel_tc_port_get_pin_assignment_mask(struct intel_digital_port *dig_port)283{284	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);285	struct intel_tc_port *tc = to_tc_port(dig_port);286	u32 pin_mask;287 288	pin_mask = intel_de_read(i915, PORT_TX_DFLEXPA1(tc->phy_fia));289 290	drm_WARN_ON(&i915->drm, pin_mask == 0xffffffff);291	assert_tc_cold_blocked(tc);292 293	return (pin_mask & DP_PIN_ASSIGNMENT_MASK(tc->phy_fia_idx)) >>294	       DP_PIN_ASSIGNMENT_SHIFT(tc->phy_fia_idx);295}296 297static int lnl_tc_port_get_max_lane_count(struct intel_digital_port *dig_port)298{299	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);300	enum tc_port tc_port = intel_encoder_to_tc(&dig_port->base);301	intel_wakeref_t wakeref;302	u32 val, pin_assignment;303 304	with_intel_display_power(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref)305		val = intel_de_read(i915, TCSS_DDI_STATUS(tc_port));306 307	pin_assignment =308		REG_FIELD_GET(TCSS_DDI_STATUS_PIN_ASSIGNMENT_MASK, val);309 310	switch (pin_assignment) {311	default:312		MISSING_CASE(pin_assignment);313		fallthrough;314	case DP_PIN_ASSIGNMENT_D:315		return 2;316	case DP_PIN_ASSIGNMENT_C:317	case DP_PIN_ASSIGNMENT_E:318		return 4;319	}320}321 322static int mtl_tc_port_get_max_lane_count(struct intel_digital_port *dig_port)323{324	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);325	intel_wakeref_t wakeref;326	u32 pin_mask;327 328	with_intel_display_power(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref)329		pin_mask = intel_tc_port_get_pin_assignment_mask(dig_port);330 331	switch (pin_mask) {332	default:333		MISSING_CASE(pin_mask);334		fallthrough;335	case DP_PIN_ASSIGNMENT_D:336		return 2;337	case DP_PIN_ASSIGNMENT_C:338	case DP_PIN_ASSIGNMENT_E:339		return 4;340	}341}342 343static int intel_tc_port_get_max_lane_count(struct intel_digital_port *dig_port)344{345	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);346	intel_wakeref_t wakeref;347	u32 lane_mask = 0;348 349	with_intel_display_power(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref)350		lane_mask = intel_tc_port_get_lane_mask(dig_port);351 352	switch (lane_mask) {353	default:354		MISSING_CASE(lane_mask);355		fallthrough;356	case 0x1:357	case 0x2:358	case 0x4:359	case 0x8:360		return 1;361	case 0x3:362	case 0xc:363		return 2;364	case 0xf:365		return 4;366	}367}368 369int intel_tc_port_max_lane_count(struct intel_digital_port *dig_port)370{371	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);372	struct intel_tc_port *tc = to_tc_port(dig_port);373 374	if (!intel_encoder_is_tc(&dig_port->base) || tc->mode != TC_PORT_DP_ALT)375		return 4;376 377	assert_tc_cold_blocked(tc);378 379	if (DISPLAY_VER(i915) >= 20)380		return lnl_tc_port_get_max_lane_count(dig_port);381 382	if (DISPLAY_VER(i915) >= 14)383		return mtl_tc_port_get_max_lane_count(dig_port);384 385	return intel_tc_port_get_max_lane_count(dig_port);386}387 388void intel_tc_port_set_fia_lane_count(struct intel_digital_port *dig_port,389				      int required_lanes)390{391	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);392	struct intel_tc_port *tc = to_tc_port(dig_port);393	bool lane_reversal = dig_port->saved_port_bits & DDI_BUF_PORT_REVERSAL;394	u32 val;395 396	if (DISPLAY_VER(i915) >= 14)397		return;398 399	drm_WARN_ON(&i915->drm,400		    lane_reversal && tc->mode != TC_PORT_LEGACY);401 402	assert_tc_cold_blocked(tc);403 404	val = intel_de_read(i915, PORT_TX_DFLEXDPMLE1(tc->phy_fia));405	val &= ~DFLEXDPMLE1_DPMLETC_MASK(tc->phy_fia_idx);406 407	switch (required_lanes) {408	case 1:409		val |= lane_reversal ?410			DFLEXDPMLE1_DPMLETC_ML3(tc->phy_fia_idx) :411			DFLEXDPMLE1_DPMLETC_ML0(tc->phy_fia_idx);412		break;413	case 2:414		val |= lane_reversal ?415			DFLEXDPMLE1_DPMLETC_ML3_2(tc->phy_fia_idx) :416			DFLEXDPMLE1_DPMLETC_ML1_0(tc->phy_fia_idx);417		break;418	case 4:419		val |= DFLEXDPMLE1_DPMLETC_ML3_0(tc->phy_fia_idx);420		break;421	default:422		MISSING_CASE(required_lanes);423	}424 425	intel_de_write(i915, PORT_TX_DFLEXDPMLE1(tc->phy_fia), val);426}427 428static void tc_port_fixup_legacy_flag(struct intel_tc_port *tc,429				      u32 live_status_mask)430{431	struct drm_i915_private *i915 = tc_to_i915(tc);432	u32 valid_hpd_mask;433 434	drm_WARN_ON(&i915->drm, tc->mode != TC_PORT_DISCONNECTED);435 436	if (hweight32(live_status_mask) != 1)437		return;438 439	if (tc->legacy_port)440		valid_hpd_mask = BIT(TC_PORT_LEGACY);441	else442		valid_hpd_mask = BIT(TC_PORT_DP_ALT) |443				 BIT(TC_PORT_TBT_ALT);444 445	if (!(live_status_mask & ~valid_hpd_mask))446		return;447 448	/* If live status mismatches the VBT flag, trust the live status. */449	drm_dbg_kms(&i915->drm,450		    "Port %s: live status %08x mismatches the legacy port flag %08x, fixing flag\n",451		    tc->port_name, live_status_mask, valid_hpd_mask);452 453	tc->legacy_port = !tc->legacy_port;454}455 456static void tc_phy_load_fia_params(struct intel_tc_port *tc, bool modular_fia)457{458	enum tc_port tc_port = intel_encoder_to_tc(&tc->dig_port->base);459 460	/*461	 * Each Modular FIA instance houses 2 TC ports. In SOC that has more462	 * than two TC ports, there are multiple instances of Modular FIA.463	 */464	if (modular_fia) {465		tc->phy_fia = tc_port / 2;466		tc->phy_fia_idx = tc_port % 2;467	} else {468		tc->phy_fia = FIA1;469		tc->phy_fia_idx = tc_port;470	}471}472 473/*474 * ICL TC PHY handlers475 * -------------------476 */477static enum intel_display_power_domain478icl_tc_phy_cold_off_domain(struct intel_tc_port *tc)479{480	struct drm_i915_private *i915 = tc_to_i915(tc);481	struct intel_digital_port *dig_port = tc->dig_port;482 483	if (tc->legacy_port)484		return intel_display_power_legacy_aux_domain(i915, dig_port->aux_ch);485 486	return POWER_DOMAIN_TC_COLD_OFF;487}488 489static u32 icl_tc_phy_hpd_live_status(struct intel_tc_port *tc)490{491	struct drm_i915_private *i915 = tc_to_i915(tc);492	struct intel_digital_port *dig_port = tc->dig_port;493	u32 isr_bit = i915->display.hotplug.pch_hpd[dig_port->base.hpd_pin];494	intel_wakeref_t wakeref;495	u32 fia_isr;496	u32 pch_isr;497	u32 mask = 0;498 499	with_intel_display_power(i915, tc_phy_cold_off_domain(tc), wakeref) {500		fia_isr = intel_de_read(i915, PORT_TX_DFLEXDPSP(tc->phy_fia));501		pch_isr = intel_de_read(i915, SDEISR);502	}503 504	if (fia_isr == 0xffffffff) {505		drm_dbg_kms(&i915->drm,506			    "Port %s: PHY in TCCOLD, nothing connected\n",507			    tc->port_name);508		return mask;509	}510 511	if (fia_isr & TC_LIVE_STATE_TBT(tc->phy_fia_idx))512		mask |= BIT(TC_PORT_TBT_ALT);513	if (fia_isr & TC_LIVE_STATE_TC(tc->phy_fia_idx))514		mask |= BIT(TC_PORT_DP_ALT);515 516	if (pch_isr & isr_bit)517		mask |= BIT(TC_PORT_LEGACY);518 519	return mask;520}521 522/*523 * Return the PHY status complete flag indicating that display can acquire the524 * PHY ownership. The IOM firmware sets this flag when a DP-alt or legacy sink525 * is connected and it's ready to switch the ownership to display. The flag526 * will be left cleared when a TBT-alt sink is connected, where the PHY is527 * owned by the TBT subsystem and so switching the ownership to display is not528 * required.529 */530static bool icl_tc_phy_is_ready(struct intel_tc_port *tc)531{532	struct drm_i915_private *i915 = tc_to_i915(tc);533	u32 val;534 535	assert_tc_cold_blocked(tc);536 537	val = intel_de_read(i915, PORT_TX_DFLEXDPPMS(tc->phy_fia));538	if (val == 0xffffffff) {539		drm_dbg_kms(&i915->drm,540			    "Port %s: PHY in TCCOLD, assuming not ready\n",541			    tc->port_name);542		return false;543	}544 545	return val & DP_PHY_MODE_STATUS_COMPLETED(tc->phy_fia_idx);546}547 548static bool icl_tc_phy_take_ownership(struct intel_tc_port *tc,549				      bool take)550{551	struct drm_i915_private *i915 = tc_to_i915(tc);552	u32 val;553 554	assert_tc_cold_blocked(tc);555 556	val = intel_de_read(i915, PORT_TX_DFLEXDPCSSS(tc->phy_fia));557	if (val == 0xffffffff) {558		drm_dbg_kms(&i915->drm,559			    "Port %s: PHY in TCCOLD, can't %s ownership\n",560			    tc->port_name, take ? "take" : "release");561 562		return false;563	}564 565	val &= ~DP_PHY_MODE_STATUS_NOT_SAFE(tc->phy_fia_idx);566	if (take)567		val |= DP_PHY_MODE_STATUS_NOT_SAFE(tc->phy_fia_idx);568 569	intel_de_write(i915, PORT_TX_DFLEXDPCSSS(tc->phy_fia), val);570 571	return true;572}573 574static bool icl_tc_phy_is_owned(struct intel_tc_port *tc)575{576	struct drm_i915_private *i915 = tc_to_i915(tc);577	u32 val;578 579	assert_tc_cold_blocked(tc);580 581	val = intel_de_read(i915, PORT_TX_DFLEXDPCSSS(tc->phy_fia));582	if (val == 0xffffffff) {583		drm_dbg_kms(&i915->drm,584			    "Port %s: PHY in TCCOLD, assume not owned\n",585			    tc->port_name);586		return false;587	}588 589	return val & DP_PHY_MODE_STATUS_NOT_SAFE(tc->phy_fia_idx);590}591 592static void icl_tc_phy_get_hw_state(struct intel_tc_port *tc)593{594	enum intel_display_power_domain domain;595	intel_wakeref_t tc_cold_wref;596 597	tc_cold_wref = __tc_cold_block(tc, &domain);598 599	tc->mode = tc_phy_get_current_mode(tc);600	if (tc->mode != TC_PORT_DISCONNECTED)601		tc->lock_wakeref = tc_cold_block(tc);602 603	__tc_cold_unblock(tc, domain, tc_cold_wref);604}605 606/*607 * This function implements the first part of the Connect Flow described by our608 * specification, Gen11 TypeC Programming chapter. The rest of the flow (reading609 * lanes, EDID, etc) is done as needed in the typical places.610 *611 * Unlike the other ports, type-C ports are not available to use as soon as we612 * get a hotplug. The type-C PHYs can be shared between multiple controllers:613 * display, USB, etc. As a result, handshaking through FIA is required around614 * connect and disconnect to cleanly transfer ownership with the controller and615 * set the type-C power state.616 */617static bool tc_phy_verify_legacy_or_dp_alt_mode(struct intel_tc_port *tc,618						int required_lanes)619{620	struct drm_i915_private *i915 = tc_to_i915(tc);621	struct intel_digital_port *dig_port = tc->dig_port;622	int max_lanes;623 624	max_lanes = intel_tc_port_max_lane_count(dig_port);625	if (tc->mode == TC_PORT_LEGACY) {626		drm_WARN_ON(&i915->drm, max_lanes != 4);627		return true;628	}629 630	drm_WARN_ON(&i915->drm, tc->mode != TC_PORT_DP_ALT);631 632	/*633	 * Now we have to re-check the live state, in case the port recently634	 * became disconnected. Not necessary for legacy mode.635	 */636	if (!(tc_phy_hpd_live_status(tc) & BIT(TC_PORT_DP_ALT))) {637		drm_dbg_kms(&i915->drm, "Port %s: PHY sudden disconnect\n",638			    tc->port_name);639		return false;640	}641 642	if (max_lanes < required_lanes) {643		drm_dbg_kms(&i915->drm,644			    "Port %s: PHY max lanes %d < required lanes %d\n",645			    tc->port_name,646			    max_lanes, required_lanes);647		return false;648	}649 650	return true;651}652 653static bool icl_tc_phy_connect(struct intel_tc_port *tc,654			       int required_lanes)655{656	struct drm_i915_private *i915 = tc_to_i915(tc);657 658	tc->lock_wakeref = tc_cold_block(tc);659 660	if (tc->mode == TC_PORT_TBT_ALT)661		return true;662 663	if ((!tc_phy_is_ready(tc) ||664	     !icl_tc_phy_take_ownership(tc, true)) &&665	    !drm_WARN_ON(&i915->drm, tc->mode == TC_PORT_LEGACY)) {666		drm_dbg_kms(&i915->drm, "Port %s: can't take PHY ownership (ready %s)\n",667			    tc->port_name,668			    str_yes_no(tc_phy_is_ready(tc)));669		goto out_unblock_tc_cold;670	}671 672 673	if (!tc_phy_verify_legacy_or_dp_alt_mode(tc, required_lanes))674		goto out_release_phy;675 676	return true;677 678out_release_phy:679	icl_tc_phy_take_ownership(tc, false);680out_unblock_tc_cold:681	tc_cold_unblock(tc, fetch_and_zero(&tc->lock_wakeref));682 683	return false;684}685 686/*687 * See the comment at the connect function. This implements the Disconnect688 * Flow.689 */690static void icl_tc_phy_disconnect(struct intel_tc_port *tc)691{692	switch (tc->mode) {693	case TC_PORT_LEGACY:694	case TC_PORT_DP_ALT:695		icl_tc_phy_take_ownership(tc, false);696		fallthrough;697	case TC_PORT_TBT_ALT:698		tc_cold_unblock(tc, fetch_and_zero(&tc->lock_wakeref));699		break;700	default:701		MISSING_CASE(tc->mode);702	}703}704 705static void icl_tc_phy_init(struct intel_tc_port *tc)706{707	tc_phy_load_fia_params(tc, false);708}709 710static const struct intel_tc_phy_ops icl_tc_phy_ops = {711	.cold_off_domain = icl_tc_phy_cold_off_domain,712	.hpd_live_status = icl_tc_phy_hpd_live_status,713	.is_ready = icl_tc_phy_is_ready,714	.is_owned = icl_tc_phy_is_owned,715	.get_hw_state = icl_tc_phy_get_hw_state,716	.connect = icl_tc_phy_connect,717	.disconnect = icl_tc_phy_disconnect,718	.init = icl_tc_phy_init,719};720 721/*722 * TGL TC PHY handlers723 * -------------------724 */725static enum intel_display_power_domain726tgl_tc_phy_cold_off_domain(struct intel_tc_port *tc)727{728	return POWER_DOMAIN_TC_COLD_OFF;729}730 731static void tgl_tc_phy_init(struct intel_tc_port *tc)732{733	struct drm_i915_private *i915 = tc_to_i915(tc);734	intel_wakeref_t wakeref;735	u32 val;736 737	with_intel_display_power(i915, tc_phy_cold_off_domain(tc), wakeref)738		val = intel_de_read(i915, PORT_TX_DFLEXDPSP(FIA1));739 740	drm_WARN_ON(&i915->drm, val == 0xffffffff);741 742	tc_phy_load_fia_params(tc, val & MODULAR_FIA_MASK);743}744 745static const struct intel_tc_phy_ops tgl_tc_phy_ops = {746	.cold_off_domain = tgl_tc_phy_cold_off_domain,747	.hpd_live_status = icl_tc_phy_hpd_live_status,748	.is_ready = icl_tc_phy_is_ready,749	.is_owned = icl_tc_phy_is_owned,750	.get_hw_state = icl_tc_phy_get_hw_state,751	.connect = icl_tc_phy_connect,752	.disconnect = icl_tc_phy_disconnect,753	.init = tgl_tc_phy_init,754};755 756/*757 * ADLP TC PHY handlers758 * --------------------759 */760static enum intel_display_power_domain761adlp_tc_phy_cold_off_domain(struct intel_tc_port *tc)762{763	struct drm_i915_private *i915 = tc_to_i915(tc);764	struct intel_digital_port *dig_port = tc->dig_port;765 766	if (tc->mode != TC_PORT_TBT_ALT)767		return intel_display_power_legacy_aux_domain(i915, dig_port->aux_ch);768 769	return POWER_DOMAIN_TC_COLD_OFF;770}771 772static u32 adlp_tc_phy_hpd_live_status(struct intel_tc_port *tc)773{774	struct drm_i915_private *i915 = tc_to_i915(tc);775	struct intel_digital_port *dig_port = tc->dig_port;776	enum hpd_pin hpd_pin = dig_port->base.hpd_pin;777	u32 cpu_isr_bits = i915->display.hotplug.hpd[hpd_pin];778	u32 pch_isr_bit = i915->display.hotplug.pch_hpd[hpd_pin];779	intel_wakeref_t wakeref;780	u32 cpu_isr;781	u32 pch_isr;782	u32 mask = 0;783 784	with_intel_display_power(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref) {785		cpu_isr = intel_de_read(i915, GEN11_DE_HPD_ISR);786		pch_isr = intel_de_read(i915, SDEISR);787	}788 789	if (cpu_isr & (cpu_isr_bits & GEN11_DE_TC_HOTPLUG_MASK))790		mask |= BIT(TC_PORT_DP_ALT);791	if (cpu_isr & (cpu_isr_bits & GEN11_DE_TBT_HOTPLUG_MASK))792		mask |= BIT(TC_PORT_TBT_ALT);793 794	if (pch_isr & pch_isr_bit)795		mask |= BIT(TC_PORT_LEGACY);796 797	return mask;798}799 800/*801 * Return the PHY status complete flag indicating that display can acquire the802 * PHY ownership. The IOM firmware sets this flag when it's ready to switch803 * the ownership to display, regardless of what sink is connected (TBT-alt,804 * DP-alt, legacy or nothing). For TBT-alt sinks the PHY is owned by the TBT805 * subsystem and so switching the ownership to display is not required.806 */807static bool adlp_tc_phy_is_ready(struct intel_tc_port *tc)808{809	struct drm_i915_private *i915 = tc_to_i915(tc);810	enum tc_port tc_port = intel_encoder_to_tc(&tc->dig_port->base);811	u32 val;812 813	assert_display_core_power_enabled(tc);814 815	val = intel_de_read(i915, TCSS_DDI_STATUS(tc_port));816	if (val == 0xffffffff) {817		drm_dbg_kms(&i915->drm,818			    "Port %s: PHY in TCCOLD, assuming not ready\n",819			    tc->port_name);820		return false;821	}822 823	return val & TCSS_DDI_STATUS_READY;824}825 826static bool adlp_tc_phy_take_ownership(struct intel_tc_port *tc,827				       bool take)828{829	struct drm_i915_private *i915 = tc_to_i915(tc);830	enum port port = tc->dig_port->base.port;831 832	assert_tc_port_power_enabled(tc);833 834	intel_de_rmw(i915, DDI_BUF_CTL(port), DDI_BUF_CTL_TC_PHY_OWNERSHIP,835		     take ? DDI_BUF_CTL_TC_PHY_OWNERSHIP : 0);836 837	return true;838}839 840static bool adlp_tc_phy_is_owned(struct intel_tc_port *tc)841{842	struct drm_i915_private *i915 = tc_to_i915(tc);843	enum port port = tc->dig_port->base.port;844	u32 val;845 846	assert_tc_port_power_enabled(tc);847 848	val = intel_de_read(i915, DDI_BUF_CTL(port));849	return val & DDI_BUF_CTL_TC_PHY_OWNERSHIP;850}851 852static void adlp_tc_phy_get_hw_state(struct intel_tc_port *tc)853{854	struct drm_i915_private *i915 = tc_to_i915(tc);855	enum intel_display_power_domain port_power_domain =856		tc_port_power_domain(tc);857	intel_wakeref_t port_wakeref;858 859	port_wakeref = intel_display_power_get(i915, port_power_domain);860 861	tc->mode = tc_phy_get_current_mode(tc);862	if (tc->mode != TC_PORT_DISCONNECTED)863		tc->lock_wakeref = tc_cold_block(tc);864 865	intel_display_power_put(i915, port_power_domain, port_wakeref);866}867 868static bool adlp_tc_phy_connect(struct intel_tc_port *tc, int required_lanes)869{870	struct drm_i915_private *i915 = tc_to_i915(tc);871	enum intel_display_power_domain port_power_domain =872		tc_port_power_domain(tc);873	intel_wakeref_t port_wakeref;874 875	if (tc->mode == TC_PORT_TBT_ALT) {876		tc->lock_wakeref = tc_cold_block(tc);877		return true;878	}879 880	port_wakeref = intel_display_power_get(i915, port_power_domain);881 882	if (!adlp_tc_phy_take_ownership(tc, true) &&883	    !drm_WARN_ON(&i915->drm, tc->mode == TC_PORT_LEGACY)) {884		drm_dbg_kms(&i915->drm, "Port %s: can't take PHY ownership\n",885			    tc->port_name);886		goto out_put_port_power;887	}888 889	if (!tc_phy_is_ready(tc) &&890	    !drm_WARN_ON(&i915->drm, tc->mode == TC_PORT_LEGACY)) {891		drm_dbg_kms(&i915->drm, "Port %s: PHY not ready\n",892			    tc->port_name);893		goto out_release_phy;894	}895 896	tc->lock_wakeref = tc_cold_block(tc);897 898	if (!tc_phy_verify_legacy_or_dp_alt_mode(tc, required_lanes))899		goto out_unblock_tc_cold;900 901	intel_display_power_put(i915, port_power_domain, port_wakeref);902 903	return true;904 905out_unblock_tc_cold:906	tc_cold_unblock(tc, fetch_and_zero(&tc->lock_wakeref));907out_release_phy:908	adlp_tc_phy_take_ownership(tc, false);909out_put_port_power:910	intel_display_power_put(i915, port_power_domain, port_wakeref);911 912	return false;913}914 915static void adlp_tc_phy_disconnect(struct intel_tc_port *tc)916{917	struct drm_i915_private *i915 = tc_to_i915(tc);918	enum intel_display_power_domain port_power_domain =919		tc_port_power_domain(tc);920	intel_wakeref_t port_wakeref;921 922	port_wakeref = intel_display_power_get(i915, port_power_domain);923 924	tc_cold_unblock(tc, fetch_and_zero(&tc->lock_wakeref));925 926	switch (tc->mode) {927	case TC_PORT_LEGACY:928	case TC_PORT_DP_ALT:929		adlp_tc_phy_take_ownership(tc, false);930		fallthrough;931	case TC_PORT_TBT_ALT:932		break;933	default:934		MISSING_CASE(tc->mode);935	}936 937	intel_display_power_put(i915, port_power_domain, port_wakeref);938}939 940static void adlp_tc_phy_init(struct intel_tc_port *tc)941{942	tc_phy_load_fia_params(tc, true);943}944 945static const struct intel_tc_phy_ops adlp_tc_phy_ops = {946	.cold_off_domain = adlp_tc_phy_cold_off_domain,947	.hpd_live_status = adlp_tc_phy_hpd_live_status,948	.is_ready = adlp_tc_phy_is_ready,949	.is_owned = adlp_tc_phy_is_owned,950	.get_hw_state = adlp_tc_phy_get_hw_state,951	.connect = adlp_tc_phy_connect,952	.disconnect = adlp_tc_phy_disconnect,953	.init = adlp_tc_phy_init,954};955 956/*957 * XELPDP TC PHY handlers958 * ----------------------959 */960static u32 xelpdp_tc_phy_hpd_live_status(struct intel_tc_port *tc)961{962	struct drm_i915_private *i915 = tc_to_i915(tc);963	struct intel_digital_port *dig_port = tc->dig_port;964	enum hpd_pin hpd_pin = dig_port->base.hpd_pin;965	u32 pica_isr_bits = i915->display.hotplug.hpd[hpd_pin];966	u32 pch_isr_bit = i915->display.hotplug.pch_hpd[hpd_pin];967	intel_wakeref_t wakeref;968	u32 pica_isr;969	u32 pch_isr;970	u32 mask = 0;971 972	with_intel_display_power(i915, POWER_DOMAIN_DISPLAY_CORE, wakeref) {973		pica_isr = intel_de_read(i915, PICAINTERRUPT_ISR);974		pch_isr = intel_de_read(i915, SDEISR);975	}976 977	if (pica_isr & (pica_isr_bits & XELPDP_DP_ALT_HOTPLUG_MASK))978		mask |= BIT(TC_PORT_DP_ALT);979	if (pica_isr & (pica_isr_bits & XELPDP_TBT_HOTPLUG_MASK))980		mask |= BIT(TC_PORT_TBT_ALT);981 982	if (tc->legacy_port && (pch_isr & pch_isr_bit))983		mask |= BIT(TC_PORT_LEGACY);984 985	return mask;986}987 988static bool989xelpdp_tc_phy_tcss_power_is_enabled(struct intel_tc_port *tc)990{991	struct drm_i915_private *i915 = tc_to_i915(tc);992	enum port port = tc->dig_port->base.port;993	i915_reg_t reg = XELPDP_PORT_BUF_CTL1(i915, port);994 995	assert_tc_cold_blocked(tc);996 997	return intel_de_read(i915, reg) & XELPDP_TCSS_POWER_STATE;998}999 1000static bool1001xelpdp_tc_phy_wait_for_tcss_power(struct intel_tc_port *tc, bool enabled)1002{1003	struct drm_i915_private *i915 = tc_to_i915(tc);1004 1005	if (wait_for(xelpdp_tc_phy_tcss_power_is_enabled(tc) == enabled, 5)) {1006		drm_dbg_kms(&i915->drm,1007			    "Port %s: timeout waiting for TCSS power to get %s\n",1008			    enabled ? "enabled" : "disabled",1009			    tc->port_name);1010		return false;1011	}1012 1013	return true;1014}1015 1016static void __xelpdp_tc_phy_enable_tcss_power(struct intel_tc_port *tc, bool enable)1017{1018	struct drm_i915_private *i915 = tc_to_i915(tc);1019	enum port port = tc->dig_port->base.port;1020	i915_reg_t reg = XELPDP_PORT_BUF_CTL1(i915, port);1021	u32 val;1022 1023	assert_tc_cold_blocked(tc);1024 1025	val = intel_de_read(i915, reg);1026	if (enable)1027		val |= XELPDP_TCSS_POWER_REQUEST;1028	else1029		val &= ~XELPDP_TCSS_POWER_REQUEST;1030	intel_de_write(i915, reg, val);1031}1032 1033static bool xelpdp_tc_phy_enable_tcss_power(struct intel_tc_port *tc, bool enable)1034{1035	struct drm_i915_private *i915 = tc_to_i915(tc);1036 1037	__xelpdp_tc_phy_enable_tcss_power(tc, enable);1038 1039	if (enable && !tc_phy_wait_for_ready(tc))1040		goto out_disable;1041 1042	if (!xelpdp_tc_phy_wait_for_tcss_power(tc, enable))1043		goto out_disable;1044 1045	return true;1046 1047out_disable:1048	if (drm_WARN_ON(&i915->drm, tc->mode == TC_PORT_LEGACY))1049		return false;1050 1051	if (!enable)1052		return false;1053 1054	__xelpdp_tc_phy_enable_tcss_power(tc, false);1055	xelpdp_tc_phy_wait_for_tcss_power(tc, false);1056 1057	return false;1058}1059 1060static void xelpdp_tc_phy_take_ownership(struct intel_tc_port *tc, bool take)1061{1062	struct drm_i915_private *i915 = tc_to_i915(tc);1063	enum port port = tc->dig_port->base.port;1064	i915_reg_t reg = XELPDP_PORT_BUF_CTL1(i915, port);1065	u32 val;1066 1067	assert_tc_cold_blocked(tc);1068 1069	val = intel_de_read(i915, reg);1070	if (take)1071		val |= XELPDP_TC_PHY_OWNERSHIP;1072	else1073		val &= ~XELPDP_TC_PHY_OWNERSHIP;1074	intel_de_write(i915, reg, val);1075}1076 1077static bool xelpdp_tc_phy_is_owned(struct intel_tc_port *tc)1078{1079	struct drm_i915_private *i915 = tc_to_i915(tc);1080	enum port port = tc->dig_port->base.port;1081	i915_reg_t reg = XELPDP_PORT_BUF_CTL1(i915, port);1082 1083	assert_tc_cold_blocked(tc);1084 1085	return intel_de_read(i915, reg) & XELPDP_TC_PHY_OWNERSHIP;1086}1087 1088static void xelpdp_tc_phy_get_hw_state(struct intel_tc_port *tc)1089{1090	struct drm_i915_private *i915 = tc_to_i915(tc);1091	intel_wakeref_t tc_cold_wref;1092	enum intel_display_power_domain domain;1093 1094	tc_cold_wref = __tc_cold_block(tc, &domain);1095 1096	tc->mode = tc_phy_get_current_mode(tc);1097	if (tc->mode != TC_PORT_DISCONNECTED)1098		tc->lock_wakeref = tc_cold_block(tc);1099 1100	drm_WARN_ON(&i915->drm,1101		    (tc->mode == TC_PORT_DP_ALT || tc->mode == TC_PORT_LEGACY) &&1102		    !xelpdp_tc_phy_tcss_power_is_enabled(tc));1103 1104	__tc_cold_unblock(tc, domain, tc_cold_wref);1105}1106 1107static bool xelpdp_tc_phy_connect(struct intel_tc_port *tc, int required_lanes)1108{1109	tc->lock_wakeref = tc_cold_block(tc);1110 1111	if (tc->mode == TC_PORT_TBT_ALT)1112		return true;1113 1114	if (!xelpdp_tc_phy_enable_tcss_power(tc, true))1115		goto out_unblock_tccold;1116 1117	xelpdp_tc_phy_take_ownership(tc, true);1118 1119	if (!tc_phy_verify_legacy_or_dp_alt_mode(tc, required_lanes))1120		goto out_release_phy;1121 1122	return true;1123 1124out_release_phy:1125	xelpdp_tc_phy_take_ownership(tc, false);1126	xelpdp_tc_phy_wait_for_tcss_power(tc, false);1127 1128out_unblock_tccold:1129	tc_cold_unblock(tc, fetch_and_zero(&tc->lock_wakeref));1130 1131	return false;1132}1133 1134static void xelpdp_tc_phy_disconnect(struct intel_tc_port *tc)1135{1136	switch (tc->mode) {1137	case TC_PORT_LEGACY:1138	case TC_PORT_DP_ALT:1139		xelpdp_tc_phy_take_ownership(tc, false);1140		xelpdp_tc_phy_enable_tcss_power(tc, false);1141		fallthrough;1142	case TC_PORT_TBT_ALT:1143		tc_cold_unblock(tc, fetch_and_zero(&tc->lock_wakeref));1144		break;1145	default:1146		MISSING_CASE(tc->mode);1147	}1148}1149 1150static const struct intel_tc_phy_ops xelpdp_tc_phy_ops = {1151	.cold_off_domain = tgl_tc_phy_cold_off_domain,1152	.hpd_live_status = xelpdp_tc_phy_hpd_live_status,1153	.is_ready = adlp_tc_phy_is_ready,1154	.is_owned = xelpdp_tc_phy_is_owned,1155	.get_hw_state = xelpdp_tc_phy_get_hw_state,1156	.connect = xelpdp_tc_phy_connect,1157	.disconnect = xelpdp_tc_phy_disconnect,1158	.init = adlp_tc_phy_init,1159};1160 1161/*1162 * Generic TC PHY handlers1163 * -----------------------1164 */1165static enum intel_display_power_domain1166tc_phy_cold_off_domain(struct intel_tc_port *tc)1167{1168	return tc->phy_ops->cold_off_domain(tc);1169}1170 1171static u32 tc_phy_hpd_live_status(struct intel_tc_port *tc)1172{1173	struct drm_i915_private *i915 = tc_to_i915(tc);1174	u32 mask;1175 1176	mask = tc->phy_ops->hpd_live_status(tc);1177 1178	/* The sink can be connected only in a single mode. */1179	drm_WARN_ON_ONCE(&i915->drm, hweight32(mask) > 1);1180 1181	return mask;1182}1183 1184static bool tc_phy_is_ready(struct intel_tc_port *tc)1185{1186	return tc->phy_ops->is_ready(tc);1187}1188 1189static bool tc_phy_is_owned(struct intel_tc_port *tc)1190{1191	return tc->phy_ops->is_owned(tc);1192}1193 1194static void tc_phy_get_hw_state(struct intel_tc_port *tc)1195{1196	tc->phy_ops->get_hw_state(tc);1197}1198 1199static bool tc_phy_is_ready_and_owned(struct intel_tc_port *tc,1200				      bool phy_is_ready, bool phy_is_owned)1201{1202	struct drm_i915_private *i915 = tc_to_i915(tc);1203 1204	drm_WARN_ON(&i915->drm, phy_is_owned && !phy_is_ready);1205 1206	return phy_is_ready && phy_is_owned;1207}1208 1209static bool tc_phy_is_connected(struct intel_tc_port *tc,1210				enum icl_port_dpll_id port_pll_type)1211{1212	struct intel_encoder *encoder = &tc->dig_port->base;1213	struct drm_i915_private *i915 = to_i915(encoder->base.dev);1214	bool phy_is_ready = tc_phy_is_ready(tc);1215	bool phy_is_owned = tc_phy_is_owned(tc);1216	bool is_connected;1217 1218	if (tc_phy_is_ready_and_owned(tc, phy_is_ready, phy_is_owned))1219		is_connected = port_pll_type == ICL_PORT_DPLL_MG_PHY;1220	else1221		is_connected = port_pll_type == ICL_PORT_DPLL_DEFAULT;1222 1223	drm_dbg_kms(&i915->drm,1224		    "Port %s: PHY connected: %s (ready: %s, owned: %s, pll_type: %s)\n",1225		    tc->port_name,1226		    str_yes_no(is_connected),1227		    str_yes_no(phy_is_ready),1228		    str_yes_no(phy_is_owned),1229		    port_pll_type == ICL_PORT_DPLL_DEFAULT ? "tbt" : "non-tbt");1230 1231	return is_connected;1232}1233 1234static bool tc_phy_wait_for_ready(struct intel_tc_port *tc)1235{1236	struct drm_i915_private *i915 = tc_to_i915(tc);1237 1238	if (wait_for(tc_phy_is_ready(tc), 500)) {1239		drm_err(&i915->drm, "Port %s: timeout waiting for PHY ready\n",1240			tc->port_name);1241 1242		return false;1243	}1244 1245	return true;1246}1247 1248static enum tc_port_mode1249hpd_mask_to_tc_mode(u32 live_status_mask)1250{1251	if (live_status_mask)1252		return fls(live_status_mask) - 1;1253 1254	return TC_PORT_DISCONNECTED;1255}1256 1257static enum tc_port_mode1258tc_phy_hpd_live_mode(struct intel_tc_port *tc)1259{1260	u32 live_status_mask = tc_phy_hpd_live_status(tc);1261 1262	return hpd_mask_to_tc_mode(live_status_mask);1263}1264 1265static enum tc_port_mode1266get_tc_mode_in_phy_owned_state(struct intel_tc_port *tc,1267			       enum tc_port_mode live_mode)1268{1269	switch (live_mode) {1270	case TC_PORT_LEGACY:1271	case TC_PORT_DP_ALT:1272		return live_mode;1273	default:1274		MISSING_CASE(live_mode);1275		fallthrough;1276	case TC_PORT_TBT_ALT:1277	case TC_PORT_DISCONNECTED:1278		if (tc->legacy_port)1279			return TC_PORT_LEGACY;1280		else1281			return TC_PORT_DP_ALT;1282	}1283}1284 1285static enum tc_port_mode1286get_tc_mode_in_phy_not_owned_state(struct intel_tc_port *tc,1287				   enum tc_port_mode live_mode)1288{1289	switch (live_mode) {1290	case TC_PORT_LEGACY:1291		return TC_PORT_DISCONNECTED;1292	case TC_PORT_DP_ALT:1293	case TC_PORT_TBT_ALT:1294		return TC_PORT_TBT_ALT;1295	default:1296		MISSING_CASE(live_mode);1297		fallthrough;1298	case TC_PORT_DISCONNECTED:1299		if (tc->legacy_port)1300			return TC_PORT_DISCONNECTED;1301		else1302			return TC_PORT_TBT_ALT;1303	}1304}1305 1306static enum tc_port_mode1307tc_phy_get_current_mode(struct intel_tc_port *tc)1308{1309	struct drm_i915_private *i915 = tc_to_i915(tc);1310	enum tc_port_mode live_mode = tc_phy_hpd_live_mode(tc);1311	bool phy_is_ready;1312	bool phy_is_owned;1313	enum tc_port_mode mode;1314 1315	/*1316	 * For legacy ports the IOM firmware initializes the PHY during boot-up1317	 * and system resume whether or not a sink is connected. Wait here for1318	 * the initialization to get ready.1319	 */1320	if (tc->legacy_port)1321		tc_phy_wait_for_ready(tc);1322 1323	phy_is_ready = tc_phy_is_ready(tc);1324	phy_is_owned = tc_phy_is_owned(tc);1325 1326	if (!tc_phy_is_ready_and_owned(tc, phy_is_ready, phy_is_owned)) {1327		mode = get_tc_mode_in_phy_not_owned_state(tc, live_mode);1328	} else {1329		drm_WARN_ON(&i915->drm, live_mode == TC_PORT_TBT_ALT);1330		mode = get_tc_mode_in_phy_owned_state(tc, live_mode);1331	}1332 1333	drm_dbg_kms(&i915->drm,1334		    "Port %s: PHY mode: %s (ready: %s, owned: %s, HPD: %s)\n",1335		    tc->port_name,1336		    tc_port_mode_name(mode),1337		    str_yes_no(phy_is_ready),1338		    str_yes_no(phy_is_owned),1339		    tc_port_mode_name(live_mode));1340 1341	return mode;1342}1343 1344static enum tc_port_mode default_tc_mode(struct intel_tc_port *tc)1345{1346	if (tc->legacy_port)1347		return TC_PORT_LEGACY;1348 1349	return TC_PORT_TBT_ALT;1350}1351 1352static enum tc_port_mode1353hpd_mask_to_target_mode(struct intel_tc_port *tc, u32 live_status_mask)1354{1355	enum tc_port_mode mode = hpd_mask_to_tc_mode(live_status_mask);1356 1357	if (mode != TC_PORT_DISCONNECTED)1358		return mode;1359 1360	return default_tc_mode(tc);1361}1362 1363static enum tc_port_mode1364tc_phy_get_target_mode(struct intel_tc_port *tc)1365{1366	u32 live_status_mask = tc_phy_hpd_live_status(tc);1367 1368	return hpd_mask_to_target_mode(tc, live_status_mask);1369}1370 1371static void tc_phy_connect(struct intel_tc_port *tc, int required_lanes)1372{1373	struct drm_i915_private *i915 = tc_to_i915(tc);1374	u32 live_status_mask = tc_phy_hpd_live_status(tc);1375	bool connected;1376 1377	tc_port_fixup_legacy_flag(tc, live_status_mask);1378 1379	tc->mode = hpd_mask_to_target_mode(tc, live_status_mask);1380 1381	connected = tc->phy_ops->connect(tc, required_lanes);1382	if (!connected && tc->mode != default_tc_mode(tc)) {1383		tc->mode = default_tc_mode(tc);1384		connected = tc->phy_ops->connect(tc, required_lanes);1385	}1386 1387	drm_WARN_ON(&i915->drm, !connected);1388}1389 1390static void tc_phy_disconnect(struct intel_tc_port *tc)1391{1392	if (tc->mode != TC_PORT_DISCONNECTED) {1393		tc->phy_ops->disconnect(tc);1394		tc->mode = TC_PORT_DISCONNECTED;1395	}1396}1397 1398static void tc_phy_init(struct intel_tc_port *tc)1399{1400	mutex_lock(&tc->lock);1401	tc->phy_ops->init(tc);1402	mutex_unlock(&tc->lock);1403}1404 1405static void intel_tc_port_reset_mode(struct intel_tc_port *tc,1406				     int required_lanes, bool force_disconnect)1407{1408	struct drm_i915_private *i915 = tc_to_i915(tc);1409	struct intel_digital_port *dig_port = tc->dig_port;1410	enum tc_port_mode old_tc_mode = tc->mode;1411 1412	intel_display_power_flush_work(i915);1413	if (!intel_tc_cold_requires_aux_pw(dig_port)) {1414		enum intel_display_power_domain aux_domain;1415		bool aux_powered;1416 1417		aux_domain = intel_aux_power_domain(dig_port);1418		aux_powered = intel_display_power_is_enabled(i915, aux_domain);1419		drm_WARN_ON(&i915->drm, aux_powered);1420	}1421 1422	tc_phy_disconnect(tc);1423	if (!force_disconnect)1424		tc_phy_connect(tc, required_lanes);1425 1426	drm_dbg_kms(&i915->drm, "Port %s: TC port mode reset (%s -> %s)\n",1427		    tc->port_name,1428		    tc_port_mode_name(old_tc_mode),1429		    tc_port_mode_name(tc->mode));1430}1431 1432static bool intel_tc_port_needs_reset(struct intel_tc_port *tc)1433{1434	return tc_phy_get_target_mode(tc) != tc->mode;1435}1436 1437static void intel_tc_port_update_mode(struct intel_tc_port *tc,1438				      int required_lanes, bool force_disconnect)1439{1440	if (force_disconnect ||1441	    intel_tc_port_needs_reset(tc))1442		intel_tc_port_reset_mode(tc, required_lanes, force_disconnect);1443}1444 1445static void __intel_tc_port_get_link(struct intel_tc_port *tc)1446{1447	tc->link_refcount++;1448}1449 1450static void __intel_tc_port_put_link(struct intel_tc_port *tc)1451{1452	tc->link_refcount--;1453}1454 1455static bool tc_port_is_enabled(struct intel_tc_port *tc)1456{1457	struct drm_i915_private *i915 = tc_to_i915(tc);1458	struct intel_digital_port *dig_port = tc->dig_port;1459 1460	assert_tc_port_power_enabled(tc);1461 1462	return intel_de_read(i915, DDI_BUF_CTL(dig_port->base.port)) &1463	       DDI_BUF_CTL_ENABLE;1464}1465 1466/**1467 * intel_tc_port_init_mode: Read out HW state and init the given port's TypeC mode1468 * @dig_port: digital port1469 *1470 * Read out the HW state and initialize the TypeC mode of @dig_port. The mode1471 * will be locked until intel_tc_port_sanitize_mode() is called.1472 */1473void intel_tc_port_init_mode(struct intel_digital_port *dig_port)1474{1475	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);1476	struct intel_tc_port *tc = to_tc_port(dig_port);1477	bool update_mode = false;1478 1479	mutex_lock(&tc->lock);1480 1481	drm_WARN_ON(&i915->drm, tc->mode != TC_PORT_DISCONNECTED);1482	drm_WARN_ON(&i915->drm, tc->lock_wakeref);1483	drm_WARN_ON(&i915->drm, tc->link_refcount);1484 1485	tc_phy_get_hw_state(tc);1486	/*1487	 * Save the initial mode for the state check in1488	 * intel_tc_port_sanitize_mode().1489	 */1490	tc->init_mode = tc->mode;1491 1492	/*1493	 * The PHY needs to be connected for AUX to work during HW readout and1494	 * MST topology resume, but the PHY mode can only be changed if the1495	 * port is disabled.1496	 *1497	 * An exception is the case where BIOS leaves the PHY incorrectly1498	 * disconnected on an enabled legacy port. Work around that by1499	 * connecting the PHY even though the port is enabled. This doesn't1500	 * cause a problem as the PHY ownership state is ignored by the1501	 * IOM/TCSS firmware (only display can own the PHY in that case).1502	 */1503	if (!tc_port_is_enabled(tc)) {1504		update_mode = true;1505	} else if (tc->mode == TC_PORT_DISCONNECTED) {1506		drm_WARN_ON(&i915->drm, !tc->legacy_port);1507		drm_err(&i915->drm,1508			"Port %s: PHY disconnected on enabled port, connecting it\n",1509			tc->port_name);1510		update_mode = true;1511	}1512 1513	if (update_mode)1514		intel_tc_port_update_mode(tc, 1, false);1515 1516	/* Prevent changing tc->mode until intel_tc_port_sanitize_mode() is called. */1517	__intel_tc_port_get_link(tc);1518 1519	mutex_unlock(&tc->lock);1520}1521 1522static bool tc_port_has_active_links(struct intel_tc_port *tc,1523				     const struct intel_crtc_state *crtc_state)1524{1525	struct drm_i915_private *i915 = tc_to_i915(tc);1526	struct intel_digital_port *dig_port = tc->dig_port;1527	enum icl_port_dpll_id pll_type = ICL_PORT_DPLL_DEFAULT;1528	int active_links = 0;1529 1530	if (dig_port->dp.is_mst) {1531		/* TODO: get the PLL type for MST, once HW readout is done for it. */1532		active_links = intel_dp_mst_encoder_active_links(dig_port);1533	} else if (crtc_state && crtc_state->hw.active) {1534		pll_type = intel_ddi_port_pll_type(&dig_port->base, crtc_state);1535		active_links = 1;1536	}1537 1538	if (active_links && !tc_phy_is_connected(tc, pll_type))1539		drm_err(&i915->drm,1540			"Port %s: PHY disconnected with %d active link(s)\n",1541			tc->port_name, active_links);1542 1543	return active_links;1544}1545 1546/**1547 * intel_tc_port_sanitize_mode: Sanitize the given port's TypeC mode1548 * @dig_port: digital port1549 * @crtc_state: atomic state of CRTC connected to @dig_port1550 *1551 * Sanitize @dig_port's TypeC mode wrt. the encoder's state right after driver1552 * loading and system resume:1553 * If the encoder is enabled keep the TypeC mode/PHY connected state locked until1554 * the encoder is disabled.1555 * If the encoder is disabled make sure the PHY is disconnected.1556 * @crtc_state is valid if @dig_port is enabled, NULL otherwise.1557 */1558void intel_tc_port_sanitize_mode(struct intel_digital_port *dig_port,1559				 const struct intel_crtc_state *crtc_state)1560{1561	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);1562	struct intel_tc_port *tc = to_tc_port(dig_port);1563 1564	mutex_lock(&tc->lock);1565 1566	drm_WARN_ON(&i915->drm, tc->link_refcount != 1);1567	if (!tc_port_has_active_links(tc, crtc_state)) {1568		/*1569		 * TBT-alt is the default mode in any case the PHY ownership is not1570		 * held (regardless of the sink's connected live state), so1571		 * we'll just switch to disconnected mode from it here without1572		 * a note.1573		 */1574		if (tc->init_mode != TC_PORT_TBT_ALT &&1575		    tc->init_mode != TC_PORT_DISCONNECTED)1576			drm_dbg_kms(&i915->drm,1577				    "Port %s: PHY left in %s mode on disabled port, disconnecting it\n",1578				    tc->port_name,1579				    tc_port_mode_name(tc->init_mode));1580		tc_phy_disconnect(tc);1581		__intel_tc_port_put_link(tc);1582	}1583 1584	drm_dbg_kms(&i915->drm, "Port %s: sanitize mode (%s)\n",1585		    tc->port_name,1586		    tc_port_mode_name(tc->mode));1587 1588	mutex_unlock(&tc->lock);1589}1590 1591/*1592 * The type-C ports are different because even when they are connected, they may1593 * not be available/usable by the graphics driver: see the comment on1594 * icl_tc_phy_connect(). So in our driver instead of adding the additional1595 * concept of "usable" and make everything check for "connected and usable" we1596 * define a port as "connected" when it is not only connected, but also when it1597 * is usable by the rest of the driver. That maintains the old assumption that1598 * connected ports are usable, and avoids exposing to the users objects they1599 * can't really use.1600 */1601bool intel_tc_port_connected(struct intel_encoder *encoder)1602{1603	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);1604	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);1605	struct intel_tc_port *tc = to_tc_port(dig_port);1606	u32 mask = ~0;1607 1608	drm_WARN_ON(&i915->drm, !intel_tc_port_ref_held(dig_port));1609 1610	if (tc->mode != TC_PORT_DISCONNECTED)1611		mask = BIT(tc->mode);1612 1613	return tc_phy_hpd_live_status(tc) & mask;1614}1615 1616static bool __intel_tc_port_link_needs_reset(struct intel_tc_port *tc)1617{1618	bool ret;1619 1620	mutex_lock(&tc->lock);1621 1622	ret = tc->link_refcount &&1623	      tc->mode == TC_PORT_DP_ALT &&1624	      intel_tc_port_needs_reset(tc);1625 1626	mutex_unlock(&tc->lock);1627 1628	return ret;1629}1630 1631bool intel_tc_port_link_needs_reset(struct intel_digital_port *dig_port)1632{1633	if (!intel_encoder_is_tc(&dig_port->base))1634		return false;1635 1636	return __intel_tc_port_link_needs_reset(to_tc_port(dig_port));1637}1638 1639static int reset_link_commit(struct intel_tc_port *tc,1640			     struct intel_atomic_state *state,1641			     struct drm_modeset_acquire_ctx *ctx)1642{1643	struct drm_i915_private *i915 = tc_to_i915(tc);1644	struct intel_digital_port *dig_port = tc->dig_port;1645	struct intel_dp *intel_dp = enc_to_intel_dp(&dig_port->base);1646	struct intel_crtc *crtc;1647	u8 pipe_mask;1648	int ret;1649 1650	ret = drm_modeset_lock(&i915->drm.mode_config.connection_mutex, ctx);1651	if (ret)1652		return ret;1653 1654	ret = intel_dp_get_active_pipes(intel_dp, ctx, &pipe_mask);1655	if (ret)1656		return ret;1657 1658	if (!pipe_mask)1659		return 0;1660 1661	for_each_intel_crtc_in_pipe_mask(&i915->drm, crtc, pipe_mask) {1662		struct intel_crtc_state *crtc_state;1663 1664		crtc_state = intel_atomic_get_crtc_state(&state->base, crtc);1665		if (IS_ERR(crtc_state))1666			return PTR_ERR(crtc_state);1667 1668		crtc_state->uapi.connectors_changed = true;1669	}1670 1671	if (!__intel_tc_port_link_needs_reset(tc))1672		return 0;1673 1674	return drm_atomic_commit(&state->base);1675}1676 1677static int reset_link(struct intel_tc_port *tc)1678{1679	struct drm_i915_private *i915 = tc_to_i915(tc);1680	struct drm_modeset_acquire_ctx ctx;1681	struct drm_atomic_state *_state;1682	struct intel_atomic_state *state;1683	int ret;1684 1685	_state = drm_atomic_state_alloc(&i915->drm);1686	if (!_state)1687		return -ENOMEM;1688 1689	state = to_intel_atomic_state(_state);1690	state->internal = true;1691 1692	intel_modeset_lock_ctx_retry(&ctx, state, 0, ret)1693		ret = reset_link_commit(tc, state, &ctx);1694 1695	drm_atomic_state_put(&state->base);1696 1697	return ret;1698}1699 1700static void intel_tc_port_link_reset_work(struct work_struct *work)1701{1702	struct intel_tc_port *tc =1703		container_of(work, struct intel_tc_port, link_reset_work.work);1704	struct drm_i915_private *i915 = tc_to_i915(tc);1705	int ret;1706 1707	if (!__intel_tc_port_link_needs_reset(tc))1708		return;1709 1710	mutex_lock(&i915->drm.mode_config.mutex);1711 1712	drm_dbg_kms(&i915->drm,1713		    "Port %s: TypeC DP-alt sink disconnected, resetting link\n",1714		    tc->port_name);1715	ret = reset_link(tc);1716	drm_WARN_ON(&i915->drm, ret);1717 1718	mutex_unlock(&i915->drm.mode_config.mutex);1719}1720 1721bool intel_tc_port_link_reset(struct intel_digital_port *dig_port)1722{1723	if (!intel_tc_port_link_needs_reset(dig_port))1724		return false;1725 1726	queue_delayed_work(system_unbound_wq,1727			   &to_tc_port(dig_port)->link_reset_work,1728			   msecs_to_jiffies(2000));1729 1730	return true;1731}1732 1733void intel_tc_port_link_cancel_reset_work(struct intel_digital_port *dig_port)1734{1735	struct intel_tc_port *tc = to_tc_port(dig_port);1736 1737	if (!intel_encoder_is_tc(&dig_port->base))1738		return;1739 1740	cancel_delayed_work(&tc->link_reset_work);1741}1742 1743static void __intel_tc_port_lock(struct intel_tc_port *tc,1744				 int required_lanes)1745{1746	struct drm_i915_private *i915 = tc_to_i915(tc);1747 1748	mutex_lock(&tc->lock);1749 1750	cancel_delayed_work(&tc->disconnect_phy_work);1751 1752	if (!tc->link_refcount)1753		intel_tc_port_update_mode(tc, required_lanes,1754					  false);1755 1756	drm_WARN_ON(&i915->drm, tc->mode == TC_PORT_DISCONNECTED);1757	drm_WARN_ON(&i915->drm, tc->mode != TC_PORT_TBT_ALT &&1758				!tc_phy_is_owned(tc));1759}1760 1761void intel_tc_port_lock(struct intel_digital_port *dig_port)1762{1763	__intel_tc_port_lock(to_tc_port(dig_port), 1);1764}1765 1766/*1767 * Disconnect the given digital port from its TypeC PHY (handing back the1768 * control of the PHY to the TypeC subsystem). This will happen in a delayed1769 * manner after each aux transactions and modeset disables.1770 */1771static void intel_tc_port_disconnect_phy_work(struct work_struct *work)1772{1773	struct intel_tc_port *tc =1774		container_of(work, struct intel_tc_port, disconnect_phy_work.work);1775 1776	mutex_lock(&tc->lock);1777 1778	if (!tc->link_refcount)1779		intel_tc_port_update_mode(tc, 1, true);1780 1781	mutex_unlock(&tc->lock);1782}1783 1784/**1785 * intel_tc_port_flush_work: flush the work disconnecting the PHY1786 * @dig_port: digital port1787 *1788 * Flush the delayed work disconnecting an idle PHY.1789 */1790static void intel_tc_port_flush_work(struct intel_digital_port *dig_port)1791{1792	flush_delayed_work(&to_tc_port(dig_port)->disconnect_phy_work);1793}1794 1795void intel_tc_port_suspend(struct intel_digital_port *dig_port)1796{1797	struct intel_tc_port *tc = to_tc_port(dig_port);1798 1799	cancel_delayed_work_sync(&tc->link_reset_work);1800	intel_tc_port_flush_work(dig_port);1801}1802 1803void intel_tc_port_unlock(struct intel_digital_port *dig_port)1804{1805	struct intel_tc_port *tc = to_tc_port(dig_port);1806 1807	if (!tc->link_refcount && tc->mode != TC_PORT_DISCONNECTED)1808		queue_delayed_work(system_unbound_wq, &tc->disconnect_phy_work,1809				   msecs_to_jiffies(1000));1810 1811	mutex_unlock(&tc->lock);1812}1813 1814bool intel_tc_port_ref_held(struct intel_digital_port *dig_port)1815{1816	struct intel_tc_port *tc = to_tc_port(dig_port);1817 1818	return mutex_is_locked(&tc->lock) ||1819	       tc->link_refcount;1820}1821 1822void intel_tc_port_get_link(struct intel_digital_port *dig_port,1823			    int required_lanes)1824{1825	struct intel_tc_port *tc = to_tc_port(dig_port);1826 1827	__intel_tc_port_lock(tc, required_lanes);1828	__intel_tc_port_get_link(tc);1829	intel_tc_port_unlock(dig_port);1830}1831 1832void intel_tc_port_put_link(struct intel_digital_port *dig_port)1833{1834	struct intel_tc_port *tc = to_tc_port(dig_port);1835 1836	intel_tc_port_lock(dig_port);1837	__intel_tc_port_put_link(tc);1838	intel_tc_port_unlock(dig_port);1839 1840	/*1841	 * The firmware will not update the HPD status of other TypeC ports1842	 * that are active in DP-alt mode with their sink disconnected, until1843	 * this port is disabled and its PHY gets disconnected. Make sure this1844	 * happens in a timely manner by disconnecting the PHY synchronously.1845	 */1846	intel_tc_port_flush_work(dig_port);1847}1848 1849int intel_tc_port_init(struct intel_digital_port *dig_port, bool is_legacy)1850{1851	struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);1852	struct intel_tc_port *tc;1853	enum port port = dig_port->base.port;1854	enum tc_port tc_port = intel_encoder_to_tc(&dig_port->base);1855 1856	if (drm_WARN_ON(&i915->drm, tc_port == TC_PORT_NONE))1857		return -EINVAL;1858 1859	tc = kzalloc(sizeof(*tc), GFP_KERNEL);1860	if (!tc)1861		return -ENOMEM;1862 1863	dig_port->tc = tc;1864	tc->dig_port = dig_port;1865 1866	if (DISPLAY_VER(i915) >= 14)1867		tc->phy_ops = &xelpdp_tc_phy_ops;1868	else if (DISPLAY_VER(i915) >= 13)1869		tc->phy_ops = &adlp_tc_phy_ops;1870	else if (DISPLAY_VER(i915) >= 12)1871		tc->phy_ops = &tgl_tc_phy_ops;1872	else1873		tc->phy_ops = &icl_tc_phy_ops;1874 1875	tc->port_name = kasprintf(GFP_KERNEL, "%c/TC#%d", port_name(port),1876				  tc_port + 1);1877	if (!tc->port_name) {1878		kfree(tc);1879		return -ENOMEM;1880	}1881 1882	mutex_init(&tc->lock);1883	/* TODO: Combine the two works */1884	INIT_DELAYED_WORK(&tc->disconnect_phy_work, intel_tc_port_disconnect_phy_work);1885	INIT_DELAYED_WORK(&tc->link_reset_work, intel_tc_port_link_reset_work);1886	tc->legacy_port = is_legacy;1887	tc->mode = TC_PORT_DISCONNECTED;1888	tc->link_refcount = 0;1889 1890	tc_phy_init(tc);1891 1892	intel_tc_port_init_mode(dig_port);1893 1894	return 0;1895}1896 1897void intel_tc_port_cleanup(struct intel_digital_port *dig_port)1898{1899	intel_tc_port_suspend(dig_port);1900 1901	kfree(dig_port->tc->port_name);1902	kfree(dig_port->tc);1903	dig_port->tc = NULL;1904}1905