All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2 v2][resend] DesignWare HDMI I2S suport
@ 2016-08-03  2:07 ` Kuninori Morimoto
  0 siblings, 0 replies; 11+ messages in thread
From: Kuninori Morimoto @ 2016-08-03  2:07 UTC (permalink / raw)
  To: Archit Taneja, Mark Brown, David Airlie, Russell King,
	Fabio Estevam, Daniel Vetter, Koji Matsuoka, Thierry Reding
  Cc: Linux-ALSA, Liam Girdwood, Simon, linux-renesas-soc, dri-devel,
	linux-kernel


Hi Archit, Mark
Cc Thierry, Russell

These are resend of v2 of DesignWare HDMI I2S support patches.
(I added drm-bridge maintainer Archit on To:)
It will use ALSA SoC hdmi-codec driver, but we can't use it as-is
at this point.
1) patch tidyup hdmi-codec driver to enable dw-hdmi I2S support.
2) patch is based on it.
Difficult is that these 2 patches are under different maintainer.
	1) Mark ?
	2) Archit ?

Kuninori Morimoto (2):
      1) ASoC: hdmi-codec: enable multi probe for same device
      2) drm: bridge: add DesignWare HDMI I2S audio support

 drivers/gpu/drm/bridge/Kconfig             |   8 ++++++++
 drivers/gpu/drm/bridge/Makefile            |   1 +
 drivers/gpu/drm/bridge/dw-hdmi-audio.h     |   7 +++++++
 drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/bridge/dw-hdmi.c           |  22 ++++++++++++++++++--
 drivers/gpu/drm/bridge/dw-hdmi.h           |  21 +++++++++++++++++++
 sound/soc/codecs/hdmi-codec.c              |  67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 7 files changed, 251 insertions(+), 5 deletions(-)


-- 
1.9.1

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 0/2 v2][resend] DesignWare HDMI I2S suport
@ 2016-08-03  2:07 ` Kuninori Morimoto
  0 siblings, 0 replies; 11+ messages in thread
From: Kuninori Morimoto @ 2016-08-03  2:07 UTC (permalink / raw)
  To: Archit Taneja, Mark Brown, David Airlie, Russell King,
	Fabio Estevam, Daniel Vetter, Koji Matsuoka, Thierry Reding
  Cc: Linux-ALSA, Liam Girdwood, Simon, linux-renesas-soc, dri-devel,
	linux-kernel


Hi Archit, Mark
Cc Thierry, Russell

These are resend of v2 of DesignWare HDMI I2S support patches.
(I added drm-bridge maintainer Archit on To:)
It will use ALSA SoC hdmi-codec driver, but we can't use it as-is
at this point.
1) patch tidyup hdmi-codec driver to enable dw-hdmi I2S support.
2) patch is based on it.
Difficult is that these 2 patches are under different maintainer.
	1) Mark ?
	2) Archit ?

Kuninori Morimoto (2):
      1) ASoC: hdmi-codec: enable multi probe for same device
      2) drm: bridge: add DesignWare HDMI I2S audio support

 drivers/gpu/drm/bridge/Kconfig             |   8 ++++++++
 drivers/gpu/drm/bridge/Makefile            |   1 +
 drivers/gpu/drm/bridge/dw-hdmi-audio.h     |   7 +++++++
 drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/bridge/dw-hdmi.c           |  22 ++++++++++++++++++--
 drivers/gpu/drm/bridge/dw-hdmi.h           |  21 +++++++++++++++++++
 sound/soc/codecs/hdmi-codec.c              |  67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 7 files changed, 251 insertions(+), 5 deletions(-)


-- 
1.9.1

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 1/2 v2][resend] ASoC: hdmi-codec: enable multi probe for same device
  2016-08-03  2:07 ` Kuninori Morimoto
@ 2016-08-03  2:08   ` Kuninori Morimoto
  -1 siblings, 0 replies; 11+ messages in thread
From: Kuninori Morimoto @ 2016-08-03  2:08 UTC (permalink / raw)
  To: Archit Taneja, Mark Brown
  Cc: David Airlie, Russell King, Fabio Estevam, Daniel Vetter,
	Koji Matsuoka, Thierry Reding, Linux-ALSA, Liam Girdwood, Simon,
	linux-renesas-soc, dri-devel, linux-kernel


From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>

hdmi-codec driver is common HDMI sound driver,
but it doesn't care about multi sound ports.
For example, hdmi-codec driver is supporting 1 I2S and 1 SPDIF ports,
so, we can't use this driver if HDMI has 2 or more I2S ports.

And we would like to use multi detection.
For example, DesignWare HDMI driver is providing dw_hdmi_bind() to
DRM/KMS driver, and it will setups HDMI video/sound.
Note is that it will be called under for_each loop of ports.

int dw_hdmi_bind(xxx)
{
        /* register hdmi-codec driver here */
}

static int xxx_probe(struct platform_device *pdev)
{
        for_each_xxx(xx) {
                ...
                dw_hdmi_bind(xxx);
                ...
        }
}

This case, dw_hdmi_bind() would like to use hdmi-codec,
and it will be called multiple times for each ports.

Here, ASoC's CPU/Codec/Card bind will checks each "of_node" on DT,
and hdmi-codec driver is assuming its parent device for it.
But it doesn't care about case.
Thus, ASoC never detect correct sound card in this case.

To solve this issue, this patch checks each parent device,
and names "hdmi-hifi.x" in order to each ports.
And uses struct snd_soc_component_driver :: of_xlate_dai_name
for snd_soc_get_dai_name().

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
 sound/soc/codecs/hdmi-codec.c | 67 +++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 64 insertions(+), 3 deletions(-)

diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index f27d115..f64ecaa 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -24,6 +24,15 @@
 
 #include <drm/drm_crtc.h> /* This is only to get MAX_ELD_BYTES */
 
+struct hdmi_device {
+	struct device *dev;
+	struct list_head list;
+	int cnt;
+};
+#define pos_to_hdmi_device(pos)	container_of((pos), struct hdmi_device, list)
+LIST_HEAD(hdmi_device_list);
+
+#define DAI_NAME_SIZE 16
 struct hdmi_codec_priv {
 	struct hdmi_codec_pdata hcd;
 	struct snd_soc_dai_driver *daidrv;
@@ -320,7 +329,6 @@ static const struct snd_soc_dai_ops hdmi_dai_ops = {
 			 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE)
 
 static struct snd_soc_dai_driver hdmi_i2s_dai = {
-	.name = "i2s-hifi",
 	.id = DAI_ID_I2S,
 	.playback = {
 		.stream_name = "Playback",
@@ -334,7 +342,6 @@ static struct snd_soc_dai_driver hdmi_i2s_dai = {
 };
 
 static const struct snd_soc_dai_driver hdmi_spdif_dai = {
-	.name = "spdif-hifi",
 	.id = DAI_ID_SPDIF,
 	.playback = {
 		.stream_name = "Playback",
@@ -346,6 +353,27 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = {
 	.ops = &hdmi_dai_ops,
 };
 
+static char hdmi_dai_name[][DAI_NAME_SIZE] = {
+	"hdmi-hifi.0",
+	"hdmi-hifi.1",
+	"hdmi-hifi.2",
+	"hdmi-hifi.3",
+};
+
+static int hdmi_of_xlate_dai_name(struct snd_soc_component *component,
+				  struct of_phandle_args *args,
+				  const char **dai_name)
+{
+	int id = args->args[0];
+
+	if (id < ARRAY_SIZE(hdmi_dai_name)) {
+		*dai_name = hdmi_dai_name[id];
+		return 0;
+	}
+
+	return -EAGAIN;
+}
+
 static struct snd_soc_codec_driver hdmi_codec = {
 	.controls = hdmi_controls,
 	.num_controls = ARRAY_SIZE(hdmi_controls),
@@ -353,6 +381,9 @@ static struct snd_soc_codec_driver hdmi_codec = {
 	.num_dapm_widgets = ARRAY_SIZE(hdmi_widgets),
 	.dapm_routes = hdmi_routes,
 	.num_dapm_routes = ARRAY_SIZE(hdmi_routes),
+	.component_driver = {
+		.of_xlate_dai_name	= hdmi_of_xlate_dai_name,
+	},
 };
 
 static int hdmi_codec_probe(struct platform_device *pdev)
@@ -360,6 +391,8 @@ static int hdmi_codec_probe(struct platform_device *pdev)
 	struct hdmi_codec_pdata *hcd = pdev->dev.platform_data;
 	struct device *dev = &pdev->dev;
 	struct hdmi_codec_priv *hcp;
+	struct hdmi_device *hd;
+	struct list_head *pos;
 	int dai_count, i = 0;
 	int ret;
 
@@ -381,6 +414,31 @@ static int hdmi_codec_probe(struct platform_device *pdev)
 	if (!hcp)
 		return -ENOMEM;
 
+	hd = NULL;
+	list_for_each(pos, &hdmi_device_list) {
+		struct hdmi_device *tmp = pos_to_hdmi_device(pos);
+
+		if (tmp->dev == dev->parent) {
+			hd = tmp;
+			break;
+		}
+	}
+
+	if (!hd) {
+		hd = devm_kzalloc(dev, sizeof(*hd), GFP_KERNEL);
+		if (!hd)
+			return -ENOMEM;
+
+		hd->dev = dev->parent;
+
+		list_add_tail(&hd->list, &hdmi_device_list);
+	}
+
+	if (hd->cnt >= ARRAY_SIZE(hdmi_dai_name)) {
+		dev_err(dev, "too many hdmi codec are deteced\n");
+		return -EINVAL;
+	}
+
 	hcp->hcd = *hcd;
 	mutex_init(&hcp->current_stream_lock);
 
@@ -393,11 +451,14 @@ static int hdmi_codec_probe(struct platform_device *pdev)
 		hcp->daidrv[i] = hdmi_i2s_dai;
 		hcp->daidrv[i].playback.channels_max =
 			hcd->max_i2s_channels;
+		hcp->daidrv[i].name = hdmi_dai_name[hd->cnt++];
 		i++;
 	}
 
-	if (hcd->spdif)
+	if (hcd->spdif) {
 		hcp->daidrv[i] = hdmi_spdif_dai;
+		hcp->daidrv[i].name = hdmi_dai_name[hd->cnt++];
+	}
 
 	ret = snd_soc_register_codec(dev, &hdmi_codec, hcp->daidrv,
 				     dai_count);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 1/2 v2][resend] ASoC: hdmi-codec: enable multi probe for same device
@ 2016-08-03  2:08   ` Kuninori Morimoto
  0 siblings, 0 replies; 11+ messages in thread
From: Kuninori Morimoto @ 2016-08-03  2:08 UTC (permalink / raw)
  To: Archit Taneja, Mark Brown
  Cc: Fabio Estevam, Linux-ALSA, David Airlie, Daniel Vetter,
	Koji Matsuoka, dri-devel, Liam Girdwood, linux-renesas-soc,
	Simon, Russell King, Thierry Reding, linux-kernel


From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>

hdmi-codec driver is common HDMI sound driver,
but it doesn't care about multi sound ports.
For example, hdmi-codec driver is supporting 1 I2S and 1 SPDIF ports,
so, we can't use this driver if HDMI has 2 or more I2S ports.

And we would like to use multi detection.
For example, DesignWare HDMI driver is providing dw_hdmi_bind() to
DRM/KMS driver, and it will setups HDMI video/sound.
Note is that it will be called under for_each loop of ports.

int dw_hdmi_bind(xxx)
{
        /* register hdmi-codec driver here */
}

static int xxx_probe(struct platform_device *pdev)
{
        for_each_xxx(xx) {
                ...
                dw_hdmi_bind(xxx);
                ...
        }
}

This case, dw_hdmi_bind() would like to use hdmi-codec,
and it will be called multiple times for each ports.

Here, ASoC's CPU/Codec/Card bind will checks each "of_node" on DT,
and hdmi-codec driver is assuming its parent device for it.
But it doesn't care about case.
Thus, ASoC never detect correct sound card in this case.

To solve this issue, this patch checks each parent device,
and names "hdmi-hifi.x" in order to each ports.
And uses struct snd_soc_component_driver :: of_xlate_dai_name
for snd_soc_get_dai_name().

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
 sound/soc/codecs/hdmi-codec.c | 67 +++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 64 insertions(+), 3 deletions(-)

diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index f27d115..f64ecaa 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -24,6 +24,15 @@
 
 #include <drm/drm_crtc.h> /* This is only to get MAX_ELD_BYTES */
 
+struct hdmi_device {
+	struct device *dev;
+	struct list_head list;
+	int cnt;
+};
+#define pos_to_hdmi_device(pos)	container_of((pos), struct hdmi_device, list)
+LIST_HEAD(hdmi_device_list);
+
+#define DAI_NAME_SIZE 16
 struct hdmi_codec_priv {
 	struct hdmi_codec_pdata hcd;
 	struct snd_soc_dai_driver *daidrv;
@@ -320,7 +329,6 @@ static const struct snd_soc_dai_ops hdmi_dai_ops = {
 			 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE)
 
 static struct snd_soc_dai_driver hdmi_i2s_dai = {
-	.name = "i2s-hifi",
 	.id = DAI_ID_I2S,
 	.playback = {
 		.stream_name = "Playback",
@@ -334,7 +342,6 @@ static struct snd_soc_dai_driver hdmi_i2s_dai = {
 };
 
 static const struct snd_soc_dai_driver hdmi_spdif_dai = {
-	.name = "spdif-hifi",
 	.id = DAI_ID_SPDIF,
 	.playback = {
 		.stream_name = "Playback",
@@ -346,6 +353,27 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = {
 	.ops = &hdmi_dai_ops,
 };
 
+static char hdmi_dai_name[][DAI_NAME_SIZE] = {
+	"hdmi-hifi.0",
+	"hdmi-hifi.1",
+	"hdmi-hifi.2",
+	"hdmi-hifi.3",
+};
+
+static int hdmi_of_xlate_dai_name(struct snd_soc_component *component,
+				  struct of_phandle_args *args,
+				  const char **dai_name)
+{
+	int id = args->args[0];
+
+	if (id < ARRAY_SIZE(hdmi_dai_name)) {
+		*dai_name = hdmi_dai_name[id];
+		return 0;
+	}
+
+	return -EAGAIN;
+}
+
 static struct snd_soc_codec_driver hdmi_codec = {
 	.controls = hdmi_controls,
 	.num_controls = ARRAY_SIZE(hdmi_controls),
@@ -353,6 +381,9 @@ static struct snd_soc_codec_driver hdmi_codec = {
 	.num_dapm_widgets = ARRAY_SIZE(hdmi_widgets),
 	.dapm_routes = hdmi_routes,
 	.num_dapm_routes = ARRAY_SIZE(hdmi_routes),
+	.component_driver = {
+		.of_xlate_dai_name	= hdmi_of_xlate_dai_name,
+	},
 };
 
 static int hdmi_codec_probe(struct platform_device *pdev)
@@ -360,6 +391,8 @@ static int hdmi_codec_probe(struct platform_device *pdev)
 	struct hdmi_codec_pdata *hcd = pdev->dev.platform_data;
 	struct device *dev = &pdev->dev;
 	struct hdmi_codec_priv *hcp;
+	struct hdmi_device *hd;
+	struct list_head *pos;
 	int dai_count, i = 0;
 	int ret;
 
@@ -381,6 +414,31 @@ static int hdmi_codec_probe(struct platform_device *pdev)
 	if (!hcp)
 		return -ENOMEM;
 
+	hd = NULL;
+	list_for_each(pos, &hdmi_device_list) {
+		struct hdmi_device *tmp = pos_to_hdmi_device(pos);
+
+		if (tmp->dev == dev->parent) {
+			hd = tmp;
+			break;
+		}
+	}
+
+	if (!hd) {
+		hd = devm_kzalloc(dev, sizeof(*hd), GFP_KERNEL);
+		if (!hd)
+			return -ENOMEM;
+
+		hd->dev = dev->parent;
+
+		list_add_tail(&hd->list, &hdmi_device_list);
+	}
+
+	if (hd->cnt >= ARRAY_SIZE(hdmi_dai_name)) {
+		dev_err(dev, "too many hdmi codec are deteced\n");
+		return -EINVAL;
+	}
+
 	hcp->hcd = *hcd;
 	mutex_init(&hcp->current_stream_lock);
 
@@ -393,11 +451,14 @@ static int hdmi_codec_probe(struct platform_device *pdev)
 		hcp->daidrv[i] = hdmi_i2s_dai;
 		hcp->daidrv[i].playback.channels_max =
 			hcd->max_i2s_channels;
+		hcp->daidrv[i].name = hdmi_dai_name[hd->cnt++];
 		i++;
 	}
 
-	if (hcd->spdif)
+	if (hcd->spdif) {
 		hcp->daidrv[i] = hdmi_spdif_dai;
+		hcp->daidrv[i].name = hdmi_dai_name[hd->cnt++];
+	}
 
 	ret = snd_soc_register_codec(dev, &hdmi_codec, hcp->daidrv,
 				     dai_count);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 2/2 v2][resend] drm: bridge: add DesignWare HDMI I2S audio support
  2016-08-03  2:07 ` Kuninori Morimoto
@ 2016-08-03  2:09   ` Kuninori Morimoto
  -1 siblings, 0 replies; 11+ messages in thread
From: Kuninori Morimoto @ 2016-08-03  2:09 UTC (permalink / raw)
  To: Archit Taneja, Mark Brown
  Cc: David Airlie, Russell King, Fabio Estevam, Daniel Vetter,
	Koji Matsuoka, Thierry Reding, Linux-ALSA, Liam Girdwood, Simon,
	linux-renesas-soc, dri-devel, linux-kernel


From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>

Current dw-hdmi is supporting sound via AHB bus, but it has
I2S audio feature too. This patch adds I2S audio support to dw-hdmi.
This HDMI I2S is supported by using ALSA SoC common HDMI encoder
driver.

Tested-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
v1 -> v2

 - tidyup return value of snd_dw_hdmi_probe()

 drivers/gpu/drm/bridge/Kconfig             |   8 ++
 drivers/gpu/drm/bridge/Makefile            |   1 +
 drivers/gpu/drm/bridge/dw-hdmi-audio.h     |   7 ++
 drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c | 130 +++++++++++++++++++++++++++++
 drivers/gpu/drm/bridge/dw-hdmi.c           |  22 ++++-
 drivers/gpu/drm/bridge/dw-hdmi.h           |  21 +++++
 6 files changed, 187 insertions(+), 2 deletions(-)
 create mode 100644 drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 8f7423f..8e2a22d 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -32,6 +32,14 @@ config DRM_DW_HDMI_AHB_AUDIO
 	  Designware HDMI block.  This is used in conjunction with
 	  the i.MX6 HDMI driver.
 
+config DRM_DW_HDMI_I2S_AUDIO
+	tristate "Synopsis Designware I2S Audio interface"
+	depends on DRM_DW_HDMI
+	select SND_SOC_HDMI_CODEC
+	help
+	  Support the I2S Audio 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 96b13b3..1af92ad 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_I2S_AUDIO) += dw-hdmi-i2s-audio.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-audio.h b/drivers/gpu/drm/bridge/dw-hdmi-audio.h
index 91f631b..fd1f745 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi-audio.h
+++ b/drivers/gpu/drm/bridge/dw-hdmi-audio.h
@@ -11,4 +11,11 @@ struct dw_hdmi_audio_data {
 	u8 *eld;
 };
 
+struct dw_hdmi_i2s_audio_data {
+	struct dw_hdmi *hdmi;
+
+	void (*write)(struct dw_hdmi *hdmi, u8 val, int offset);
+	u8 (*read)(struct dw_hdmi *hdmi, int offset);
+};
+
 #endif
diff --git a/drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c
new file mode 100644
index 0000000..7dd2091
--- /dev/null
+++ b/drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c
@@ -0,0 +1,130 @@
+/*
+ * dw-hdmi-i2s-audio.c
+ *
+ * Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <drm/bridge/dw_hdmi.h>
+
+#include <sound/hdmi-codec.h>
+
+#include "dw-hdmi.h"
+#include "dw-hdmi-audio.h"
+
+#define DRIVER_NAME "dw-hdmi-i2s-audio"
+
+static inline void hdmi_write(struct dw_hdmi_i2s_audio_data *audio,
+			      u8 val, int offset)
+{
+	struct dw_hdmi *hdmi = audio->hdmi;
+
+	audio->write(hdmi, val, offset);
+}
+
+static inline u8 hdmi_read(struct dw_hdmi_i2s_audio_data *audio, int offset)
+{
+	struct dw_hdmi *hdmi = audio->hdmi;
+
+	return audio->read(hdmi, offset);
+}
+
+static int dw_hdmi_i2s_hw_params(struct device *dev, void *data,
+				 struct hdmi_codec_daifmt *fmt,
+				 struct hdmi_codec_params *hparms)
+{
+	struct dw_hdmi_i2s_audio_data *audio = data;
+	struct dw_hdmi *hdmi = audio->hdmi;
+	u8 conf0 = 0;
+	u8 conf1 = 0;
+	u8 inputclkfs = 0;
+
+	/* it cares I2S only */
+	if ((fmt->fmt != HDMI_I2S) ||
+	    (fmt->bit_clk_master | fmt->frame_clk_master)) {
+		dev_err(dev, "unsupported format/settings\n");
+		return -EINVAL;
+	}
+
+	inputclkfs	= HDMI_AUD_INPUTCLKFS_64FS;
+	conf0		= HDMI_AUD_CONF0_I2S_ALL_ENABLE;
+
+	switch (hparms->sample_width) {
+	case 16:
+		conf1 = HDMI_AUD_CONF1_WIDTH_16;
+		break;
+	case 24:
+	case 32:
+		conf1 = HDMI_AUD_CONF1_WIDTH_24;
+		break;
+	}
+
+	dw_hdmi_set_sample_rate(hdmi, hparms->sample_rate);
+
+	hdmi_write(audio, inputclkfs, HDMI_AUD_INPUTCLKFS);
+	hdmi_write(audio, conf0, HDMI_AUD_CONF0);
+	hdmi_write(audio, conf1, HDMI_AUD_CONF1);
+
+	dw_hdmi_audio_enable(hdmi);
+
+	return 0;
+}
+
+static void dw_hdmi_i2s_audio_shutdown(struct device *dev, void *data)
+{
+	struct dw_hdmi_i2s_audio_data *audio = data;
+	struct dw_hdmi *hdmi = audio->hdmi;
+
+	dw_hdmi_audio_disable(hdmi);
+
+	hdmi_write(audio, HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0);
+}
+
+static struct hdmi_codec_ops dw_hdmi_i2s_ops = {
+	.hw_params	= dw_hdmi_i2s_hw_params,
+	.audio_shutdown	= dw_hdmi_i2s_audio_shutdown,
+};
+
+static int snd_dw_hdmi_probe(struct platform_device *pdev)
+{
+	struct dw_hdmi_i2s_audio_data *audio = pdev->dev.platform_data;
+	struct platform_device_info pdevinfo;
+	struct hdmi_codec_pdata pdata;
+	struct platform_device *platform;
+
+
+	pdata.ops		= &dw_hdmi_i2s_ops;
+	pdata.i2s		= 1;
+	pdata.max_i2s_channels	= 6;
+	pdata.data		= audio;
+
+	memset(&pdevinfo, 0, sizeof(pdevinfo));
+	pdevinfo.parent		= pdev->dev.parent;
+	pdevinfo.id		= PLATFORM_DEVID_AUTO;
+	pdevinfo.name		= HDMI_CODEC_DRV_NAME;
+	pdevinfo.data		= &pdata;
+	pdevinfo.size_data	= sizeof(pdata);
+	pdevinfo.dma_mask	= DMA_BIT_MASK(32);
+
+	platform = platform_device_register_full(&pdevinfo);
+	if (IS_ERR_OR_NULL(platform))
+		return PTR_ERR(platform);
+
+	return 0;
+}
+
+static struct platform_driver snd_dw_hdmi_driver = {
+	.probe	= snd_dw_hdmi_probe,
+	.driver	= {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+module_platform_driver(snd_dw_hdmi_driver);
+
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
+MODULE_DESCRIPTION("Synopsis Designware HDMI I2S ALSA SoC interface");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 55e73e8..e9ba59e 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -2013,10 +2013,11 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
 	struct device_node *np = dev->of_node;
 	struct platform_device_info pdevinfo;
 	struct device_node *ddc_node;
-	struct dw_hdmi_audio_data audio;
 	struct dw_hdmi *hdmi;
 	int ret;
 	u32 val = 1;
+	u8 config0;
+	u8 config1;
 
 	hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
 	if (!hdmi)
@@ -2185,7 +2186,12 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
 	pdevinfo.parent = dev;
 	pdevinfo.id = PLATFORM_DEVID_AUTO;
 
-	if (hdmi_readb(hdmi, HDMI_CONFIG1_ID) & HDMI_CONFIG1_AHB) {
+	config0 = hdmi_readb(hdmi, HDMI_CONFIG0_ID);
+	config1 = hdmi_readb(hdmi, HDMI_CONFIG1_ID);
+
+	if (config1 & HDMI_CONFIG1_AHB) {
+		struct dw_hdmi_audio_data audio;
+
 		audio.phys = iores->start;
 		audio.base = hdmi->regs;
 		audio.irq = irq;
@@ -2197,6 +2203,18 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
 		pdevinfo.size_data = sizeof(audio);
 		pdevinfo.dma_mask = DMA_BIT_MASK(32);
 		hdmi->audio = platform_device_register_full(&pdevinfo);
+	} else if (config0 & HDMI_CONFIG0_I2S) {
+		struct dw_hdmi_i2s_audio_data audio;
+
+		audio.hdmi	= hdmi;
+		audio.write	= hdmi_writeb;
+		audio.read	= hdmi_readb;
+
+		pdevinfo.name = "dw-hdmi-i2s-audio";
+		pdevinfo.data = &audio;
+		pdevinfo.size_data = sizeof(audio);
+		pdevinfo.dma_mask = DMA_BIT_MASK(32);
+		hdmi->audio = platform_device_register_full(&pdevinfo);
 	}
 
 	/* Unmute I2CM interrupts and reset HDMI DDC I2C master controller */
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.h b/drivers/gpu/drm/bridge/dw-hdmi.h
index fc9a560..c8bdbf2 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.h
+++ b/drivers/gpu/drm/bridge/dw-hdmi.h
@@ -545,6 +545,10 @@
 #define HDMI_I2CM_FS_SCL_LCNT_0_ADDR            0x7E12
 
 enum {
+
+/* CONFIG0_ID field values */
+	HDMI_CONFIG0_I2S = 0x10,
+
 /* CONFIG1_ID field values */
 	HDMI_CONFIG1_AHB = 0x01,
 
@@ -887,6 +891,17 @@ enum {
 	HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL = 0x08,
 	HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_MASK = 0x04,
 
+/* AUD_CONF0 field values */
+	HDMI_AUD_CONF0_SW_RESET = 0x80,
+	HDMI_AUD_CONF0_I2S_ALL_ENABLE = 0x2F,
+
+/* AUD_CONF1 field values */
+	HDMI_AUD_CONF1_MODE_I2S = 0x00,
+	HDMI_AUD_CONF1_MODE_RIGHT_J = 0x02,
+	HDMI_AUD_CONF1_MODE_LEFT_J = 0x04,
+	HDMI_AUD_CONF1_WIDTH_16 = 0x10,
+	HDMI_AUD_CONF1_WIDTH_24 = 0x18,
+
 /* AUD_CTS3 field values */
 	HDMI_AUD_CTS3_N_SHIFT_OFFSET = 5,
 	HDMI_AUD_CTS3_N_SHIFT_MASK = 0xe0,
@@ -901,6 +916,12 @@ enum {
 	HDMI_AUD_CTS3_CTS_MANUAL = 0x10,
 	HDMI_AUD_CTS3_AUDCTS19_16_MASK = 0x0f,
 
+/* HDMI_AUD_INPUTCLKFS field values */
+	HDMI_AUD_INPUTCLKFS_128FS = 0,
+	HDMI_AUD_INPUTCLKFS_256FS = 1,
+	HDMI_AUD_INPUTCLKFS_512FS = 2,
+	HDMI_AUD_INPUTCLKFS_64FS = 4,
+
 /* AHB_DMA_CONF0 field values */
 	HDMI_AHB_DMA_CONF0_SW_FIFO_RST_OFFSET = 7,
 	HDMI_AHB_DMA_CONF0_SW_FIFO_RST_MASK = 0x80,
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 2/2 v2][resend] drm: bridge: add DesignWare HDMI I2S audio support
@ 2016-08-03  2:09   ` Kuninori Morimoto
  0 siblings, 0 replies; 11+ messages in thread
From: Kuninori Morimoto @ 2016-08-03  2:09 UTC (permalink / raw)
  To: Archit Taneja, Mark Brown
  Cc: Fabio Estevam, Linux-ALSA, David Airlie, Daniel Vetter,
	Koji Matsuoka, dri-devel, Liam Girdwood, linux-renesas-soc,
	Simon, Russell King, Thierry Reding, linux-kernel


From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>

Current dw-hdmi is supporting sound via AHB bus, but it has
I2S audio feature too. This patch adds I2S audio support to dw-hdmi.
This HDMI I2S is supported by using ALSA SoC common HDMI encoder
driver.

Tested-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
v1 -> v2

 - tidyup return value of snd_dw_hdmi_probe()

 drivers/gpu/drm/bridge/Kconfig             |   8 ++
 drivers/gpu/drm/bridge/Makefile            |   1 +
 drivers/gpu/drm/bridge/dw-hdmi-audio.h     |   7 ++
 drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c | 130 +++++++++++++++++++++++++++++
 drivers/gpu/drm/bridge/dw-hdmi.c           |  22 ++++-
 drivers/gpu/drm/bridge/dw-hdmi.h           |  21 +++++
 6 files changed, 187 insertions(+), 2 deletions(-)
 create mode 100644 drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 8f7423f..8e2a22d 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -32,6 +32,14 @@ config DRM_DW_HDMI_AHB_AUDIO
 	  Designware HDMI block.  This is used in conjunction with
 	  the i.MX6 HDMI driver.
 
+config DRM_DW_HDMI_I2S_AUDIO
+	tristate "Synopsis Designware I2S Audio interface"
+	depends on DRM_DW_HDMI
+	select SND_SOC_HDMI_CODEC
+	help
+	  Support the I2S Audio 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 96b13b3..1af92ad 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_I2S_AUDIO) += dw-hdmi-i2s-audio.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-audio.h b/drivers/gpu/drm/bridge/dw-hdmi-audio.h
index 91f631b..fd1f745 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi-audio.h
+++ b/drivers/gpu/drm/bridge/dw-hdmi-audio.h
@@ -11,4 +11,11 @@ struct dw_hdmi_audio_data {
 	u8 *eld;
 };
 
+struct dw_hdmi_i2s_audio_data {
+	struct dw_hdmi *hdmi;
+
+	void (*write)(struct dw_hdmi *hdmi, u8 val, int offset);
+	u8 (*read)(struct dw_hdmi *hdmi, int offset);
+};
+
 #endif
diff --git a/drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c
new file mode 100644
index 0000000..7dd2091
--- /dev/null
+++ b/drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c
@@ -0,0 +1,130 @@
+/*
+ * dw-hdmi-i2s-audio.c
+ *
+ * Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <drm/bridge/dw_hdmi.h>
+
+#include <sound/hdmi-codec.h>
+
+#include "dw-hdmi.h"
+#include "dw-hdmi-audio.h"
+
+#define DRIVER_NAME "dw-hdmi-i2s-audio"
+
+static inline void hdmi_write(struct dw_hdmi_i2s_audio_data *audio,
+			      u8 val, int offset)
+{
+	struct dw_hdmi *hdmi = audio->hdmi;
+
+	audio->write(hdmi, val, offset);
+}
+
+static inline u8 hdmi_read(struct dw_hdmi_i2s_audio_data *audio, int offset)
+{
+	struct dw_hdmi *hdmi = audio->hdmi;
+
+	return audio->read(hdmi, offset);
+}
+
+static int dw_hdmi_i2s_hw_params(struct device *dev, void *data,
+				 struct hdmi_codec_daifmt *fmt,
+				 struct hdmi_codec_params *hparms)
+{
+	struct dw_hdmi_i2s_audio_data *audio = data;
+	struct dw_hdmi *hdmi = audio->hdmi;
+	u8 conf0 = 0;
+	u8 conf1 = 0;
+	u8 inputclkfs = 0;
+
+	/* it cares I2S only */
+	if ((fmt->fmt != HDMI_I2S) ||
+	    (fmt->bit_clk_master | fmt->frame_clk_master)) {
+		dev_err(dev, "unsupported format/settings\n");
+		return -EINVAL;
+	}
+
+	inputclkfs	= HDMI_AUD_INPUTCLKFS_64FS;
+	conf0		= HDMI_AUD_CONF0_I2S_ALL_ENABLE;
+
+	switch (hparms->sample_width) {
+	case 16:
+		conf1 = HDMI_AUD_CONF1_WIDTH_16;
+		break;
+	case 24:
+	case 32:
+		conf1 = HDMI_AUD_CONF1_WIDTH_24;
+		break;
+	}
+
+	dw_hdmi_set_sample_rate(hdmi, hparms->sample_rate);
+
+	hdmi_write(audio, inputclkfs, HDMI_AUD_INPUTCLKFS);
+	hdmi_write(audio, conf0, HDMI_AUD_CONF0);
+	hdmi_write(audio, conf1, HDMI_AUD_CONF1);
+
+	dw_hdmi_audio_enable(hdmi);
+
+	return 0;
+}
+
+static void dw_hdmi_i2s_audio_shutdown(struct device *dev, void *data)
+{
+	struct dw_hdmi_i2s_audio_data *audio = data;
+	struct dw_hdmi *hdmi = audio->hdmi;
+
+	dw_hdmi_audio_disable(hdmi);
+
+	hdmi_write(audio, HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0);
+}
+
+static struct hdmi_codec_ops dw_hdmi_i2s_ops = {
+	.hw_params	= dw_hdmi_i2s_hw_params,
+	.audio_shutdown	= dw_hdmi_i2s_audio_shutdown,
+};
+
+static int snd_dw_hdmi_probe(struct platform_device *pdev)
+{
+	struct dw_hdmi_i2s_audio_data *audio = pdev->dev.platform_data;
+	struct platform_device_info pdevinfo;
+	struct hdmi_codec_pdata pdata;
+	struct platform_device *platform;
+
+
+	pdata.ops		= &dw_hdmi_i2s_ops;
+	pdata.i2s		= 1;
+	pdata.max_i2s_channels	= 6;
+	pdata.data		= audio;
+
+	memset(&pdevinfo, 0, sizeof(pdevinfo));
+	pdevinfo.parent		= pdev->dev.parent;
+	pdevinfo.id		= PLATFORM_DEVID_AUTO;
+	pdevinfo.name		= HDMI_CODEC_DRV_NAME;
+	pdevinfo.data		= &pdata;
+	pdevinfo.size_data	= sizeof(pdata);
+	pdevinfo.dma_mask	= DMA_BIT_MASK(32);
+
+	platform = platform_device_register_full(&pdevinfo);
+	if (IS_ERR_OR_NULL(platform))
+		return PTR_ERR(platform);
+
+	return 0;
+}
+
+static struct platform_driver snd_dw_hdmi_driver = {
+	.probe	= snd_dw_hdmi_probe,
+	.driver	= {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+module_platform_driver(snd_dw_hdmi_driver);
+
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
+MODULE_DESCRIPTION("Synopsis Designware HDMI I2S ALSA SoC interface");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 55e73e8..e9ba59e 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -2013,10 +2013,11 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
 	struct device_node *np = dev->of_node;
 	struct platform_device_info pdevinfo;
 	struct device_node *ddc_node;
-	struct dw_hdmi_audio_data audio;
 	struct dw_hdmi *hdmi;
 	int ret;
 	u32 val = 1;
+	u8 config0;
+	u8 config1;
 
 	hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
 	if (!hdmi)
@@ -2185,7 +2186,12 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
 	pdevinfo.parent = dev;
 	pdevinfo.id = PLATFORM_DEVID_AUTO;
 
-	if (hdmi_readb(hdmi, HDMI_CONFIG1_ID) & HDMI_CONFIG1_AHB) {
+	config0 = hdmi_readb(hdmi, HDMI_CONFIG0_ID);
+	config1 = hdmi_readb(hdmi, HDMI_CONFIG1_ID);
+
+	if (config1 & HDMI_CONFIG1_AHB) {
+		struct dw_hdmi_audio_data audio;
+
 		audio.phys = iores->start;
 		audio.base = hdmi->regs;
 		audio.irq = irq;
@@ -2197,6 +2203,18 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
 		pdevinfo.size_data = sizeof(audio);
 		pdevinfo.dma_mask = DMA_BIT_MASK(32);
 		hdmi->audio = platform_device_register_full(&pdevinfo);
+	} else if (config0 & HDMI_CONFIG0_I2S) {
+		struct dw_hdmi_i2s_audio_data audio;
+
+		audio.hdmi	= hdmi;
+		audio.write	= hdmi_writeb;
+		audio.read	= hdmi_readb;
+
+		pdevinfo.name = "dw-hdmi-i2s-audio";
+		pdevinfo.data = &audio;
+		pdevinfo.size_data = sizeof(audio);
+		pdevinfo.dma_mask = DMA_BIT_MASK(32);
+		hdmi->audio = platform_device_register_full(&pdevinfo);
 	}
 
 	/* Unmute I2CM interrupts and reset HDMI DDC I2C master controller */
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.h b/drivers/gpu/drm/bridge/dw-hdmi.h
index fc9a560..c8bdbf2 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.h
+++ b/drivers/gpu/drm/bridge/dw-hdmi.h
@@ -545,6 +545,10 @@
 #define HDMI_I2CM_FS_SCL_LCNT_0_ADDR            0x7E12
 
 enum {
+
+/* CONFIG0_ID field values */
+	HDMI_CONFIG0_I2S = 0x10,
+
 /* CONFIG1_ID field values */
 	HDMI_CONFIG1_AHB = 0x01,
 
@@ -887,6 +891,17 @@ enum {
 	HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL = 0x08,
 	HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_MASK = 0x04,
 
+/* AUD_CONF0 field values */
+	HDMI_AUD_CONF0_SW_RESET = 0x80,
+	HDMI_AUD_CONF0_I2S_ALL_ENABLE = 0x2F,
+
+/* AUD_CONF1 field values */
+	HDMI_AUD_CONF1_MODE_I2S = 0x00,
+	HDMI_AUD_CONF1_MODE_RIGHT_J = 0x02,
+	HDMI_AUD_CONF1_MODE_LEFT_J = 0x04,
+	HDMI_AUD_CONF1_WIDTH_16 = 0x10,
+	HDMI_AUD_CONF1_WIDTH_24 = 0x18,
+
 /* AUD_CTS3 field values */
 	HDMI_AUD_CTS3_N_SHIFT_OFFSET = 5,
 	HDMI_AUD_CTS3_N_SHIFT_MASK = 0xe0,
@@ -901,6 +916,12 @@ enum {
 	HDMI_AUD_CTS3_CTS_MANUAL = 0x10,
 	HDMI_AUD_CTS3_AUDCTS19_16_MASK = 0x0f,
 
+/* HDMI_AUD_INPUTCLKFS field values */
+	HDMI_AUD_INPUTCLKFS_128FS = 0,
+	HDMI_AUD_INPUTCLKFS_256FS = 1,
+	HDMI_AUD_INPUTCLKFS_512FS = 2,
+	HDMI_AUD_INPUTCLKFS_64FS = 4,
+
 /* AHB_DMA_CONF0 field values */
 	HDMI_AHB_DMA_CONF0_SW_FIFO_RST_OFFSET = 7,
 	HDMI_AHB_DMA_CONF0_SW_FIFO_RST_MASK = 0x80,
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/2 v2][resend] drm: bridge: add DesignWare HDMI I2S audio support
  2016-08-03  2:09   ` Kuninori Morimoto
@ 2016-09-16  8:01     ` Kuninori Morimoto
  -1 siblings, 0 replies; 11+ messages in thread
From: Kuninori Morimoto @ 2016-09-16  8:01 UTC (permalink / raw)
  To: Mark Brown
  Cc: Archit Taneja, David Airlie, Russell King, Fabio Estevam,
	Daniel Vetter, Koji Matsuoka, Thierry Reding, Linux-ALSA,
	Liam Girdwood, Simon, linux-renesas-soc, dri-devel, linux-kernel


Hi Mark

Can I have feedback about this patch ?

> From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> 
> Current dw-hdmi is supporting sound via AHB bus, but it has
> I2S audio feature too. This patch adds I2S audio support to dw-hdmi.
> This HDMI I2S is supported by using ALSA SoC common HDMI encoder
> driver.
> 
> Tested-by: Jose Abreu <joabreu@synopsys.com>
> Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> ---
> v1 -> v2
> 
>  - tidyup return value of snd_dw_hdmi_probe()
> 
>  drivers/gpu/drm/bridge/Kconfig             |   8 ++
>  drivers/gpu/drm/bridge/Makefile            |   1 +
>  drivers/gpu/drm/bridge/dw-hdmi-audio.h     |   7 ++
>  drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c | 130 +++++++++++++++++++++++++++++
>  drivers/gpu/drm/bridge/dw-hdmi.c           |  22 ++++-
>  drivers/gpu/drm/bridge/dw-hdmi.h           |  21 +++++
>  6 files changed, 187 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c
> 
> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
> index 8f7423f..8e2a22d 100644
> --- a/drivers/gpu/drm/bridge/Kconfig
> +++ b/drivers/gpu/drm/bridge/Kconfig
> @@ -32,6 +32,14 @@ config DRM_DW_HDMI_AHB_AUDIO
>  	  Designware HDMI block.  This is used in conjunction with
>  	  the i.MX6 HDMI driver.
>  
> +config DRM_DW_HDMI_I2S_AUDIO
> +	tristate "Synopsis Designware I2S Audio interface"
> +	depends on DRM_DW_HDMI
> +	select SND_SOC_HDMI_CODEC
> +	help
> +	  Support the I2S Audio 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 96b13b3..1af92ad 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_I2S_AUDIO) += dw-hdmi-i2s-audio.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-audio.h b/drivers/gpu/drm/bridge/dw-hdmi-audio.h
> index 91f631b..fd1f745 100644
> --- a/drivers/gpu/drm/bridge/dw-hdmi-audio.h
> +++ b/drivers/gpu/drm/bridge/dw-hdmi-audio.h
> @@ -11,4 +11,11 @@ struct dw_hdmi_audio_data {
>  	u8 *eld;
>  };
>  
> +struct dw_hdmi_i2s_audio_data {
> +	struct dw_hdmi *hdmi;
> +
> +	void (*write)(struct dw_hdmi *hdmi, u8 val, int offset);
> +	u8 (*read)(struct dw_hdmi *hdmi, int offset);
> +};
> +
>  #endif
> diff --git a/drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c
> new file mode 100644
> index 0000000..7dd2091
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c
> @@ -0,0 +1,130 @@
> +/*
> + * dw-hdmi-i2s-audio.c
> + *
> + * Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +#include <drm/bridge/dw_hdmi.h>
> +
> +#include <sound/hdmi-codec.h>
> +
> +#include "dw-hdmi.h"
> +#include "dw-hdmi-audio.h"
> +
> +#define DRIVER_NAME "dw-hdmi-i2s-audio"
> +
> +static inline void hdmi_write(struct dw_hdmi_i2s_audio_data *audio,
> +			      u8 val, int offset)
> +{
> +	struct dw_hdmi *hdmi = audio->hdmi;
> +
> +	audio->write(hdmi, val, offset);
> +}
> +
> +static inline u8 hdmi_read(struct dw_hdmi_i2s_audio_data *audio, int offset)
> +{
> +	struct dw_hdmi *hdmi = audio->hdmi;
> +
> +	return audio->read(hdmi, offset);
> +}
> +
> +static int dw_hdmi_i2s_hw_params(struct device *dev, void *data,
> +				 struct hdmi_codec_daifmt *fmt,
> +				 struct hdmi_codec_params *hparms)
> +{
> +	struct dw_hdmi_i2s_audio_data *audio = data;
> +	struct dw_hdmi *hdmi = audio->hdmi;
> +	u8 conf0 = 0;
> +	u8 conf1 = 0;
> +	u8 inputclkfs = 0;
> +
> +	/* it cares I2S only */
> +	if ((fmt->fmt != HDMI_I2S) ||
> +	    (fmt->bit_clk_master | fmt->frame_clk_master)) {
> +		dev_err(dev, "unsupported format/settings\n");
> +		return -EINVAL;
> +	}
> +
> +	inputclkfs	= HDMI_AUD_INPUTCLKFS_64FS;
> +	conf0		= HDMI_AUD_CONF0_I2S_ALL_ENABLE;
> +
> +	switch (hparms->sample_width) {
> +	case 16:
> +		conf1 = HDMI_AUD_CONF1_WIDTH_16;
> +		break;
> +	case 24:
> +	case 32:
> +		conf1 = HDMI_AUD_CONF1_WIDTH_24;
> +		break;
> +	}
> +
> +	dw_hdmi_set_sample_rate(hdmi, hparms->sample_rate);
> +
> +	hdmi_write(audio, inputclkfs, HDMI_AUD_INPUTCLKFS);
> +	hdmi_write(audio, conf0, HDMI_AUD_CONF0);
> +	hdmi_write(audio, conf1, HDMI_AUD_CONF1);
> +
> +	dw_hdmi_audio_enable(hdmi);
> +
> +	return 0;
> +}
> +
> +static void dw_hdmi_i2s_audio_shutdown(struct device *dev, void *data)
> +{
> +	struct dw_hdmi_i2s_audio_data *audio = data;
> +	struct dw_hdmi *hdmi = audio->hdmi;
> +
> +	dw_hdmi_audio_disable(hdmi);
> +
> +	hdmi_write(audio, HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0);
> +}
> +
> +static struct hdmi_codec_ops dw_hdmi_i2s_ops = {
> +	.hw_params	= dw_hdmi_i2s_hw_params,
> +	.audio_shutdown	= dw_hdmi_i2s_audio_shutdown,
> +};
> +
> +static int snd_dw_hdmi_probe(struct platform_device *pdev)
> +{
> +	struct dw_hdmi_i2s_audio_data *audio = pdev->dev.platform_data;
> +	struct platform_device_info pdevinfo;
> +	struct hdmi_codec_pdata pdata;
> +	struct platform_device *platform;
> +
> +
> +	pdata.ops		= &dw_hdmi_i2s_ops;
> +	pdata.i2s		= 1;
> +	pdata.max_i2s_channels	= 6;
> +	pdata.data		= audio;
> +
> +	memset(&pdevinfo, 0, sizeof(pdevinfo));
> +	pdevinfo.parent		= pdev->dev.parent;
> +	pdevinfo.id		= PLATFORM_DEVID_AUTO;
> +	pdevinfo.name		= HDMI_CODEC_DRV_NAME;
> +	pdevinfo.data		= &pdata;
> +	pdevinfo.size_data	= sizeof(pdata);
> +	pdevinfo.dma_mask	= DMA_BIT_MASK(32);
> +
> +	platform = platform_device_register_full(&pdevinfo);
> +	if (IS_ERR_OR_NULL(platform))
> +		return PTR_ERR(platform);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver snd_dw_hdmi_driver = {
> +	.probe	= snd_dw_hdmi_probe,
> +	.driver	= {
> +		.name = DRIVER_NAME,
> +		.owner = THIS_MODULE,
> +	},
> +};
> +module_platform_driver(snd_dw_hdmi_driver);
> +
> +MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
> +MODULE_DESCRIPTION("Synopsis Designware HDMI I2S ALSA SoC interface");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("platform:" DRIVER_NAME);
> diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
> index 55e73e8..e9ba59e 100644
> --- a/drivers/gpu/drm/bridge/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/dw-hdmi.c
> @@ -2013,10 +2013,11 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
>  	struct device_node *np = dev->of_node;
>  	struct platform_device_info pdevinfo;
>  	struct device_node *ddc_node;
> -	struct dw_hdmi_audio_data audio;
>  	struct dw_hdmi *hdmi;
>  	int ret;
>  	u32 val = 1;
> +	u8 config0;
> +	u8 config1;
>  
>  	hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
>  	if (!hdmi)
> @@ -2185,7 +2186,12 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
>  	pdevinfo.parent = dev;
>  	pdevinfo.id = PLATFORM_DEVID_AUTO;
>  
> -	if (hdmi_readb(hdmi, HDMI_CONFIG1_ID) & HDMI_CONFIG1_AHB) {
> +	config0 = hdmi_readb(hdmi, HDMI_CONFIG0_ID);
> +	config1 = hdmi_readb(hdmi, HDMI_CONFIG1_ID);
> +
> +	if (config1 & HDMI_CONFIG1_AHB) {
> +		struct dw_hdmi_audio_data audio;
> +
>  		audio.phys = iores->start;
>  		audio.base = hdmi->regs;
>  		audio.irq = irq;
> @@ -2197,6 +2203,18 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
>  		pdevinfo.size_data = sizeof(audio);
>  		pdevinfo.dma_mask = DMA_BIT_MASK(32);
>  		hdmi->audio = platform_device_register_full(&pdevinfo);
> +	} else if (config0 & HDMI_CONFIG0_I2S) {
> +		struct dw_hdmi_i2s_audio_data audio;
> +
> +		audio.hdmi	= hdmi;
> +		audio.write	= hdmi_writeb;
> +		audio.read	= hdmi_readb;
> +
> +		pdevinfo.name = "dw-hdmi-i2s-audio";
> +		pdevinfo.data = &audio;
> +		pdevinfo.size_data = sizeof(audio);
> +		pdevinfo.dma_mask = DMA_BIT_MASK(32);
> +		hdmi->audio = platform_device_register_full(&pdevinfo);
>  	}
>  
>  	/* Unmute I2CM interrupts and reset HDMI DDC I2C master controller */
> diff --git a/drivers/gpu/drm/bridge/dw-hdmi.h b/drivers/gpu/drm/bridge/dw-hdmi.h
> index fc9a560..c8bdbf2 100644
> --- a/drivers/gpu/drm/bridge/dw-hdmi.h
> +++ b/drivers/gpu/drm/bridge/dw-hdmi.h
> @@ -545,6 +545,10 @@
>  #define HDMI_I2CM_FS_SCL_LCNT_0_ADDR            0x7E12
>  
>  enum {
> +
> +/* CONFIG0_ID field values */
> +	HDMI_CONFIG0_I2S = 0x10,
> +
>  /* CONFIG1_ID field values */
>  	HDMI_CONFIG1_AHB = 0x01,
>  
> @@ -887,6 +891,17 @@ enum {
>  	HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL = 0x08,
>  	HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_MASK = 0x04,
>  
> +/* AUD_CONF0 field values */
> +	HDMI_AUD_CONF0_SW_RESET = 0x80,
> +	HDMI_AUD_CONF0_I2S_ALL_ENABLE = 0x2F,
> +
> +/* AUD_CONF1 field values */
> +	HDMI_AUD_CONF1_MODE_I2S = 0x00,
> +	HDMI_AUD_CONF1_MODE_RIGHT_J = 0x02,
> +	HDMI_AUD_CONF1_MODE_LEFT_J = 0x04,
> +	HDMI_AUD_CONF1_WIDTH_16 = 0x10,
> +	HDMI_AUD_CONF1_WIDTH_24 = 0x18,
> +
>  /* AUD_CTS3 field values */
>  	HDMI_AUD_CTS3_N_SHIFT_OFFSET = 5,
>  	HDMI_AUD_CTS3_N_SHIFT_MASK = 0xe0,
> @@ -901,6 +916,12 @@ enum {
>  	HDMI_AUD_CTS3_CTS_MANUAL = 0x10,
>  	HDMI_AUD_CTS3_AUDCTS19_16_MASK = 0x0f,
>  
> +/* HDMI_AUD_INPUTCLKFS field values */
> +	HDMI_AUD_INPUTCLKFS_128FS = 0,
> +	HDMI_AUD_INPUTCLKFS_256FS = 1,
> +	HDMI_AUD_INPUTCLKFS_512FS = 2,
> +	HDMI_AUD_INPUTCLKFS_64FS = 4,
> +
>  /* AHB_DMA_CONF0 field values */
>  	HDMI_AHB_DMA_CONF0_SW_FIFO_RST_OFFSET = 7,
>  	HDMI_AHB_DMA_CONF0_SW_FIFO_RST_MASK = 0x80,
> -- 
> 1.9.1
> 


Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/2 v2][resend] drm: bridge: add DesignWare HDMI I2S audio support
@ 2016-09-16  8:01     ` Kuninori Morimoto
  0 siblings, 0 replies; 11+ messages in thread
From: Kuninori Morimoto @ 2016-09-16  8:01 UTC (permalink / raw)
  To: Mark Brown
  Cc: Archit Taneja, David Airlie, Russell King, Fabio Estevam,
	Daniel Vetter, Koji Matsuoka, Thierry Reding, Linux-ALSA,
	Liam Girdwood, Simon, linux-renesas-soc, dri-devel, linux-kernel


Hi Mark

Can I have feedback about this patch ?

> From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> 
> Current dw-hdmi is supporting sound via AHB bus, but it has
> I2S audio feature too. This patch adds I2S audio support to dw-hdmi.
> This HDMI I2S is supported by using ALSA SoC common HDMI encoder
> driver.
> 
> Tested-by: Jose Abreu <joabreu@synopsys.com>
> Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> ---
> v1 -> v2
> 
>  - tidyup return value of snd_dw_hdmi_probe()
> 
>  drivers/gpu/drm/bridge/Kconfig             |   8 ++
>  drivers/gpu/drm/bridge/Makefile            |   1 +
>  drivers/gpu/drm/bridge/dw-hdmi-audio.h     |   7 ++
>  drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c | 130 +++++++++++++++++++++++++++++
>  drivers/gpu/drm/bridge/dw-hdmi.c           |  22 ++++-
>  drivers/gpu/drm/bridge/dw-hdmi.h           |  21 +++++
>  6 files changed, 187 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c
> 
> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
> index 8f7423f..8e2a22d 100644
> --- a/drivers/gpu/drm/bridge/Kconfig
> +++ b/drivers/gpu/drm/bridge/Kconfig
> @@ -32,6 +32,14 @@ config DRM_DW_HDMI_AHB_AUDIO
>  	  Designware HDMI block.  This is used in conjunction with
>  	  the i.MX6 HDMI driver.
>  
> +config DRM_DW_HDMI_I2S_AUDIO
> +	tristate "Synopsis Designware I2S Audio interface"
> +	depends on DRM_DW_HDMI
> +	select SND_SOC_HDMI_CODEC
> +	help
> +	  Support the I2S Audio 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 96b13b3..1af92ad 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_I2S_AUDIO) += dw-hdmi-i2s-audio.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-audio.h b/drivers/gpu/drm/bridge/dw-hdmi-audio.h
> index 91f631b..fd1f745 100644
> --- a/drivers/gpu/drm/bridge/dw-hdmi-audio.h
> +++ b/drivers/gpu/drm/bridge/dw-hdmi-audio.h
> @@ -11,4 +11,11 @@ struct dw_hdmi_audio_data {
>  	u8 *eld;
>  };
>  
> +struct dw_hdmi_i2s_audio_data {
> +	struct dw_hdmi *hdmi;
> +
> +	void (*write)(struct dw_hdmi *hdmi, u8 val, int offset);
> +	u8 (*read)(struct dw_hdmi *hdmi, int offset);
> +};
> +
>  #endif
> diff --git a/drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c
> new file mode 100644
> index 0000000..7dd2091
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c
> @@ -0,0 +1,130 @@
> +/*
> + * dw-hdmi-i2s-audio.c
> + *
> + * Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +#include <drm/bridge/dw_hdmi.h>
> +
> +#include <sound/hdmi-codec.h>
> +
> +#include "dw-hdmi.h"
> +#include "dw-hdmi-audio.h"
> +
> +#define DRIVER_NAME "dw-hdmi-i2s-audio"
> +
> +static inline void hdmi_write(struct dw_hdmi_i2s_audio_data *audio,
> +			      u8 val, int offset)
> +{
> +	struct dw_hdmi *hdmi = audio->hdmi;
> +
> +	audio->write(hdmi, val, offset);
> +}
> +
> +static inline u8 hdmi_read(struct dw_hdmi_i2s_audio_data *audio, int offset)
> +{
> +	struct dw_hdmi *hdmi = audio->hdmi;
> +
> +	return audio->read(hdmi, offset);
> +}
> +
> +static int dw_hdmi_i2s_hw_params(struct device *dev, void *data,
> +				 struct hdmi_codec_daifmt *fmt,
> +				 struct hdmi_codec_params *hparms)
> +{
> +	struct dw_hdmi_i2s_audio_data *audio = data;
> +	struct dw_hdmi *hdmi = audio->hdmi;
> +	u8 conf0 = 0;
> +	u8 conf1 = 0;
> +	u8 inputclkfs = 0;
> +
> +	/* it cares I2S only */
> +	if ((fmt->fmt != HDMI_I2S) ||
> +	    (fmt->bit_clk_master | fmt->frame_clk_master)) {
> +		dev_err(dev, "unsupported format/settings\n");
> +		return -EINVAL;
> +	}
> +
> +	inputclkfs	= HDMI_AUD_INPUTCLKFS_64FS;
> +	conf0		= HDMI_AUD_CONF0_I2S_ALL_ENABLE;
> +
> +	switch (hparms->sample_width) {
> +	case 16:
> +		conf1 = HDMI_AUD_CONF1_WIDTH_16;
> +		break;
> +	case 24:
> +	case 32:
> +		conf1 = HDMI_AUD_CONF1_WIDTH_24;
> +		break;
> +	}
> +
> +	dw_hdmi_set_sample_rate(hdmi, hparms->sample_rate);
> +
> +	hdmi_write(audio, inputclkfs, HDMI_AUD_INPUTCLKFS);
> +	hdmi_write(audio, conf0, HDMI_AUD_CONF0);
> +	hdmi_write(audio, conf1, HDMI_AUD_CONF1);
> +
> +	dw_hdmi_audio_enable(hdmi);
> +
> +	return 0;
> +}
> +
> +static void dw_hdmi_i2s_audio_shutdown(struct device *dev, void *data)
> +{
> +	struct dw_hdmi_i2s_audio_data *audio = data;
> +	struct dw_hdmi *hdmi = audio->hdmi;
> +
> +	dw_hdmi_audio_disable(hdmi);
> +
> +	hdmi_write(audio, HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0);
> +}
> +
> +static struct hdmi_codec_ops dw_hdmi_i2s_ops = {
> +	.hw_params	= dw_hdmi_i2s_hw_params,
> +	.audio_shutdown	= dw_hdmi_i2s_audio_shutdown,
> +};
> +
> +static int snd_dw_hdmi_probe(struct platform_device *pdev)
> +{
> +	struct dw_hdmi_i2s_audio_data *audio = pdev->dev.platform_data;
> +	struct platform_device_info pdevinfo;
> +	struct hdmi_codec_pdata pdata;
> +	struct platform_device *platform;
> +
> +
> +	pdata.ops		= &dw_hdmi_i2s_ops;
> +	pdata.i2s		= 1;
> +	pdata.max_i2s_channels	= 6;
> +	pdata.data		= audio;
> +
> +	memset(&pdevinfo, 0, sizeof(pdevinfo));
> +	pdevinfo.parent		= pdev->dev.parent;
> +	pdevinfo.id		= PLATFORM_DEVID_AUTO;
> +	pdevinfo.name		= HDMI_CODEC_DRV_NAME;
> +	pdevinfo.data		= &pdata;
> +	pdevinfo.size_data	= sizeof(pdata);
> +	pdevinfo.dma_mask	= DMA_BIT_MASK(32);
> +
> +	platform = platform_device_register_full(&pdevinfo);
> +	if (IS_ERR_OR_NULL(platform))
> +		return PTR_ERR(platform);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver snd_dw_hdmi_driver = {
> +	.probe	= snd_dw_hdmi_probe,
> +	.driver	= {
> +		.name = DRIVER_NAME,
> +		.owner = THIS_MODULE,
> +	},
> +};
> +module_platform_driver(snd_dw_hdmi_driver);
> +
> +MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
> +MODULE_DESCRIPTION("Synopsis Designware HDMI I2S ALSA SoC interface");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("platform:" DRIVER_NAME);
> diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
> index 55e73e8..e9ba59e 100644
> --- a/drivers/gpu/drm/bridge/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/dw-hdmi.c
> @@ -2013,10 +2013,11 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
>  	struct device_node *np = dev->of_node;
>  	struct platform_device_info pdevinfo;
>  	struct device_node *ddc_node;
> -	struct dw_hdmi_audio_data audio;
>  	struct dw_hdmi *hdmi;
>  	int ret;
>  	u32 val = 1;
> +	u8 config0;
> +	u8 config1;
>  
>  	hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
>  	if (!hdmi)
> @@ -2185,7 +2186,12 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
>  	pdevinfo.parent = dev;
>  	pdevinfo.id = PLATFORM_DEVID_AUTO;
>  
> -	if (hdmi_readb(hdmi, HDMI_CONFIG1_ID) & HDMI_CONFIG1_AHB) {
> +	config0 = hdmi_readb(hdmi, HDMI_CONFIG0_ID);
> +	config1 = hdmi_readb(hdmi, HDMI_CONFIG1_ID);
> +
> +	if (config1 & HDMI_CONFIG1_AHB) {
> +		struct dw_hdmi_audio_data audio;
> +
>  		audio.phys = iores->start;
>  		audio.base = hdmi->regs;
>  		audio.irq = irq;
> @@ -2197,6 +2203,18 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
>  		pdevinfo.size_data = sizeof(audio);
>  		pdevinfo.dma_mask = DMA_BIT_MASK(32);
>  		hdmi->audio = platform_device_register_full(&pdevinfo);
> +	} else if (config0 & HDMI_CONFIG0_I2S) {
> +		struct dw_hdmi_i2s_audio_data audio;
> +
> +		audio.hdmi	= hdmi;
> +		audio.write	= hdmi_writeb;
> +		audio.read	= hdmi_readb;
> +
> +		pdevinfo.name = "dw-hdmi-i2s-audio";
> +		pdevinfo.data = &audio;
> +		pdevinfo.size_data = sizeof(audio);
> +		pdevinfo.dma_mask = DMA_BIT_MASK(32);
> +		hdmi->audio = platform_device_register_full(&pdevinfo);
>  	}
>  
>  	/* Unmute I2CM interrupts and reset HDMI DDC I2C master controller */
> diff --git a/drivers/gpu/drm/bridge/dw-hdmi.h b/drivers/gpu/drm/bridge/dw-hdmi.h
> index fc9a560..c8bdbf2 100644
> --- a/drivers/gpu/drm/bridge/dw-hdmi.h
> +++ b/drivers/gpu/drm/bridge/dw-hdmi.h
> @@ -545,6 +545,10 @@
>  #define HDMI_I2CM_FS_SCL_LCNT_0_ADDR            0x7E12
>  
>  enum {
> +
> +/* CONFIG0_ID field values */
> +	HDMI_CONFIG0_I2S = 0x10,
> +
>  /* CONFIG1_ID field values */
>  	HDMI_CONFIG1_AHB = 0x01,
>  
> @@ -887,6 +891,17 @@ enum {
>  	HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL = 0x08,
>  	HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_MASK = 0x04,
>  
> +/* AUD_CONF0 field values */
> +	HDMI_AUD_CONF0_SW_RESET = 0x80,
> +	HDMI_AUD_CONF0_I2S_ALL_ENABLE = 0x2F,
> +
> +/* AUD_CONF1 field values */
> +	HDMI_AUD_CONF1_MODE_I2S = 0x00,
> +	HDMI_AUD_CONF1_MODE_RIGHT_J = 0x02,
> +	HDMI_AUD_CONF1_MODE_LEFT_J = 0x04,
> +	HDMI_AUD_CONF1_WIDTH_16 = 0x10,
> +	HDMI_AUD_CONF1_WIDTH_24 = 0x18,
> +
>  /* AUD_CTS3 field values */
>  	HDMI_AUD_CTS3_N_SHIFT_OFFSET = 5,
>  	HDMI_AUD_CTS3_N_SHIFT_MASK = 0xe0,
> @@ -901,6 +916,12 @@ enum {
>  	HDMI_AUD_CTS3_CTS_MANUAL = 0x10,
>  	HDMI_AUD_CTS3_AUDCTS19_16_MASK = 0x0f,
>  
> +/* HDMI_AUD_INPUTCLKFS field values */
> +	HDMI_AUD_INPUTCLKFS_128FS = 0,
> +	HDMI_AUD_INPUTCLKFS_256FS = 1,
> +	HDMI_AUD_INPUTCLKFS_512FS = 2,
> +	HDMI_AUD_INPUTCLKFS_64FS = 4,
> +
>  /* AHB_DMA_CONF0 field values */
>  	HDMI_AHB_DMA_CONF0_SW_FIFO_RST_OFFSET = 7,
>  	HDMI_AHB_DMA_CONF0_SW_FIFO_RST_MASK = 0x80,
> -- 
> 1.9.1
> 


Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/2 v2][resend] drm: bridge: add DesignWare HDMI I2S audio support
  2016-09-16  8:01     ` Kuninori Morimoto
  (?)
@ 2016-09-16 10:30     ` Mark Brown
  -1 siblings, 0 replies; 11+ messages in thread
From: Mark Brown @ 2016-09-16 10:30 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: Archit Taneja, David Airlie, Russell King, Fabio Estevam,
	Daniel Vetter, Koji Matsuoka, Thierry Reding, Linux-ALSA,
	Liam Girdwood, Simon, linux-renesas-soc, dri-devel, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 916 bytes --]

On Fri, Sep 16, 2016 at 08:01:01AM +0000, Kuninori Morimoto wrote:
> 
> Hi Mark
> 
> Can I have feedback about this patch ?

These are DRM patches, I'd expect them to go via the DRM subsystem.

Please don't send content free pings and please allow a reasonable time
for review.  People get busy, go on holiday, attend conferences and so 
on so unless there is some reason for urgency (like critical bug fixes)
please allow at least a couple of weeks for review.  If there have been
review comments then people may be waiting for those to be addressed.

Sending content free pings adds to the mail volume (if they are seen at
all) which is often the problem and since they can't be reviewed
directly if something has gone wrong you'll have to resend the patches
anyway, though there are some other maintainers who like them - if in
doubt look at how patches for the subsystem are normally handled.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v2][resend v2] drm: bridge: add DesignWare HDMI I2S audio support
  2016-08-03  2:07 ` Kuninori Morimoto
@ 2016-10-17  7:56   ` Kuninori Morimoto
  -1 siblings, 0 replies; 11+ messages in thread
From: Kuninori Morimoto @ 2016-10-17  7:56 UTC (permalink / raw)
  To: Archit Taneja, Mark Brown
  Cc: David Airlie, Russell King, Fabio Estevam, Daniel Vetter,
	Koji Matsuoka, Thierry Reding, Linux-ALSA, Liam Girdwood, Simon,
	linux-renesas-soc, dri-devel, linux-kernel


From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>

Current dw-hdmi is supporting sound via AHB bus, but it has
I2S audio feature too. This patch adds I2S audio support to dw-hdmi.
This HDMI I2S is supported by using ALSA SoC common HDMI encoder
driver.

Tested-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
v1 -> v2

 - tidyup return value of snd_dw_hdmi_probe()

 drivers/gpu/drm/bridge/Kconfig             |   8 ++
 drivers/gpu/drm/bridge/Makefile            |   1 +
 drivers/gpu/drm/bridge/dw-hdmi-audio.h     |   7 ++
 drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c | 130 +++++++++++++++++++++++++++++
 drivers/gpu/drm/bridge/dw-hdmi.c           |  22 ++++-
 drivers/gpu/drm/bridge/dw-hdmi.h           |  21 +++++
 6 files changed, 187 insertions(+), 2 deletions(-)
 create mode 100644 drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 8f7423f..8e2a22d 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -32,6 +32,14 @@ config DRM_DW_HDMI_AHB_AUDIO
 	  Designware HDMI block.  This is used in conjunction with
 	  the i.MX6 HDMI driver.
 
+config DRM_DW_HDMI_I2S_AUDIO
+	tristate "Synopsis Designware I2S Audio interface"
+	depends on DRM_DW_HDMI
+	select SND_SOC_HDMI_CODEC
+	help
+	  Support the I2S Audio 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 96b13b3..1af92ad 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_I2S_AUDIO) += dw-hdmi-i2s-audio.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-audio.h b/drivers/gpu/drm/bridge/dw-hdmi-audio.h
index 91f631b..fd1f745 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi-audio.h
+++ b/drivers/gpu/drm/bridge/dw-hdmi-audio.h
@@ -11,4 +11,11 @@ struct dw_hdmi_audio_data {
 	u8 *eld;
 };
 
+struct dw_hdmi_i2s_audio_data {
+	struct dw_hdmi *hdmi;
+
+	void (*write)(struct dw_hdmi *hdmi, u8 val, int offset);
+	u8 (*read)(struct dw_hdmi *hdmi, int offset);
+};
+
 #endif
diff --git a/drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c
new file mode 100644
index 0000000..7dd2091
--- /dev/null
+++ b/drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c
@@ -0,0 +1,130 @@
+/*
+ * dw-hdmi-i2s-audio.c
+ *
+ * Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <drm/bridge/dw_hdmi.h>
+
+#include <sound/hdmi-codec.h>
+
+#include "dw-hdmi.h"
+#include "dw-hdmi-audio.h"
+
+#define DRIVER_NAME "dw-hdmi-i2s-audio"
+
+static inline void hdmi_write(struct dw_hdmi_i2s_audio_data *audio,
+			      u8 val, int offset)
+{
+	struct dw_hdmi *hdmi = audio->hdmi;
+
+	audio->write(hdmi, val, offset);
+}
+
+static inline u8 hdmi_read(struct dw_hdmi_i2s_audio_data *audio, int offset)
+{
+	struct dw_hdmi *hdmi = audio->hdmi;
+
+	return audio->read(hdmi, offset);
+}
+
+static int dw_hdmi_i2s_hw_params(struct device *dev, void *data,
+				 struct hdmi_codec_daifmt *fmt,
+				 struct hdmi_codec_params *hparms)
+{
+	struct dw_hdmi_i2s_audio_data *audio = data;
+	struct dw_hdmi *hdmi = audio->hdmi;
+	u8 conf0 = 0;
+	u8 conf1 = 0;
+	u8 inputclkfs = 0;
+
+	/* it cares I2S only */
+	if ((fmt->fmt != HDMI_I2S) ||
+	    (fmt->bit_clk_master | fmt->frame_clk_master)) {
+		dev_err(dev, "unsupported format/settings\n");
+		return -EINVAL;
+	}
+
+	inputclkfs	= HDMI_AUD_INPUTCLKFS_64FS;
+	conf0		= HDMI_AUD_CONF0_I2S_ALL_ENABLE;
+
+	switch (hparms->sample_width) {
+	case 16:
+		conf1 = HDMI_AUD_CONF1_WIDTH_16;
+		break;
+	case 24:
+	case 32:
+		conf1 = HDMI_AUD_CONF1_WIDTH_24;
+		break;
+	}
+
+	dw_hdmi_set_sample_rate(hdmi, hparms->sample_rate);
+
+	hdmi_write(audio, inputclkfs, HDMI_AUD_INPUTCLKFS);
+	hdmi_write(audio, conf0, HDMI_AUD_CONF0);
+	hdmi_write(audio, conf1, HDMI_AUD_CONF1);
+
+	dw_hdmi_audio_enable(hdmi);
+
+	return 0;
+}
+
+static void dw_hdmi_i2s_audio_shutdown(struct device *dev, void *data)
+{
+	struct dw_hdmi_i2s_audio_data *audio = data;
+	struct dw_hdmi *hdmi = audio->hdmi;
+
+	dw_hdmi_audio_disable(hdmi);
+
+	hdmi_write(audio, HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0);
+}
+
+static struct hdmi_codec_ops dw_hdmi_i2s_ops = {
+	.hw_params	= dw_hdmi_i2s_hw_params,
+	.audio_shutdown	= dw_hdmi_i2s_audio_shutdown,
+};
+
+static int snd_dw_hdmi_probe(struct platform_device *pdev)
+{
+	struct dw_hdmi_i2s_audio_data *audio = pdev->dev.platform_data;
+	struct platform_device_info pdevinfo;
+	struct hdmi_codec_pdata pdata;
+	struct platform_device *platform;
+
+
+	pdata.ops		= &dw_hdmi_i2s_ops;
+	pdata.i2s		= 1;
+	pdata.max_i2s_channels	= 6;
+	pdata.data		= audio;
+
+	memset(&pdevinfo, 0, sizeof(pdevinfo));
+	pdevinfo.parent		= pdev->dev.parent;
+	pdevinfo.id		= PLATFORM_DEVID_AUTO;
+	pdevinfo.name		= HDMI_CODEC_DRV_NAME;
+	pdevinfo.data		= &pdata;
+	pdevinfo.size_data	= sizeof(pdata);
+	pdevinfo.dma_mask	= DMA_BIT_MASK(32);
+
+	platform = platform_device_register_full(&pdevinfo);
+	if (IS_ERR_OR_NULL(platform))
+		return PTR_ERR(platform);
+
+	return 0;
+}
+
+static struct platform_driver snd_dw_hdmi_driver = {
+	.probe	= snd_dw_hdmi_probe,
+	.driver	= {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+module_platform_driver(snd_dw_hdmi_driver);
+
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
+MODULE_DESCRIPTION("Synopsis Designware HDMI I2S ALSA SoC interface");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 55e73e8..e9ba59e 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -2013,10 +2013,11 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
 	struct device_node *np = dev->of_node;
 	struct platform_device_info pdevinfo;
 	struct device_node *ddc_node;
-	struct dw_hdmi_audio_data audio;
 	struct dw_hdmi *hdmi;
 	int ret;
 	u32 val = 1;
+	u8 config0;
+	u8 config1;
 
 	hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
 	if (!hdmi)
@@ -2185,7 +2186,12 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
 	pdevinfo.parent = dev;
 	pdevinfo.id = PLATFORM_DEVID_AUTO;
 
-	if (hdmi_readb(hdmi, HDMI_CONFIG1_ID) & HDMI_CONFIG1_AHB) {
+	config0 = hdmi_readb(hdmi, HDMI_CONFIG0_ID);
+	config1 = hdmi_readb(hdmi, HDMI_CONFIG1_ID);
+
+	if (config1 & HDMI_CONFIG1_AHB) {
+		struct dw_hdmi_audio_data audio;
+
 		audio.phys = iores->start;
 		audio.base = hdmi->regs;
 		audio.irq = irq;
@@ -2197,6 +2203,18 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
 		pdevinfo.size_data = sizeof(audio);
 		pdevinfo.dma_mask = DMA_BIT_MASK(32);
 		hdmi->audio = platform_device_register_full(&pdevinfo);
+	} else if (config0 & HDMI_CONFIG0_I2S) {
+		struct dw_hdmi_i2s_audio_data audio;
+
+		audio.hdmi	= hdmi;
+		audio.write	= hdmi_writeb;
+		audio.read	= hdmi_readb;
+
+		pdevinfo.name = "dw-hdmi-i2s-audio";
+		pdevinfo.data = &audio;
+		pdevinfo.size_data = sizeof(audio);
+		pdevinfo.dma_mask = DMA_BIT_MASK(32);
+		hdmi->audio = platform_device_register_full(&pdevinfo);
 	}
 
 	/* Unmute I2CM interrupts and reset HDMI DDC I2C master controller */
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.h b/drivers/gpu/drm/bridge/dw-hdmi.h
index fc9a560..c8bdbf2 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.h
+++ b/drivers/gpu/drm/bridge/dw-hdmi.h
@@ -545,6 +545,10 @@
 #define HDMI_I2CM_FS_SCL_LCNT_0_ADDR            0x7E12
 
 enum {
+
+/* CONFIG0_ID field values */
+	HDMI_CONFIG0_I2S = 0x10,
+
 /* CONFIG1_ID field values */
 	HDMI_CONFIG1_AHB = 0x01,
 
@@ -887,6 +891,17 @@ enum {
 	HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL = 0x08,
 	HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_MASK = 0x04,
 
+/* AUD_CONF0 field values */
+	HDMI_AUD_CONF0_SW_RESET = 0x80,
+	HDMI_AUD_CONF0_I2S_ALL_ENABLE = 0x2F,
+
+/* AUD_CONF1 field values */
+	HDMI_AUD_CONF1_MODE_I2S = 0x00,
+	HDMI_AUD_CONF1_MODE_RIGHT_J = 0x02,
+	HDMI_AUD_CONF1_MODE_LEFT_J = 0x04,
+	HDMI_AUD_CONF1_WIDTH_16 = 0x10,
+	HDMI_AUD_CONF1_WIDTH_24 = 0x18,
+
 /* AUD_CTS3 field values */
 	HDMI_AUD_CTS3_N_SHIFT_OFFSET = 5,
 	HDMI_AUD_CTS3_N_SHIFT_MASK = 0xe0,
@@ -901,6 +916,12 @@ enum {
 	HDMI_AUD_CTS3_CTS_MANUAL = 0x10,
 	HDMI_AUD_CTS3_AUDCTS19_16_MASK = 0x0f,
 
+/* HDMI_AUD_INPUTCLKFS field values */
+	HDMI_AUD_INPUTCLKFS_128FS = 0,
+	HDMI_AUD_INPUTCLKFS_256FS = 1,
+	HDMI_AUD_INPUTCLKFS_512FS = 2,
+	HDMI_AUD_INPUTCLKFS_64FS = 4,
+
 /* AHB_DMA_CONF0 field values */
 	HDMI_AHB_DMA_CONF0_SW_FIFO_RST_OFFSET = 7,
 	HDMI_AHB_DMA_CONF0_SW_FIFO_RST_MASK = 0x80,
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2][resend v2] drm: bridge: add DesignWare HDMI I2S audio support
@ 2016-10-17  7:56   ` Kuninori Morimoto
  0 siblings, 0 replies; 11+ messages in thread
From: Kuninori Morimoto @ 2016-10-17  7:56 UTC (permalink / raw)
  To: Archit Taneja, Mark Brown
  Cc: David Airlie, Russell King, Fabio Estevam, Daniel Vetter,
	Koji Matsuoka, Thierry Reding, Linux-ALSA, Liam Girdwood, Simon,
	linux-renesas-soc, dri-devel, linux-kernel


From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>

Current dw-hdmi is supporting sound via AHB bus, but it has
I2S audio feature too. This patch adds I2S audio support to dw-hdmi.
This HDMI I2S is supported by using ALSA SoC common HDMI encoder
driver.

Tested-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
v1 -> v2

 - tidyup return value of snd_dw_hdmi_probe()

 drivers/gpu/drm/bridge/Kconfig             |   8 ++
 drivers/gpu/drm/bridge/Makefile            |   1 +
 drivers/gpu/drm/bridge/dw-hdmi-audio.h     |   7 ++
 drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c | 130 +++++++++++++++++++++++++++++
 drivers/gpu/drm/bridge/dw-hdmi.c           |  22 ++++-
 drivers/gpu/drm/bridge/dw-hdmi.h           |  21 +++++
 6 files changed, 187 insertions(+), 2 deletions(-)
 create mode 100644 drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 8f7423f..8e2a22d 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -32,6 +32,14 @@ config DRM_DW_HDMI_AHB_AUDIO
 	  Designware HDMI block.  This is used in conjunction with
 	  the i.MX6 HDMI driver.
 
+config DRM_DW_HDMI_I2S_AUDIO
+	tristate "Synopsis Designware I2S Audio interface"
+	depends on DRM_DW_HDMI
+	select SND_SOC_HDMI_CODEC
+	help
+	  Support the I2S Audio 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 96b13b3..1af92ad 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_I2S_AUDIO) += dw-hdmi-i2s-audio.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-audio.h b/drivers/gpu/drm/bridge/dw-hdmi-audio.h
index 91f631b..fd1f745 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi-audio.h
+++ b/drivers/gpu/drm/bridge/dw-hdmi-audio.h
@@ -11,4 +11,11 @@ struct dw_hdmi_audio_data {
 	u8 *eld;
 };
 
+struct dw_hdmi_i2s_audio_data {
+	struct dw_hdmi *hdmi;
+
+	void (*write)(struct dw_hdmi *hdmi, u8 val, int offset);
+	u8 (*read)(struct dw_hdmi *hdmi, int offset);
+};
+
 #endif
diff --git a/drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c
new file mode 100644
index 0000000..7dd2091
--- /dev/null
+++ b/drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c
@@ -0,0 +1,130 @@
+/*
+ * dw-hdmi-i2s-audio.c
+ *
+ * Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <drm/bridge/dw_hdmi.h>
+
+#include <sound/hdmi-codec.h>
+
+#include "dw-hdmi.h"
+#include "dw-hdmi-audio.h"
+
+#define DRIVER_NAME "dw-hdmi-i2s-audio"
+
+static inline void hdmi_write(struct dw_hdmi_i2s_audio_data *audio,
+			      u8 val, int offset)
+{
+	struct dw_hdmi *hdmi = audio->hdmi;
+
+	audio->write(hdmi, val, offset);
+}
+
+static inline u8 hdmi_read(struct dw_hdmi_i2s_audio_data *audio, int offset)
+{
+	struct dw_hdmi *hdmi = audio->hdmi;
+
+	return audio->read(hdmi, offset);
+}
+
+static int dw_hdmi_i2s_hw_params(struct device *dev, void *data,
+				 struct hdmi_codec_daifmt *fmt,
+				 struct hdmi_codec_params *hparms)
+{
+	struct dw_hdmi_i2s_audio_data *audio = data;
+	struct dw_hdmi *hdmi = audio->hdmi;
+	u8 conf0 = 0;
+	u8 conf1 = 0;
+	u8 inputclkfs = 0;
+
+	/* it cares I2S only */
+	if ((fmt->fmt != HDMI_I2S) ||
+	    (fmt->bit_clk_master | fmt->frame_clk_master)) {
+		dev_err(dev, "unsupported format/settings\n");
+		return -EINVAL;
+	}
+
+	inputclkfs	= HDMI_AUD_INPUTCLKFS_64FS;
+	conf0		= HDMI_AUD_CONF0_I2S_ALL_ENABLE;
+
+	switch (hparms->sample_width) {
+	case 16:
+		conf1 = HDMI_AUD_CONF1_WIDTH_16;
+		break;
+	case 24:
+	case 32:
+		conf1 = HDMI_AUD_CONF1_WIDTH_24;
+		break;
+	}
+
+	dw_hdmi_set_sample_rate(hdmi, hparms->sample_rate);
+
+	hdmi_write(audio, inputclkfs, HDMI_AUD_INPUTCLKFS);
+	hdmi_write(audio, conf0, HDMI_AUD_CONF0);
+	hdmi_write(audio, conf1, HDMI_AUD_CONF1);
+
+	dw_hdmi_audio_enable(hdmi);
+
+	return 0;
+}
+
+static void dw_hdmi_i2s_audio_shutdown(struct device *dev, void *data)
+{
+	struct dw_hdmi_i2s_audio_data *audio = data;
+	struct dw_hdmi *hdmi = audio->hdmi;
+
+	dw_hdmi_audio_disable(hdmi);
+
+	hdmi_write(audio, HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0);
+}
+
+static struct hdmi_codec_ops dw_hdmi_i2s_ops = {
+	.hw_params	= dw_hdmi_i2s_hw_params,
+	.audio_shutdown	= dw_hdmi_i2s_audio_shutdown,
+};
+
+static int snd_dw_hdmi_probe(struct platform_device *pdev)
+{
+	struct dw_hdmi_i2s_audio_data *audio = pdev->dev.platform_data;
+	struct platform_device_info pdevinfo;
+	struct hdmi_codec_pdata pdata;
+	struct platform_device *platform;
+
+
+	pdata.ops		= &dw_hdmi_i2s_ops;
+	pdata.i2s		= 1;
+	pdata.max_i2s_channels	= 6;
+	pdata.data		= audio;
+
+	memset(&pdevinfo, 0, sizeof(pdevinfo));
+	pdevinfo.parent		= pdev->dev.parent;
+	pdevinfo.id		= PLATFORM_DEVID_AUTO;
+	pdevinfo.name		= HDMI_CODEC_DRV_NAME;
+	pdevinfo.data		= &pdata;
+	pdevinfo.size_data	= sizeof(pdata);
+	pdevinfo.dma_mask	= DMA_BIT_MASK(32);
+
+	platform = platform_device_register_full(&pdevinfo);
+	if (IS_ERR_OR_NULL(platform))
+		return PTR_ERR(platform);
+
+	return 0;
+}
+
+static struct platform_driver snd_dw_hdmi_driver = {
+	.probe	= snd_dw_hdmi_probe,
+	.driver	= {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+module_platform_driver(snd_dw_hdmi_driver);
+
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
+MODULE_DESCRIPTION("Synopsis Designware HDMI I2S ALSA SoC interface");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 55e73e8..e9ba59e 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -2013,10 +2013,11 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
 	struct device_node *np = dev->of_node;
 	struct platform_device_info pdevinfo;
 	struct device_node *ddc_node;
-	struct dw_hdmi_audio_data audio;
 	struct dw_hdmi *hdmi;
 	int ret;
 	u32 val = 1;
+	u8 config0;
+	u8 config1;
 
 	hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
 	if (!hdmi)
@@ -2185,7 +2186,12 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
 	pdevinfo.parent = dev;
 	pdevinfo.id = PLATFORM_DEVID_AUTO;
 
-	if (hdmi_readb(hdmi, HDMI_CONFIG1_ID) & HDMI_CONFIG1_AHB) {
+	config0 = hdmi_readb(hdmi, HDMI_CONFIG0_ID);
+	config1 = hdmi_readb(hdmi, HDMI_CONFIG1_ID);
+
+	if (config1 & HDMI_CONFIG1_AHB) {
+		struct dw_hdmi_audio_data audio;
+
 		audio.phys = iores->start;
 		audio.base = hdmi->regs;
 		audio.irq = irq;
@@ -2197,6 +2203,18 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
 		pdevinfo.size_data = sizeof(audio);
 		pdevinfo.dma_mask = DMA_BIT_MASK(32);
 		hdmi->audio = platform_device_register_full(&pdevinfo);
+	} else if (config0 & HDMI_CONFIG0_I2S) {
+		struct dw_hdmi_i2s_audio_data audio;
+
+		audio.hdmi	= hdmi;
+		audio.write	= hdmi_writeb;
+		audio.read	= hdmi_readb;
+
+		pdevinfo.name = "dw-hdmi-i2s-audio";
+		pdevinfo.data = &audio;
+		pdevinfo.size_data = sizeof(audio);
+		pdevinfo.dma_mask = DMA_BIT_MASK(32);
+		hdmi->audio = platform_device_register_full(&pdevinfo);
 	}
 
 	/* Unmute I2CM interrupts and reset HDMI DDC I2C master controller */
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.h b/drivers/gpu/drm/bridge/dw-hdmi.h
index fc9a560..c8bdbf2 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.h
+++ b/drivers/gpu/drm/bridge/dw-hdmi.h
@@ -545,6 +545,10 @@
 #define HDMI_I2CM_FS_SCL_LCNT_0_ADDR            0x7E12
 
 enum {
+
+/* CONFIG0_ID field values */
+	HDMI_CONFIG0_I2S = 0x10,
+
 /* CONFIG1_ID field values */
 	HDMI_CONFIG1_AHB = 0x01,
 
@@ -887,6 +891,17 @@ enum {
 	HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL = 0x08,
 	HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_MASK = 0x04,
 
+/* AUD_CONF0 field values */
+	HDMI_AUD_CONF0_SW_RESET = 0x80,
+	HDMI_AUD_CONF0_I2S_ALL_ENABLE = 0x2F,
+
+/* AUD_CONF1 field values */
+	HDMI_AUD_CONF1_MODE_I2S = 0x00,
+	HDMI_AUD_CONF1_MODE_RIGHT_J = 0x02,
+	HDMI_AUD_CONF1_MODE_LEFT_J = 0x04,
+	HDMI_AUD_CONF1_WIDTH_16 = 0x10,
+	HDMI_AUD_CONF1_WIDTH_24 = 0x18,
+
 /* AUD_CTS3 field values */
 	HDMI_AUD_CTS3_N_SHIFT_OFFSET = 5,
 	HDMI_AUD_CTS3_N_SHIFT_MASK = 0xe0,
@@ -901,6 +916,12 @@ enum {
 	HDMI_AUD_CTS3_CTS_MANUAL = 0x10,
 	HDMI_AUD_CTS3_AUDCTS19_16_MASK = 0x0f,
 
+/* HDMI_AUD_INPUTCLKFS field values */
+	HDMI_AUD_INPUTCLKFS_128FS = 0,
+	HDMI_AUD_INPUTCLKFS_256FS = 1,
+	HDMI_AUD_INPUTCLKFS_512FS = 2,
+	HDMI_AUD_INPUTCLKFS_64FS = 4,
+
 /* AHB_DMA_CONF0 field values */
 	HDMI_AHB_DMA_CONF0_SW_FIFO_RST_OFFSET = 7,
 	HDMI_AHB_DMA_CONF0_SW_FIFO_RST_MASK = 0x80,
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2016-10-17  8:06 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-08-03  2:07 [PATCH 0/2 v2][resend] DesignWare HDMI I2S suport Kuninori Morimoto
2016-08-03  2:07 ` Kuninori Morimoto
2016-08-03  2:08 ` [PATCH 1/2 v2][resend] ASoC: hdmi-codec: enable multi probe for same device Kuninori Morimoto
2016-08-03  2:08   ` Kuninori Morimoto
2016-08-03  2:09 ` [PATCH 2/2 v2][resend] drm: bridge: add DesignWare HDMI I2S audio support Kuninori Morimoto
2016-08-03  2:09   ` Kuninori Morimoto
2016-09-16  8:01   ` Kuninori Morimoto
2016-09-16  8:01     ` Kuninori Morimoto
2016-09-16 10:30     ` Mark Brown
2016-10-17  7:56 ` [PATCH v2][resend v2] " Kuninori Morimoto
2016-10-17  7:56   ` Kuninori Morimoto

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.