summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_dp_tunnel.c')
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_tunnel.c122
1 files changed, 84 insertions, 38 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
index 589872babdd7..7363c9817297 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
@@ -4,6 +4,7 @@
*/
#include <drm/display/drm_dp_tunnel.h>
+#include <drm/drm_print.h>
#include "intel_atomic.h"
#include "intel_display_core.h"
@@ -53,31 +54,20 @@ static int kbytes_to_mbits(int kbytes)
return DIV_ROUND_UP(kbytes * 8, 1000);
}
-static int get_current_link_bw(struct intel_dp *intel_dp,
- bool *below_dprx_bw)
+static int get_current_link_bw(struct intel_dp *intel_dp)
{
int rate = intel_dp_max_common_rate(intel_dp);
int lane_count = intel_dp_max_common_lane_count(intel_dp);
- int bw;
- bw = intel_dp_max_link_data_rate(intel_dp, rate, lane_count);
- *below_dprx_bw = bw < drm_dp_max_dprx_data_rate(rate, lane_count);
-
- return bw;
+ return intel_dp_max_link_data_rate(intel_dp, rate, lane_count);
}
-static int update_tunnel_state(struct intel_dp *intel_dp)
+static int __update_tunnel_state(struct intel_dp *intel_dp, bool force_sink_update)
{
struct intel_display *display = to_intel_display(intel_dp);
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
- bool old_bw_below_dprx;
- bool new_bw_below_dprx;
- int old_bw;
- int new_bw;
int ret;
- old_bw = get_current_link_bw(intel_dp, &old_bw_below_dprx);
-
ret = drm_dp_tunnel_update_state(intel_dp->tunnel);
if (ret < 0) {
drm_dbg_kms(display->drm,
@@ -89,18 +79,26 @@ static int update_tunnel_state(struct intel_dp *intel_dp)
return ret;
}
- if (ret == 0 ||
- !drm_dp_tunnel_bw_alloc_is_enabled(intel_dp->tunnel))
+ if (!force_sink_update &&
+ (ret == 0 || !drm_dp_tunnel_bw_alloc_is_enabled(intel_dp->tunnel)))
return 0;
intel_dp_update_sink_caps(intel_dp);
- new_bw = get_current_link_bw(intel_dp, &new_bw_below_dprx);
+ return 0;
+}
+
+static bool has_tunnel_bw_changed(struct intel_dp *intel_dp, int old_bw)
+{
+ struct intel_display *display = to_intel_display(intel_dp);
+ struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+ int new_bw;
+
+ new_bw = get_current_link_bw(intel_dp);
/* Suppress the notification if the mode list can't change due to bw. */
- if (old_bw_below_dprx == new_bw_below_dprx &&
- !new_bw_below_dprx)
- return 0;
+ if (old_bw == new_bw)
+ return false;
drm_dbg_kms(display->drm,
"[DPTUN %s][ENCODER:%d:%s] Notify users about BW change: %d -> %d\n",
@@ -108,7 +106,29 @@ static int update_tunnel_state(struct intel_dp *intel_dp)
encoder->base.base.id, encoder->base.name,
kbytes_to_mbits(old_bw), kbytes_to_mbits(new_bw));
- return 1;
+ return true;
+}
+
+/*
+ * Returns:
+ * - 0 in case of success - if there wasn't any change in the tunnel state
+ * requiring a user notification
+ * - 1 in case of success - if there was a change in the tunnel state
+ * requiring a user notification
+ * - Negative error code if updating the tunnel state failed
+ */
+static int update_tunnel_state(struct intel_dp *intel_dp)
+{
+ int old_bw;
+ int err;
+
+ old_bw = get_current_link_bw(intel_dp);
+
+ err = __update_tunnel_state(intel_dp, false);
+ if (err)
+ return err;
+
+ return has_tunnel_bw_changed(intel_dp, old_bw) ? 1 : 0;
}
/*
@@ -149,11 +169,9 @@ static int allocate_initial_tunnel_bw_for_pipes(struct intel_dp *intel_dp, u8 pi
drm_dp_tunnel_name(intel_dp->tunnel),
encoder->base.base.id, encoder->base.name,
ERR_PTR(err));
-
- return err;
}
- return update_tunnel_state(intel_dp);
+ return err;
}
static int allocate_initial_tunnel_bw(struct intel_dp *intel_dp,
@@ -169,13 +187,24 @@ static int allocate_initial_tunnel_bw(struct intel_dp *intel_dp,
return allocate_initial_tunnel_bw_for_pipes(intel_dp, pipe_mask);
}
+/*
+ * Returns:
+ * - 0 in case of success - after any tunnel detected and added to @intel_dp
+ * - 1 in case of success - after a tunnel detected and added to @intel_dp,
+ * where the link BW via the tunnel changed in a way requiring a user
+ * notification
+ * - Negative error code if the tunnel detection failed
+ */
static int detect_new_tunnel(struct intel_dp *intel_dp, struct drm_modeset_acquire_ctx *ctx)
{
struct intel_display *display = to_intel_display(intel_dp);
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
struct drm_dp_tunnel *tunnel;
+ int old_bw;
int ret;
+ old_bw = get_current_link_bw(intel_dp);
+
tunnel = drm_dp_tunnel_detect(display->dp_tunnel_mgr,
&intel_dp->aux);
if (IS_ERR(tunnel))
@@ -199,10 +228,17 @@ static int detect_new_tunnel(struct intel_dp *intel_dp, struct drm_modeset_acqui
}
ret = allocate_initial_tunnel_bw(intel_dp, ctx);
- if (ret < 0)
+ if (ret < 0) {
intel_dp_tunnel_destroy(intel_dp);
- return ret;
+ return ret;
+ }
+
+ ret = __update_tunnel_state(intel_dp, true);
+ if (ret)
+ return ret;
+
+ return has_tunnel_bw_changed(intel_dp, old_bw) ? 1 : 0;
}
/**
@@ -220,9 +256,12 @@ static int detect_new_tunnel(struct intel_dp *intel_dp, struct drm_modeset_acqui
* tunnel. If the tunnel's state change requires this - for instance the
* tunnel's group ID has changed - the tunnel will be dropped and recreated.
*
- * Return 0 in case of success - after any tunnel detected and added to
- * @intel_dp - 1 in case the BW on an already existing tunnel has changed in a
- * way that requires notifying user space.
+ * Returns:
+ * - 0 in case of success - after any tunnel detected and added to @intel_dp
+ * - 1 in case the link BW via the new or an already existing tunnel has changed
+ * in a way that requires notifying user space
+ * - Negative error code, if creating a new tunnel or updating the tunnel
+ * state failed
*/
int intel_dp_tunnel_detect(struct intel_dp *intel_dp, struct drm_modeset_acquire_ctx *ctx)
{
@@ -380,8 +419,7 @@ add_inherited_tunnel(struct intel_atomic_state *state,
}
if (!state->inherited_dp_tunnels) {
- state->inherited_dp_tunnels = kzalloc(sizeof(*state->inherited_dp_tunnels),
- GFP_KERNEL);
+ state->inherited_dp_tunnels = kzalloc_obj(*state->inherited_dp_tunnels);
if (!state->inherited_dp_tunnels)
return -ENOMEM;
}
@@ -621,19 +659,27 @@ int intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state,
*
* Clear any DP tunnel stream BW requirement set by
* intel_dp_tunnel_atomic_compute_stream_bw().
+ *
+ * Returns 0 in case of success, a negative error code otherwise.
*/
-void intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,
- struct intel_crtc_state *crtc_state)
+int intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,
+ struct intel_crtc_state *crtc_state)
{
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+ int err;
if (!crtc_state->dp_tunnel_ref.tunnel)
- return;
+ return 0;
+
+ err = drm_dp_tunnel_atomic_set_stream_bw(&state->base,
+ crtc_state->dp_tunnel_ref.tunnel,
+ crtc->pipe, 0);
+ if (err)
+ return err;
- drm_dp_tunnel_atomic_set_stream_bw(&state->base,
- crtc_state->dp_tunnel_ref.tunnel,
- crtc->pipe, 0);
drm_dp_tunnel_ref_put(&crtc_state->dp_tunnel_ref);
+
+ return 0;
}
/**
@@ -647,7 +693,7 @@ void intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,
* @state must be recomputed with the updated @limits.
*
* Returns:
- * - 0 if the confugration is valid
+ * - 0 if the configuration is valid
* - %-EAGAIN, if the configuration is invalid and @limits got updated
* with fallback values with which the configuration of all CRTCs in
* @state must be recomputed