On Tue, 14 Jan 2014, Thierry Reding <thierry.reding@xxxxxxxxx> wrote: > 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. > > Signed-off-by: Thierry Reding <treding@xxxxxxxxxx> > --- > 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 > > drivers/gpu/drm/drm_dp_helper.c | 94 +++++++++++++++++++++++++++++++++++++++++ > include/drm/drm_dp_helper.h | 17 ++++++++ > 2 files changed, 111 insertions(+) > > diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c > index 572637456713..ac2e12789634 100644 > --- a/drivers/gpu/drm/drm_dp_helper.c > +++ b/drivers/gpu/drm/drm_dp_helper.c > @@ -472,3 +472,97 @@ 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; Since DP_DPCD_REV == 0, you could use the #defines for the indexes (if you're going to send another version anyway). Ditto below for drm_dp_link_configure. Other than that nitpick, the series looks good to me. If we face any issues migrating i915 on top of this, we can iron them out later on. On the series, Reviewed-by: Jani Nikula <jani.nikula@xxxxxxxxx> > + > + return 0; > +} > + > +/** > + * 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; > +} > + > +/** > + * drm_dp_link_configure() - configure a DisplayPort link > + * @aux: DisplayPort AUX cahnnel > + * @link: pointer to a structure containing the link configuration > + * > + * Returns 0 on seccuss 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; > +} > diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h > index 8af695277a84..c7b3c736c40a 100644 > --- a/include/drm/drm_dp_helper.h > +++ b/include/drm/drm_dp_helper.h > @@ -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) > @@ -468,4 +469,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_ */ > -- > 1.8.4.2 > -- Jani Nikula, Intel Open Source Technology Center _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx