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:
@@ -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)
|
static void drm_dp_link_reset(struct drm_dp_link *link)
|
||||||
{
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
if (!link)
|
if (!link)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -47,6 +49,111 @@ static void drm_dp_link_reset(struct drm_dp_link *link)
|
|||||||
|
|
||||||
link->rate = 0;
|
link->rate = 0;
|
||||||
link->lanes = 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->rate = link->max_rate;
|
||||||
link->lanes = link->max_lanes;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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, ...)
|
* @edp: eDP revision (0x11: eDP 1.1, 0x12: eDP 1.2, ...)
|
||||||
* @rate: currently configured link rate
|
* @rate: currently configured link rate
|
||||||
* @lanes: currently configured number of lanes
|
* @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 {
|
struct drm_dp_link {
|
||||||
unsigned char revision;
|
unsigned char revision;
|
||||||
@@ -87,8 +89,15 @@ struct drm_dp_link {
|
|||||||
|
|
||||||
unsigned int rate;
|
unsigned int rate;
|
||||||
unsigned int lanes;
|
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_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_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);
|
int drm_dp_link_power_down(struct drm_dp_aux *aux, struct drm_dp_link *link);
|
||||||
|
Reference in New Issue
Block a user