From: Chaoyi Chen <chaoyi.chen@xxxxxxxxxxxxxx> Add default DRM AUX HPD bridge device when register DisplayPort altmode. That makes it redundant for each Type-C driver to implement a similar registration process in embedded scenarios. Signed-off-by: Chaoyi Chen <chaoyi.chen@xxxxxxxxxxxxxx> --- drivers/usb/typec/altmodes/displayport.c | 27 ++++++++++++++++++++++++ drivers/usb/typec/altmodes/displayport.h | 2 ++ drivers/usb/typec/class.c | 8 +++++++ include/linux/usb/typec_altmode.h | 2 ++ 4 files changed, 39 insertions(+) diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c index 1dcb77faf85d..e026dc6e5430 100644 --- a/drivers/usb/typec/altmodes/displayport.c +++ b/drivers/usb/typec/altmodes/displayport.c @@ -14,6 +14,7 @@ #include <linux/property.h> #include <linux/usb/pd_vdo.h> #include <linux/usb/typec_dp.h> +#include <drm/bridge/aux-bridge.h> #include <drm/drm_connector.h> #include "displayport.h" @@ -182,6 +183,10 @@ static int dp_altmode_status_update(struct dp_altmode *dp) dp->pending_irq_hpd = true; } } else { + if (dp->port->hpd_dev) + drm_aux_hpd_bridge_notify(dp->port->hpd_dev, + hpd ? connector_status_connected : + connector_status_disconnected); drm_connector_oob_hotplug_event(dp->connector_fwnode, hpd ? connector_status_connected : connector_status_disconnected); @@ -206,6 +211,9 @@ static int dp_altmode_configured(struct dp_altmode *dp) * configuration is complete to signal HPD. */ if (dp->pending_hpd) { + if (dp->port->hpd_dev) + drm_aux_hpd_bridge_notify(dp->port->hpd_dev, + connector_status_connected); drm_connector_oob_hotplug_event(dp->connector_fwnode, connector_status_connected); sysfs_notify(&dp->alt->dev.kobj, "displayport", "hpd"); @@ -391,6 +399,9 @@ static int dp_altmode_vdm(struct typec_altmode *alt, dp->data.status = 0; dp->data.conf = 0; if (dp->hpd) { + if (dp->port->hpd_dev) + drm_aux_hpd_bridge_notify(dp->port->hpd_dev, + connector_status_disconnected); drm_connector_oob_hotplug_event(dp->connector_fwnode, connector_status_disconnected); dp->hpd = false; @@ -751,6 +762,18 @@ static const struct attribute_group *displayport_groups[] = { NULL, }; +void dp_altmode_hpd_device_register(struct typec_altmode *alt) +{ + if (alt->svid != USB_TYPEC_DP_SID) + return; + + alt->hpd_dev = drm_dp_hpd_bridge_register(alt->dev.parent->parent, + dev_of_node(alt->dev.parent->parent)); + if (IS_ERR(alt->hpd_dev)) + alt->hpd_dev = NULL; +} +EXPORT_SYMBOL_GPL(dp_altmode_hpd_device_register); + int dp_altmode_probe(struct typec_altmode *alt) { const struct typec_altmode *port = typec_altmode_get_partner(alt); @@ -812,6 +835,10 @@ void dp_altmode_remove(struct typec_altmode *alt) cancel_work_sync(&dp->work); typec_altmode_put_plug(dp->plug_prime); + if (dp->port->hpd_dev) + drm_aux_hpd_bridge_notify(dp->port->hpd_dev, + connector_status_disconnected); + if (dp->connector_fwnode) { drm_connector_oob_hotplug_event(dp->connector_fwnode, connector_status_disconnected); diff --git a/drivers/usb/typec/altmodes/displayport.h b/drivers/usb/typec/altmodes/displayport.h index e120364da9fd..9f3483ec10fb 100644 --- a/drivers/usb/typec/altmodes/displayport.h +++ b/drivers/usb/typec/altmodes/displayport.h @@ -2,7 +2,9 @@ #if IS_ENABLED(CONFIG_TYPEC_DP_ALTMODE) int dp_altmode_probe(struct typec_altmode *alt); void dp_altmode_remove(struct typec_altmode *alt); +void dp_altmode_hpd_device_register(struct typec_altmode *alt); #else int dp_altmode_probe(struct typec_altmode *alt) { return -ENOTSUPP; } void dp_altmode_remove(struct typec_altmode *alt) { } +void dp_altmode_hpd_device_register(struct typec_altmode *alt) { } #endif /* CONFIG_TYPEC_DP_ALTMODE */ diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index 67a533e35150..95732b6d9a95 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -15,6 +15,7 @@ #include <linux/usb/typec_mux.h> #include <linux/usb/typec_retimer.h> #include <linux/usb.h> +#include "altmodes/displayport.h" #include "bus.h" #include "class.h" @@ -600,6 +601,13 @@ typec_register_altmode(struct device *parent, return ERR_PTR(ret); } + /* + * It is too late to register the HPD device when the DisplayPort + * altmode device becomes ready. If the current altmode is DP, + * register a static HPD device. + */ + dp_altmode_hpd_device_register(&alt->adev); + return &alt->adev; } diff --git a/include/linux/usb/typec_altmode.h b/include/linux/usb/typec_altmode.h index b3c0866ea70f..acb0af1b9d5d 100644 --- a/include/linux/usb/typec_altmode.h +++ b/include/linux/usb/typec_altmode.h @@ -21,6 +21,7 @@ struct typec_altmode_ops; * @desc: Optional human readable description of the mode * @ops: Operations vector from the driver * @cable_ops: Cable operations vector from the driver. + * @hpd_dev: HPD device for DisplayPort */ struct typec_altmode { struct device dev; @@ -32,6 +33,7 @@ struct typec_altmode { char *desc; const struct typec_altmode_ops *ops; const struct typec_cable_ops *cable_ops; + struct device *hpd_dev; }; #define to_typec_altmode(d) container_of(d, struct typec_altmode, dev) -- 2.49.0