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: Thierry Reding <treding@nvidia.com>
This commit is contained in:
Thierry Reding 2018-02-01 17:46:42 +01:00
parent 01f09f242e
commit 6a127160c4
2 changed files with 136 additions and 0 deletions

View File

@ -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;
}

View File

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