drivers/gpu/drm/i915/display/intel_dp_tunnel.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/i915/display/intel_dp_tunnel.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/i915/display/intel_dp_tunnel.c
Extension
.c
Size
26545 bytes
Lines
876
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct intel_dp_tunnel_inherited_state {
	struct drm_dp_tunnel_ref ref[I915_MAX_PIPES];
};

/**
 * 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);

	intel_dp_tunnel_disconnect(intel_dp);
}

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)
{
	int rate = intel_dp_max_common_rate(intel_dp);
	int lane_count = intel_dp_max_common_lane_count(intel_dp);

	return intel_dp_max_link_data_rate(intel_dp, rate, lane_count);
}

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;
	int ret;

	ret = drm_dp_tunnel_update_state(intel_dp->tunnel);
	if (ret < 0) {
		drm_dbg_kms(display->drm,
			    "[DPTUN %s][ENCODER:%d:%s] State update failed (err %pe)\n",
			    drm_dp_tunnel_name(intel_dp->tunnel),
			    encoder->base.base.id, encoder->base.name,
			    ERR_PTR(ret));

		return ret;
	}

	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);

	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 == new_bw)
		return false;

	drm_dbg_kms(display->drm,
		    "[DPTUN %s][ENCODER:%d:%s] Notify users about BW change: %d -> %d\n",
		    drm_dp_tunnel_name(intel_dp->tunnel),
		    encoder->base.base.id, encoder->base.name,
		    kbytes_to_mbits(old_bw), kbytes_to_mbits(new_bw));

Annotation

Implementation Notes