Commit 6a127160 authored by Thierry Reding's avatar Thierry Reding
Browse files

drm/tegra: dp: Add support for eDP link rates



Parses additional link rates from DPCD if the sink supports eDP 1.4.

Signed-off-by: default avatarThierry Reding <treding@nvidia.com>
parent 01f09f24
Loading
Loading
Loading
Loading
+127 −0
Original line number Diff line number Diff line
@@ -33,6 +33,8 @@ void drm_dp_link_caps_copy(struct drm_dp_link_caps *dest,

static void drm_dp_link_reset(struct drm_dp_link *link)
{
	unsigned int i;

	if (!link)
		return;

@@ -47,6 +49,111 @@ static void drm_dp_link_reset(struct drm_dp_link *link)

	link->rate = 0;
	link->lanes = 0;

	for (i = 0; i < DP_MAX_SUPPORTED_RATES; i++)
		link->rates[i] = 0;

	link->num_rates = 0;
}

/**
 * drm_dp_link_add_rate() - add a rate to the list of supported rates
 * @link: the link to add the rate to
 * @rate: the rate to add
 *
 * Add a link rate to the list of supported link rates.
 *
 * Returns:
 * 0 on success or one of the following negative error codes on failure:
 * - ENOSPC if the maximum number of supported rates has been reached
 * - EEXISTS if the link already supports this rate
 *
 * See also:
 * drm_dp_link_remove_rate()
 */
int drm_dp_link_add_rate(struct drm_dp_link *link, unsigned long rate)
{
	unsigned int i, pivot;

	if (link->num_rates == DP_MAX_SUPPORTED_RATES)
		return -ENOSPC;

	for (pivot = 0; pivot < link->num_rates; pivot++)
		if (rate <= link->rates[pivot])
			break;

	if (pivot != link->num_rates && rate == link->rates[pivot])
		return -EEXIST;

	for (i = link->num_rates; i > pivot; i--)
		link->rates[i] = link->rates[i - 1];

	link->rates[pivot] = rate;
	link->num_rates++;

	return 0;
}

/**
 * drm_dp_link_remove_rate() - remove a rate from the list of supported rates
 * @link: the link from which to remove the rate
 * @rate: the rate to remove
 *
 * Removes a link rate from the list of supported link rates.
 *
 * Returns:
 * 0 on success or one of the following negative error codes on failure:
 * - EINVAL if the specified rate is not among the supported rates
 *
 * See also:
 * drm_dp_link_add_rate()
 */
int drm_dp_link_remove_rate(struct drm_dp_link *link, unsigned long rate)
{
	unsigned int i;

	for (i = 0; i < link->num_rates; i++)
		if (rate == link->rates[i])
			break;

	if (i == link->num_rates)
		return -EINVAL;

	link->num_rates--;

	while (i < link->num_rates) {
		link->rates[i] = link->rates[i + 1];
		i++;
	}

	return 0;
}

/**
 * drm_dp_link_update_rates() - normalize the supported link rates array
 * @link: the link for which to normalize the supported link rates
 *
 * Users should call this function after they've manually modified the array
 * of supported link rates. This function removes any stale entries, compacts
 * the array and updates the supported link rate count. Note that calling the
 * drm_dp_link_remove_rate() function already does this janitorial work.
 *
 * See also:
 * drm_dp_link_add_rate(), drm_dp_link_remove_rate()
 */
void drm_dp_link_update_rates(struct drm_dp_link *link)
{
	unsigned int i, count = 0;

	for (i = 0; i < link->num_rates; i++) {
		if (link->rates[i] != 0)
			link->rates[count++] = link->rates[i];
	}

	for (i = count; i < link->num_rates; i++)
		link->rates[i] = 0;

	link->num_rates = count;
}

/**
@@ -125,6 +232,26 @@ int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link)
	link->rate = link->max_rate;
	link->lanes = link->max_lanes;

	/* Parse SUPPORTED_LINK_RATES from eDP 1.4 */
	if (link->edp >= 0x14) {
		u8 supported_rates[DP_MAX_SUPPORTED_RATES * 2];
		unsigned int i;
		u16 rate;

		err = drm_dp_dpcd_read(aux, DP_SUPPORTED_LINK_RATES,
				       supported_rates,
				       sizeof(supported_rates));
		if (err < 0)
			return err;

		for (i = 0; i < DP_MAX_SUPPORTED_RATES; i++) {
			rate = supported_rates[i * 2 + 1] << 8 |
			       supported_rates[i * 2 + 0];

			drm_dp_link_add_rate(link, rate * 200);
		}
	}

	return 0;
}

+9 −0
Original line number Diff line number Diff line
@@ -66,6 +66,8 @@ void drm_dp_link_caps_copy(struct drm_dp_link_caps *dest,
 * @edp: eDP revision (0x11: eDP 1.1, 0x12: eDP 1.2, ...)
 * @rate: currently configured link rate
 * @lanes: currently configured number of lanes
 * @rates: additional supported link rates in kHz (eDP 1.4)
 * @num_rates: number of additional supported link rates (eDP 1.4)
 */
struct drm_dp_link {
	unsigned char revision;
@@ -87,8 +89,15 @@ struct drm_dp_link {

	unsigned int rate;
	unsigned int lanes;

	unsigned long rates[DP_MAX_SUPPORTED_RATES];
	unsigned int num_rates;
};

int drm_dp_link_add_rate(struct drm_dp_link *link, unsigned long rate);
int drm_dp_link_remove_rate(struct drm_dp_link *link, unsigned long rate);
void drm_dp_link_update_rates(struct drm_dp_link *link);

int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link);
int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link);
int drm_dp_link_power_down(struct drm_dp_aux *aux, struct drm_dp_link *link);