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'
This commit is contained in:
macallan 2019-09-20 21:24:34 +00:00
parent 1200baa95c
commit 9927696972
1 changed files with 155 additions and 49 deletions

View File

@ -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 1.52 2019/06/08 08:02:37 isaki Exp $");
#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 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);