1*08004a7eSisaki /* $NetBSD: bba.c,v 1.46 2020/09/12 05:19:16 isaki Exp $ */
2621ef4d7Saugustss
3621ef4d7Saugustss /*
4621ef4d7Saugustss * Copyright (c) 2000 The NetBSD Foundation, Inc.
5621ef4d7Saugustss * All rights reserved.
6621ef4d7Saugustss *
7621ef4d7Saugustss * Redistribution and use in source and binary forms, with or without
8621ef4d7Saugustss * modification, are permitted provided that the following conditions
9621ef4d7Saugustss * are met:
10621ef4d7Saugustss * 1. Redistributions of source code must retain the above copyright
11621ef4d7Saugustss * notice, this list of conditions and the following disclaimer.
12621ef4d7Saugustss * 2. Redistributions in binary form must reproduce the above copyright
13621ef4d7Saugustss * notice, this list of conditions and the following disclaimer in the
14621ef4d7Saugustss * documentation and/or other materials provided with the distribution.
15621ef4d7Saugustss *
16621ef4d7Saugustss * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17621ef4d7Saugustss * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18621ef4d7Saugustss * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19621ef4d7Saugustss * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20621ef4d7Saugustss * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21621ef4d7Saugustss * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22621ef4d7Saugustss * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23621ef4d7Saugustss * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24621ef4d7Saugustss * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25621ef4d7Saugustss * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26621ef4d7Saugustss * POSSIBILITY OF SUCH DAMAGE.
27621ef4d7Saugustss */
28621ef4d7Saugustss
29621ef4d7Saugustss /* maxine/alpha baseboard audio (bba) */
30621ef4d7Saugustss
316a3181d3Slukem #include <sys/cdefs.h>
32*08004a7eSisaki __KERNEL_RCSID(0, "$NetBSD: bba.c,v 1.46 2020/09/12 05:19:16 isaki Exp $");
336a3181d3Slukem
34621ef4d7Saugustss #include <sys/param.h>
35621ef4d7Saugustss #include <sys/systm.h>
36621ef4d7Saugustss #include <sys/kernel.h>
37621ef4d7Saugustss #include <sys/device.h>
388a962f23Sjmcneill #include <sys/kmem.h>
39621ef4d7Saugustss
40a2a38285Sad #include <sys/bus.h>
41621ef4d7Saugustss #include <machine/autoconf.h>
42a2a38285Sad #include <sys/cpu.h>
43621ef4d7Saugustss
44621ef4d7Saugustss #include <sys/audioio.h>
45e622eac4Sisaki #include <dev/audio/audio_if.h>
46621ef4d7Saugustss
47621ef4d7Saugustss #include <dev/ic/am7930reg.h>
48621ef4d7Saugustss #include <dev/ic/am7930var.h>
49621ef4d7Saugustss
50621ef4d7Saugustss #include <dev/tc/tcvar.h>
51621ef4d7Saugustss #include <dev/tc/ioasicreg.h>
52621ef4d7Saugustss #include <dev/tc/ioasicvar.h>
53621ef4d7Saugustss
54e622eac4Sisaki /* include mulaw.c (not .h file) here to expand mulaw32 */
55e622eac4Sisaki void audio_mulaw32_to_internal(audio_filter_arg_t *);
56e622eac4Sisaki void audio_internal_to_mulaw32(audio_filter_arg_t *);
57e622eac4Sisaki #define MULAW32
58e622eac4Sisaki #include <dev/audio/mulaw.c>
59e622eac4Sisaki
60621ef4d7Saugustss #ifdef AUDIO_DEBUG
61621ef4d7Saugustss #define DPRINTF(x) if (am7930debug) printf x
62621ef4d7Saugustss #else
63621ef4d7Saugustss #define DPRINTF(x)
64621ef4d7Saugustss #endif /* AUDIO_DEBUG */
65621ef4d7Saugustss
666ab5c336Sgmcgarry #define BBA_MAX_DMA_SEGMENTS 16
678746b7c8Sthorpej #define BBA_DMABUF_SIZE (BBA_MAX_DMA_SEGMENTS*IOASIC_DMA_BLOCKSIZE)
688746b7c8Sthorpej #define BBA_DMABUF_ALIGN IOASIC_DMA_BLOCKSIZE
696ab5c336Sgmcgarry #define BBA_DMABUF_BOUNDARY 0
70621ef4d7Saugustss
71621ef4d7Saugustss struct bba_mem {
726ab5c336Sgmcgarry struct bba_mem *next;
73621ef4d7Saugustss bus_addr_t addr;
74621ef4d7Saugustss bus_size_t size;
7553524e44Schristos void *kva;
76621ef4d7Saugustss };
77621ef4d7Saugustss
78621ef4d7Saugustss struct bba_dma_state {
791ffa7b76Swiz bus_dmamap_t dmam; /* DMA map */
80621ef4d7Saugustss int active;
811ffa7b76Swiz int curseg; /* current segment in DMA buffer */
8293293b9eSkent void (*intr)(void *); /* higher-level audio handler */
83621ef4d7Saugustss void *intr_arg;
84621ef4d7Saugustss };
85621ef4d7Saugustss
86621ef4d7Saugustss struct bba_softc {
87621ef4d7Saugustss struct am7930_softc sc_am7930; /* glue to MI code */
88621ef4d7Saugustss
89621ef4d7Saugustss bus_space_tag_t sc_bst; /* IOASIC bus tag/handle */
90621ef4d7Saugustss bus_space_handle_t sc_bsh;
91621ef4d7Saugustss bus_dma_tag_t sc_dmat;
92621ef4d7Saugustss bus_space_handle_t sc_codec_bsh; /* codec bus space handle */
93621ef4d7Saugustss
94621ef4d7Saugustss struct bba_mem *sc_mem_head; /* list of buffers */
95621ef4d7Saugustss
96621ef4d7Saugustss struct bba_dma_state sc_tx_dma_state;
97621ef4d7Saugustss struct bba_dma_state sc_rx_dma_state;
98621ef4d7Saugustss };
99621ef4d7Saugustss
1007cf29912Scegger static int bba_match(device_t, cfdata_t, void *);
1017cf29912Scegger static void bba_attach(device_t, device_t, void *);
102621ef4d7Saugustss
103595cbc6aStsutsui CFATTACH_DECL_NEW(bba, sizeof(struct bba_softc),
104b75a007dSthorpej bba_match, bba_attach, NULL, NULL);
105621ef4d7Saugustss
106621ef4d7Saugustss /*
107621ef4d7Saugustss * Define our interface into the am7930 MI driver.
108621ef4d7Saugustss */
109621ef4d7Saugustss
110*08004a7eSisaki static uint8_t bba_codec_dread(struct am7930_softc *, int);
111*08004a7eSisaki static void bba_codec_dwrite(struct am7930_softc *, int, uint8_t);
1126ecb4ef7Sthorpej
113621ef4d7Saugustss struct am7930_glue bba_glue = {
114*08004a7eSisaki bba_codec_dread,
115*08004a7eSisaki bba_codec_dwrite,
116621ef4d7Saugustss };
117621ef4d7Saugustss
118621ef4d7Saugustss /*
119621ef4d7Saugustss * Define our interface to the higher level audio driver.
120621ef4d7Saugustss */
121621ef4d7Saugustss
122e622eac4Sisaki static int bba_query_format(void *, audio_format_query_t *);
123e622eac4Sisaki static int bba_set_format(void *, int,
124e622eac4Sisaki const audio_params_t *, const audio_params_t *,
125e622eac4Sisaki audio_filter_reg_t *, audio_filter_reg_t *);
1266ecb4ef7Sthorpej static int bba_round_blocksize(void *, int, int, const audio_params_t *);
1276ecb4ef7Sthorpej static int bba_halt_output(void *);
1286ecb4ef7Sthorpej static int bba_halt_input(void *);
1296ecb4ef7Sthorpej static int bba_getdev(void *, struct audio_device *);
1308a962f23Sjmcneill static void *bba_allocm(void *, int, size_t);
1318a962f23Sjmcneill static void bba_freem(void *, void *, size_t);
1326ecb4ef7Sthorpej static size_t bba_round_buffersize(void *, int, size_t);
1336ecb4ef7Sthorpej static int bba_trigger_output(void *, void *, void *, int,
1346ecb4ef7Sthorpej void (*)(void *), void *,
1356ecb4ef7Sthorpej const audio_params_t *);
1366ecb4ef7Sthorpej static int bba_trigger_input(void *, void *, void *, int,
1376ecb4ef7Sthorpej void (*)(void *), void *,
1386ecb4ef7Sthorpej const audio_params_t *);
139621ef4d7Saugustss
1406ecb4ef7Sthorpej static const struct audio_hw_if sa_hw_if = {
141e622eac4Sisaki .query_format = bba_query_format,
142e622eac4Sisaki .set_format = bba_set_format,
1436291b134Sisaki .round_blocksize = bba_round_blocksize, /* md */
1446291b134Sisaki .commit_settings = am7930_commit_settings,
1456291b134Sisaki .halt_output = bba_halt_output, /* md */
1466291b134Sisaki .halt_input = bba_halt_input, /* md */
1476291b134Sisaki .getdev = bba_getdev,
1486291b134Sisaki .set_port = am7930_set_port,
1496291b134Sisaki .get_port = am7930_get_port,
1506291b134Sisaki .query_devinfo = am7930_query_devinfo,
1516291b134Sisaki .allocm = bba_allocm, /* md */
1526291b134Sisaki .freem = bba_freem, /* md */
1536291b134Sisaki .round_buffersize = bba_round_buffersize, /* md */
154ede47d01Sisaki .get_props = am7930_get_props,
1556291b134Sisaki .trigger_output = bba_trigger_output, /* md */
1566291b134Sisaki .trigger_input = bba_trigger_input, /* md */
157*08004a7eSisaki .get_locks = am7930_get_locks,
158621ef4d7Saugustss };
159621ef4d7Saugustss
1606ecb4ef7Sthorpej static struct audio_device bba_device = {
161621ef4d7Saugustss "am7930",
162621ef4d7Saugustss "x",
163621ef4d7Saugustss "bba"
164621ef4d7Saugustss };
165621ef4d7Saugustss
166e622eac4Sisaki static const struct audio_format bba_format = {
167e622eac4Sisaki .mode = AUMODE_PLAY | AUMODE_RECORD,
168e622eac4Sisaki .encoding = AUDIO_ENCODING_ULAW, /* XXX */
169e622eac4Sisaki .validbits = 32,
170e622eac4Sisaki .precision = 32,
171e622eac4Sisaki .channels = 1,
172e622eac4Sisaki .channel_mask = AUFMT_MONAURAL,
173e622eac4Sisaki .frequency_type = 1,
174e622eac4Sisaki .frequency = { 8000 },
175e622eac4Sisaki };
176e622eac4Sisaki
1776ecb4ef7Sthorpej static int bba_intr(void *);
1786ecb4ef7Sthorpej static void bba_reset(struct bba_softc *, int);
179621ef4d7Saugustss
1806ecb4ef7Sthorpej static int
bba_match(device_t parent,cfdata_t cf,void * aux)1817cf29912Scegger bba_match(device_t parent, cfdata_t cf, void *aux)
182621ef4d7Saugustss {
18393293b9eSkent struct ioasicdev_attach_args *ia;
184621ef4d7Saugustss
18593293b9eSkent ia = aux;
186621ef4d7Saugustss if (strcmp(ia->iada_modname, "isdn") != 0 &&
187621ef4d7Saugustss strcmp(ia->iada_modname, "AMD79c30") != 0)
188621ef4d7Saugustss return 0;
189621ef4d7Saugustss
190621ef4d7Saugustss return 1;
191621ef4d7Saugustss }
192621ef4d7Saugustss
193621ef4d7Saugustss
1946ecb4ef7Sthorpej static void
bba_attach(device_t parent,device_t self,void * aux)1957cf29912Scegger bba_attach(device_t parent, device_t self, void *aux)
196621ef4d7Saugustss {
19793293b9eSkent struct ioasicdev_attach_args *ia;
19893293b9eSkent struct bba_softc *sc;
199*08004a7eSisaki struct am7930_softc *amsc;
200516792c3Sthorpej struct ioasic_softc *iosc = device_private(parent);
201621ef4d7Saugustss
20293293b9eSkent ia = aux;
20307c30f82Sthorpej sc = device_private(self);
204*08004a7eSisaki amsc = &sc->sc_am7930;
205*08004a7eSisaki amsc->sc_dev = self;
206516792c3Sthorpej sc->sc_bst = iosc->sc_bst;
207516792c3Sthorpej sc->sc_bsh = iosc->sc_bsh;
208516792c3Sthorpej sc->sc_dmat = iosc->sc_dmat;
209621ef4d7Saugustss
210621ef4d7Saugustss /* get the bus space handle for codec */
211621ef4d7Saugustss if (bus_space_subregion(sc->sc_bst, sc->sc_bsh,
212621ef4d7Saugustss ia->iada_offset, 0, &sc->sc_codec_bsh)) {
213595cbc6aStsutsui aprint_error_dev(self, "unable to map device\n");
214621ef4d7Saugustss return;
215621ef4d7Saugustss }
216621ef4d7Saugustss
217621ef4d7Saugustss printf("\n");
218621ef4d7Saugustss
219621ef4d7Saugustss bba_reset(sc, 1);
220621ef4d7Saugustss
221621ef4d7Saugustss /*
222621ef4d7Saugustss * Set up glue for MI code early; we use some of it here.
223621ef4d7Saugustss */
224*08004a7eSisaki amsc->sc_glue = &bba_glue;
225621ef4d7Saugustss
226621ef4d7Saugustss /*
227621ef4d7Saugustss * MI initialisation. We will be doing DMA.
228621ef4d7Saugustss */
229*08004a7eSisaki am7930_init(amsc, AUDIOAMD_DMA_MODE);
230621ef4d7Saugustss
231621ef4d7Saugustss ioasic_intr_establish(parent, ia->iada_cookie, TC_IPL_NONE,
232621ef4d7Saugustss bba_intr, sc);
233621ef4d7Saugustss
234*08004a7eSisaki audio_attach_mi(&sa_hw_if, sc, self);
235621ef4d7Saugustss }
236621ef4d7Saugustss
237621ef4d7Saugustss
2386ecb4ef7Sthorpej static void
bba_reset(struct bba_softc * sc,int reset)23993293b9eSkent bba_reset(struct bba_softc *sc, int reset)
240621ef4d7Saugustss {
24193293b9eSkent uint32_t ssr;
242621ef4d7Saugustss
243621ef4d7Saugustss /* disable any DMA and reset the codec */
244621ef4d7Saugustss ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
245621ef4d7Saugustss ssr &= ~(IOASIC_CSR_DMAEN_ISDN_T | IOASIC_CSR_DMAEN_ISDN_R);
246621ef4d7Saugustss if (reset)
247621ef4d7Saugustss ssr &= ~IOASIC_CSR_ISDN_ENABLE;
248621ef4d7Saugustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
249621ef4d7Saugustss DELAY(10); /* 400ns required for codec to reset */
250621ef4d7Saugustss
251621ef4d7Saugustss /* initialise DMA pointers */
252621ef4d7Saugustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR, -1);
253621ef4d7Saugustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR, -1);
254621ef4d7Saugustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR, -1);
255621ef4d7Saugustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR, -1);
256621ef4d7Saugustss
257621ef4d7Saugustss /* take out of reset state */
258621ef4d7Saugustss if (reset) {
259621ef4d7Saugustss ssr |= IOASIC_CSR_ISDN_ENABLE;
260621ef4d7Saugustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
261621ef4d7Saugustss }
262621ef4d7Saugustss }
263621ef4d7Saugustss
264621ef4d7Saugustss
2656ecb4ef7Sthorpej static void *
bba_allocm(void * addr,int direction,size_t size)2668a962f23Sjmcneill bba_allocm(void *addr, int direction, size_t size)
267621ef4d7Saugustss {
268*08004a7eSisaki struct am7930_softc *amsc;
26993293b9eSkent struct bba_softc *sc;
270621ef4d7Saugustss bus_dma_segment_t seg;
271621ef4d7Saugustss int rseg;
27253524e44Schristos void *kva;
273621ef4d7Saugustss struct bba_mem *m;
27493293b9eSkent int state;
275621ef4d7Saugustss
2763b3dbbe7Skleink DPRINTF(("bba_allocm: size = %zu\n", size));
27793293b9eSkent sc = addr;
278*08004a7eSisaki amsc = addr;
27993293b9eSkent state = 0;
2806ab5c336Sgmcgarry
2816ab5c336Sgmcgarry if (bus_dmamem_alloc(sc->sc_dmat, size, BBA_DMABUF_ALIGN,
2828a962f23Sjmcneill BBA_DMABUF_BOUNDARY, &seg, 1, &rseg, BUS_DMA_WAITOK)) {
283*08004a7eSisaki aprint_error_dev(amsc->sc_dev, "can't allocate DMA buffer\n");
284621ef4d7Saugustss goto bad;
285621ef4d7Saugustss }
286621ef4d7Saugustss state |= 1;
287621ef4d7Saugustss
288621ef4d7Saugustss if (bus_dmamem_map(sc->sc_dmat, &seg, rseg, size,
2898a962f23Sjmcneill &kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT)) {
290*08004a7eSisaki aprint_error_dev(amsc->sc_dev, "can't map DMA buffer\n");
291621ef4d7Saugustss goto bad;
292621ef4d7Saugustss }
293621ef4d7Saugustss state |= 2;
294621ef4d7Saugustss
2958a962f23Sjmcneill m = kmem_alloc(sizeof(struct bba_mem), KM_SLEEP);
296621ef4d7Saugustss m->addr = seg.ds_addr;
297621ef4d7Saugustss m->size = seg.ds_len;
298621ef4d7Saugustss m->kva = kva;
299621ef4d7Saugustss m->next = sc->sc_mem_head;
300621ef4d7Saugustss sc->sc_mem_head = m;
301621ef4d7Saugustss
302621ef4d7Saugustss return (void *)kva;
303621ef4d7Saugustss
304621ef4d7Saugustss bad:
305621ef4d7Saugustss if (state & 2)
306621ef4d7Saugustss bus_dmamem_unmap(sc->sc_dmat, kva, size);
307621ef4d7Saugustss if (state & 1)
308621ef4d7Saugustss bus_dmamem_free(sc->sc_dmat, &seg, 1);
309621ef4d7Saugustss return NULL;
310621ef4d7Saugustss }
311621ef4d7Saugustss
312621ef4d7Saugustss
3136ecb4ef7Sthorpej static void
bba_freem(void * addr,void * ptr,size_t size)3148a962f23Sjmcneill bba_freem(void *addr, void *ptr, size_t size)
315621ef4d7Saugustss {
31693293b9eSkent struct bba_softc *sc;
317621ef4d7Saugustss struct bba_mem **mp, *m;
318621ef4d7Saugustss bus_dma_segment_t seg;
31953524e44Schristos void *kva;
320621ef4d7Saugustss
32193293b9eSkent sc = addr;
32253524e44Schristos kva = (void *)addr;
323621ef4d7Saugustss for (mp = &sc->sc_mem_head; *mp && (*mp)->kva != kva;
324621ef4d7Saugustss mp = &(*mp)->next)
32593293b9eSkent continue;
326621ef4d7Saugustss m = *mp;
3276ab5c336Sgmcgarry if (m == NULL) {
3286ab5c336Sgmcgarry printf("bba_freem: freeing unallocated memory\n");
329621ef4d7Saugustss return;
330621ef4d7Saugustss }
331621ef4d7Saugustss *mp = m->next;
332621ef4d7Saugustss bus_dmamem_unmap(sc->sc_dmat, kva, m->size);
333621ef4d7Saugustss
334621ef4d7Saugustss seg.ds_addr = m->addr;
335621ef4d7Saugustss seg.ds_len = m->size;
336621ef4d7Saugustss bus_dmamem_free(sc->sc_dmat, &seg, 1);
3378a962f23Sjmcneill kmem_free(m, sizeof(struct bba_mem));
338621ef4d7Saugustss }
339621ef4d7Saugustss
340621ef4d7Saugustss
3416ecb4ef7Sthorpej static size_t
bba_round_buffersize(void * addr,int direction,size_t size)34293293b9eSkent bba_round_buffersize(void *addr, int direction, size_t size)
343621ef4d7Saugustss {
344621ef4d7Saugustss
3453b3dbbe7Skleink DPRINTF(("bba_round_buffersize: size=%zu\n", size));
34693293b9eSkent return size > BBA_DMABUF_SIZE ? BBA_DMABUF_SIZE :
34793293b9eSkent roundup(size, IOASIC_DMA_BLOCKSIZE);
348621ef4d7Saugustss }
349621ef4d7Saugustss
350621ef4d7Saugustss
3516ecb4ef7Sthorpej static int
bba_halt_output(void * addr)35293293b9eSkent bba_halt_output(void *addr)
353621ef4d7Saugustss {
35493293b9eSkent struct bba_softc *sc;
35593293b9eSkent struct bba_dma_state *d;
35693293b9eSkent uint32_t ssr;
357621ef4d7Saugustss
35893293b9eSkent sc = addr;
35993293b9eSkent d = &sc->sc_tx_dma_state;
360621ef4d7Saugustss /* disable any DMA */
361621ef4d7Saugustss ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
362621ef4d7Saugustss ssr &= ~IOASIC_CSR_DMAEN_ISDN_T;
363621ef4d7Saugustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
364621ef4d7Saugustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR, -1);
365621ef4d7Saugustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR, -1);
366621ef4d7Saugustss
367621ef4d7Saugustss if (d->active) {
368621ef4d7Saugustss bus_dmamap_unload(sc->sc_dmat, d->dmam);
369621ef4d7Saugustss bus_dmamap_destroy(sc->sc_dmat, d->dmam);
370621ef4d7Saugustss d->active = 0;
371621ef4d7Saugustss }
372621ef4d7Saugustss
373621ef4d7Saugustss return 0;
374621ef4d7Saugustss }
375621ef4d7Saugustss
376621ef4d7Saugustss
3776ecb4ef7Sthorpej static int
bba_halt_input(void * addr)37893293b9eSkent bba_halt_input(void *addr)
379621ef4d7Saugustss {
38093293b9eSkent struct bba_softc *sc;
38193293b9eSkent struct bba_dma_state *d;
38293293b9eSkent uint32_t ssr;
383621ef4d7Saugustss
38493293b9eSkent sc = addr;
38593293b9eSkent d = &sc->sc_rx_dma_state;
386621ef4d7Saugustss /* disable any DMA */
387621ef4d7Saugustss ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
388621ef4d7Saugustss ssr &= ~IOASIC_CSR_DMAEN_ISDN_R;
389621ef4d7Saugustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
390621ef4d7Saugustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR, -1);
391621ef4d7Saugustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR, -1);
392621ef4d7Saugustss
393621ef4d7Saugustss if (d->active) {
394621ef4d7Saugustss bus_dmamap_unload(sc->sc_dmat, d->dmam);
395621ef4d7Saugustss bus_dmamap_destroy(sc->sc_dmat, d->dmam);
396621ef4d7Saugustss d->active = 0;
397621ef4d7Saugustss }
398621ef4d7Saugustss
399621ef4d7Saugustss return 0;
400621ef4d7Saugustss }
401621ef4d7Saugustss
402621ef4d7Saugustss
4036ecb4ef7Sthorpej static int
bba_getdev(void * addr,struct audio_device * retp)40493293b9eSkent bba_getdev(void *addr, struct audio_device *retp)
405621ef4d7Saugustss {
40693293b9eSkent
407621ef4d7Saugustss *retp = bba_device;
408621ef4d7Saugustss return 0;
409621ef4d7Saugustss }
410621ef4d7Saugustss
411621ef4d7Saugustss
4126ecb4ef7Sthorpej static int
bba_trigger_output(void * addr,void * start,void * end,int blksize,void (* intr)(void *),void * arg,const audio_params_t * param)41393293b9eSkent bba_trigger_output(void *addr, void *start, void *end, int blksize,
41493293b9eSkent void (*intr)(void *), void *arg,
41593293b9eSkent const audio_params_t *param)
416621ef4d7Saugustss {
41793293b9eSkent struct bba_softc *sc;
41893293b9eSkent struct bba_dma_state *d;
41993293b9eSkent uint32_t ssr;
420621ef4d7Saugustss tc_addr_t phys, nphys;
42193293b9eSkent int state;
422621ef4d7Saugustss
423621ef4d7Saugustss DPRINTF(("bba_trigger_output: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n",
424621ef4d7Saugustss addr, start, end, blksize, intr, arg));
42593293b9eSkent sc = addr;
42693293b9eSkent d = &sc->sc_tx_dma_state;
42793293b9eSkent state = 0;
428621ef4d7Saugustss
4296ab5c336Sgmcgarry /* disable any DMA */
4306ab5c336Sgmcgarry ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
4316ab5c336Sgmcgarry ssr &= ~IOASIC_CSR_DMAEN_ISDN_T;
4326ab5c336Sgmcgarry bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
4336ab5c336Sgmcgarry
434621ef4d7Saugustss if (bus_dmamap_create(sc->sc_dmat, (char *)end - (char *)start,
4358746b7c8Sthorpej BBA_MAX_DMA_SEGMENTS, IOASIC_DMA_BLOCKSIZE,
4368746b7c8Sthorpej BBA_DMABUF_BOUNDARY, BUS_DMA_NOWAIT, &d->dmam)) {
437621ef4d7Saugustss printf("bba_trigger_output: can't create DMA map\n");
438621ef4d7Saugustss goto bad;
439621ef4d7Saugustss }
440621ef4d7Saugustss state |= 1;
441621ef4d7Saugustss
442621ef4d7Saugustss if (bus_dmamap_load(sc->sc_dmat, d->dmam, start,
44344e529feSthorpej (char *)end - (char *)start, NULL, BUS_DMA_WRITE|BUS_DMA_NOWAIT)) {
444621ef4d7Saugustss printf("bba_trigger_output: can't load DMA map\n");
445621ef4d7Saugustss goto bad;
446621ef4d7Saugustss }
447621ef4d7Saugustss state |= 2;
448621ef4d7Saugustss
449621ef4d7Saugustss d->intr = intr;
450621ef4d7Saugustss d->intr_arg = arg;
451621ef4d7Saugustss d->curseg = 1;
452621ef4d7Saugustss
453621ef4d7Saugustss /* get physical address of buffer start */
45457e5e86eSgmcgarry phys = (tc_addr_t)d->dmam->dm_segs[0].ds_addr;
45557e5e86eSgmcgarry nphys = (tc_addr_t)d->dmam->dm_segs[1].ds_addr;
456621ef4d7Saugustss
457621ef4d7Saugustss /* setup DMA pointer */
458621ef4d7Saugustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR,
459621ef4d7Saugustss IOASIC_DMA_ADDR(phys));
460621ef4d7Saugustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR,
461621ef4d7Saugustss IOASIC_DMA_ADDR(nphys));
462621ef4d7Saugustss
463621ef4d7Saugustss /* kick off DMA */
464621ef4d7Saugustss ssr |= IOASIC_CSR_DMAEN_ISDN_T;
465621ef4d7Saugustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
466621ef4d7Saugustss
467621ef4d7Saugustss d->active = 1;
468621ef4d7Saugustss
469621ef4d7Saugustss return 0;
470621ef4d7Saugustss
471621ef4d7Saugustss bad:
472621ef4d7Saugustss if (state & 2)
473621ef4d7Saugustss bus_dmamap_unload(sc->sc_dmat, d->dmam);
474621ef4d7Saugustss if (state & 1)
475621ef4d7Saugustss bus_dmamap_destroy(sc->sc_dmat, d->dmam);
476621ef4d7Saugustss return 1;
477621ef4d7Saugustss }
478621ef4d7Saugustss
479621ef4d7Saugustss
4806ecb4ef7Sthorpej static int
bba_trigger_input(void * addr,void * start,void * end,int blksize,void (* intr)(void *),void * arg,const audio_params_t * param)48193293b9eSkent bba_trigger_input(void *addr, void *start, void *end, int blksize,
48293293b9eSkent void (*intr)(void *), void *arg, const audio_params_t *param)
483621ef4d7Saugustss {
48493293b9eSkent struct bba_softc *sc;
48593293b9eSkent struct bba_dma_state *d;
486621ef4d7Saugustss tc_addr_t phys, nphys;
487ccc34e8dStsutsui uint32_t ssr;
488621ef4d7Saugustss int state = 0;
489621ef4d7Saugustss
490621ef4d7Saugustss DPRINTF(("bba_trigger_input: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n",
491621ef4d7Saugustss addr, start, end, blksize, intr, arg));
492595cbc6aStsutsui sc = addr;
49393293b9eSkent d = &sc->sc_rx_dma_state;
49493293b9eSkent state = 0;
495621ef4d7Saugustss
4966ab5c336Sgmcgarry /* disable any DMA */
4976ab5c336Sgmcgarry ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
4986ab5c336Sgmcgarry ssr &= ~IOASIC_CSR_DMAEN_ISDN_R;
4996ab5c336Sgmcgarry bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
5006ab5c336Sgmcgarry
501621ef4d7Saugustss if (bus_dmamap_create(sc->sc_dmat, (char *)end - (char *)start,
5028746b7c8Sthorpej BBA_MAX_DMA_SEGMENTS, IOASIC_DMA_BLOCKSIZE,
5038746b7c8Sthorpej BBA_DMABUF_BOUNDARY, BUS_DMA_NOWAIT, &d->dmam)) {
504621ef4d7Saugustss printf("bba_trigger_input: can't create DMA map\n");
505621ef4d7Saugustss goto bad;
506621ef4d7Saugustss }
507621ef4d7Saugustss state |= 1;
508621ef4d7Saugustss
509621ef4d7Saugustss if (bus_dmamap_load(sc->sc_dmat, d->dmam, start,
51044e529feSthorpej (char *)end - (char *)start, NULL, BUS_DMA_READ|BUS_DMA_NOWAIT)) {
511621ef4d7Saugustss printf("bba_trigger_input: can't load DMA map\n");
512621ef4d7Saugustss goto bad;
513621ef4d7Saugustss }
514621ef4d7Saugustss state |= 2;
515621ef4d7Saugustss
516621ef4d7Saugustss d->intr = intr;
517621ef4d7Saugustss d->intr_arg = arg;
518621ef4d7Saugustss d->curseg = 1;
519621ef4d7Saugustss
520621ef4d7Saugustss /* get physical address of buffer start */
52157e5e86eSgmcgarry phys = (tc_addr_t)d->dmam->dm_segs[0].ds_addr;
52257e5e86eSgmcgarry nphys = (tc_addr_t)d->dmam->dm_segs[1].ds_addr;
523621ef4d7Saugustss
524621ef4d7Saugustss /* setup DMA pointer */
525621ef4d7Saugustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR,
526621ef4d7Saugustss IOASIC_DMA_ADDR(phys));
527621ef4d7Saugustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR,
528621ef4d7Saugustss IOASIC_DMA_ADDR(nphys));
529621ef4d7Saugustss
530621ef4d7Saugustss /* kick off DMA */
531621ef4d7Saugustss ssr |= IOASIC_CSR_DMAEN_ISDN_R;
532621ef4d7Saugustss bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
533621ef4d7Saugustss
534621ef4d7Saugustss d->active = 1;
535621ef4d7Saugustss
536621ef4d7Saugustss return 0;
537621ef4d7Saugustss
538621ef4d7Saugustss bad:
539621ef4d7Saugustss if (state & 2)
540621ef4d7Saugustss bus_dmamap_unload(sc->sc_dmat, d->dmam);
541621ef4d7Saugustss if (state & 1)
542621ef4d7Saugustss bus_dmamap_destroy(sc->sc_dmat, d->dmam);
543621ef4d7Saugustss return 1;
544621ef4d7Saugustss }
545621ef4d7Saugustss
5466ecb4ef7Sthorpej static int
bba_intr(void * addr)54793293b9eSkent bba_intr(void *addr)
548621ef4d7Saugustss {
54993293b9eSkent struct bba_softc *sc;
550621ef4d7Saugustss struct bba_dma_state *d;
551621ef4d7Saugustss tc_addr_t nphys;
5528a962f23Sjmcneill int mask;
553621ef4d7Saugustss
55493293b9eSkent sc = addr;
5558a962f23Sjmcneill mutex_enter(&sc->sc_am7930.sc_intr_lock);
556621ef4d7Saugustss
557621ef4d7Saugustss mask = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_INTR);
558621ef4d7Saugustss
559621ef4d7Saugustss if (mask & IOASIC_INTR_ISDN_TXLOAD) {
560621ef4d7Saugustss d = &sc->sc_tx_dma_state;
561621ef4d7Saugustss d->curseg = (d->curseg+1) % d->dmam->dm_nsegs;
562621ef4d7Saugustss nphys = (tc_addr_t)d->dmam->dm_segs[d->curseg].ds_addr;
563621ef4d7Saugustss bus_space_write_4(sc->sc_bst, sc->sc_bsh,
564621ef4d7Saugustss IOASIC_ISDN_X_NEXTPTR, IOASIC_DMA_ADDR(nphys));
565621ef4d7Saugustss if (d->intr != NULL)
566621ef4d7Saugustss (*d->intr)(d->intr_arg);
567621ef4d7Saugustss }
568621ef4d7Saugustss if (mask & IOASIC_INTR_ISDN_RXLOAD) {
569621ef4d7Saugustss d = &sc->sc_rx_dma_state;
570621ef4d7Saugustss d->curseg = (d->curseg+1) % d->dmam->dm_nsegs;
571621ef4d7Saugustss nphys = (tc_addr_t)d->dmam->dm_segs[d->curseg].ds_addr;
572621ef4d7Saugustss bus_space_write_4(sc->sc_bst, sc->sc_bsh,
573621ef4d7Saugustss IOASIC_ISDN_R_NEXTPTR, IOASIC_DMA_ADDR(nphys));
574621ef4d7Saugustss if (d->intr != NULL)
575621ef4d7Saugustss (*d->intr)(d->intr_arg);
576621ef4d7Saugustss }
577621ef4d7Saugustss
5788a962f23Sjmcneill mutex_exit(&sc->sc_am7930.sc_intr_lock);
579621ef4d7Saugustss
580621ef4d7Saugustss return 0;
581621ef4d7Saugustss }
582621ef4d7Saugustss
5836ecb4ef7Sthorpej static int
bba_query_format(void * addr,audio_format_query_t * afp)584e622eac4Sisaki bba_query_format(void *addr, audio_format_query_t *afp)
5856ab5c336Sgmcgarry {
5866ab5c336Sgmcgarry
587e622eac4Sisaki return audio_query_format(&bba_format, 1, afp);
588621ef4d7Saugustss }
589621ef4d7Saugustss
59023b5d914Skent static int
bba_set_format(void * addr,int setmode,const audio_params_t * play,const audio_params_t * rec,audio_filter_reg_t * pfil,audio_filter_reg_t * rfil)591e622eac4Sisaki bba_set_format(void *addr, int setmode,
592e622eac4Sisaki const audio_params_t *play, const audio_params_t *rec,
593e622eac4Sisaki audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
594621ef4d7Saugustss {
595621ef4d7Saugustss
596e622eac4Sisaki if ((setmode & AUMODE_PLAY) != 0) {
597e622eac4Sisaki pfil->codec = audio_internal_to_mulaw32;
598e622eac4Sisaki }
599e622eac4Sisaki if ((setmode & AUMODE_RECORD) != 0) {
600e622eac4Sisaki rfil->codec = audio_mulaw32_to_internal;
601621ef4d7Saugustss }
60223b5d914Skent
60323b5d914Skent return 0;
604621ef4d7Saugustss }
605621ef4d7Saugustss
6066ecb4ef7Sthorpej static int
bba_round_blocksize(void * addr,int blk,int mode,const audio_params_t * param)60793293b9eSkent bba_round_blocksize(void *addr, int blk, int mode, const audio_params_t *param)
608621ef4d7Saugustss {
60993293b9eSkent
61093293b9eSkent return IOASIC_DMA_BLOCKSIZE;
611621ef4d7Saugustss }
612621ef4d7Saugustss
613621ef4d7Saugustss
614621ef4d7Saugustss /* direct write */
6156ecb4ef7Sthorpej static void
bba_codec_dwrite(struct am7930_softc * amsc,int reg,uint8_t val)616*08004a7eSisaki bba_codec_dwrite(struct am7930_softc *amsc, int reg, uint8_t val)
617621ef4d7Saugustss {
61893293b9eSkent struct bba_softc *sc;
619621ef4d7Saugustss
620*08004a7eSisaki sc = (struct bba_softc *)amsc;
621621ef4d7Saugustss DPRINTF(("bba_codec_dwrite(): sc=%p, reg=%d, val=%d\n", sc, reg, val));
622621ef4d7Saugustss
6238746b7c8Sthorpej #if defined(__alpha__)
624c2a8e26eSgmcgarry bus_space_write_4(sc->sc_bst, sc->sc_codec_bsh,
6258746b7c8Sthorpej reg << 2, val << 8);
6268746b7c8Sthorpej #else
6278746b7c8Sthorpej bus_space_write_4(sc->sc_bst, sc->sc_codec_bsh,
6288746b7c8Sthorpej reg << 6, val);
6298746b7c8Sthorpej #endif
630621ef4d7Saugustss }
631621ef4d7Saugustss
632621ef4d7Saugustss /* direct read */
6336ecb4ef7Sthorpej static uint8_t
bba_codec_dread(struct am7930_softc * amsc,int reg)634*08004a7eSisaki bba_codec_dread(struct am7930_softc *amsc, int reg)
635621ef4d7Saugustss {
63693293b9eSkent struct bba_softc *sc;
637621ef4d7Saugustss
638*08004a7eSisaki sc = (struct bba_softc *)amsc;
639621ef4d7Saugustss DPRINTF(("bba_codec_dread(): sc=%p, reg=%d\n", sc, reg));
640621ef4d7Saugustss
6418746b7c8Sthorpej #if defined(__alpha__)
6428746b7c8Sthorpej return ((bus_space_read_4(sc->sc_bst, sc->sc_codec_bsh,
6438746b7c8Sthorpej reg << 2) >> 8) & 0xff);
6448746b7c8Sthorpej #else
6458746b7c8Sthorpej return (bus_space_read_4(sc->sc_bst, sc->sc_codec_bsh,
6468746b7c8Sthorpej reg << 6) & 0xff);
6478746b7c8Sthorpej #endif
648621ef4d7Saugustss }
649