815 lines · c
1// SPDX-License-Identifier: MIT2/*3 * Copyright © 2023 Intel Corporation4 */5 6#include "i915_drv.h"7 8#include <drm/display/drm_dp_tunnel.h>9 10#include "intel_atomic.h"11#include "intel_display_limits.h"12#include "intel_display_types.h"13#include "intel_dp.h"14#include "intel_dp_link_training.h"15#include "intel_dp_mst.h"16#include "intel_dp_tunnel.h"17#include "intel_link_bw.h"18 19struct intel_dp_tunnel_inherited_state {20 struct drm_dp_tunnel_ref ref[I915_MAX_PIPES];21};22 23/**24 * intel_dp_tunnel_disconnect - Disconnect a DP tunnel from a port25 * @intel_dp: DP port object the tunnel is connected to26 *27 * Disconnect a DP tunnel from @intel_dp, destroying any related state. This28 * should be called after detecting a sink-disconnect event from the port.29 */30void intel_dp_tunnel_disconnect(struct intel_dp *intel_dp)31{32 drm_dp_tunnel_destroy(intel_dp->tunnel);33 intel_dp->tunnel = NULL;34}35 36/**37 * intel_dp_tunnel_destroy - Destroy a DP tunnel38 * @intel_dp: DP port object the tunnel is connected to39 *40 * Destroy a DP tunnel connected to @intel_dp, after disabling the BW41 * allocation mode on the tunnel. This should be called while destroying the42 * port.43 */44void intel_dp_tunnel_destroy(struct intel_dp *intel_dp)45{46 if (intel_dp_tunnel_bw_alloc_is_enabled(intel_dp))47 drm_dp_tunnel_disable_bw_alloc(intel_dp->tunnel);48 49 intel_dp_tunnel_disconnect(intel_dp);50}51 52static int kbytes_to_mbits(int kbytes)53{54 return DIV_ROUND_UP(kbytes * 8, 1000);55}56 57static int get_current_link_bw(struct intel_dp *intel_dp,58 bool *below_dprx_bw)59{60 int rate = intel_dp_max_common_rate(intel_dp);61 int lane_count = intel_dp_max_common_lane_count(intel_dp);62 int bw;63 64 bw = intel_dp_max_link_data_rate(intel_dp, rate, lane_count);65 *below_dprx_bw = bw < drm_dp_max_dprx_data_rate(rate, lane_count);66 67 return bw;68}69 70static int update_tunnel_state(struct intel_dp *intel_dp)71{72 struct intel_display *display = to_intel_display(intel_dp);73 struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;74 bool old_bw_below_dprx;75 bool new_bw_below_dprx;76 int old_bw;77 int new_bw;78 int ret;79 80 old_bw = get_current_link_bw(intel_dp, &old_bw_below_dprx);81 82 ret = drm_dp_tunnel_update_state(intel_dp->tunnel);83 if (ret < 0) {84 drm_dbg_kms(display->drm,85 "[DPTUN %s][ENCODER:%d:%s] State update failed (err %pe)\n",86 drm_dp_tunnel_name(intel_dp->tunnel),87 encoder->base.base.id, encoder->base.name,88 ERR_PTR(ret));89 90 return ret;91 }92 93 if (ret == 0 ||94 !drm_dp_tunnel_bw_alloc_is_enabled(intel_dp->tunnel))95 return 0;96 97 intel_dp_update_sink_caps(intel_dp);98 99 new_bw = get_current_link_bw(intel_dp, &new_bw_below_dprx);100 101 /* Suppress the notification if the mode list can't change due to bw. */102 if (old_bw_below_dprx == new_bw_below_dprx &&103 !new_bw_below_dprx)104 return 0;105 106 drm_dbg_kms(display->drm,107 "[DPTUN %s][ENCODER:%d:%s] Notify users about BW change: %d -> %d\n",108 drm_dp_tunnel_name(intel_dp->tunnel),109 encoder->base.base.id, encoder->base.name,110 kbytes_to_mbits(old_bw), kbytes_to_mbits(new_bw));111 112 return 1;113}114 115/*116 * Allocate the BW for a tunnel on a DP connector/port if the connector/port117 * was already active when detecting the tunnel. The allocated BW must be118 * freed by the next atomic modeset, storing the BW in the119 * intel_atomic_state::inherited_dp_tunnels, and calling120 * intel_dp_tunnel_atomic_free_bw().121 */122static int allocate_initial_tunnel_bw_for_pipes(struct intel_dp *intel_dp, u8 pipe_mask)123{124 struct intel_display *display = to_intel_display(intel_dp);125 struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;126 struct intel_crtc *crtc;127 int tunnel_bw = 0;128 int err;129 130 for_each_intel_crtc_in_pipe_mask(display->drm, crtc, pipe_mask) {131 const struct intel_crtc_state *crtc_state =132 to_intel_crtc_state(crtc->base.state);133 int stream_bw = intel_dp_config_required_rate(crtc_state);134 135 tunnel_bw += stream_bw;136 137 drm_dbg_kms(display->drm,138 "[DPTUN %s][ENCODER:%d:%s][CRTC:%d:%s] Initial BW for stream %d: %d/%d Mb/s\n",139 drm_dp_tunnel_name(intel_dp->tunnel),140 encoder->base.base.id, encoder->base.name,141 crtc->base.base.id, crtc->base.name,142 crtc->pipe,143 kbytes_to_mbits(stream_bw), kbytes_to_mbits(tunnel_bw));144 }145 146 err = drm_dp_tunnel_alloc_bw(intel_dp->tunnel, tunnel_bw);147 if (err) {148 drm_dbg_kms(display->drm,149 "[DPTUN %s][ENCODER:%d:%s] Initial BW allocation failed (err %pe)\n",150 drm_dp_tunnel_name(intel_dp->tunnel),151 encoder->base.base.id, encoder->base.name,152 ERR_PTR(err));153 154 return err;155 }156 157 return update_tunnel_state(intel_dp);158}159 160static int allocate_initial_tunnel_bw(struct intel_dp *intel_dp,161 struct drm_modeset_acquire_ctx *ctx)162{163 u8 pipe_mask;164 int err;165 166 err = intel_dp_get_active_pipes(intel_dp, ctx, &pipe_mask);167 if (err)168 return err;169 170 return allocate_initial_tunnel_bw_for_pipes(intel_dp, pipe_mask);171}172 173static int detect_new_tunnel(struct intel_dp *intel_dp, struct drm_modeset_acquire_ctx *ctx)174{175 struct intel_display *display = to_intel_display(intel_dp);176 struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;177 struct drm_dp_tunnel *tunnel;178 int ret;179 180 tunnel = drm_dp_tunnel_detect(display->dp_tunnel_mgr,181 &intel_dp->aux);182 if (IS_ERR(tunnel))183 return PTR_ERR(tunnel);184 185 intel_dp->tunnel = tunnel;186 187 ret = drm_dp_tunnel_enable_bw_alloc(intel_dp->tunnel);188 if (ret) {189 if (ret == -EOPNOTSUPP)190 return 0;191 192 drm_dbg_kms(display->drm,193 "[DPTUN %s][ENCODER:%d:%s] Failed to enable BW allocation mode (ret %pe)\n",194 drm_dp_tunnel_name(intel_dp->tunnel),195 encoder->base.base.id, encoder->base.name,196 ERR_PTR(ret));197 198 /* Keep the tunnel with BWA disabled */199 return 0;200 }201 202 ret = allocate_initial_tunnel_bw(intel_dp, ctx);203 if (ret < 0)204 intel_dp_tunnel_destroy(intel_dp);205 206 return ret;207}208 209/**210 * intel_dp_tunnel_detect - Detect a DP tunnel on a port211 * @intel_dp: DP port object212 * @ctx: lock context acquired by the connector detection handler213 *214 * Detect a DP tunnel on the @intel_dp port, enabling the BW allocation mode215 * on it if supported and allocating the BW required on an already active port.216 * The BW allocated this way must be freed by the next atomic modeset calling217 * intel_dp_tunnel_atomic_free_bw().218 *219 * If @intel_dp has already a tunnel detected on it, update the tunnel's state220 * wrt. its support for BW allocation mode and the available BW via the221 * tunnel. If the tunnel's state change requires this - for instance the222 * tunnel's group ID has changed - the tunnel will be dropped and recreated.223 *224 * Return 0 in case of success - after any tunnel detected and added to225 * @intel_dp - 1 in case the BW on an already existing tunnel has changed in a226 * way that requires notifying user space.227 */228int intel_dp_tunnel_detect(struct intel_dp *intel_dp, struct drm_modeset_acquire_ctx *ctx)229{230 int ret;231 232 if (intel_dp_is_edp(intel_dp))233 return 0;234 235 if (intel_dp->tunnel) {236 ret = update_tunnel_state(intel_dp);237 if (ret >= 0)238 return ret;239 240 /* Try to recreate the tunnel after an update error. */241 intel_dp_tunnel_destroy(intel_dp);242 }243 244 return detect_new_tunnel(intel_dp, ctx);245}246 247/**248 * intel_dp_tunnel_bw_alloc_is_enabled - Query the BW allocation support on a tunnel249 * @intel_dp: DP port object250 *251 * Query whether a DP tunnel is connected on @intel_dp and the tunnel supports252 * the BW allocation mode.253 *254 * Returns %true if the BW allocation mode is supported on @intel_dp.255 */256bool intel_dp_tunnel_bw_alloc_is_enabled(struct intel_dp *intel_dp)257{258 return drm_dp_tunnel_bw_alloc_is_enabled(intel_dp->tunnel);259}260 261/**262 * intel_dp_tunnel_suspend - Suspend a DP tunnel connected on a port263 * @intel_dp: DP port object264 *265 * Suspend a DP tunnel on @intel_dp with BW allocation mode enabled on it.266 */267void intel_dp_tunnel_suspend(struct intel_dp *intel_dp)268{269 struct intel_display *display = to_intel_display(intel_dp);270 struct intel_connector *connector = intel_dp->attached_connector;271 struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;272 273 if (!intel_dp_tunnel_bw_alloc_is_enabled(intel_dp))274 return;275 276 drm_dbg_kms(display->drm,277 "[DPTUN %s][CONNECTOR:%d:%s][ENCODER:%d:%s] Suspend\n",278 drm_dp_tunnel_name(intel_dp->tunnel),279 connector->base.base.id, connector->base.name,280 encoder->base.base.id, encoder->base.name);281 282 drm_dp_tunnel_disable_bw_alloc(intel_dp->tunnel);283 284 intel_dp->tunnel_suspended = true;285}286 287/**288 * intel_dp_tunnel_resume - Resume a DP tunnel connected on a port289 * @intel_dp: DP port object290 * @crtc_state: CRTC state291 * @dpcd_updated: the DPCD DPRX capabilities got updated during resume292 *293 * Resume a DP tunnel on @intel_dp with BW allocation mode enabled on it.294 */295void intel_dp_tunnel_resume(struct intel_dp *intel_dp,296 const struct intel_crtc_state *crtc_state,297 bool dpcd_updated)298{299 struct intel_display *display = to_intel_display(intel_dp);300 struct intel_connector *connector = intel_dp->attached_connector;301 struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;302 u8 dpcd[DP_RECEIVER_CAP_SIZE];303 u8 pipe_mask;304 int err = 0;305 306 if (!intel_dp->tunnel_suspended)307 return;308 309 intel_dp->tunnel_suspended = false;310 311 drm_dbg_kms(display->drm,312 "[DPTUN %s][CONNECTOR:%d:%s][ENCODER:%d:%s] Resume\n",313 drm_dp_tunnel_name(intel_dp->tunnel),314 connector->base.base.id, connector->base.name,315 encoder->base.base.id, encoder->base.name);316 317 /*318 * The TBT Connection Manager requires the GFX driver to read out319 * the sink's DPRX caps to be able to service any BW requests later.320 * During resume overriding the caps in @intel_dp cached before321 * suspend must be avoided, so do here only a dummy read, unless the322 * capabilities were updated already during resume.323 */324 if (!dpcd_updated) {325 err = intel_dp_read_dprx_caps(intel_dp, dpcd);326 327 if (err) {328 drm_dp_tunnel_set_io_error(intel_dp->tunnel);329 goto out_err;330 }331 }332 333 err = drm_dp_tunnel_enable_bw_alloc(intel_dp->tunnel);334 if (err)335 goto out_err;336 337 pipe_mask = 0;338 if (crtc_state) {339 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);340 341 /* TODO: Add support for MST */342 pipe_mask |= BIT(crtc->pipe);343 }344 345 err = allocate_initial_tunnel_bw_for_pipes(intel_dp, pipe_mask);346 if (err < 0)347 goto out_err;348 349 return;350 351out_err:352 drm_dbg_kms(display->drm,353 "[DPTUN %s][CONNECTOR:%d:%s][ENCODER:%d:%s] Tunnel can't be resumed, will drop and reject it (err %pe)\n",354 drm_dp_tunnel_name(intel_dp->tunnel),355 connector->base.base.id, connector->base.name,356 encoder->base.base.id, encoder->base.name,357 ERR_PTR(err));358}359 360static struct drm_dp_tunnel *361get_inherited_tunnel(struct intel_atomic_state *state, struct intel_crtc *crtc)362{363 if (!state->inherited_dp_tunnels)364 return NULL;365 366 return state->inherited_dp_tunnels->ref[crtc->pipe].tunnel;367}368 369static int370add_inherited_tunnel(struct intel_atomic_state *state,371 struct drm_dp_tunnel *tunnel,372 struct intel_crtc *crtc)373{374 struct intel_display *display = to_intel_display(state);375 struct drm_dp_tunnel *old_tunnel;376 377 old_tunnel = get_inherited_tunnel(state, crtc);378 if (old_tunnel) {379 drm_WARN_ON(display->drm, old_tunnel != tunnel);380 return 0;381 }382 383 if (!state->inherited_dp_tunnels) {384 state->inherited_dp_tunnels = kzalloc(sizeof(*state->inherited_dp_tunnels),385 GFP_KERNEL);386 if (!state->inherited_dp_tunnels)387 return -ENOMEM;388 }389 390 drm_dp_tunnel_ref_get(tunnel, &state->inherited_dp_tunnels->ref[crtc->pipe]);391 392 return 0;393}394 395static int check_inherited_tunnel_state(struct intel_atomic_state *state,396 struct intel_dp *intel_dp,397 const struct intel_digital_connector_state *old_conn_state)398{399 struct intel_display *display = to_intel_display(state);400 struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;401 struct intel_connector *connector =402 to_intel_connector(old_conn_state->base.connector);403 struct intel_crtc *old_crtc;404 const struct intel_crtc_state *old_crtc_state;405 406 /*407 * If a BWA tunnel gets detected only after the corresponding408 * connector got enabled already without a BWA tunnel, or a different409 * BWA tunnel (which was removed meanwhile) the old CRTC state won't410 * contain the state of the current tunnel. This tunnel still has a411 * reserved BW, which needs to be released, add the state for such412 * inherited tunnels separately only to this atomic state.413 */414 if (!intel_dp_tunnel_bw_alloc_is_enabled(intel_dp))415 return 0;416 417 if (!old_conn_state->base.crtc)418 return 0;419 420 old_crtc = to_intel_crtc(old_conn_state->base.crtc);421 old_crtc_state = intel_atomic_get_old_crtc_state(state, old_crtc);422 423 if (!old_crtc_state->hw.active ||424 old_crtc_state->dp_tunnel_ref.tunnel == intel_dp->tunnel)425 return 0;426 427 drm_dbg_kms(display->drm,428 "[DPTUN %s][CONNECTOR:%d:%s][ENCODER:%d:%s][CRTC:%d:%s] Adding state for inherited tunnel %p\n",429 drm_dp_tunnel_name(intel_dp->tunnel),430 connector->base.base.id, connector->base.name,431 encoder->base.base.id, encoder->base.name,432 old_crtc->base.base.id, old_crtc->base.name,433 intel_dp->tunnel);434 435 return add_inherited_tunnel(state, intel_dp->tunnel, old_crtc);436}437 438/**439 * intel_dp_tunnel_atomic_cleanup_inherited_state - Free any inherited DP tunnel state440 * @state: Atomic state441 *442 * Free the inherited DP tunnel state in @state.443 */444void intel_dp_tunnel_atomic_cleanup_inherited_state(struct intel_atomic_state *state)445{446 struct intel_display *display = to_intel_display(state);447 enum pipe pipe;448 449 if (!state->inherited_dp_tunnels)450 return;451 452 for_each_pipe(display, pipe)453 if (state->inherited_dp_tunnels->ref[pipe].tunnel)454 drm_dp_tunnel_ref_put(&state->inherited_dp_tunnels->ref[pipe]);455 456 kfree(state->inherited_dp_tunnels);457 state->inherited_dp_tunnels = NULL;458}459 460static int intel_dp_tunnel_atomic_add_group_state(struct intel_atomic_state *state,461 struct drm_dp_tunnel *tunnel)462{463 struct intel_display *display = to_intel_display(state);464 u32 pipe_mask;465 int err;466 467 err = drm_dp_tunnel_atomic_get_group_streams_in_state(&state->base,468 tunnel, &pipe_mask);469 if (err)470 return err;471 472 drm_WARN_ON(display->drm, pipe_mask & ~((1 << I915_MAX_PIPES) - 1));473 474 return intel_modeset_pipes_in_mask_early(state, "DPTUN", pipe_mask);475}476 477/**478 * intel_dp_tunnel_atomic_add_state_for_crtc - Add CRTC specific DP tunnel state479 * @state: Atomic state480 * @crtc: CRTC to add the tunnel state for481 *482 * Add the DP tunnel state for @crtc if the CRTC (aka DP tunnel stream) is enabled483 * via a DP tunnel.484 *485 * Return 0 in case of success, a negative error code otherwise.486 */487int intel_dp_tunnel_atomic_add_state_for_crtc(struct intel_atomic_state *state,488 struct intel_crtc *crtc)489{490 const struct intel_crtc_state *new_crtc_state =491 intel_atomic_get_new_crtc_state(state, crtc);492 const struct drm_dp_tunnel_state *tunnel_state;493 struct drm_dp_tunnel *tunnel = new_crtc_state->dp_tunnel_ref.tunnel;494 495 if (!tunnel)496 return 0;497 498 tunnel_state = drm_dp_tunnel_atomic_get_state(&state->base, tunnel);499 if (IS_ERR(tunnel_state))500 return PTR_ERR(tunnel_state);501 502 return 0;503}504 505static int check_group_state(struct intel_atomic_state *state,506 struct intel_dp *intel_dp,507 struct intel_connector *connector,508 struct intel_crtc *crtc)509{510 struct intel_display *display = to_intel_display(state);511 struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;512 const struct intel_crtc_state *crtc_state =513 intel_atomic_get_new_crtc_state(state, crtc);514 515 if (!crtc_state->dp_tunnel_ref.tunnel)516 return 0;517 518 drm_dbg_kms(display->drm,519 "[DPTUN %s][CONNECTOR:%d:%s][ENCODER:%d:%s][CRTC:%d:%s] Adding group state for tunnel %p\n",520 drm_dp_tunnel_name(intel_dp->tunnel),521 connector->base.base.id, connector->base.name,522 encoder->base.base.id, encoder->base.name,523 crtc->base.base.id, crtc->base.name,524 crtc_state->dp_tunnel_ref.tunnel);525 526 return intel_dp_tunnel_atomic_add_group_state(state, crtc_state->dp_tunnel_ref.tunnel);527}528 529/**530 * intel_dp_tunnel_atomic_check_state - Check a connector's DP tunnel specific state531 * @state: Atomic state532 * @intel_dp: DP port object533 * @connector: connector using @intel_dp534 *535 * Check and add the DP tunnel atomic state for @intel_dp/@connector to536 * @state, if there is a DP tunnel detected on @intel_dp with BW allocation537 * mode enabled on it, or if @intel_dp/@connector was previously enabled via a538 * DP tunnel.539 *540 * Returns 0 in case of success, or a negative error code otherwise.541 */542int intel_dp_tunnel_atomic_check_state(struct intel_atomic_state *state,543 struct intel_dp *intel_dp,544 struct intel_connector *connector)545{546 const struct intel_digital_connector_state *old_conn_state =547 intel_atomic_get_old_connector_state(state, connector);548 const struct intel_digital_connector_state *new_conn_state =549 intel_atomic_get_new_connector_state(state, connector);550 int err;551 552 if (old_conn_state->base.crtc) {553 err = check_group_state(state, intel_dp, connector,554 to_intel_crtc(old_conn_state->base.crtc));555 if (err)556 return err;557 }558 559 if (new_conn_state->base.crtc &&560 new_conn_state->base.crtc != old_conn_state->base.crtc) {561 err = check_group_state(state, intel_dp, connector,562 to_intel_crtc(new_conn_state->base.crtc));563 if (err)564 return err;565 }566 567 return check_inherited_tunnel_state(state, intel_dp, old_conn_state);568}569 570/**571 * intel_dp_tunnel_atomic_compute_stream_bw - Compute the BW required by a DP tunnel stream572 * @state: Atomic state573 * @intel_dp: DP object574 * @connector: connector using @intel_dp575 * @crtc_state: state of CRTC of the given DP tunnel stream576 *577 * Compute the required BW of CRTC (aka DP tunnel stream), storing this BW to578 * the DP tunnel state containing the stream in @state. Before re-calculating a579 * BW requirement in the crtc_state state the old BW requirement computed by this580 * function must be cleared by calling intel_dp_tunnel_atomic_clear_stream_bw().581 *582 * Returns 0 in case of success, a negative error code otherwise.583 */584int intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state,585 struct intel_dp *intel_dp,586 const struct intel_connector *connector,587 struct intel_crtc_state *crtc_state)588{589 struct intel_display *display = to_intel_display(state);590 struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;591 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);592 int required_rate = intel_dp_config_required_rate(crtc_state);593 int ret;594 595 if (!intel_dp_tunnel_bw_alloc_is_enabled(intel_dp))596 return 0;597 598 drm_dbg_kms(display->drm,599 "[DPTUN %s][CONNECTOR:%d:%s][ENCODER:%d:%s][CRTC:%d:%s] Stream %d required BW %d Mb/s\n",600 drm_dp_tunnel_name(intel_dp->tunnel),601 connector->base.base.id, connector->base.name,602 encoder->base.base.id, encoder->base.name,603 crtc->base.base.id, crtc->base.name,604 crtc->pipe,605 kbytes_to_mbits(required_rate));606 607 ret = drm_dp_tunnel_atomic_set_stream_bw(&state->base, intel_dp->tunnel,608 crtc->pipe, required_rate);609 if (ret < 0)610 return ret;611 612 drm_dp_tunnel_ref_get(intel_dp->tunnel,613 &crtc_state->dp_tunnel_ref);614 615 return 0;616}617 618/**619 * intel_dp_tunnel_atomic_clear_stream_bw - Clear any DP tunnel stream BW requirement620 * @state: Atomic state621 * @crtc_state: state of CRTC of the given DP tunnel stream622 *623 * Clear any DP tunnel stream BW requirement set by624 * intel_dp_tunnel_atomic_compute_stream_bw().625 */626void intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state,627 struct intel_crtc_state *crtc_state)628{629 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);630 631 if (!crtc_state->dp_tunnel_ref.tunnel)632 return;633 634 drm_dp_tunnel_atomic_set_stream_bw(&state->base,635 crtc_state->dp_tunnel_ref.tunnel,636 crtc->pipe, 0);637 drm_dp_tunnel_ref_put(&crtc_state->dp_tunnel_ref);638}639 640/**641 * intel_dp_tunnel_atomic_check_link - Check the DP tunnel atomic state642 * @state: intel atomic state643 * @limits: link BW limits644 *645 * Check the link configuration for all DP tunnels in @state. If the646 * configuration is invalid @limits will be updated if possible to647 * reduce the total BW, after which the configuration for all CRTCs in648 * @state must be recomputed with the updated @limits.649 *650 * Returns:651 * - 0 if the confugration is valid652 * - %-EAGAIN, if the configuration is invalid and @limits got updated653 * with fallback values with which the configuration of all CRTCs in654 * @state must be recomputed655 * - Other negative error, if the configuration is invalid without a656 * fallback possibility, or the check failed for another reason657 */658int intel_dp_tunnel_atomic_check_link(struct intel_atomic_state *state,659 struct intel_link_bw_limits *limits)660{661 u32 failed_stream_mask;662 int err;663 664 err = drm_dp_tunnel_atomic_check_stream_bws(&state->base,665 &failed_stream_mask);666 if (err != -ENOSPC)667 return err;668 669 err = intel_link_bw_reduce_bpp(state, limits,670 failed_stream_mask, "DP tunnel link BW");671 672 return err ? : -EAGAIN;673}674 675static void atomic_decrease_bw(struct intel_atomic_state *state)676{677 struct intel_crtc *crtc;678 const struct intel_crtc_state *old_crtc_state;679 const struct intel_crtc_state *new_crtc_state;680 int i;681 682 for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {683 const struct drm_dp_tunnel_state *new_tunnel_state;684 struct drm_dp_tunnel *tunnel;685 int old_bw;686 int new_bw;687 688 if (!intel_crtc_needs_modeset(new_crtc_state))689 continue;690 691 tunnel = get_inherited_tunnel(state, crtc);692 if (!tunnel)693 tunnel = old_crtc_state->dp_tunnel_ref.tunnel;694 695 if (!tunnel)696 continue;697 698 old_bw = drm_dp_tunnel_get_allocated_bw(tunnel);699 700 new_tunnel_state = drm_dp_tunnel_atomic_get_new_state(&state->base, tunnel);701 new_bw = drm_dp_tunnel_atomic_get_required_bw(new_tunnel_state);702 703 if (new_bw >= old_bw)704 continue;705 706 drm_dp_tunnel_alloc_bw(tunnel, new_bw);707 }708}709 710static void queue_retry_work(struct intel_atomic_state *state,711 struct drm_dp_tunnel *tunnel,712 const struct intel_crtc_state *crtc_state)713{714 struct intel_display *display = to_intel_display(state);715 struct intel_encoder *encoder;716 717 encoder = intel_get_crtc_new_encoder(state, crtc_state);718 719 if (!intel_digital_port_connected(encoder))720 return;721 722 drm_dbg_kms(display->drm,723 "[DPTUN %s][ENCODER:%d:%s] BW allocation failed on a connected sink\n",724 drm_dp_tunnel_name(tunnel),725 encoder->base.base.id,726 encoder->base.name);727 728 intel_dp_queue_modeset_retry_for_link(state, encoder, crtc_state);729}730 731static void atomic_increase_bw(struct intel_atomic_state *state)732{733 struct intel_crtc *crtc;734 const struct intel_crtc_state *crtc_state;735 int i;736 737 for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) {738 struct drm_dp_tunnel_state *tunnel_state;739 struct drm_dp_tunnel *tunnel = crtc_state->dp_tunnel_ref.tunnel;740 int bw;741 742 if (!intel_crtc_needs_modeset(crtc_state))743 continue;744 745 if (!tunnel)746 continue;747 748 tunnel_state = drm_dp_tunnel_atomic_get_new_state(&state->base, tunnel);749 750 bw = drm_dp_tunnel_atomic_get_required_bw(tunnel_state);751 752 if (drm_dp_tunnel_alloc_bw(tunnel, bw) != 0)753 queue_retry_work(state, tunnel, crtc_state);754 }755}756 757/**758 * intel_dp_tunnel_atomic_alloc_bw - Allocate the BW for all modeset tunnels759 * @state: Atomic state760 *761 * Allocate the required BW for all tunnels in @state.762 */763void intel_dp_tunnel_atomic_alloc_bw(struct intel_atomic_state *state)764{765 atomic_decrease_bw(state);766 atomic_increase_bw(state);767}768 769/**770 * intel_dp_tunnel_mgr_init - Initialize the DP tunnel manager771 * @display: display device772 *773 * Initialize the DP tunnel manager. The tunnel manager will support the774 * detection/management of DP tunnels on all DP connectors, so the function775 * must be called after all these connectors have been registered already.776 *777 * Return 0 in case of success, a negative error code otherwise.778 */779int intel_dp_tunnel_mgr_init(struct intel_display *display)780{781 struct drm_dp_tunnel_mgr *tunnel_mgr;782 struct drm_connector_list_iter connector_list_iter;783 struct intel_connector *connector;784 int dp_connectors = 0;785 786 drm_connector_list_iter_begin(display->drm, &connector_list_iter);787 for_each_intel_connector_iter(connector, &connector_list_iter) {788 if (connector->base.connector_type != DRM_MODE_CONNECTOR_DisplayPort)789 continue;790 791 dp_connectors++;792 }793 drm_connector_list_iter_end(&connector_list_iter);794 795 tunnel_mgr = drm_dp_tunnel_mgr_create(display->drm, dp_connectors);796 if (IS_ERR(tunnel_mgr))797 return PTR_ERR(tunnel_mgr);798 799 display->dp_tunnel_mgr = tunnel_mgr;800 801 return 0;802}803 804/**805 * intel_dp_tunnel_mgr_cleanup - Clean up the DP tunnel manager state806 * @display: display device807 *808 * Clean up the DP tunnel manager state.809 */810void intel_dp_tunnel_mgr_cleanup(struct intel_display *display)811{812 drm_dp_tunnel_mgr_destroy(display->dp_tunnel_mgr);813 display->dp_tunnel_mgr = NULL;814}815