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