Re: cx18: "missing audio" for analog recordings

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 15/03/10 07:51 AM, Andy Walls wrote:
On Sun, 2010-03-14 at 22:48 -0400, Mark Lord wrote:
On 03/02/10 07:40, Andy Walls wrote:
..
after updating to the tip of the v4l2-dvb git tree last week,
I've been hitting the "no audio" on analog recordings bug much more often.

Digging through google, it appears this problem has been around as long
as the cx18 driver has existed, with no clear resolution.  Lots of people
have reported it to you before, and nobody has found a silver bullet fix.
..
Here are all the potential problem areas I can think of:

1. A/V digitizer/decoder audio detection firmware load and init.  (I've
added firmware readback verification to try and head this off.)

2. A/V digitizer decoder audio microcontroller hard reset and "soft"
reset sequencing.  (I think the cx18 driver has this wrong ATM.)

3. APU load and init.  (The double load is to fix a DTV TS stream bug on
every other APU&  CPU firmware load sequence.  The APU_AI_RESET is to
fix the audio bitrate problem on first capture after a double firmware
load.)

4. AI1 Mux setting failing when switching between the internal A/V
decoder's I2S output and the external I2S inputs.  (I thought I had this
fixed, but I don't have detailed register specs for that register - so
maybe not.)

5. A/V decoder audio clock PLL stops operating due to being programmed
out of range.  (This was a problem for 32 ksps audio a while ago, but
I'm pretty confident I have it fixed.)

6. A/V decoder analog frontend setup for SIF wrong?.  (I fixed this due
to a problen Helen Buus reported with cable TV.)

I think #2 is the real problem.  I just started to disassmble the
digitizer firmware 2 nights ago to see if I could get some insight as to
how to properly reset it.

I've got a first WAG at fixing the resets of the audio microcontroller's
resets at:

	http://linuxtv.org/hg/~awalls/cx18-audio

If it doesn't work, change the CXADEC_AUDIO_SOFT_RESET register define
from 0x810 to 0x9cc, although that may not work either.
..
Thanks for the troubleshooting and reporting.
..

Back at this again today, after a month away from it -- getting tired
of watching "Survivor" with closed-captioning instead of audio.  :)

I pulled your (Andy) repository today, and merged the cx18 audio reset
changes from it into today's tip from v4l-dvb.  Patch attached for reference.

So far, so good.  I'll keep tabs on it over time, and see if the audio
is stable, or if it still fails once in a while.

Cheers
--
Mark Lord
Real-Time Remedies Inc.
mlord@xxxxxxxxx
--- v4l-dvb-7c0b887911cf/linux/drivers/media/video/cx18/cx18-av-audio.c	2010-04-05 22:56:43.000000000 -0400
+++ patched/linux/drivers/media/video/cx18/cx18-av-audio.c	2010-03-13 22:06:55.000000000 -0500
@@ -305,14 +305,14 @@
 	struct cx18_av_state *state = &cx->av_state;
 	u8 v;
 
+	/* assert soft reset */
+	v = cx18_av_read(cx, CXADEC_AUDIO_SOFT_RESET) | 0x01;
+	cx18_av_write_expect(cx, CXADEC_AUDIO_SOFT_RESET, v, v, 0x0f);
+
 	/* stop microcontroller */
 	v = cx18_av_read(cx, 0x803) & ~0x10;
 	cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
 
-	/* assert soft reset */
-	v = cx18_av_read(cx, 0x810) | 0x01;
-	cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
-
 	/* Mute everything to prevent the PFFT! */
 	cx18_av_write(cx, 0x8d3, 0x1f);
 
@@ -330,16 +330,17 @@
 
 	set_audclk_freq(cx, state->audclk_freq);
 
-	/* deassert soft reset */
-	v = cx18_av_read(cx, 0x810) & ~0x01;
-	cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
-
 	if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
+		/* start microcontroller */
 		/* When the microcontroller detects the
 		 * audio format, it will unmute the lines */
 		v = cx18_av_read(cx, 0x803) | 0x10;
 		cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
 	}
+
+	/* deassert soft reset */
+	v = cx18_av_read(cx, CXADEC_AUDIO_SOFT_RESET) & ~0x01;
+	cx18_av_write_expect(cx, CXADEC_AUDIO_SOFT_RESET, v, v, 0x0f);
 }
 
 static int get_volume(struct cx18 *cx)
@@ -449,12 +450,13 @@
 		 * changes to the mute register. */
 		v = cx18_av_read(cx, 0x803);
 		if (mute) {
-			/* disable microcontroller */
+			/* stop microcontroller */
 			v &= ~0x10;
 			cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
+			/* mute all of Path 1 */
 			cx18_av_write(cx, 0x8d3, 0x1f);
 		} else {
-			/* enable microcontroller */
+			/* start microcontroller */
 			v |= 0x10;
 			cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
 		}
@@ -471,22 +473,29 @@
 	int retval;
 	u8 v;
 
+	/* assert soft reset */
+	v = cx18_av_read(cx, CXADEC_AUDIO_SOFT_RESET) | 0x1;
+	cx18_av_write_expect(cx, CXADEC_AUDIO_SOFT_RESET, v, v, 0x0f);
+
 	if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
+		/* stop microcontroller */
 		v = cx18_av_read(cx, 0x803) & ~0x10;
 		cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
+		/* mute all of Path 1 */
 		cx18_av_write(cx, 0x8d3, 0x1f);
 	}
-	v = cx18_av_read(cx, 0x810) | 0x1;
-	cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
 
 	retval = set_audclk_freq(cx, freq);
 
-	v = cx18_av_read(cx, 0x810) & ~0x1;
-	cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
 	if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
+		/* start microcontroller */
 		v = cx18_av_read(cx, 0x803) | 0x10;
 		cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
 	}
+
+	/* deassert soft reset */
+	v = cx18_av_read(cx, CXADEC_AUDIO_SOFT_RESET) & ~0x1;
+	cx18_av_write_expect(cx, CXADEC_AUDIO_SOFT_RESET, v, v, 0x0f);
 	return retval;
 }
 
diff -u --recursive --new-file --exclude='.*' --exclude='*.[osa]' --exclude=System.map --exclude='*.orig' --exclude='*.lds' --exclude='*.symvers' --exclude='*.mod.c' --exclude='*.ko' v4l-dvb-7c0b887911cf/linux/drivers/media/video/cx18/cx18-av-core.c patched/linux/drivers/media/video/cx18/cx18-av-core.c
--- v4l-dvb-7c0b887911cf/linux/drivers/media/video/cx18/cx18-av-core.c	2010-04-05 22:56:43.000000000 -0400
+++ patched/linux/drivers/media/video/cx18/cx18-av-core.c	2010-04-10 17:10:13.618719139 -0400
@@ -525,6 +525,10 @@
 	cx18_av_and_or(cx, 0x401, ~0x60, 0);
 	cx18_av_and_or(cx, 0x401, ~0x60, 0x60);
 
+	/* assert soft reset of audio */
+	v = cx18_av_read(cx, CXADEC_AUDIO_SOFT_RESET) | 0x01;
+	cx18_av_write_expect(cx, CXADEC_AUDIO_SOFT_RESET, v, v, 0x0f);
+
 	if (std & V4L2_STD_525_60) {
 		if (std == V4L2_STD_NTSC_M_JP) {
 			/* Japan uses EIAJ audio standard */
@@ -549,14 +553,9 @@
 		cx18_av_write_expect(cx, 0x80b, 0x03, 0x03, 0x3f);
 	}
 
-	v = cx18_av_read(cx, 0x803);
-	if (v & 0x10) {
-		/* restart audio decoder microcontroller */
-		v &= ~0x10;
-		cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
-		v |= 0x10;
-		cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
-	}
+	/* deassert soft reset of audio */
+	v = cx18_av_read(cx, CXADEC_AUDIO_SOFT_RESET) & ~0x01;
+	cx18_av_write_expect(cx, CXADEC_AUDIO_SOFT_RESET, v, v, 0x0f);
 }
 
 static int cx18_av_s_frequency(struct v4l2_subdev *sd,
diff -u --recursive --new-file --exclude='.*' --exclude='*.[osa]' --exclude=System.map --exclude='*.orig' --exclude='*.lds' --exclude='*.symvers' --exclude='*.mod.c' --exclude='*.ko' v4l-dvb-7c0b887911cf/linux/drivers/media/video/cx18/cx18-av-core.h patched/linux/drivers/media/video/cx18/cx18-av-core.h
--- v4l-dvb-7c0b887911cf/linux/drivers/media/video/cx18/cx18-av-core.h	2010-04-05 22:56:43.000000000 -0400
+++ patched/linux/drivers/media/video/cx18/cx18-av-core.h	2010-04-10 17:09:26.532890773 -0400
@@ -246,6 +246,7 @@
 
 #define CXADEC_DW8051_INT          0x80C
 #define CXADEC_GENERAL_CTL         0x810
+#define CXADEC_AUDIO_SOFT_RESET    0x810  /* 0x810 or 0x9cc ??? */
 #define CXADEC_AAGC_CTL            0x814
 #define CXADEC_IF_SRC_CTL          0x818
 #define CXADEC_ANLOG_DEMOD_CTL     0x81C
diff -u --recursive --new-file --exclude='.*' --exclude='*.[osa]' --exclude=System.map --exclude='*.orig' --exclude='*.lds' --exclude='*.symvers' --exclude='*.mod.c' --exclude='*.ko' v4l-dvb-7c0b887911cf/linux/drivers/media/video/cx18/cx18-av-firmware.c patched/linux/drivers/media/video/cx18/cx18-av-firmware.c
--- v4l-dvb-7c0b887911cf/linux/drivers/media/video/cx18/cx18-av-firmware.c	2010-04-05 22:56:43.000000000 -0400
+++ patched/linux/drivers/media/video/cx18/cx18-av-firmware.c	2010-03-13 22:06:55.000000000 -0500
@@ -142,14 +142,20 @@
 		return -EIO;
 	}
 
+	/* Disable firmware upload, keeping the 8051 in reset */
 	cx18_av_write4_expect(cx, CXADEC_DL_CTL,
 				0x03000000 | fw->size, 0x03000000, 0x13000000);
 
 	CX18_INFO_DEV(sd, "loaded %s firmware (%d bytes)\n", FWFILE, size);
 
-	if (cx18_av_verifyfw(cx, fw) == 0)
+	if (cx18_av_verifyfw(cx, fw) == 0) {
+		/* deassert soft reset */
+		v = cx18_av_read4(cx, CXADEC_AUDIO_SOFT_RESET) & ~0x01;
+		cx18_av_write4_expect(cx, CXADEC_AUDIO_SOFT_RESET, v, v, 0x0f);
+		/* deassert 8051 reset */
 		cx18_av_write4_expect(cx, CXADEC_DL_CTL,
 				0x13000000 | fw->size, 0x13000000, 0x13000000);
+	}
 
 	/* Output to the 416 */
 	cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x78000);

[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux