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:
parent
1200baa95c
commit
9927696972
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue