Subject: port-macppc/35204: snapper(4) does not set sampling rates
To: None <port-macppc-maintainer@netbsd.org, gnats-admin@netbsd.org,>
From: None <marco@ununoctium.homeunix.org>
List: netbsd-bugs
Date: 12/08/2006 00:25:01
>Number: 35204
>Category: port-macppc
>Synopsis: snapper(4) does not set sampling rates
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: port-macppc-maintainer
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Fri Dec 08 00:25:00 +0000 2006
>Originator: marcotrillo@gmail.com
>Release: NetBSD 3.1
>Organization:
>Environment:
System: NetBSD ununoctium.homeunix.org 3.1 NetBSD 3.1 (UNUNHEXIUM) #12: Thu Dec 7 23:47:51 CET 2006 marco@ununoctium.homeunix.org:/usr/src/sys/arch/macppc/compile/UNUNHEXIUM macppc
Architecture: powerpc
Machine: macppc
>Description:
When playing an audio file at a different sampling rate than 44100,
snapper(4) plays with a speed of 44100 ignoring the real rate.
However, the audio hardware supports many different rates (8000,
32000, 44100 and 48000).
The problem is that the snapper_set_rate() stuff does not
stop and restart the clock to get the new speed.
>How-To-Repeat:
Play an audio file at a different sampling rate.
For some sample files, see:
http://mail-index.netbsd.org/port-macppc/2006/12/07/0000.html
>Fix:
The following patch should fix the problem.
It works for me on NetBSD 3.1, should work on -current too.
I have only tested audio output, although input should work too.
I got the patch from Tsubai Masanari's latest versions of snapper.c
and i2s.c, available at the CVS repository:
http://cvsweb.ki.nu/mef/macppc/sys/arch/macppc/dev/
^^^^^^^^^^^^^^^^^ cut here ^^^^^^^^^^^^^^^^^^^^^^^^
Index: snapper.c
===================================================================
RCS file: /cvsroot/src/sys/arch/macppc/dev/snapper.c,v
retrieving revision 1.13
diff -u -r1.13 snapper.c
--- snapper.c 24 Sep 2006 03:47:09 -0000 1.13
+++ snapper.c 7 Dec 2006 23:02:40 -0000
@@ -1,8 +1,9 @@
/* $NetBSD: snapper.c,v 1.13 2006/09/24 03:47:09 jmcneill Exp $ */
/* Id: snapper.c,v 1.11 2002/10/31 17:42:13 tsubai Exp */
+/* Id: i2s.c,v 1.12 2005/01/15 14:32:35 tsubai Exp */
/*-
- * Copyright (c) 2002 Tsubai Masanari. All rights reserved.
+ * Copyright (c) 2002,2003 Tsubai Masanari. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -77,6 +78,7 @@
i2c_addr_t sc_deqaddr;
i2c_tag_t sc_i2c;
+ int sc_rate; /* current sampling rate */
u_int sc_vol_l;
u_int sc_vol_r;
u_int sc_treble;
@@ -113,7 +115,7 @@
int snapper_trigger_input(void *, void *, void *, int, void (*)(void *),
void *, const audio_params_t *);
void snapper_set_volume(struct snapper_softc *, int, int);
-int snapper_set_rate(struct snapper_softc *, u_int);
+int snapper_set_rate(struct snapper_softc *);
void snapper_set_treble(struct snapper_softc *, int);
void snapper_set_bass(struct snapper_softc *, int);
void snapper_write_mixers(struct snapper_softc *);
@@ -392,7 +394,7 @@
#define SNAPPER_NFORMATS 1
static const struct audio_format snapper_formats[SNAPPER_NFORMATS] = {
{NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_BE, 16, 16,
- 2, AUFMT_STEREO, 3, {8000, 44100, 48000}},
+ 2, AUFMT_STEREO, 4, {8000, 32000, 44100, 48000}},
};
static u_char *amp_mute;
@@ -409,6 +411,16 @@
#define I2S_FRAMEMATCH 0x50
#define I2S_WORDSIZE 0x60
+/* I2S_INT register definitions */
+#define I2S_INT_CLKSTOPPEND 0x01000000 /* clock-stop interrupt pending */
+
+/* FCR(0x3c) bits */
+#define I2S0CLKEN 0x1000
+#define I2S0EN 0x2000
+#define I2S1CLKEN 0x080000
+#define I2S1EN 0x100000
+#define FCR3C_BITMASK "\020\25I2S1EN\24I2S1CLKEN\16I2S0EN\15I2S0CLKEN"
+
/* TAS3004 registers */
#define DEQ_MCR1 0x01 /* Main control register 1 (1byte) */
#define DEQ_DRC 0x02 /* Dynamic range compression (6bytes?) */
@@ -782,8 +794,8 @@
}
/* Set the speed. p points HW encoding. */
- if (snapper_set_rate(sc, p->sample_rate))
- return EINVAL;
+ if (p)
+ sc->sc_rate = p->sample_rate;
return 0;
}
@@ -1120,9 +1132,14 @@
struct dbdma_command *cmd;
vaddr_t va;
int i, len, intmode;
+ int res;
DPRINTF("trigger_output %p %p 0x%x\n", start, end, bsize);
sc = h;
+
+ if ((res = snapper_set_rate(sc)) != 0)
+ return res;
+
cmd = sc->sc_odmacmd;
sc->sc_ointr = intr;
sc->sc_oarg = arg;
@@ -1170,9 +1187,14 @@
struct dbdma_command *cmd;
vaddr_t va;
int i, len, intmode;
+ int res;
DPRINTF("trigger_input %p %p 0x%x\n", start, end, bsize);
sc = h;
+
+ if ((res = snapper_set_rate(sc)) != 0)
+ return res;
+
cmd = sc->sc_idmacmd;
sc->sc_iintr = intr;
sc->sc_iarg = arg;
@@ -1343,41 +1365,43 @@
*/
int
-snapper_set_rate(struct snapper_softc *sc, u_int rate)
+snapper_set_rate(struct snapper_softc *sc)
{
- u_int reg;
+ int rate = sc->sc_rate;
+ u_int reg = 0, x;
int MCLK;
int clksrc, mdiv, sdiv;
int mclk_fs;
+ int timo;
- reg = 0;
switch (rate) {
case 8000:
- clksrc = 18432000; /* 18MHz */
+ clksrc = 18432000; /* 18MHz */
reg = CLKSRC_18MHz;
mclk_fs = 256;
break;
case 44100:
- clksrc = 45158400; /* 45MHz */
+ clksrc = 45158400; /* 45MHz */
reg = CLKSRC_45MHz;
mclk_fs = 256;
break;
+ case 32000:
case 48000:
- clksrc = 49152000; /* 49MHz */
+ clksrc = 49152000; /* 49MHz */
reg = CLKSRC_49MHz;
mclk_fs = 256;
break;
default:
- DPRINTF("snapper_set_rate: invalid rate %u\n", rate);
+ DPRINTF("snapper_set_rate: invalid rate %d\n", rate);
return EINVAL;
}
MCLK = rate * mclk_fs;
- mdiv = clksrc / MCLK; /* 4 */
- sdiv = mclk_fs / 64; /* 4 */
+ mdiv = clksrc / MCLK; /* 4 */
+ sdiv = mclk_fs / 64; /* 4 */
switch (mdiv) {
case 1:
@@ -1406,19 +1430,38 @@
break;
}
- reg |= SCLK_MASTER; /* XXX master mode */
+ reg |= SCLK_MASTER; /* XXX master mode */
reg |= SERIAL_64x;
+ x = in32rb(sc->sc_reg + I2S_FORMAT);
+ if (x == reg)
+ return 0; /* No change; do nothing. */
+
/* stereo input and output */
- DPRINTF("I2SSetDataWordSizeReg 0x%08x -> 0x%08x\n",
- in32rb(sc->sc_reg + I2S_WORDSIZE), 0x02000200);
out32rb(sc->sc_reg + I2S_WORDSIZE, 0x02000200);
- DPRINTF("I2SSetSerialFormatReg 0x%x -> 0x%x\n",
- in32rb(sc->sc_reg + I2S_FORMAT), reg);
+ /* Clear CLKSTOPPEND. */
+ out32rb(sc->sc_reg + I2S_INT, I2S_INT_CLKSTOPPEND);
+
+ x = in32rb(0x8000003c); /* FCR */
+ x &= ~I2S0CLKEN; /* XXX I2S0 */
+ out32rb(0x8000003c, x);
+
+ /* Wait until clock is stopped. */
+ for (timo = 1000; timo > 0; timo--) {
+ if (in32rb(sc->sc_reg + I2S_INT) & I2S_INT_CLKSTOPPEND)
+ goto done;
+ delay(1);
+ }
+ printf("snapper_set_rate: timeout\n");
+done:
out32rb(sc->sc_reg + I2S_FORMAT, reg);
+ x = in32rb(0x8000003c);
+ x |= I2S0CLKEN;
+ out32rb(0x8000003c, x);
+
return 0;
}
@@ -1666,14 +1709,6 @@
return -1;
}
-/* FCR(0x3c) bits */
-#define I2S0CLKEN 0x1000
-#define I2S0EN 0x2000
-#define I2S1CLKEN 0x080000
-#define I2S1EN 0x100000
-
-#define FCR3C_BITMASK "\020\25I2S1EN\24I2S1CLKEN\16I2S0EN\15I2S0CLKEN"
-
void
snapper_init(struct snapper_softc *sc, int node)
{
@@ -1734,8 +1769,7 @@
intr_establish(headphone_detect_intr, IST_EDGE, IPL_AUDIO,
snapper_cint, sc);
- /* "sample-rates" (44100, 48000) */
- snapper_set_rate(sc, 44100);
+ sc->sc_rate = 44100; /* default rate */
/* Enable headphone interrupt? */
*headphone_detect |= 0x80;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ CUT HERE ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^