1 /* $NetBSD: mpc5200_ac97.c,v 1.2 2026/07/01 00:03:18 rkujawa Exp $ */ 2 3 /*- 4 * Copyright (c) 2026 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Radoslaw Kujawa. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Driver for the Freescale MPC5200B on-chip AC97 controller (a PSC in AC97 34 * mode), written with the assumption that it's connected to a codec that 35 * can be driver through the ac97(4) interface. 36 */ 37 38 #include <sys/cdefs.h> 39 __KERNEL_RCSID(0, "$NetBSD: mpc5200_ac97.c,v 1.2 2026/07/01 00:03:18 rkujawa Exp $"); 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/device.h> 44 #include <sys/bus.h> 45 #include <sys/mutex.h> 46 #include <sys/audioio.h> 47 48 #include <dev/audio/audio_if.h> 49 50 #include <dev/ic/ac97var.h> 51 52 #include <dev/ofw/openfirm.h> 53 54 #include <machine/intr.h> 55 56 #include <powerpc/mpc5200/obiovar.h> 57 #include <powerpc/mpc5200/mpc5200reg.h> 58 #include <powerpc/mpc5200/pscreg.h> 59 #include <powerpc/mpc5200/mpc5200_ac97reg.h> 60 #include <powerpc/mpc5200/mpc5200_ac97var.h> 61 #include <powerpc/mpc5200/bestcommvar.h> 62 63 /* 64 * BestComm wiring for the PSC2 transmit path. 65 */ 66 #define MPCAC97_TX_TASK 12 67 #define MPCAC97_TX_INITIATOR 12 68 #define MPCAC97_TX_PRIO 5 /* SDMA initiator priority (0-7) */ 69 #define AC97_FIFO_TX PSC_TB /* DMA target: Tx Buffer (0x0c) */ 70 71 #define MPCAC97_RATE 48000 /* AC97 fixed sample rate */ 72 #define MPCAC97_FRAME_SIZE 8 /* 2 ch * 32-bit slot word */ 73 #define MPCAC97_MAX_NBLK 256 /* SDMA descriptor-ring sanity cap */ 74 75 /* 76 * Tx FIFO "almost empty" threshold 77 */ 78 #define MPCAC97_TFALARM 0x100 79 #define MPCAC97_TFGRAN 0x04 80 81 /* Codec register-access poll limits. */ 82 #define AC97_CMD_TIMEOUT 1000 /* x10us = 10ms for a command frame */ 83 #define AC97_READY_TIMEOUT 1000 /* x1ms = 1s for codec power-up */ 84 85 #define AC97_REG_POWERDOWN 0x26 /* powerdown ctrl/status (AC97_REG_POWER) */ 86 #define AC97_POWER_READY 0x000f /* ADC+DAC+ANL+REF ready bits */ 87 88 static int mpcac97_match(device_t, cfdata_t, void *); 89 static void mpcac97_attach(device_t, device_t, void *); 90 91 static void mpcac97_init_psc(struct mpcac97_softc *); 92 static int mpcac97_intr(void *); 93 94 /* ac97(4) host interface. */ 95 static int mpcac97_ac97_attach(void *, struct ac97_codec_if *); 96 static int mpcac97_ac97_read(void *, uint8_t, uint16_t *); 97 static int mpcac97_ac97_write(void *, uint8_t, uint16_t); 98 static int mpcac97_ac97_reset(void *); 99 static enum ac97_host_flags mpcac97_ac97_flags(void *); 100 101 /* audio(4) hardware interface. */ 102 static int mpcac97_open(void *, int); 103 static void mpcac97_close(void *); 104 static int mpcac97_query_format(void *, audio_format_query_t *); 105 static int mpcac97_set_format(void *, int, const audio_params_t *, 106 const audio_params_t *, audio_filter_reg_t *, 107 audio_filter_reg_t *); 108 static int mpcac97_round_blocksize(void *, int, int, 109 const audio_params_t *); 110 static size_t mpcac97_round_buffersize(void *, int, size_t); 111 static void *mpcac97_allocm(void *, int, size_t); 112 static void mpcac97_freem(void *, void *, size_t); 113 static int mpcac97_get_props(void *); 114 static int mpcac97_trigger_output(void *, void *, void *, int, 115 void (*)(void *), void *, const audio_params_t *); 116 static int mpcac97_halt_output(void *); 117 static int mpcac97_getdev(void *, struct audio_device *); 118 static int mpcac97_set_port(void *, mixer_ctrl_t *); 119 static int mpcac97_get_port(void *, mixer_ctrl_t *); 120 static int mpcac97_query_devinfo(void *, mixer_devinfo_t *); 121 static void mpcac97_get_locks(void *, kmutex_t **, kmutex_t **); 122 123 CFATTACH_DECL_NEW(mpcaudio, sizeof(struct mpcac97_softc), 124 mpcac97_match, mpcac97_attach, NULL, NULL); 125 126 static const struct bestcomm_bd_layout mpcac97_tx_layout = 127 BESTCOMM_LAYOUT_GEN_TX; 128 129 /* 130 * Data-routing-descriptor offsets 131 */ 132 static const uint16_t mpcac97_tx_drd[] = { 133 0x04, 0x0c, 0x10, 0x14, 0x20, 0x28, 0x30, 0x34 134 }; 135 136 static const struct audio_format mpcac97_formats[] = { 137 { 138 .mode = AUMODE_PLAY, 139 .encoding = AUDIO_ENCODING_SLINEAR_BE, 140 .validbits = 16, 141 .precision = 32, 142 .channels = 2, 143 .channel_mask = AUFMT_STEREO, 144 .frequency_type = 1, 145 .frequency = { MPCAC97_RATE }, 146 }, 147 }; 148 149 static const struct audio_hw_if mpcac97_hw_if = { 150 .open = mpcac97_open, 151 .close = mpcac97_close, 152 .query_format = mpcac97_query_format, 153 .set_format = mpcac97_set_format, 154 .round_blocksize = mpcac97_round_blocksize, 155 .round_buffersize = mpcac97_round_buffersize, 156 .allocm = mpcac97_allocm, 157 .freem = mpcac97_freem, 158 .get_props = mpcac97_get_props, 159 .trigger_output = mpcac97_trigger_output, 160 .halt_output = mpcac97_halt_output, 161 .getdev = mpcac97_getdev, 162 .set_port = mpcac97_set_port, 163 .get_port = mpcac97_get_port, 164 .query_devinfo = mpcac97_query_devinfo, 165 .get_locks = mpcac97_get_locks, 166 }; 167 168 /* Register accessors over the big-endian SoC bus_space tag. */ 169 static inline uint8_t 170 RD1(struct mpcac97_softc *sc, bus_size_t o) 171 { 172 return bus_space_read_1(sc->sc_iot, sc->sc_ioh, o); 173 } 174 static inline uint16_t 175 RD2(struct mpcac97_softc *sc, bus_size_t o) 176 { 177 return bus_space_read_2(sc->sc_iot, sc->sc_ioh, o); 178 } 179 static inline uint32_t 180 RD4(struct mpcac97_softc *sc, bus_size_t o) 181 { 182 return bus_space_read_4(sc->sc_iot, sc->sc_ioh, o); 183 } 184 static inline void 185 WR1(struct mpcac97_softc *sc, bus_size_t o, uint8_t v) 186 { 187 bus_space_write_1(sc->sc_iot, sc->sc_ioh, o, v); 188 } 189 static inline void 190 WR2(struct mpcac97_softc *sc, bus_size_t o, uint16_t v) 191 { 192 bus_space_write_2(sc->sc_iot, sc->sc_ioh, o, v); 193 } 194 static inline void 195 WR4(struct mpcac97_softc *sc, bus_size_t o, uint32_t v) 196 { 197 bus_space_write_4(sc->sc_iot, sc->sc_ioh, o, v); 198 } 199 200 static int 201 mpcac97_match(device_t parent, cfdata_t cf, void *aux) 202 { 203 struct obio_attach_args *oba = aux; 204 char compat[40]; 205 int len; 206 207 if (strcmp(oba->obio_name, "sound") == 0) 208 return 1; 209 210 len = OF_getprop(oba->obio_node, "compatible", compat, sizeof(compat)); 211 if (len > 0 && 212 (strcmp(compat, "mpc5200-psc-ac97") == 0 || 213 strcmp(compat, "mpc5200b-psc-ac97") == 0)) 214 return 1; 215 216 return 0; 217 } 218 219 static void 220 mpcac97_attach(device_t parent, device_t self, void *aux) 221 { 222 struct mpcac97_softc *sc = device_private(self); 223 struct obio_attach_args *oba = aux; 224 bus_addr_t addr; 225 bus_size_t size; 226 227 sc->sc_dev = self; 228 sc->sc_iot = oba->obio_bst; 229 sc->sc_dmat = oba->obio_dmat; 230 231 aprint_naive("\n"); 232 aprint_normal(": MPC5200 AC97 controller\n"); 233 234 if (!bestcomm_available()) { 235 aprint_error_dev(self, "BestComm SDMA not available\n"); 236 return; 237 } 238 239 /* 240 * XXX: we should not depend on the firmware here? 241 */ 242 addr = oba->obio_addr != 0 ? oba->obio_addr : 243 (MPC5200_MBAR_DEFAULT + MPC5200_REG_PSC2); 244 size = oba->obio_size != 0 ? oba->obio_size : MPC5200_PSC_SIZE; 245 sc->sc_pa = addr; 246 if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh) != 0) { 247 aprint_error_dev(self, "can't map registers\n"); 248 return; 249 } 250 251 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 252 /* 253 * XXX: The hardware interrupt lock is at IPL_NET, not usual IPL_AUDIO! 254 * The completion interrupt is a leaf on the shared BestComm SDMA cascade 255 * (along with FEC), and every leaf on that cascade MUST run at the 256 * cascade's own IPL!!! Otherwise, enjoy hard lockups. 257 */ 258 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_NET); 259 260 /* Put PSC2 into normal AC97 mode and enable the transceiver. */ 261 mpcac97_init_psc(sc); 262 263 /* 264 * Attach the codec-independent AC97 layer. 265 */ 266 sc->sc_host_if.arg = sc; 267 sc->sc_host_if.attach = mpcac97_ac97_attach; 268 sc->sc_host_if.read = mpcac97_ac97_read; 269 sc->sc_host_if.write = mpcac97_ac97_write; 270 sc->sc_host_if.reset = mpcac97_ac97_reset; 271 sc->sc_host_if.flags = mpcac97_ac97_flags; 272 aprint_debug_dev(self, "calling ac97_attach\n"); 273 if (ac97_attach(&sc->sc_host_if, self, &sc->sc_lock) != 0) { 274 aprint_error_dev(self, "no AC97 codec found\n"); 275 goto fail; 276 } 277 aprint_debug_dev(self, "ac97_attach returned ok\n"); 278 279 /* 280 * The codec's SPDIF control is lock-gated 281 */ 282 mutex_enter(&sc->sc_lock); 283 sc->sc_codec->vtbl->unlock(sc->sc_codec); 284 mutex_exit(&sc->sc_lock); 285 aprint_debug_dev(self, "spdif unlocked\n"); 286 287 /* 288 * Route the BestComm transmit-task completion event to our block 289 * handler. 290 */ 291 sc->sc_txih = intr_establish(bestcomm_task_irq(MPCAC97_TX_TASK), 292 IST_LEVEL, IPL_NET, mpcac97_intr, sc); 293 if (sc->sc_txih == NULL) { 294 aprint_error_dev(self, "can't establish SDMA interrupt\n"); 295 goto fail; 296 } 297 aprint_debug_dev(self, "SDMA intr established\n"); 298 299 sc->sc_audiodev = audio_attach_mi(&mpcac97_hw_if, sc, self); 300 aprint_debug_dev(self, "audio_attach_mi done\n"); 301 return; 302 303 fail: 304 if (sc->sc_txih != NULL) 305 intr_disestablish(sc->sc_txih); 306 mutex_destroy(&sc->sc_lock); 307 mutex_destroy(&sc->sc_intr_lock); 308 bus_space_unmap(sc->sc_iot, sc->sc_ioh, size); 309 } 310 311 /* 312 * Configure PSC2 for "normal" AC97 mode. 313 */ 314 static void 315 mpcac97_init_psc(struct mpcac97_softc *sc) 316 { 317 318 WR1(sc, PSC_CR, CMD_RESET_RX); 319 WR1(sc, PSC_CR, CMD_RESET_TX); 320 WR1(sc, PSC_CR, CMD_RESET_ERR); 321 WR1(sc, PSC_CR, CMD_RESET_MR); 322 323 WR4(sc, PSC_SICR, SICR_NORMAL_AC97); 324 WR4(sc, PSC_AC97SLOTS, AC97SLOTS_TX_STEREO); 325 326 WR2(sc, PSC_TFALARM, MPCAC97_TFALARM); 327 WR1(sc, PSC_TFCNTL, MPCAC97_TFGRAN); 328 329 WR2(sc, PSC_IMR, 0); /* no PSC interrupts; BestComm drives playback */ 330 } 331 332 /* 333 * BestComm transmit-task completion handler. 334 */ 335 static int 336 mpcac97_intr(void *arg) 337 { 338 struct mpcac97_softc *sc = arg; 339 int handled = 0; 340 341 mutex_enter(&sc->sc_intr_lock); 342 if (!sc->sc_txon) { 343 mutex_exit(&sc->sc_intr_lock); 344 return 0; 345 } 346 347 while ((bestcomm_bd_status(&sc->sc_txring, sc->sc_curblk) & 348 BESTCOMM_BD_READY) == 0) { 349 u_int blk = sc->sc_curblk; 350 351 bestcomm_bd_post(&sc->sc_txring, blk, 352 sc->sc_blkbase + blk * sc->sc_blksize, sc->sc_blksize, 0); 353 sc->sc_curblk = (blk + 1) % sc->sc_nblk; 354 if (sc->sc_pintr != NULL) 355 (*sc->sc_pintr)(sc->sc_pintrarg); 356 handled = 1; 357 } 358 359 /* Restart the task if it ran the ring dry between completions. */ 360 if (handled) 361 bestcomm_task_start(MPCAC97_TX_TASK); 362 363 mutex_exit(&sc->sc_intr_lock); 364 return handled; 365 } 366 367 /* 368 * ac97(4) host interface. 369 */ 370 static int 371 mpcac97_ac97_attach(void *arg, struct ac97_codec_if *codec) 372 { 373 struct mpcac97_softc *sc = arg; 374 375 sc->sc_codec = codec; 376 return 0; 377 } 378 379 static int 380 mpcac97_ac97_read(void *arg, uint8_t reg, uint16_t *valp) 381 { 382 struct mpcac97_softc *sc = arg; 383 int i; 384 385 /* Drop any stale response, then issue the read command. */ 386 (void)RD4(sc, PSC_AC97DATA); 387 WR4(sc, PSC_AC97CMD, AC97CMD_READ | AC97CMD_INDEX(reg)); 388 389 for (i = 0; i < AC97_CMD_TIMEOUT; i++) { 390 if (RD2(sc, PSC_SR) & AC97_SR_DATA_VALID) { 391 *valp = AC97DATA_VALUE(RD4(sc, PSC_AC97DATA)); 392 return 0; 393 } 394 DELAY(10); 395 } 396 397 *valp = 0xffff; 398 return ETIMEDOUT; 399 } 400 401 static int 402 mpcac97_ac97_write(void *arg, uint8_t reg, uint16_t val) 403 { 404 struct mpcac97_softc *sc = arg; 405 int i; 406 407 WR4(sc, PSC_AC97CMD, AC97CMD_WRITE(reg, val)); 408 409 /* CMD_SEND is set by the write and cleared once the frame is sent. */ 410 for (i = 0; i < AC97_CMD_TIMEOUT; i++) { 411 if ((RD2(sc, PSC_SR) & AC97_SR_CMD_SEND) == 0) 412 return 0; 413 DELAY(10); 414 } 415 416 return ETIMEDOUT; 417 } 418 419 static int 420 mpcac97_ac97_reset(void *arg) 421 { 422 struct mpcac97_softc *sc = arg; 423 uint16_t val = 0xffff; 424 int i, rderr = ETIMEDOUT; 425 426 /* 427 * Cold-reset the external codec by pulsing RES low then high 428 */ 429 WR1(sc, PSC_CR, CMD_TX_DISABLE | CMD_RX_DISABLE); 430 WR1(sc, PSC_OP1, AC97_OP_RES); /* RES -> low */ 431 DELAY(1000); 432 WR1(sc, PSC_OP0, AC97_OP_RES); /* RES -> high */ 433 DELAY(1000); 434 WR1(sc, PSC_CR, CMD_TX_ENABLE | CMD_RX_ENABLE); 435 436 /* Wait for the codec's analog/digital subsections to power up. */ 437 for (i = 0; i < AC97_READY_TIMEOUT; i++) { 438 rderr = mpcac97_ac97_read(sc, AC97_REG_POWERDOWN, &val); 439 if (rderr == 0 && 440 (val & AC97_POWER_READY) == AC97_POWER_READY) { 441 aprint_debug_dev(sc->sc_dev, 442 "codec ready after ~%dms (powerdown=0x%04x)\n", 443 i, val); 444 return 0; 445 } 446 DELAY(1000); 447 } 448 449 /* 450 * Rare, not-reliably-reproducible cold-boot race: the STAC9766 is 451 * occasionally not ready within AC97_READY_TIMEOUT. Try to hunt this 452 * down. 453 */ 454 aprint_error_dev(sc->sc_dev, 455 "codec not ready after reset: last read %s, powerdown=0x%04x, " 456 "sr=0x%04x\n", 457 rderr ? "TIMED OUT (AC-link silent)" : "ok-but-not-ready", 458 val, RD2(sc, PSC_SR)); 459 return 0; /* best effort: let ac97_attach probe the codec ID */ 460 } 461 462 static enum ac97_host_flags 463 mpcac97_ac97_flags(void *arg) 464 { 465 466 return 0; 467 } 468 469 /* 470 * audio(4) hardware interface. 471 */ 472 static int 473 mpcac97_open(void *v, int flags) 474 { 475 struct mpcac97_softc *sc = v; 476 477 /* 478 * Lock the codec's SPDIF control for the duration the device is open 479 */ 480 sc->sc_codec->vtbl->lock(sc->sc_codec); 481 return 0; 482 } 483 484 static void 485 mpcac97_close(void *v) 486 { 487 struct mpcac97_softc *sc = v; 488 489 sc->sc_codec->vtbl->unlock(sc->sc_codec); 490 } 491 492 static int 493 mpcac97_query_format(void *v, audio_format_query_t *afp) 494 { 495 496 return audio_query_format(mpcac97_formats, 497 __arraycount(mpcac97_formats), afp); 498 } 499 500 static int 501 mpcac97_set_format(void *v, int setmode, 502 const audio_params_t *play, const audio_params_t *rec, 503 audio_filter_reg_t *pfil, audio_filter_reg_t *rfil) 504 { 505 506 /* 507 * Only the single advertised hardware format is offered 508 */ 509 return 0; 510 } 511 512 static int 513 mpcac97_round_blocksize(void *v, int bs, int mode, const audio_params_t *p) 514 { 515 516 /* Keep a block a whole number of 8-byte stereo DMA frames. */ 517 bs &= ~(MPCAC97_FRAME_SIZE - 1); 518 if (bs < MPCAC97_FRAME_SIZE) 519 bs = MPCAC97_FRAME_SIZE; 520 return bs; 521 } 522 523 static size_t 524 mpcac97_round_buffersize(void *v, int mode, size_t size) 525 { 526 527 /* 528 * The audio layer sizes the hardware buffer as a whole number of 529 * blocks; keep it intact. 530 */ 531 return size; 532 } 533 534 static void * 535 mpcac97_allocm(void *v, int direction, size_t size) 536 { 537 struct mpcac97_softc *sc = v; 538 int rseg; 539 540 if (direction != AUMODE_PLAY) /* playback only */ 541 return NULL; 542 if (sc->sc_dmakva != NULL) /* one play buffer */ 543 return NULL; 544 545 if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &sc->sc_dmaseg, 546 1, &rseg, BUS_DMA_WAITOK) != 0) 547 return NULL; 548 sc->sc_dmanseg = rseg; 549 if (bus_dmamem_map(sc->sc_dmat, &sc->sc_dmaseg, rseg, size, 550 &sc->sc_dmakva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0) 551 goto free; 552 if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, BUS_DMA_WAITOK, 553 &sc->sc_dmamap) != 0) 554 goto unmap; 555 if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_dmakva, size, 556 NULL, BUS_DMA_WAITOK) != 0) 557 goto destroy; 558 559 sc->sc_dmaphys = sc->sc_dmamap->dm_segs[0].ds_addr; 560 sc->sc_dmasize = size; 561 return sc->sc_dmakva; 562 563 destroy: 564 bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap); 565 sc->sc_dmamap = NULL; 566 unmap: 567 bus_dmamem_unmap(sc->sc_dmat, sc->sc_dmakva, size); 568 sc->sc_dmakva = NULL; 569 free: 570 bus_dmamem_free(sc->sc_dmat, &sc->sc_dmaseg, rseg); 571 return NULL; 572 } 573 574 static void 575 mpcac97_freem(void *v, void *ptr, size_t size) 576 { 577 struct mpcac97_softc *sc = v; 578 579 if (ptr != sc->sc_dmakva) 580 return; 581 582 bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamap); 583 bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap); 584 bus_dmamem_unmap(sc->sc_dmat, sc->sc_dmakva, size); 585 bus_dmamem_free(sc->sc_dmat, &sc->sc_dmaseg, sc->sc_dmanseg); 586 sc->sc_dmamap = NULL; 587 sc->sc_dmakva = NULL; 588 sc->sc_dmasize = 0; 589 } 590 591 static int 592 mpcac97_get_props(void *v) 593 { 594 595 return AUDIO_PROP_PLAYBACK; 596 } 597 598 static int 599 mpcac97_trigger_output(void *v, void *start, void *end, int blksize, 600 void (*intr)(void *), void *arg, const audio_params_t *param) 601 { 602 struct mpcac97_softc *sc = v; 603 bus_addr_t base; 604 u_int i, nblk; 605 606 nblk = ((char *)end - (char *)start) / blksize; 607 if (nblk == 0 || nblk > MPCAC97_MAX_NBLK) 608 return EINVAL; 609 if ((char *)start < (char *)sc->sc_dmakva || 610 (char *)start + nblk * blksize > 611 (char *)sc->sc_dmakva + sc->sc_dmasize) 612 return EINVAL; 613 614 base = sc->sc_dmaphys + ((char *)start - (char *)sc->sc_dmakva); 615 616 /* (Re)build the BD ring: one descriptor per audio block. */ 617 bestcomm_bd_teardown(&sc->sc_txring); 618 if (bestcomm_bd_setup(&sc->sc_txring, MPCAC97_TX_TASK, 619 &mpcac97_tx_layout, sc->sc_pa + AC97_FIFO_TX, nblk, blksize, 620 sizeof(uint32_t), MPCAC97_TX_INITIATOR, MPCAC97_TX_PRIO) != 0) 621 return ENOMEM; 622 623 /* 624 * GEN_TX_BD is a runtime-configurable task 625 */ 626 bestcomm_task_set_initiator(MPCAC97_TX_TASK, MPCAC97_TX_INITIATOR, 627 mpcac97_tx_drd, __arraycount(mpcac97_tx_drd)); 628 629 sc->sc_blkbase = base; 630 sc->sc_blksize = blksize; 631 sc->sc_nblk = nblk; 632 sc->sc_curblk = 0; 633 sc->sc_pintr = intr; 634 sc->sc_pintrarg = arg; 635 sc->sc_txon = true; 636 637 for (i = 0; i < nblk; i++) 638 bestcomm_bd_post(&sc->sc_txring, i, base + i * blksize, 639 blksize, 0); 640 641 bestcomm_task_start(MPCAC97_TX_TASK); 642 return 0; 643 } 644 645 static int 646 mpcac97_halt_output(void *v) 647 { 648 struct mpcac97_softc *sc = v; 649 650 sc->sc_txon = false; 651 sc->sc_pintr = NULL; 652 sc->sc_pintrarg = NULL; 653 bestcomm_bd_teardown(&sc->sc_txring); 654 return 0; 655 } 656 657 static int 658 mpcac97_getdev(void *v, struct audio_device *adp) 659 { 660 661 strlcpy(adp->name, "MPC5200 AC97", sizeof(adp->name)); 662 strlcpy(adp->version, "", sizeof(adp->version)); 663 strlcpy(adp->config, "mpcac97", sizeof(adp->config)); 664 return 0; 665 } 666 667 static int 668 mpcac97_set_port(void *v, mixer_ctrl_t *mc) 669 { 670 struct mpcac97_softc *sc = v; 671 672 return sc->sc_codec->vtbl->mixer_set_port(sc->sc_codec, mc); 673 } 674 675 static int 676 mpcac97_get_port(void *v, mixer_ctrl_t *mc) 677 { 678 struct mpcac97_softc *sc = v; 679 680 return sc->sc_codec->vtbl->mixer_get_port(sc->sc_codec, mc); 681 } 682 683 static int 684 mpcac97_query_devinfo(void *v, mixer_devinfo_t *di) 685 { 686 struct mpcac97_softc *sc = v; 687 688 return sc->sc_codec->vtbl->query_devinfo(sc->sc_codec, di); 689 } 690 691 static void 692 mpcac97_get_locks(void *v, kmutex_t **intr, kmutex_t **thread) 693 { 694 struct mpcac97_softc *sc = v; 695 696 *intr = &sc->sc_intr_lock; 697 *thread = &sc->sc_lock; 698 } 699