1 /* $OpenBSD: bba.c,v 1.12 2022/10/26 20:19:09 kn Exp $ */
2 /* $NetBSD: bba.c,v 1.38 2011/06/04 01:27:57 tsutsui Exp $ */
3 /*
4 * Copyright (c) 2011 Miodrag Vallat.
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 /*
19 * Copyright (c) 2000 The NetBSD Foundation, Inc.
20 * All rights reserved.
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 * 1. Redistributions of source code must retain the above copyright
26 * notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
30 *
31 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
32 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
33 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
34 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
35 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
36 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
39 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGE.
42 */
43
44 /* maxine/alpha baseboard audio (bba) */
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/device.h>
50 #include <sys/malloc.h>
51
52 #include <machine/autoconf.h>
53 #include <machine/bus.h>
54 #include <machine/cpu.h>
55
56 #include <sys/audioio.h>
57 #include <dev/audio_if.h>
58
59 #include <dev/ic/am7930reg.h>
60 #include <dev/ic/am7930var.h>
61
62 #include <dev/tc/tcvar.h>
63 #include <dev/tc/ioasicreg.h>
64 #include <dev/tc/ioasicvar.h>
65
66 #ifdef AUDIO_DEBUG
67 #define DPRINTF(x) if (am7930debug) printf x
68 #else
69 #define DPRINTF(x)
70 #endif /* AUDIO_DEBUG */
71
72 #define BBA_MAX_DMA_SEGMENTS 16
73 #define BBA_DMABUF_SIZE (BBA_MAX_DMA_SEGMENTS*IOASIC_DMA_BLOCKSIZE)
74 #define BBA_DMABUF_ALIGN IOASIC_DMA_BLOCKSIZE
75 #define BBA_DMABUF_BOUNDARY 0
76
77 struct bba_mem {
78 struct bba_mem *next;
79 bus_addr_t addr;
80 bus_size_t size;
81 void *kva;
82 };
83
84 struct bba_dma_state {
85 bus_dmamap_t dmam; /* DMA map */
86 size_t size;
87 int active;
88 int curseg; /* current segment in DMA buffer */
89 void (*intr)(void *); /* higher-level audio handler */
90 void *intr_arg;
91 };
92
93 struct bba_softc {
94 struct am7930_softc sc_am7930; /* glue to MI code */
95
96 bus_space_tag_t sc_bst; /* IOASIC bus tag/handle */
97 bus_space_handle_t sc_bsh;
98 bus_dma_tag_t sc_dmat;
99 bus_space_handle_t sc_codec_bsh; /* codec bus space handle */
100
101 struct bba_mem *sc_mem_head; /* list of buffers */
102
103 struct bba_dma_state sc_tx_dma_state;
104 struct bba_dma_state sc_rx_dma_state;
105 };
106
107 int bba_match(struct device *, void *, void *);
108 void bba_attach(struct device *, struct device *, void *);
109
110 struct cfdriver bba_cd = {
111 NULL, "bba", DV_DULL
112 };
113
114 const struct cfattach bba_ca = {
115 sizeof(struct bba_softc), bba_match, bba_attach
116 };
117
118 /*
119 * Define our interface into the am7930 MI driver.
120 */
121
122 uint8_t bba_codec_iread(struct am7930_softc *, int);
123 uint16_t bba_codec_iread16(struct am7930_softc *, int);
124 void bba_codec_iwrite(struct am7930_softc *, int, uint8_t);
125 void bba_codec_iwrite16(struct am7930_softc *, int, uint16_t);
126 void bba_onopen(struct am7930_softc *);
127 void bba_onclose(struct am7930_softc *);
128
129 struct am7930_glue bba_glue = {
130 bba_codec_iread,
131 bba_codec_iwrite,
132 bba_codec_iread16,
133 bba_codec_iwrite16,
134 bba_onopen,
135 bba_onclose,
136 24
137 };
138
139 /*
140 * Define our interface to the higher level audio driver.
141 */
142
143 int bba_round_blocksize(void *, int);
144 int bba_halt_output(void *);
145 int bba_halt_input(void *);
146 void *bba_allocm(void *, int, size_t, int, int);
147 void bba_freem(void *, void *, int);
148 size_t bba_round_buffersize(void *, int, size_t);
149 int bba_trigger_output(void *, void *, void *, int,
150 void (*)(void *), void *, struct audio_params *);
151 int bba_trigger_input(void *, void *, void *, int,
152 void (*)(void *), void *, struct audio_params *);
153
154 const struct audio_hw_if bba_hw_if = {
155 .open = am7930_open,
156 .close = am7930_close,
157 .set_params = am7930_set_params,
158 .round_blocksize = bba_round_blocksize,
159 .commit_settings = am7930_commit_settings,
160 .halt_output = bba_halt_output,
161 .halt_input = bba_halt_input,
162 .set_port = am7930_set_port,
163 .get_port = am7930_get_port,
164 .query_devinfo = am7930_query_devinfo,
165 .allocm = bba_allocm,
166 .freem = bba_freem,
167 .round_buffersize = bba_round_buffersize,
168 .trigger_output = bba_trigger_output,
169 .trigger_input = bba_trigger_input,
170 };
171
172 int bba_intr(void *);
173 void bba_reset(struct bba_softc *, int);
174 void bba_codec_dwrite(struct am7930_softc *, int, uint8_t);
175 uint8_t bba_codec_dread(struct am7930_softc *, int);
176
177 int
bba_match(struct device * parent,void * vcf,void * aux)178 bba_match(struct device *parent, void *vcf, void *aux)
179 {
180 struct ioasicdev_attach_args *ia = aux;
181
182 if (strcmp(ia->iada_modname, "isdn") != 0 &&
183 strcmp(ia->iada_modname, "AMD79c30") != 0)
184 return 0;
185
186 return 1;
187 }
188
189 void
bba_attach(struct device * parent,struct device * self,void * aux)190 bba_attach(struct device *parent, struct device *self, void *aux)
191 {
192 struct ioasicdev_attach_args *ia = aux;
193 struct bba_softc *sc = (struct bba_softc *)self;
194 struct ioasic_softc *iosc = (struct ioasic_softc *)parent;
195
196 sc->sc_bst = iosc->sc_bst;
197 sc->sc_bsh = iosc->sc_bsh;
198 sc->sc_dmat = iosc->sc_dmat;
199
200 /* get the bus space handle for codec */
201 if (bus_space_subregion(sc->sc_bst, sc->sc_bsh,
202 ia->iada_offset, 0, &sc->sc_codec_bsh)) {
203 printf(": unable to map device\n");
204 return;
205 }
206
207 printf("\n");
208
209 bba_reset(sc,1);
210
211 /*
212 * Set up glue for MI code early; we use some of it here.
213 */
214 sc->sc_am7930.sc_glue = &bba_glue;
215
216 /*
217 * MI initialisation. We will be doing DMA.
218 */
219 am7930_init(&sc->sc_am7930, AUDIOAMD_DMA_MODE);
220
221 ioasic_intr_establish(parent, ia->iada_cookie, IPL_AUDIO,
222 bba_intr, sc, self->dv_xname);
223
224 audio_attach_mi(&bba_hw_if, sc, NULL, self);
225 }
226
227 void
bba_onopen(struct am7930_softc * sc)228 bba_onopen(struct am7930_softc *sc)
229 {
230 }
231
232 void
bba_onclose(struct am7930_softc * sc)233 bba_onclose(struct am7930_softc *sc)
234 {
235 }
236
237 void
bba_reset(struct bba_softc * sc,int reset)238 bba_reset(struct bba_softc *sc, int reset)
239 {
240 uint32_t ssr;
241
242 /* disable any DMA and reset the codec */
243 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
244 ssr &= ~(IOASIC_CSR_DMAEN_ISDN_T | IOASIC_CSR_DMAEN_ISDN_R);
245 if (reset)
246 ssr &= ~IOASIC_CSR_ISDN_ENABLE;
247 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
248 DELAY(10); /* 400ns required for codec to reset */
249
250 /* initialise DMA pointers */
251 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR, 0);
252 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR, 0);
253 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR, 0);
254 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR, 0);
255
256 /* take out of reset state */
257 if (reset) {
258 ssr |= IOASIC_CSR_ISDN_ENABLE;
259 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
260 }
261
262 }
263
264 void *
bba_allocm(void * v,int direction,size_t size,int mtype,int flags)265 bba_allocm(void *v, int direction, size_t size, int mtype, int flags)
266 {
267 struct bba_softc *sc = v;
268 bus_dma_segment_t seg;
269 int rseg;
270 caddr_t kva;
271 struct bba_mem *m;
272 int w;
273 int state;
274
275 DPRINTF(("bba_allocm: size = %zu\n", size));
276 state = 0;
277 w = (flags & M_NOWAIT) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK;
278
279 if (bus_dmamem_alloc(sc->sc_dmat, size, BBA_DMABUF_ALIGN,
280 BBA_DMABUF_BOUNDARY, &seg, 1, &rseg, w)) {
281 printf("%s: can't allocate DMA buffer\n",
282 sc->sc_am7930.sc_dev.dv_xname);
283 goto bad;
284 }
285 state |= 1;
286
287 if (bus_dmamem_map(sc->sc_dmat, &seg, rseg, size,
288 &kva, w | BUS_DMA_COHERENT)) {
289 printf("%s: can't map DMA buffer\n",
290 sc->sc_am7930.sc_dev.dv_xname);
291 goto bad;
292 }
293 state |= 2;
294
295 m = malloc(sizeof(struct bba_mem), mtype, flags | M_CANFAIL);
296 if (m == NULL)
297 goto bad;
298 m->addr = seg.ds_addr;
299 m->size = seg.ds_len;
300 m->kva = kva;
301 m->next = sc->sc_mem_head;
302 sc->sc_mem_head = m;
303
304 return (void *)kva;
305
306 bad:
307 if (state & 2)
308 bus_dmamem_unmap(sc->sc_dmat, kva, size);
309 if (state & 1)
310 bus_dmamem_free(sc->sc_dmat, &seg, 1);
311 return NULL;
312 }
313
314 void
bba_freem(void * v,void * ptr,int mtype)315 bba_freem(void *v, void *ptr, int mtype)
316 {
317 struct bba_softc *sc = v;
318 struct bba_mem **mp, *m;
319 bus_dma_segment_t seg;
320 void *kva;
321
322 kva = (void *)ptr;
323 for (mp = &sc->sc_mem_head; *mp && (*mp)->kva != kva; mp = &(*mp)->next)
324 continue;
325 m = *mp;
326 if (m == NULL) {
327 printf("bba_freem: freeing unallocated memory\n");
328 return;
329 }
330 *mp = m->next;
331 bus_dmamem_unmap(sc->sc_dmat, kva, m->size);
332
333 seg.ds_addr = m->addr;
334 seg.ds_len = m->size;
335 bus_dmamem_free(sc->sc_dmat, &seg, 1);
336 free(m, mtype, 0);
337 }
338
339 size_t
bba_round_buffersize(void * v,int direction,size_t size)340 bba_round_buffersize(void *v, int direction, size_t size)
341 {
342
343 DPRINTF(("bba_round_buffersize: size=%zu\n", size));
344 return size > BBA_DMABUF_SIZE ? BBA_DMABUF_SIZE :
345 roundup(size, IOASIC_DMA_BLOCKSIZE);
346 }
347
348 int
bba_halt_output(void * v)349 bba_halt_output(void *v)
350 {
351 struct bba_softc *sc = v;
352 struct bba_dma_state *d;
353 uint32_t ssr;
354
355 mtx_enter(&audio_lock);
356 d = &sc->sc_tx_dma_state;
357 /* disable any DMA */
358 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
359 ssr &= ~IOASIC_CSR_DMAEN_ISDN_T;
360 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
361 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR, 0);
362 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR, 0);
363 mtx_leave(&audio_lock);
364
365 if (d->active) {
366 bus_dmamap_sync(sc->sc_dmat, d->dmam, 0, d->size,
367 BUS_DMASYNC_POSTWRITE);
368 bus_dmamap_unload(sc->sc_dmat, d->dmam);
369 bus_dmamap_destroy(sc->sc_dmat, d->dmam);
370 d->active = 0;
371 }
372
373 return 0;
374 }
375
376 int
bba_halt_input(void * v)377 bba_halt_input(void *v)
378 {
379 struct bba_softc *sc = v;
380 struct bba_dma_state *d;
381 uint32_t ssr;
382
383 mtx_enter(&audio_lock);
384 d = &sc->sc_rx_dma_state;
385 /* disable any DMA */
386 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
387 ssr &= ~IOASIC_CSR_DMAEN_ISDN_R;
388 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
389 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR, 0);
390 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR, 0);
391 mtx_leave(&audio_lock);
392
393 if (d->active) {
394 bus_dmamap_sync(sc->sc_dmat, d->dmam, 0, d->size,
395 BUS_DMASYNC_POSTREAD);
396 bus_dmamap_unload(sc->sc_dmat, d->dmam);
397 bus_dmamap_destroy(sc->sc_dmat, d->dmam);
398 d->active = 0;
399 }
400
401 return 0;
402 }
403
404 int
bba_trigger_output(void * v,void * start,void * end,int blksize,void (* intr)(void *),void * arg,struct audio_params * param)405 bba_trigger_output(void *v, void *start, void *end, int blksize,
406 void (*intr)(void *), void *arg, struct audio_params *param)
407 {
408 struct bba_softc *sc = v;
409 struct bba_dma_state *d;
410 uint32_t ssr;
411 tc_addr_t phys, nphys;
412 int state;
413
414 DPRINTF(("bba_trigger_output: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n",
415 sc, start, end, blksize, intr, arg));
416 d = &sc->sc_tx_dma_state;
417 state = 0;
418
419 /* disable any DMA */
420 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
421 ssr &= ~IOASIC_CSR_DMAEN_ISDN_T;
422 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
423
424 d->size = (vaddr_t)end - (vaddr_t)start;
425 if (bus_dmamap_create(sc->sc_dmat, d->size,
426 BBA_MAX_DMA_SEGMENTS, IOASIC_DMA_BLOCKSIZE,
427 BBA_DMABUF_BOUNDARY, BUS_DMA_NOWAIT, &d->dmam)) {
428 printf("bba_trigger_output: can't create DMA map\n");
429 goto bad;
430 }
431 state |= 1;
432
433 if (bus_dmamap_load(sc->sc_dmat, d->dmam, start, d->size, NULL,
434 BUS_DMA_WRITE | BUS_DMA_NOWAIT)) {
435 printf("bba_trigger_output: can't load DMA map\n");
436 goto bad;
437 }
438 bus_dmamap_sync(sc->sc_dmat, d->dmam, 0, d->size, BUS_DMASYNC_PREWRITE);
439 state |= 2;
440
441 d->intr = intr;
442 d->intr_arg = arg;
443 d->curseg = 1;
444
445 /* get physical address of buffer start */
446 phys = (tc_addr_t)d->dmam->dm_segs[0].ds_addr;
447 nphys = (tc_addr_t)d->dmam->dm_segs[1 % d->dmam->dm_nsegs].ds_addr;
448
449 /* setup DMA pointer */
450 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR,
451 IOASIC_DMA_ADDR(phys));
452 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR,
453 IOASIC_DMA_ADDR(nphys));
454
455 /* kick off DMA */
456 mtx_enter(&audio_lock);
457 ssr |= IOASIC_CSR_DMAEN_ISDN_T;
458 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
459
460 d->active = 1;
461 mtx_leave(&audio_lock);
462 return 0;
463
464 bad:
465 if (state & 2)
466 bus_dmamap_unload(sc->sc_dmat, d->dmam);
467 if (state & 1)
468 bus_dmamap_destroy(sc->sc_dmat, d->dmam);
469 return 1;
470 }
471
472 int
bba_trigger_input(void * v,void * start,void * end,int blksize,void (* intr)(void *),void * arg,struct audio_params * param)473 bba_trigger_input(void *v, void *start, void *end, int blksize,
474 void (*intr)(void *), void *arg, struct audio_params *param)
475 {
476 struct bba_softc *sc = v;
477 struct bba_dma_state *d;
478 uint32_t ssr;
479 tc_addr_t phys, nphys;
480 int state;
481
482 DPRINTF(("bba_trigger_input: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n",
483 sc, start, end, blksize, intr, arg));
484 d = &sc->sc_rx_dma_state;
485 state = 0;
486
487 /* disable any DMA */
488 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
489 ssr &= ~IOASIC_CSR_DMAEN_ISDN_R;
490 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
491
492 d->size = (vaddr_t)end - (vaddr_t)start;
493 if (bus_dmamap_create(sc->sc_dmat, d->size,
494 BBA_MAX_DMA_SEGMENTS, IOASIC_DMA_BLOCKSIZE,
495 BBA_DMABUF_BOUNDARY, BUS_DMA_NOWAIT, &d->dmam)) {
496 printf("bba_trigger_input: can't create DMA map\n");
497 goto bad;
498 }
499 state |= 1;
500
501 if (bus_dmamap_load(sc->sc_dmat, d->dmam, start, d->size, NULL,
502 BUS_DMA_READ | BUS_DMA_NOWAIT)) {
503 printf("bba_trigger_input: can't load DMA map\n");
504 goto bad;
505 }
506 bus_dmamap_sync(sc->sc_dmat, d->dmam, 0, d->size, BUS_DMASYNC_PREREAD);
507 state |= 2;
508
509 d->intr = intr;
510 d->intr_arg = arg;
511 d->curseg = 1;
512
513 /* get physical address of buffer start */
514 phys = (tc_addr_t)d->dmam->dm_segs[0].ds_addr;
515 nphys = (tc_addr_t)d->dmam->dm_segs[1 % d->dmam->dm_nsegs].ds_addr;
516
517 /* setup DMA pointer */
518 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR,
519 IOASIC_DMA_ADDR(phys));
520 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR,
521 IOASIC_DMA_ADDR(nphys));
522
523 /* kick off DMA */
524 mtx_enter(&audio_lock);
525 ssr |= IOASIC_CSR_DMAEN_ISDN_R;
526 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr);
527
528 d->active = 1;
529 mtx_leave(&audio_lock);
530 return 0;
531
532 bad:
533 if (state & 2)
534 bus_dmamap_unload(sc->sc_dmat, d->dmam);
535 if (state & 1)
536 bus_dmamap_destroy(sc->sc_dmat, d->dmam);
537 return 1;
538 }
539
540 int
bba_intr(void * v)541 bba_intr(void *v)
542 {
543 struct bba_softc *sc = v;
544 struct bba_dma_state *d;
545 tc_addr_t nphys;
546 int mask;
547
548 mtx_enter(&audio_lock);
549
550 mask = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_INTR);
551
552 if (mask & IOASIC_INTR_ISDN_TXLOAD) {
553 d = &sc->sc_tx_dma_state;
554 d->curseg = (d->curseg+1) % d->dmam->dm_nsegs;
555 nphys = (tc_addr_t)d->dmam->dm_segs[d->curseg].ds_addr;
556 bus_space_write_4(sc->sc_bst, sc->sc_bsh,
557 IOASIC_ISDN_X_NEXTPTR, IOASIC_DMA_ADDR(nphys));
558 if (d->intr != NULL)
559 (*d->intr)(d->intr_arg);
560 }
561 if (mask & IOASIC_INTR_ISDN_RXLOAD) {
562 d = &sc->sc_rx_dma_state;
563 d->curseg = (d->curseg+1) % d->dmam->dm_nsegs;
564 nphys = (tc_addr_t)d->dmam->dm_segs[d->curseg].ds_addr;
565 bus_space_write_4(sc->sc_bst, sc->sc_bsh,
566 IOASIC_ISDN_R_NEXTPTR, IOASIC_DMA_ADDR(nphys));
567 if (d->intr != NULL)
568 (*d->intr)(d->intr_arg);
569 }
570
571 mtx_leave(&audio_lock);
572
573 return 0;
574 }
575
576 int
bba_round_blocksize(void * v,int blk)577 bba_round_blocksize(void *v, int blk)
578 {
579 return IOASIC_DMA_BLOCKSIZE;
580 }
581
582
583 /* indirect write */
584 void
bba_codec_iwrite(struct am7930_softc * sc,int reg,uint8_t val)585 bba_codec_iwrite(struct am7930_softc *sc, int reg, uint8_t val)
586 {
587 DPRINTF(("bba_codec_iwrite(): sc=%p, reg=%02x, val=%02x\n", sc, reg, val));
588 bba_codec_dwrite(sc, AM7930_DREG_CR, reg);
589 bba_codec_dwrite(sc, AM7930_DREG_DR, val);
590 }
591
592
593 void
bba_codec_iwrite16(struct am7930_softc * sc,int reg,uint16_t val)594 bba_codec_iwrite16(struct am7930_softc *sc, int reg, uint16_t val)
595 {
596 DPRINTF(("bba_codec_iwrite16(): sc=%p, reg=%02x, val=%04x\n", sc, reg, val));
597 bba_codec_dwrite(sc, AM7930_DREG_CR, reg);
598 bba_codec_dwrite(sc, AM7930_DREG_DR, val);
599 bba_codec_dwrite(sc, AM7930_DREG_DR, val >> 8);
600 }
601
602
603 /* indirect read */
604 uint8_t
bba_codec_iread(struct am7930_softc * sc,int reg)605 bba_codec_iread(struct am7930_softc *sc, int reg)
606 {
607 uint8_t val;
608
609 DPRINTF(("bba_codec_iread(): sc=%p, reg=%02x\n", sc, reg));
610 bba_codec_dwrite(sc, AM7930_DREG_CR, reg);
611 val = bba_codec_dread(sc, AM7930_DREG_DR);
612
613 DPRINTF(("read 0x%02x (%d)\n", val, val));
614
615 return val;
616 }
617
618 uint16_t
bba_codec_iread16(struct am7930_softc * sc,int reg)619 bba_codec_iread16(struct am7930_softc *sc, int reg)
620 {
621 uint16_t val;
622
623 DPRINTF(("bba_codec_iread16(): sc=%p, reg=%02x\n", sc, reg));
624 bba_codec_dwrite(sc, AM7930_DREG_CR, reg);
625 val = bba_codec_dread(sc, AM7930_DREG_DR);
626 val |= bba_codec_dread(sc, AM7930_DREG_DR) << 8;
627
628 return val;
629 }
630
631
632 /* direct write */
633 void
bba_codec_dwrite(struct am7930_softc * asc,int reg,uint8_t val)634 bba_codec_dwrite(struct am7930_softc *asc, int reg, uint8_t val)
635 {
636 struct bba_softc *sc = (struct bba_softc *)asc;
637
638 #if defined(__alpha__)
639 bus_space_write_4(sc->sc_bst, sc->sc_codec_bsh, reg << 2, val << 8);
640 #else
641 bus_space_write_4(sc->sc_bst, sc->sc_codec_bsh, reg << 6, val);
642 #endif
643 }
644
645 /* direct read */
646 uint8_t
bba_codec_dread(struct am7930_softc * asc,int reg)647 bba_codec_dread(struct am7930_softc *asc, int reg)
648 {
649 struct bba_softc *sc = (struct bba_softc *)asc;
650
651 #if defined(__alpha__)
652 return (bus_space_read_4(sc->sc_bst, sc->sc_codec_bsh, reg << 2) >> 8) &
653 0xff;
654 #else
655 return bus_space_read_4(sc->sc_bst, sc->sc_codec_bsh, reg << 6) & 0xff;
656 #endif
657 }
658