xref: /netbsd-src/sys/dev/tc/bba.c (revision 08004a7e10cfd628d4ced7e33ae51167467d34a1)
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