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 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 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 228 bba_onopen(struct am7930_softc *sc) 229 { 230 } 231 232 void 233 bba_onclose(struct am7930_softc *sc) 234 { 235 } 236 237 void 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 * 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 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 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 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 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 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 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 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 577 bba_round_blocksize(void *v, int blk) 578 { 579 return IOASIC_DMA_BLOCKSIZE; 580 } 581 582 583 /* indirect write */ 584 void 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 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 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 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 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 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