1 /* $NetBSD: bba.c,v 1.5 2000/06/05 23:02:04 gmcgarry Exp $ */ 2 3 /* 4 * Copyright (c) 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the NetBSD 18 * Foundation, Inc. and its contributors. 19 * 4. Neither the name of The NetBSD Foundation nor the names of its 20 * contributors may be used to endorse or promote products derived 21 * from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 27 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 /* maxine/alpha baseboard audio (bba) */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/kernel.h> 41 #include <sys/device.h> 42 #include <sys/malloc.h> 43 44 #include <machine/bus.h> 45 #include <machine/autoconf.h> 46 #include <machine/cpu.h> 47 48 #include <vm/vm.h> /* for PAGE_SIZE */ 49 50 #include <sys/audioio.h> 51 #include <dev/audio_if.h> 52 53 #include <dev/ic/am7930reg.h> 54 #include <dev/ic/am7930var.h> 55 56 #include <dev/tc/tcvar.h> 57 #include <dev/tc/ioasicreg.h> 58 #include <dev/tc/ioasicvar.h> 59 60 #ifdef AUDIO_DEBUG 61 #define DPRINTF(x) if (am7930debug) printf x 62 #else 63 #define DPRINTF(x) 64 #endif /* AUDIO_DEBUG */ 65 66 #define BBA_MAX_DMA_SEGMENTS 16 67 #define BBA_REGISTER_SHIFT 6 68 69 struct bba_mem { 70 bus_addr_t addr; 71 bus_size_t size; 72 caddr_t kva; 73 struct bba_mem *next; 74 }; 75 76 struct bba_dma_state { 77 bus_dmamap_t dmam; /* dma map */ 78 int active; 79 int curseg; /* current segment in dma buffer */ 80 void (*intr)__P((void *)); /* higher-level audio handler */ 81 void *intr_arg; 82 }; 83 84 struct bba_softc { 85 struct am7930_softc sc_am7930; /* glue to MI code */ 86 87 bus_space_tag_t sc_bst; /* IOASIC bus tag/handle */ 88 bus_space_handle_t sc_bsh; 89 bus_dma_tag_t sc_dmat; 90 bus_space_handle_t sc_codec_bsh; /* codec bus space handle */ 91 92 struct bba_mem *sc_mem_head; /* list of buffers */ 93 94 struct bba_dma_state sc_tx_dma_state; 95 struct bba_dma_state sc_rx_dma_state; 96 }; 97 98 int bba_match __P((struct device *, struct cfdata *, void *)); 99 void bba_attach __P((struct device *, struct device *, void *)); 100 101 struct cfattach bba_ca = { 102 sizeof(struct bba_softc), bba_match, bba_attach 103 }; 104 105 /* 106 * Define our interface into the am7930 MI driver. 107 */ 108 109 u_int8_t bba_codec_iread __P((struct am7930_softc *, int)); 110 u_int16_t bba_codec_iread16 __P((struct am7930_softc *, int)); 111 void bba_codec_iwrite __P((struct am7930_softc *, int, u_int8_t)); 112 void bba_codec_iwrite16 __P((struct am7930_softc *, int, u_int16_t)); 113 void bba_onopen __P((struct am7930_softc *sc)); 114 void bba_onclose __P((struct am7930_softc *sc)); 115 void bba_output_conv __P((void *, u_int8_t *, int)); 116 void bba_input_conv __P((void *, u_int8_t *, int)); 117 118 struct am7930_glue bba_glue = { 119 bba_codec_iread, 120 bba_codec_iwrite, 121 bba_codec_iread16, 122 bba_codec_iwrite16, 123 bba_onopen, 124 bba_onclose, 125 4, 126 bba_input_conv, 127 bba_output_conv, 128 }; 129 130 /* 131 * Define our interface to the higher level audio driver. 132 */ 133 134 int bba_round_blocksize __P((void *, int)); 135 int bba_halt_output __P((void *)); 136 int bba_halt_input __P((void *)); 137 int bba_getdev __P((void *, struct audio_device *)); 138 void *bba_allocm __P((void *, int, size_t, int, int)); 139 void bba_freem __P((void *, void *, int)); 140 size_t bba_round_buffersize __P((void *, int, size_t)); 141 int bba_trigger_output __P((void *, void *, void *, int, 142 void (*)(void *), void *, struct audio_params *)); 143 int bba_trigger_input __P((void *, void *, void *, int, 144 void (*)(void *), void *, struct audio_params *)); 145 146 struct audio_hw_if sa_hw_if = { 147 am7930_open, 148 am7930_close, 149 0, 150 am7930_query_encoding, 151 am7930_set_params, 152 bba_round_blocksize, /* md */ 153 am7930_commit_settings, 154 0, 155 0, 156 0, 157 0, 158 bba_halt_output, /* md */ 159 bba_halt_input, /* md */ 160 0, 161 bba_getdev, 162 0, 163 am7930_set_port, 164 am7930_get_port, 165 am7930_query_devinfo, 166 bba_allocm, /* md */ 167 bba_freem, /* md */ 168 bba_round_buffersize, /* md */ 169 0, 170 am7930_get_props, 171 bba_trigger_output, /* md */ 172 bba_trigger_input /* md */ 173 }; 174 175 struct audio_device bba_device = { 176 "am7930", 177 "x", 178 "bba" 179 }; 180 181 int bba_intr __P((void *)); 182 void bba_reset __P((struct bba_softc *, int)); 183 void bba_codec_dwrite __P((struct am7930_softc *, int, u_int8_t)); 184 u_int8_t bba_codec_dread __P((struct am7930_softc *, int)); 185 186 int bba_match(parent, cf, aux) 187 struct device *parent; 188 struct cfdata *cf; 189 void *aux; 190 { 191 struct ioasicdev_attach_args *ia = aux; 192 193 if (strcmp(ia->iada_modname, "isdn") != 0 && 194 strcmp(ia->iada_modname, "AMD79c30") != 0) 195 return 0; 196 197 return 1; 198 } 199 200 201 void 202 bba_attach(parent, self, aux) 203 struct device *parent; 204 struct device *self; 205 void *aux; 206 { 207 struct ioasicdev_attach_args *ia = aux; 208 struct bba_softc *sc = (struct bba_softc *)self; 209 struct am7930_softc *asc = &sc->sc_am7930; 210 211 sc->sc_bst = ((struct ioasic_softc *)parent)->sc_bst; 212 sc->sc_bsh = ((struct ioasic_softc *)parent)->sc_bsh; 213 sc->sc_dmat = ((struct ioasic_softc *)parent)->sc_dmat; 214 215 /* get the bus space handle for codec */ 216 if (bus_space_subregion(sc->sc_bst, sc->sc_bsh, 217 ia->iada_offset, 0, &sc->sc_codec_bsh)) { 218 printf("%s: unable to map device\n", asc->sc_dev.dv_xname); 219 return; 220 } 221 222 printf("\n"); 223 224 bba_reset(sc,1); 225 226 /* 227 * Set up glue for MI code early; we use some of it here. 228 */ 229 asc->sc_glue = &bba_glue; 230 231 /* 232 * MI initialisation. We will be doing DMA. 233 */ 234 am7930_init(asc, AUDIOAMD_DMA_MODE); 235 236 ioasic_intr_establish(parent, ia->iada_cookie, TC_IPL_NONE, 237 bba_intr, sc); 238 239 audio_attach_mi(&sa_hw_if, asc, &asc->sc_dev); 240 } 241 242 243 void 244 bba_onopen(sc) 245 struct am7930_softc *sc; 246 { 247 bba_reset((struct bba_softc *)sc, 0); 248 } 249 250 251 void 252 bba_onclose(sc) 253 struct am7930_softc *sc; 254 { 255 bba_halt_input((struct bba_softc *)sc); 256 bba_halt_output((struct bba_softc *)sc); 257 } 258 259 260 void 261 bba_reset(sc, reset) 262 struct bba_softc *sc; 263 int reset; 264 { 265 u_int32_t ssr; 266 267 /* disable any DMA and reset the codec */ 268 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 269 ssr &= ~(IOASIC_CSR_DMAEN_ISDN_T | IOASIC_CSR_DMAEN_ISDN_R); 270 if (reset) 271 ssr &= ~IOASIC_CSR_ISDN_ENABLE; 272 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 273 DELAY(10); /* 400ns required for codec to reset */ 274 275 /* initialise DMA pointers */ 276 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR, -1); 277 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR, -1); 278 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR, -1); 279 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR, -1); 280 281 /* take out of reset state */ 282 if (reset) { 283 ssr |= IOASIC_CSR_ISDN_ENABLE; 284 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 285 } 286 287 } 288 289 290 void * 291 bba_allocm(addr, direction, size, pool, flags) 292 void *addr; 293 int direction; 294 size_t size; 295 int pool, flags; 296 { 297 struct am7930_softc *asc = addr; 298 struct bba_softc *sc = addr; 299 bus_dma_segment_t seg; 300 int rseg; 301 caddr_t kva; 302 struct bba_mem *m; 303 int state = 0; 304 305 DPRINTF(("bba_allocm: size = %d\n",size)); 306 307 if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &seg, 308 1, &rseg, BUS_DMA_NOWAIT)) { 309 printf("%s: can't allocate DMA buffer\n", 310 asc->sc_dev.dv_xname); 311 goto bad; 312 } 313 state |= 1; 314 315 if (bus_dmamem_map(sc->sc_dmat, &seg, rseg, size, 316 &kva, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) { 317 printf("%s: can't map DMA buffer\n", asc->sc_dev.dv_xname); 318 goto bad; 319 } 320 state |= 2; 321 322 m = malloc(sizeof(struct bba_mem), pool, flags); 323 if (m == NULL) 324 goto bad; 325 m->addr = seg.ds_addr; 326 m->size = seg.ds_len; 327 m->kva = kva; 328 m->next = sc->sc_mem_head; 329 sc->sc_mem_head = m; 330 331 return (void *)kva; 332 333 bad: 334 if (state & 2) 335 bus_dmamem_unmap(sc->sc_dmat, kva, size); 336 if (state & 1) 337 bus_dmamem_free(sc->sc_dmat, &seg, 1); 338 return NULL; 339 } 340 341 342 void 343 bba_freem(addr, ptr, pool) 344 void *addr; 345 void *ptr; 346 int pool; 347 { 348 struct bba_softc *sc = addr; 349 struct bba_mem **mp, *m; 350 bus_dma_segment_t seg; 351 caddr_t kva = (caddr_t)addr; 352 353 for (mp = &sc->sc_mem_head; *mp && (*mp)->kva != kva; 354 mp = &(*mp)->next) 355 /* nothing */ ; 356 m = *mp; 357 if (m != NULL) { 358 printf("bba_freem: freeing unallocted memory\n"); 359 return; 360 } 361 *mp = m->next; 362 bus_dmamem_unmap(sc->sc_dmat, kva, m->size); 363 364 seg.ds_addr = m->addr; 365 seg.ds_len = m->size; 366 bus_dmamem_free(sc->sc_dmat, &seg, 1); 367 free(m, pool); 368 } 369 370 371 size_t 372 bba_round_buffersize(addr, direction, size) 373 void *addr; 374 int direction; 375 size_t size; 376 { 377 DPRINTF(("bba_round_buffersize: size=%d\n", size)); 378 379 #define BBA_BUFFERSIZE (BBA_MAX_DMA_SEGMENTS * PAGE_SIZE) 380 return (size > BBA_BUFFERSIZE ? BBA_BUFFERSIZE : round_page(size)); 381 } 382 383 384 int 385 bba_halt_output(addr) 386 void *addr; 387 { 388 struct bba_softc *sc = addr; 389 struct bba_dma_state *d = &sc->sc_tx_dma_state; 390 u_int32_t ssr; 391 392 /* disable any DMA */ 393 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 394 ssr &= ~IOASIC_CSR_DMAEN_ISDN_T; 395 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 396 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR, -1); 397 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR, -1); 398 399 if (d->active) { 400 bus_dmamap_unload(sc->sc_dmat, d->dmam); 401 bus_dmamap_destroy(sc->sc_dmat, d->dmam); 402 d->active = 0; 403 } 404 405 return 0; 406 } 407 408 409 int 410 bba_halt_input(addr) 411 void *addr; 412 { 413 struct bba_softc *sc = addr; 414 struct bba_dma_state *d = &sc->sc_rx_dma_state; 415 u_int32_t ssr; 416 417 /* disable any DMA */ 418 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 419 ssr &= ~IOASIC_CSR_DMAEN_ISDN_R; 420 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 421 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR, -1); 422 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR, -1); 423 424 if (d->active) { 425 bus_dmamap_unload(sc->sc_dmat, d->dmam); 426 bus_dmamap_destroy(sc->sc_dmat, d->dmam); 427 d->active = 0; 428 } 429 430 return 0; 431 } 432 433 434 int 435 bba_getdev(addr, retp) 436 void *addr; 437 struct audio_device *retp; 438 { 439 *retp = bba_device; 440 return 0; 441 } 442 443 444 int 445 bba_trigger_output(addr, start, end, blksize, intr, arg, param) 446 void *addr; 447 void *start, *end; 448 int blksize; 449 void (*intr) __P((void *)); 450 void *arg; 451 struct audio_params *param; 452 { 453 struct bba_softc *sc = addr; 454 struct bba_dma_state *d = &sc->sc_tx_dma_state; 455 u_int32_t ssr; 456 tc_addr_t phys, nphys; 457 int state = 0; 458 459 DPRINTF(("bba_trigger_output: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n", 460 addr, start, end, blksize, intr, arg)); 461 462 if (bus_dmamap_create(sc->sc_dmat, (char *)end - (char *)start, 463 BBA_MAX_DMA_SEGMENTS, PAGE_SIZE, 0, BUS_DMA_NOWAIT, &d->dmam)) { 464 printf("bba_trigger_output: can't create DMA map\n"); 465 goto bad; 466 } 467 state |= 1; 468 469 if (bus_dmamap_load(sc->sc_dmat, d->dmam, start, 470 (char *)end - (char *)start, NULL, BUS_DMA_NOWAIT)) { 471 printf("bba_trigger_output: can't load DMA map\n"); 472 goto bad; 473 } 474 state |= 2; 475 476 /* disable any DMA */ 477 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 478 ssr &= ~IOASIC_CSR_DMAEN_ISDN_T; 479 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 480 481 d->intr = intr; 482 d->intr_arg = arg; 483 d->curseg = 1; 484 485 /* get physical address of buffer start */ 486 phys = (tc_addr_t)d->dmam->dm_segs[0].ds_addr; 487 nphys = (tc_addr_t)d->dmam->dm_segs[1].ds_addr; 488 489 /* setup DMA pointer */ 490 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR, 491 IOASIC_DMA_ADDR(phys)); 492 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR, 493 IOASIC_DMA_ADDR(nphys)); 494 495 /* kick off DMA */ 496 ssr |= IOASIC_CSR_DMAEN_ISDN_T; 497 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 498 499 d->active = 1; 500 501 return 0; 502 503 bad: 504 if (state & 2) 505 bus_dmamap_unload(sc->sc_dmat, d->dmam); 506 if (state & 1) 507 bus_dmamap_destroy(sc->sc_dmat, d->dmam); 508 return 1; 509 } 510 511 512 int 513 bba_trigger_input(addr, start, end, blksize, intr, arg, param) 514 void *addr; 515 void *start, *end; 516 int blksize; 517 void (*intr) __P((void *)); 518 void *arg; 519 struct audio_params *param; 520 { 521 struct bba_softc *sc = (struct bba_softc *)addr; 522 struct bba_dma_state *d = &sc->sc_rx_dma_state; 523 tc_addr_t phys, nphys; 524 u_int32_t ssr; 525 int state = 0; 526 527 DPRINTF(("bba_trigger_input: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n", 528 addr, start, end, blksize, intr, arg)); 529 530 if (bus_dmamap_create(sc->sc_dmat, (char *)end - (char *)start, 531 BBA_MAX_DMA_SEGMENTS, PAGE_SIZE, 0, BUS_DMA_NOWAIT, &d->dmam)) { 532 printf("bba_trigger_input: can't create DMA map\n"); 533 goto bad; 534 } 535 state |= 1; 536 537 if (bus_dmamap_load(sc->sc_dmat, d->dmam, start, 538 (char *)end - (char *)start, NULL, BUS_DMA_NOWAIT)) { 539 printf("bba_trigger_input: can't load DMA map\n"); 540 goto bad; 541 } 542 state |= 2; 543 544 /* disable any DMA */ 545 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 546 ssr &= ~IOASIC_CSR_DMAEN_ISDN_R; 547 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 548 549 d->intr = intr; 550 d->intr_arg = arg; 551 d->curseg = 1; 552 553 /* get physical address of buffer start */ 554 phys = (tc_addr_t)d->dmam->dm_segs[0].ds_addr; 555 nphys = (tc_addr_t)d->dmam->dm_segs[1].ds_addr; 556 557 /* setup DMA pointer */ 558 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR, 559 IOASIC_DMA_ADDR(phys)); 560 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR, 561 IOASIC_DMA_ADDR(nphys)); 562 563 /* kick off DMA */ 564 ssr |= IOASIC_CSR_DMAEN_ISDN_R; 565 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 566 567 d->active = 1; 568 569 return 0; 570 571 bad: 572 if (state & 2) 573 bus_dmamap_unload(sc->sc_dmat, d->dmam); 574 if (state & 1) 575 bus_dmamap_destroy(sc->sc_dmat, d->dmam); 576 return 1; 577 } 578 579 int 580 bba_intr(addr) 581 void *addr; 582 { 583 struct bba_softc *sc = addr; 584 struct bba_dma_state *d; 585 tc_addr_t nphys; 586 int s, mask; 587 588 s = splaudio(); 589 590 mask = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_INTR); 591 592 if (mask & IOASIC_INTR_ISDN_TXLOAD) { 593 d = &sc->sc_tx_dma_state; 594 d->curseg = (d->curseg+1) % d->dmam->dm_nsegs; 595 nphys = (tc_addr_t)d->dmam->dm_segs[d->curseg].ds_addr; 596 bus_space_write_4(sc->sc_bst, sc->sc_bsh, 597 IOASIC_ISDN_X_NEXTPTR, IOASIC_DMA_ADDR(nphys)); 598 if (d->intr != NULL) 599 (*d->intr)(d->intr_arg); 600 } 601 if (mask & IOASIC_INTR_ISDN_RXLOAD) { 602 d = &sc->sc_rx_dma_state; 603 d->curseg = (d->curseg+1) % d->dmam->dm_nsegs; 604 nphys = (tc_addr_t)d->dmam->dm_segs[d->curseg].ds_addr; 605 bus_space_write_4(sc->sc_bst, sc->sc_bsh, 606 IOASIC_ISDN_R_NEXTPTR, IOASIC_DMA_ADDR(nphys)); 607 if (d->intr != NULL) 608 (*d->intr)(d->intr_arg); 609 } 610 611 splx(s); 612 613 return 0; 614 } 615 616 617 void 618 bba_input_conv(v, p, cc) 619 void *v; 620 u_int8_t *p; 621 int cc; 622 { 623 u_int8_t *q = p; 624 625 DPRINTF(("bba_input_conv(): v=%p p=%p cc=%d\n", v, p, cc)); 626 627 /* 628 * p points start of buffer 629 * cc is the number of bytes in the destination buffer 630 */ 631 632 while (--cc >= 0) { 633 *p = ((*(u_int32_t *)q)>>16)&0xff; 634 q += 4; 635 p++; 636 } 637 } 638 639 640 void 641 bba_output_conv(v, p, cc) 642 void *v; 643 u_int8_t *p; 644 int cc; 645 { 646 u_int8_t *q = p; 647 648 DPRINTF(("bba_output_conv(): v=%p p=%p cc=%d\n", v, p, cc)); 649 650 /* 651 * p points start of buffer 652 * cc is the number of bytes in the source buffer 653 */ 654 655 p += cc; 656 q += cc * 4; 657 while (--cc >= 0) { 658 q -= 4; 659 p -= 1; 660 *(u_int32_t *)q = (*p<<16); 661 } 662 } 663 664 665 int 666 bba_round_blocksize(addr, blk) 667 void *addr; 668 int blk; 669 { 670 return (PAGE_SIZE); 671 } 672 673 674 /* indirect write */ 675 void 676 bba_codec_iwrite(sc, reg, val) 677 struct am7930_softc *sc; 678 int reg; 679 u_int8_t val; 680 { 681 DPRINTF(("bba_codec_iwrite(): sc=%p, reg=%d, val=%d\n",sc,reg,val)); 682 683 bba_codec_dwrite(sc, AM7930_DREG_CR, reg); 684 bba_codec_dwrite(sc, AM7930_DREG_DR, val); 685 } 686 687 688 void 689 bba_codec_iwrite16(sc, reg, val) 690 struct am7930_softc *sc; 691 int reg; 692 u_int16_t val; 693 { 694 DPRINTF(("bba_codec_iwrite16(): sc=%p, reg=%d, val=%d\n",sc,reg,val)); 695 696 bba_codec_dwrite(sc, AM7930_DREG_CR, reg); 697 bba_codec_dwrite(sc, AM7930_DREG_DR, val); 698 bba_codec_dwrite(sc, AM7930_DREG_DR, val>>8); 699 } 700 701 702 u_int16_t 703 bba_codec_iread16(sc, reg) 704 struct am7930_softc *sc; 705 int reg; 706 { 707 u_int16_t val; 708 DPRINTF(("bba_codec_iread16(): sc=%p, reg=%d\n",sc,reg)); 709 710 bba_codec_dwrite(sc, AM7930_DREG_CR, reg); 711 val = bba_codec_dread(sc, AM7930_DREG_DR) << 8; 712 val |= bba_codec_dread(sc, AM7930_DREG_DR); 713 714 return val; 715 } 716 717 718 /* indirect read */ 719 u_int8_t 720 bba_codec_iread(sc, reg) 721 struct am7930_softc *sc; 722 int reg; 723 { 724 u_int8_t val; 725 726 DPRINTF(("bba_codec_iread(): sc=%p, reg=%d\n",sc,reg)); 727 728 bba_codec_dwrite(sc, AM7930_DREG_CR, reg); 729 val = bba_codec_dread(sc, AM7930_DREG_DR); 730 731 DPRINTF(("read 0x%x (%d)\n", val, val)); 732 733 return val; 734 } 735 736 737 #define TIMETOWASTE 50 738 739 /* direct write */ 740 void 741 bba_codec_dwrite(asc, reg, val) 742 struct am7930_softc *asc; 743 int reg; 744 u_int8_t val; 745 { 746 struct bba_softc *sc = (struct bba_softc *)asc; 747 int i; 748 749 DPRINTF(("bba_codec_dwrite(): sc=%p, reg=%d, val=%d\n",sc,reg,val)); 750 751 bus_space_write_4(sc->sc_bst, sc->sc_codec_bsh, 752 (reg<<BBA_REGISTER_SHIFT), val); 753 754 for (i=0; i<TIMETOWASTE; i++) {}; 755 } 756 757 /* direct read */ 758 u_int8_t 759 bba_codec_dread(asc, reg) 760 struct am7930_softc *asc; 761 int reg; 762 { 763 struct bba_softc *sc = (struct bba_softc *)asc; 764 u_int8_t val; 765 int i; 766 767 DPRINTF(("bba_codec_dread(): sc=%p, reg=%d\n",sc,reg)); 768 769 val = bus_space_read_1(sc->sc_bst, sc->sc_codec_bsh, 770 (reg<<BBA_REGISTER_SHIFT)); 771 772 for (i=0; i<TIMETOWASTE; i++) {}; 773 774 return val; 775 } 776