Commit 877d8c07 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge tag 'topic/nouveau-i915-dp-helpers-and-cleanup-2020-08-31-1' of...

Merge tag 'topic/nouveau-i915-dp-helpers-and-cleanup-2020-08-31-1' of git://anongit.freedesktop.org/drm/drm-misc

 into drm-next

UAPI Changes:

None

Cross-subsystem Changes:

* Moves a bunch of miscellaneous DP code from the i915 driver into a set
  of shared DRM DP helpers

Core Changes:

* New DRM DP helpers (see above)

Driver Changes:

* Implements usage of the aforementioned DP helpers in the nouveau
  driver, along with some other various HPD related cleanup for nouveau

Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
From: Lyude Paul <lyude@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/11e59ebdea7ee4f46803a21fe9b21443d2b9c401.camel@redhat.com
parents 1f4b2aca 79416e97
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -29,6 +29,8 @@ properties:
    # compatible must be listed in alphabetical order, ordered by compatible.
    # The description in the comment is mandatory for each compatible.

        # Ampire AM-1280800N3TZQW-T00H 10.1" WQVGA TFT LCD panel
      - ampire,am-1280800n3tzqw-t00h
        # Ampire AM-480272H3TMQW-T01H 4.3" WQVGA TFT LCD panel
      - ampire,am-480272h3tmqw-t01h
        # Ampire AM-800480R3TMQW-A1H 7.0" WVGA TFT LCD panel
+4 −4
Original line number Diff line number Diff line
@@ -473,7 +473,7 @@ int amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev,
 * help move buffers to and from VRAM.
 */
static int amdgpu_move_blit(struct ttm_buffer_object *bo,
			    bool evict, bool no_wait_gpu,
			    bool evict,
			    struct ttm_resource *new_mem,
			    struct ttm_resource *old_mem)
{
@@ -571,7 +571,7 @@ static int amdgpu_move_vram_ram(struct ttm_buffer_object *bo, bool evict,
	}

	/* blit VRAM to GTT */
	r = amdgpu_move_blit(bo, evict, ctx->no_wait_gpu, &tmp_mem, old_mem);
	r = amdgpu_move_blit(bo, evict, &tmp_mem, old_mem);
	if (unlikely(r)) {
		goto out_cleanup;
	}
@@ -621,7 +621,7 @@ static int amdgpu_move_ram_vram(struct ttm_buffer_object *bo, bool evict,
	}

	/* copy to VRAM */
	r = amdgpu_move_blit(bo, evict, ctx->no_wait_gpu, new_mem, old_mem);
	r = amdgpu_move_blit(bo, evict, new_mem, old_mem);
	if (unlikely(r)) {
		goto out_cleanup;
	}
@@ -710,7 +710,7 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict,
		   new_mem->mem_type == TTM_PL_VRAM) {
		r = amdgpu_move_ram_vram(bo, evict, ctx, new_mem);
	} else {
		r = amdgpu_move_blit(bo, evict, ctx->no_wait_gpu,
		r = amdgpu_move_blit(bo, evict,
				     new_mem, old_mem);
	}

+2 −2
Original line number Diff line number Diff line
@@ -960,13 +960,13 @@ static const struct drm_bridge_funcs lt9611_bridge_funcs = {
static int lt9611_parse_dt(struct device *dev,
			   struct lt9611 *lt9611)
{
	lt9611->dsi0_node = of_graph_get_remote_node(dev->of_node, 1, -1);
	lt9611->dsi0_node = of_graph_get_remote_node(dev->of_node, 0, -1);
	if (!lt9611->dsi0_node) {
		dev_err(lt9611->dev, "failed to get remote node for primary dsi\n");
		return -ENODEV;
	}

	lt9611->dsi1_node = of_graph_get_remote_node(dev->of_node, 2, -1);
	lt9611->dsi1_node = of_graph_get_remote_node(dev->of_node, 1, -1);

	lt9611->ac_mode = of_property_read_bool(dev->of_node, "lt,ac-mode");

+185 −2
Original line number Diff line number Diff line
@@ -423,6 +423,133 @@ bool drm_dp_send_real_edid_checksum(struct drm_dp_aux *aux,
}
EXPORT_SYMBOL(drm_dp_send_real_edid_checksum);

static u8 drm_dp_downstream_port_count(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
{
	u8 port_count = dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_PORT_COUNT_MASK;

	if (dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DETAILED_CAP_INFO_AVAILABLE && port_count > 4)
		port_count = 4;

	return port_count;
}

static int drm_dp_read_extended_dpcd_caps(struct drm_dp_aux *aux,
					  u8 dpcd[DP_RECEIVER_CAP_SIZE])
{
	u8 dpcd_ext[6];
	int ret;

	/*
	 * Prior to DP1.3 the bit represented by
	 * DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT was reserved.
	 * If it is set DP_DPCD_REV at 0000h could be at a value less than
	 * the true capability of the panel. The only way to check is to
	 * then compare 0000h and 2200h.
	 */
	if (!(dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
	      DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT))
		return 0;

	ret = drm_dp_dpcd_read(aux, DP_DP13_DPCD_REV, &dpcd_ext,
			       sizeof(dpcd_ext));
	if (ret < 0)
		return ret;
	if (ret != sizeof(dpcd_ext))
		return -EIO;

	if (dpcd[DP_DPCD_REV] > dpcd_ext[DP_DPCD_REV]) {
		DRM_DEBUG_KMS("%s: Extended DPCD rev less than base DPCD rev (%d > %d)\n",
			      aux->name, dpcd[DP_DPCD_REV],
			      dpcd_ext[DP_DPCD_REV]);
		return 0;
	}

	if (!memcmp(dpcd, dpcd_ext, sizeof(dpcd_ext)))
		return 0;

	DRM_DEBUG_KMS("%s: Base DPCD: %*ph\n",
		      aux->name, DP_RECEIVER_CAP_SIZE, dpcd);

	memcpy(dpcd, dpcd_ext, sizeof(dpcd_ext));

	return 0;
}

/**
 * drm_dp_read_dpcd_caps() - read DPCD caps and extended DPCD caps if
 * available
 * @aux: DisplayPort AUX channel
 * @dpcd: Buffer to store the resulting DPCD in
 *
 * Attempts to read the base DPCD caps for @aux. Additionally, this function
 * checks for and reads the extended DPRX caps (%DP_DP13_DPCD_REV) if
 * present.
 *
 * Returns: %0 if the DPCD was read successfully, negative error code
 * otherwise.
 */
int drm_dp_read_dpcd_caps(struct drm_dp_aux *aux,
			  u8 dpcd[DP_RECEIVER_CAP_SIZE])
{
	int ret;

	ret = drm_dp_dpcd_read(aux, DP_DPCD_REV, dpcd, DP_RECEIVER_CAP_SIZE);
	if (ret < 0)
		return ret;
	if (ret != DP_RECEIVER_CAP_SIZE || dpcd[DP_DPCD_REV] == 0)
		return -EIO;

	ret = drm_dp_read_extended_dpcd_caps(aux, dpcd);
	if (ret < 0)
		return ret;

	DRM_DEBUG_KMS("%s: DPCD: %*ph\n",
		      aux->name, DP_RECEIVER_CAP_SIZE, dpcd);

	return ret;
}
EXPORT_SYMBOL(drm_dp_read_dpcd_caps);

/**
 * drm_dp_read_downstream_info() - read DPCD downstream port info if available
 * @aux: DisplayPort AUX channel
 * @dpcd: A cached copy of the port's DPCD
 * @downstream_ports: buffer to store the downstream port info in
 *
 * See also:
 * drm_dp_downstream_max_clock()
 * drm_dp_downstream_max_bpc()
 *
 * Returns: 0 if either the downstream port info was read successfully or
 * there was no downstream info to read, or a negative error code otherwise.
 */
int drm_dp_read_downstream_info(struct drm_dp_aux *aux,
				const u8 dpcd[DP_RECEIVER_CAP_SIZE],
				u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS])
{
	int ret;
	u8 len;

	memset(downstream_ports, 0, DP_MAX_DOWNSTREAM_PORTS);

	/* No downstream info to read */
	if (!drm_dp_is_branch(dpcd) ||
	    dpcd[DP_DPCD_REV] < DP_DPCD_REV_10 ||
	    !(dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT))
		return 0;

	len = drm_dp_downstream_port_count(dpcd);
	if (dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DETAILED_CAP_INFO_AVAILABLE)
		len *= 4;

	ret = drm_dp_dpcd_read(aux, DP_DOWNSTREAM_PORT_0, downstream_ports, len);
	if (ret < 0)
		return ret;

	return ret == len ? 0 : -EIO;
}
EXPORT_SYMBOL(drm_dp_read_downstream_info);

/**
 * drm_dp_downstream_max_clock() - extract branch device max
 *                                 pixel rate for legacy VGA
@@ -431,7 +558,11 @@ EXPORT_SYMBOL(drm_dp_send_real_edid_checksum);
 * @dpcd: DisplayPort configuration data
 * @port_cap: port capabilities
 *
 * Returns max clock in kHz on success or 0 if max clock not defined
 * See also:
 * drm_dp_read_downstream_info()
 * drm_dp_downstream_max_bpc()
 *
 * Returns: Max clock in kHz on success or 0 if max clock not defined
 */
int drm_dp_downstream_max_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
				const u8 port_cap[4])
@@ -462,7 +593,11 @@ EXPORT_SYMBOL(drm_dp_downstream_max_clock);
 * @dpcd: DisplayPort configuration data
 * @port_cap: port capabilities
 *
 * Returns max bpc on success or 0 if max bpc not defined
 * See also:
 * drm_dp_read_downstream_info()
 * drm_dp_downstream_max_clock()
 *
 * Returns: Max bpc on success or 0 if max bpc not defined
 */
int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
			      const u8 port_cap[4])
@@ -668,6 +803,54 @@ void drm_dp_set_subconnector_property(struct drm_connector *connector,
}
EXPORT_SYMBOL(drm_dp_set_subconnector_property);

/**
 * drm_dp_read_sink_count_cap() - Check whether a given connector has a valid sink
 * count
 * @connector: The DRM connector to check
 * @dpcd: A cached copy of the connector's DPCD RX capabilities
 * @desc: A cached copy of the connector's DP descriptor
 *
 * See also: drm_dp_read_sink_count()
 *
 * Returns: %True if the (e)DP connector has a valid sink count that should
 * be probed, %false otherwise.
 */
bool drm_dp_read_sink_count_cap(struct drm_connector *connector,
				const u8 dpcd[DP_RECEIVER_CAP_SIZE],
				const struct drm_dp_desc *desc)
{
	/* Some eDP panels don't set a valid value for the sink count */
	return connector->connector_type != DRM_MODE_CONNECTOR_eDP &&
		dpcd[DP_DPCD_REV] >= DP_DPCD_REV_11 &&
		dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT &&
		!drm_dp_has_quirk(desc, 0, DP_DPCD_QUIRK_NO_SINK_COUNT);
}
EXPORT_SYMBOL(drm_dp_read_sink_count_cap);

/**
 * drm_dp_read_sink_count() - Retrieve the sink count for a given sink
 * @aux: The DP AUX channel to use
 *
 * See also: drm_dp_read_sink_count_cap()
 *
 * Returns: The current sink count reported by @aux, or a negative error code
 * otherwise.
 */
int drm_dp_read_sink_count(struct drm_dp_aux *aux)
{
	u8 count;
	int ret;

	ret = drm_dp_dpcd_readb(aux, DP_SINK_COUNT, &count);
	if (ret < 0)
		return ret;
	if (ret != 1)
		return -EIO;

	return DP_GET_SINK_COUNT(count);
}
EXPORT_SYMBOL(drm_dp_read_sink_count);

/*
 * I2C-over-AUX implementation
 */
+22 −0
Original line number Diff line number Diff line
@@ -3486,6 +3486,28 @@ static int drm_dp_get_vc_payload_bw(u8 dp_link_bw, u8 dp_link_count)
	return dp_link_bw * dp_link_count / 2;
}

/**
 * drm_dp_read_mst_cap() - check whether or not a sink supports MST
 * @aux: The DP AUX channel to use
 * @dpcd: A cached copy of the DPCD capabilities for this sink
 *
 * Returns: %True if the sink supports MST, %false otherwise
 */
bool drm_dp_read_mst_cap(struct drm_dp_aux *aux,
			 const u8 dpcd[DP_RECEIVER_CAP_SIZE])
{
	u8 mstm_cap;

	if (dpcd[DP_DPCD_REV] < DP_DPCD_REV_12)
		return false;

	if (drm_dp_dpcd_readb(aux, DP_MSTM_CAP, &mstm_cap) != 1)
		return false;

	return mstm_cap & DP_MST_CAP;
}
EXPORT_SYMBOL(drm_dp_read_mst_cap);

/**
 * drm_dp_mst_topology_mgr_set_mst() - Set the MST state for a topology manager
 * @mgr: manager to set state for
Loading