From owner-svn-src-all@FreeBSD.ORG Sun Jan 25 18:20:15 2009 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 9E5041065673; Sun, 25 Jan 2009 18:20:15 +0000 (UTC) (envelope-from nwhitehorn@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 8791E8FC21; Sun, 25 Jan 2009 18:20:15 +0000 (UTC) (envelope-from nwhitehorn@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n0PIKFmp024360; Sun, 25 Jan 2009 18:20:15 GMT (envelope-from nwhitehorn@svn.freebsd.org) Received: (from nwhitehorn@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n0PIKF0G024352; Sun, 25 Jan 2009 18:20:15 GMT (envelope-from nwhitehorn@svn.freebsd.org) Message-Id: <200901251820.n0PIKF0G024352@svn.freebsd.org> From: Nathan Whitehorn Date: Sun, 25 Jan 2009 18:20:15 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r187692 - in head: share/man/man4/man4.powerpc sys/conf sys/dev/sound/macio sys/modules/sound/driver sys/modules/sound/driver/ai2s sys/modules/sound/driver/davbus sys/powerpc/conf X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 25 Jan 2009 18:20:16 -0000 Author: nwhitehorn Date: Sun Jan 25 18:20:15 2009 New Revision: 187692 URL: http://svn.freebsd.org/changeset/base/187692 Log: Add support for the I2S and davbus audio controllers found in Apple PowerPC hardware. Submitted by: Marco Trillo Added: head/share/man/man4/man4.powerpc/snd_ai2s.4 (contents, props changed) head/share/man/man4/man4.powerpc/snd_davbus.4 (contents, props changed) head/sys/dev/sound/macio/ head/sys/dev/sound/macio/aoa.c (contents, props changed) head/sys/dev/sound/macio/aoa.h (contents, props changed) head/sys/dev/sound/macio/davbus.c (contents, props changed) head/sys/dev/sound/macio/davbusreg.h (contents, props changed) head/sys/dev/sound/macio/i2s.c (contents, props changed) head/sys/dev/sound/macio/snapper.c (contents, props changed) head/sys/dev/sound/macio/tumbler.c (contents, props changed) head/sys/modules/sound/driver/ai2s/ head/sys/modules/sound/driver/ai2s/Makefile (contents, props changed) head/sys/modules/sound/driver/davbus/ head/sys/modules/sound/driver/davbus/Makefile (contents, props changed) Modified: head/share/man/man4/man4.powerpc/Makefile head/sys/conf/files.powerpc head/sys/modules/sound/driver/Makefile head/sys/powerpc/conf/GENERIC head/sys/powerpc/conf/NOTES Modified: head/share/man/man4/man4.powerpc/Makefile ============================================================================== --- head/share/man/man4/man4.powerpc/Makefile Sun Jan 25 17:50:53 2009 (r187691) +++ head/share/man/man4/man4.powerpc/Makefile Sun Jan 25 18:20:15 2009 (r187692) @@ -2,7 +2,9 @@ MAN= bm.4 \ pmu.4 \ - powermac_nvram.4 + powermac_nvram.4 \ + snd_ai2s.4 \ + snd_davbus MANSUBDIR=/powerpc Added: head/share/man/man4/man4.powerpc/snd_ai2s.4 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/share/man/man4/man4.powerpc/snd_ai2s.4 Sun Jan 25 18:20:15 2009 (r187692) @@ -0,0 +1,90 @@ +.\"- +.\" Copyright (c) 2009 Nathan Whitehorn +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +.\" DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd January 20, 2009 +.Dt SND_AI2S 4 +.Os +.Sh NAME +.Nm snd_ai2s +.Nd "Apple I2S audio device driver" +.Sh SYNOPSIS +To compile this driver into the kernel, +place the following lines in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device sound" +.Cd "device snd_ai2s" +.Ed +.Pp +Alternatively, to load the driver as a +module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +snd_ai2s_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +driver provides support for the Apple I2S audio controllers found +predominantly in G4 and G5 machines, along with the snapper and tumbler +codecs. Some machines (e.g. the Mac Mini) do not have configurable +codecs and so lack hardware volume control. +.Sh HARDWARE +.Pp +Chips supported by the +.Nm +driver include: +.Pp +.Bl -bullet -compact +.It +Apple Tumbler Audio +.It +Apple Snapper Audio +.El +.Pp +.Sh BUGS +Recording and operation with non-44.1 Khz audio are not currently supported. +.Sh SEE ALSO +.Xr sound 4 , +.Xr snd_davbus 4 +.Sh HISTORY +The +.Nm +device driver appeared in +.Nx 2.0 +and then in +.Fx 8.0 . +.Sh AUTHORS +.An -nosplit +The +.Nm +driver was written by +.An Tsubai Masanari +.Aq tsubai@netbsd.org , +and ported to FreeBSD by +.An Marco Trillo +.Aq marcotrillo@gmail.com . Added: head/share/man/man4/man4.powerpc/snd_davbus.4 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/share/man/man4/man4.powerpc/snd_davbus.4 Sun Jan 25 18:20:15 2009 (r187692) @@ -0,0 +1,83 @@ +.\"- +.\" Copyright (c) 2009 Nathan Whitehorn +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +.\" DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd January 20, 2009 +.Dt SND_DAVBUS 4 +.Os +.Sh NAME +.Nm snd_davbus +.Nd "Apple Davbus audio device driver" +.Sh SYNOPSIS +To compile this driver into the kernel, +place the following lines in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device sound" +.Cd "device snd_davbus" +.Ed +.Pp +Alternatively, to load the driver as a +module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +snd_davbus_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +driver provides support for the Apple Davbus audio controllers found in +many G3-era Apple machines. +.Sh HARDWARE +.Pp +Chips supported by the +.Nm +driver include: +.Pp +.Bl -bullet -compact +.It +Apple Burgundy Audio +.It +Apple Screamer Audio +.El +.Pp +.Sh BUGS +Recording is not currently supported. +.Sh SEE ALSO +.Xr sound 4 , +.Xr snd_ai2s 4 +.Sh HISTORY +The +.Nm +device driver appeared in +.Fx 8.0 . +.Sh AUTHORS +.An -nosplit +The +.Nm +driver was written by +.An Marco Trillo +.Aq marcotrillo@gmail.com . Modified: head/sys/conf/files.powerpc ============================================================================== --- head/sys/conf/files.powerpc Sun Jan 25 17:50:53 2009 (r187691) +++ head/sys/conf/files.powerpc Sun Jan 25 18:20:15 2009 (r187692) @@ -39,6 +39,11 @@ dev/ofw/ofw_standard.c optional aim dev/powermac_nvram/powermac_nvram.c optional powermac_nvram powermac dev/quicc/quicc_bfe_ocp.c optional quicc mpc85xx dev/scc/scc_bfe_macio.c optional scc powermac +dev/sound/macio/aoa.c optional snd_davbus | snd_ai2s powermac +dev/sound/macio/davbus.c optional snd_davbus powermac +dev/sound/macio/i2s.c optional snd_ai2s powermac +dev/sound/macio/snapper.c optional snd_ai2s iicbus powermac +dev/sound/macio/tumbler.c optional snd_ai2s iicbus powermac dev/syscons/scgfbrndr.c optional sc dev/syscons/scterm-teken.c optional sc dev/syscons/scvtb.c optional sc Added: head/sys/dev/sound/macio/aoa.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/sound/macio/aoa.c Sun Jan 25 18:20:15 2009 (r187692) @@ -0,0 +1,379 @@ +/*- + * Copyright 2008 by Marco Trillo. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Apple Onboard Audio (AOA). + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mixer_if.h" + +struct aoa_dma { + struct mtx mutex; + struct resource *reg; /* DBDMA registers */ + dbdma_channel_t *channel; /* DBDMA channel */ + bus_dma_tag_t tag; /* bus_dma tag */ + struct pcm_channel *pcm; /* PCM channel */ + struct snd_dbuf *buf; /* PCM buffer */ + u_int slots; /* # of slots */ + u_int slot; /* current slot */ + u_int bufsz; /* buffer size */ + u_int blksz; /* block size */ + int running; +}; + +static void +aoa_dma_set_program(struct aoa_dma *dma) +{ + u_int32_t addr; + int i; + + addr = (u_int32_t) sndbuf_getbufaddr(dma->buf); + KASSERT(dma->bufsz == sndbuf_getsize(dma->buf), ("bad size")); + + dma->slots = dma->bufsz / dma->blksz; + + for (i = 0; i < dma->slots; ++i) { + dbdma_insert_command(dma->channel, + i, /* slot */ + DBDMA_OUTPUT_MORE, /* command */ + 0, /* stream */ + addr, /* data */ + dma->blksz, /* count */ + DBDMA_ALWAYS, /* interrupt */ + DBDMA_COND_TRUE, /* branch */ + DBDMA_NEVER, /* wait */ + dma->slots + 1 /* branch_slot */ + ); + + addr += dma->blksz; + } + + /* Branch back to beginning. */ + dbdma_insert_branch(dma->channel, dma->slots, 0); + + /* STOP command to branch when S0 is asserted. */ + dbdma_insert_stop(dma->channel, dma->slots + 1); + + /* Set S0 as the condition to branch to STOP. */ + dbdma_set_branch_selector(dma->channel, 1 << 0, 1 << 0); + dbdma_set_device_status(dma->channel, 1 << 0, 0); + + dbdma_sync_commands(dma->channel, BUS_DMASYNC_PREWRITE); +} + +#define AOA_BUFFER_SIZE 65536 + +static struct aoa_dma * +aoa_dma_create(device_t self) +{ + struct aoa_softc *sc = device_get_softc(self); + struct aoa_dma *dma; + bus_dma_tag_t tag; + int err; + + err = bus_dma_tag_create(bus_get_dma_tag(self), + 4, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + AOA_BUFFER_SIZE, 1, AOA_BUFFER_SIZE, 0, NULL, NULL, &tag); + if (err != 0) + return (NULL); + + dma = malloc(sizeof(*dma), M_DEVBUF, M_WAITOK | M_ZERO); + dma->tag = tag; + dma->bufsz = AOA_BUFFER_SIZE; + dma->blksz = PAGE_SIZE; /* initial blocksize */ + + mtx_init(&dma->mutex, "AOA", NULL, MTX_DEF); + + sc->sc_intrp = dma; + + return (dma); +} + +static void +aoa_dma_delete(struct aoa_dma *dma) +{ + bus_dma_tag_destroy(dma->tag); + mtx_destroy(&dma->mutex); + free(dma, M_DEVBUF); +} + +static int +aoa_chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksz) +{ + struct aoa_dma *dma = data; + int err, lz; + + DPRINTF(("aoa_chan_setblocksize: blocksz = %u, dma->blksz = %u\n", + blocksz, dma->blksz)); + KASSERT(!dma->running, ("dma is running")); + KASSERT(blocksz > 0, ("bad blocksz")); + + /* Round blocksz down to a power of two... */ + __asm volatile ("cntlzw %0,%1" : "=r"(lz) : "r"(blocksz)); + blocksz = 1 << (31 - lz); + DPRINTF(("blocksz = %u\n", blocksz)); + + /* ...but no more than the buffer. */ + if (blocksz > dma->bufsz) + blocksz = dma->bufsz; + + err = sndbuf_resize(dma->buf, dma->bufsz / blocksz, blocksz); + if (err != 0) { + DPRINTF(("sndbuf_resize returned %d\n", err)); + return (0); + } + + if (blocksz == dma->blksz) + return (dma->blksz); + + /* One slot per block plus branch to 0 plus STOP. */ + err = dbdma_resize_channel(dma->channel, 2 + dma->bufsz / blocksz); + if (err != 0) { + DPRINTF(("dbdma_resize_channel returned %d\n", err)); + return (0); + } + + /* Set the new blocksize. */ + dma->blksz = blocksz; + aoa_dma_set_program(dma); + + return (dma->blksz); +} + +static int +aoa_chan_setformat(kobj_t obj, void *data, u_int32_t format) +{ + DPRINTF(("aoa_chan_setformat: format = %u\n", format)); + + if (format != (AFMT_STEREO | AFMT_S16_BE)) + return (EINVAL); + + return (0); +} + +static int +aoa_chan_setspeed(kobj_t obj, void *data, u_int32_t speed) +{ + DPRINTF(("aoa_chan_setspeed: speed = %u\n", speed)); + + return (44100); +} + +static int +aoa_chan_getptr(kobj_t obj, void *data) +{ + struct aoa_dma *dma = data; + + if (!dma->running) + return (0); + + return (dma->slot * dma->blksz); +} + +static void * +aoa_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, + struct pcm_channel *c, int dir) +{ + device_t self = devinfo; + struct aoa_softc *sc = device_get_softc(self); + struct aoa_dma *dma; + int max_slots, err; + + KASSERT(dir == PCMDIR_PLAY, ("bad dir")); + + dma = aoa_dma_create(self); + if (!dma) + return (NULL); + dma->pcm = c; + dma->buf = b; + dma->reg = sc->sc_odma; + + /* One slot per block, plus branch to 0 plus STOP. */ + max_slots = 2 + dma->bufsz / dma->blksz; + err = dbdma_allocate_channel(dma->reg, 0, bus_get_dma_tag(self), + max_slots, &dma->channel ); + if (err != 0) { + aoa_dma_delete(dma); + return (NULL); + } + + if (sndbuf_alloc(dma->buf, dma->tag, 0, dma->bufsz) != 0) { + dbdma_free_channel(dma->channel); + aoa_dma_delete(dma); + return (NULL); + } + + aoa_dma_set_program(dma); + + return (dma); +} + +static int +aoa_chan_trigger(kobj_t obj, void *data, int go) +{ + struct aoa_dma *dma = data; + int i; + + switch (go) { + case PCMTRIG_START: + + /* Start the DMA. */ + dma->running = 1; + + dma->slot = 0; + dbdma_set_current_cmd(dma->channel, dma->slot); + + dbdma_run(dma->channel); + + return (0); + + case PCMTRIG_STOP: + case PCMTRIG_ABORT: + + mtx_lock(&dma->mutex); + + dma->running = 0; + + /* Make it branch to the STOP command. */ + dbdma_set_device_status(dma->channel, 1 << 0, 1 << 0); + + /* XXX should wait for DBDMA_ACTIVE to clear. */ + DELAY(40000); + + /* Reset the DMA. */ + dbdma_stop(dma->channel); + dbdma_set_device_status(dma->channel, 1 << 0, 0); + + for (i = 0; i < dma->slots; ++i) + dbdma_clear_cmd_status(dma->channel, i); + + mtx_unlock(&dma->mutex); + + return (0); + } + + return (0); +} + +static int +aoa_chan_free(kobj_t obj, void *data) +{ + struct aoa_dma *dma = data; + + sndbuf_free(dma->buf); + dbdma_free_channel(dma->channel); + aoa_dma_delete(dma); + + return (0); +} + +void +aoa_interrupt(void *arg) +{ + struct aoa_softc *sc = arg; + struct aoa_dma *dma; + + if (!(dma = sc->sc_intrp) || !dma->running) + return; + + mtx_lock(&dma->mutex); + + while (dbdma_get_cmd_status(dma->channel, dma->slot)) { + + dbdma_clear_cmd_status(dma->channel, dma->slot); + dma->slot = (dma->slot + 1) % dma->slots; + + mtx_unlock(&dma->mutex); + chn_intr(dma->pcm); + mtx_lock(&dma->mutex); + } + + mtx_unlock(&dma->mutex); +} + +static u_int32_t sc_fmt[] = { + AFMT_S16_BE | AFMT_STEREO, + 0 +}; +static struct pcmchan_caps aoa_caps = {44100, 44100, sc_fmt, 0}; + +static struct pcmchan_caps * +aoa_chan_getcaps(kobj_t obj, void *data) +{ + return (&aoa_caps); +} + +static kobj_method_t aoa_chan_methods[] = { + KOBJMETHOD(channel_init, aoa_chan_init), + KOBJMETHOD(channel_free, aoa_chan_free), + KOBJMETHOD(channel_setformat, aoa_chan_setformat), + KOBJMETHOD(channel_setspeed, aoa_chan_setspeed), + KOBJMETHOD(channel_setblocksize,aoa_chan_setblocksize), + KOBJMETHOD(channel_trigger, aoa_chan_trigger), + KOBJMETHOD(channel_getptr, aoa_chan_getptr), + KOBJMETHOD(channel_getcaps, aoa_chan_getcaps), + { 0, 0 } +}; +CHANNEL_DECLARE(aoa_chan); + +int +aoa_attach(device_t self) +{ + char status[SND_STATUSLEN]; + int err; + + if (pcm_register(self, self, 1, 0)) + return (ENXIO); + + err = pcm_getbuffersize(self, AOA_BUFFER_SIZE, AOA_BUFFER_SIZE, + AOA_BUFFER_SIZE); + DPRINTF(("pcm_getbuffersize returned %d\n", err)); + + pcm_addchan(self, PCMDIR_PLAY, &aoa_chan_class, self); + + snprintf(status, sizeof(status), "at %s", ofw_bus_get_name(self)); + pcm_setstatus(self, status); + + return (0); +} + Added: head/sys/dev/sound/macio/aoa.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/sound/macio/aoa.h Sun Jan 25 18:20:15 2009 (r187692) @@ -0,0 +1,44 @@ +/*- + * Copyright 2008 by Marco Trillo. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef SOUND_AOA_H +#define SOUND_AOA_H + +#define DPRINTF(x) /* nothing */ +/* #define DPRINTF(x) printf x */ + +struct aoa_softc { + u_int8_t sc_super[PCM_SOFTC_SIZE]; + void *sc_intrp; + struct resource *sc_odma; +}; + +void aoa_interrupt(void *); +int aoa_attach(device_t); + +#endif /* SOUND_AOA_H */ + Added: head/sys/dev/sound/macio/davbus.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/sound/macio/davbus.c Sun Jan 25 18:20:15 2009 (r187692) @@ -0,0 +1,600 @@ +/*- + * Copyright 2008 by Marco Trillo. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Apple DAVbus audio controller. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "mixer_if.h" + +struct davbus_softc { + struct aoa_softc aoa; + device_t dev; + phandle_t node; + phandle_t soundnode; + struct resource *reg; + struct mtx mutex; + int device_id; + u_int output_mask; + u_int (*read_status)(struct davbus_softc *, u_int); + void (*set_outputs)(struct davbus_softc *, u_int); +}; + +static int davbus_probe(device_t); +static int davbus_attach(device_t); +static void davbus_cint(void *); + +static device_method_t pcm_davbus_methods[] = { + /* Device interface. */ + DEVMETHOD(device_probe, davbus_probe), + DEVMETHOD(device_attach, davbus_attach), + + { 0, 0 } +}; + +static driver_t pcm_davbus_driver = { + "pcm", + pcm_davbus_methods, + sizeof(struct davbus_softc) +}; + +DRIVER_MODULE(pcm_davbus, macio, pcm_davbus_driver, pcm_devclass, 0, 0); +MODULE_DEPEND(pcm_davbus, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); + +/***************************************************************************** + Probe and attachment routines. + *****************************************************************************/ +static int +davbus_probe(device_t self) +{ + const char *name; + struct davbus_softc *sc; + + name = ofw_bus_get_name(self); + if (!name) + return (ENXIO); + + if (strcmp(name, "davbus") != 0) + return (ENXIO); + + sc = device_get_softc(self); + if (!sc) + return (ENOMEM); + bzero(sc, sizeof(*sc)); + + device_set_desc(self, "Apple DAVBus Audio Controller"); + + return (0); +} + +/* + * Burgundy codec control + */ + +static int burgundy_init(struct snd_mixer *m); +static int burgundy_uninit(struct snd_mixer *m); +static int burgundy_reinit(struct snd_mixer *m); +static void burgundy_write_locked(struct davbus_softc *, u_int, u_int); +static void burgundy_set_outputs(struct davbus_softc *d, u_int mask); +static u_int burgundy_read_status(struct davbus_softc *d, u_int status); +static int burgundy_set(struct snd_mixer *m, unsigned dev, unsigned left, + unsigned right); +static int burgundy_setrecsrc(struct snd_mixer *m, u_int32_t src); + +static kobj_method_t burgundy_mixer_methods[] = { + KOBJMETHOD(mixer_init, burgundy_init), + KOBJMETHOD(mixer_uninit, burgundy_uninit), + KOBJMETHOD(mixer_reinit, burgundy_reinit), + KOBJMETHOD(mixer_set, burgundy_set), + KOBJMETHOD(mixer_setrecsrc, burgundy_setrecsrc), + { 0, 0 } +}; + +MIXER_DECLARE(burgundy_mixer); + +static int +burgundy_init(struct snd_mixer *m) +{ + struct davbus_softc *d; + + d = mix_getdevinfo(m); + + d->read_status = burgundy_read_status; + d->set_outputs = burgundy_set_outputs; + + /* + * We configure the Burgundy codec as follows: + * + * o Input subframe 0 is connected to input digital + * stream A (ISA). + * o Stream A (ISA) is mixed in mixer 2 (MIX2). + * o Output of mixer 2 (MIX2) is routed to output sources + * OS0 and OS1 which can be converted to analog. + * + */ + mtx_lock(&d->mutex); + + burgundy_write_locked(d, 0x16700, 0x40); + + burgundy_write_locked(d, BURGUNDY_MIX0_REG, 0); + burgundy_write_locked(d, BURGUNDY_MIX1_REG, 0); + burgundy_write_locked(d, BURGUNDY_MIX2_REG, BURGUNDY_MIX_ISA); + burgundy_write_locked(d, BURGUNDY_MIX3_REG, 0); + + burgundy_write_locked(d, BURGUNDY_OS_REG, BURGUNDY_OS0_MIX2 | + BURGUNDY_OS1_MIX2); + + burgundy_write_locked(d, BURGUNDY_SDIN_REG, BURGUNDY_ISA_SF0); + + /* Set several digital scalers to unity gain. */ + burgundy_write_locked(d, BURGUNDY_MXS2L_REG, BURGUNDY_MXS_UNITY); + burgundy_write_locked(d, BURGUNDY_MXS2R_REG, BURGUNDY_MXS_UNITY); + burgundy_write_locked(d, BURGUNDY_OSS0L_REG, BURGUNDY_OSS_UNITY); + burgundy_write_locked(d, BURGUNDY_OSS0R_REG, BURGUNDY_OSS_UNITY); + burgundy_write_locked(d, BURGUNDY_OSS1L_REG, BURGUNDY_OSS_UNITY); + burgundy_write_locked(d, BURGUNDY_OSS1R_REG, BURGUNDY_OSS_UNITY); + burgundy_write_locked(d, BURGUNDY_ISSAL_REG, BURGUNDY_ISS_UNITY); + burgundy_write_locked(d, BURGUNDY_ISSAR_REG, BURGUNDY_ISS_UNITY); + + burgundy_set_outputs(d, burgundy_read_status(d, + bus_read_4(d->reg, DAVBUS_CODEC_STATUS))); + + mtx_unlock(&d->mutex); + + mix_setdevs(m, SOUND_MASK_VOLUME); + + return (0); +} + +static int +burgundy_uninit(struct snd_mixer *m) +{ + return (0); +} + +static int +burgundy_reinit(struct snd_mixer *m) +{ + return (0); +} + +static void +burgundy_write_locked(struct davbus_softc *d, u_int reg, u_int val) +{ + u_int size, addr, offset, data, i; + + size = (reg & 0x00FF0000) >> 16; + addr = (reg & 0x0000FF00) >> 8; + offset = reg & 0xFF; + + for (i = offset; i < offset + size; ++i) { + data = BURGUNDY_CTRL_WRITE | (addr << 12) | + ((size + offset - 1) << 10) | (i << 8) | (val & 0xFF); + if (i == offset) + data |= BURGUNDY_CTRL_RESET; + + bus_write_4(d->reg, DAVBUS_CODEC_CTRL, data); + + while (bus_read_4(d->reg, DAVBUS_CODEC_CTRL) & + DAVBUS_CODEC_BUSY) + DELAY(1); + + val >>= 8; /* next byte. */ + } +} + +/* Must be called with d->mutex held. */ +static void +burgundy_set_outputs(struct davbus_softc *d, u_int mask) +{ + u_int x = 0; + + if (mask == d->output_mask) + return; + + /* + * Bordeaux card wirings: + * Port 15: RCA out + * Port 16: Minijack out + * Port 17: Internal speaker + * + * B&W G3 wirings: + * Port 14: Minijack out + * Port 17: Internal speaker + */ + + DPRINTF(("Enabled outputs:")); + if (mask & (1 << 0)) { + DPRINTF((" SPEAKER")); + x |= BURGUNDY_P17M_EN; + } + if (mask & (1 << 1)) { + DPRINTF((" HEADPHONES")); + x |= BURGUNDY_P14L_EN | BURGUNDY_P14R_EN; + } + DPRINTF(("\n")); + + burgundy_write_locked(d, BURGUNDY_MUTE_REG, x); + d->output_mask = mask; +} + +static u_int +burgundy_read_status(struct davbus_softc *d, u_int status) +{ + if (status & 0x4) + return (1 << 1); + else + return (1 << 0); +} + +static int +burgundy_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) +{ + struct davbus_softc *d; + int lval, rval; + + lval = ((100 - left) * 15 / 100) & 0xf; + rval = ((100 - right) * 15 / 100) & 0xf; + DPRINTF(("volume %d %d\n", lval, rval)); + + d = mix_getdevinfo(m); + + switch (dev) { + case SOUND_MIXER_VOLUME: + mtx_lock(&d->mutex); + + burgundy_write_locked(d, BURGUNDY_OL13_REG, lval); + burgundy_write_locked(d, BURGUNDY_OL14_REG, (rval << 4) | lval); + burgundy_write_locked(d, BURGUNDY_OL15_REG, (rval << 4) | lval); + burgundy_write_locked(d, BURGUNDY_OL16_REG, (rval << 4) | lval); + burgundy_write_locked(d, BURGUNDY_OL17_REG, lval); + + mtx_unlock(&d->mutex); + + return (left | (right << 8)); + } + + return (0); +} + +static int +burgundy_setrecsrc(struct snd_mixer *m, u_int32_t src) +{ + return (0); +} + +/* + * Screamer Codec Control + */ + +static int screamer_init(struct snd_mixer *m); +static int screamer_uninit(struct snd_mixer *m); +static int screamer_reinit(struct snd_mixer *m); +static void screamer_write_locked(struct davbus_softc *, u_int, u_int); +static void screamer_set_outputs(struct davbus_softc *d, u_int mask); +static u_int screamer_read_status(struct davbus_softc *d, u_int status); +static int screamer_set(struct snd_mixer *m, unsigned dev, unsigned left, + unsigned right); +static int screamer_setrecsrc(struct snd_mixer *m, u_int32_t src); + +static kobj_method_t screamer_mixer_methods[] = { + KOBJMETHOD(mixer_init, screamer_init), + KOBJMETHOD(mixer_uninit, screamer_uninit), + KOBJMETHOD(mixer_reinit, screamer_reinit), + KOBJMETHOD(mixer_set, screamer_set), + KOBJMETHOD(mixer_setrecsrc, screamer_setrecsrc), + { 0, 0 } +}; + +MIXER_DECLARE(screamer_mixer); + +static int +screamer_init(struct snd_mixer *m) +{ + struct davbus_softc *d; + + d = mix_getdevinfo(m); + + d->read_status = screamer_read_status; + d->set_outputs = screamer_set_outputs; + + mtx_lock(&d->mutex); + + screamer_write_locked(d, SCREAMER_CODEC_ADDR0, SCREAMER_INPUT_CD | + SCREAMER_DEFAULT_CD_GAIN); + + screamer_set_outputs(d, screamer_read_status(d, + bus_read_4(d->reg, DAVBUS_CODEC_STATUS))); + + screamer_write_locked(d, SCREAMER_CODEC_ADDR2, 0); + screamer_write_locked(d, SCREAMER_CODEC_ADDR4, 0); + screamer_write_locked(d, SCREAMER_CODEC_ADDR5, 0); + screamer_write_locked(d, SCREAMER_CODEC_ADDR6, 0); + + mtx_unlock(&d->mutex); + + mix_setdevs(m, SOUND_MASK_VOLUME); + + return (0); +} *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***