On Mon, Jul 01, 2019 at 11:00:21AM +0300, Oleg Vasilev wrote: > Currently, downstream port type is only reported in debugfs. This > information should be considered important since it reflects the actual > physical connector type. Some userspace (e.g. window compositors) > may want to show this info to a user. > > The 'subconnector' property is already utilized for DVI-I and TV-out for > reporting connector subtype. > > The initial motivation for this feature came from i2c test [1]. > It is supposed to be skipped on VGA connectors, but it cannot > detect VGA over DP and fails instead. > > [1]: https://bugs.freedesktop.org/show_bug.cgi?id=104097 > Signed-off-by: Oleg Vasilev <oleg.vasilev@xxxxxxxxx> > --- > drivers/gpu/drm/drm_connector.c | 38 +++++++++++++++++++++++++++++++-- > drivers/gpu/drm/drm_dp_helper.c | 36 +++++++++++++++++++++++++++++++ > include/drm/drm_connector.h | 2 ++ > include/drm/drm_dp_helper.h | 3 +++ > include/drm/drm_mode_config.h | 6 ++++++ > include/uapi/drm/drm_mode.h | 22 ++++++++++++------- > 6 files changed, 97 insertions(+), 10 deletions(-) > > diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c > index 068d4b05f1be..95cd51254be6 100644 > --- a/drivers/gpu/drm/drm_connector.c > +++ b/drivers/gpu/drm/drm_connector.c > @@ -793,7 +793,7 @@ static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = { > DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list) > > static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = { > - { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ > + { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I, TV-out and DP */ > { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ > { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ > }; > @@ -810,7 +810,7 @@ static const struct drm_prop_enum_list drm_tv_select_enum_list[] = { > DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list) > > static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = { > - { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ > + { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I, TV-out and DP */ > { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ > { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ > { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ > @@ -819,6 +819,19 @@ static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = { > DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, > drm_tv_subconnector_enum_list) > > +static const struct drm_prop_enum_list drm_dp_subconnector_enum_list[] = { > + { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I, TV-out and DP */ > + { DRM_MODE_SUBCONNECTOR_VGA, "VGA" }, /* DP */ > + { DRM_MODE_SUBCONNECTOR_DVI, "DVI" }, /* DP */ > + { DRM_MODE_SUBCONNECTOR_HDMI, "HDMI" }, /* DP */ > + { DRM_MODE_SUBCONNECTOR_DP, "DP" }, /* DP */ > + { DRM_MODE_SUBCONNECTOR_Wireless, "Wireless" }, /* DP */ > + { DRM_MODE_SUBCONNECTOR_Native, "Native" }, /* DP */ > +}; > + > +DRM_ENUM_NAME_FN(drm_get_dp_subconnector_name, > + drm_dp_subconnector_enum_list) > + > static const struct drm_prop_enum_list hdmi_colorspaces[] = { > /* For Default case, driver will set the colorspace */ > { DRM_MODE_COLORIMETRY_DEFAULT, "Default" }, > @@ -1128,6 +1141,27 @@ int drm_mode_create_dvi_i_properties(struct drm_device *dev) > } > EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); > > +/** > + * drm_mode_create_dp_properties - create DP specific connector properties > + * @dev: DRM device > + * > + * Called by a driver the first time a DP connector is made. > + */ > +void drm_mode_create_dp_properties(struct drm_device *dev) > +{ > + struct drm_property *dp_subconnector; > + > + if (dev->mode_config.dp_subconnector_property) > + return; > + > + dp_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, > + "subconnector", > + drm_dp_subconnector_enum_list, > + ARRAY_SIZE(drm_dp_subconnector_enum_list)); > + dev->mode_config.dp_subconnector_property = dp_subconnector; > +} > +EXPORT_SYMBOL(drm_mode_create_dp_properties); > + > /** > * DOC: HDMI connector properties > * > diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c > index 0b994d083a89..63d8f0b8492c 100644 > --- a/drivers/gpu/drm/drm_dp_helper.c > +++ b/drivers/gpu/drm/drm_dp_helper.c > @@ -662,6 +662,42 @@ void drm_dp_downstream_debug(struct seq_file *m, > } > EXPORT_SYMBOL(drm_dp_downstream_debug); > > +/** > + * drm_dp_downstream_subconnector_type() - get DP branch device type > + * @dpcd: DisplayPort configuration data > + * @port_cap: port capabilities > + * > + */ > +enum drm_mode_subconnector > +drm_dp_downstream_subconnector_type(const u8 dpcd[DP_RECEIVER_CAP_SIZE], > + const u8 port_cap[4]) > +{ > + int type = port_cap[0] & DP_DS_PORT_TYPE_MASK; > + bool branch_device_present = dpcd[DP_DOWNSTREAMPORT_PRESENT] & > + DP_DWN_STRM_PORT_PRESENT; drm_dp_is_branch() > + > + if (!branch_device_present) > + return DRM_MODE_SUBCONNECTOR_Native; > + > + switch (type) { > + case DP_DS_PORT_TYPE_DP: > + case DP_DS_PORT_TYPE_DP_DUALMODE: > + return DRM_MODE_SUBCONNECTOR_DP; > + case DP_DS_PORT_TYPE_VGA: > + return DRM_MODE_SUBCONNECTOR_VGA; > + case DP_DS_PORT_TYPE_DVI: > + return DRM_MODE_SUBCONNECTOR_DVI; > + case DP_DS_PORT_TYPE_HDMI: > + return DRM_MODE_SUBCONNECTOR_HDMI; > + case DP_DS_PORT_TYPE_WIRELESS: > + return DRM_MODE_SUBCONNECTOR_Wireless; > + case DP_DS_PORT_TYPE_NON_EDID: > + default: > + return DRM_MODE_SUBCONNECTOR_Unknown; > + } DPCD 1.0 doesn't have the downstream port information at 0x80. For those you have to rely on DP_DWN_STRM_PORT_TYPE_MASK & co. > +} > +EXPORT_SYMBOL(drm_dp_downstream_subconnector_type); > + > /* > * I2C-over-AUX implementation > */ > diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h > index 4c30d751487a..66f0b2a59c9c 100644 > --- a/include/drm/drm_connector.h > +++ b/include/drm/drm_connector.h > @@ -1483,9 +1483,11 @@ const char *drm_get_dvi_i_subconnector_name(int val); > const char *drm_get_dvi_i_select_name(int val); > const char *drm_get_tv_subconnector_name(int val); > const char *drm_get_tv_select_name(int val); > +const char *drm_get_dp_subconnector_name(int val); > const char *drm_get_content_protection_name(int val); > > int drm_mode_create_dvi_i_properties(struct drm_device *dev); > +void drm_mode_create_dp_properties(struct drm_device *dev); > int drm_mode_create_tv_margin_properties(struct drm_device *dev); > int drm_mode_create_tv_properties(struct drm_device *dev, > unsigned int num_modes, > diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h > index 397896b5b21a..38792c1afed8 100644 > --- a/include/drm/drm_dp_helper.h > +++ b/include/drm/drm_dp_helper.h > @@ -1372,6 +1372,9 @@ int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE], > 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], > const u8 port_cap[4], struct drm_dp_aux *aux); > +enum drm_mode_subconnector > +drm_dp_downstream_subconnector_type(const u8 dpcd[DP_RECEIVER_CAP_SIZE], > + const u8 port_cap[4]); > > void drm_dp_aux_init(struct drm_dp_aux *aux); > int drm_dp_aux_register(struct drm_dp_aux *aux); > diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h > index 759d462d028b..957d99a34843 100644 > --- a/include/drm/drm_mode_config.h > +++ b/include/drm/drm_mode_config.h > @@ -680,6 +680,12 @@ struct drm_mode_config { > */ > struct drm_property *dvi_i_select_subconnector_property; > > + /** > + * @dp_subconnector_property: Optional DP property to differentiate > + * between different DP downstream port types. > + */ > + struct drm_property *dp_subconnector_property; > + > /** > * @tv_subconnector_property: Optional TV property to differentiate > * between different TV connector types. > diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h > index 5ab331e5dc23..9808464bdb63 100644 > --- a/include/uapi/drm/drm_mode.h > +++ b/include/uapi/drm/drm_mode.h > @@ -332,14 +332,20 @@ struct drm_mode_get_encoder { > /* This is for connectors with multiple signal types. */ > /* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */ > enum drm_mode_subconnector { > - DRM_MODE_SUBCONNECTOR_Automatic = 0, > - DRM_MODE_SUBCONNECTOR_Unknown = 0, > - DRM_MODE_SUBCONNECTOR_DVID = 3, > - DRM_MODE_SUBCONNECTOR_DVIA = 4, > - DRM_MODE_SUBCONNECTOR_Composite = 5, > - DRM_MODE_SUBCONNECTOR_SVIDEO = 6, > - DRM_MODE_SUBCONNECTOR_Component = 8, > - DRM_MODE_SUBCONNECTOR_SCART = 9, > + DRM_MODE_SUBCONNECTOR_Automatic = 0, /* DVI-I, TV */ > + DRM_MODE_SUBCONNECTOR_Unknown = 0, /* DVI-I, TV, DP */ > + DRM_MODE_SUBCONNECTOR_VGA = 1, /* DP */ > + DRM_MODE_SUBCONNECTOR_DVI = 2, /* DP */ > + DRM_MODE_SUBCONNECTOR_DVID = 3, /* DVI-I */ > + DRM_MODE_SUBCONNECTOR_DVIA = 4, /* DVI-I */ > + DRM_MODE_SUBCONNECTOR_Composite = 5, /* TV */ > + DRM_MODE_SUBCONNECTOR_SVIDEO = 6, /* TV */ > + DRM_MODE_SUBCONNECTOR_Component = 8, /* TV */ > + DRM_MODE_SUBCONNECTOR_SCART = 9, /* TV */ > + DRM_MODE_SUBCONNECTOR_DP = 10, /* DP */ > + DRM_MODE_SUBCONNECTOR_HDMI = 11, /* DP */ > + DRM_MODE_SUBCONNECTOR_Native = 15, /* DP */ > + DRM_MODE_SUBCONNECTOR_Wireless = 19, /* DP */ > }; > > #define DRM_MODE_CONNECTOR_Unknown 0 > -- > 2.22.0 > > _______________________________________________ > Intel-gfx mailing list > Intel-gfx@xxxxxxxxxxxxxxxxxxxxx > https://lists.freedesktop.org/mailman/listinfo/intel-gfx -- Ville Syrjälä Intel _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx