/** * intel_dp_tunnel_disconnect - Disconnect a DP tunnel from a port * @intel_dp: DP port object the tunnel is connected to * * Disconnect a DP tunnel from @intel_dp, destroying any related state. This * should be called after detecting a sink-disconnect event from the port.
*/ void intel_dp_tunnel_disconnect(struct intel_dp *intel_dp)
{
drm_dp_tunnel_destroy(intel_dp->tunnel);
intel_dp->tunnel = NULL;
}
/** * intel_dp_tunnel_destroy - Destroy a DP tunnel * @intel_dp: DP port object the tunnel is connected to * * Destroy a DP tunnel connected to @intel_dp, after disabling the BW * allocation mode on the tunnel. This should be called while destroying the * port.
*/ void intel_dp_tunnel_destroy(struct intel_dp *intel_dp)
{ if (intel_dp_tunnel_bw_alloc_is_enabled(intel_dp))
drm_dp_tunnel_disable_bw_alloc(intel_dp->tunnel);
/* * Allocate the BW for a tunnel on a DP connector/port if the connector/port * was already active when detecting the tunnel. The allocated BW must be * freed by the next atomic modeset, storing the BW in the * intel_atomic_state::inherited_dp_tunnels, and calling * intel_dp_tunnel_atomic_free_bw().
*/ staticint allocate_initial_tunnel_bw_for_pipes(struct intel_dp *intel_dp, u8 pipe_mask)
{ struct intel_display *display = to_intel_display(intel_dp); struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; struct intel_crtc *crtc; int tunnel_bw = 0; int err;
/* Keep the tunnel with BWA disabled */ return 0;
}
ret = allocate_initial_tunnel_bw(intel_dp, ctx); if (ret < 0)
intel_dp_tunnel_destroy(intel_dp);
return ret;
}
/** * intel_dp_tunnel_detect - Detect a DP tunnel on a port * @intel_dp: DP port object * @ctx: lock context acquired by the connector detection handler * * Detect a DP tunnel on the @intel_dp port, enabling the BW allocation mode * on it if supported and allocating the BW required on an already active port. * The BW allocated this way must be freed by the next atomic modeset calling * intel_dp_tunnel_atomic_free_bw(). * * If @intel_dp has already a tunnel detected on it, update the tunnel's state * wrt. its support for BW allocation mode and the available BW via the * 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.
*/ int intel_dp_tunnel_detect(struct intel_dp *intel_dp, struct drm_modeset_acquire_ctx *ctx)
{ int ret;
if (intel_dp_is_edp(intel_dp)) return 0;
if (intel_dp->tunnel) {
ret = update_tunnel_state(intel_dp); if (ret >= 0) return ret;
/* Try to recreate the tunnel after an update error. */
intel_dp_tunnel_destroy(intel_dp);
}
return detect_new_tunnel(intel_dp, ctx);
}
/** * intel_dp_tunnel_bw_alloc_is_enabled - Query the BW allocation support on a tunnel * @intel_dp: DP port object * * Query whether a DP tunnel is connected on @intel_dp and the tunnel supports * the BW allocation mode. * * Returns %true if the BW allocation mode is supported on @intel_dp.
*/ bool intel_dp_tunnel_bw_alloc_is_enabled(struct intel_dp *intel_dp)
{ return drm_dp_tunnel_bw_alloc_is_enabled(intel_dp->tunnel);
}
/** * intel_dp_tunnel_suspend - Suspend a DP tunnel connected on a port * @intel_dp: DP port object * * Suspend a DP tunnel on @intel_dp with BW allocation mode enabled on it.
*/ void intel_dp_tunnel_suspend(struct intel_dp *intel_dp)
{ struct intel_display *display = to_intel_display(intel_dp); struct intel_connector *connector = intel_dp->attached_connector; struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
if (!intel_dp_tunnel_bw_alloc_is_enabled(intel_dp)) return;
/* * The TBT Connection Manager requires the GFX driver to read out * the sink's DPRX caps to be able to service any BW requests later. * During resume overriding the caps in @intel_dp cached before * suspend must be avoided, so do here only a dummy read, unless the * capabilities were updated already during resume.
*/ if (!dpcd_updated) {
err = intel_dp_read_dprx_caps(intel_dp, dpcd);
if (err) {
drm_dp_tunnel_set_io_error(intel_dp->tunnel); goto out_err;
}
}
err = drm_dp_tunnel_enable_bw_alloc(intel_dp->tunnel); if (err) goto out_err;
/* TODO: Add support for MST */
pipe_mask |= BIT(crtc->pipe);
}
err = allocate_initial_tunnel_bw_for_pipes(intel_dp, pipe_mask); if (err < 0) goto out_err;
return;
out_err:
drm_dbg_kms(display->drm, "[DPTUN %s][CONNECTOR:%d:%s][ENCODER:%d:%s] Tunnel can't be resumed, will drop and reject it (err %pe)\n",
drm_dp_tunnel_name(intel_dp->tunnel),
connector->base.base.id, connector->base.name,
encoder->base.base.id, encoder->base.name,
ERR_PTR(err));
}
/* * If a BWA tunnel gets detected only after the corresponding * connector got enabled already without a BWA tunnel, or a different * BWA tunnel (which was removed meanwhile) the old CRTC state won't * contain the state of the current tunnel. This tunnel still has a * reserved BW, which needs to be released, add the state for such * inherited tunnels separately only to this atomic state.
*/ if (!intel_dp_tunnel_bw_alloc_is_enabled(intel_dp)) return 0;
/** * intel_dp_tunnel_atomic_add_state_for_crtc - Add CRTC specific DP tunnel state * @state: Atomic state * @crtc: CRTC to add the tunnel state for * * Add the DP tunnel state for @crtc if the CRTC (aka DP tunnel stream) is enabled * via a DP tunnel. * * Return 0 in case of success, a negative error code otherwise.
*/ int intel_dp_tunnel_atomic_add_state_for_crtc(struct intel_atomic_state *state, struct intel_crtc *crtc)
{ conststruct intel_crtc_state *new_crtc_state =
intel_atomic_get_new_crtc_state(state, crtc); conststruct drm_dp_tunnel_state *tunnel_state; struct drm_dp_tunnel *tunnel = new_crtc_state->dp_tunnel_ref.tunnel;
if (!tunnel) return 0;
tunnel_state = drm_dp_tunnel_atomic_get_state(&state->base, tunnel); if (IS_ERR(tunnel_state)) return PTR_ERR(tunnel_state);
/** * intel_dp_tunnel_atomic_check_state - Check a connector's DP tunnel specific state * @state: Atomic state * @intel_dp: DP port object * @connector: connector using @intel_dp * * Check and add the DP tunnel atomic state for @intel_dp/@connector to * @state, if there is a DP tunnel detected on @intel_dp with BW allocation * mode enabled on it, or if @intel_dp/@connector was previously enabled via a * DP tunnel. * * Returns 0 in case of success, or a negative error code otherwise.
*/ int intel_dp_tunnel_atomic_check_state(struct intel_atomic_state *state, struct intel_dp *intel_dp, struct intel_connector *connector)
{ conststruct intel_digital_connector_state *old_conn_state =
intel_atomic_get_old_connector_state(state, connector); conststruct intel_digital_connector_state *new_conn_state =
intel_atomic_get_new_connector_state(state, connector); int err;
if (old_conn_state->base.crtc) {
err = check_group_state(state, intel_dp, connector,
to_intel_crtc(old_conn_state->base.crtc)); if (err) return err;
}
if (new_conn_state->base.crtc &&
new_conn_state->base.crtc != old_conn_state->base.crtc) {
err = check_group_state(state, intel_dp, connector,
to_intel_crtc(new_conn_state->base.crtc)); if (err) return err;
}
/** * intel_dp_tunnel_atomic_compute_stream_bw - Compute the BW required by a DP tunnel stream * @state: Atomic state * @intel_dp: DP object * @connector: connector using @intel_dp * @crtc_state: state of CRTC of the given DP tunnel stream * * Compute the required BW of CRTC (aka DP tunnel stream), storing this BW to * the DP tunnel state containing the stream in @state. Before re-calculating a * BW requirement in the crtc_state state the old BW requirement computed by this * function must be cleared by calling intel_dp_tunnel_atomic_clear_stream_bw(). * * Returns 0 in case of success, a negative error code otherwise.
*/ int intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state, struct intel_dp *intel_dp, conststruct intel_connector *connector, struct intel_crtc_state *crtc_state)
{ struct intel_display *display = to_intel_display(state); struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); int required_rate = intel_dp_config_required_rate(crtc_state); int ret;
if (!intel_dp_tunnel_bw_alloc_is_enabled(intel_dp)) return 0;
/** * intel_dp_tunnel_atomic_check_link - Check the DP tunnel atomic state * @state: intel atomic state * @limits: link BW limits * * Check the link configuration for all DP tunnels in @state. If the * configuration is invalid @limits will be updated if possible to * reduce the total BW, after which the configuration for all CRTCs in * @state must be recomputed with the updated @limits. * * Returns: * - 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 * - Other negative error, if the configuration is invalid without a * fallback possibility, or the check failed for another reason
*/ int intel_dp_tunnel_atomic_check_link(struct intel_atomic_state *state, struct intel_link_bw_limits *limits)
{
u32 failed_stream_mask; int err;
err = drm_dp_tunnel_atomic_check_stream_bws(&state->base,
&failed_stream_mask); if (err != -ENOSPC) return err;
err = intel_link_bw_reduce_bpp(state, limits,
failed_stream_mask, "DP tunnel link BW");
if (drm_dp_tunnel_alloc_bw(tunnel, bw) != 0)
queue_retry_work(state, tunnel, crtc_state);
}
}
/** * intel_dp_tunnel_atomic_alloc_bw - Allocate the BW for all modeset tunnels * @state: Atomic state * * Allocate the required BW for all tunnels in @state.
*/ void intel_dp_tunnel_atomic_alloc_bw(struct intel_atomic_state *state)
{
atomic_decrease_bw(state);
atomic_increase_bw(state);
}
/** * intel_dp_tunnel_mgr_init - Initialize the DP tunnel manager * @display: display device * * Initialize the DP tunnel manager. The tunnel manager will support the * detection/management of DP tunnels on all DP connectors, so the function * must be called after all these connectors have been registered already. * * Return 0 in case of success, a negative error code otherwise.
*/ int intel_dp_tunnel_mgr_init(struct intel_display *display)
{ struct drm_dp_tunnel_mgr *tunnel_mgr; struct drm_connector_list_iter connector_list_iter; struct intel_connector *connector; int dp_connectors = 0;
drm_connector_list_iter_begin(display->drm, &connector_list_iter);
for_each_intel_connector_iter(connector, &connector_list_iter) { if (connector->base.connector_type != DRM_MODE_CONNECTOR_DisplayPort) continue;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.