Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1641435 > unrolled thread

[PATCH 0/3] drm/omap: Support for hotplug detection

Started byPeter Ujfalusi <peter.ujfalusi@ti.com>
First post2017-05-15 11:10 +0200
Last post2017-05-23 13:30 +0200
Articles 9 — 3 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH 0/3] drm/omap: Support for hotplug detection Peter Ujfalusi <peter.ujfalusi@ti.com> - 2017-05-15 11:10 +0200
    [PATCH 1/3] drm/omap: Support for HDMI hot plug detection Peter Ujfalusi <peter.ujfalusi@ti.com> - 2017-05-15 11:10 +0200
      Re: [PATCH 1/3] drm/omap: Support for HDMI hot plug detection Tomi Valkeinen <tomi.valkeinen@ti.com> - 2017-05-22 14:00 +0200
        Re: [PATCH 1/3] drm/omap: Support for HDMI hot plug detection Laurent Pinchart <laurent.pinchart@ideasonboard.com> - 2017-05-23 11:40 +0200
    [PATCH 3/3] drm/omap: displays: encoder-tpd12s015: Support for hot plug detection Peter Ujfalusi <peter.ujfalusi@ti.com> - 2017-05-15 11:10 +0200
      Re: [PATCH 3/3] drm/omap: displays: encoder-tpd12s015: Support for hot plug detection Laurent Pinchart <laurent.pinchart@ideasonboard.com> - 2017-05-23 11:50 +0200
        Re: [PATCH 3/3] drm/omap: displays: encoder-tpd12s015: Support for  hot plug detection Tomi Valkeinen <tomi.valkeinen@ti.com> - 2017-05-23 12:30 +0200
          Re: [PATCH 3/3] drm/omap: displays: encoder-tpd12s015: Support for hot plug detection Laurent Pinchart <laurent.pinchart@ideasonboard.com> - 2017-05-23 12:50 +0200
            Re: [PATCH 3/3] drm/omap: displays: encoder-tpd12s015: Support for  hot plug detection Tomi Valkeinen <tomi.valkeinen@ti.com> - 2017-05-23 13:30 +0200

#1641435 — [PATCH 0/3] drm/omap: Support for hotplug detection

FromPeter Ujfalusi <peter.ujfalusi@ti.com>
Date2017-05-15 11:10 +0200
Subject[PATCH 0/3] drm/omap: Support for hotplug detection
Message-ID<tHkaT-67d-27@gated-at.bofh.it>
Hi,

this series will add support for HPD in omapdrm. Instead of polling for HPD
changes we can use interrupts to be notified of HPD change, thus we can react to
events faster.

The series is based on top of 4.12-rc1

Regards,
Peter
---
Peter Ujfalusi (3):
  drm/omap: Support for HDMI hot plug detection
  drm/omap: displays: connector-hdmi: Support for hot plug detection
  drm/omap: displays: encoder-tpd12s015: Support for hot plug detection

 drivers/gpu/drm/omapdrm/displays/connector-hdmi.c  | 104 +++++++++++++++++++++
 .../gpu/drm/omapdrm/displays/encoder-tpd12s015.c   |  81 ++++++++++++++++
 drivers/gpu/drm/omapdrm/dss/omapdss.h              |  17 ++++
 drivers/gpu/drm/omapdrm/omap_connector.c           |  32 ++++++-
 drivers/gpu/drm/omapdrm/omap_drv.c                 |  29 ++++++
 5 files changed, 262 insertions(+), 1 deletion(-)

-- 
2.12.2

[toc] | [next] | [standalone]


#1641440 — [PATCH 1/3] drm/omap: Support for HDMI hot plug detection

FromPeter Ujfalusi <peter.ujfalusi@ti.com>
Date2017-05-15 11:10 +0200
Subject[PATCH 1/3] drm/omap: Support for HDMI hot plug detection
Message-ID<tHkaW-67d-97@gated-at.bofh.it>
In reply to#1641435
The HPD signal can be used for detecting HDMI cable plug and unplug event
without the need for polling the status of the line.
This will speed up detecting such event because we do not need to wait for
the next poll event to notice the state change.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
---
 drivers/gpu/drm/omapdrm/dss/omapdss.h    | 17 +++++++++++++++++
 drivers/gpu/drm/omapdrm/omap_connector.c | 32 +++++++++++++++++++++++++++++++-
 drivers/gpu/drm/omapdrm/omap_drv.c       | 29 +++++++++++++++++++++++++++++
 3 files changed, 77 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h
index b19dae1fd6c5..1f01669eb610 100644
--- a/drivers/gpu/drm/omapdrm/dss/omapdss.h
+++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h
@@ -25,6 +25,7 @@
 #include <video/videomode.h>
 #include <linux/platform_data/omapdss.h>
 #include <uapi/drm/drm_mode.h>
+#include <drm/drm_crtc.h>
 
 #define DISPC_IRQ_FRAMEDONE		(1 << 0)
 #define DISPC_IRQ_VSYNC			(1 << 1)
@@ -555,6 +556,14 @@ struct omapdss_hdmi_ops {
 	int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len);
 	bool (*detect)(struct omap_dss_device *dssdev);
 
+	int (*register_hpd_cb)(struct omap_dss_device *dssdev,
+			       void (*cb)(void *cb_data,
+					  enum drm_connector_status status),
+			       void *cb_data);
+	void (*unregister_hpd_cb)(struct omap_dss_device *dssdev);
+	void (*enable_hpd)(struct omap_dss_device *dssdev);
+	void (*disable_hpd)(struct omap_dss_device *dssdev);
+
 	int (*set_hdmi_mode)(struct omap_dss_device *dssdev, bool hdmi_mode);
 	int (*set_infoframe)(struct omap_dss_device *dssdev,
 		const struct hdmi_avi_infoframe *avi);
@@ -761,6 +770,14 @@ struct omap_dss_driver {
 	int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len);
 	bool (*detect)(struct omap_dss_device *dssdev);
 
+	int (*register_hpd_cb)(struct omap_dss_device *dssdev,
+			       void (*cb)(void *cb_data,
+					  enum drm_connector_status status),
+			       void *cb_data);
+	void (*unregister_hpd_cb)(struct omap_dss_device *dssdev);
+	void (*enable_hpd)(struct omap_dss_device *dssdev);
+	void (*disable_hpd)(struct omap_dss_device *dssdev);
+
 	int (*set_hdmi_mode)(struct omap_dss_device *dssdev, bool hdmi_mode);
 	int (*set_hdmi_infoframe)(struct omap_dss_device *dssdev,
 		const struct hdmi_avi_infoframe *avi);
diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c
index c24b6b783e9a..5219e340ed9d 100644
--- a/drivers/gpu/drm/omapdrm/omap_connector.c
+++ b/drivers/gpu/drm/omapdrm/omap_connector.c
@@ -35,6 +35,18 @@ struct omap_connector {
 	bool hdmi_mode;
 };
 
+static void omap_connector_hpd_cb(void *cb_data,
+				  enum drm_connector_status status)
+{
+	struct omap_connector *omap_connector = cb_data;
+	struct drm_connector *connector = &omap_connector->base;
+
+	if (connector->status != status) {
+		connector->status = status;
+		drm_kms_helper_hotplug_event(omap_connector->base.dev);
+	}
+}
+
 bool omap_connector_get_hdmi_mode(struct drm_connector *connector)
 {
 	struct omap_connector *omap_connector = to_omap_connector(connector);
@@ -75,6 +87,10 @@ static void omap_connector_destroy(struct drm_connector *connector)
 	struct omap_dss_device *dssdev = omap_connector->dssdev;
 
 	DBG("%s", omap_connector->dssdev->name);
+	if (connector->polled == DRM_CONNECTOR_POLL_HPD &&
+	    dssdev->driver->unregister_hpd_cb) {
+		dssdev->driver->unregister_hpd_cb(dssdev);
+	}
 	drm_connector_unregister(connector);
 	drm_connector_cleanup(connector);
 	kfree(omap_connector);
@@ -216,6 +232,7 @@ struct drm_connector *omap_connector_init(struct drm_device *dev,
 {
 	struct drm_connector *connector = NULL;
 	struct omap_connector *omap_connector;
+	bool hpd_supported = false;
 
 	DBG("%s", dssdev->name);
 
@@ -233,7 +250,20 @@ struct drm_connector *omap_connector_init(struct drm_device *dev,
 				connector_type);
 	drm_connector_helper_add(connector, &omap_connector_helper_funcs);
 
-	if (dssdev->driver->detect)
+	if (dssdev->driver->register_hpd_cb) {
+		int ret = dssdev->driver->register_hpd_cb(dssdev,
+							  omap_connector_hpd_cb,
+							  omap_connector);
+		if (!ret)
+			hpd_supported = true;
+		else if (ret != -ENOTSUPP)
+			DBG("%s: Failed to register HPD callback (%d).",
+			    dssdev->name, ret);
+	}
+
+	if (hpd_supported)
+		connector->polled = DRM_CONNECTOR_POLL_HPD;
+	else if (dssdev->driver->detect)
 		connector->polled = DRM_CONNECTOR_POLL_CONNECT |
 				    DRM_CONNECTOR_POLL_DISCONNECT;
 	else
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index e1f47f0b3ccf..6e54e4d446a9 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -394,6 +394,32 @@ static int omap_modeset_init(struct drm_device *dev)
 }
 
 /*
+ * Enable the HPD in external components if supported
+ */
+static void omap_modeset_enable_external_hpd(void)
+{
+	struct omap_dss_device *dssdev = NULL;
+
+	for_each_dss_dev(dssdev) {
+		if (dssdev->driver->enable_hpd)
+			dssdev->driver->enable_hpd(dssdev);
+	}
+}
+
+/*
+ * Disable the HPD in external components if supported
+ */
+static void omap_modeset_disable_external_hpd(void)
+{
+	struct omap_dss_device *dssdev = NULL;
+
+	for_each_dss_dev(dssdev) {
+		if (dssdev->driver->disable_hpd)
+			dssdev->driver->disable_hpd(dssdev);
+	}
+}
+
+/*
  * drm ioctl funcs
  */
 
@@ -710,6 +736,7 @@ static int pdev_probe(struct platform_device *pdev)
 	priv->fbdev = omap_fbdev_init(ddev);
 
 	drm_kms_helper_poll_init(ddev);
+	omap_modeset_enable_external_hpd();
 
 	/*
 	 * Register the DRM device with the core and the connectors with
@@ -722,6 +749,7 @@ static int pdev_probe(struct platform_device *pdev)
 	return 0;
 
 err_cleanup_helpers:
+	omap_modeset_disable_external_hpd();
 	drm_kms_helper_poll_fini(ddev);
 	if (priv->fbdev)
 		omap_fbdev_free(ddev);
@@ -750,6 +778,7 @@ static int pdev_remove(struct platform_device *pdev)
 
 	drm_dev_unregister(ddev);
 
+	omap_modeset_disable_external_hpd();
 	drm_kms_helper_poll_fini(ddev);
 
 	if (priv->fbdev)
-- 
2.12.2

[toc] | [prev] | [next] | [standalone]


#1646786 — Re: [PATCH 1/3] drm/omap: Support for HDMI hot plug detection

FromTomi Valkeinen <tomi.valkeinen@ti.com>
Date2017-05-22 14:00 +0200
SubjectRe: [PATCH 1/3] drm/omap: Support for HDMI hot plug detection
Message-ID<tJUae-5dJ-27@gated-at.bofh.it>
In reply to#1641440

[Multipart message — attachments visible in raw view] — view raw

On 15/05/17 12:03, Peter Ujfalusi wrote:
> The HPD signal can be used for detecting HDMI cable plug and unplug event
> without the need for polling the status of the line.
> This will speed up detecting such event because we do not need to wait for
> the next poll event to notice the state change.
> 
> Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
> ---
>  drivers/gpu/drm/omapdrm/dss/omapdss.h    | 17 +++++++++++++++++
>  drivers/gpu/drm/omapdrm/omap_connector.c | 32 +++++++++++++++++++++++++++++++-
>  drivers/gpu/drm/omapdrm/omap_drv.c       | 29 +++++++++++++++++++++++++++++
>  3 files changed, 77 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h
> index b19dae1fd6c5..1f01669eb610 100644
> --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h
> +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h
> @@ -25,6 +25,7 @@
>  #include <video/videomode.h>
>  #include <linux/platform_data/omapdss.h>
>  #include <uapi/drm/drm_mode.h>
> +#include <drm/drm_crtc.h>
>  
>  #define DISPC_IRQ_FRAMEDONE		(1 << 0)
>  #define DISPC_IRQ_VSYNC			(1 << 1)
> @@ -555,6 +556,14 @@ struct omapdss_hdmi_ops {
>  	int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len);
>  	bool (*detect)(struct omap_dss_device *dssdev);
>  
> +	int (*register_hpd_cb)(struct omap_dss_device *dssdev,
> +			       void (*cb)(void *cb_data,
> +					  enum drm_connector_status status),
> +			       void *cb_data);
> +	void (*unregister_hpd_cb)(struct omap_dss_device *dssdev);
> +	void (*enable_hpd)(struct omap_dss_device *dssdev);
> +	void (*disable_hpd)(struct omap_dss_device *dssdev);
> +
>  	int (*set_hdmi_mode)(struct omap_dss_device *dssdev, bool hdmi_mode);
>  	int (*set_infoframe)(struct omap_dss_device *dssdev,
>  		const struct hdmi_avi_infoframe *avi);
> @@ -761,6 +770,14 @@ struct omap_dss_driver {
>  	int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len);
>  	bool (*detect)(struct omap_dss_device *dssdev);
>  
> +	int (*register_hpd_cb)(struct omap_dss_device *dssdev,
> +			       void (*cb)(void *cb_data,
> +					  enum drm_connector_status status),
> +			       void *cb_data);
> +	void (*unregister_hpd_cb)(struct omap_dss_device *dssdev);
> +	void (*enable_hpd)(struct omap_dss_device *dssdev);
> +	void (*disable_hpd)(struct omap_dss_device *dssdev);
> +
>  	int (*set_hdmi_mode)(struct omap_dss_device *dssdev, bool hdmi_mode);
>  	int (*set_hdmi_infoframe)(struct omap_dss_device *dssdev,
>  		const struct hdmi_avi_infoframe *avi);
> diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c
> index c24b6b783e9a..5219e340ed9d 100644
> --- a/drivers/gpu/drm/omapdrm/omap_connector.c
> +++ b/drivers/gpu/drm/omapdrm/omap_connector.c
> @@ -35,6 +35,18 @@ struct omap_connector {
>  	bool hdmi_mode;
>  };
>  
> +static void omap_connector_hpd_cb(void *cb_data,
> +				  enum drm_connector_status status)
> +{
> +	struct omap_connector *omap_connector = cb_data;
> +	struct drm_connector *connector = &omap_connector->base;
> +
> +	if (connector->status != status) {
> +		connector->status = status;
> +		drm_kms_helper_hotplug_event(omap_connector->base.dev);
> +	}
> +}

I'm not sure if this is racy or not... drm_kms_helper_hotplug_event()
should be called without locks held, but is it safe to touch
connector->status without any locks?

> +
>  bool omap_connector_get_hdmi_mode(struct drm_connector *connector)
>  {
>  	struct omap_connector *omap_connector = to_omap_connector(connector);
> @@ -75,6 +87,10 @@ static void omap_connector_destroy(struct drm_connector *connector)
>  	struct omap_dss_device *dssdev = omap_connector->dssdev;
>  
>  	DBG("%s", omap_connector->dssdev->name);
> +	if (connector->polled == DRM_CONNECTOR_POLL_HPD &&
> +	    dssdev->driver->unregister_hpd_cb) {
> +		dssdev->driver->unregister_hpd_cb(dssdev);
> +	}
>  	drm_connector_unregister(connector);
>  	drm_connector_cleanup(connector);
>  	kfree(omap_connector);
> @@ -216,6 +232,7 @@ struct drm_connector *omap_connector_init(struct drm_device *dev,
>  {
>  	struct drm_connector *connector = NULL;
>  	struct omap_connector *omap_connector;
> +	bool hpd_supported = false;
>  
>  	DBG("%s", dssdev->name);
>  
> @@ -233,7 +250,20 @@ struct drm_connector *omap_connector_init(struct drm_device *dev,
>  				connector_type);
>  	drm_connector_helper_add(connector, &omap_connector_helper_funcs);
>  
> -	if (dssdev->driver->detect)
> +	if (dssdev->driver->register_hpd_cb) {
> +		int ret = dssdev->driver->register_hpd_cb(dssdev,
> +							  omap_connector_hpd_cb,
> +							  omap_connector);
> +		if (!ret)
> +			hpd_supported = true;
> +		else if (ret != -ENOTSUPP)
> +			DBG("%s: Failed to register HPD callback (%d).",
> +			    dssdev->name, ret);

This should be an error print, shouldn't it?

 Tomi

[toc] | [prev] | [next] | [standalone]


#1647883 — Re: [PATCH 1/3] drm/omap: Support for HDMI hot plug detection

FromLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Date2017-05-23 11:40 +0200
SubjectRe: [PATCH 1/3] drm/omap: Support for HDMI hot plug detection
Message-ID<tKesh-1hY-7@gated-at.bofh.it>
In reply to#1646786
Hi Tomi,

On Monday 22 May 2017 14:59:09 Tomi Valkeinen wrote:
> On 15/05/17 12:03, Peter Ujfalusi wrote:
> > The HPD signal can be used for detecting HDMI cable plug and unplug event
> > without the need for polling the status of the line.
> > This will speed up detecting such event because we do not need to wait for
> > the next poll event to notice the state change.
> > 
> > Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
> > ---
> > 
> >  drivers/gpu/drm/omapdrm/dss/omapdss.h    | 17 +++++++++++++++++
> >  drivers/gpu/drm/omapdrm/omap_connector.c | 32 ++++++++++++++++++++++++++-
> >  drivers/gpu/drm/omapdrm/omap_drv.c       | 29 ++++++++++++++++++++++++++
> >  3 files changed, 77 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h
> > b/drivers/gpu/drm/omapdrm/dss/omapdss.h index b19dae1fd6c5..1f01669eb610
> > 100644
> > --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h
> > +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h
> > @@ -25,6 +25,7 @@
> > 
> >  #include <video/videomode.h>
> >  #include <linux/platform_data/omapdss.h>
> >  #include <uapi/drm/drm_mode.h>
> > 
> > +#include <drm/drm_crtc.h>
> > 
> >  #define DISPC_IRQ_FRAMEDONE		(1 << 0)
> >  #define DISPC_IRQ_VSYNC			(1 << 1)
> > 
> > @@ -555,6 +556,14 @@ struct omapdss_hdmi_ops {
> > 
> >  	int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len);
> >  	bool (*detect)(struct omap_dss_device *dssdev);
> > 
> > +	int (*register_hpd_cb)(struct omap_dss_device *dssdev,
> > +			       void (*cb)(void *cb_data,
> > +					  enum drm_connector_status status),
> > +			       void *cb_data);
> > +	void (*unregister_hpd_cb)(struct omap_dss_device *dssdev);
> > +	void (*enable_hpd)(struct omap_dss_device *dssdev);
> > +	void (*disable_hpd)(struct omap_dss_device *dssdev);
> > +
> > 
> >  	int (*set_hdmi_mode)(struct omap_dss_device *dssdev, bool hdmi_mode);
> >  	int (*set_infoframe)(struct omap_dss_device *dssdev,
> >  	
> >  		const struct hdmi_avi_infoframe *avi);
> > 
> > @@ -761,6 +770,14 @@ struct omap_dss_driver {
> > 
> >  	int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len);
> >  	bool (*detect)(struct omap_dss_device *dssdev);
> > 
> > +	int (*register_hpd_cb)(struct omap_dss_device *dssdev,
> > +			       void (*cb)(void *cb_data,
> > +					  enum drm_connector_status status),
> > +			       void *cb_data);
> > +	void (*unregister_hpd_cb)(struct omap_dss_device *dssdev);
> > +	void (*enable_hpd)(struct omap_dss_device *dssdev);
> > +	void (*disable_hpd)(struct omap_dss_device *dssdev);
> > +
> > 
> >  	int (*set_hdmi_mode)(struct omap_dss_device *dssdev, bool hdmi_mode);
> >  	int (*set_hdmi_infoframe)(struct omap_dss_device *dssdev,
> >  	
> >  		const struct hdmi_avi_infoframe *avi);
> > 
> > diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c
> > b/drivers/gpu/drm/omapdrm/omap_connector.c index
> > c24b6b783e9a..5219e340ed9d 100644
> > --- a/drivers/gpu/drm/omapdrm/omap_connector.c
> > +++ b/drivers/gpu/drm/omapdrm/omap_connector.c
> > @@ -35,6 +35,18 @@ struct omap_connector {
> > 
> >  	bool hdmi_mode;
> >  
> >  };
> > 
> > +static void omap_connector_hpd_cb(void *cb_data,
> > +				  enum drm_connector_status status)
> > +{
> > +	struct omap_connector *omap_connector = cb_data;
> > +	struct drm_connector *connector = &omap_connector->base;
> > +
> > +	if (connector->status != status) {
> > +		connector->status = status;
> > +		drm_kms_helper_hotplug_event(omap_connector->base.dev);
> > +	}
> > +}
> 
> I'm not sure if this is racy or not... drm_kms_helper_hotplug_event()
> should be called without locks held, but is it safe to touch
> connector->status without any locks?

We should at least protect against internal race conditions if the hpd 
callback can be called concurrently (I haven't checked the callers yet). I 
think it would be safer to use the mode_config mutex the same way 
drm_helper_hpd_irq_event() does. Something like the following should do.

	struct omap_connector *omap_connector = cb_data;
	struct drm_connector *connector = &omap_connector->base;
	struct drm_device *dev = connector->dev;
	enum drm_connector_status old_status;

	mutex_lock(&dev->mode_config.mutex);
	old_status = connector->status;
	connector->status = status;
	mutex_unlock(&dev->mode_config.mutex);

	if (old_status != status)
		drm_kms_helper_hotplug_event(dev);

> > +	if (connector->status != status) {
> > +		connector->status = status;
> > +		drm_kms_helper_hotplug_event(omap_connector->base.dev);
> > +	}
> > +
> >  bool omap_connector_get_hdmi_mode(struct drm_connector *connector)
> >  {
> >  	struct omap_connector *omap_connector = to_omap_connector(connector);
> > @@ -75,6 +87,10 @@ static void omap_connector_destroy(struct drm_connector
> > *connector)
> >  	struct omap_dss_device *dssdev = omap_connector->dssdev;
> >  	
> >  	DBG("%s", omap_connector->dssdev->name);
> > +	if (connector->polled == DRM_CONNECTOR_POLL_HPD &&
> > +	    dssdev->driver->unregister_hpd_cb) {
> > +		dssdev->driver->unregister_hpd_cb(dssdev);
> > +	}
> >  	drm_connector_unregister(connector);
> >  	drm_connector_cleanup(connector);
> >  	kfree(omap_connector);
> > @@ -216,6 +232,7 @@ struct drm_connector *omap_connector_init(struct
> > drm_device *dev,
> >  {
> >  	struct drm_connector *connector = NULL;
> >  	struct omap_connector *omap_connector;
> > +	bool hpd_supported = false;
> > 
> >  	DBG("%s", dssdev->name);
> > 
> > @@ -233,7 +250,20 @@ struct drm_connector *omap_connector_init(struct
> > drm_device *dev,
> >  				connector_type);
> >  	
> >  	drm_connector_helper_add(connector, &omap_connector_helper_funcs);
> > 
> > -	if (dssdev->driver->detect)
> > +	if (dssdev->driver->register_hpd_cb) {
> > +		int ret = dssdev->driver->register_hpd_cb(dssdev,
> > +							  
omap_connector_hpd_cb,
> > +							  omap_connector);
> > +		if (!ret)
> > +			hpd_supported = true;
> > +		else if (ret != -ENOTSUPP)
> > +			DBG("%s: Failed to register HPD callback (%d).",
> > +			    dssdev->name, ret);
> 
> This should be an error print, shouldn't it?

Can it actually happen ? If it can't, I wouldn't bother with a message at all.

-- 
Regards,

Laurent Pinchart

[toc] | [prev] | [next] | [standalone]


#1641443 — [PATCH 3/3] drm/omap: displays: encoder-tpd12s015: Support for hot plug detection

FromPeter Ujfalusi <peter.ujfalusi@ti.com>
Date2017-05-15 11:10 +0200
Subject[PATCH 3/3] drm/omap: displays: encoder-tpd12s015: Support for hot plug detection
Message-ID<tHkaW-67d-111@gated-at.bofh.it>
In reply to#1641435
Use interrupt handler for hpd GPIO to react to HPD changes.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
---
 .../gpu/drm/omapdrm/displays/encoder-tpd12s015.c   | 81 ++++++++++++++++++++++
 1 file changed, 81 insertions(+)

diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c
index 58276a48112e..529b8509dd99 100644
--- a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c
+++ b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c
@@ -15,12 +15,17 @@
 #include <linux/slab.h>
 #include <linux/platform_device.h>
 #include <linux/gpio/consumer.h>
+#include <linux/spinlock.h>
 
 #include "../dss/omapdss.h"
 
 struct panel_drv_data {
 	struct omap_dss_device dssdev;
 	struct omap_dss_device *in;
+	void (*hpd_cb)(void *cb_data, enum drm_connector_status status);
+	void *hpd_cb_data;
+	bool hpd_enabled;
+	struct mutex hpd_lock;
 
 	struct gpio_desc *ct_cp_hpd_gpio;
 	struct gpio_desc *ls_oe_gpio;
@@ -162,6 +167,49 @@ static bool tpd_detect(struct omap_dss_device *dssdev)
 	return gpiod_get_value_cansleep(ddata->hpd_gpio);
 }
 
+static int tpd_register_hpd_cb(struct omap_dss_device *dssdev,
+			       void (*cb)(void *cb_data,
+					  enum drm_connector_status status),
+			       void *cb_data)
+{
+	struct panel_drv_data *ddata = to_panel_data(dssdev);
+
+	mutex_lock(&ddata->hpd_lock);
+	ddata->hpd_cb = cb;
+	ddata->hpd_cb_data = cb_data;
+	mutex_unlock(&ddata->hpd_lock);
+
+	return 0;
+}
+
+static void tpd_unregister_hpd_cb(struct omap_dss_device *dssdev)
+{
+	struct panel_drv_data *ddata = to_panel_data(dssdev);
+
+	mutex_lock(&ddata->hpd_lock);
+	ddata->hpd_cb = NULL;
+	ddata->hpd_cb_data = NULL;
+	mutex_unlock(&ddata->hpd_lock);
+}
+
+static void tpd_enable_hpd(struct omap_dss_device *dssdev)
+{
+	struct panel_drv_data *ddata = to_panel_data(dssdev);
+
+	mutex_lock(&ddata->hpd_lock);
+	ddata->hpd_enabled = true;
+	mutex_unlock(&ddata->hpd_lock);
+}
+
+static void tpd_disable_hpd(struct omap_dss_device *dssdev)
+{
+	struct panel_drv_data *ddata = to_panel_data(dssdev);
+
+	mutex_lock(&ddata->hpd_lock);
+	ddata->hpd_enabled = false;
+	mutex_unlock(&ddata->hpd_lock);
+}
+
 static int tpd_set_infoframe(struct omap_dss_device *dssdev,
 		const struct hdmi_avi_infoframe *avi)
 {
@@ -193,10 +241,34 @@ static const struct omapdss_hdmi_ops tpd_hdmi_ops = {
 
 	.read_edid		= tpd_read_edid,
 	.detect			= tpd_detect,
+	.register_hpd_cb	= tpd_register_hpd_cb,
+	.unregister_hpd_cb	= tpd_unregister_hpd_cb,
+	.enable_hpd		= tpd_enable_hpd,
+	.disable_hpd		= tpd_disable_hpd,
 	.set_infoframe		= tpd_set_infoframe,
 	.set_hdmi_mode		= tpd_set_hdmi_mode,
 };
 
+static irqreturn_t tpd_hpd_isr(int irq, void *data)
+{
+	struct panel_drv_data *ddata = data;
+
+	mutex_lock(&ddata->hpd_lock);
+	if (ddata->hpd_enabled && ddata->hpd_cb) {
+		enum drm_connector_status status;
+
+		if (tpd_detect(&ddata->dssdev))
+			status = connector_status_connected;
+		else
+			status = connector_status_disconnected;
+
+		ddata->hpd_cb(ddata->hpd_cb_data, status);
+	}
+	mutex_unlock(&ddata->hpd_lock);
+
+	return IRQ_HANDLED;
+}
+
 static int tpd_probe_of(struct platform_device *pdev)
 {
 	struct panel_drv_data *ddata = platform_get_drvdata(pdev);
@@ -261,6 +333,15 @@ static int tpd_probe(struct platform_device *pdev)
 
 	ddata->hpd_gpio = gpio;
 
+	mutex_init(&ddata->hpd_lock);
+
+	r = devm_request_threaded_irq(&pdev->dev, gpiod_to_irq(ddata->hpd_gpio),
+		NULL, tpd_hpd_isr,
+		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+		"tpd12s015 hpd", ddata);
+	if (r)
+		goto err_gpio;
+
 	dssdev = &ddata->dssdev;
 	dssdev->ops.hdmi = &tpd_hdmi_ops;
 	dssdev->dev = &pdev->dev;
-- 
2.12.2

[toc] | [prev] | [next] | [standalone]


#1647897 — Re: [PATCH 3/3] drm/omap: displays: encoder-tpd12s015: Support for hot plug detection

FromLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Date2017-05-23 11:50 +0200
SubjectRe: [PATCH 3/3] drm/omap: displays: encoder-tpd12s015: Support for hot plug detection
Message-ID<tKeBY-1li-17@gated-at.bofh.it>
In reply to#1641443
Hi Peter,

Thank you for the patch.

On Monday 15 May 2017 12:03:12 Peter Ujfalusi wrote:
> Use interrupt handler for hpd GPIO to react to HPD changes.
> 
> Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
> ---
>  .../gpu/drm/omapdrm/displays/encoder-tpd12s015.c   | 81 +++++++++++++++++++
>  1 file changed, 81 insertions(+)
> 
> diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c
> b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c index
> 58276a48112e..529b8509dd99 100644
> --- a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c
> +++ b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c
> @@ -15,12 +15,17 @@
>  #include <linux/slab.h>
>  #include <linux/platform_device.h>
>  #include <linux/gpio/consumer.h>
> +#include <linux/spinlock.h>

Did you mean linux/mutex.h ?

> 
>  #include "../dss/omapdss.h"
> 
>  struct panel_drv_data {
>  	struct omap_dss_device dssdev;
>  	struct omap_dss_device *in;
> +	void (*hpd_cb)(void *cb_data, enum drm_connector_status status);
> +	void *hpd_cb_data;
> +	bool hpd_enabled;
> +	struct mutex hpd_lock;
> 
>  	struct gpio_desc *ct_cp_hpd_gpio;
>  	struct gpio_desc *ls_oe_gpio;
> @@ -162,6 +167,49 @@ static bool tpd_detect(struct omap_dss_device *dssdev)
>  	return gpiod_get_value_cansleep(ddata->hpd_gpio);
>  }
> 
> +static int tpd_register_hpd_cb(struct omap_dss_device *dssdev,
> +			       void (*cb)(void *cb_data,
> +					  enum drm_connector_status status),
> +			       void *cb_data)
> +{
> +	struct panel_drv_data *ddata = to_panel_data(dssdev);
> +
> +	mutex_lock(&ddata->hpd_lock);
> +	ddata->hpd_cb = cb;
> +	ddata->hpd_cb_data = cb_data;
> +	mutex_unlock(&ddata->hpd_lock);
> +
> +	return 0;
> +}
> +
> +static void tpd_unregister_hpd_cb(struct omap_dss_device *dssdev)
> +{
> +	struct panel_drv_data *ddata = to_panel_data(dssdev);
> +
> +	mutex_lock(&ddata->hpd_lock);
> +	ddata->hpd_cb = NULL;
> +	ddata->hpd_cb_data = NULL;
> +	mutex_unlock(&ddata->hpd_lock);
> +}
> +
> +static void tpd_enable_hpd(struct omap_dss_device *dssdev)
> +{
> +	struct panel_drv_data *ddata = to_panel_data(dssdev);
> +
> +	mutex_lock(&ddata->hpd_lock);
> +	ddata->hpd_enabled = true;
> +	mutex_unlock(&ddata->hpd_lock);
> +}
> +
> +static void tpd_disable_hpd(struct omap_dss_device *dssdev)
> +{
> +	struct panel_drv_data *ddata = to_panel_data(dssdev);
> +
> +	mutex_lock(&ddata->hpd_lock);
> +	ddata->hpd_enabled = false;
> +	mutex_unlock(&ddata->hpd_lock);
> +}
> +
>  static int tpd_set_infoframe(struct omap_dss_device *dssdev,
>  		const struct hdmi_avi_infoframe *avi)
>  {
> @@ -193,10 +241,34 @@ static const struct omapdss_hdmi_ops tpd_hdmi_ops = {
> 
>  	.read_edid		= tpd_read_edid,
>  	.detect			= tpd_detect,
> +	.register_hpd_cb	= tpd_register_hpd_cb,
> +	.unregister_hpd_cb	= tpd_unregister_hpd_cb,
> +	.enable_hpd		= tpd_enable_hpd,
> +	.disable_hpd		= tpd_disable_hpd,
>  	.set_infoframe		= tpd_set_infoframe,
>  	.set_hdmi_mode		= tpd_set_hdmi_mode,
>  };
> 
> +static irqreturn_t tpd_hpd_isr(int irq, void *data)
> +{
> +	struct panel_drv_data *ddata = data;
> +
> +	mutex_lock(&ddata->hpd_lock);
> +	if (ddata->hpd_enabled && ddata->hpd_cb) {
> +		enum drm_connector_status status;
> +
> +		if (tpd_detect(&ddata->dssdev))
> +			status = connector_status_connected;
> +		else
> +			status = connector_status_disconnected;
> +
> +		ddata->hpd_cb(ddata->hpd_cb_data, status);
> +	}
> +	mutex_unlock(&ddata->hpd_lock);
> +
> +	return IRQ_HANDLED;
> +}
> +
>  static int tpd_probe_of(struct platform_device *pdev)
>  {
>  	struct panel_drv_data *ddata = platform_get_drvdata(pdev);
> @@ -261,6 +333,15 @@ static int tpd_probe(struct platform_device *pdev)
> 
>  	ddata->hpd_gpio = gpio;
> 
> +	mutex_init(&ddata->hpd_lock);
> +
> +	r = devm_request_threaded_irq(&pdev->dev, gpiod_to_irq(ddata-
>hpd_gpio),

As the connector code can handle GPIO HPD thanks to patch 2/3, why does it 
have to be duplicated here ? I agree that encoders should support reporting of 
hotplug events when the HPD signal is connected to an encoder, but if it's 
connected to a GPIO, it seems to me that it should be the sole responsibility 
of the connector code to handle it.

> +		NULL, tpd_hpd_isr,
> +		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
> +		"tpd12s015 hpd", ddata);
> +	if (r)
> +		goto err_gpio;
> +
>  	dssdev = &ddata->dssdev;
>  	dssdev->ops.hdmi = &tpd_hdmi_ops;
>  	dssdev->dev = &pdev->dev;

-- 
Regards,

Laurent Pinchart

[toc] | [prev] | [next] | [standalone]


#1647919 — Re: [PATCH 3/3] drm/omap: displays: encoder-tpd12s015: Support for hot plug detection

FromTomi Valkeinen <tomi.valkeinen@ti.com>
Date2017-05-23 12:30 +0200
SubjectRe: [PATCH 3/3] drm/omap: displays: encoder-tpd12s015: Support for hot plug detection
Message-ID<tKfeG-1OH-11@gated-at.bofh.it>
In reply to#1647897

[Multipart message — attachments visible in raw view] — view raw

On 23/05/17 12:48, Laurent Pinchart wrote:

> As the connector code can handle GPIO HPD thanks to patch 2/3, why does it 
> have to be duplicated here ? I agree that encoders should support reporting of 
> hotplug events when the HPD signal is connected to an encoder, but if it's 
> connected to a GPIO, it seems to me that it should be the sole responsibility 
> of the connector code to handle it.

The HPD line goes from the connector to TPD12S015. From TPD12S015
another line goes to the SoCs GPIO.

 Tomi

[toc] | [prev] | [next] | [standalone]


#1647936 — Re: [PATCH 3/3] drm/omap: displays: encoder-tpd12s015: Support for hot plug detection

FromLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Date2017-05-23 12:50 +0200
SubjectRe: [PATCH 3/3] drm/omap: displays: encoder-tpd12s015: Support for hot plug detection
Message-ID<tKfy2-1Zz-13@gated-at.bofh.it>
In reply to#1647919
Hi Tomi,

On Tuesday 23 May 2017 13:25:34 Tomi Valkeinen wrote:
> On 23/05/17 12:48, Laurent Pinchart wrote:
> > As the connector code can handle GPIO HPD thanks to patch 2/3, why does it
> > have to be duplicated here ? I agree that encoders should support
> > reporting of hotplug events when the HPD signal is connected to an
> > encoder, but if it's connected to a GPIO, it seems to me that it should
> > be the sole responsibility of the connector code to handle it.
> 
> The HPD line goes from the connector to TPD12S015. From TPD12S015
> another line goes to the SoCs GPIO.

Isn't it the same signal, just with glitches filtered ? The TPD12S015 is an 
ESD clamp, level shifter and DC-DC converter, if it wasn't for the two control 
inputs CT_CP_HPD and LS_OE, we could probably do without a driver. I wouldn't 
add HPD support to this driver, as the chip really can't detect HPD.

-- 
Regards,

Laurent Pinchart

[toc] | [prev] | [next] | [standalone]


#1647945 — Re: [PATCH 3/3] drm/omap: displays: encoder-tpd12s015: Support for hot plug detection

FromTomi Valkeinen <tomi.valkeinen@ti.com>
Date2017-05-23 13:30 +0200
SubjectRe: [PATCH 3/3] drm/omap: displays: encoder-tpd12s015: Support for hot plug detection
Message-ID<tKgaK-2wv-3@gated-at.bofh.it>
In reply to#1647936

[Multipart message — attachments visible in raw view] — view raw

On 23/05/17 13:42, Laurent Pinchart wrote:
> Hi Tomi,
> 
> On Tuesday 23 May 2017 13:25:34 Tomi Valkeinen wrote:
>> On 23/05/17 12:48, Laurent Pinchart wrote:
>>> As the connector code can handle GPIO HPD thanks to patch 2/3, why does it
>>> have to be duplicated here ? I agree that encoders should support
>>> reporting of hotplug events when the HPD signal is connected to an
>>> encoder, but if it's connected to a GPIO, it seems to me that it should
>>> be the sole responsibility of the connector code to handle it.
>>
>> The HPD line goes from the connector to TPD12S015. From TPD12S015
>> another line goes to the SoCs GPIO.
> 
> Isn't it the same signal, just with glitches filtered ? The TPD12S015 is an 
> ESD clamp, level shifter and DC-DC converter, if it wasn't for the two control 
> inputs CT_CP_HPD and LS_OE, we could probably do without a driver. I wouldn't 
> add HPD support to this driver, as the chip really can't detect HPD.

Yes, it is the same signal, level shifted and filtered, if I'm not mistaken.

The HPD gpio is defined in TPD's DT data. And can we know what is the
state of the HPD signal when TPD hasn't configured CT_CP_HPD and LS_OE.
Will there be a glitch when CT_CP_HPD is enabled? What if connector-hdmi
is already listening to HPD signal at that point?

My guess is that having gpio handling just in the connector would work,
especially as we set the CT_CP_HPD very early when TPD is being set up.
With this series we could probably do a bit more optimized management
for CT_CP_HPD, but probably we could still make sure the sequence is
such that the CT_CP_HPD is enabled before connector-hdmi registers the irq.

But that doesn't sound quite correct to me... I do think it's TPD
driver's responsibility, and it removes all the "make sure that"'s.

 Tomi

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web