Module Name:    src
Committed By:   macallan
Date:           Fri Sep 20 21:24:34 UTC 2019

Modified Files:
        src/sys/arch/macppc/dev: snapper.c

Log Message:
various minor fixes and updates:
- add (very) basic ONYX support. Treat as 16bit codec with software volume
  control. Makes basic audio work on PCIe G5
- correctly detect TAS3001 without 'compatible' property, now this works on
  Quicksilver
- mute line input on TAS3001 - it's unconnected on Quicksilver and causes noise
- make more of an effort to match codecs to i2sbus instances, needed on G5 and
  some other models with software 'modems'


To generate a diff of this commit:
cvs rdiff -u -r1.52 -r1.53 src/sys/arch/macppc/dev/snapper.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/macppc/dev/snapper.c
diff -u src/sys/arch/macppc/dev/snapper.c:1.52 src/sys/arch/macppc/dev/snapper.c:1.53
--- src/sys/arch/macppc/dev/snapper.c:1.52	Sat Jun  8 08:02:37 2019
+++ src/sys/arch/macppc/dev/snapper.c	Fri Sep 20 21:24:34 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: snapper.c,v 1.52 2019/06/08 08:02:37 isaki Exp $	*/
+/*	$NetBSD: snapper.c,v 1.53 2019/09/20 21:24:34 macallan 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		*/
 
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: snapper.c,v 1.52 2019/06/08 08:02:37 isaki Exp $");
+__KERNEL_RCSID(0, "$NetBSD: snapper.c,v 1.53 2019/09/20 21:24:34 macallan Exp $");
 
 #include <sys/param.h>
 #include <sys/audioio.h>
@@ -55,7 +55,7 @@ __KERNEL_RCSID(0, "$NetBSD: snapper.c,v 
 
 #include <macppc/dev/deqvar.h>
 #include <macppc/dev/obiovar.h>
-
+//#define SNAPPER_DEBUG
 #ifdef SNAPPER_DEBUG
 # define DPRINTF printf
 #else
@@ -66,9 +66,12 @@ __KERNEL_RCSID(0, "$NetBSD: snapper.c,v 
 
 struct snapper_softc {
 	device_t sc_dev;
-	int sc_mode;		  // 0 for TAS3004
+	int sc_mode;
+#define SNAPPER_IS_TAS3004	0 // codec is TAS3004
 #define SNAPPER_IS_TAS3001	1 // codec is TAS3001
-#define SNAPPER_SWVOL		2 // software codec
+#define SNAPPER_IS_PCM3052	2 // codec is PCM3052
+#define SNAPPER_IS_CS8416	3 // codec is CS8416
+#define SNAPPER_SWVOL		4 // software codec
 	
 	int sc_node;
 
@@ -475,6 +478,21 @@ static const struct audio_format tumbler
 };
 #define TUMBLER_NFORMATS	__arraycount(tumbler_formats)
 
+/* OF hands us the codec in 16bit mode, run with it for now */
+static const struct audio_format onyx_formats[] = {
+	{
+		.mode		= AUMODE_PLAY | AUMODE_RECORD,
+		.encoding	= AUDIO_ENCODING_SLINEAR_BE,
+		.validbits	= 16,
+		.precision	= 16,
+		.channels	= 2,
+		.channel_mask	= AUFMT_STEREO,
+		.frequency_type	= 3,
+		.frequency	= { 44100, 48000, 96000 },
+	},
+};
+#define ONYX_NFORMATS	__arraycount(onyx_formats)
+
 static bus_size_t amp_mute;
 static bus_size_t headphone_mute;
 static bus_size_t audio_hw_reset;
@@ -492,6 +510,16 @@ static uint8_t headphone_detect_active;
 /* I2S_INT register definitions */
 #define I2S_INT_CLKSTOPPEND 0x01000000  /* clock-stop interrupt pending */
 
+/* I2S_WORDSIZE register definitions */
+#define INPUT_STEREO            (2 << 24)
+#define INPUT_MONO              (1 << 24)
+#define INPUT_16BIT             (0 << 16)
+#define INPUT_24BIT             (3 << 16)
+#define OUTPUT_STEREO           (2 << 8)
+#define OUTPUT_MONO             (1 << 8)
+#define OUTPUT_16BIT            (0 << 0)
+#define OUTPUT_24BIT            (3 << 0)
+
 /* FCR(0x3c) bits */
 #define KEYLARGO_FCR1   0x3c
 #define  I2S0CLKEN      0x1000
@@ -639,6 +667,9 @@ snapper_match(device_t parent, struct cf
 	if (strcmp(compat, "AOAK2") == 0)
 		return 1;
 		
+	if (strcmp(compat, "AOAbase") == 0)
+		return 1;
+
 	if (OF_getprop(soundchip, "platform-tas-codec-ref",
 	    &soundcodec, sizeof soundcodec) == sizeof soundcodec)
 		return 1;
@@ -664,6 +695,8 @@ snapper_attach(device_t parent, device_t
 	memset(compat, 0, sizeof compat);
 	OF_getprop(OF_child(soundbus), "compatible", compat, sizeof compat);
 
+	sc->sc_mode = SNAPPER_IS_TAS3004;
+
 	if (strcmp(compat, "tumbler") == 0)
 		sc->sc_mode = SNAPPER_IS_TAS3001;
 	sc->sc_swvol_l = 255;
@@ -718,8 +751,8 @@ snapper_attach(device_t parent, device_t
 	oirq = intr[2];
 	iirq = intr[4];
 	/* cirq_type = intr[1] ? IST_LEVEL : IST_EDGE; */
-	oirq_type = intr[3] ? IST_LEVEL : IST_EDGE;
-	iirq_type = intr[5] ? IST_LEVEL : IST_EDGE;
+	oirq_type = (intr[3] & 1) ? IST_LEVEL : IST_EDGE;
+	iirq_type = (intr[5] & 1) ? IST_LEVEL : IST_EDGE;
 
 	/* intr_establish(cirq, cirq_type, IPL_AUDIO, snapper_intr, sc); */
 	intr_establish(oirq, oirq_type, IPL_AUDIO, snapper_intr, sc);
@@ -743,25 +776,79 @@ snapper_defer(device_t dev)
 	device_t dv;
 	deviter_t di;
 	struct deq_softc *deq;
+	char prop[64], next[64], codec[64], *cref;
+	int codec_node, soundbus, sound, ok, deqnode = 0;
 	
 	sc = device_private(dev);
+
+	/* look for platform-*-codec-ref node */
+
+	/*
+	 * XXX
+	 * there can be more than one i2sbus, the one we want just so happens
+	 * to be the first we see
+	 */
+	soundbus = OF_child(sc->sc_node);
+	sound = OF_child(soundbus);
+	ok = OF_nextprop(sound, NULL, next);
+	codec_node = 0;
+	while (ok && (codec_node == 0)) {
+		DPRINTF("prop %d %s\n", ok, next);
+		strncpy(prop, next, 64);
+		if ((cref = strstr(next, "-codec-ref")) != NULL) {
+			OF_getprop(sound, next, &codec_node, 4);
+			if (codec_node != 0) {
+				OF_getprop(codec_node, "compatible", codec, 64);
+				DPRINTF("%08x %s\n", codec_node, codec);
+			}
+		}	
+		ok = OF_nextprop(sound, prop, next);
+	}	
+
 	for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST);
 	     dv != NULL;
 	     dv = deviter_next(&di)) {
 		if (device_is_a(dv, "deq")) {
 			deq = device_private(dv);
+			if (codec_node != 0) {
+				if (codec_node != deq->sc_node)
+					continue;
+			}
 			sc->sc_i2c = deq->sc_i2c;
 			sc->sc_deqaddr = deq->sc_address;
+			deqnode = deq->sc_node;
 		}
 	}
 	deviter_release(&di);
 
+	DPRINTF("deqnode: %08x\n", deqnode);
+
 	/* If we don't find a codec, it's not the end of the world;
 	 * we can control the volume in software in this case.
 	 */
-	if (sc->sc_i2c == NULL)
+	if (sc->sc_i2c == NULL) {
 		sc->sc_mode = SNAPPER_SWVOL;
-
+	} else if (deqnode != 0) {
+		int ret;
+		codec[0] = 0;
+		ret = OF_getprop(deqnode, "compatible", codec, 64);
+
+		DPRINTF("codec <%s> %d\n", codec, ret);
+
+		if (codec[0] == 0) {
+			if (sc->sc_deqaddr == 0x34) {
+				sc->sc_mode = SNAPPER_IS_TAS3001;
+			} else
+				sc->sc_mode = SNAPPER_IS_TAS3004;
+		} else if (strcmp(codec, "tas3004") == 0) {
+			sc->sc_mode = SNAPPER_IS_TAS3004;
+		} else if (strcmp(codec, "pcm3052") == 0) {
+			sc->sc_mode = SNAPPER_IS_PCM3052;
+		} else if (strcmp(codec, "cs8416") == 0) {
+			sc->sc_mode = SNAPPER_IS_CS8416;
+		}
+	}
+	DPRINTF("mode %d\n", sc->sc_mode);
 	switch (sc->sc_mode) {
 	case SNAPPER_SWVOL:
 		aprint_verbose("%s: software codec\n", device_xname(dev));
@@ -769,9 +856,15 @@ snapper_defer(device_t dev)
 	case SNAPPER_IS_TAS3001:
 		aprint_verbose("%s: codec: TAS3001\n", device_xname(dev));
 		break;
-	case 0:
+	case SNAPPER_IS_TAS3004:
 		aprint_verbose("%s: codec: TAS3004\n", device_xname(dev));
 		break;
+	case SNAPPER_IS_PCM3052:
+		aprint_verbose("%s: codec: PCM3052 / ONYX\n", device_xname(dev));
+		break;
+	default:
+		aprint_error_dev(sc->sc_dev, "unsupported codec\n");
+		sc->sc_mode = SNAPPER_SWVOL;
 	}
 
 	snapper_init(sc, sc->sc_node);
@@ -826,13 +919,19 @@ snapper_query_format(void *h, audio_form
 {
 	struct snapper_softc *sc = h;
 
-	if (sc->sc_mode == SNAPPER_IS_TAS3001) {
-		return audio_query_format(tumbler_formats, TUMBLER_NFORMATS,
-		    afp);
-	} else {
-		return audio_query_format(snapper_formats, SNAPPER_NFORMATS,
-		    afp);
+	switch (sc->sc_mode) {
+		case SNAPPER_IS_TAS3001:
+			return audio_query_format(tumbler_formats,
+			    TUMBLER_NFORMATS, afp);
+		case SNAPPER_SWVOL:
+		case SNAPPER_IS_TAS3004:
+			return audio_query_format(snapper_formats,
+			    SNAPPER_NFORMATS, afp);
+		case SNAPPER_IS_PCM3052:
+			return audio_query_format(onyx_formats,
+			    ONYX_NFORMATS, afp);
 	}
+	return -1;
 }
 
 static int
@@ -870,8 +969,8 @@ snapper_round_blocksize(void *h, int siz
 			const audio_params_t *param)
 {
 
-	if (size < NBPG)
-		size = NBPG;
+	if (size < (3 * NBPG))
+		size = (3 * NBPG);
 	return size & ~PGOFSET;
 }
 
@@ -1476,7 +1575,7 @@ snapper_write_mixers(struct snapper_soft
 {
 	uint8_t regs[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
 	int i;
-
+if (sc->sc_mode > 1) return;
 	/* Left channel of SDIN1 */
 	ADJUST(i, sc->mixer[0]);
 	regs[0] = snapper_mixer_gain[i][0];
@@ -1619,11 +1718,13 @@ snapper_set_rate(struct snapper_softc *s
 	DPRINTF("precision: %d\n", sc->sc_bitspersample);
 	switch(sc->sc_bitspersample) {
 		case 16:
-			wordsize = 0x02000200;
+			wordsize = INPUT_STEREO | INPUT_16BIT |
+			           OUTPUT_STEREO | OUTPUT_16BIT;
 			mcr1 = DEQ_MCR1_SC_64 | DEQ_MCR1_SM_I2S | DEQ_MCR1_W_16;
 			break;
 		case 24:
-			wordsize = 0x03000300;
+			wordsize = INPUT_STEREO | INPUT_24BIT |
+			           OUTPUT_STEREO | OUTPUT_24BIT;
 			mcr1 = DEQ_MCR1_SC_64 | DEQ_MCR1_SM_I2S | DEQ_MCR1_W_24;
 			break;
 		default:
@@ -1895,34 +1996,36 @@ tas3004_init(struct snapper_softc *sc)
 	delay(10000);
 
 noreset:
-	DEQ_WRITE(sc, DEQ_LB0, tas3004_initdata.LB0);
-	DEQ_WRITE(sc, DEQ_LB1, tas3004_initdata.LB1);
-	DEQ_WRITE(sc, DEQ_LB2, tas3004_initdata.LB2);
-	DEQ_WRITE(sc, DEQ_LB3, tas3004_initdata.LB3);
-	DEQ_WRITE(sc, DEQ_LB4, tas3004_initdata.LB4);
-	DEQ_WRITE(sc, DEQ_LB5, tas3004_initdata.LB5);
-	DEQ_WRITE(sc, DEQ_LB6, tas3004_initdata.LB6);
-	DEQ_WRITE(sc, DEQ_RB0, tas3004_initdata.RB0);
-	DEQ_WRITE(sc, DEQ_RB1, tas3004_initdata.RB1);
-	DEQ_WRITE(sc, DEQ_RB1, tas3004_initdata.RB1);
-	DEQ_WRITE(sc, DEQ_RB2, tas3004_initdata.RB2);
-	DEQ_WRITE(sc, DEQ_RB3, tas3004_initdata.RB3);
-	DEQ_WRITE(sc, DEQ_RB4, tas3004_initdata.RB4);
-	DEQ_WRITE(sc, DEQ_RB5, tas3004_initdata.RB5);
-	DEQ_WRITE(sc, DEQ_MCR1, tas3004_initdata.MCR1);
-	DEQ_WRITE(sc, DEQ_MCR2, tas3004_initdata.MCR2);
-	DEQ_WRITE(sc, DEQ_DRC, tas3004_initdata.DRC);
-	DEQ_WRITE(sc, DEQ_VOLUME, tas3004_initdata.VOLUME);
-	DEQ_WRITE(sc, DEQ_TREBLE, tas3004_initdata.TREBLE);
-	DEQ_WRITE(sc, DEQ_BASS, tas3004_initdata.BASS);
-	DEQ_WRITE(sc, DEQ_MIXER_L, tas3004_initdata.MIXER_L);
-	DEQ_WRITE(sc, DEQ_MIXER_R, tas3004_initdata.MIXER_R);
-	DEQ_WRITE(sc, DEQ_LLB, tas3004_initdata.LLB);
-	DEQ_WRITE(sc, DEQ_RLB, tas3004_initdata.RLB);
-	DEQ_WRITE(sc, DEQ_LLB_GAIN, tas3004_initdata.LLB_GAIN);
-	DEQ_WRITE(sc, DEQ_RLB_GAIN, tas3004_initdata.RLB_GAIN);
-	DEQ_WRITE(sc, DEQ_ACR, tas3004_initdata.ACR);
-
+	if ((sc->sc_mode == SNAPPER_IS_TAS3004) ||
+	    (sc->sc_mode == SNAPPER_IS_TAS3001)) {
+		DEQ_WRITE(sc, DEQ_LB0, tas3004_initdata.LB0);
+		DEQ_WRITE(sc, DEQ_LB1, tas3004_initdata.LB1);
+		DEQ_WRITE(sc, DEQ_LB2, tas3004_initdata.LB2);
+		DEQ_WRITE(sc, DEQ_LB3, tas3004_initdata.LB3);
+		DEQ_WRITE(sc, DEQ_LB4, tas3004_initdata.LB4);
+		DEQ_WRITE(sc, DEQ_LB5, tas3004_initdata.LB5);
+		DEQ_WRITE(sc, DEQ_LB6, tas3004_initdata.LB6);
+		DEQ_WRITE(sc, DEQ_RB0, tas3004_initdata.RB0);
+		DEQ_WRITE(sc, DEQ_RB1, tas3004_initdata.RB1);
+		DEQ_WRITE(sc, DEQ_RB1, tas3004_initdata.RB1);
+		DEQ_WRITE(sc, DEQ_RB2, tas3004_initdata.RB2);
+		DEQ_WRITE(sc, DEQ_RB3, tas3004_initdata.RB3);
+		DEQ_WRITE(sc, DEQ_RB4, tas3004_initdata.RB4);
+		DEQ_WRITE(sc, DEQ_RB5, tas3004_initdata.RB5);
+		DEQ_WRITE(sc, DEQ_MCR1, tas3004_initdata.MCR1);
+		DEQ_WRITE(sc, DEQ_MCR2, tas3004_initdata.MCR2);
+		DEQ_WRITE(sc, DEQ_DRC, tas3004_initdata.DRC);
+		DEQ_WRITE(sc, DEQ_VOLUME, tas3004_initdata.VOLUME);
+		DEQ_WRITE(sc, DEQ_TREBLE, tas3004_initdata.TREBLE);
+		DEQ_WRITE(sc, DEQ_BASS, tas3004_initdata.BASS);
+		DEQ_WRITE(sc, DEQ_MIXER_L, tas3004_initdata.MIXER_L);
+		DEQ_WRITE(sc, DEQ_MIXER_R, tas3004_initdata.MIXER_R);
+		DEQ_WRITE(sc, DEQ_LLB, tas3004_initdata.LLB);
+		DEQ_WRITE(sc, DEQ_RLB, tas3004_initdata.RLB);
+		DEQ_WRITE(sc, DEQ_LLB_GAIN, tas3004_initdata.LLB_GAIN);
+		DEQ_WRITE(sc, DEQ_RLB_GAIN, tas3004_initdata.RLB_GAIN);
+		DEQ_WRITE(sc, DEQ_ACR, tas3004_initdata.ACR);
+	}
 	return 0;
 err:
 	printf("tas3004_init: error\n");
@@ -2042,7 +2145,10 @@ snapper_init(struct snapper_softc *sc, i
 	sc->mixer[0] = 128;
 	sc->mixer[1] = 128;
 	sc->mixer[2] = 0;
-	sc->mixer[3] = 128;
+	if (sc->sc_mode == SNAPPER_IS_TAS3001) {
+		sc->mixer[3] = 0;
+	} else
+		sc->mixer[3] = 128;
 	sc->mixer[4] = 128;
 	sc->mixer[5] = 0;
 	snapper_write_mixers(sc);

Reply via email to