[PATCH] [UBUNTU:sound/pci/] Fix detection of SIS7012 tertiary codec for intel8x0

crimsun at fungus.sh.nu crimsun at fungus.sh.nu
Mon Apr 10 22:54:42 UTC 2006


Subject: [PATCH] [UBUNTU:sound/pci/] Fix detection of SIS7012 tertiary codec for intel8x0

UpstreamStatus: Added in upstream pci/intel8x0.c r1.23[36]

Takashi Iwai applied these fixes for detection of newer SIS7012
chipsets that can have 3 codecs (ICH has 2) and for Mike Gorchak's
<lestat at i.com.ua> discovery that some "hardware requires time to reset
bus master registers".

The SIS7012 fix closes LP#5844.

Signed-off-by: Daniel T Chen <crimsun at ubuntu.com>

---

 sound/pci/intel8x0.c |  154 ++++++++++++++++++++++++++++++++------------------
 1 files changed, 98 insertions(+), 56 deletions(-)

e951d0b9d76b76517ec62781adcb3ab0a156bab3
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index ac6fd77..47e80d8 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -178,6 +178,8 @@ DEFINE_REGSET(SP, 0x60);	/* SPDIF out */
 #define   ICH_SAMPLE_CAP	0x00c00000	/* ICH4: sample capability bits (RO) */
 #define   ICH_SAMPLE_16_20	0x00400000	/* ICH4: 16- and 20-bit samples */
 #define   ICH_MULTICHAN_CAP	0x00300000	/* ICH4: multi-channel capability bits (RO) */
+#define   ICH_SIS_TRI		0x00080000	/* SIS: tertiary resume irq */
+#define   ICH_SIS_TCR		0x00040000	/* SIS: tertiary codec ready */
 #define   ICH_MD3		0x00020000	/* modem power down semaphore */
 #define   ICH_AD3		0x00010000	/* audio power down semaphore */
 #define   ICH_RCS		0x00008000	/* read completion status */
@@ -377,6 +379,10 @@ struct _snd_intel8x0 {
 	ac97_bus_t *ac97_bus;
 	ac97_t *ac97[3];
 	unsigned int ac97_sdin[3];
+	unsigned int max_codecs, ncodecs;
+	unsigned int *codec_bit;
+	unsigned int codec_isr_bits;
+	unsigned int codec_ready_bits;
 
 	spinlock_t reg_lock;
 	
@@ -495,18 +501,6 @@ static void iaputword(intel8x0_t *chip, 
  * access to AC97 codec via normal i/o (for ICH and SIS7012)
  */
 
-/* return the GLOB_STA bit for the corresponding codec */
-static unsigned int get_ich_codec_bit(intel8x0_t *chip, unsigned int codec)
-{
-	static unsigned int codec_bit[3] = {
-		ICH_PCR, ICH_SCR, ICH_TCR
-	};
-	snd_assert(codec < 3, return ICH_PCR);
-	if (chip->device_type == DEVICE_INTEL_ICH4)
-		codec = chip->ac97_sdin[codec];
-	return codec_bit[codec];
-}
-
 static int snd_intel8x0_codec_semaphore(intel8x0_t *chip, unsigned int codec)
 {
 	int time;
@@ -516,9 +510,9 @@ static int snd_intel8x0_codec_semaphore(
 	if (chip->in_sdin_init) {
 		/* we don't know the ready bit assignment at the moment */
 		/* so we check any */
-		codec = ICH_PCR | ICH_SCR | ICH_TCR;
+		codec = chip->codec_isr_bits;
 	} else {
-		codec = get_ich_codec_bit(chip, codec);
+		codec = chip->codec_bit[chip->ac97_sdin[codec]];
 	}
 
 	/* codec ready ? */
@@ -574,7 +568,8 @@ static unsigned short snd_intel8x0_codec
 		res = iagetword(chip, reg + ac97->num * 0x80);
 		if ((tmp = igetdword(chip, ICHREG(GLOB_STA))) & ICH_RCS) {
 			/* reset RCS and preserve other R/WC bits */
-			iputdword(chip, ICHREG(GLOB_STA), tmp & ~(ICH_SRI|ICH_PRI|ICH_TRI|ICH_GSCI));
+			iputdword(chip, ICHREG(GLOB_STA), tmp &
+					~(chip->codec_ready_bits | ICH_GSCI));
 			if (! chip->in_ac97_init)
 				snd_printk(KERN_ERR "codec_read %d: read timeout for register 0x%x\n", ac97->num, reg);
 			res = 0xffff;
@@ -583,7 +578,7 @@ static unsigned short snd_intel8x0_codec
 	return res;
 }
 
-static void snd_intel8x0_codec_read_test(intel8x0_t *chip, unsigned int codec)
+static void __devinit snd_intel8x0_codec_read_test(intel8x0_t *chip, unsigned int codec)
 {
 	unsigned int tmp;
 
@@ -591,7 +586,8 @@ static void snd_intel8x0_codec_read_test
 		iagetword(chip, codec * 0x80);
 		if ((tmp = igetdword(chip, ICHREG(GLOB_STA))) & ICH_RCS) {
 			/* reset RCS and preserve other R/WC bits */
-			iputdword(chip, ICHREG(GLOB_STA), tmp & ~(ICH_SRI|ICH_PRI|ICH_TRI|ICH_GSCI));
+			iputdword(chip, ICHREG(GLOB_STA), tmp &
+					~(chip->codec_ready_bits | ICH_GSCI));
 		}
 	}
 }
@@ -2027,23 +2023,24 @@ static int __devinit snd_intel8x0_mixer(
 	if (chip->device_type != DEVICE_ALI) {
 		glob_sta = igetdword(chip, ICHREG(GLOB_STA));
 		ops = &standard_bus_ops;
-		if (chip->device_type == DEVICE_INTEL_ICH4) {
-			codecs = 0;
-			if (glob_sta & ICH_PCR)
-				codecs++;
-			if (glob_sta & ICH_SCR)
-				codecs++;
-			if (glob_sta & ICH_TCR)
-				codecs++;
-			chip->in_sdin_init = 1;
-			for (i = 0; i < codecs; i++) {
-				snd_intel8x0_codec_read_test(chip, i);
-				chip->ac97_sdin[i] = igetbyte(chip, ICHREG(SDM)) & ICH_LDI_MASK;
-			}
-			chip->in_sdin_init = 0;
-		} else {
-			codecs = glob_sta & ICH_SCR ? 2 : 1;
-		}
+		chip->in_sdin_init = 1;
+		codecs = 0;
+		for (i = 0; i < chip->max_codecs; i++) {
+			if (! (glob_sta & chip->codec_bit[i]))
+				continue;
+			if (chip->device_type == DEVICE_INTEL_ICH4) {
+				snd_intel8x0_codec_read_test(chip, codecs);
+				chip->ac97_sdin[codecs] =
+					igetbyte(chip, ICHREG(SDM)) & ICH_LDI_MASK;
+				snd_assert(chip->ac97_sdin[codecs] < 3,
+					   chip->ac97_sdin[codecs] = 0);
+			} else
+				chip->ac97_sdin[codecs] = i;
+			codecs++;
+		}
+		chip->in_sdin_init = 0;
+		if (! codecs)
+			codecs = 1;
 	} else {
 		ops = &ali_bus_ops;
 		codecs = 1;
@@ -2069,6 +2066,7 @@ static int __devinit snd_intel8x0_mixer(
 	else
 		pbus->dra = 1;
 	chip->ac97_bus = pbus;
+	chip->ncodecs = codecs;
 
 	ac97.pci = chip->pci;
 	for (i = 0; i < codecs; i++) {
@@ -2214,7 +2212,8 @@ static int snd_intel8x0_ich_chip_init(in
 		 */
 		end_time = jiffies + HZ;
 		do {
-			status = igetdword(chip, ICHREG(GLOB_STA)) & (ICH_PCR | ICH_SCR | ICH_TCR);
+			status = igetdword(chip, ICHREG(GLOB_STA)) &
+				chip->codec_isr_bits;
 			if (status)
 				break;
 			do_delay(chip);
@@ -2225,31 +2224,27 @@ static int snd_intel8x0_ich_chip_init(in
 			return -EIO;
 		}
 
-		if (chip->device_type == DEVICE_INTEL_ICH4)
-			/* ICH4 can have three codecs */
-			nstatus = ICH_PCR | ICH_SCR | ICH_TCR;
-		else
-			/* others up to two codecs */
-			nstatus = ICH_PCR | ICH_SCR;
-
 		/* wait for other codecs ready status. */
 		end_time = jiffies + HZ / 4;
-		while (status != nstatus && time_after_eq(end_time, jiffies)) {
+		while (status != chip->codec_isr_bits &&
+			time_after_eq(end_time, jiffies)) {
 			do_delay(chip);
-			status |= igetdword(chip, ICHREG(GLOB_STA)) & nstatus;
+			status |= igetdword(chip, ICHREG(GLOB_STA)) &
+				chip->codec_isr_bits;
 		}
 
 	} else {
 		/* resume phase */
 		int i;
 		status = 0;
-		for (i = 0; i < 3; i++)
+		for (i = 0; i < chip->ncodecs; i++)
 			if (chip->ac97[i])
-				status |= get_ich_codec_bit(chip, i);
+				status |= chip->codec_bit[chip->ac97_sdin[i]];
 		/* wait until all the probed codecs are ready */
 		end_time = jiffies + HZ;
 		do {
-			nstatus = igetdword(chip, ICHREG(GLOB_STA)) & (ICH_PCR | ICH_SCR | ICH_TCR);
+			nstatus = igetdword(chip, ICHREG(GLOB_STA)) &
+				chip->codec_isr_bits;
 			if (status == nstatus)
 				break;
 			do_delay(chip);
@@ -2307,7 +2302,7 @@ static int snd_intel8x0_ali_chip_init(in
 
 static int snd_intel8x0_chip_init(intel8x0_t *chip, int probing)
 {
-	unsigned int i;
+	unsigned int i, timeout;
 	int err;
 	
 	if (chip->device_type != DEVICE_ALI) {
@@ -2325,6 +2320,15 @@ static int snd_intel8x0_chip_init(intel8
 	/* reset channels */
 	for (i = 0; i < chip->bdbars_count; i++)
 		iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, ICH_RESETREGS);
+	for (i = 0; i < chip->bdbars_count; i++) {
+	        timeout = 100000;
+	        while (--timeout != 0) {
+        		if ((igetbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset) & ICH_RESETREGS) == 0)
+        		        break;
+                }
+                if (timeout == 0)
+                        printk(KERN_ERR "intel8x0: reset of registers failed?\n");
+        }
 	/* initialize Buffer Descriptor Lists */
 	for (i = 0; i < chip->bdbars_count; i++)
 		iputdword(chip, ICH_REG_OFF_BDBAR + chip->ichd[i].reg_offset, chip->ichd[i].bdbar_addr);
@@ -2392,7 +2396,7 @@ static int intel8x0_suspend(snd_card_t *
 			}
 		}
 	}
-	for (i = 0; i < 3; i++)
+	for (i = 0; i < chip->ncodecs; i++)
 		if (chip->ac97[i])
 			snd_ac97_suspend(chip->ac97[i]);
 	if (chip->device_type == DEVICE_INTEL_ICH4)
@@ -2429,7 +2433,7 @@ static int intel8x0_resume(snd_card_t *c
 	if (chip->fix_nocache)
 		fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 1);
 
-	for (i = 0; i < 3; i++)
+	for (i = 0; i < chip->ncodecs; i++)
 		if (chip->ac97[i])
 			snd_ac97_resume(chip->ac97[i]);
 
@@ -2559,12 +2563,20 @@ static void snd_intel8x0_proc_read(snd_i
 	snd_iprintf(buffer, "Global status         : 0x%08x\n", tmp);
 	if (chip->device_type == DEVICE_INTEL_ICH4)
 		snd_iprintf(buffer, "SDM                   : 0x%08x\n", igetdword(chip, ICHREG(SDM)));
-	snd_iprintf(buffer, "AC'97 codecs ready    :%s%s%s%s\n",
-			tmp & ICH_PCR ? " primary" : "",
-			tmp & ICH_SCR ? " secondary" : "",
-			tmp & ICH_TCR ? " tertiary" : "",
-			(tmp & (ICH_PCR | ICH_SCR | ICH_TCR)) == 0 ? " none" : "");
-	if (chip->device_type == DEVICE_INTEL_ICH4)
+	snd_iprintf(buffer, "AC'97 codecs ready    :");
+	if (tmp & chip->codec_isr_bits) {
+		int i;
+		static const char *codecs[3] = {
+			"primary", "secondary", "tertiary"
+		};
+		for (i = 0; i < chip->max_codecs; i++)
+			if (tmp & chip->codec_bit[i])
+				snd_iprintf(buffer, " %s", codecs[i]);
+	} else
+		snd_iprintf(buffer, " none");
+	snd_iprintf(buffer, "\n");
+	if (chip->device_type == DEVICE_INTEL_ICH4 ||
+	    chip->device_type == DEVICE_SIS)
 		snd_iprintf(buffer, "AC'97 codecs SDIN     : %i %i %i\n",
 			chip->ac97_sdin[0],
 			chip->ac97_sdin[1],
@@ -2590,6 +2602,13 @@ struct ich_reg_info {
 	unsigned int offset;
 };
 
+static unsigned int ich_codec_bits[3] = {
+	ICH_PCR, ICH_SCR, ICH_TCR
+};
+static unsigned int sis_codec_bits[3] = {
+	ICH_PCR, ICH_SCR, ICH_SIS_TCR
+};
+
 static int __devinit snd_intel8x0_create(snd_card_t * card,
 					 struct pci_dev *pci,
 					 unsigned long device_type,
@@ -2772,6 +2791,29 @@ static int __devinit snd_intel8x0_create
 	pci_set_master(pci);
 	synchronize_irq(chip->irq);
 
+	switch(chip->device_type) {
+	case DEVICE_INTEL_ICH4:
+		/* ICH4 can have three codecs */
+		chip->max_codecs = 3;
+		chip->codec_bit = ich_codec_bits;
+		chip->codec_ready_bits = ICH_PRI | ICH_SRI | ICH_TRI;
+		break;
+	case DEVICE_SIS:
+		/* recent SIS7012 can have three codecs */
+		chip->max_codecs = 3;
+		chip->codec_bit = sis_codec_bits;
+		chip->codec_ready_bits = ICH_PRI | ICH_SRI | ICH_SIS_TRI;
+		break;
+	default:
+		/* others up to two codecs */
+		chip->max_codecs = 2;
+		chip->codec_bit = ich_codec_bits;
+		chip->codec_ready_bits = ICH_PRI | ICH_SRI;
+		break;
+	}
+	for (i = 0; i < chip->max_codecs; i++)
+		chip->codec_isr_bits |= chip->codec_bit[i];
+
 	if ((err = snd_intel8x0_chip_init(chip, 1)) < 0) {
 		snd_intel8x0_free(chip);
 		return err;
-- 
1.1.3


-- 
Daniel T. Chen            crimsun at ubuntu.com
GPG key:   www.sh.nu/~crimsun/pubkey.gpg.asc
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
URL: <https://lists.ubuntu.com/archives/kernel-team/attachments/20060410/4098102c/attachment.sig>


More information about the kernel-team mailing list