[PATCH RFC 4/5] drm/bridge: add dw-hdmi cec driver using Hans Verkil's CEC code

2016-08-31 Thread Russell King - ARM Linux
On Tue, Aug 23, 2016 at 10:05:45AM +0200, Hans Verkuil wrote:
> 
> 
> On 08/23/16 09:59, Russell King - ARM Linux wrote:
> > On Tue, Aug 23, 2016 at 09:21:17AM +0200, Hans Verkuil wrote:
> >> Hi Russell,
> >>
> >> On 08/12/2016 04:15 PM, Russell King wrote:
> >>> Add a CEC driver for the dw-hdmi hardware using Hans Verkil's CEC
> >>> implementation.
> >>>
> >>> Signed-off-by: Russell King 
> >>> ---
> >>>  drivers/gpu/drm/bridge/Kconfig|   7 +
> >>>  drivers/gpu/drm/bridge/Makefile   |   1 +
> >>>  drivers/gpu/drm/bridge/dw-hdmi-cec.c  | 344 
> >>> ++
> >>>  drivers/gpu/drm/bridge/dw-hdmi.c  |  64 +-
> >>>  include/linux/platform_data/dw_hdmi-cec.h |  16 ++
> >>>  5 files changed, 421 insertions(+), 11 deletions(-)
> >>>  create mode 100644 drivers/gpu/drm/bridge/dw-hdmi-cec.c
> >>>  create mode 100644 include/linux/platform_data/dw_hdmi-cec.h
> >>>
> >>
> >> 
> >>
> >>> +static unsigned int parse_hdmi_addr(const struct edid *edid)
> >>> +{
> >>> + if (!edid || edid->extensions == 0)
> >>> + return (u16)~0;
> >>> +
> >>> + return cec_get_edid_phys_addr((u8 *)edid,
> >>> + EDID_LENGTH * (edid->extensions + 1), NULL);
> >>> +}
> >>> +
> >>> +static int dw_hdmi_cec_notify(struct notifier_block *nb, unsigned long 
> >>> event,
> >>> +   void *data)
> >>> +{
> >>> + struct dw_hdmi_cec *cec = container_of(nb, struct dw_hdmi_cec, nb);
> >>> + union hdmi_event *event_block = data;
> >>> + unsigned int phys;
> >>> +
> >>> + dev_info(event_block->base.source, "event %lu\n", event);
> >>> +
> >>> + if (event_block->base.source != cec->adap->devnode.parent)
> >>> + return NOTIFY_OK;
> >>> +
> >>> + switch (event) {
> >>> + case HDMI_CONNECTED:
> >>> + break;
> >>> +
> >>> + case HDMI_DISCONNECTED:
> >>> + cec_s_phys_addr(cec->adap, CEC_PHYS_ADDR_INVALID, false);
> >>> + break;
> >>> +
> >>> + case HDMI_NEW_EDID:
> >>> + phys = parse_hdmi_addr(event_block->edid.edid);
> >>> + cec_s_phys_addr(cec->adap, phys, false);
> >>> + break;
> >>> + }
> >>> +
> >>> + return NOTIFY_OK;
> >>> +}
> >>
> >> Wouldn't it make a lot of sense to integrate this into the cec framework?
> >>
> >> All you need is to pass an hdmi_notifier_dev as argument to 
> >> cec_allocate_adapter()
> >> and you can integrate this.
> >>
> >> If you are OK with that, then I can make patches for that.
> > 
> > It's not just about CEC.  It's also used for passing information between
> > the video and audio parts, so tying this into CEC is wrong.
> 
> I'm not saying that the hdmi notifier should be integrated, just that the
> CEC core can register itself as a notifier and handle cec_s_phys_addr.

Yes, that would decrease the amount of code duplication.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.


[PATCH RFC 4/5] drm/bridge: add dw-hdmi cec driver using Hans Verkil's CEC code

2016-08-31 Thread Russell King - ARM Linux
On Tue, Aug 23, 2016 at 10:03:03AM +0200, Hans Verkuil wrote:
> Hi Russell,
> 
> On 08/12/16 16:15, Russell King wrote:
> > +   ret = devm_request_threaded_irq(>dev, cec->irq,
> > +   dw_hdmi_cec_hardirq,
> > +   dw_hdmi_cec_thread, IRQF_SHARED,
> > +   DEV_NAME, cec->adap);
> > +   if (ret < 0)
> > +   return ret;
> > +
> > +   ret = cec_register_adapter(cec->adap);
> > +   if (ret < 0)
> > +   return ret;
> > +
> > +   /*
> > +* CEC documentation says we must not call cec_delete_adapter
> > +* after a successful call to cec_register_adapter().
> > +*/
> > +   devm_remove_action(>dev, dw_hdmi_cec_del, cec);
> > +
> > +   hdmi_register_notifier(>nb);
> 
> The notifier is registered here, but who provides CEC with the initial
> physical address? As I understand it, it only tells you when things change,
> not what the initial state is.

Correct, that's a short-coming of this.  Solving that is not really
an easy problem - the hdmi notifiers don't track the state (they
aren't really aware of state themselves), nor do they track who the
originator of the messages is (again, because they don't track state.)

Fixing that requires a much more complex solution - I don't think I've
time to solve that (as illustrated by this reply taking over a week.)

So, we can either decide that we're not going to merge any CEC drivers
and other HDMI audio drivers until we solve this problem, denying people
the ability to use CEC, or we can merge what we have now and work on
solving the problem later.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.


[PATCH RFC 4/5] drm/bridge: add dw-hdmi cec driver using Hans Verkil's CEC code

2016-08-23 Thread Hans Verkuil


On 08/23/16 09:59, Russell King - ARM Linux wrote:
> On Tue, Aug 23, 2016 at 09:21:17AM +0200, Hans Verkuil wrote:
>> Hi Russell,
>>
>> On 08/12/2016 04:15 PM, Russell King wrote:
>>> Add a CEC driver for the dw-hdmi hardware using Hans Verkil's CEC
>>> implementation.
>>>
>>> Signed-off-by: Russell King 
>>> ---
>>>  drivers/gpu/drm/bridge/Kconfig|   7 +
>>>  drivers/gpu/drm/bridge/Makefile   |   1 +
>>>  drivers/gpu/drm/bridge/dw-hdmi-cec.c  | 344 
>>> ++
>>>  drivers/gpu/drm/bridge/dw-hdmi.c  |  64 +-
>>>  include/linux/platform_data/dw_hdmi-cec.h |  16 ++
>>>  5 files changed, 421 insertions(+), 11 deletions(-)
>>>  create mode 100644 drivers/gpu/drm/bridge/dw-hdmi-cec.c
>>>  create mode 100644 include/linux/platform_data/dw_hdmi-cec.h
>>>
>>
>> 
>>
>>> +static unsigned int parse_hdmi_addr(const struct edid *edid)
>>> +{
>>> +   if (!edid || edid->extensions == 0)
>>> +   return (u16)~0;
>>> +
>>> +   return cec_get_edid_phys_addr((u8 *)edid,
>>> +   EDID_LENGTH * (edid->extensions + 1), NULL);
>>> +}
>>> +
>>> +static int dw_hdmi_cec_notify(struct notifier_block *nb, unsigned long 
>>> event,
>>> + void *data)
>>> +{
>>> +   struct dw_hdmi_cec *cec = container_of(nb, struct dw_hdmi_cec, nb);
>>> +   union hdmi_event *event_block = data;
>>> +   unsigned int phys;
>>> +
>>> +   dev_info(event_block->base.source, "event %lu\n", event);
>>> +
>>> +   if (event_block->base.source != cec->adap->devnode.parent)
>>> +   return NOTIFY_OK;
>>> +
>>> +   switch (event) {
>>> +   case HDMI_CONNECTED:
>>> +   break;
>>> +
>>> +   case HDMI_DISCONNECTED:
>>> +   cec_s_phys_addr(cec->adap, CEC_PHYS_ADDR_INVALID, false);
>>> +   break;
>>> +
>>> +   case HDMI_NEW_EDID:
>>> +   phys = parse_hdmi_addr(event_block->edid.edid);
>>> +   cec_s_phys_addr(cec->adap, phys, false);
>>> +   break;
>>> +   }
>>> +
>>> +   return NOTIFY_OK;
>>> +}
>>
>> Wouldn't it make a lot of sense to integrate this into the cec framework?
>>
>> All you need is to pass an hdmi_notifier_dev as argument to 
>> cec_allocate_adapter()
>> and you can integrate this.
>>
>> If you are OK with that, then I can make patches for that.
> 
> It's not just about CEC.  It's also used for passing information between
> the video and audio parts, so tying this into CEC is wrong.

I'm not saying that the hdmi notifier should be integrated, just that the
CEC core can register itself as a notifier and handle cec_s_phys_addr.

Regards,

Hans


[PATCH RFC 4/5] drm/bridge: add dw-hdmi cec driver using Hans Verkil's CEC code

2016-08-23 Thread Hans Verkuil
Hi Russell,

On 08/12/16 16:15, Russell King wrote:
> + ret = devm_request_threaded_irq(>dev, cec->irq,
> + dw_hdmi_cec_hardirq,
> + dw_hdmi_cec_thread, IRQF_SHARED,
> + DEV_NAME, cec->adap);
> + if (ret < 0)
> + return ret;
> +
> + ret = cec_register_adapter(cec->adap);
> + if (ret < 0)
> + return ret;
> +
> + /*
> +  * CEC documentation says we must not call cec_delete_adapter
> +  * after a successful call to cec_register_adapter().
> +  */
> + devm_remove_action(>dev, dw_hdmi_cec_del, cec);
> +
> + hdmi_register_notifier(>nb);

The notifier is registered here, but who provides CEC with the initial
physical address? As I understand it, it only tells you when things change,
not what the initial state is.

Regards,

Hans


[PATCH RFC 4/5] drm/bridge: add dw-hdmi cec driver using Hans Verkil's CEC code

2016-08-23 Thread Hans Verkuil
Hi Russell,

On 08/12/2016 04:15 PM, Russell King wrote:
> Add a CEC driver for the dw-hdmi hardware using Hans Verkil's CEC
> implementation.
> 
> Signed-off-by: Russell King 
> ---
>  drivers/gpu/drm/bridge/Kconfig|   7 +
>  drivers/gpu/drm/bridge/Makefile   |   1 +
>  drivers/gpu/drm/bridge/dw-hdmi-cec.c  | 344 
> ++
>  drivers/gpu/drm/bridge/dw-hdmi.c  |  64 +-
>  include/linux/platform_data/dw_hdmi-cec.h |  16 ++
>  5 files changed, 421 insertions(+), 11 deletions(-)
>  create mode 100644 drivers/gpu/drm/bridge/dw-hdmi-cec.c
>  create mode 100644 include/linux/platform_data/dw_hdmi-cec.h
> 



> +static unsigned int parse_hdmi_addr(const struct edid *edid)
> +{
> + if (!edid || edid->extensions == 0)
> + return (u16)~0;
> +
> + return cec_get_edid_phys_addr((u8 *)edid,
> + EDID_LENGTH * (edid->extensions + 1), NULL);
> +}
> +
> +static int dw_hdmi_cec_notify(struct notifier_block *nb, unsigned long event,
> +   void *data)
> +{
> + struct dw_hdmi_cec *cec = container_of(nb, struct dw_hdmi_cec, nb);
> + union hdmi_event *event_block = data;
> + unsigned int phys;
> +
> + dev_info(event_block->base.source, "event %lu\n", event);
> +
> + if (event_block->base.source != cec->adap->devnode.parent)
> + return NOTIFY_OK;
> +
> + switch (event) {
> + case HDMI_CONNECTED:
> + break;
> +
> + case HDMI_DISCONNECTED:
> + cec_s_phys_addr(cec->adap, CEC_PHYS_ADDR_INVALID, false);
> + break;
> +
> + case HDMI_NEW_EDID:
> + phys = parse_hdmi_addr(event_block->edid.edid);
> + cec_s_phys_addr(cec->adap, phys, false);
> + break;
> + }
> +
> + return NOTIFY_OK;
> +}

Wouldn't it make a lot of sense to integrate this into the cec framework?

All you need is to pass an hdmi_notifier_dev as argument to 
cec_allocate_adapter()
and you can integrate this.

If you are OK with that, then I can make patches for that.

Regards,

Hans


[PATCH RFC 4/5] drm/bridge: add dw-hdmi cec driver using Hans Verkil's CEC code

2016-08-23 Thread Russell King - ARM Linux
On Tue, Aug 23, 2016 at 09:21:17AM +0200, Hans Verkuil wrote:
> Hi Russell,
> 
> On 08/12/2016 04:15 PM, Russell King wrote:
> > Add a CEC driver for the dw-hdmi hardware using Hans Verkil's CEC
> > implementation.
> > 
> > Signed-off-by: Russell King 
> > ---
> >  drivers/gpu/drm/bridge/Kconfig|   7 +
> >  drivers/gpu/drm/bridge/Makefile   |   1 +
> >  drivers/gpu/drm/bridge/dw-hdmi-cec.c  | 344 
> > ++
> >  drivers/gpu/drm/bridge/dw-hdmi.c  |  64 +-
> >  include/linux/platform_data/dw_hdmi-cec.h |  16 ++
> >  5 files changed, 421 insertions(+), 11 deletions(-)
> >  create mode 100644 drivers/gpu/drm/bridge/dw-hdmi-cec.c
> >  create mode 100644 include/linux/platform_data/dw_hdmi-cec.h
> > 
> 
> 
> 
> > +static unsigned int parse_hdmi_addr(const struct edid *edid)
> > +{
> > +   if (!edid || edid->extensions == 0)
> > +   return (u16)~0;
> > +
> > +   return cec_get_edid_phys_addr((u8 *)edid,
> > +   EDID_LENGTH * (edid->extensions + 1), NULL);
> > +}
> > +
> > +static int dw_hdmi_cec_notify(struct notifier_block *nb, unsigned long 
> > event,
> > + void *data)
> > +{
> > +   struct dw_hdmi_cec *cec = container_of(nb, struct dw_hdmi_cec, nb);
> > +   union hdmi_event *event_block = data;
> > +   unsigned int phys;
> > +
> > +   dev_info(event_block->base.source, "event %lu\n", event);
> > +
> > +   if (event_block->base.source != cec->adap->devnode.parent)
> > +   return NOTIFY_OK;
> > +
> > +   switch (event) {
> > +   case HDMI_CONNECTED:
> > +   break;
> > +
> > +   case HDMI_DISCONNECTED:
> > +   cec_s_phys_addr(cec->adap, CEC_PHYS_ADDR_INVALID, false);
> > +   break;
> > +
> > +   case HDMI_NEW_EDID:
> > +   phys = parse_hdmi_addr(event_block->edid.edid);
> > +   cec_s_phys_addr(cec->adap, phys, false);
> > +   break;
> > +   }
> > +
> > +   return NOTIFY_OK;
> > +}
> 
> Wouldn't it make a lot of sense to integrate this into the cec framework?
> 
> All you need is to pass an hdmi_notifier_dev as argument to 
> cec_allocate_adapter()
> and you can integrate this.
> 
> If you are OK with that, then I can make patches for that.

It's not just about CEC.  It's also used for passing information between
the video and audio parts, so tying this into CEC is wrong.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.


[PATCH RFC 4/5] drm/bridge: add dw-hdmi cec driver using Hans Verkil's CEC code

2016-08-12 Thread Hans Verkuil
On 08/12/2016 04:15 PM, Russell King wrote:
> Add a CEC driver for the dw-hdmi hardware using Hans Verkil's CEC

That's Verkuil :-)

BTW, since cec is part of the media subsystem please include linux-media for 
the next round.

Regards,

Hans


[PATCH RFC 4/5] drm/bridge: add dw-hdmi cec driver using Hans Verkil's CEC code

2016-08-12 Thread Russell King - ARM Linux
On Fri, Aug 12, 2016 at 04:25:02PM +0200, Hans Verkuil wrote:
> On 08/12/2016 04:15 PM, Russell King wrote:
> >Add a CEC driver for the dw-hdmi hardware using Hans Verkil's CEC
> 
> That's Verkuil :-)

Oops, sorry about that.

> BTW, since cec is part of the media subsystem please include linux-media
> for the next round.

I can't guarantee that, I'm quite forgetful.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.


[PATCH RFC 4/5] drm/bridge: add dw-hdmi cec driver using Hans Verkil's CEC code

2016-08-12 Thread Russell King
Add a CEC driver for the dw-hdmi hardware using Hans Verkil's CEC
implementation.

Signed-off-by: Russell King 
---
 drivers/gpu/drm/bridge/Kconfig|   7 +
 drivers/gpu/drm/bridge/Makefile   |   1 +
 drivers/gpu/drm/bridge/dw-hdmi-cec.c  | 344 ++
 drivers/gpu/drm/bridge/dw-hdmi.c  |  64 +-
 include/linux/platform_data/dw_hdmi-cec.h |  16 ++
 5 files changed, 421 insertions(+), 11 deletions(-)
 create mode 100644 drivers/gpu/drm/bridge/dw-hdmi-cec.c
 create mode 100644 include/linux/platform_data/dw_hdmi-cec.h

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 6d97d9f2b164..3ad19d16f4ca 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -33,6 +33,13 @@ config DRM_DW_HDMI_AHB_AUDIO
  Designware HDMI block.  This is used in conjunction with
  the i.MX6 HDMI driver.

+config DRM_DW_HDMI_CEC
+   tristate "Synopsis Designware CEC interface"
+   depends on DRM_DW_HDMI && MEDIA_CEC
+   help
+ Support the CE interface which is part of the Synopsis
+ Designware HDMI block.
+
 config DRM_NXP_PTN3460
tristate "NXP PTN3460 DP/LVDS bridge"
depends on OF
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index 96b13b30e6ab..4869441d35f4 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -3,6 +3,7 @@ ccflags-y := -Iinclude/drm
 obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o
 obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o
 obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o
+obj-$(CONFIG_DRM_DW_HDMI_CEC) += dw-hdmi-cec.o
 obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
 obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
 obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/
diff --git a/drivers/gpu/drm/bridge/dw-hdmi-cec.c 
b/drivers/gpu/drm/bridge/dw-hdmi-cec.c
new file mode 100644
index ..9d6b8daa584d
--- /dev/null
+++ b/drivers/gpu/drm/bridge/dw-hdmi-cec.c
@@ -0,0 +1,344 @@
+/* http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/
+ * tree/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c?h=imx_3.0.35_4.1.0 */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+#include 
+#include 
+
+#define DEV_NAME "mxc_hdmi_cec"
+
+enum {
+   HDMI_IH_CEC_STAT0   = 0x0106,
+   HDMI_IH_MUTE_CEC_STAT0  = 0x0186,
+
+   HDMI_CEC_CTRL   = 0x7d00,
+   CEC_CTRL_START  = BIT(0),
+   CEC_CTRL_NORMAL = 1 << 1,
+
+   HDMI_CEC_STAT   = 0x7d01,
+   CEC_STAT_DONE   = BIT(0),
+   CEC_STAT_EOM= BIT(1),
+   CEC_STAT_NACK   = BIT(2),
+   CEC_STAT_ARBLOST= BIT(3),
+   CEC_STAT_ERROR_INIT = BIT(4),
+   CEC_STAT_ERROR_FOLL = BIT(5),
+   CEC_STAT_WAKEUP = BIT(6),
+
+   HDMI_CEC_MASK   = 0x7d02,
+   HDMI_CEC_POLARITY   = 0x7d03,
+   HDMI_CEC_INT= 0x7d04,
+   HDMI_CEC_ADDR_L = 0x7d05,
+   HDMI_CEC_ADDR_H = 0x7d06,
+   HDMI_CEC_TX_CNT = 0x7d07,
+   HDMI_CEC_RX_CNT = 0x7d08,
+   HDMI_CEC_TX_DATA0   = 0x7d10,
+   HDMI_CEC_RX_DATA0   = 0x7d20,
+   HDMI_CEC_LOCK   = 0x7d30,
+   HDMI_CEC_WKUPCTRL   = 0x7d31,
+};
+
+struct dw_hdmi_cec {
+   void __iomem *base;
+   u32 addresses;
+   struct cec_adapter *adap;
+   struct cec_msg rx_msg;
+   unsigned int tx_status;
+   bool tx_done;
+   bool rx_done;
+   const struct dw_hdmi_cec_ops *ops;
+   void *ops_data;
+   int retries;
+   int irq;
+   struct notifier_block nb;
+};
+
+static int dw_hdmi_cec_log_addr(struct cec_adapter *adap, u8 logical_addr)
+{
+   struct dw_hdmi_cec *cec = adap->priv;
+   u32 addresses;
+
+   if (logical_addr == CEC_LOG_ADDR_INVALID)
+   addresses = cec->addresses = BIT(15);
+   else
+   addresses = cec->addresses |= BIT(logical_addr);
+
+   writeb_relaxed(addresses & 255, cec->base + HDMI_CEC_ADDR_L);
+   writeb_relaxed(addresses >> 8, cec->base + HDMI_CEC_ADDR_H);
+
+   return 0;
+}
+
+static int dw_hdmi_cec_transmit(struct cec_adapter *adap, u8 attempts,
+   u32 signal_free_time, struct cec_msg *msg)
+{
+   struct dw_hdmi_cec *cec = adap->priv;
+   unsigned i;
+
+   cec->retries = attempts;
+
+   for (i = 0; i < msg->len; i++)
+   writeb_relaxed(msg->msg[i], cec->base + HDMI_CEC_TX_DATA0 + i);
+
+   writeb_relaxed(msg->len, cec->base + HDMI_CEC_TX_CNT);
+   writeb_relaxed(CEC_CTRL_NORMAL | CEC_CTRL_START, cec->base + 
HDMI_CEC_CTRL);
+
+   return 0;
+}
+
+static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data)
+{
+   struct cec_adapter *adap = data;
+   struct dw_hdmi_cec *cec = adap->priv;
+   unsigned stat =