On Fri, 2020-09-04 at 14:53 +0300, Ville Syrjala wrote: > From: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> > > The downstream facing port caps in the DPCD can give us a hint > as to what kind of display mode the sink can use if it doesn't > have an EDID. Use that information to pick a suitable mode. > > Signed-off-by: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> > --- > drivers/gpu/drm/drm_dp_helper.c | 54 +++++++++++++++++++++++++++++++++ > drivers/gpu/drm/drm_edid.c | 19 ++++++++++++ > include/drm/drm_dp_helper.h | 12 ++++++++ > include/drm/drm_edid.h | 4 +++ > 4 files changed, 89 insertions(+) > > diff --git a/drivers/gpu/drm/drm_dp_helper.c > b/drivers/gpu/drm/drm_dp_helper.c > index f567428f2aef..0d5e9bcf11d0 100644 > --- a/drivers/gpu/drm/drm_dp_helper.c > +++ b/drivers/gpu/drm/drm_dp_helper.c > @@ -808,6 +808,60 @@ int drm_dp_downstream_max_bpc(const u8 > dpcd[DP_RECEIVER_CAP_SIZE], > } > EXPORT_SYMBOL(drm_dp_downstream_max_bpc); > > +/** > + * drm_dp_downstream_mode() - return a mode for downstream facing port > + * @dpcd: DisplayPort configuration data > + * @port_cap: port capabilities > + * > + * Provides a suitable mode for downstream facing ports without EDID. > + * > + * Returns a new drm_display_mode on success or NULL on failure > + */ > +struct drm_display_mode * > +drm_dp_downstream_mode(struct drm_device *dev, > + const u8 dpcd[DP_RECEIVER_CAP_SIZE], > + const u8 port_cap[4]) > + > +{ > + u8 vic; > + > + if (!drm_dp_is_branch(dpcd)) > + return NULL; > + > + if (dpcd[DP_DPCD_REV] < 0x11) > + return NULL; > + > + switch (port_cap[0] & DP_DS_PORT_TYPE_MASK) { > + case DP_DS_PORT_TYPE_NON_EDID: > + switch (port_cap[0] & DP_DS_NON_EDID_MASK) { > + case DP_DS_NON_EDID_720x480i_60: > + vic = 6; > + break; > + case DP_DS_NON_EDID_720x480i_50: > + vic = 21; > + break; > + case DP_DS_NON_EDID_1920x1080i_60: > + vic = 5; > + break; > + case DP_DS_NON_EDID_1920x1080i_50: > + vic = 20; > + break; > + case DP_DS_NON_EDID_1280x720_60: > + vic = 4; > + break; > + case DP_DS_NON_EDID_1280x720_50: > + vic = 19; > + break; > + default: > + return NULL; > + } > + return drm_display_mode_from_cea_vic(dev, vic); > + default: > + return NULL; > + } > +} > +EXPORT_SYMBOL(drm_dp_downstream_mode); > + > /** > * drm_dp_downstream_id() - identify branch device > * @aux: DisplayPort AUX channel > diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c > index 6840f0530a38..b9419fed6c28 100644 > --- a/drivers/gpu/drm/drm_edid.c > +++ b/drivers/gpu/drm/drm_edid.c > @@ -3738,6 +3738,25 @@ drm_add_cmdb_modes(struct drm_connector *connector, > u8 svd) > bitmap_set(hdmi->y420_cmdb_modes, vic, 1); > } > > +struct drm_display_mode * > +drm_display_mode_from_cea_vic(struct drm_device *dev, > + u8 video_code) > +{ > + const struct drm_display_mode *cea_mode; > + struct drm_display_mode *newmode; > + > + cea_mode = cea_mode_for_vic(video_code); > + if (!cea_mode) > + return NULL; > + > + newmode = drm_mode_duplicate(dev, cea_mode); > + if (!newmode) > + return NULL; > + > + return newmode; > +} > +EXPORT_SYMBOL(drm_display_mode_from_cea_vic); Forgot the kdocs > + > static int > do_cea_modes(struct drm_connector *connector, const u8 *db, u8 len) > { > diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h > index 6812a3e0de8d..fbba4a0f7366 100644 > --- a/include/drm/drm_dp_helper.h > +++ b/include/drm/drm_dp_helper.h > @@ -28,6 +28,8 @@ > #include <linux/types.h> > #include <drm/drm_connector.h> > > +struct drm_device; > + > /* > * Unless otherwise noted, all values are from the DP 1.1a spec. Note that > * DP and DPCD versions are independent. Differences from 1.0 are not > noted, > @@ -385,6 +387,13 @@ > # define DP_DS_PORT_TYPE_DP_DUALMODE 5 > # define DP_DS_PORT_TYPE_WIRELESS 6 > # define DP_DS_PORT_HPD (1 << 3) > +# define DP_DS_NON_EDID_MASK (0xf << 4) > +# define DP_DS_NON_EDID_720x480i_60 (1 << 4) > +# define DP_DS_NON_EDID_720x480i_50 (2 << 4) > +# define DP_DS_NON_EDID_1920x1080i_60 (3 << 4) > +# define DP_DS_NON_EDID_1920x1080i_50 (4 << 4) > +# define DP_DS_NON_EDID_1280x720_60 (5 << 4) > +# define DP_DS_NON_EDID_1280x720_50 (7 << 4) > /* offset 1 for VGA is maximum megapixels per second / 8 */ > /* offset 1 for DVI/HDMI is maximum TMDS clock in Mbps / 2.5 */ > /* offset 2 for VGA/DVI/HDMI */ > @@ -1654,6 +1663,9 @@ int drm_dp_downstream_min_tmds_clock(const u8 > dpcd[DP_RECEIVER_CAP_SIZE], > int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE], > const u8 port_cap[4], > const struct edid *edid); > +struct drm_display_mode *drm_dp_downstream_mode(struct drm_device *dev, > + const u8 > dpcd[DP_RECEIVER_CAP_SIZE], > + const u8 port_cap[4]); > int drm_dp_downstream_id(struct drm_dp_aux *aux, char id[6]); > void drm_dp_downstream_debug(struct seq_file *m, > const u8 dpcd[DP_RECEIVER_CAP_SIZE], > diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h > index cfa4f5af49af..b27a0e2169c8 100644 > --- a/include/drm/drm_edid.h > +++ b/include/drm/drm_edid.h > @@ -517,4 +517,8 @@ void drm_edid_get_monitor_name(struct edid *edid, char > *name, > struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, > int hsize, int vsize, int fresh, > bool rb); > +struct drm_display_mode * > +drm_display_mode_from_cea_vic(struct drm_device *dev, > + u8 video_code); > + > #endif /* __DRM_EDID_H__ */ -- Cheers, Lyude Paul (she/her) Software Engineer at Red Hat _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel