1 /* $OpenBSD: bba.c,v 1.7 2016/09/19 06:46:44 ratchov 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_get_props(void *); 150 int bba_trigger_output(void *, void *, void *, int, 151 void (*)(void *), void *, struct audio_params *); 152 int bba_trigger_input(void *, void *, void *, int, 153 void (*)(void *), void *, struct audio_params *); 154 155 struct audio_hw_if bba_hw_if = { 156 am7930_open, 157 am7930_close, 158 am7930_set_params, 159 bba_round_blocksize, /* md */ 160 am7930_commit_settings, 161 NULL, 162 NULL, 163 NULL, 164 NULL, 165 bba_halt_output, /* md */ 166 bba_halt_input, /* md */ 167 NULL, 168 NULL, 169 am7930_set_port, 170 am7930_get_port, 171 am7930_query_devinfo, 172 bba_allocm, /* md */ 173 bba_freem, /* md */ 174 bba_round_buffersize, /* md */ 175 bba_get_props, 176 bba_trigger_output, /* md */ 177 bba_trigger_input /* md */ 178 }; 179 180 int bba_intr(void *); 181 void bba_reset(struct bba_softc *, int); 182 void bba_codec_dwrite(struct am7930_softc *, int, uint8_t); 183 uint8_t bba_codec_dread(struct am7930_softc *, int); 184 185 int 186 bba_match(struct device *parent, void *vcf, void *aux) 187 { 188 struct ioasicdev_attach_args *ia = aux; 189 190 if (strcmp(ia->iada_modname, "isdn") != 0 && 191 strcmp(ia->iada_modname, "AMD79c30") != 0) 192 return 0; 193 194 return 1; 195 } 196 197 void 198 bba_attach(struct device *parent, struct device *self, void *aux) 199 { 200 struct ioasicdev_attach_args *ia = aux; 201 struct bba_softc *sc = (struct bba_softc *)self; 202 struct ioasic_softc *iosc = (struct ioasic_softc *)parent; 203 204 sc->sc_bst = iosc->sc_bst; 205 sc->sc_bsh = iosc->sc_bsh; 206 sc->sc_dmat = iosc->sc_dmat; 207 208 /* get the bus space handle for codec */ 209 if (bus_space_subregion(sc->sc_bst, sc->sc_bsh, 210 ia->iada_offset, 0, &sc->sc_codec_bsh)) { 211 printf(": unable to map device\n"); 212 return; 213 } 214 215 printf("\n"); 216 217 bba_reset(sc,1); 218 219 /* 220 * Set up glue for MI code early; we use some of it here. 221 */ 222 sc->sc_am7930.sc_glue = &bba_glue; 223 224 /* 225 * MI initialisation. We will be doing DMA. 226 */ 227 am7930_init(&sc->sc_am7930, AUDIOAMD_DMA_MODE); 228 229 ioasic_intr_establish(parent, ia->iada_cookie, IPL_AUDIO, 230 bba_intr, sc, self->dv_xname); 231 232 audio_attach_mi(&bba_hw_if, sc, self); 233 } 234 235 void 236 bba_onopen(struct am7930_softc *sc) 237 { 238 } 239 240 void 241 bba_onclose(struct am7930_softc *sc) 242 { 243 } 244 245 void 246 bba_reset(struct bba_softc *sc, int reset) 247 { 248 uint32_t ssr; 249 250 /* disable any DMA and reset the codec */ 251 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 252 ssr &= ~(IOASIC_CSR_DMAEN_ISDN_T | IOASIC_CSR_DMAEN_ISDN_R); 253 if (reset) 254 ssr &= ~IOASIC_CSR_ISDN_ENABLE; 255 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 256 DELAY(10); /* 400ns required for codec to reset */ 257 258 /* initialise DMA pointers */ 259 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR, 0); 260 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR, 0); 261 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR, 0); 262 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR, 0); 263 264 /* take out of reset state */ 265 if (reset) { 266 ssr |= IOASIC_CSR_ISDN_ENABLE; 267 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 268 } 269 270 } 271 272 void * 273 bba_allocm(void *v, int direction, size_t size, int mtype, int flags) 274 { 275 struct bba_softc *sc = v; 276 bus_dma_segment_t seg; 277 int rseg; 278 caddr_t kva; 279 struct bba_mem *m; 280 int w; 281 int state; 282 283 DPRINTF(("bba_allocm: size = %zu\n", size)); 284 state = 0; 285 w = (flags & M_NOWAIT) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK; 286 287 if (bus_dmamem_alloc(sc->sc_dmat, size, BBA_DMABUF_ALIGN, 288 BBA_DMABUF_BOUNDARY, &seg, 1, &rseg, w)) { 289 printf("%s: can't allocate DMA buffer\n", 290 sc->sc_am7930.sc_dev.dv_xname); 291 goto bad; 292 } 293 state |= 1; 294 295 if (bus_dmamem_map(sc->sc_dmat, &seg, rseg, size, 296 &kva, w | BUS_DMA_COHERENT)) { 297 printf("%s: can't map DMA buffer\n", 298 sc->sc_am7930.sc_dev.dv_xname); 299 goto bad; 300 } 301 state |= 2; 302 303 m = malloc(sizeof(struct bba_mem), mtype, flags | M_CANFAIL); 304 if (m == NULL) 305 goto bad; 306 m->addr = seg.ds_addr; 307 m->size = seg.ds_len; 308 m->kva = kva; 309 m->next = sc->sc_mem_head; 310 sc->sc_mem_head = m; 311 312 return (void *)kva; 313 314 bad: 315 if (state & 2) 316 bus_dmamem_unmap(sc->sc_dmat, kva, size); 317 if (state & 1) 318 bus_dmamem_free(sc->sc_dmat, &seg, 1); 319 return NULL; 320 } 321 322 void 323 bba_freem(void *v, void *ptr, int mtype) 324 { 325 struct bba_softc *sc = v; 326 struct bba_mem **mp, *m; 327 bus_dma_segment_t seg; 328 void *kva; 329 330 kva = (void *)ptr; 331 for (mp = &sc->sc_mem_head; *mp && (*mp)->kva != kva; mp = &(*mp)->next) 332 continue; 333 m = *mp; 334 if (m == NULL) { 335 printf("bba_freem: freeing unallocated memory\n"); 336 return; 337 } 338 *mp = m->next; 339 bus_dmamem_unmap(sc->sc_dmat, kva, m->size); 340 341 seg.ds_addr = m->addr; 342 seg.ds_len = m->size; 343 bus_dmamem_free(sc->sc_dmat, &seg, 1); 344 free(m, mtype, 0); 345 } 346 347 size_t 348 bba_round_buffersize(void *v, int direction, size_t size) 349 { 350 351 DPRINTF(("bba_round_buffersize: size=%zu\n", size)); 352 return size > BBA_DMABUF_SIZE ? BBA_DMABUF_SIZE : 353 roundup(size, IOASIC_DMA_BLOCKSIZE); 354 } 355 356 int 357 bba_halt_output(void *v) 358 { 359 struct bba_softc *sc = v; 360 struct bba_dma_state *d; 361 uint32_t ssr; 362 363 mtx_enter(&audio_lock); 364 d = &sc->sc_tx_dma_state; 365 /* disable any DMA */ 366 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 367 ssr &= ~IOASIC_CSR_DMAEN_ISDN_T; 368 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 369 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR, 0); 370 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR, 0); 371 mtx_leave(&audio_lock); 372 373 if (d->active) { 374 bus_dmamap_sync(sc->sc_dmat, d->dmam, 0, d->size, 375 BUS_DMASYNC_POSTWRITE); 376 bus_dmamap_unload(sc->sc_dmat, d->dmam); 377 bus_dmamap_destroy(sc->sc_dmat, d->dmam); 378 d->active = 0; 379 } 380 381 return 0; 382 } 383 384 int 385 bba_halt_input(void *v) 386 { 387 struct bba_softc *sc = v; 388 struct bba_dma_state *d; 389 uint32_t ssr; 390 391 mtx_enter(&audio_lock); 392 d = &sc->sc_rx_dma_state; 393 /* disable any DMA */ 394 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 395 ssr &= ~IOASIC_CSR_DMAEN_ISDN_R; 396 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 397 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR, 0); 398 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR, 0); 399 mtx_leave(&audio_lock); 400 401 if (d->active) { 402 bus_dmamap_sync(sc->sc_dmat, d->dmam, 0, d->size, 403 BUS_DMASYNC_POSTREAD); 404 bus_dmamap_unload(sc->sc_dmat, d->dmam); 405 bus_dmamap_destroy(sc->sc_dmat, d->dmam); 406 d->active = 0; 407 } 408 409 return 0; 410 } 411 412 int 413 bba_trigger_output(void *v, void *start, void *end, int blksize, 414 void (*intr)(void *), void *arg, struct audio_params *param) 415 { 416 struct bba_softc *sc = v; 417 struct bba_dma_state *d; 418 uint32_t ssr; 419 tc_addr_t phys, nphys; 420 int state; 421 422 DPRINTF(("bba_trigger_output: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n", 423 sc, start, end, blksize, intr, arg)); 424 d = &sc->sc_tx_dma_state; 425 state = 0; 426 427 /* disable any DMA */ 428 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 429 ssr &= ~IOASIC_CSR_DMAEN_ISDN_T; 430 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 431 432 d->size = (vaddr_t)end - (vaddr_t)start; 433 if (bus_dmamap_create(sc->sc_dmat, d->size, 434 BBA_MAX_DMA_SEGMENTS, IOASIC_DMA_BLOCKSIZE, 435 BBA_DMABUF_BOUNDARY, BUS_DMA_NOWAIT, &d->dmam)) { 436 printf("bba_trigger_output: can't create DMA map\n"); 437 goto bad; 438 } 439 state |= 1; 440 441 if (bus_dmamap_load(sc->sc_dmat, d->dmam, start, d->size, NULL, 442 BUS_DMA_WRITE | BUS_DMA_NOWAIT)) { 443 printf("bba_trigger_output: can't load DMA map\n"); 444 goto bad; 445 } 446 bus_dmamap_sync(sc->sc_dmat, d->dmam, 0, d->size, BUS_DMASYNC_PREWRITE); 447 state |= 2; 448 449 d->intr = intr; 450 d->intr_arg = arg; 451 d->curseg = 1; 452 453 /* get physical address of buffer start */ 454 phys = (tc_addr_t)d->dmam->dm_segs[0].ds_addr; 455 nphys = (tc_addr_t)d->dmam->dm_segs[1 % d->dmam->dm_nsegs].ds_addr; 456 457 /* setup DMA pointer */ 458 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR, 459 IOASIC_DMA_ADDR(phys)); 460 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR, 461 IOASIC_DMA_ADDR(nphys)); 462 463 /* kick off DMA */ 464 mtx_enter(&audio_lock); 465 ssr |= IOASIC_CSR_DMAEN_ISDN_T; 466 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 467 468 d->active = 1; 469 mtx_leave(&audio_lock); 470 return 0; 471 472 bad: 473 if (state & 2) 474 bus_dmamap_unload(sc->sc_dmat, d->dmam); 475 if (state & 1) 476 bus_dmamap_destroy(sc->sc_dmat, d->dmam); 477 return 1; 478 } 479 480 int 481 bba_trigger_input(void *v, void *start, void *end, int blksize, 482 void (*intr)(void *), void *arg, struct audio_params *param) 483 { 484 struct bba_softc *sc = v; 485 struct bba_dma_state *d; 486 uint32_t ssr; 487 tc_addr_t phys, nphys; 488 int state; 489 490 DPRINTF(("bba_trigger_input: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n", 491 sc, start, end, blksize, intr, arg)); 492 d = &sc->sc_rx_dma_state; 493 state = 0; 494 495 /* disable any DMA */ 496 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 497 ssr &= ~IOASIC_CSR_DMAEN_ISDN_R; 498 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 499 500 d->size = (vaddr_t)end - (vaddr_t)start; 501 if (bus_dmamap_create(sc->sc_dmat, d->size, 502 BBA_MAX_DMA_SEGMENTS, IOASIC_DMA_BLOCKSIZE, 503 BBA_DMABUF_BOUNDARY, BUS_DMA_NOWAIT, &d->dmam)) { 504 printf("bba_trigger_input: can't create DMA map\n"); 505 goto bad; 506 } 507 state |= 1; 508 509 if (bus_dmamap_load(sc->sc_dmat, d->dmam, start, d->size, NULL, 510 BUS_DMA_READ | BUS_DMA_NOWAIT)) { 511 printf("bba_trigger_input: can't load DMA map\n"); 512 goto bad; 513 } 514 bus_dmamap_sync(sc->sc_dmat, d->dmam, 0, d->size, BUS_DMASYNC_PREREAD); 515 state |= 2; 516 517 d->intr = intr; 518 d->intr_arg = arg; 519 d->curseg = 1; 520 521 /* get physical address of buffer start */ 522 phys = (tc_addr_t)d->dmam->dm_segs[0].ds_addr; 523 nphys = (tc_addr_t)d->dmam->dm_segs[1 % d->dmam->dm_nsegs].ds_addr; 524 525 /* setup DMA pointer */ 526 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR, 527 IOASIC_DMA_ADDR(phys)); 528 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR, 529 IOASIC_DMA_ADDR(nphys)); 530 531 /* kick off DMA */ 532 mtx_enter(&audio_lock); 533 ssr |= IOASIC_CSR_DMAEN_ISDN_R; 534 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 535 536 d->active = 1; 537 mtx_leave(&audio_lock); 538 return 0; 539 540 bad: 541 if (state & 2) 542 bus_dmamap_unload(sc->sc_dmat, d->dmam); 543 if (state & 1) 544 bus_dmamap_destroy(sc->sc_dmat, d->dmam); 545 return 1; 546 } 547 548 int 549 bba_intr(void *v) 550 { 551 struct bba_softc *sc = v; 552 struct bba_dma_state *d; 553 tc_addr_t nphys; 554 int mask; 555 556 mtx_enter(&audio_lock); 557 558 mask = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_INTR); 559 560 if (mask & IOASIC_INTR_ISDN_TXLOAD) { 561 d = &sc->sc_tx_dma_state; 562 d->curseg = (d->curseg+1) % d->dmam->dm_nsegs; 563 nphys = (tc_addr_t)d->dmam->dm_segs[d->curseg].ds_addr; 564 bus_space_write_4(sc->sc_bst, sc->sc_bsh, 565 IOASIC_ISDN_X_NEXTPTR, IOASIC_DMA_ADDR(nphys)); 566 if (d->intr != NULL) 567 (*d->intr)(d->intr_arg); 568 } 569 if (mask & IOASIC_INTR_ISDN_RXLOAD) { 570 d = &sc->sc_rx_dma_state; 571 d->curseg = (d->curseg+1) % d->dmam->dm_nsegs; 572 nphys = (tc_addr_t)d->dmam->dm_segs[d->curseg].ds_addr; 573 bus_space_write_4(sc->sc_bst, sc->sc_bsh, 574 IOASIC_ISDN_R_NEXTPTR, IOASIC_DMA_ADDR(nphys)); 575 if (d->intr != NULL) 576 (*d->intr)(d->intr_arg); 577 } 578 579 mtx_leave(&audio_lock); 580 581 return 0; 582 } 583 584 int 585 bba_get_props(void *v) 586 { 587 return AUDIO_PROP_MMAP | am7930_get_props(v); 588 } 589 590 int 591 bba_round_blocksize(void *v, int blk) 592 { 593 return IOASIC_DMA_BLOCKSIZE; 594 } 595 596 597 /* indirect write */ 598 void 599 bba_codec_iwrite(struct am7930_softc *sc, int reg, uint8_t val) 600 { 601 DPRINTF(("bba_codec_iwrite(): sc=%p, reg=%02x, val=%02x\n", sc, reg, val)); 602 bba_codec_dwrite(sc, AM7930_DREG_CR, reg); 603 bba_codec_dwrite(sc, AM7930_DREG_DR, val); 604 } 605 606 607 void 608 bba_codec_iwrite16(struct am7930_softc *sc, int reg, uint16_t val) 609 { 610 DPRINTF(("bba_codec_iwrite16(): sc=%p, reg=%02x, val=%04x\n", sc, reg, val)); 611 bba_codec_dwrite(sc, AM7930_DREG_CR, reg); 612 bba_codec_dwrite(sc, AM7930_DREG_DR, val); 613 bba_codec_dwrite(sc, AM7930_DREG_DR, val >> 8); 614 } 615 616 617 /* indirect read */ 618 uint8_t 619 bba_codec_iread(struct am7930_softc *sc, int reg) 620 { 621 uint8_t val; 622 623 DPRINTF(("bba_codec_iread(): 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 627 DPRINTF(("read 0x%02x (%d)\n", val, val)); 628 629 return val; 630 } 631 632 uint16_t 633 bba_codec_iread16(struct am7930_softc *sc, int reg) 634 { 635 uint16_t val; 636 637 DPRINTF(("bba_codec_iread16(): sc=%p, reg=%02x\n", sc, reg)); 638 bba_codec_dwrite(sc, AM7930_DREG_CR, reg); 639 val = bba_codec_dread(sc, AM7930_DREG_DR); 640 val |= bba_codec_dread(sc, AM7930_DREG_DR) << 8; 641 642 return val; 643 } 644 645 646 /* direct write */ 647 void 648 bba_codec_dwrite(struct am7930_softc *asc, int reg, uint8_t val) 649 { 650 struct bba_softc *sc = (struct bba_softc *)asc; 651 652 #if defined(__alpha__) 653 bus_space_write_4(sc->sc_bst, sc->sc_codec_bsh, reg << 2, val << 8); 654 #else 655 bus_space_write_4(sc->sc_bst, sc->sc_codec_bsh, reg << 6, val); 656 #endif 657 } 658 659 /* direct read */ 660 uint8_t 661 bba_codec_dread(struct am7930_softc *asc, int reg) 662 { 663 struct bba_softc *sc = (struct bba_softc *)asc; 664 665 #if defined(__alpha__) 666 return (bus_space_read_4(sc->sc_bst, sc->sc_codec_bsh, reg << 2) >> 8) & 667 0xff; 668 #else 669 return bus_space_read_4(sc->sc_bst, sc->sc_codec_bsh, reg << 6) & 0xff; 670 #endif 671 } 672