dri-devel.lists.freedesktop.org archive mirror
 help / color / mirror / Atom feed
* [RFC 0/5] another generic audio hdmi codec proposal
@ 2015-09-21 13:19 Arnaud Pouliquen
  2015-09-21 13:19 ` [RFC 1/5] video: hdmi: add help function for N and CTS Arnaud Pouliquen
                   ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: Arnaud Pouliquen @ 2015-09-21 13:19 UTC (permalink / raw)
  To: alsa-devel, dri-devel
  Cc: moinejf, linux, Takashi Iwai, tomi.valkeinen, arnaud.pouliquen,
	lgirdwood, Jyri Sarha, peter.ujfalusi, airlied, tony, broonie,
	bcousson

I 'm working on HDMI implementation for sti platform. 
As some discussions are on going for audio on HDMI. Here is the begin of my work...

This patch set is a tentative to implement a generic code for the HDMI audio.
Main concept are aligned with solution proposeded for TI platform. 
 -  ASoC codec driver registered by DRM driver
 -  ASOC driver is a generic driver.
 -  compatible with simple card
 
 Difference is that i propose a DRM generic interface based on bridge structure.
 Advantage is that all data exchanges are done through the DRM API.
 
 I think also that some helper functions could been used for N and CTS parameters calculation,
 as suggested by Russell King in a previous mail.
 
 I full aware that some features (like ELD and info frame) are partially or not implemented in my patches. 
 This patch set is more a skeleton than a full implementation...
 I just post it to suggest a possible DRM API.

Arnaud Pouliquen (5):
  video: hdmi: add help function for N and cts
  drm: add helper functionto add audio capabilities for bridge
  ASoC: codec:  hdmi drm codec driver
  drm: sti: connect audio driver
  DT: sti: add audio HDMI dai link in audio card

 arch/arm/boot/dts/stih410.dtsi       |   4 +-
 arch/arm/boot/dts/stihxxx-b2120.dtsi |  21 +++++
 arch/arm/configs/multi_v7_defconfig  |   1 +
 drivers/gpu/drm/drm_bridge.c         | 114 +++++++++++++++++++++++++++
 drivers/gpu/drm/sti/sti_hdmi.c       | 146 +++++++++++++++++++++++++++++++---
 drivers/gpu/drm/sti/sti_hdmi.h       |   3 +
 drivers/video/hdmi.c                 | 148 +++++++++++++++++++++++++++++++++++
 include/drm/drm_crtc.h               |  31 ++++++++
 include/linux/hdmi.h                 |  24 ++++++
 include/sound/hdmi_drm.h             |  16 ++++
 sound/soc/codecs/Kconfig             |   4 +
 sound/soc/codecs/Makefile            |   2 +
 sound/soc/codecs/hdmi_drm.c          | 125 +++++++++++++++++++++++++++++
 13 files changed, 625 insertions(+), 14 deletions(-)
 create mode 100644 include/sound/hdmi_drm.h
 create mode 100644 sound/soc/codecs/hdmi_drm.c

-- 
1.9.1

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

* [RFC 1/5] video: hdmi: add help function for N and CTS
  2015-09-21 13:19 [RFC 0/5] another generic audio hdmi codec proposal Arnaud Pouliquen
@ 2015-09-21 13:19 ` Arnaud Pouliquen
  2015-09-21 13:19 ` [RFC 2/5] drm: add helper functions to add bridge audio capabilities Arnaud Pouliquen
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Arnaud Pouliquen @ 2015-09-21 13:19 UTC (permalink / raw)
  To: alsa-devel, dri-devel
  Cc: moinejf, linux, Takashi Iwai, tomi.valkeinen, arnaud.pouliquen,
	lgirdwood, Jyri Sarha, peter.ujfalusi, airlied, tony, broonie,
	bcousson

Add helper function to compute CTS and N parameters base on 
table described in HDMI specification 1.4b

Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@st.com>
---
 drivers/video/hdmi.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/hdmi.h |   8 +++
 2 files changed, 156 insertions(+)

diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 1626892..9c487fb 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -1242,3 +1242,151 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer)
 	return ret;
 }
 EXPORT_SYMBOL(hdmi_infoframe_unpack);
+
+/*
+ * audio clock regeneration (acr) parameters
+ * N and CTS computation are based on HDMI specification 1.4b
+ */
+
+enum audio_rate {
+	HDMI_AUDIO_N_CTS_32KHZ,
+	HDMI_AUDIO_N_CTS_44_1KHZ,
+	HDMI_AUDIO_N_CTS_48KHZ,
+};
+
+struct hdmi_audio_acr {
+	unsigned long pixel_clk;
+	struct hdmi_audio_n_cts n_cts;
+};
+
+static const struct hdmi_audio_acr hdmi_audio_standard_acr[3][12] = {
+	{ /*32 kHz*/
+		{  25175, {  4576,  28125 } }, /* 25,20/1.001  MHz */
+		{  25200, {  4096,  25200 } }, /* 25.20        MHz */
+		{  27000, {  4096,  27000 } }, /* 27.00        MHz */
+		{  27027, {  4096,  27027 } }, /* 27.00*1.001  MHz */
+		{  54000, {  4096,  54000 } }, /* 54.00        MHz */
+		{  54054, {  4096,  54054 } }, /* 54.00*1.001  MHz */
+		{  74176, { 11648, 310938 } }, /* 74.25/1.001  MHz */
+		{  74250, {  4096,  74250 } }, /* 74.25        MHz */
+		{ 148352, { 11648, 421875 } }, /* 148.50/1.001 MHz */
+		{ 148500, {  4096, 148500 } }, /* 148.50       MHz */
+		{ 296703, {  5824, 421875 } }, /* 297/1.001    MHz */
+		{ 297000, {  3072, 222750 } }, /* 297          MHz */
+	},
+	{ /*44.1 kHz, 88.2 kHz  176.4 kHz*/
+		{  25175, {  7007,  31250 } }, /* 25,20/1.001  MHz */
+		{  25200, {  6272,  28000 } }, /* 25.20        MHz */
+		{  27000, {  6272,  30000 } }, /* 27.00        MHz */
+		{  27027, {  6272,  30030 } }, /* 27.00*1.001  MHz */
+		{  54000, {  6272,  60000 } }, /* 54.00        MHz */
+		{  54054, {  6272,  60060 } }, /* 54.00*1.001  MHz */
+		{  74176, { 17836, 234375 } }, /* 74.25/1.001  MHz */
+		{  74250, {  6272,  82500 } }, /* 74.25        MHz */
+		{ 148352, {  8918, 234375 } }, /* 148.50/1.001 MHz */
+		{ 148500, {  6272, 165000 } }, /* 148.50       MHz */
+		{ 296703, {  4459, 234375 } }, /* 297/1.001    MHz */
+		{ 297000, {  4704, 247500 } }, /* 297          MHz */
+	},
+	{ /*48 kHz, 96 kHz  192 kHz*/
+		{  25175, {  6864,  28125 } }, /* 25,20/1.001  MHz */
+		{  25200, {  6144,  25200 } }, /* 25.20        MHz */
+		{  27000, {  6144,  27000 } }, /* 27.00        MHz */
+		{  27027, {  6144,  27027 } }, /* 27.00*1.001  MHz */
+		{  54000, {  6144,  54000 } }, /* 54.00        MHz */
+		{  54054, {  6144,  54054 } }, /* 54.00*1.001  MHz */
+		{  74176, { 11648, 140625 } }, /* 74.25/1.001  MHz */
+		{  74250, {  6144,  74250 } }, /* 74.25        MHz */
+		{ 148352, {  5824, 140625 } }, /* 148.50/1.001 MHz */
+		{ 148500, {  6144, 148500 } }, /* 148.50       MHz */
+		{ 296703, {  5824, 281250 } }, /* 297/1.001    MHz */
+		{ 297000, {  5120, 247500 } }, /* 297          MHz */
+	}
+};
+
+/**
+ * hdmi_compute_n_cts() - compute N and CTS parameters
+ * @audio_clk: audio frame clock frequency in KHz
+ * @pixel_clk: pixel cloack frequency in kHz
+ * @n_cts: N and CTS parameter returned to user
+ *
+ * Values computed are based on table described in HDMI specification 1.4b
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+
+int hdmi_audio_compute_n_cts(unsigned int audio_fs, unsigned long pixel_clk,
+			     struct hdmi_audio_n_cts *n_cts)
+{
+	int audio_freq_id, i;
+	int ratio = 1;
+	const struct hdmi_audio_acr  *acr_table;
+	const struct hdmi_audio_n_cts *predef_n_cts = NULL;
+
+	switch (audio_fs) {
+	case 32000:
+		audio_freq_id = HDMI_AUDIO_N_CTS_32KHZ;
+		n_cts->n = 4096;
+		break;
+
+	case 44100:
+		audio_freq_id = HDMI_AUDIO_N_CTS_44_1KHZ;
+		n_cts->n = 6272;
+		break;
+
+	case 48000:
+		audio_freq_id = HDMI_AUDIO_N_CTS_48KHZ;
+		n_cts->n = 6144;
+		break;
+
+	case 88200:
+		audio_freq_id = HDMI_AUDIO_N_CTS_44_1KHZ;
+		ratio = 2;
+		n_cts->n = 6272 * 2;
+		break;
+
+	case 96000:
+		audio_freq_id = HDMI_AUDIO_N_CTS_48KHZ;
+		ratio = 2;
+		n_cts->n = 6144 * 2;
+		break;
+
+	case 176400:
+		audio_freq_id = HDMI_AUDIO_N_CTS_44_1KHZ;
+		ratio = 2;
+		n_cts->n = 6272 * 4;
+		break;
+
+	case 192000:
+		audio_freq_id = HDMI_AUDIO_N_CTS_48KHZ;
+		ratio = 4;
+		n_cts->n = 6144 * 4;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	acr_table = hdmi_audio_standard_acr[audio_freq_id];
+	for (i = 0; i < ARRAY_SIZE(hdmi_audio_standard_acr[0]); i++) {
+		if (pixel_clk == acr_table[i].pixel_clk) {
+			predef_n_cts = &acr_table[i].n_cts;
+			break;
+		}
+	}
+
+	if (!predef_n_cts) {
+		/*
+		 * predifined frequency not found compute CTS using formula:
+		 * CTS = (Ftdms_clk * N) / (128* audio_fs)
+		 */
+		n_cts->cts =  pixel_clk * n_cts->n / (128 * audio_fs);
+	} else {
+		n_cts->n = predef_n_cts->n * ratio;
+		n_cts->cts = predef_n_cts->cts;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(hdmi_audio_compute_n_cts);
+
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index e974420..32107a0 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -333,4 +333,12 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer);
 void hdmi_infoframe_log(const char *level, struct device *dev,
 			union hdmi_infoframe *frame);
 
+struct hdmi_audio_n_cts {
+	unsigned int n;
+	unsigned int cts;
+};
+
+int hdmi_audio_compute_n_cts(unsigned int audio_fs, unsigned long pixel_clk,
+			     struct hdmi_audio_n_cts *n_cts);
+
 #endif /* _DRM_HDMI_H */
-- 
1.9.1

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

* [RFC 2/5] drm: add helper functions to add bridge audio capabilities
  2015-09-21 13:19 [RFC 0/5] another generic audio hdmi codec proposal Arnaud Pouliquen
  2015-09-21 13:19 ` [RFC 1/5] video: hdmi: add help function for N and CTS Arnaud Pouliquen
@ 2015-09-21 13:19 ` Arnaud Pouliquen
  2015-09-21 13:19 ` [RFC 3/5] ASoC: codec: hdmi drm codec driver Arnaud Pouliquen
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Arnaud Pouliquen @ 2015-09-21 13:19 UTC (permalink / raw)
  To: alsa-devel, dri-devel
  Cc: moinejf, linux, Takashi Iwai, tomi.valkeinen, arnaud.pouliquen,
	lgirdwood, Jyri Sarha, peter.ujfalusi, airlied, tony, broonie,
	bcousson

Extend bridge capabilities for audio to enable to connect an audio driver to a
DRM driver with audio capabilities

Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@st.com>
---
 drivers/gpu/drm/drm_bridge.c | 114 +++++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_crtc.h       |  31 ++++++++++++
 include/linux/hdmi.h         |  16 ++++++
 3 files changed, 161 insertions(+)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 6b8f721..2284ac9 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -328,6 +328,120 @@ struct drm_bridge *of_drm_find_bridge(struct device_node *np)
 EXPORT_SYMBOL(of_drm_find_bridge);
 #endif
 
+/**
+ * DOC: audio bridge callbacks
+ *
+ * The drm_audio_bridge_funcs ops are populated by the bridge driver that have
+ * audio capabilities (a.e HDMI)
+ * The drm internals(atomic and crtc helpers) use the helpers defined in
+ * drm_bridge.c
+ * These helpers call a specific drm_audio_bridge_funcs ops for all the bridges
+ * during encoder configuration.
+ *
+ * When creating a bridge driver, one can implement drm_audio_bridge_funcs op
+ * with the help of these rough rules:
+ *
+ * pre_enable: this contains things needed to be done for the bridge before
+ * audio is enabled by its source.
+ *
+ * enable: this contains things needed to be done for the audio bridge once its
+ * source is enabled. In other words, enable is called once the source is
+ * ready to start stream rendering.
+ *
+ * disable: this contains things needed to be done for audio bridge when to
+ * disable the audio part for the bridge, assuming that its source is still
+ * enabled.
+ *
+ * post_disable: this contains things needed to be done for the bridge once
+ * its source is disabled.
+ *
+ * mode_set: this sets up the mode for the audio bridge. It assumes that its
+ * source (an encoder or a bridge) has set the mode too.
+ */
+
+/**
+ * drm_audio_bridge_pre_enable - calls 'pre_enable' drm_audio_bridge_funcs ops
+ *                               for audio bridges in the encoder chain.
+ * @bridge: bridge control structure
+ *
+ * Calls 'pre_enable' drm_audio_bridge_funcs op for  audio bridge in the
+ * encoder chain.
+ *
+ */
+
+void drm_audio_bridge_pre_enable(struct drm_bridge *bridge)
+{
+	if (!bridge)
+		return;
+
+	if (bridge->audio_funcs->pre_enable)
+		bridge->audio_funcs->pre_enable(bridge);
+}
+EXPORT_SYMBOL(drm_audio_bridge_pre_enable);
+
+/**
+ * drm_audio_bridge_disable - calls 'disable' drm_audio_bridge_funcs op for
+ *                            audio bridge in the encoder chain.
+ * @bridge: bridge control structure
+ *
+ * Calls 'disable' drm_audio_bridge_funcs op for bridges with audio in the
+ * encoder chain.
+ *
+ */
+void drm_audio_bridge_disable(struct drm_bridge *bridge)
+{
+	if (!bridge)
+		return;
+
+	if (bridge->audio_funcs->disable)
+		bridge->audio_funcs->disable(bridge);
+}
+EXPORT_SYMBOL(drm_audio_bridge_disable);
+
+/**
+ * drm_audio_bridge_mode_set - set audio mode for audio bridge in the
+ *			 encoder chain
+ * @bridge: bridge control structure
+ * @mode: desired audio mode to be set for the audio bridge
+ *
+ * Calls 'mode_set' drm_audio_bridge_funcs op for audio bridge in the
+ * encoder chain.
+ *
+ */
+void drm_audio_bridge_mode_set(struct drm_bridge *bridge,
+			       struct hdmi_audio_mode *mode)
+{
+	if (!bridge)
+		return;
+
+	if (bridge->audio_funcs->mode_set)
+		bridge->audio_funcs->mode_set(bridge, mode);
+}
+EXPORT_SYMBOL(drm_audio_bridge_mode_set);
+
+/**
+ * drm_audio_bridge_enable - calls 'enable' drm_audio_bridge_funcs op for all bridges
+ *		       in the encoder chain.
+ * @bridge: bridge control structure
+ *
+ * Calls 'enable' drm_audio_bridge_funcs op for all the bridges in the encoder
+ * chain, starting from the first bridge to the last. These are called
+ * after completing the encoder's commit op.
+ *
+ * Note that the bridge passed should be the one closest to the encoder
+ */
+void drm_audio_bridge_enable(struct drm_bridge *bridge)
+{
+	if (!bridge)
+		return;
+
+	if (bridge->audio_funcs->mode_set)
+		bridge->audio_funcs->enable(bridge);
+
+}
+EXPORT_SYMBOL(drm_audio_bridge_enable);
+
+
 MODULE_AUTHOR("Ajay Kumar <ajaykumar.rs@samsung.com>");
 MODULE_DESCRIPTION("DRM bridge infrastructure");
 MODULE_LICENSE("GPL and additional rights");
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 3b4d8a4..5074019 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -583,6 +583,7 @@ struct drm_encoder_funcs {
  * @possible_clones: bitmask of potential sibling encoders for cloning
  * @crtc: currently bound CRTC
  * @bridge: bridge associated to the encoder
+ * @abridge: optional audio bridge associated to the encoder (HDMI)
  * @funcs: control functions
  * @helper_private: mid-layer private data
  *
@@ -601,6 +602,7 @@ struct drm_encoder {
 
 	struct drm_crtc *crtc;
 	struct drm_bridge *bridge;
+	struct drm_bridge *abridge;
 	const struct drm_encoder_funcs *funcs;
 	const void *helper_private;
 };
@@ -905,6 +907,24 @@ struct drm_bridge_funcs {
 };
 
 /**
+ * struct drm_audio_bridge_funcs - audio drm_bridge control functions
+ * @attach: Called during drm_audio_bridge_attach
+ * @mode_fixup: Try to fixup (or reject entirely) proposed mode for this bridge
+ * @disable: Called right before encoder prepare, disables the bridge
+ * @post_disable: Called right after encoder prepare, for lockstepped disable
+ * @mode_set: Set this mode to the bridge
+ * @pre_enable: Called right before encoder commit, for lockstepped commit
+ * @enable: Called right after encoder commit, enables the bridge
+ */
+struct drm_audio_bridge_funcs {
+	void (*disable)(struct drm_bridge *bridge);
+	void (*pre_enable)(struct drm_bridge *bridge);
+	void (*enable)(struct drm_bridge *bridge);
+	int (*mode_set)(struct drm_bridge *bridge,
+			struct hdmi_audio_mode *mode);
+};
+
+/**
  * struct drm_bridge - central DRM bridge control structure
  * @dev: DRM device this bridge belongs to
  * @encoder: encoder to which this bridge is connected
@@ -925,7 +945,9 @@ struct drm_bridge {
 	struct list_head list;
 
 	const struct drm_bridge_funcs *funcs;
+	const struct drm_audio_bridge_funcs *audio_funcs;
 	void *driver_private;
+	void *snd_private;
 };
 
 /**
@@ -1271,6 +1293,15 @@ extern int drm_encoder_init(struct drm_device *dev,
 			    const struct drm_encoder_funcs *funcs,
 			    int encoder_type);
 
+int drm_audio_bridge_attach(struct drm_device *dev,
+			     struct drm_bridge *bridge);
+void drm_audio_bridge_disable(struct drm_bridge *bridge);
+void drm_audio_bridge_mode_set(struct drm_bridge *bridge,
+			       struct hdmi_audio_mode *mode);
+void drm_audio_bridge_pre_enable(struct drm_bridge *bridge);
+void drm_audio_bridge_enable(struct drm_bridge *bridge);
+
+
 /**
  * drm_encoder_crtc_ok - can a given crtc drive a given encoder?
  * @encoder: encoder to test
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index 32107a0..d3d1a80 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -333,11 +333,27 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer);
 void hdmi_infoframe_log(const char *level, struct device *dev,
 			union hdmi_infoframe *frame);
 
+/**
+ * struct hdmi_audio_n_cts - n and cts parameter for ACR packets
+ */
 struct hdmi_audio_n_cts {
 	unsigned int n;
 	unsigned int cts;
 };
 
+/**
+ * struct hdmi_audio_mode - hdmi audio structure for audio configuration
+ * @enabled audio state
+ * @infoframe: audio infoframe info frame
+ * @data: private data use by alsa driver to retrieve context
+ *
+ * This is used by audio driver to configure the HDMI audio part
+ */
+struct hdmi_audio_mode {
+	bool enabled;
+	struct hdmi_audio_infoframe infoframe;
+};
+
 int hdmi_audio_compute_n_cts(unsigned int audio_fs, unsigned long pixel_clk,
 			     struct hdmi_audio_n_cts *n_cts);
 
-- 
1.9.1

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

* [RFC 3/5] ASoC: codec:  hdmi drm codec driver
  2015-09-21 13:19 [RFC 0/5] another generic audio hdmi codec proposal Arnaud Pouliquen
  2015-09-21 13:19 ` [RFC 1/5] video: hdmi: add help function for N and CTS Arnaud Pouliquen
  2015-09-21 13:19 ` [RFC 2/5] drm: add helper functions to add bridge audio capabilities Arnaud Pouliquen
@ 2015-09-21 13:19 ` Arnaud Pouliquen
  2015-09-25 14:11   ` Jyri Sarha
  2015-09-21 13:19 ` [RFC 4/5] drm: sti: connect audio driver Arnaud Pouliquen
  2015-09-21 13:19 ` [RFC 5/5] DT: sti: add audio HDMI dai link in audio card Arnaud Pouliquen
  4 siblings, 1 reply; 9+ messages in thread
From: Arnaud Pouliquen @ 2015-09-21 13:19 UTC (permalink / raw)
  To: alsa-devel, dri-devel
  Cc: moinejf, linux, Takashi Iwai, tomi.valkeinen, arnaud.pouliquen,
	lgirdwood, Jyri Sarha, peter.ujfalusi, airlied, tony, broonie,
	bcousson

Add a generic codec to interface audio with DRM drivers

Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@st.com>
---
 include/sound/hdmi_drm.h    |  16 ++++++
 sound/soc/codecs/Kconfig    |   4 ++
 sound/soc/codecs/Makefile   |   2 +
 sound/soc/codecs/hdmi_drm.c | 125 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 147 insertions(+)
 create mode 100644 include/sound/hdmi_drm.h
 create mode 100644 sound/soc/codecs/hdmi_drm.c

diff --git a/include/sound/hdmi_drm.h b/include/sound/hdmi_drm.h
new file mode 100644
index 0000000..0146b88
--- /dev/null
+++ b/include/sound/hdmi_drm.h
@@ -0,0 +1,16 @@
+/*
+ * Interface for HDMI DRM  codec
+ *
+ * Author: Arnaud Pouliquen <arnaud.pouliquen@st.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.
+ */
+#ifndef __HDMI_DRM__H__
+#define __HDMI_DRM__H__
+
+int hdmi_drm_codec_register(struct device *dev);
+void hdmi_drm_codec_unregister(struct device *dev);
+
+#endif
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 0c9733e..922af30 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -80,6 +80,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_MC13783 if MFD_MC13XXX
 	select SND_SOC_ML26124 if I2C
 	select SND_SOC_HDMI_CODEC
+	select SND_SOC_HDMI_DRM_CODEC
 	select SND_SOC_PCM1681 if I2C
 	select SND_SOC_PCM1792A if SPI_MASTER
 	select SND_SOC_PCM3008
@@ -445,6 +446,9 @@ config SND_SOC_DMIC
 config SND_SOC_HDMI_CODEC
        tristate "HDMI stub CODEC"
 
+config SND_SOC_HDMI_DRM_CODEC
+       tristate "HDMI DRM CODEC"
+
 config SND_SOC_ES8328
 	tristate "Everest Semi ES8328 CODEC"
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 4a32077..c92aaf7 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -73,6 +73,7 @@ snd-soc-max9850-objs := max9850.o
 snd-soc-mc13783-objs := mc13783.o
 snd-soc-ml26124-objs := ml26124.o
 snd-soc-hdmi-codec-objs := hdmi.o
+snd-soc-hdmi-drm-codec-objs := hdmi_drm.o
 snd-soc-pcm1681-objs := pcm1681.o
 snd-soc-pcm1792a-codec-objs := pcm1792a.o
 snd-soc-pcm3008-objs := pcm3008.o
@@ -265,6 +266,7 @@ obj-$(CONFIG_SND_SOC_MAX9850)	+= snd-soc-max9850.o
 obj-$(CONFIG_SND_SOC_MC13783)	+= snd-soc-mc13783.o
 obj-$(CONFIG_SND_SOC_ML26124)	+= snd-soc-ml26124.o
 obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
+obj-$(CONFIG_SND_SOC_HDMI_DRM_CODEC) += snd-soc-hdmi-drm-codec.o
 obj-$(CONFIG_SND_SOC_PCM1681)	+= snd-soc-pcm1681.o
 obj-$(CONFIG_SND_SOC_PCM1792A)	+= snd-soc-pcm1792a-codec.o
 obj-$(CONFIG_SND_SOC_PCM3008)	+= snd-soc-pcm3008.o
diff --git a/sound/soc/codecs/hdmi_drm.c b/sound/soc/codecs/hdmi_drm.c
new file mode 100644
index 0000000..2df9a8f
--- /dev/null
+++ b/sound/soc/codecs/hdmi_drm.c
@@ -0,0 +1,125 @@
+/*
+ * ALSA SoC codec driver for DRM HDMI device.
+ * Copyright (C) STMicroelectronics SA 2015
+ * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com>
+ *          for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/module.h>
+#include <sound/soc.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include <drm/drm_crtc_helper.h>
+
+struct hdmi_drm_dai_data {
+	struct drm_bridge *bridge;
+};
+
+static const struct snd_soc_dapm_widget hdmi_drm_widgets[] = {
+	SND_SOC_DAPM_OUTPUT("TX"),
+};
+
+static const struct snd_soc_dapm_route hdmi_drm_routes[] = {
+	{ "TX", NULL, "Playback" },
+};
+
+int hdmi_drm_dai_prepare(struct snd_pcm_substream *substream,
+			 struct snd_soc_dai *dai)
+{
+	struct hdmi_drm_dai_data *priv = snd_soc_dai_get_drvdata(dai);
+
+	dev_err(dai->dev, "%s: enter for bridge %p\n", __func__, priv->bridge);
+	drm_audio_bridge_pre_enable(priv->bridge);
+	return 0;
+}
+
+int hdmi_drm_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+			 struct snd_soc_dai *dai)
+{
+	struct hdmi_drm_dai_data *priv = snd_soc_dai_get_drvdata(dai);
+
+	dev_err(dai->dev, "%s: enter\n", __func__);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		drm_audio_bridge_enable(priv->bridge);
+		break;
+
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		drm_audio_bridge_disable(priv->bridge);
+		break;
+	}
+
+	return 0;
+}
+
+static int st_hdmi_dai_probe(struct snd_soc_dai *dai)
+{
+	struct hdmi_drm_dai_data *priv;
+
+	dev_err(dai->dev, "%s: enter\n", __func__);
+	priv = devm_kzalloc(dai->dev, sizeof(*priv), GFP_KERNEL);
+
+	priv->bridge = of_drm_find_bridge(dai->dev->of_node);
+
+	dev_err(dai->dev, "%s: bridge %p\n", __func__, priv->bridge);
+
+	snd_soc_dai_set_drvdata(dai, priv);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops hdmi_drm_codec_ops = {
+		.prepare =  hdmi_drm_dai_prepare,
+		.trigger = hdmi_drm_dai_trigger,
+};
+
+static struct snd_soc_dai_driver hdmi_drm_codec_dai = {
+	.name = "hdmi-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 8,
+		.rates = SNDRV_PCM_RATE_32000 |
+			SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+			SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+			SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE |
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
+		.sig_bits = 24,
+	},
+	.probe = st_hdmi_dai_probe,
+	.ops = &hdmi_drm_codec_ops,
+};
+
+static struct snd_soc_codec_driver hdmi_drm_codec = {
+	.dapm_widgets = hdmi_drm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(hdmi_drm_widgets),
+	.dapm_routes = hdmi_drm_routes,
+	.num_dapm_routes = ARRAY_SIZE(hdmi_drm_routes),
+	.ignore_pmdown_time = true,
+};
+
+int hdmi_drm_codec_register(struct device *dev)
+{
+	dev_err(dev, "%s: enter", __func__);
+	return snd_soc_register_codec(dev, &hdmi_drm_codec,
+				      &hdmi_drm_codec_dai, 1);
+}
+EXPORT_SYMBOL_GPL(hdmi_drm_codec_register);
+
+void hdmi_drm_codec_unregister(struct device *dev)
+{
+	dev_err(dev, "%s: enter", __func__);
+	snd_soc_unregister_codec(dev);
+}
+EXPORT_SYMBOL_GPL(hdmi_drm_codec_unregister);
+
+MODULE_AUTHOR("Arnaud.pouliquen@st.com");
+MODULE_DESCRIPTION("ASoC HDMI codec driver");
+MODULE_LICENSE("GPL");
-- 
1.9.1

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

* [RFC 4/5] drm: sti: connect audio driver
  2015-09-21 13:19 [RFC 0/5] another generic audio hdmi codec proposal Arnaud Pouliquen
                   ` (2 preceding siblings ...)
  2015-09-21 13:19 ` [RFC 3/5] ASoC: codec: hdmi drm codec driver Arnaud Pouliquen
@ 2015-09-21 13:19 ` Arnaud Pouliquen
  2015-09-21 13:19 ` [RFC 5/5] DT: sti: add audio HDMI dai link in audio card Arnaud Pouliquen
  4 siblings, 0 replies; 9+ messages in thread
From: Arnaud Pouliquen @ 2015-09-21 13:19 UTC (permalink / raw)
  To: alsa-devel, dri-devel
  Cc: moinejf, linux, Takashi Iwai, tomi.valkeinen, arnaud.pouliquen,
	lgirdwood, Jyri Sarha, peter.ujfalusi, airlied, tony, broonie,
	bcousson

Add management of the audio bridge

Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@st.com>
---
 drivers/gpu/drm/sti/sti_hdmi.c | 146 +++++++++++++++++++++++++++++++++++++----
 drivers/gpu/drm/sti/sti_hdmi.h |   3 +
 2 files changed, 137 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
index 06595e9..d324e0a 100644
--- a/drivers/gpu/drm/sti/sti_hdmi.c
+++ b/drivers/gpu/drm/sti/sti_hdmi.c
@@ -17,6 +17,8 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_edid.h>
 
+#include <sound/hdmi_drm.h>
+
 #include "sti_hdmi.h"
 #include "sti_hdmi_tx3g4c28phy.h"
 #include "sti_hdmi_tx3g0c55phy.h"
@@ -34,6 +36,8 @@
 #define HDMI_DFLT_CHL0_DAT              0x0110
 #define HDMI_DFLT_CHL1_DAT              0x0114
 #define HDMI_DFLT_CHL2_DAT              0x0118
+#define HDMI_AUDIO_CFG                  0x0200
+#define HDMI_SPDIF_FIFO_STATUS          0x0204
 #define HDMI_SW_DI_1_HEAD_WORD          0x0210
 #define HDMI_SW_DI_1_PKT_WORD0          0x0214
 #define HDMI_SW_DI_1_PKT_WORD1          0x0218
@@ -43,6 +47,9 @@
 #define HDMI_SW_DI_1_PKT_WORD5          0x0228
 #define HDMI_SW_DI_1_PKT_WORD6          0x022C
 #define HDMI_SW_DI_CFG                  0x0230
+#define HDMI_SAMPLE_FLAT_MASK           0x0244
+#define HDMI_AUDN                       0x0400
+#define HDMI_AUD_CTS                    0x0404
 #define HDMI_SW_DI_2_HEAD_WORD          0x0600
 #define HDMI_SW_DI_2_PKT_WORD0          0x0604
 #define HDMI_SW_DI_2_PKT_WORD1          0x0608
@@ -52,6 +59,7 @@
 #define HDMI_SW_DI_2_PKT_WORD5          0x0618
 #define HDMI_SW_DI_2_PKT_WORD6          0x061C
 
+
 #define HDMI_IFRAME_SLOT_AVI            1
 #define HDMI_IFRAME_SLOT_AUDIO          2
 
@@ -109,6 +117,27 @@
 
 #define HDMI_STA_SW_RST                 BIT(1)
 
+#define HDMI_AUD_CFG_8CH        BIT(0)
+#define HDMI_AUD_CFG_SPDIF_DIV_2  BIT(1)
+#define HDMI_AUD_CFG_SPDIF_DIV_3  BIT(2)
+#define HDMI_AUD_CFG_SPDIF_CLK_DIV_4 (BIT(1) | BIT(1))
+#define HDMI_AUD_CFG_CTS_CLK_128FS  BIT(17)
+#define HDMI_AUD_CFG_CH12_VALID BIT(28)
+#define HDMI_AUD_CFG_CH34_VALID BIT(29)
+#define HDMI_AUD_CFG_CH56_VALID BIT(30)
+#define HDMI_AUD_CFG_CH78_VALID BIT(31)
+
+/* sample flat mask */
+#define HDMI_SAMPLE_FLAT_NO	 0
+#define HDMI_SAMPLE_FLAT_SP0 BIT(0)
+#define HDMI_SAMPLE_FLAT_SP1 BIT(1)
+#define HDMI_SAMPLE_FLAT_SP2 BIT(2)
+#define HDMI_SAMPLE_FLAT_SP3 BIT(3)
+#define HDMI_SAMPLE_FLAT_ALL (HDMI_SAMPLE_FLAT_SP0 \
+				  | HDMI_SAMPLE_FLAT_SP1 \
+				  | HDMI_SAMPLE_FLAT_SP2 \
+				  | HDMI_SAMPLE_FLAT_SP3)
+
 #define HDMI_INFOFRAME_HEADER_TYPE(x)    (((x) & 0xff) <<  0)
 #define HDMI_INFOFRAME_HEADER_VERSION(x) (((x) & 0xff) <<  8)
 #define HDMI_INFOFRAME_HEADER_LEN(x)     (((x) & 0x0f) << 16)
@@ -380,19 +409,13 @@ static int hdmi_avi_infoframe_config(struct sti_hdmi *hdmi)
  */
 static int hdmi_audio_infoframe_config(struct sti_hdmi *hdmi)
 {
-	struct hdmi_audio_infoframe infofame;
+	struct hdmi_audio_infoframe *infoframe;
 	u8 buffer[HDMI_INFOFRAME_SIZE(AUDIO)];
 	int ret;
 
-	ret = hdmi_audio_infoframe_init(&infofame);
-	if (ret < 0) {
-		DRM_ERROR("failed to setup audio infoframe: %d\n", ret);
-		return ret;
-	}
-
-	infofame.channels = 2;
+	infoframe = &hdmi->audio.infoframe;
 
-	ret = hdmi_audio_infoframe_pack(&infofame, buffer, sizeof(buffer));
+	ret = hdmi_audio_infoframe_pack(infoframe, buffer, sizeof(buffer));
 	if (ret < 0) {
 		DRM_ERROR("failed to pack audio infoframe: %d\n", ret);
 		return ret;
@@ -404,6 +427,56 @@ static int hdmi_audio_infoframe_config(struct sti_hdmi *hdmi)
 }
 
 /**
+ * set audio frame rate
+ *
+ * @hdmi: pointer on the hdmi internal structure
+ *
+ */
+static int hdmi_audio_set_infoframe(struct sti_hdmi *hdmi,
+				    struct hdmi_audio_infoframe *info)
+{
+	struct hdmi_audio_n_cts n_cts;
+	int ret, audio_cfg;
+
+	hdmi->audio.infoframe = *info;
+
+	if (!hdmi->enabled)
+		return 0;
+
+	/* update HDMI registers according to configuration */
+	audio_cfg = HDMI_AUD_CFG_SPDIF_DIV_3 | HDMI_AUD_CFG_CTS_CLK_128FS;
+
+	switch (info->channels) {
+	case 8:
+		audio_cfg |= HDMI_AUD_CFG_CH78_VALID;
+	case 6:
+		audio_cfg |= HDMI_AUD_CFG_CH56_VALID;
+	case 4:
+		audio_cfg |= HDMI_AUD_CFG_CH34_VALID | HDMI_AUD_CFG_8CH;
+	case 2:
+		audio_cfg = HDMI_AUD_CFG_CH12_VALID;
+		break;
+	default:
+		DRM_ERROR("ERROR: Unsupported number of channels (%d)!\n",
+			  info->channels);
+		return -EINVAL;
+	}
+
+	hdmi_write(hdmi, audio_cfg, HDMI_AUDIO_CFG);
+
+	/* update N parameter */
+	ret = hdmi_audio_compute_n_cts(info->sample_frequency,
+				       hdmi->mode.clock * 1000, &n_cts);
+
+	DRM_DEBUG_DRIVER("n= %d, cts = %d\n", n_cts.n, n_cts.cts);
+
+	/* clear interrupt status */
+	hdmi_write(hdmi, n_cts.n, HDMI_AUDN);
+
+	return 0;
+}
+
+/**
  * Software reset of the hdmi subsystem
  *
  * @hdmi: pointer on the hdmi internal structure
@@ -462,7 +535,6 @@ static void sti_hdmi_disable(struct drm_bridge *bridge)
 	/* Disable HDMI */
 	val &= ~HDMI_CFG_DEVICE_EN;
 	hdmi_write(hdmi, val, HDMI_CFG);
-
 	hdmi_write(hdmi, 0xffffffff, HDMI_INT_CLR);
 
 	/* Stop the phy */
@@ -520,8 +592,9 @@ static void sti_hdmi_pre_enable(struct drm_bridge *bridge)
 		DRM_ERROR("Unable to configure AVI infoframe\n");
 
 	/* Program AUDIO infoframe */
-	if (hdmi_audio_infoframe_config(hdmi))
-		DRM_ERROR("Unable to configure AUDIO infoframe\n");
+	if (hdmi->audio.enabled)
+		if (hdmi_audio_infoframe_config(hdmi))
+			DRM_ERROR("Unable to configure AUDIO infoframe\n");
 
 	/* Sw reset */
 	hdmi_swreset(hdmi);
@@ -567,6 +640,43 @@ static const struct drm_bridge_funcs sti_hdmi_bridge_funcs = {
 	.mode_set = sti_hdmi_set_mode,
 };
 
+void sti_hdmi_audio_disable(struct drm_bridge *bridge)
+{
+	struct sti_hdmi *hdmi = bridge->driver_private;
+
+	DRM_ERROR("enter %s\n", __func__);
+	/* mute */
+	hdmi_write(hdmi, HDMI_SAMPLE_FLAT_ALL, HDMI_SAMPLE_FLAT_MASK);
+}
+
+int sti_hdmi_audio_set_mode(struct drm_bridge *bridge,
+			       struct hdmi_audio_mode *mode)
+{
+	DRM_ERROR("enter %s\n", __func__);
+	return 0;
+}
+
+void sti_hdmi_audio_pre_enable(struct drm_bridge *bridge)
+{
+	DRM_ERROR("enter %s\n", __func__);
+}
+
+void sti_hdmi_audio_bridge_enable(struct drm_bridge *bridge)
+{
+	struct sti_hdmi *hdmi = bridge->driver_private;
+
+	DRM_ERROR("enter %s\n", __func__);
+	/* unmute */
+	hdmi_write(hdmi, HDMI_SAMPLE_FLAT_NO, HDMI_SAMPLE_FLAT_MASK);
+}
+
+static const struct drm_audio_bridge_funcs sti_hdmi_audio_bridge_funcs = {
+	.pre_enable = sti_hdmi_audio_pre_enable,
+	.enable = sti_hdmi_audio_bridge_enable,
+	.disable = sti_hdmi_audio_disable,
+	.mode_set = sti_hdmi_audio_set_mode,
+};
+
 static int sti_hdmi_connector_get_modes(struct drm_connector *connector)
 {
 	struct sti_hdmi_connector *hdmi_connector
@@ -658,6 +768,7 @@ static void sti_hdmi_connector_destroy(struct drm_connector *connector)
 	struct sti_hdmi_connector *hdmi_connector
 		= to_sti_hdmi_connector(connector);
 
+	drm_bridge_remove(connector->encoder->bridge);
 	drm_connector_unregister(connector);
 	drm_connector_cleanup(connector);
 	kfree(hdmi_connector);
@@ -715,8 +826,14 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
 
 	bridge->driver_private = hdmi;
 	bridge->funcs = &sti_hdmi_bridge_funcs;
+	bridge->audio_funcs = &sti_hdmi_audio_bridge_funcs;
 	drm_bridge_attach(drm_dev, bridge);
 
+	bridge->of_node = dev->of_node;
+	err = drm_bridge_add(bridge);
+	if (err)
+		goto err_adapt;
+
 	encoder->bridge = bridge;
 	connector->encoder = encoder;
 
@@ -748,6 +865,7 @@ err_sysfs:
 	drm_connector_unregister(drm_connector);
 err_connector:
 	drm_connector_cleanup(drm_connector);
+	drm_bridge_remove(bridge);
 err_adapt:
 	put_device(&hdmi->ddc_adapt->dev);
 	return -EINVAL;
@@ -877,6 +995,10 @@ static int sti_hdmi_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, hdmi);
 
+	/* Register audio driver */
+	if (hdmi_drm_codec_register(dev))
+		DRM_INFO("Failed to register HDMI audio driver\n");
+
 	return component_add(&pdev->dev, &sti_hdmi_ops);
 }
 
diff --git a/drivers/gpu/drm/sti/sti_hdmi.h b/drivers/gpu/drm/sti/sti_hdmi.h
index 3d22390..3b93a63 100644
--- a/drivers/gpu/drm/sti/sti_hdmi.h
+++ b/drivers/gpu/drm/sti/sti_hdmi.h
@@ -24,6 +24,7 @@ struct hdmi_phy_ops {
 	void (*stop)(struct sti_hdmi *hdmi);
 };
 
+
 /**
  * STI hdmi structure
  *
@@ -36,6 +37,7 @@ struct hdmi_phy_ops {
  * @clk_tmds: hdmi tmds clock
  * @clk_phy: hdmi phy clock
  * @clk_audio: hdmi audio clock
+ * @audio: hdmi audio state
  * @irq: hdmi interrupt number
  * @irq_status: interrupt status register
  * @phy_ops: phy start/stop operations
@@ -55,6 +57,7 @@ struct sti_hdmi {
 	struct clk *clk_tmds;
 	struct clk *clk_phy;
 	struct clk *clk_audio;
+	struct hdmi_audio_mode audio;
 	int irq;
 	u32 irq_status;
 	struct hdmi_phy_ops *phy_ops;
-- 
1.9.1

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

* [RFC 5/5] DT: sti: add audio HDMI dai link in audio card
  2015-09-21 13:19 [RFC 0/5] another generic audio hdmi codec proposal Arnaud Pouliquen
                   ` (3 preceding siblings ...)
  2015-09-21 13:19 ` [RFC 4/5] drm: sti: connect audio driver Arnaud Pouliquen
@ 2015-09-21 13:19 ` Arnaud Pouliquen
  4 siblings, 0 replies; 9+ messages in thread
From: Arnaud Pouliquen @ 2015-09-21 13:19 UTC (permalink / raw)
  To: alsa-devel, dri-devel
  Cc: moinejf, linux, Takashi Iwai, tomi.valkeinen, arnaud.pouliquen,
	lgirdwood, Jyri Sarha, peter.ujfalusi, airlied, tony, broonie,
	bcousson

Add the HDMI dai link to support audio for HDMi output

Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@st.com>
---
 arch/arm/boot/dts/stih410.dtsi       |  4 ++--
 arch/arm/boot/dts/stihxxx-b2120.dtsi | 21 +++++++++++++++++++++
 arch/arm/configs/multi_v7_defconfig  |  1 +
 3 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/stih410.dtsi b/arch/arm/boot/dts/stih410.dtsi
index 7ee7dc0..3881016 100644
--- a/arch/arm/boot/dts/stih410.dtsi
+++ b/arch/arm/boot/dts/stih410.dtsi
@@ -186,8 +186,9 @@
 							 <&clk_s_d2_quadfs 0>;
 			};
 
-				sti-hdmi@8d04000 {
+				sti_hdmi: sti-hdmi@8d04000 {
 					compatible = "st,stih407-hdmi";
+					#sound-dai-cells = <0>;
 					reg = <0x8d04000 0x1000>;
 					reg-names = "hdmi-reg";
 					interrupts = <GIC_SPI 106 IRQ_TYPE_NONE>;
@@ -210,7 +211,6 @@
 					reset-names = "hdmi";
 					resets = <&softreset STIH407_HDMI_TX_PHY_SOFTRESET>;
 					ddc = <&hdmiddc>;
-
 				};
 
 				sti-hda@8d02000 {
diff --git a/arch/arm/boot/dts/stihxxx-b2120.dtsi b/arch/arm/boot/dts/stihxxx-b2120.dtsi
index 3ad9c82..80fed19 100644
--- a/arch/arm/boot/dts/stihxxx-b2120.dtsi
+++ b/arch/arm/boot/dts/stihxxx-b2120.dtsi
@@ -81,6 +81,9 @@
 		audio_controller: sti-asoc-platform {
 			status = "okay";
 		};
+		sti_uni_player0: sti-uni-player@0 {
+			status = "okay";
+		};
 		sti_uni_player2: sti-uni-player@2 {
 			status = "okay";
 		};
@@ -93,6 +96,12 @@
 		sti_uni_reader1: sti-uni-reader@1 {
 			status = "okay";
 		};
+
+		sti-display-subsystem {
+			sti_hdmi: sti-hdmi@8d04000 {
+				status = "okay";
+			};
+		};
 	};
 
 	sound {
@@ -125,6 +134,18 @@
 				sound-dai = <&sti_sasg_codec 0>;
 			};
 		};
+		simple-audio-card,dai-link@2 {
+			/* HDMI */
+			format = "i2s";
+			mclk-fs = <128>;
+			cpu {
+				sound-dai = <&sti_uni_player0>;
+			};
+
+			codec {
+				sound-dai = <&sti_hdmi>;
+			};
+		};
 	};
 
 };
diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index 2a44694..6f43666 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -461,6 +461,7 @@ CONFIG_SND_ATMEL_SOC=m
 CONFIG_SND_ATMEL_SOC_WM8904=m
 CONFIG_SND_SOC_SH4_FSI=m
 CONFIG_SND_SOC_RCAR=m
+CONFIG_SND_SOC_HDMI_DRM_CODEC=y
 CONFIG_SND_SOC_STI=y
 CONFIG_SND_SOC_STI_SAS=y
 CONFIG_SND_SOC_TEGRA=m
-- 
1.9.1

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

* Re: [RFC 3/5] ASoC: codec: hdmi drm codec driver
  2015-09-21 13:19 ` [RFC 3/5] ASoC: codec: hdmi drm codec driver Arnaud Pouliquen
@ 2015-09-25 14:11   ` Jyri Sarha
  2015-09-25 15:50     ` Arnaud Pouliquen
  0 siblings, 1 reply; 9+ messages in thread
From: Jyri Sarha @ 2015-09-25 14:11 UTC (permalink / raw)
  To: Arnaud Pouliquen, alsa-devel, dri-devel
  Cc: moinejf, linux, Takashi Iwai, tomi.valkeinen, lgirdwood,
	peter.ujfalusi, airlied, tony, broonie, bcousson

Despite my earlier comment this implementation and the related HW is 
quite similar in all significant aspects to the patch set posted couple 
of days ago [1] for Beaglebone-Black HDMI audio.

[1] http://permalink.gmane.org/gmane.linux.alsa.devel/144144

I have not yet gotten to bottom of drm-side audio bride part, but I am 
working on it. Bellow is couple of early comments to the ASoC part.

Best regards,
Jyri

On 09/21/15 16:19, Arnaud Pouliquen wrote:
> Add a generic codec to interface audio with DRM drivers
>
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@st.com>
> ---
>   include/sound/hdmi_drm.h    |  16 ++++++
>   sound/soc/codecs/Kconfig    |   4 ++
>   sound/soc/codecs/Makefile   |   2 +
>   sound/soc/codecs/hdmi_drm.c | 125 ++++++++++++++++++++++++++++++++++++++++++++
>   4 files changed, 147 insertions(+)
>   create mode 100644 include/sound/hdmi_drm.h
>   create mode 100644 sound/soc/codecs/hdmi_drm.c
>
> diff --git a/include/sound/hdmi_drm.h b/include/sound/hdmi_drm.hhere are several important callbacks missing here
> new file mode 100644
> index 0000000..0146b88
> --- /dev/null
> +++ b/include/sound/hdmi_drm.h
> @@ -0,0 +1,16 @@
> +/*
> + * Interface for HDMI DRM  codec
> + *
> + * Author: Arnaud Pouliquen <arnaud.pouliquen@st.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.
> + */
> +#ifndef __HDMI_DRM__H__
> +#define __HDMI_DRM__H__
> +
> +int hdmi_drm_codec_register(struct device *dev);
> +void hdmi_drm_codec_unregister(struct device *dev);
> +
> +#endif
> diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
> index 0c9733e..922af30 100644
> --- a/sound/soc/codecs/Kconfig
> +++ b/sound/soc/codecs/Kconfig
> @@ -80,6 +80,7 @@ config SND_SOC_ALL_CODECS
>   	select SND_SOC_MC13783 if MFD_MC13XXX
>   	select SND_SOC_ML26124 if I2C
>   	select SND_SOC_HDMI_CODEC
> +	select SND_SOC_HDMI_DRM_CODEC
>   	select SND_SOC_PCM1681 if I2C
>   	select SND_SOC_PCM1792A if SPI_MASTER
>   	select SND_SOC_PCM3008
> @@ -445,6 +446,9 @@ config SND_SOC_DMIC
>   config SND_SOC_HDMI_CODEC
>          tristate "HDMI stub CODEC"
>
> +config SND_SOC_HDMI_DRM_CODEC
> +       tristate "HDMI DRM CODEC"
> +
>   config SND_SOC_ES8328
>   	tristate "Everest Semi ES8328 CODEC"
>
> diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
> index 4a32077..c92aaf7 100644
> --- a/sound/soc/codecs/Makefile
> +++ b/sound/soc/codecs/Makefile
> @@ -73,6 +73,7 @@ snd-soc-max9850-objs := max9850.o
>   snd-soc-mc13783-objs := mc13783.o
>   snd-soc-ml26124-objs := ml26124.o
>   snd-soc-hdmi-codec-objs := hdmi.o
> +snd-soc-hdmi-drm-codec-objs := hdmi_drm.o
>   snd-soc-pcm1681-objs := pcm1681.o
>   snd-soc-pcm1792a-codec-objs := pcm1792a.o
>   snd-soc-pcm3008-objs := pcm3008.o
> @@ -265,6 +266,7 @@ obj-$(CONFIG_SND_SOC_MAX9850)	+= snd-soc-max9850.o
>   obj-$(CONFIG_SND_SOC_MC13783)	+= snd-soc-mc13783.o
>   obj-$(CONFIG_SND_SOC_ML26124)	+= snd-soc-ml26124.o
>   obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
> +obj-$(CONFIG_SND_SOC_HDMI_DRM_CODEC) += snd-soc-hdmi-drm-codec.o
>   obj-$(CONFIG_SND_SOC_PCM1681)	+= snd-soc-pcm1681.o
>   obj-$(CONFIG_SND_SOC_PCM1792A)	+= snd-soc-pcm1792a-codec.o
>   obj-$(CONFIG_SND_SOC_PCM3008)	+= snd-soc-pcm3008.o
> diff --git a/sound/soc/codecs/hdmi_drm.c b/sound/soc/codecs/hdmi_drm.c
> new file mode 100644
> index 0000000..2df9a8f
> --- /dev/null
> +++ b/sound/soc/codecs/hdmi_drm.c
> @@ -0,0 +1,125 @@
> +/*
> + * ALSA SoC codec driver for DRM HDMI device.
> + * Copyright (C) STMicroelectronics SA 2015
> + * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com>
> + *          for STMicroelectronics.
> + * License terms:  GNU General Public License (GPL), version 2
> + */
> +
> +#include <linux/module.h>
> +#include <sound/soc.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +
> +#include <drm/drm_crtc_helper.h>
> +
> +struct hdmi_drm_dai_data {
> +	struct drm_bridge *bridge;
> +};here are several important callbacks missing here
> +
> +static const struct snd_soc_dapm_widget hdmi_drm_widgets[] = {
> +	SND_SOC_DAPM_OUTPUT("TX"),
> +};
> +
> +static const struct snd_soc_dapm_route hdmi_drm_routes[] = {
> +	{ "TX", NULL, "Playback" },
> +};
> +
> +int hdmi_drm_dai_prepare(struct snd_pcm_substream *substream,
> +			 struct snd_soc_dai *dai)
> +{
> +	struct hdmi_drm_dai_data *priv = snd_soc_dai_get_drvdata(dai);
> +
> +	dev_err(dai->dev, "%s: enter for bridge %p\n", __func__, priv->bridge);
> +	drm_audio_bridge_pre_enable(priv->bridge);
> +	return 0;
> +}
> +
> +int hdmi_drm_dai_trigger(struct snd_pcm_substream *substream, int cmd,
> +			 struct snd_soc_dai *dai)
> +{
> +	struct hdmi_drm_dai_data *priv = snd_soc_dai_get_drvdata(dai);
> +
> +	dev_err(dai->dev, "%s: enter\n", __func__);
> +	switch (cmd) {
> +	case SNDRV_PCM_TRIGGER_START:
> +	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> +	case SNDRV_PCM_TRIGGER_RESUME:
> +		drm_audio_bridge_enable(priv->bridge);
> +		break;
> +
> +	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> +	case SNDRV_PCM_TRIGGER_STOP:
> +	case SNDRV_PCM_TRIGGER_SUSPEND:
> +		drm_audio_bridge_disable(priv->bridge);
> +		break;
> +	}
> +
> +	return 0;here are several important callbacks missing here
> +}
> +
> +static int st_hdmi_dai_probe(struct snd_soc_dai *dai)
> +{
> +	struct hdmi_drm_dai_data *priv;
> +
> +	dev_err(dai->dev, "%s: enter\n", __func__);
> +	priv = devm_kzalloc(dai->dev, sizeof(*priv), GFP_KERNEL);
> +
> +	priv->bridge = of_drm_find_bridge(dai->dev->of_node);
> +
> +	dev_err(dai->dev, "%s: bridge %p\n", __func__, priv->bridge);
> +
> +	snd_soc_dai_set_drvdata(dai, priv);
> +

The call above overwrites the private data pointer of the drivers that 
registering the codec. This hardly works in general.

A separate platform driver - with this already merged patch [2] - that I 
use with my patch-set solves this issue quite nicely.

[2] http://lists.freedesktop.org/archives/dri-devel/2015-May/083517.html
> +	return 0;
> +}here are several important callbacks missing here
> +
> +static const struct snd_soc_dai_ops hdmi_drm_codec_ops = {
> +		.prepare =  hdmi_drm_dai_prepare,
> +		.trigger = hdmi_drm_dai_trigger,
> +};


At least set_daifmt() and hw_params() callbacks should be defined before 
this could be generally usable. HDMI encoders do not usually support too 
many daifmts, but the driver should be able the check that the selected 
format is supported. But as you said this not complete code yet.

> +
> +static struct snd_soc_dai_driver hdmi_drm_codec_dai = {
> +	.name = "hdmi-hifi",
> +	.playback = {
> +		.stream_name = "Playback",
> +		.channels_min = 2,
> +		.channels_max = 8,
> +		.rates = SNDRV_PCM_RATE_32000 |
> +			SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
> +			SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
> +			SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
> +		.formats = SNDRV_PCM_FMTBIT_S16_LE |
> +			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
> +		.sig_bits = 24,
> +	},11.3
> +	.probe = st_hdmi_dai_probe,
> +	.ops = &hdmi_drm_codec_ops,
> +};
> +
> +static struct snd_soc_codec_driver hdmi_drm_codec = {
> +	.dapm_widgets = hdmi_drm_widgets,
> +	.num_dapm_widgets = ARRAY_SIZE(hdmi_drm_widgets),
> +	.dapm_routes = hdmi_drm_routes,
> +	.num_dapm_routes = ARRAY_SIZE(hdmi_drm_routes),
> +	.ignore_pmdown_time = true,
> +};
> +
> +int hdmi_drm_codec_register(struct device *dev)
> +{
> +	dev_err(dev, "%s: enter", __func__);
> +	return snd_soc_register_codec(dev, &hdmi_drm_codec,
> +				      &hdmi_drm_codec_dai, 1);
> +}
> +EXPORT_SYMBOL_GPL(hdmi_drm_codec_register);
> +
> +void hdmi_drm_codec_unregister(struct device *dev)
> +{
> +	dev_err(dev, "%s: enter", __func__);
> +	snd_soc_unregister_codec(dev);
> +}
> +EXPORT_SYMBOL_GPL(hdmi_drm_codec_unregister);
> +
> +MODULE_AUTHOR("Arnaud.pouliquen@st.com");
> +MODULE_DESCRIPTION("ASoC HDMI codec driver");
> +MODULE_LICENSE("GPL");
>

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

* Re: [RFC 3/5] ASoC: codec: hdmi drm codec driver
  2015-09-25 14:11   ` Jyri Sarha
@ 2015-09-25 15:50     ` Arnaud Pouliquen
  2015-09-29 13:53       ` Jyri Sarha
  0 siblings, 1 reply; 9+ messages in thread
From: Arnaud Pouliquen @ 2015-09-25 15:50 UTC (permalink / raw)
  To: Jyri Sarha, alsa-devel, dri-devel
  Cc: moinejf, linux, Takashi Iwai, tomi.valkeinen, lgirdwood,
	peter.ujfalusi, airlied, tony, broonie, bcousson

Hello Jyri,

Yes using or not DRM bridge we should be able to have a common 
implementation

Please find,my answer belows

BR,
Arnaud

On 09/25/2015 04:11 PM, Jyri Sarha wrote:
> Despite my earlier comment this implementation and the related HW is
> quite similar in all significant aspects to the patch set posted couple
> of days ago [1] for Beaglebone-Black HDMI audio.
>
> [1] http://permalink.gmane.org/gmane.linux.alsa.devel/144144
yes i trying to align my dev on it. to match with your development.
Aim for me is to reuse it and adapt it using a DRM bridge interface.
i hope to provide a V2 next week.
>
> I have not yet gotten to bottom of drm-side audio bride part, but I am
> working on it. Bellow is couple of early comments to the ASoC part.
>
> Best regards,
> Jyri
>
> On 09/21/15 16:19, Arnaud Pouliquen wrote:
>> +
>> +static int st_hdmi_dai_probe(struct snd_soc_dai *dai)
>> +{
>> +	struct hdmi_drm_dai_data *priv;
>> +
>> +	dev_err(dai->dev, "%s: enter\n", __func__);
>> +	priv = devm_kzalloc(dai->dev, sizeof(*priv), GFP_KERNEL);
>> +
>> +	priv->bridge = of_drm_find_bridge(dai->dev->of_node);
>> +
>> +	dev_err(dai->dev, "%s: bridge %p\n", __func__, priv->bridge);
>> +
>> +	snd_soc_dai_set_drvdata(dai, priv);
>> +
>
> The call above overwrites the private data pointer of the drivers that
> registering the codec. This hardly works in general.
>
> A separate platform driver - with this already merged patch [2] - that I
> use with my patch-set solves this issue quite nicely.
>
> [2] http://lists.freedesktop.org/archives/dri-devel/2015-May/083517.html
Yes same dev,(but no crash...?).i need to define sub node.
>> +	return 0;
>> +}here are several important callbacks missing here
>> +
>> +static const struct snd_soc_dai_ops hdmi_drm_codec_ops = {
>> +		.prepare =  hdmi_drm_dai_prepare,
>> +		.trigger = hdmi_drm_dai_trigger,
>> +};
>
>
> At least set_daifmt() and hw_params() callbacks should be defined before
> this could be generally usable. HDMI encoders do not usually support too
> many daifmts, but the driver should be able the check that the selected
> format is supported. But as you said this not complete code yet.
I'm trying to match codec ops with following DRM audio bridge ops,
that is similar to the existing drm_bridge_funcs structure.
struct drm_audio_bridge_funcs {
	void (*disable)(struct drm_bridge *bridge);
	void (*post_disable)(struct drm_bridge *bridge);
	void (*pre_enable)(struct drm_bridge *bridge);
	void (*enable)(struct drm_bridge *bridge);
	int  (*mode_set)(struct drm_bridge *bridge,
			struct hdmi_audio_mode *mode);
	uint8_t *(*mode_get)(struct drm_bridge *bridge); /*return eld*/
};
audio parameters should be part of struct hdmi_audio_mode that contains 
audio configurations ( info frame,iec, format, clk...)

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

* Re: [RFC 3/5] ASoC: codec: hdmi drm codec driver
  2015-09-25 15:50     ` Arnaud Pouliquen
@ 2015-09-29 13:53       ` Jyri Sarha
  0 siblings, 0 replies; 9+ messages in thread
From: Jyri Sarha @ 2015-09-29 13:53 UTC (permalink / raw)
  To: Arnaud Pouliquen, alsa-devel, dri-devel
  Cc: moinejf, linux, Takashi Iwai, tomi.valkeinen, lgirdwood,
	peter.ujfalusi, airlied, tony, broonie, bcousson

On 09/25/15 18:50, Arnaud Pouliquen wrote:
> Hello Jyri,
>
> Yes using or not DRM bridge we should be able to have a common
> implementation
>
> Please find,my answer belows
>
> BR,
> Arnaud
>
> On 09/25/2015 04:11 PM, Jyri Sarha wrote:
>> Despite my earlier comment this implementation and the related HW is
>> quite similar in all significant aspects to the patch set posted couple
>> of days ago [1] for Beaglebone-Black HDMI audio.
>>
>> [1] http://permalink.gmane.org/gmane.linux.alsa.devel/144144
> yes i trying to align my dev on it. to match with your development.
> Aim for me is to reuse it and adapt it using a DRM bridge interface.
> i hope to provide a V2 next week.
>>
>> I have not yet gotten to bottom of drm-side audio bride part, but I am
>> working on it. Bellow is couple of early comments to the ASoC part.
>>
>> Best regards,
>> Jyri
>>
>> On 09/21/15 16:19, Arnaud Pouliquen wrote:
>>> +
>>> +static int st_hdmi_dai_probe(struct snd_soc_dai *dai)
>>> +{
>>> +    struct hdmi_drm_dai_data *priv;
>>> +
>>> +    dev_err(dai->dev, "%s: enter\n", __func__);
>>> +    priv = devm_kzalloc(dai->dev, sizeof(*priv), GFP_KERNEL);
>>> +
>>> +    priv->bridge = of_drm_find_bridge(dai->dev->of_node);
>>> +
>>> +    dev_err(dai->dev, "%s: bridge %p\n", __func__, priv->bridge);
>>> +
>>> +    snd_soc_dai_set_drvdata(dai, priv);
>>> +
>>
>> The call above overwrites the private data pointer of the drivers that
>> registering the codec. This hardly works in general.
>>
>> A separate platform driver - with this already merged patch [2] - that I
>> use with my patch-set solves this issue quite nicely.
>>
>> [2] http://lists.freedesktop.org/archives/dri-devel/2015-May/083517.html
> Yes same dev,(but no crash...?).i need to define sub node.
>>> +    return 0;
>>> +}here are several important callbacks missing here
>>> +
>>> +static const struct snd_soc_dai_ops hdmi_drm_codec_ops = {
>>> +        .prepare =  hdmi_drm_dai_prepare,
>>> +        .trigger = hdmi_drm_dai_trigger,
>>> +};
>>
>>
>> At least set_daifmt() and hw_params() callbacks should be defined before
>> this could be generally usable. HDMI encoders do not usually support too
>> many daifmts, but the driver should be able the check that the selected
>> format is supported. But as you said this not complete code yet.
> I'm trying to match codec ops with following DRM audio bridge ops,
> that is similar to the existing drm_bridge_funcs structure.

I am not yet too familiar with drm way of doing things. My code is 
trying to follow the way how ALSA does things. I tried to survive with 
as few callback as possible, but if you think more is needed I can add 
those if there is a corresponding callback in ALSA.

> struct drm_audio_bridge_funcs {
>      void (*disable)(struct drm_bridge *bridge);

There is no such thing in my HDMI codec. However, there is digital_mute 
callback that is used by alsa before the streams are shut down to avoid 
undesired pops and clicks.

>      void (*post_disable)(struct drm_bridge *bridge);

Post_disable should map more or less directly to audio_shutdown() in my 
code.

>      void (*pre_enable)(struct drm_bridge *bridge);

audio_startup() and hw_params() should both be called at pre_enable() 
phase.

>      void (*enable)(struct drm_bridge *bridge);

... or one could see hw_params() to map to enable. And there is 
digital_mute which is toggled by ALSA at this phase.

>      int  (*mode_set)(struct drm_bridge *bridge,
>              struct hdmi_audio_mode *mode);

Actually hw_params() does pretty much the same thing as set_mode(), but 
it should be called after audio_startup() has been called.

>      uint8_t *(*mode_get)(struct drm_bridge *bridge); /*return eld*/
> };

For this there is get_eld() in my HDMI codec code.

> audio parameters should be part of struct hdmi_audio_mode that contains
> audio configurations ( info frame,iec, format, clk...)
>
>

BTW, the HDMI codec is made in such a way that one can get by with only 
hw_params() and audio_shutdown(). In such an implementation hw_params() 
sets the HDMI encoder ready for receiving i2s or spdif from CPU DAI and 
audio_shutdown() disables the audio stream.

Best regards,
Jyri

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

end of thread, other threads:[~2015-09-29 13:53 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-09-21 13:19 [RFC 0/5] another generic audio hdmi codec proposal Arnaud Pouliquen
2015-09-21 13:19 ` [RFC 1/5] video: hdmi: add help function for N and CTS Arnaud Pouliquen
2015-09-21 13:19 ` [RFC 2/5] drm: add helper functions to add bridge audio capabilities Arnaud Pouliquen
2015-09-21 13:19 ` [RFC 3/5] ASoC: codec: hdmi drm codec driver Arnaud Pouliquen
2015-09-25 14:11   ` Jyri Sarha
2015-09-25 15:50     ` Arnaud Pouliquen
2015-09-29 13:53       ` Jyri Sarha
2015-09-21 13:19 ` [RFC 4/5] drm: sti: connect audio driver Arnaud Pouliquen
2015-09-21 13:19 ` [RFC 5/5] DT: sti: add audio HDMI dai link in audio card Arnaud Pouliquen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).