If the output on a DP-alt link with its sink disconnected is kept enabled for too long (about 20 sec), then some IOM/TCSS firmware timeout will cause havoc on the PCI bus, at least for other GFX devices on it which will stop powering up. Since user space is not guaranteed to do a disabling modeset in time, switch such disconnected but active links to TBT mode - which is without such shortcomings - with a 2 second delay. If the above condition is detected already during the driver load/system resume sanitization step disable the output instead, as at that point no user space or kernel client depends on a consistent output state yet and because subsequent atomic modeset on such connectors - without the actual sink capabilities available - can fail. An active/disconnected port as above will also block the HPD status of other active/disconnected ports to get updated (stuck in the connected state), until the former port is disabled, its PHY is disconnected and a ~10 ms delay has elapsed. This means the link state for all TypeC ports/CRTCs must be rechecked after a CRTC is disabled due to the above reason. For this disconnect the PHY synchronously after the CRTC/port is disabled and recheck all CRTCs for the above condition whenever such a port is disabled. To account for a race condition during driver loading where the sink is disconnected after the above sanitization step and before the HPD interrupts get enabled, do an explicit check/link reset if needed from the encoder's late_register hook, which is called after the HPD interrupts are enabled already. v2: - Handle an active/disconnected port blocking the HPD state update of another active/disconnected port. - Cancel the delayed work resetting the link also from the encoder enable/suspend/shutdown hooks. - Rebase on the earlier intel_modeset_lock_ctx_retry() addition, fixing here the missed atomic state reset in case of a retry. - Fix handling of an error return from intel_atomic_get_crtc_state(). - Recheck if the port needs to be reset after all the atomic state is locked and async commits are waited on. v3: - Add intel_crtc_needs_link_reset(), instead of open-coding it, keep intel_crtc_has_encoders(). (Ville) - Fix state dumping and use a bitmask to track disabled CRTCs in intel_sanitize_all_crtcs(). (Ville) - Set internal in intel_atomic_state right after allocating it. (Ville) - Recheck all CRTCs (not yet force-disabled) after a CRTC is force-disabled for any reason (not only due to a link state) in intel_sanitize_all_crtcs(). - Reduce delay after CRTC disabling to 20ms, and use the simpler msleep(). - Clarify code comment about HPD behaviour in intel_sanitize_all_crtcs(). - Move all the TC link reset logic to intel_tc.c . - Cancel the link reset work synchronously during system suspend, driver unload and shutdown. v4: - Rebased on previous patch, which allows calling the TC port suspend/cleanup handlers without modeset locks held; remove the display driver suspended assert from the link reset work accordingly. v5: (Ville) - Remove reset work canceling from intel_ddi_pre_pll_enable(). - Track a crtc vs. pipe mask in intel_sanitize_all_crtcs(). - Add reset_link_commit() to clarify the intel_modeset_lock_ctx_retry loop. Cc: Kai-Heng Feng <kai.heng.feng@canonical.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Tested-by: Kai-Heng Feng <kai.heng.feng@canonical.com> Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/5860 Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Imre Deak <imre.deak@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20230512195513.2699-2-imre.deak@intel.com
47 lines
1.9 KiB
C
47 lines
1.9 KiB
C
/* SPDX-License-Identifier: MIT */
|
|
/*
|
|
* Copyright © 2019 Intel Corporation
|
|
*/
|
|
|
|
#ifndef __INTEL_TC_H__
|
|
#define __INTEL_TC_H__
|
|
|
|
#include <linux/types.h>
|
|
|
|
struct intel_crtc_state;
|
|
struct intel_digital_port;
|
|
struct intel_encoder;
|
|
|
|
bool intel_tc_port_in_tbt_alt_mode(struct intel_digital_port *dig_port);
|
|
bool intel_tc_port_in_dp_alt_mode(struct intel_digital_port *dig_port);
|
|
bool intel_tc_port_in_legacy_mode(struct intel_digital_port *dig_port);
|
|
|
|
bool intel_tc_port_connected(struct intel_encoder *encoder);
|
|
bool intel_tc_port_connected_locked(struct intel_encoder *encoder);
|
|
|
|
u32 intel_tc_port_get_lane_mask(struct intel_digital_port *dig_port);
|
|
u32 intel_tc_port_get_pin_assignment_mask(struct intel_digital_port *dig_port);
|
|
int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port);
|
|
void intel_tc_port_set_fia_lane_count(struct intel_digital_port *dig_port,
|
|
int required_lanes);
|
|
|
|
void intel_tc_port_init_mode(struct intel_digital_port *dig_port);
|
|
void intel_tc_port_sanitize_mode(struct intel_digital_port *dig_port,
|
|
const struct intel_crtc_state *crtc_state);
|
|
void intel_tc_port_lock(struct intel_digital_port *dig_port);
|
|
void intel_tc_port_unlock(struct intel_digital_port *dig_port);
|
|
void intel_tc_port_suspend(struct intel_digital_port *dig_port);
|
|
void intel_tc_port_get_link(struct intel_digital_port *dig_port,
|
|
int required_lanes);
|
|
void intel_tc_port_put_link(struct intel_digital_port *dig_port);
|
|
bool intel_tc_port_ref_held(struct intel_digital_port *dig_port);
|
|
bool intel_tc_port_link_needs_reset(struct intel_digital_port *dig_port);
|
|
bool intel_tc_port_link_reset(struct intel_digital_port *dig_port);
|
|
void intel_tc_port_link_cancel_reset_work(struct intel_digital_port *dig_port);
|
|
|
|
int intel_tc_port_init(struct intel_digital_port *dig_port, bool is_legacy);
|
|
void intel_tc_port_cleanup(struct intel_digital_port *dig_port);
|
|
|
|
bool intel_tc_cold_requires_aux_pw(struct intel_digital_port *dig_port);
|
|
|
|
#endif /* __INTEL_TC_H__ */
|