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