Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 25 Jun 2005 14:00:50 +0400
From:      Gleb Smirnoff <glebius@FreeBSD.org>
To:        Doug White <dwhite@gumbysoft.com>
Cc:        current@FreeBSD.org
Subject:   Re: who can review&commit kern/82243?
Message-ID:  <20050625100050.GA80864@cell.sick.ru>
In-Reply-To: <20050624212829.E47411@carver.gumbysoft.com>
References:  <20050624073400.GA70323@cell.sick.ru> <20050624212829.E47411@carver.gumbysoft.com>

next in thread | previous in thread | raw e-mail | index | archive | help

--2fHTh5uZTiUOsy+g
Content-Type: text/plain; charset=koi8-r
Content-Disposition: inline

On Fri, Jun 24, 2005 at 09:28:57PM -0700, Doug White wrote:
D> > recently a patch making csa(4) suspend/resume working. I have tested
D> > it on my notebook and it works perfectly.
D> >
D> > The patch is attached (with small style editing from me) to this message.
D> 
D> The #defines should be placed in csareg.h if they define positions or
D> values for the chip registers. Otherwise they belong in csavar.h.

Yes, this is true. Here is updated patch, with more style issues resolved
and defines moved.

-- 
Totus tuus, Glebius.
GLEBIUS-RIPN GLEB-RIPE

--2fHTh5uZTiUOsy+g
Content-Type: text/plain; charset=koi8-r
Content-Disposition: attachment; filename="csa.diff"

Index: csa.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/sound/pci/csa.c,v
retrieving revision 1.32
diff -u -r1.32 csa.c
--- csa.c	1 Mar 2005 08:58:05 -0000	1.32
+++ csa.c	25 Jun 2005 09:32:46 -0000
@@ -87,7 +87,6 @@
 			     struct resource *irq, void *cookie);
 static driver_intr_t csa_intr;
 static int csa_initialize(sc_p scp);
-static void csa_resetdsp(csa_res *resp);
 static int csa_downloadimage(csa_res *resp);
 
 static devclass_t csa_devclass;
@@ -366,15 +365,24 @@
 static int
 csa_resume(device_t dev)
 {
-#if 0
-	/*
-	 * XXX: this cannot possibly work
-	 * needs to be properly implemented
-	 */
-	csa_detach(dev);
-	csa_attach(dev);
-#endif
-	return 0;
+	csa_res *resp;
+	sc_p scp;
+
+	scp = device_get_softc(dev);
+	resp = &scp->res;
+
+	/* Initialize the chip. */
+	if (csa_initialize(scp))
+		return (ENXIO);
+
+	/* Reset the Processor. */
+	csa_resetdsp(resp);
+
+	/* Download the Processor Image to the processor. */
+	if (csa_downloadimage(resp))
+		return (ENXIO);
+
+	return (bus_generic_resume(dev));
 }
 
 static struct resource *
@@ -794,7 +802,7 @@
 		csa_writeio(resp, BA0_CLKCR1, clkcr1);
 }
 
-static void
+void
 csa_resetdsp(csa_res *resp)
 {
 	int i;
Index: csapcm.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/sound/pci/csapcm.c,v
retrieving revision 1.33
diff -u -r1.33 csapcm.c
--- csapcm.c	6 Jan 2005 01:43:19 -0000	1.33
+++ csapcm.c	25 Jun 2005 09:32:35 -0000
@@ -70,6 +70,9 @@
 	u_long		pctl;
 	u_long		cctl;
 	struct csa_chinfo pch, rch;
+	u_int32_t	ac97[CS461x_AC97_NUMBER_RESTORE_REGS];
+	u_int32_t	ac97_powerdown;
+	u_int32_t	ac97_general_purpose;
 };
 
 /* -------------------------------------------------------------------- */
@@ -84,8 +87,11 @@
 static void	csa_stopplaydma(struct csa_info *csa);
 static void	csa_stopcapturedma(struct csa_info *csa);
 static int	csa_startdsp(csa_res *resp);
+static int	csa_stopdsp(csa_res *resp);
 static int	csa_allocres(struct csa_info *scp, device_t dev);
 static void	csa_releaseres(struct csa_info *scp, device_t dev);
+static void	csa_ac97_suspend(struct csa_info *csa);
+static void	csa_ac97_resume(struct csa_info *csa);
 
 static u_int32_t csa_playfmt[] = {
 	AFMT_U8,
@@ -112,16 +118,16 @@
 static int
 csa_active(struct csa_info *csa, int run)
 {
-	int old, go;
+	int old;
 
 	old = csa->active;
 	csa->active += run;
 
-	if ((csa->active == 0 && old == 1) || (csa->active == 1 && old == 0)) {
-		go = csa->active;
-		if (csa->card->active)
-			return csa->card->active(go);
-	}
+	if ((csa->active > 1) || (csa->active < -1))
+		csa->active = 0;
+	if (csa->card->active)
+		return (csa->card->active(!(csa->active && old)));
+
 	return 0;
 }
 
@@ -455,6 +461,18 @@
 }
 
 static int
+csa_stopdsp(csa_res *resp)
+{
+	/*
+	 * Turn off the run, run at frame, and DMA enable bits in
+	 * the local copy of the SP control register.
+	 */
+	csa_writemem(resp, BA1_SPCR, 0);
+
+	return (0);
+}
+
+static int
 csa_setupchan(struct csa_chinfo *ch)
 {
 	struct csa_info *csa = ch->parent;
@@ -833,11 +851,169 @@
 	return 0;
 }
 
+static void
+csa_ac97_suspend(struct csa_info *csa)
+{
+	int count, i;
+	uint32_t tmp;
+
+	for (count = 0x2, i=0;
+	    (count <= CS461x_AC97_HIGHESTREGTORESTORE) &&
+	    (i < CS461x_AC97_NUMBER_RESTORE_REGS);
+	    count += 2, i++)
+		csa_readcodec(&csa->res, BA0_AC97_RESET + count, &csa->ac97[i]);
+
+	/* mute the outputs */
+	csa_writecodec(&csa->res, BA0_AC97_MASTER_VOLUME, 0x8000);
+	csa_writecodec(&csa->res, BA0_AC97_HEADPHONE_VOLUME, 0x8000);
+	csa_writecodec(&csa->res, BA0_AC97_MASTER_VOLUME_MONO, 0x8000);
+	csa_writecodec(&csa->res, BA0_AC97_PCM_OUT_VOLUME, 0x8000);
+	/* save the registers that cause pops */
+	csa_readcodec(&csa->res, BA0_AC97_POWERDOWN, &csa->ac97_powerdown);
+	csa_readcodec(&csa->res, BA0_AC97_GENERAL_PURPOSE,
+	    &csa->ac97_general_purpose);
+
+	/*
+	 * And power down everything on the AC97 codec. Well, for now,
+	 * only power down the DAC/ADC and MIXER VREFON components.
+	 * trouble with removing VREF.
+	 */
+
+	/* MIXVON */
+	csa_readcodec(&csa->res, BA0_AC97_POWERDOWN, &tmp);
+	csa_writecodec(&csa->res, BA0_AC97_POWERDOWN,
+	    tmp | CS_AC97_POWER_CONTROL_MIXVON);
+	/* ADC */
+	csa_readcodec(&csa->res, BA0_AC97_POWERDOWN, &tmp);
+	csa_writecodec(&csa->res, BA0_AC97_POWERDOWN,
+	    tmp | CS_AC97_POWER_CONTROL_ADC);
+	/* DAC */
+	csa_readcodec(&csa->res, BA0_AC97_POWERDOWN, &tmp);
+	csa_writecodec(&csa->res, BA0_AC97_POWERDOWN,
+	    tmp | CS_AC97_POWER_CONTROL_DAC);
+}
+
+static void
+csa_ac97_resume(struct csa_info *csa)
+{
+	int count, i;
+
+	/*
+	 * First, we restore the state of the general purpose register.  This
+	 * contains the mic select (mic1 or mic2) and if we restore this after
+	 * we restore the mic volume/boost state and mic2 was selected at
+	 * suspend time, we will end up with a brief period of time where mic1
+	 * is selected with the volume/boost settings for mic2, causing
+	 * acoustic feedback.  So we restore the general purpose register
+	 * first, thereby getting the correct mic selected before we restore
+	 * the mic volume/boost.
+	 */
+	csa_writecodec(&csa->res, BA0_AC97_GENERAL_PURPOSE,
+	    csa->ac97_general_purpose);
+	/*
+	 * Now, while the outputs are still muted, restore the state of power
+	 * on the AC97 part.
+	 */
+	csa_writecodec(&csa->res, BA0_AC97_POWERDOWN, csa->ac97_powerdown);
+	/*
+	 * Restore just the first set of registers, from register number
+	 * 0x02 to the register number that ulHighestRegToRestore specifies.
+	 */
+	for (count = 0x2, i=0;
+	    (count <= CS461x_AC97_HIGHESTREGTORESTORE) &&
+	    (i < CS461x_AC97_NUMBER_RESTORE_REGS);
+	    count += 2, i++)
+		csa_writecodec(&csa->res, BA0_AC97_RESET + count, csa->ac97[i]);
+}
+
+static int
+pcmcsa_suspend(device_t dev)
+{
+	struct csa_info *csa;
+	csa_res *resp;
+
+	csa = pcm_getdevinfo(dev);
+	resp = &csa->res;
+
+	csa_active(csa, 1);
+
+	/* playback interrupt disable */
+	csa_writemem(resp, BA1_PFIE,
+	    (csa_readmem(resp, BA1_PFIE) & ~0x0000f03f) | 0x00000010);
+	/* capture interrupt disable */
+	csa_writemem(resp, BA1_CIE,
+	    (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000011);
+	csa_stopplaydma(csa);
+	csa_stopcapturedma(csa);
+
+	csa_ac97_suspend(csa);
+
+	csa_resetdsp(resp);
+
+	csa_stopdsp(resp);
+	/*
+	 *  Power down the DAC and ADC.  For now leave the other areas on.
+	 */
+	csa_writecodec(&csa->res, BA0_AC97_POWERDOWN, 0x300);
+	/*
+	 *  Power down the PLL.
+	 */
+	csa_writemem(resp, BA0_CLKCR1, 0);
+	/*
+	 * Turn off the Processor by turning off the software clock
+	 * enable flag in the clock control register.
+	 */
+	csa_writemem(resp, BA0_CLKCR1,
+	    csa_readmem(resp, BA0_CLKCR1) & ~CLKCR1_SWCE);
+
+	csa_active(csa, -1);
+
+	return 0;
+}
+
+static int
+pcmcsa_resume(device_t dev)
+{
+	struct csa_info *csa;
+	csa_res *resp;
+
+	csa = pcm_getdevinfo(dev);
+	resp = &csa->res;
+
+	csa_active(csa, 1);
+
+	/* cs_hardware_init */
+	csa_stopplaydma(csa);
+	csa_stopcapturedma(csa);
+	csa_ac97_resume(csa);
+	if (csa_startdsp(resp))
+		return (ENXIO);
+	/* Enable interrupts on the part. */
+	if ((csa_readio(resp, BA0_HISR) & HISR_INTENA) == 0)
+		csa_writeio(resp, BA0_HICR, HICR_IEV | HICR_CHGM);
+	/* playback interrupt enable */
+	csa_writemem(resp, BA1_PFIE, csa_readmem(resp, BA1_PFIE) & ~0x0000f03f);
+	/* capture interrupt enable */
+	csa_writemem(resp, BA1_CIE,
+	    (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000001);
+	/* cs_restart_part */
+	csa_setupchan(&csa->pch);
+	csa_startplaydma(csa);
+	csa_setupchan(&csa->rch);
+	csa_startcapturedma(csa);
+
+	csa_active(csa, -1);
+
+	return 0;
+}
+
 static device_method_t pcmcsa_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe , pcmcsa_probe ),
 	DEVMETHOD(device_attach, pcmcsa_attach),
 	DEVMETHOD(device_detach, pcmcsa_detach),
+	DEVMETHOD(device_suspend, pcmcsa_suspend),
+	DEVMETHOD(device_resume, pcmcsa_resume),
 
 	{ 0, 0 },
 };
Index: csareg.h
===================================================================
RCS file: /home/ncvs/src/sys/dev/sound/pci/csareg.h,v
retrieving revision 1.3
diff -u -r1.3 csareg.h
--- csareg.h	30 May 2001 22:38:31 -0000	1.3
+++ csareg.h	25 Jun 2005 09:18:25 -0000
@@ -1931,6 +1931,24 @@
 #define BA1_CCST                0x13c    /* BA1_CAPTURE_CONSTANT_REG */
 #define BA1_CSPB                0x340    /* BA1_CAPTURE_SPB_ADDRESS */
 
+/* PM state definitions */
+#define CS461x_AC97_HIGHESTREGTORESTORE	0x26
+#define CS461x_AC97_NUMBER_RESTORE_REGS	(CS461x_AC97_HIGHESTREGTORESTORE/2-1)
+
+#define CS_POWER_DAC			0x0001
+#define CS_POWER_ADC			0x0002
+#define CS_POWER_MIXVON			0x0004
+#define CS_POWER_MIXVOFF		0x0008
+#define CS_AC97_POWER_CONTROL_ON	0xf000	/* always on bits (inverted) */
+#define CS_AC97_POWER_CONTROL_ADC	0x0100
+#define CS_AC97_POWER_CONTROL_DAC	0x0200
+#define CS_AC97_POWER_CONTROL_MIXVON	0x0400
+#define CS_AC97_POWER_CONTROL_MIXVOFF	0x0800
+#define CS_AC97_POWER_CONTROL_ADC_ON	0x0001
+#define CS_AC97_POWER_CONTROL_DAC_ON	0x0002
+#define CS_AC97_POWER_CONTROL_MIXVON_ON	0x0004
+#define CS_AC97_POWER_CONTROL_MIXVOFF_ON 0x0008
+
 /* The following struct holds the initialization array. */
 
 /*
Index: csavar.h
===================================================================
RCS file: /home/ncvs/src/sys/dev/sound/pci/csavar.h,v
retrieving revision 1.4
diff -u -r1.4 csavar.h
--- csavar.h	23 Jun 2001 18:00:06 -0000	1.4
+++ csavar.h	23 Jun 2005 19:42:44 -0000
@@ -66,4 +66,5 @@
 u_int32_t csa_readmem(csa_res *resp, u_long offset);
 void csa_writemem(csa_res *resp, u_long offset, u_int32_t data);
 
+void csa_resetdsp(csa_res *resp);
 #endif /* _CSA_VAR_H */

--2fHTh5uZTiUOsy+g--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20050625100050.GA80864>