Commit 91888b5b authored by Imre Deak's avatar Imre Deak

drm/i915/dp: Add support for DP tunnel BW allocation

Add support to enable the DP tunnel BW allocation mode. Follow-up
patches will call the required helpers added here to prepare for a
modeset on a link with DP tunnels, the last change in the patchset
actually enabling BWA.

With BWA enabled, the driver will expose the full mode list a display
supports, regardless of any BW limitation on a shared (Thunderbolt)
link. Such BW limits will be checked against only during a modeset, when
the driver has the full knowledge of each display's BW requirement.

If the link BW changes in a way that a connector's modelist may also
change, userspace will get a hotplug notification for all the connectors
sharing the same link (so it can adjust the mode used for a display).

The BW limitation can change at any point, asynchronously to modesets
on a given connector, so a modeset can fail even though the atomic check
for it passed. In such scenarios userspace will get a bad link
notification and in response is supposed to retry the modeset.

v2:
- Fix old vs. new connector state in intel_dp_tunnel_atomic_check_state().
  (Ville)
- Fix propagating the error from
  intel_dp_tunnel_atomic_compute_stream_bw(). (Ville)
- Move tunnel==NULL checks from driver to DRM core helpers. (Ville)
- Simplify return flow from intel_dp_tunnel_detect(). (Ville)
- s/dp_tunnel_state/inherited_dp_tunnels (Ville)
- Simplify struct intel_dp_tunnel_inherited_state. (Ville)
- Unconstify object pointers (vs. states) where possible. (Ville)
- Init crtc_state while declaring it in check_group_state(). (Ville)
- Join obj->base.id, obj->name arg lines in debug prints to reduce LOC.
  (Ville)
- Add/rework intel_dp_tunnel_atomic_alloc_bw() to prepare for moving the
  BW allocation from encoder hooks up to intel_atomic_commit_tail()
  later in the patchset.
- Disable BW alloc mode during system suspend.
- Allocate the required BW for all tunnels during system resume.
- Add intel_dp_tunnel_atomic_clear_stream_bw() instead of the open-coded
  sequence in a follow-up patch.
- Add function documentation to all exported functions.
- Add CONFIG_USB4 dependency to CONFIG_DRM_I915_DP_TUNNEL.

v3:
- Rebase on intel_dp_get_active_pipes() change in previous patch.

Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: default avatarUma Shankar <uma.shankar@intel.com>
Signed-off-by: default avatarImre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240226185246.1276018-4-imre.deak@intel.com
parent 199c7d75
...@@ -155,6 +155,20 @@ config DRM_I915_PXP ...@@ -155,6 +155,20 @@ config DRM_I915_PXP
protected session and manage the status of the alive software session, protected session and manage the status of the alive software session,
as well as its life cycle. as well as its life cycle.
config DRM_I915_DP_TUNNEL
bool "Enable DP tunnel support"
depends on DRM_I915
depends on USB4
select DRM_DISPLAY_DP_TUNNEL
default y
help
Choose this option to detect DP tunnels and enable the Bandwidth
Allocation mode for such tunnels. This allows using the maximum
resolution allowed by the link BW on all displays sharing the
link BW, for instance on a Thunderbolt link.
If in doubt, say "Y".
menu "drm/i915 Debugging" menu "drm/i915 Debugging"
depends on DRM_I915 depends on DRM_I915
depends on EXPERT depends on EXPERT
......
...@@ -28,6 +28,7 @@ config DRM_I915_DEBUG ...@@ -28,6 +28,7 @@ config DRM_I915_DEBUG
select STACKDEPOT select STACKDEPOT
select STACKTRACE select STACKTRACE
select DRM_DP_AUX_CHARDEV select DRM_DP_AUX_CHARDEV
select DRM_DISPLAY_DEBUG_DP_TUNNEL_STATE if DRM_I915_DP_TUNNEL
select X86_MSR # used by igt/pm_rpm select X86_MSR # used by igt/pm_rpm
select DRM_VGEM # used by igt/prime_vgem (dmabuf interop checks) select DRM_VGEM # used by igt/prime_vgem (dmabuf interop checks)
select DRM_DEBUG_MM if DRM=y select DRM_DEBUG_MM if DRM=y
......
...@@ -369,6 +369,9 @@ i915-y += \ ...@@ -369,6 +369,9 @@ i915-y += \
display/vlv_dsi.o \ display/vlv_dsi.o \
display/vlv_dsi_pll.o display/vlv_dsi_pll.o
i915-$(CONFIG_DRM_I915_DP_TUNNEL) += \
display/intel_dp_tunnel.o
i915-y += \ i915-y += \
i915_perf.o i915_perf.o
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
* See intel_atomic_plane.c for the plane-specific atomic functionality. * See intel_atomic_plane.c for the plane-specific atomic functionality.
*/ */
#include <drm/display/drm_dp_tunnel.h>
#include <drm/drm_atomic.h> #include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_fourcc.h> #include <drm/drm_fourcc.h>
...@@ -38,6 +39,7 @@ ...@@ -38,6 +39,7 @@
#include "intel_atomic.h" #include "intel_atomic.h"
#include "intel_cdclk.h" #include "intel_cdclk.h"
#include "intel_display_types.h" #include "intel_display_types.h"
#include "intel_dp_tunnel.h"
#include "intel_global_state.h" #include "intel_global_state.h"
#include "intel_hdcp.h" #include "intel_hdcp.h"
#include "intel_psr.h" #include "intel_psr.h"
......
...@@ -524,6 +524,7 @@ struct intel_display { ...@@ -524,6 +524,7 @@ struct intel_display {
} wq; } wq;
/* Grouping using named structs. Keep sorted. */ /* Grouping using named structs. Keep sorted. */
struct drm_dp_tunnel_mgr *dp_tunnel_mgr;
struct intel_audio audio; struct intel_audio audio;
struct intel_dpll dpll; struct intel_dpll dpll;
struct intel_fbc *fbc[I915_MAX_FBCS]; struct intel_fbc *fbc[I915_MAX_FBCS];
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <drm/display/drm_dp_dual_mode_helper.h> #include <drm/display/drm_dp_dual_mode_helper.h>
#include <drm/display/drm_dp_mst_helper.h> #include <drm/display/drm_dp_mst_helper.h>
#include <drm/display/drm_dp_tunnel.h>
#include <drm/display/drm_dsc.h> #include <drm/display/drm_dsc.h>
#include <drm/drm_atomic.h> #include <drm/drm_atomic.h>
#include <drm/drm_crtc.h> #include <drm/drm_crtc.h>
...@@ -682,6 +683,8 @@ struct intel_atomic_state { ...@@ -682,6 +683,8 @@ struct intel_atomic_state {
struct intel_shared_dpll_state shared_dpll[I915_NUM_PLLS]; struct intel_shared_dpll_state shared_dpll[I915_NUM_PLLS];
struct intel_dp_tunnel_inherited_state *inherited_dp_tunnels;
/* /*
* Current watermarks can't be trusted during hardware readout, so * Current watermarks can't be trusted during hardware readout, so
* don't bother calculating intermediate watermarks. * don't bother calculating intermediate watermarks.
...@@ -1379,6 +1382,9 @@ struct intel_crtc_state { ...@@ -1379,6 +1382,9 @@ struct intel_crtc_state {
struct drm_dsc_config config; struct drm_dsc_config config;
} dsc; } dsc;
/* DP tunnel used for BW allocation. */
struct drm_dp_tunnel_ref dp_tunnel_ref;
/* HSW+ linetime watermarks */ /* HSW+ linetime watermarks */
u16 linetime; u16 linetime;
u16 ips_linetime; u16 ips_linetime;
...@@ -1789,6 +1795,9 @@ struct intel_dp { ...@@ -1789,6 +1795,9 @@ struct intel_dp {
/* connector directly attached - won't be use for modeset in mst world */ /* connector directly attached - won't be use for modeset in mst world */
struct intel_connector *attached_connector; struct intel_connector *attached_connector;
struct drm_dp_tunnel *tunnel;
bool tunnel_suspended:1;
/* mst connector list */ /* mst connector list */
struct intel_dp_mst_encoder *mst_encoders[I915_MAX_PIPES]; struct intel_dp_mst_encoder *mst_encoders[I915_MAX_PIPES];
struct drm_dp_mst_topology_mgr mst_mgr; struct drm_dp_mst_topology_mgr mst_mgr;
......
This diff is collapsed.
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef __INTEL_DP_TUNNEL_H__
#define __INTEL_DP_TUNNEL_H__
#include <linux/errno.h>
#include <linux/types.h>
struct drm_i915_private;
struct drm_connector_state;
struct drm_modeset_acquire_ctx;
struct intel_atomic_state;
struct intel_connector;
struct intel_crtc;
struct intel_crtc_state;
struct intel_dp;
struct intel_encoder;
struct intel_link_bw_limits;
#if defined(CONFIG_DRM_I915_DP_TUNNEL) && defined(I915)
int intel_dp_tunnel_detect(struct intel_dp *intel_dp, struct drm_modeset_acquire_ctx *ctx);
void intel_dp_tunnel_disconnect(struct intel_dp *intel_dp);
void intel_dp_tunnel_destroy(struct intel_dp *intel_dp);
void intel_dp_tunnel_resume(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state,
bool dpcd_updated);
void intel_dp_tunnel_suspend(struct intel_dp *intel_dp);
bool intel_dp_tunnel_bw_alloc_is_enabled(struct intel_dp *intel_dp);
void
intel_dp_tunnel_atomic_cleanup_inherited_state(struct intel_atomic_state *state);
int intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state,
struct intel_dp *intel_dp,
const struct intel_connector *connector,
struct intel_crtc_state *crtc_state);
void intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,
struct intel_crtc_state *crtc_state);
int intel_dp_tunnel_atomic_add_state_for_crtc(struct intel_atomic_state *state,
struct intel_crtc *crtc);
int intel_dp_tunnel_atomic_check_link(struct intel_atomic_state *state,
struct intel_link_bw_limits *limits);
int intel_dp_tunnel_atomic_check_state(struct intel_atomic_state *state,
struct intel_dp *intel_dp,
struct intel_connector *connector);
void intel_dp_tunnel_atomic_alloc_bw(struct intel_atomic_state *state);
int intel_dp_tunnel_mgr_init(struct drm_i915_private *i915);
void intel_dp_tunnel_mgr_cleanup(struct drm_i915_private *i915);
#else
static inline int
intel_dp_tunnel_detect(struct intel_dp *intel_dp, struct drm_modeset_acquire_ctx *ctx)
{
return -EOPNOTSUPP;
}
static inline void intel_dp_tunnel_disconnect(struct intel_dp *intel_dp) {}
static inline void intel_dp_tunnel_destroy(struct intel_dp *intel_dp) {}
static inline void intel_dp_tunnel_resume(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state,
bool dpcd_updated) {}
static inline void intel_dp_tunnel_suspend(struct intel_dp *intel_dp) {}
static inline bool intel_dp_tunnel_bw_alloc_is_enabled(struct intel_dp *intel_dp)
{
return false;
}
static inline void
intel_dp_tunnel_atomic_cleanup_inherited_state(struct intel_atomic_state *state) {}
static inline int
intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state,
struct intel_dp *intel_dp,
const struct intel_connector *connector,
struct intel_crtc_state *crtc_state)
{
return 0;
}
static inline void
intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,
struct intel_crtc_state *crtc_state) {}
static inline int
intel_dp_tunnel_atomic_add_state_for_crtc(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
return 0;
}
static inline int
intel_dp_tunnel_atomic_check_link(struct intel_atomic_state *state,
struct intel_link_bw_limits *limits)
{
return 0;
}
static inline int
intel_dp_tunnel_atomic_check_state(struct intel_atomic_state *state,
struct intel_dp *intel_dp,
struct intel_connector *connector)
{
return 0;
}
static inline int
intel_dp_tunnel_atomic_alloc_bw(struct intel_atomic_state *state)
{
return 0;
}
static inline int
intel_dp_tunnel_mgr_init(struct drm_i915_private *i915)
{
return 0;
}
static inline void intel_dp_tunnel_mgr_cleanup(struct drm_i915_private *i915) {}
#endif /* CONFIG_DRM_I915_DP_TUNNEL */
#endif /* __INTEL_DP_TUNNEL_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment