Skip to content

Commit

Permalink
drm/dp: Add DisplayPort link helpers
Browse files Browse the repository at this point in the history
Add a helper to probe a DP link (read out the supported DPCD revision,
maximum rate, link count and capabilities) as well as power up the DP
link and configure it accordingly.

Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Reviewed-by: Jani Nikula <jani.nikula@intel.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
Changes in v5:
- export helpers

Changes in v4:
- fix a couple of typos in comments as pointed out by Alex Deucher

Changes in v3:
- split into drm_dp_link_power_up() and drm_dp_link_configure()
- do not change sink state for DPCD versions earlier than 1.1
- sleep for 1-2 ms after setting local sink to D0 state
- read and write consecutive registers where possible
- read DPCD revision when link is probed
- remove duplicate kerneldoc
  • Loading branch information
Thierry Reding committed Feb 26, 2014
1 parent 8d4adc6 commit 516c0f7
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 0 deletions.
97 changes: 97 additions & 0 deletions drivers/gpu/drm/drm_dp_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -472,3 +472,100 @@ int drm_dp_dpcd_read_link_status(struct drm_dp_aux *aux,
DP_LINK_STATUS_SIZE);
}
EXPORT_SYMBOL(drm_dp_dpcd_read_link_status);

/**
* drm_dp_link_probe() - probe a DisplayPort link for capabilities
* @aux: DisplayPort AUX channel
* @link: pointer to structure in which to return link capabilities
*
* The structure filled in by this function can usually be passed directly
* into drm_dp_link_power_up() and drm_dp_link_configure() to power up and
* configure the link based on the link's capabilities.
*
* Returns 0 on success or a negative error code on failure.
*/
int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link)
{
u8 values[3];
int err;

memset(link, 0, sizeof(*link));

err = drm_dp_dpcd_read(aux, DP_DPCD_REV, values, sizeof(values));
if (err < 0)
return err;

link->revision = values[0];
link->rate = drm_dp_bw_code_to_link_rate(values[1]);
link->num_lanes = values[2] & DP_MAX_LANE_COUNT_MASK;

if (values[2] & DP_ENHANCED_FRAME_CAP)
link->capabilities |= DP_LINK_CAP_ENHANCED_FRAMING;

return 0;
}
EXPORT_SYMBOL(drm_dp_link_probe);

/**
* drm_dp_link_power_up() - power up a DisplayPort link
* @aux: DisplayPort AUX channel
* @link: pointer to a structure containing the link configuration
*
* Returns 0 on success or a negative error code on failure.
*/
int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link)
{
u8 value;
int err;

/* DP_SET_POWER register is only available on DPCD v1.1 and later */
if (link->revision < 0x11)
return 0;

err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value);
if (err < 0)
return err;

value &= ~DP_SET_POWER_MASK;
value |= DP_SET_POWER_D0;

err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value);
if (err < 0)
return err;

/*
* According to the DP 1.1 specification, a "Sink Device must exit the
* power saving state within 1 ms" (Section 2.5.3.1, Table 5-52, "Sink
* Control Field" (register 0x600).
*/
usleep_range(1000, 2000);

return 0;
}
EXPORT_SYMBOL(drm_dp_link_power_up);

/**
* drm_dp_link_configure() - configure a DisplayPort link
* @aux: DisplayPort AUX channel
* @link: pointer to a structure containing the link configuration
*
* Returns 0 on success or a negative error code on failure.
*/
int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link)
{
u8 values[2];
int err;

values[0] = drm_dp_link_rate_to_bw_code(link->rate);
values[1] = link->num_lanes;

if (link->capabilities & DP_LINK_CAP_ENHANCED_FRAMING)
values[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;

err = drm_dp_dpcd_write(aux, DP_LINK_BW_SET, values, sizeof(values));
if (err < 0)
return err;

return 0;
}
EXPORT_SYMBOL(drm_dp_link_configure);
17 changes: 17 additions & 0 deletions include/drm/drm_dp_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@
#define DP_SET_POWER 0x600
# define DP_SET_POWER_D0 0x1
# define DP_SET_POWER_D3 0x2
# define DP_SET_POWER_MASK 0x3

#define DP_PSR_ERROR_STATUS 0x2006 /* XXX 1.2? */
# define DP_PSR_LINK_CRC_ERROR (1 << 0)
Expand Down Expand Up @@ -480,4 +481,20 @@ static inline ssize_t drm_dp_dpcd_writeb(struct drm_dp_aux *aux,
int drm_dp_dpcd_read_link_status(struct drm_dp_aux *aux,
u8 status[DP_LINK_STATUS_SIZE]);

/*
* DisplayPort link
*/
#define DP_LINK_CAP_ENHANCED_FRAMING (1 << 0)

struct drm_dp_link {
unsigned char revision;
unsigned int rate;
unsigned int num_lanes;
unsigned long capabilities;
};

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_configure(struct drm_dp_aux *aux, struct drm_dp_link *link);

#endif /* _DRM_DP_HELPER_H_ */

0 comments on commit 516c0f7

Please sign in to comment.