From 9927696972de95a35830c2c9ed12358b505b5a85 Mon Sep 17 00:00:00 2001 From: macallan Date: Fri, 20 Sep 2019 21:24:34 +0000 Subject: [PATCH] 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' --- sys/arch/macppc/dev/snapper.c | 204 ++++++++++++++++++++++++++-------- 1 file changed, 155 insertions(+), 49 deletions(-) diff --git a/sys/arch/macppc/dev/snapper.c b/sys/arch/macppc/dev/snapper.c index 31899c5056a7..f0e5edd88f44 100644 --- a/sys/arch/macppc/dev/snapper.c +++ b/sys/arch/macppc/dev/snapper.c @@ -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 -__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 #include @@ -55,7 +55,7 @@ __KERNEL_RCSID(0, "$NetBSD: snapper.c,v 1.52 2019/06/08 08:02:37 isaki Exp $"); #include #include - +//#define SNAPPER_DEBUG #ifdef SNAPPER_DEBUG # define DPRINTF printf #else @@ -66,9 +66,12 @@ __KERNEL_RCSID(0, "$NetBSD: snapper.c,v 1.52 2019/06/08 08:02:37 isaki Exp $"); 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_formats[] = { }; #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 cfdata *match, void *aux) 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 self, void *aux) 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 self, void *aux) 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_format_query_t *afp) { 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 size, int mode, 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_softc *sc) { 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 *sc) 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, int node) 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);