[PATCH 162/222] dw-hdmi-audio: try implementing ERR005174 to fix burbling audio

Russell King rmk+kernel at arm.linux.org.uk
Fri Apr 25 04:48:06 PDT 2014


Signed-off-by: Russell King <rmk+kernel at arm.linux.org.uk>
---
 drivers/staging/imx-drm/dw-hdmi-audio.c | 35 +++++++++++++++++++++++++++------
 1 file changed, 29 insertions(+), 6 deletions(-)

diff --git a/drivers/staging/imx-drm/dw-hdmi-audio.c b/drivers/staging/imx-drm/dw-hdmi-audio.c
index 05fe6024fe17..f70fe00f9c41 100644
--- a/drivers/staging/imx-drm/dw-hdmi-audio.c
+++ b/drivers/staging/imx-drm/dw-hdmi-audio.c
@@ -7,6 +7,7 @@
  *
  * Written and tested against the (alleged) DW HDMI Tx found in iMX6S.
  */
+#include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
@@ -68,6 +69,8 @@ enum {
 	HDMI_AHB_DMA_THRSLD = 0x3603,
 	HDMI_AHB_DMA_STRADDR0 = 0x3604,
 	HDMI_AHB_DMA_STPADDR0 = 0x3608,
+	HDMI_AHB_DMA_STAT = 0x3612,
+	HDMI_AHB_DMA_STAT_FULL = BIT(1),
 	HDMI_AHB_DMA_MASK = 0x3614,
 	HDMI_AHB_DMA_POL = 0x3615,
 	HDMI_AHB_DMA_CONF1 = 0x3616,
@@ -473,20 +476,40 @@ static int dw_hdmi_prepare(struct snd_pcm_substream *substream)
 static int dw_hdmi_trigger(struct snd_pcm_substream *substream, int cmd)
 {
 	struct snd_dw_hdmi *dw = substream->private_data;
-	int ret = 0;
+	void __iomem *base = dw->data.base;
+	unsigned val[3];
+	unsigned timeout = 10000;
+	int ret = 0, i;
+	bool err005174;
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
+		err005174 = dw->revision == 0x0a;
+		if (err005174) {
+			for (i = 2; i >= 0; i--) {
+				val[i] = readb_relaxed(base + HDMI_AUD_N1 + i);
+				writeb_relaxed(0, base + HDMI_AUD_N1 + i);
+			}
+		}
+
 		dw->buf_offset = 0;
 		dw->substream = substream;
 		dw_hdmi_start_dma(dw);
-		if (dw->revision == 0x0a) {
-			void __iomem *base = dw->data.base;
-			unsigned val;
 
-			val = readb_relaxed(base + HDMI_AUD_N1);
-			writeb_relaxed(val, base + HDMI_AUD_N1);
+		if (err005174) {
+			do {
+				if (readb_relaxed(base + HDMI_AHB_DMA_STAT) & HDMI_AHB_DMA_STAT_FULL)
+					break;
+				udelay(1);
+			} while (timeout--);
+
+			if (!(readb_relaxed(base + HDMI_AHB_DMA_STAT) & HDMI_AHB_DMA_STAT_FULL))
+				pr_info("timeout!\n");
+
+			for (i = 2; i >= 0; i--)
+				writeb_relaxed(val[i], base + HDMI_AUD_N1 + i);
 		}
+
 		substream->runtime->delay = substream->runtime->period_size;
 		break;
 
-- 
1.8.3.1




More information about the linux-arm-kernel mailing list