1/* $NetBSD: auacer.c,v 1.39 2020/02/29 06:34:30 isaki Exp $ */ 2 3/*- 4 * Copyright (c) 2004, 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Lennart Augustsson. 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 * Acer Labs M5455 audio driver 34 * 35 * Acer provides data sheets after signing an NDA, so this is guess work. 36 * The chip behaves somewhat like the Intel i8x0, so this driver 37 * is loosely based on the auich driver. Additional information taken from 38 * the ALSA intel8x0.c driver (which handles M5455 as well). 39 * 40 * As an historical note one can observe that the auich driver borrows 41 * lot from the first NetBSD PCI audio driver, the eap driver. But this 42 * is not attributed anywhere. 43 */ 44 45 46#include <sys/cdefs.h> 47__KERNEL_RCSID(0, "$NetBSD: auacer.c,v 1.39 2020/02/29 06:34:30 isaki Exp $"); 48 49#include <sys/param.h> 50#include <sys/systm.h> 51#include <sys/kernel.h> 52#include <sys/kmem.h> 53#include <sys/device.h> 54#include <sys/fcntl.h> 55#include <sys/proc.h> 56 57#include <dev/pci/pcidevs.h> 58#include <dev/pci/pcivar.h> 59#include <dev/pci/auacerreg.h> 60 61#include <sys/audioio.h> 62#include <dev/audio/audio_if.h> 63 64#include <sys/bus.h> 65 66#include <dev/ic/ac97reg.h> 67#include <dev/ic/ac97var.h> 68 69struct auacer_dma { 70 bus_dmamap_t map; 71 void *addr; 72 bus_dma_segment_t segs[1]; 73 int nsegs; 74 size_t size; 75 struct auacer_dma *next; 76}; 77 78#define DMAADDR(p) ((p)->map->dm_segs[0].ds_addr) 79#define KERNADDR(p) ((void *)((p)->addr)) 80 81struct auacer_cdata { 82 struct auacer_dmalist ic_dmalist_pcmo[ALI_DMALIST_MAX]; 83}; 84 85struct auacer_chan { 86 uint32_t ptr; 87 uint32_t start, p, end; 88 uint32_t blksize, fifoe; 89 uint32_t ack; 90 uint32_t port; 91 struct auacer_dmalist *dmalist; 92 void (*intr)(void *); 93 void *arg; 94}; 95 96struct auacer_softc { 97 device_t sc_dev; 98 void *sc_ih; 99 kmutex_t sc_lock; 100 kmutex_t sc_intr_lock; 101 102 audio_device_t sc_audev; 103 104 bus_space_tag_t iot; 105 bus_space_handle_t mix_ioh; 106 bus_space_handle_t aud_ioh; 107 bus_dma_tag_t dmat; 108 109 struct ac97_codec_if *codec_if; 110 struct ac97_host_if host_if; 111 112 /* DMA scatter-gather lists. */ 113 bus_dmamap_t sc_cddmamap; 114#define sc_cddma sc_cddmamap->dm_segs[0].ds_addr 115 116 struct auacer_cdata *sc_cdata; 117 118 struct auacer_chan sc_pcmo; 119 120 struct auacer_dma *sc_dmas; 121 122 pci_chipset_tag_t sc_pc; 123 pcitag_t sc_pt; 124 125 int sc_dmamap_flags; 126 127#define AUACER_NFORMATS 3 128 struct audio_format sc_formats[AUACER_NFORMATS]; 129}; 130 131#define READ1(sc, a) bus_space_read_1(sc->iot, sc->aud_ioh, a) 132#define READ2(sc, a) bus_space_read_2(sc->iot, sc->aud_ioh, a) 133#define READ4(sc, a) bus_space_read_4(sc->iot, sc->aud_ioh, a) 134#define WRITE1(sc, a, v) bus_space_write_1(sc->iot, sc->aud_ioh, a, v) 135#define WRITE2(sc, a, v) bus_space_write_2(sc->iot, sc->aud_ioh, a, v) 136#define WRITE4(sc, a, v) bus_space_write_4(sc->iot, sc->aud_ioh, a, v) 137 138/* Debug */ 139#ifdef AUACER_DEBUG 140#define DPRINTF(l,x) do { if (auacer_debug & (l)) printf x; } while(0) 141int auacer_debug = 0; 142#define ALI_DEBUG_CODECIO 0x0001 143#define ALI_DEBUG_DMA 0x0002 144#define ALI_DEBUG_INTR 0x0004 145#define ALI_DEBUG_API 0x0008 146#define ALI_DEBUG_MIXERAPI 0x0010 147#else 148#define DPRINTF(x,y) /* nothing */ 149#endif 150 151static int auacer_intr(void *); 152 153static int auacer_query_format(void *, audio_format_query_t *); 154static int auacer_set_format(void *, int, 155 const audio_params_t *, const audio_params_t *, 156 audio_filter_reg_t *, audio_filter_reg_t *); 157static int auacer_halt_output(void *); 158static int auacer_halt_input(void *); 159static int auacer_getdev(void *, struct audio_device *); 160static int auacer_set_port(void *, mixer_ctrl_t *); 161static int auacer_get_port(void *, mixer_ctrl_t *); 162static int auacer_query_devinfo(void *, mixer_devinfo_t *); 163static void *auacer_allocm(void *, int, size_t); 164static void auacer_freem(void *, void *, size_t); 165static size_t auacer_round_buffersize(void *, int, size_t); 166static int auacer_get_props(void *); 167static int auacer_trigger_output(void *, void *, void *, int, 168 void (*)(void *), void *, 169 const audio_params_t *); 170static int auacer_trigger_input(void *, void *, void *, int, 171 void (*)(void *), void *, 172 const audio_params_t *); 173 174static int auacer_alloc_cdata(struct auacer_softc *); 175 176static int auacer_allocmem(struct auacer_softc *, size_t, size_t, 177 struct auacer_dma *); 178static int auacer_freemem(struct auacer_softc *, struct auacer_dma *); 179static void auacer_get_locks(void *, kmutex_t **, kmutex_t **); 180 181static bool auacer_resume(device_t, const pmf_qual_t *); 182static int auacer_set_rate(struct auacer_softc *, int, u_int); 183 184static void auacer_reset(struct auacer_softc *sc); 185 186static const struct audio_hw_if auacer_hw_if = { 187 .query_format = auacer_query_format, 188 .set_format = auacer_set_format, 189 .halt_output = auacer_halt_output, 190 .halt_input = auacer_halt_input, 191 .getdev = auacer_getdev, 192 .set_port = auacer_set_port, 193 .get_port = auacer_get_port, 194 .query_devinfo = auacer_query_devinfo, 195 .allocm = auacer_allocm, 196 .freem = auacer_freem, 197 .round_buffersize = auacer_round_buffersize, 198 .get_props = auacer_get_props, 199 .trigger_output = auacer_trigger_output, 200 .trigger_input = auacer_trigger_input, 201 .get_locks = auacer_get_locks, 202}; 203 204#define AUACER_FORMATS_4CH 1 205#define AUACER_FORMATS_6CH 2 206#define AUACER_FORMAT(aumode, ch, chmask) \ 207 { \ 208 .mode = (aumode), \ 209 .encoding = AUDIO_ENCODING_SLINEAR_LE, \ 210 .validbits = 16, \ 211 .precision = 16, \ 212 .channels = (ch), \ 213 .channel_mask = (chmask), \ 214 .frequency_type = 9, \ 215 .frequency = { 8000, 11025, 12000, 16000, 22050, \ 216 24000, 32000, 44100, 48000, }, \ 217 } 218static const struct audio_format auacer_formats[AUACER_NFORMATS] = { 219 AUACER_FORMAT(AUMODE_PLAY | AUMODE_RECORD, 2, AUFMT_STEREO), 220 AUACER_FORMAT(AUMODE_PLAY , 4, AUFMT_SURROUND4), 221 AUACER_FORMAT(AUMODE_PLAY , 6, AUFMT_DOLBY_5_1), 222}; 223 224static int auacer_attach_codec(void *, struct ac97_codec_if *); 225static int auacer_read_codec(void *, uint8_t, uint16_t *); 226static int auacer_write_codec(void *, uint8_t, uint16_t); 227static int auacer_reset_codec(void *); 228 229static int 230auacer_match(device_t parent, cfdata_t match, void *aux) 231{ 232 struct pci_attach_args *pa; 233 234 pa = (struct pci_attach_args *)aux; 235 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ALI && 236 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ALI_M5455) 237 return 1; 238 return 0; 239} 240 241static void 242auacer_attach(device_t parent, device_t self, void *aux) 243{ 244 struct auacer_softc *sc; 245 struct pci_attach_args *pa; 246 pci_intr_handle_t ih; 247 bus_size_t aud_size; 248 pcireg_t v; 249 const char *intrstr; 250 int i; 251 char intrbuf[PCI_INTRSTR_LEN]; 252 253 sc = device_private(self); 254 sc->sc_dev = self; 255 pa = aux; 256 aprint_normal(": Acer Labs M5455 Audio controller\n"); 257 258 if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_IO, 0, &sc->iot, 259 &sc->aud_ioh, NULL, &aud_size)) { 260 aprint_error(": can't map i/o space\n"); 261 return; 262 } 263 264 sc->sc_pc = pa->pa_pc; 265 sc->sc_pt = pa->pa_tag; 266 sc->dmat = pa->pa_dmat; 267 268 sc->sc_dmamap_flags = BUS_DMA_COHERENT; /* XXX remove */ 269 270 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 271 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO); 272 273 /* enable bus mastering */ 274 v = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); 275 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, 276 v | PCI_COMMAND_MASTER_ENABLE); 277 278 /* Map and establish the interrupt. */ 279 if (pci_intr_map(pa, &ih)) { 280 aprint_error_dev(sc->sc_dev, "can't map interrupt\n"); 281 mutex_destroy(&sc->sc_lock); 282 mutex_destroy(&sc->sc_intr_lock); 283 return; 284 } 285 intrstr = pci_intr_string(pa->pa_pc, ih, intrbuf, sizeof(intrbuf)); 286 sc->sc_ih = pci_intr_establish_xname(pa->pa_pc, ih, IPL_AUDIO, 287 auacer_intr, sc, device_xname(self)); 288 if (sc->sc_ih == NULL) { 289 aprint_error_dev(sc->sc_dev, "can't establish interrupt"); 290 if (intrstr != NULL) 291 aprint_error(" at %s", intrstr); 292 aprint_error("\n"); 293 mutex_destroy(&sc->sc_lock); 294 mutex_destroy(&sc->sc_intr_lock); 295 return; 296 } 297 aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr); 298 299 strlcpy(sc->sc_audev.name, "M5455 AC97", MAX_AUDIO_DEV_LEN); 300 snprintf(sc->sc_audev.version, MAX_AUDIO_DEV_LEN, 301 "0x%02x", PCI_REVISION(pa->pa_class)); 302 strlcpy(sc->sc_audev.config, device_xname(sc->sc_dev), MAX_AUDIO_DEV_LEN); 303 304 /* Set up DMA lists. */ 305 auacer_alloc_cdata(sc); 306 sc->sc_pcmo.dmalist = sc->sc_cdata->ic_dmalist_pcmo; 307 sc->sc_pcmo.ptr = 0; 308 sc->sc_pcmo.port = ALI_BASE_PO; 309 310 DPRINTF(ALI_DEBUG_DMA, ("auacer_attach: lists %p\n", 311 sc->sc_pcmo.dmalist)); 312 313 sc->host_if.arg = sc; 314 sc->host_if.attach = auacer_attach_codec; 315 sc->host_if.read = auacer_read_codec; 316 sc->host_if.write = auacer_write_codec; 317 sc->host_if.reset = auacer_reset_codec; 318 319 if (ac97_attach(&sc->host_if, self, &sc->sc_lock) != 0) { 320 mutex_destroy(&sc->sc_lock); 321 mutex_destroy(&sc->sc_intr_lock); 322 return; 323 } 324 325 /* setup audio_format */ 326 memcpy(sc->sc_formats, auacer_formats, sizeof(auacer_formats)); 327 mutex_enter(&sc->sc_lock); 328 if (!AC97_IS_4CH(sc->codec_if)) 329 AUFMT_INVALIDATE(&sc->sc_formats[AUACER_FORMATS_4CH]); 330 if (!AC97_IS_6CH(sc->codec_if)) 331 AUFMT_INVALIDATE(&sc->sc_formats[AUACER_FORMATS_6CH]); 332 if (AC97_IS_FIXED_RATE(sc->codec_if)) { 333 for (i = 0; i < AUACER_NFORMATS; i++) { 334 sc->sc_formats[i].frequency_type = 1; 335 sc->sc_formats[i].frequency[0] = 48000; 336 } 337 } 338 339 mutex_spin_enter(&sc->sc_intr_lock); 340 auacer_reset(sc); 341 mutex_spin_exit(&sc->sc_intr_lock); 342 mutex_exit(&sc->sc_lock); 343 344 audio_attach_mi(&auacer_hw_if, sc, sc->sc_dev); 345 346 if (!pmf_device_register(self, NULL, auacer_resume)) 347 aprint_error_dev(self, "couldn't establish power handler\n"); 348} 349 350CFATTACH_DECL_NEW(auacer, sizeof(struct auacer_softc), 351 auacer_match, auacer_attach, NULL, NULL); 352 353static int 354auacer_ready_codec(struct auacer_softc *sc, int mask) 355{ 356 int count; 357 358 for (count = 0; count < 0x7f; count++) { 359 int val = READ1(sc, ALI_CSPSR); 360 if (val & mask) 361 return 0; 362 } 363 364 aprint_normal("auacer_ready_codec: AC97 codec ready timeout.\n"); 365 return EBUSY; 366} 367 368static int 369auacer_sema_codec(struct auacer_softc *sc) 370{ 371 int ttime; 372 373 ttime = 100; 374 while (ttime-- && (READ4(sc, ALI_CAS) & ALI_CAS_SEM_BUSY)) 375 delay(1); 376 if (!ttime) 377 aprint_normal("auacer_sema_codec: timeout\n"); 378 return auacer_ready_codec(sc, ALI_CSPSR_CODEC_READY); 379} 380 381static int 382auacer_read_codec(void *v, uint8_t reg, uint16_t *val) 383{ 384 struct auacer_softc *sc; 385 386 sc = v; 387 if (auacer_sema_codec(sc)) 388 return EIO; 389 390 reg |= ALI_CPR_ADDR_READ; 391#if 0 392 if (ac97->num) 393 reg |= ALI_CPR_ADDR_SECONDARY; 394#endif 395 WRITE2(sc, ALI_CPR_ADDR, reg); 396 if (auacer_ready_codec(sc, ALI_CSPSR_READ_OK)) 397 return EIO; 398 *val = READ2(sc, ALI_SPR); 399 400 DPRINTF(ALI_DEBUG_CODECIO, ("auacer_read_codec: reg=0x%x val=0x%x\n", 401 reg, *val)); 402 403 return 0; 404} 405 406int 407auacer_write_codec(void *v, uint8_t reg, uint16_t val) 408{ 409 struct auacer_softc *sc; 410 411 DPRINTF(ALI_DEBUG_CODECIO, ("auacer_write_codec: reg=0x%x val=0x%x\n", 412 reg, val)); 413 sc = v; 414 if (auacer_sema_codec(sc)) 415 return EIO; 416 WRITE2(sc, ALI_CPR, val); 417#if 0 418 if (ac97->num) 419 reg |= ALI_CPR_ADDR_SECONDARY; 420#endif 421 WRITE2(sc, ALI_CPR_ADDR, reg); 422 auacer_ready_codec(sc, ALI_CSPSR_WRITE_OK); 423 return 0; 424} 425 426static int 427auacer_attach_codec(void *v, struct ac97_codec_if *cif) 428{ 429 struct auacer_softc *sc; 430 431 sc = v; 432 sc->codec_if = cif; 433 return 0; 434} 435 436static int 437auacer_reset_codec(void *v) 438{ 439 struct auacer_softc *sc; 440 uint32_t reg; 441 int i; 442 443 sc = v; 444 i = 0; 445 reg = READ4(sc, ALI_SCR); 446 if ((reg & 2) == 0) /* Cold required */ 447 reg |= 2; 448 else 449 reg |= 1; /* Warm */ 450 reg &= ~0x80000000; /* ACLink on */ 451 WRITE4(sc, ALI_SCR, reg); 452 453 while (i < 10) { 454 if ((READ4(sc, ALI_INTERRUPTSR) & ALI_INT_GPIO) == 0) 455 break; 456 delay(50000); /* XXX */ 457 i++; 458 } 459 if (i == 10) { 460 return EIO; 461 } 462 463 for (i = 0; i < 10; i++) { 464 reg = READ4(sc, ALI_RTSR); 465 if (reg & 0x80) /* primary codec */ 466 break; 467 WRITE4(sc, ALI_RTSR, reg | 0x80); 468 delay(50000); /* XXX */ 469 } 470 471 return 0; 472} 473 474static void 475auacer_reset(struct auacer_softc *sc) 476{ 477 WRITE4(sc, ALI_SCR, ALI_SCR_RESET); 478 WRITE4(sc, ALI_FIFOCR1, 0x83838383); 479 WRITE4(sc, ALI_FIFOCR2, 0x83838383); 480 WRITE4(sc, ALI_FIFOCR3, 0x83838383); 481 WRITE4(sc, ALI_INTERFACECR, ALI_IF_PO); /* XXX pcm out only */ 482 WRITE4(sc, ALI_INTERRUPTCR, 0x00000000); 483 WRITE4(sc, ALI_INTERRUPTSR, 0x00000000); 484} 485 486static int 487auacer_query_format(void *v, audio_format_query_t *afp) 488{ 489 struct auacer_softc *sc; 490 491 DPRINTF(ALI_DEBUG_API, ("%s\n", __func__)); 492 sc = v; 493 return audio_query_format(sc->sc_formats, AUACER_NFORMATS, afp); 494} 495 496static int 497auacer_set_rate(struct auacer_softc *sc, int mode, u_int srate) 498{ 499 int ret; 500 u_int ratetmp; 501 502 DPRINTF(ALI_DEBUG_API, ("auacer_set_rate: srate=%u\n", srate)); 503 504 ratetmp = srate; 505 if (mode == AUMODE_RECORD) 506 return sc->codec_if->vtbl->set_rate(sc->codec_if, 507 AC97_REG_PCM_LR_ADC_RATE, &ratetmp); 508 ret = sc->codec_if->vtbl->set_rate(sc->codec_if, 509 AC97_REG_PCM_FRONT_DAC_RATE, &ratetmp); 510 if (ret) 511 return ret; 512 ratetmp = srate; 513 ret = sc->codec_if->vtbl->set_rate(sc->codec_if, 514 AC97_REG_PCM_SURR_DAC_RATE, &ratetmp); 515 if (ret) 516 return ret; 517 ratetmp = srate; 518 ret = sc->codec_if->vtbl->set_rate(sc->codec_if, 519 AC97_REG_PCM_LFE_DAC_RATE, &ratetmp); 520 return ret; 521} 522 523static int 524auacer_set_format(void *v, int setmode, 525 const audio_params_t *play, const audio_params_t *rec, 526 audio_filter_reg_t *pfil, audio_filter_reg_t *rfil) 527{ 528 struct auacer_softc *sc; 529 const audio_params_t *p; 530 uint32_t control; 531 int mode, index; 532 533 DPRINTF(ALI_DEBUG_API, ("%s\n", __func__)); 534 sc = v; 535 for (mode = AUMODE_RECORD; mode != -1; 536 mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) { 537 if ((setmode & mode) == 0) 538 continue; 539 540 p = mode == AUMODE_PLAY ? play : rec; 541 542 index = audio_indexof_format(sc->sc_formats, AUACER_NFORMATS, 543 mode, p); 544 /* p points HW encoding */ 545 if (sc->sc_formats[index].frequency_type != 1 546 && auacer_set_rate(sc, mode, p->sample_rate)) 547 return EINVAL; 548 if (mode == AUMODE_PLAY) { 549 control = READ4(sc, ALI_SCR); 550 control &= ~ALI_SCR_PCM_246_MASK; 551 if (p->channels == 4) 552 control |= ALI_SCR_PCM_4; 553 else if (p->channels == 6) 554 control |= ALI_SCR_PCM_6; 555 WRITE4(sc, ALI_SCR, control); 556 } 557 } 558 559 return 0; 560} 561 562static void 563auacer_halt(struct auacer_softc *sc, struct auacer_chan *chan) 564{ 565 uint32_t val; 566 uint8_t port; 567 uint32_t slot; 568 569 port = chan->port; 570 DPRINTF(ALI_DEBUG_API, ("auacer_halt: port=0x%x\n", port)); 571 chan->intr = 0; 572 573 slot = ALI_PORT2SLOT(port); 574 575 val = READ4(sc, ALI_DMACR); 576 val |= 1 << (slot+16); /* pause */ 577 val &= ~(1 << slot); /* no start */ 578 WRITE4(sc, ALI_DMACR, val); 579 WRITE1(sc, port + ALI_OFF_CR, 0); 580 while (READ1(sc, port + ALI_OFF_CR)) 581 ; 582 /* reset whole DMA things */ 583 WRITE1(sc, port + ALI_OFF_CR, ALI_CR_RR); 584 /* clear interrupts */ 585 WRITE1(sc, port + ALI_OFF_SR, READ1(sc, port+ALI_OFF_SR) | ALI_SR_W1TC); 586 WRITE4(sc, ALI_INTERRUPTSR, ALI_PORT2INTR(port)); 587} 588 589static int 590auacer_halt_output(void *v) 591{ 592 struct auacer_softc *sc; 593 594 DPRINTF(ALI_DEBUG_DMA, ("auacer_halt_output\n")); 595 sc = v; 596 auacer_halt(sc, &sc->sc_pcmo); 597 598 return 0; 599} 600 601static int 602auacer_halt_input(void *v) 603{ 604 DPRINTF(ALI_DEBUG_DMA, ("auacer_halt_input\n")); 605 606 return 0; 607} 608 609static int 610auacer_getdev(void *v, struct audio_device *adp) 611{ 612 struct auacer_softc *sc; 613 614 DPRINTF(ALI_DEBUG_API, ("auacer_getdev\n")); 615 sc = v; 616 *adp = sc->sc_audev; 617 return 0; 618} 619 620static int 621auacer_set_port(void *v, mixer_ctrl_t *cp) 622{ 623 struct auacer_softc *sc; 624 625 DPRINTF(ALI_DEBUG_MIXERAPI, ("auacer_set_port\n")); 626 sc = v; 627 return sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp); 628} 629 630static int 631auacer_get_port(void *v, mixer_ctrl_t *cp) 632{ 633 struct auacer_softc *sc; 634 635 DPRINTF(ALI_DEBUG_MIXERAPI, ("auacer_get_port\n")); 636 sc = v; 637 return sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp); 638} 639 640static int 641auacer_query_devinfo(void *v, mixer_devinfo_t *dp) 642{ 643 struct auacer_softc *sc; 644 645 DPRINTF(ALI_DEBUG_MIXERAPI, ("auacer_query_devinfo\n")); 646 sc = v; 647 return sc->codec_if->vtbl->query_devinfo(sc->codec_if, dp); 648} 649 650static void * 651auacer_allocm(void *v, int direction, size_t size) 652{ 653 struct auacer_softc *sc; 654 struct auacer_dma *p; 655 int error; 656 657 if (size > (ALI_DMALIST_MAX * ALI_DMASEG_MAX)) 658 return NULL; 659 660 p = kmem_zalloc(sizeof(*p), KM_SLEEP); 661 sc = v; 662 error = auacer_allocmem(sc, size, 0, p); 663 if (error) { 664 kmem_free(p, sizeof(*p)); 665 return NULL; 666 } 667 668 p->next = sc->sc_dmas; 669 sc->sc_dmas = p; 670 671 return KERNADDR(p); 672} 673 674static void 675auacer_freem(void *v, void *ptr, size_t size) 676{ 677 struct auacer_softc *sc; 678 struct auacer_dma *p, **pp; 679 680 sc = v; 681 for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->next) { 682 if (KERNADDR(p) == ptr) { 683 auacer_freemem(sc, p); 684 *pp = p->next; 685 kmem_free(p, sizeof(*p)); 686 return; 687 } 688 } 689} 690 691static size_t 692auacer_round_buffersize(void *v, int direction, size_t size) 693{ 694 695 if (size > (ALI_DMALIST_MAX * ALI_DMASEG_MAX)) 696 size = ALI_DMALIST_MAX * ALI_DMASEG_MAX; 697 698 return size; 699} 700 701static int 702auacer_get_props(void *v) 703{ 704 705 return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE | 706 AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX; 707} 708 709static void 710auacer_get_locks(void *v, kmutex_t **intr, kmutex_t **proc) 711{ 712 struct auacer_softc *sc; 713 714 sc = v; 715 *intr = &sc->sc_intr_lock; 716 *proc = &sc->sc_lock; 717} 718 719static void 720auacer_add_entry(struct auacer_chan *chan) 721{ 722 struct auacer_dmalist *q; 723 724 q = &chan->dmalist[chan->ptr]; 725 726 DPRINTF(ALI_DEBUG_INTR, 727 ("auacer_add_entry: %p = %x @ 0x%x\n", 728 q, chan->blksize / 2, chan->p)); 729 730 q->base = htole32(chan->p); 731 q->len = htole32((chan->blksize / ALI_SAMPLE_SIZE) | ALI_DMAF_IOC); 732 chan->p += chan->blksize; 733 if (chan->p >= chan->end) 734 chan->p = chan->start; 735 736 if (++chan->ptr >= ALI_DMALIST_MAX) 737 chan->ptr = 0; 738} 739 740static void 741auacer_upd_chan(struct auacer_softc *sc, struct auacer_chan *chan) 742{ 743 uint32_t sts; 744 uint32_t civ; 745 746 sts = READ2(sc, chan->port + ALI_OFF_SR); 747 /* intr ack */ 748 WRITE2(sc, chan->port + ALI_OFF_SR, sts & ALI_SR_W1TC); 749 WRITE4(sc, ALI_INTERRUPTSR, ALI_PORT2INTR(chan->port)); 750 751 DPRINTF(ALI_DEBUG_INTR, ("auacer_upd_chan: sts=0x%x\n", sts)); 752 753 if (sts & ALI_SR_DMA_INT_FIFO) { 754 printf("%s: fifo underrun # %u\n", 755 device_xname(sc->sc_dev), ++chan->fifoe); 756 } 757 758 civ = READ1(sc, chan->port + ALI_OFF_CIV); 759 760 DPRINTF(ALI_DEBUG_INTR,("auacer_intr: civ=%u ptr=%u\n",civ,chan->ptr)); 761 762 /* XXX */ 763 while (chan->ptr != civ) { 764 auacer_add_entry(chan); 765 } 766 767 WRITE1(sc, chan->port + ALI_OFF_LVI, (chan->ptr - 1) & ALI_LVI_MASK); 768 769 while (chan->ack != civ) { 770 if (chan->intr) { 771 DPRINTF(ALI_DEBUG_INTR,("auacer_upd_chan: callback\n")); 772 chan->intr(chan->arg); 773 } 774 chan->ack++; 775 if (chan->ack >= ALI_DMALIST_MAX) 776 chan->ack = 0; 777 } 778} 779 780static int 781auacer_intr(void *v) 782{ 783 struct auacer_softc *sc; 784 int ret, intrs; 785 786 sc = v; 787 788 DPRINTF(ALI_DEBUG_INTR, ("auacer_intr: intrs=0x%x\n", 789 READ4(sc, ALI_INTERRUPTSR))); 790 791 mutex_spin_enter(&sc->sc_intr_lock); 792 intrs = READ4(sc, ALI_INTERRUPTSR); 793 ret = 0; 794 if (intrs & ALI_INT_PCMOUT) { 795 auacer_upd_chan(sc, &sc->sc_pcmo); 796 ret++; 797 } 798 mutex_spin_exit(&sc->sc_intr_lock); 799 800 return ret != 0; 801} 802 803static void 804auacer_setup_chan(struct auacer_softc *sc, struct auacer_chan *chan, 805 uint32_t start, uint32_t size, uint32_t blksize, 806 void (*intr)(void *), void *arg) 807{ 808 uint32_t port, slot; 809 uint32_t offs, val; 810 811 chan->start = start; 812 chan->ptr = 0; 813 chan->p = chan->start; 814 chan->end = chan->start + size; 815 chan->blksize = blksize; 816 chan->ack = 0; 817 chan->intr = intr; 818 chan->arg = arg; 819 820 auacer_add_entry(chan); 821 auacer_add_entry(chan); 822 823 port = chan->port; 824 slot = ALI_PORT2SLOT(port); 825 826 WRITE1(sc, port + ALI_OFF_CIV, 0); 827 WRITE1(sc, port + ALI_OFF_LVI, (chan->ptr - 1) & ALI_LVI_MASK); 828 offs = (char *)chan->dmalist - (char *)sc->sc_cdata; 829 WRITE4(sc, port + ALI_OFF_BDBAR, sc->sc_cddma + offs); 830 WRITE1(sc, port + ALI_OFF_CR, 831 ALI_CR_IOCE | ALI_CR_FEIE | ALI_CR_LVBIE | ALI_CR_RPBM); 832 val = READ4(sc, ALI_DMACR); 833 val &= ~(1 << (slot+16)); /* no pause */ 834 val |= 1 << slot; /* start */ 835 WRITE4(sc, ALI_DMACR, val); 836} 837 838static int 839auacer_trigger_output(void *v, void *start, void *end, int blksize, 840 void (*intr)(void *), void *arg, const audio_params_t *param) 841{ 842 struct auacer_softc *sc; 843 struct auacer_dma *p; 844 uint32_t size; 845 846 DPRINTF(ALI_DEBUG_DMA, 847 ("auacer_trigger_output(%p, %p, %d, %p, %p, %p)\n", 848 start, end, blksize, intr, arg, param)); 849 sc = v; 850 for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next) 851 continue; 852 if (!p) { 853 printf("auacer_trigger_output: bad addr %p\n", start); 854 return (EINVAL); 855 } 856 857 size = (char *)end - (char *)start; 858 auacer_setup_chan(sc, &sc->sc_pcmo, DMAADDR(p), size, blksize, 859 intr, arg); 860 861 return 0; 862} 863 864static int 865auacer_trigger_input(void *v, void *start, void *end, 866 int blksize, void (*intr)(void *), void *arg, 867 const audio_params_t *param) 868{ 869 return EINVAL; 870} 871 872static int 873auacer_allocmem(struct auacer_softc *sc, size_t size, size_t align, 874 struct auacer_dma *p) 875{ 876 int error; 877 878 p->size = size; 879 error = bus_dmamem_alloc(sc->dmat, p->size, align, 0, 880 p->segs, sizeof(p->segs)/sizeof(p->segs[0]), 881 &p->nsegs, BUS_DMA_WAITOK); 882 if (error) 883 return error; 884 885 error = bus_dmamem_map(sc->dmat, p->segs, p->nsegs, p->size, 886 &p->addr, BUS_DMA_WAITOK|sc->sc_dmamap_flags); 887 if (error) 888 goto free; 889 890 error = bus_dmamap_create(sc->dmat, p->size, 1, p->size, 891 0, BUS_DMA_WAITOK, &p->map); 892 if (error) 893 goto unmap; 894 895 error = bus_dmamap_load(sc->dmat, p->map, p->addr, p->size, NULL, 896 BUS_DMA_WAITOK); 897 if (error) 898 goto destroy; 899 return (0); 900 901 destroy: 902 bus_dmamap_destroy(sc->dmat, p->map); 903 unmap: 904 bus_dmamem_unmap(sc->dmat, p->addr, p->size); 905 free: 906 bus_dmamem_free(sc->dmat, p->segs, p->nsegs); 907 return error; 908} 909 910static int 911auacer_freemem(struct auacer_softc *sc, struct auacer_dma *p) 912{ 913 914 bus_dmamap_unload(sc->dmat, p->map); 915 bus_dmamap_destroy(sc->dmat, p->map); 916 bus_dmamem_unmap(sc->dmat, p->addr, p->size); 917 bus_dmamem_free(sc->dmat, p->segs, p->nsegs); 918 return 0; 919} 920 921static int 922auacer_alloc_cdata(struct auacer_softc *sc) 923{ 924 bus_dma_segment_t seg; 925 int error, rseg; 926 927 /* 928 * Allocate the control data structure, and create and load the 929 * DMA map for it. 930 */ 931 if ((error = bus_dmamem_alloc(sc->dmat, 932 sizeof(struct auacer_cdata), 933 PAGE_SIZE, 0, &seg, 1, &rseg, 0)) != 0) { 934 aprint_error_dev(sc->sc_dev, "unable to allocate control data, error = %d\n", 935 error); 936 goto fail_0; 937 } 938 939 if ((error = bus_dmamem_map(sc->dmat, &seg, rseg, 940 sizeof(struct auacer_cdata), 941 (void **) &sc->sc_cdata, 942 sc->sc_dmamap_flags)) != 0) { 943 aprint_error_dev(sc->sc_dev, "unable to map control data, error = %d\n", 944 error); 945 goto fail_1; 946 } 947 948 if ((error = bus_dmamap_create(sc->dmat, sizeof(struct auacer_cdata), 1, 949 sizeof(struct auacer_cdata), 0, 0, 950 &sc->sc_cddmamap)) != 0) { 951 aprint_error_dev(sc->sc_dev, "unable to create control data DMA map, " 952 "error = %d\n", error); 953 goto fail_2; 954 } 955 956 if ((error = bus_dmamap_load(sc->dmat, sc->sc_cddmamap, 957 sc->sc_cdata, sizeof(struct auacer_cdata), 958 NULL, 0)) != 0) { 959 aprint_error_dev(sc->sc_dev, "unable to load control data DMA map, " 960 "error = %d\n", error); 961 goto fail_3; 962 } 963 964 return 0; 965 966 fail_3: 967 bus_dmamap_destroy(sc->dmat, sc->sc_cddmamap); 968 fail_2: 969 bus_dmamem_unmap(sc->dmat, (void *) sc->sc_cdata, 970 sizeof(struct auacer_cdata)); 971 fail_1: 972 bus_dmamem_free(sc->dmat, &seg, rseg); 973 fail_0: 974 return error; 975} 976 977static bool 978auacer_resume(device_t dv, const pmf_qual_t *qual) 979{ 980 struct auacer_softc *sc = device_private(dv); 981 982 mutex_enter(&sc->sc_lock); 983 mutex_spin_enter(&sc->sc_intr_lock); 984 auacer_reset_codec(sc); 985 mutex_spin_exit(&sc->sc_intr_lock); 986 delay(1000); 987 sc->codec_if->vtbl->restore_ports(sc->codec_if); 988 mutex_exit(&sc->sc_lock); 989 990 return true; 991} 992