1 /* $OpenBSD: auglx.c,v 1.15 2016/09/19 06:46:44 ratchov Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Marc Balmer <mbalmer@openbsd.org> 5 * All rights reserved. 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN 16 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* 21 * AMD CS5536 series AC'97 audio driver. 22 * 23 * The following datasheets were helpful in the development of this 24 * driver: 25 * 26 * AMD Geode LX Processors Data Book 27 * http://www.amd.com/files/connectivitysolutions/geode/geode_lx/\ 28 * 33234F_LX_databook.pdf 29 * 30 * AMD Geode CS5536 Companion Device Data Book 31 * http://www.amd.com/files/connectivitysolutions/geode/geode_lx/\ 32 * 33238G_cs5536_db.pdf 33 * 34 * Realtek ALC203 Two-Channel AC'97 2.3 Audio Codec 35 * ftp://202.65.194.211/pc/audio/ALC203_DataSheet_1.6.pdf 36 * 37 * This driver is inspired by the auich(4) and auixp(4) drivers, some 38 * of the hardware-independent functionality has been derived from them 39 * (e.g. memory allocation for the upper level, parameter setting). 40 */ 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/device.h> 45 #include <sys/malloc.h> 46 #include <sys/audioio.h> 47 48 #include <machine/bus.h> 49 50 #include <dev/pci/pcireg.h> 51 #include <dev/pci/pcivar.h> 52 #include <dev/pci/pcidevs.h> 53 #include <dev/audio_if.h> 54 55 #include <dev/ic/ac97.h> 56 57 #define AUGLX_ACC_BAR 0x10 58 59 /* ACC Native Registers */ 60 #define ACC_GPIO_STATUS 0x00 61 #define ACC_GPIO_CNTL 0x04 62 #define ACC_CODEC_STATUS 0x08 63 #define ACC_CODEC_CNTL 0x0c 64 #define ACC_IRQ_STATUS 0x12 65 #define ACC_ENGINE_CNTL 0x14 66 #define ACC_BM0_CMD 0x20 /* Bus Master 0 Command */ 67 #define ACC_BM0_STATUS 0x21 /* Bus Master 0 IRQ Status */ 68 #define ACC_BM0_PRD 0x24 /* BM0 PRD Table Address */ 69 #define ACC_BM1_CMD 0x28 /* Bus Master 1 Command */ 70 #define ACC_BM1_STATUS 0x29 /* Bus Master 1 IRQ Status */ 71 #define ACC_BM1_PRD 0x2c /* BM1 PRD Table Address */ 72 #define ACC_BM2_CMD 0x30 /* Bus Master 2 Command */ 73 #define ACC_BM2_STATUS 0x31 /* Bus Master 2 IRQ Status */ 74 #define ACC_BM2_PRD 0x34 /* BM2 PRD Table Address */ 75 #define ACC_BM3_CMD 0x38 /* Bus Master 3 Command */ 76 #define ACC_BM3_STATUS 0x39 /* Bus Master 3 IRQ Status */ 77 #define ACC_BM3_PRD 0x3c /* BM3 PRD Table Address */ 78 #define ACC_BM4_CMD 0x40 /* Bus Master 4 Command */ 79 #define ACC_BM4_STATUS 0x41 /* Bus Master 4 IRQ Status */ 80 #define ACC_BM4_PRD 0x44 /* BM4 PRD Table Address */ 81 #define ACC_BM5_CMD 0x48 /* Bus Master 5 Command */ 82 #define ACC_BM5_STATUS 0x49 /* Bus Master 5 IRQ Status */ 83 #define ACC_BM5_PRD 0x4c /* BM5 PRD Table Address */ 84 #define ACC_BM6_CMD 0x50 /* Bus Master 6 Command */ 85 #define ACC_BM6_STATUS 0x51 /* Bus Master 6 IRQ Status */ 86 #define ACC_BM6_PRD 0x54 /* BM6 PRD Table Address */ 87 #define ACC_BM7_CMD 0x58 /* Bus Master 7 Command */ 88 #define ACC_BM7_STATUS 0x59 /* Bus Master 7 IRQ Status */ 89 #define ACC_BM7_PRD 0x5c /* BM7 PRD Table Address */ 90 #define ACC_BM0_PNTR 0x60 /* Bus Master 0 DMA Pointer */ 91 #define ACC_BM1_PNTR 0x64 /* Bus Master 1 DMA Pointer */ 92 #define ACC_BM2_PNTR 0x68 /* Bus Master 2 DMA Pointer */ 93 #define ACC_BM3_PNTR 0x6c /* Bus Master 3 DMA Pointer */ 94 #define ACC_BM4_PNTR 0x70 /* Bus Master 4 DMA Pointer */ 95 #define ACC_BM5_PNTR 0x74 /* Bus Master 5 DMA Pointer */ 96 #define ACC_BM6_PNTR 0x78 /* Bus Master 6 DMA Pointer */ 97 #define ACC_BM7_PNTR 0x7c /* Bus Master 7 DMA Pointer */ 98 99 /* ACC_IRQ_STATUS Bit Definitions */ 100 #define BM7_IRQ_STS 0x0200 /* Audio Bus Master 7 IRQ Status */ 101 #define BM6_IRQ_STS 0x0100 /* Audio Bus Master 6 IRQ Status */ 102 #define BM5_IRQ_STS 0x0080 /* Audio Bus Master 5 IRQ Status */ 103 #define BM4_IRQ_STS 0x0040 /* Audio Bus Master 4 IRQ Status */ 104 #define BM3_IRQ_STS 0x0020 /* Audio Bus Master 3 IRQ Status */ 105 #define BM2_IRQ_STS 0x0010 /* Audio Bus Master 2 IRQ Status */ 106 #define BM1_IRQ_STS 0x0008 /* Audio Bus Master 1 IRQ Status */ 107 #define BM0_IRQ_STS 0x0004 /* Audio Bus Master 0 IRQ Status */ 108 #define WU_IRQ_STS 0x0002 /* Codec GPIO Wakeup IRQ Status */ 109 #define IRQ_STS 0x0001 /* Codec GPIO IRQ Status */ 110 111 /* ACC_ENGINE_CNTL Bit Definitions */ 112 #define SSND_MODE 0x00000001 /* Surround Sound (5.1) Sync. Mode */ 113 114 /* ACC_BM[x]_CMD Bit Descriptions */ 115 #define BMx_CMD_RW 0x08 /* 0: Mem to codec, 1: codec to mem */ 116 #define BMx_CMD_BYTE_ORD 0x04 /* 0: Little Endian, 1: Big Endian */ 117 #define BMx_CMD_BM_CTL_DIS 0x00 /* Disable bus master */ 118 #define BMx_CMD_BM_CTL_EN 0x01 /* Enable bus master */ 119 #define BMx_CMD_BM_CTL_PAUSE 0x03 /* Pause bus master */ 120 121 /* ACC_BM[x]_STATUS Bit Definitions */ 122 #define BMx_BM_EOP_ERR 0x02 /* Bus master error */ 123 #define BMx_BM_EOP 0x01 /* End of page */ 124 125 /* ACC_CODEC_CNTL Bit Definitions */ 126 #define RW_CMD 0x80000000 127 #define PD_PRIM 0x00200000 128 #define PD_SEC 0x00100000 129 #define LNK_SHTDOWN 0x00040000 130 #define LNK_WRM_RST 0x00020000 131 #define CMD_NEW 0x00010000 132 133 /* ACC_CODEC_STATUS Bit Definitions */ 134 #define PRM_RDY_STS 0x00800000 135 #define SEC_RDY_STS 0x00400000 136 #define SDATAIN2_EN 0x00200000 137 #define BM5_SEL 0x00100000 138 #define BM4_SEL 0x00080000 139 #define STS_NEW 0x00020000 140 141 #define AUGLX_TOUT 1000 /* uSec */ 142 143 #define AUGLX_DMALIST_MAX 1 144 #define AUGLX_DMASEG_MAX 65536 145 146 struct auglx_prd { 147 u_int32_t base; 148 u_int32_t size; 149 #define AUGLX_PRD_EOT 0x80000000 150 #define AUGLX_PRD_EOP 0x40000000 151 #define AUGLX_PRD_JMP 0x20000000 152 }; 153 154 #define AUGLX_FIXED_RATE 48000 155 156 struct auglx_dma { 157 bus_dmamap_t map; 158 caddr_t addr; 159 bus_dma_segment_t segs[AUGLX_DMALIST_MAX]; 160 int nsegs; 161 size_t size; 162 struct auglx_dma *next; 163 }; 164 165 struct auglx_softc { 166 struct device sc_dev; 167 void *sc_ih; 168 169 bus_space_tag_t sc_iot; 170 bus_space_handle_t sc_ioh; 171 bus_dma_tag_t sc_dmat; 172 173 /* 174 * The CS5536 ACC has eight bus masters to support 5.1 audio. 175 * This driver, however, only supports main playback and recording 176 * since I only have a Realtek ALC203 codec available for testing. 177 */ 178 struct auglx_ring { 179 bus_dmamap_t sc_prd; 180 struct auglx_prd *sc_vprd; 181 int sc_nprd; 182 183 size_t sc_size; 184 int nsegs; 185 bus_dma_segment_t seg; 186 187 void (*intr)(void *); 188 void *arg; 189 } bm0, bm1; /* bm0: output, bm1: input */ 190 191 struct auglx_dma *sc_dmas; 192 193 struct ac97_codec_if *codec_if; 194 struct ac97_host_if host_if; 195 196 int sc_dmamap_flags; 197 }; 198 199 #ifdef AUGLX_DEBUG 200 #define DPRINTF(l,x) do { if (auglx_debug & (l)) printf x; } while(0) 201 int auglx_debug = 0; 202 #define AUGLX_DBG_ACC 0x0001 203 #define AUGLX_DBG_DMA 0x0002 204 #define AUGLX_DBG_IRQ 0x0004 205 #else 206 #define DPRINTF(x,y) /* nothing */ 207 #endif 208 209 struct cfdriver auglx_cd = { 210 NULL, "auglx", DV_DULL 211 }; 212 213 int auglx_open(void *, int); 214 void auglx_close(void *); 215 int auglx_set_params(void *, int, int, struct audio_params *, 216 struct audio_params *); 217 int auglx_round_blocksize(void *, int); 218 int auglx_halt_output(void *); 219 int auglx_halt_input(void *); 220 int auglx_set_port(void *, mixer_ctrl_t *); 221 int auglx_get_port(void *, mixer_ctrl_t *); 222 int auglx_query_devinfo(void *, mixer_devinfo_t *); 223 void *auglx_allocm(void *, int, size_t, int, int); 224 void auglx_freem(void *, void *, int); 225 size_t auglx_round_buffersize(void *, int, size_t); 226 int auglx_get_props(void *); 227 int auglx_trigger_output(void *, void *, void *, int, void (*)(void *), 228 void *, struct audio_params *); 229 int auglx_trigger_input(void *, void *, void *, int, void (*)(void *), 230 void *, struct audio_params *); 231 int auglx_alloc_cdata(struct auglx_softc *); 232 int auglx_alloc_prd(struct auglx_softc *, size_t, struct auglx_ring *); 233 void auglx_free_prd(struct auglx_softc *sc, struct auglx_ring *bm); 234 int auglx_allocmem(struct auglx_softc *, size_t, size_t, struct auglx_dma *); 235 void auglx_freemem(struct auglx_softc *, struct auglx_dma *); 236 237 struct audio_hw_if auglx_hw_if = { 238 auglx_open, 239 auglx_close, 240 auglx_set_params, 241 auglx_round_blocksize, 242 NULL, /* commit_setting */ 243 NULL, /* init_output */ 244 NULL, /* init_input */ 245 NULL, /* start_output */ 246 NULL, /* start_input */ 247 auglx_halt_output, 248 auglx_halt_input, 249 NULL, /* speaker_ctl */ 250 NULL, /* getfd */ 251 auglx_set_port, 252 auglx_get_port, 253 auglx_query_devinfo, 254 auglx_allocm, 255 auglx_freem, 256 auglx_round_buffersize, 257 auglx_get_props, 258 auglx_trigger_output, 259 auglx_trigger_input 260 }; 261 262 int auglx_match(struct device *, void *, void *); 263 void auglx_attach(struct device *, struct device *, void *); 264 int auglx_activate(struct device *, int); 265 int auglx_intr(void *); 266 267 int auglx_attach_codec(void *, struct ac97_codec_if *); 268 int auglx_read_codec(void *, u_int8_t, u_int16_t *); 269 int auglx_write_codec(void *, u_int8_t, u_int16_t); 270 void auglx_reset_codec(void *); 271 enum ac97_host_flags auglx_flags_codec(void *); 272 273 struct cfattach auglx_ca = { 274 sizeof(struct auglx_softc), auglx_match, auglx_attach, NULL, 275 auglx_activate 276 }; 277 278 const struct pci_matchid auglx_devices[] = { 279 { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_CS5536_AUDIO } 280 }; 281 282 int 283 auglx_match(struct device *parent, void *match, void *aux) 284 { 285 return (pci_matchbyid((struct pci_attach_args *)aux, auglx_devices, 286 sizeof(auglx_devices) / sizeof(auglx_devices[0]))); 287 } 288 289 void 290 auglx_attach(struct device *parent, struct device *self, void *aux) 291 { 292 struct auglx_softc *sc = (struct auglx_softc *)self; 293 struct pci_attach_args *pa = aux; 294 bus_size_t bar_size; 295 pci_intr_handle_t ih; 296 const char *intrstr; 297 298 if (pci_mapreg_map(pa, AUGLX_ACC_BAR, PCI_MAPREG_TYPE_IO, 0, 299 &sc->sc_iot, &sc->sc_ioh, NULL, &bar_size, 0)) { 300 printf(": can't map ACC I/O space\n"); 301 return; 302 } 303 304 sc->sc_dmat = pa->pa_dmat; 305 sc->sc_dmamap_flags = BUS_DMA_COHERENT; 306 307 if (pci_intr_map(pa, &ih)) { 308 printf(": can't map interrupt"); 309 bus_space_unmap(sc->sc_iot, sc->sc_ioh, bar_size); 310 return; 311 } 312 intrstr = pci_intr_string(pa->pa_pc, ih); 313 sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO | IPL_MPSAFE, 314 auglx_intr, sc, sc->sc_dev.dv_xname); 315 if (!sc->sc_ih) { 316 printf(": can't establish interrupt"); 317 if (intrstr) 318 printf(" at %s", intrstr); 319 printf("\n"); 320 bus_space_unmap(sc->sc_iot, sc->sc_ioh, bar_size); 321 return; 322 } 323 324 printf(": %s, %s\n", intrstr, "CS5536 AC97"); 325 326 sc->host_if.arg = sc; 327 sc->host_if.attach = auglx_attach_codec; 328 sc->host_if.read = auglx_read_codec; 329 sc->host_if.write = auglx_write_codec; 330 sc->host_if.reset = auglx_reset_codec; 331 sc->host_if.flags = auglx_flags_codec; 332 333 if (ac97_attach(&sc->host_if) != 0) { 334 bus_space_unmap(sc->sc_iot, sc->sc_ioh, bar_size); 335 return; 336 } 337 audio_attach_mi(&auglx_hw_if, sc, &sc->sc_dev); 338 } 339 340 /* Functions to communicate with the AC97 Codec via the ACC */ 341 int 342 auglx_read_codec(void *v, u_int8_t reg, u_int16_t *val) 343 { 344 struct auglx_softc *sc = v; 345 u_int32_t codec_cntl, codec_status; 346 int i; 347 348 codec_cntl = RW_CMD | ((u_int32_t)reg << 24) | CMD_NEW; 349 bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_CODEC_CNTL, codec_cntl); 350 351 for (i = AUGLX_TOUT; i; i--) { 352 codec_cntl = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 353 ACC_CODEC_CNTL); 354 if (!(codec_cntl & CMD_NEW)) 355 break; 356 delay(1); 357 } 358 if (codec_cntl & CMD_NEW) { 359 printf("%s: codec read timeout after write\n", 360 sc->sc_dev.dv_xname); 361 return -1; 362 } 363 364 for (i = AUGLX_TOUT; i; i--) { 365 codec_status = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 366 ACC_CODEC_STATUS); 367 if ((codec_status & STS_NEW) && (codec_status >> 24 == reg)) 368 break; 369 delay(10); 370 } 371 if (i == 0) { 372 printf("%s: codec status read timeout, 0x%08x\n", 373 sc->sc_dev.dv_xname, codec_status); 374 return -1; 375 } 376 377 *val = codec_status & 0xffff; 378 DPRINTF(AUGLX_DBG_ACC, ("%s: read codec register 0x%02x: 0x%04x\n", 379 sc->sc_dev.dv_xname, reg, *val)); 380 return 0; 381 } 382 383 int 384 auglx_write_codec(void *v, u_int8_t reg, u_int16_t val) 385 { 386 struct auglx_softc *sc = v; 387 u_int32_t codec_cntl; 388 int i; 389 390 DPRINTF(AUGLX_DBG_ACC, ("%s: write codec register 0x%02x: 0x%04x\n", 391 sc->sc_dev.dv_xname, reg, val)); 392 393 394 codec_cntl = ((u_int32_t)reg << 24) | CMD_NEW | val; 395 bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_CODEC_CNTL, codec_cntl); 396 397 for (i = AUGLX_TOUT; i; i--) { 398 codec_cntl = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 399 ACC_CODEC_CNTL); 400 if (!(codec_cntl & CMD_NEW)) 401 break; 402 delay(1); 403 } 404 if (codec_cntl & CMD_NEW) { 405 printf("%s: codec write timeout\n", sc->sc_dev.dv_xname); 406 return -1; 407 } 408 409 return 0; 410 } 411 412 int 413 auglx_attach_codec(void *v, struct ac97_codec_if *cif) 414 { 415 struct auglx_softc *sc = v; 416 417 sc->codec_if = cif; 418 return 0; 419 } 420 421 void 422 auglx_reset_codec(void *v) 423 { 424 struct auglx_softc *sc = v; 425 u_int32_t codec_cntl; 426 int i; 427 428 codec_cntl = LNK_WRM_RST | CMD_NEW; 429 bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_CODEC_CNTL, codec_cntl); 430 431 for (i = AUGLX_TOUT; i; i--) { 432 codec_cntl = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 433 ACC_CODEC_CNTL); 434 if (!(codec_cntl & CMD_NEW)) 435 continue; 436 delay(1); 437 } 438 if (codec_cntl & CMD_NEW) 439 printf("%s: codec reset timeout\n", sc->sc_dev.dv_xname); 440 } 441 442 enum ac97_host_flags 443 auglx_flags_codec(void *v) 444 { 445 return 0; 446 } 447 448 /* 449 * Audio functions 450 */ 451 int 452 auglx_open(void *v, int flags) 453 { 454 return 0; 455 } 456 457 void 458 auglx_close(void *v) 459 { 460 } 461 462 int 463 auglx_set_params(void *v, int setmode, int usemode, struct audio_params *play, 464 struct audio_params *rec) 465 { 466 struct auglx_softc *sc = v; 467 int error; 468 u_int orate; 469 470 if (setmode & AUMODE_PLAY) { 471 play->precision = 16; 472 play->channels = 2; 473 play->encoding = AUDIO_ENCODING_SLINEAR_LE; 474 play->bps = AUDIO_BPS(play->precision); 475 play->msb = 1; 476 477 orate = play->sample_rate; 478 479 play->sample_rate = orate; 480 error = ac97_set_rate(sc->codec_if, 481 AC97_REG_PCM_LFE_DAC_RATE, &play->sample_rate); 482 if (error) 483 return error; 484 485 play->sample_rate = orate; 486 error = ac97_set_rate(sc->codec_if, 487 AC97_REG_PCM_SURR_DAC_RATE, &play->sample_rate); 488 if (error) 489 return error; 490 491 play->sample_rate = orate; 492 error = ac97_set_rate(sc->codec_if, 493 AC97_REG_PCM_FRONT_DAC_RATE, &play->sample_rate); 494 if (error) 495 return error; 496 } 497 498 if (setmode & AUMODE_RECORD) { 499 rec->precision = 16; 500 rec->channels = 2; 501 rec->encoding = AUDIO_ENCODING_ULINEAR_LE; 502 rec->bps = AUDIO_BPS(rec->precision); 503 rec->msb = 1; 504 505 error = ac97_set_rate(sc->codec_if, AC97_REG_PCM_LR_ADC_RATE, 506 &rec->sample_rate); 507 if (error) 508 return error; 509 } 510 511 return 0; 512 } 513 514 int 515 auglx_round_blocksize(void *v, int blk) 516 { 517 return (blk + 0x3f) & ~0x3f; 518 } 519 520 int 521 auglx_halt_output(void *v) 522 { 523 struct auglx_softc *sc = v; 524 525 DPRINTF(AUGLX_DBG_DMA, ("%s: halt_output\n", sc->sc_dev.dv_xname)); 526 527 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM0_CMD, 0x00); 528 sc->bm0.intr = NULL; 529 return 0; 530 } 531 532 int 533 auglx_halt_input(void *v) 534 { 535 struct auglx_softc *sc = v; 536 537 DPRINTF(AUGLX_DBG_DMA, 538 ("%s: halt_input\n", sc->sc_dev.dv_xname)); 539 540 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM1_CMD, 0x00); 541 sc->bm1.intr = NULL; 542 return 0; 543 } 544 545 int 546 auglx_set_port(void *v, mixer_ctrl_t *cp) 547 { 548 struct auglx_softc *sc = v; 549 return sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp); 550 } 551 552 int 553 auglx_get_port(void *v, mixer_ctrl_t *cp) 554 { 555 struct auglx_softc *sc = v; 556 return sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp); 557 } 558 559 int 560 auglx_query_devinfo(void *v, mixer_devinfo_t *dp) 561 { 562 struct auglx_softc *sc = v; 563 return sc->codec_if->vtbl->query_devinfo(sc->codec_if, dp); 564 } 565 566 void * 567 auglx_allocm(void *v, int direction, size_t size, int pool, int flags) 568 { 569 struct auglx_softc *sc = v; 570 struct auglx_dma *p; 571 int error; 572 573 DPRINTF(AUGLX_DBG_DMA, ("%s: request buffer of size %ld, dir %d\n", 574 sc->sc_dev.dv_xname, size, direction)); 575 576 /* can only use 1 segment */ 577 if (size > AUGLX_DMASEG_MAX) { 578 DPRINTF(AUGLX_DBG_DMA, 579 ("%s: requested buffer size too large: %d", \ 580 sc->sc_dev.dv_xname, size)); 581 return NULL; 582 } 583 584 p = malloc(sizeof(*p), pool, flags | M_ZERO); 585 if (!p) 586 return NULL; 587 588 error = auglx_allocmem(sc, size, PAGE_SIZE, p); 589 if (error) { 590 free(p, pool, 0); 591 return NULL; 592 } 593 594 p->next = sc->sc_dmas; 595 sc->sc_dmas = p; 596 597 return p->addr; 598 } 599 600 void 601 auglx_freem(void *v, void *ptr, int pool) 602 { 603 struct auglx_softc *sc; 604 struct auglx_dma *p, **pp; 605 606 sc = v; 607 for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->next) { 608 if (p->addr == ptr) { 609 auglx_freemem(sc, p); 610 *pp = p->next; 611 free(p, pool, 0); 612 return; 613 } 614 } 615 } 616 617 618 size_t 619 auglx_round_buffersize(void *v, int direction, size_t size) 620 { 621 if (size > AUGLX_DMASEG_MAX) 622 size = AUGLX_DMASEG_MAX; 623 624 return size; 625 } 626 627 int 628 auglx_get_props(void *v) 629 { 630 return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX; 631 } 632 633 int 634 auglx_intr(void *v) 635 { 636 struct auglx_softc *sc = v; 637 u_int16_t irq_sts; 638 u_int8_t bm_sts; 639 640 mtx_enter(&audio_lock); 641 irq_sts = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ACC_IRQ_STATUS); 642 if (irq_sts == 0) { 643 mtx_leave(&audio_lock); 644 return 0; 645 } 646 647 if (irq_sts & BM0_IRQ_STS) { 648 bm_sts = bus_space_read_1(sc->sc_iot, sc->sc_ioh, 649 ACC_BM0_STATUS); 650 if (sc->bm0.intr) { 651 sc->bm0.intr(sc->bm0.arg); 652 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM0_CMD, 653 BMx_CMD_BM_CTL_EN); 654 } 655 } else if (irq_sts & BM1_IRQ_STS) { 656 bm_sts = bus_space_read_1(sc->sc_iot, sc->sc_ioh, 657 ACC_BM1_STATUS); 658 if (sc->bm1.intr) { 659 sc->bm1.intr(sc->bm1.arg); 660 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM1_CMD, 661 BMx_CMD_RW | BMx_CMD_BM_CTL_EN); 662 } 663 } else { 664 DPRINTF(AUGLX_DBG_IRQ, ("%s: stray intr, status = 0x%04x\n", 665 sc->sc_dev.dv_xname, irq_sts)); 666 mtx_leave(&audio_lock); 667 return -1; 668 } 669 mtx_leave(&audio_lock); 670 return 1; 671 } 672 673 int 674 auglx_trigger_output(void *v, void *start, void *end, int blksize, 675 void (*intr)(void *), void *arg, struct audio_params *param) 676 { 677 struct auglx_softc *sc = v; 678 struct auglx_dma *p; 679 size_t size; 680 u_int32_t addr; 681 int i, nprd; 682 683 size = (size_t)((caddr_t)end - (caddr_t)start); 684 DPRINTF(AUGLX_DBG_DMA, ("%s: trigger_output, %p 0x%08x bytes, " 685 "blksize 0x%04x\n", sc->sc_dev.dv_xname, start, size, blksize)); 686 687 for (p = sc->sc_dmas; p && p->addr != start; p = p->next); 688 if (!p) { 689 DPRINTF(AUGLX_DBG_DMA, ("%s dma reg not found\n", 690 sc->sc_dev.dv_xname)); 691 return -1; 692 } 693 694 /* set up the PRDs */ 695 nprd = size / blksize; 696 if (sc->bm0.sc_nprd != nprd + 1) { 697 if (sc->bm0.sc_nprd > 0) 698 auglx_free_prd(sc, &sc->bm0); 699 sc->bm0.sc_nprd = nprd + 1; 700 auglx_alloc_prd(sc, 701 sc->bm0.sc_nprd * sizeof(struct auglx_prd), &sc->bm0); 702 } 703 DPRINTF(AUGLX_DBG_DMA, ("%s: nprd = %d\n", sc->sc_dev.dv_xname, 704 nprd)); 705 addr = p->segs->ds_addr; 706 for (i = 0; i < nprd; i++) { 707 sc->bm0.sc_vprd[i].base = addr; 708 sc->bm0.sc_vprd[i].size = blksize | AUGLX_PRD_EOP; 709 addr += blksize; 710 } 711 sc->bm0.sc_vprd[i].base = sc->bm0.sc_prd->dm_segs[0].ds_addr; 712 sc->bm0.sc_vprd[i].size = AUGLX_PRD_JMP; 713 714 #ifdef AUGLX_DEBUG 715 for (i = 0; i < sc->bm0.sc_nprd; i++) 716 DPRINTF(AUGLX_DBG_DMA, ("%s: PRD[%d].base = %p, size %p\n", 717 sc->sc_dev.dv_xname, i, sc->bm0.sc_vprd[i].base, 718 sc->bm0.sc_vprd[i].size)); 719 #endif 720 sc->bm0.intr = intr; 721 sc->bm0.arg = arg; 722 723 mtx_enter(&audio_lock); 724 /* Program the BM0 PRD register */ 725 bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM0_PRD, 726 sc->bm0.sc_prd->dm_segs[0].ds_addr); 727 /* Start Audio Bus Master 0 */ 728 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM0_CMD, 729 BMx_CMD_BM_CTL_EN); 730 mtx_leave(&audio_lock); 731 return 0; 732 } 733 734 int 735 auglx_trigger_input(void *v, void *start, void *end, int blksize, 736 void (*intr)(void *), void * arg, struct audio_params *param) 737 { 738 struct auglx_softc *sc = v; 739 struct auglx_dma *p; 740 size_t size; 741 u_int32_t addr; 742 int i, nprd; 743 744 size = (size_t)((caddr_t)end - (caddr_t)start); 745 DPRINTF(AUGLX_DBG_DMA, ("%s: trigger_input, %p 0x%08x bytes, " 746 "blksize 0x%04x\n", sc->sc_dev.dv_xname, start, size, blksize)); 747 748 for (p = sc->sc_dmas; p && p->addr != start; p = p->next); 749 if (!p) { 750 DPRINTF(AUGLX_DBG_DMA, ("%s dma reg not found\n", 751 sc->sc_dev.dv_xname)); 752 return -1; 753 } 754 755 /* set up the PRDs */ 756 nprd = size / blksize; 757 if (sc->bm1.sc_nprd != nprd + 1) { 758 if (sc->bm1.sc_nprd > 0) 759 auglx_free_prd(sc, &sc->bm1); 760 sc->bm1.sc_nprd = nprd + 1; 761 auglx_alloc_prd(sc, 762 sc->bm1.sc_nprd * sizeof(struct auglx_prd), &sc->bm1); 763 } 764 DPRINTF(AUGLX_DBG_DMA, ("%s: nprd = %d\n", sc->sc_dev.dv_xname, 765 nprd)); 766 addr = p->segs->ds_addr; 767 for (i = 0; i < nprd; i++) { 768 sc->bm1.sc_vprd[i].base = addr; 769 sc->bm1.sc_vprd[i].size = blksize | AUGLX_PRD_EOP; 770 addr += blksize; 771 } 772 sc->bm1.sc_vprd[i].base = sc->bm1.sc_prd->dm_segs[0].ds_addr; 773 sc->bm1.sc_vprd[i].size = AUGLX_PRD_JMP; 774 775 #ifdef AUGLX_DEBUG 776 for (i = 0; i < sc->bm1.sc_nprd; i++) 777 DPRINTF(AUGLX_DBG_DMA, ("%s: PRD[%d].base = %p, size %p\n", 778 sc->sc_dev.dv_xname, i, sc->bm1.sc_vprd[i].base, 779 sc->bm1.sc_vprd[i].size)); 780 #endif 781 sc->bm1.intr = intr; 782 sc->bm1.arg = arg; 783 784 mtx_enter(&audio_lock); 785 /* Program the BM1 PRD register */ 786 bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM1_PRD, 787 sc->bm1.sc_prd->dm_segs[0].ds_addr); 788 /* Start Audio Bus Master 0 */ 789 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM1_CMD, 790 BMx_CMD_RW | BMx_CMD_BM_CTL_EN); 791 mtx_leave(&audio_lock); 792 return 0; 793 } 794 795 int 796 auglx_allocmem(struct auglx_softc *sc, size_t size, size_t align, 797 struct auglx_dma *p) 798 { 799 int error; 800 801 p->size = size; 802 error = bus_dmamem_alloc(sc->sc_dmat, p->size, align, 0, p->segs, 1, 803 &p->nsegs, BUS_DMA_NOWAIT); 804 if (error) { 805 DPRINTF(AUGLX_DBG_DMA, 806 ("%s: bus_dmamem_alloc failed: error %d\n", 807 sc->sc_dev.dv_xname, error)); 808 return error; 809 } 810 811 error = bus_dmamem_map(sc->sc_dmat, p->segs, 1, p->size, &p->addr, 812 BUS_DMA_NOWAIT | sc->sc_dmamap_flags); 813 if (error) { 814 DPRINTF(AUGLX_DBG_DMA, 815 ("%s: bus_dmamem_map failed: error %d\n", 816 sc->sc_dev.dv_xname, error)); 817 goto free; 818 } 819 820 error = bus_dmamap_create(sc->sc_dmat, p->size, 1, p->size, 0, 821 BUS_DMA_NOWAIT, &p->map); 822 if (error) { 823 DPRINTF(AUGLX_DBG_DMA, 824 ("%s: bus_dmamap_create failed: error %d\n", 825 sc->sc_dev.dv_xname, error)); 826 goto unmap; 827 } 828 829 error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, p->size, NULL, 830 BUS_DMA_NOWAIT); 831 if (error) { 832 DPRINTF(AUGLX_DBG_DMA, 833 ("%s: bus_dmamap_load failed: error %d\n", 834 sc->sc_dev.dv_xname, error)); 835 goto destroy; 836 } 837 return 0; 838 839 destroy: 840 bus_dmamap_destroy(sc->sc_dmat, p->map); 841 unmap: 842 bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size); 843 free: 844 bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs); 845 return error; 846 } 847 848 void 849 auglx_freemem(struct auglx_softc *sc, struct auglx_dma *p) 850 { 851 bus_dmamap_unload(sc->sc_dmat, p->map); 852 bus_dmamap_destroy(sc->sc_dmat, p->map); 853 bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size); 854 bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs); 855 } 856 857 int 858 auglx_alloc_prd(struct auglx_softc *sc, size_t size, struct auglx_ring *bm) 859 { 860 int error, rseg; 861 862 /* 863 * Allocate PRD table structure, and create and load the 864 * DMA map for it. 865 */ 866 if ((error = bus_dmamem_alloc(sc->sc_dmat, size, 867 PAGE_SIZE, 0, &bm->seg, 1, &rseg, 0)) != 0) { 868 printf("%s: unable to allocate PRD, error = %d\n", 869 sc->sc_dev.dv_xname, error); 870 goto fail_0; 871 } 872 873 if ((error = bus_dmamem_map(sc->sc_dmat, &bm->seg, rseg, 874 size, (caddr_t *)&bm->sc_vprd, 875 sc->sc_dmamap_flags)) != 0) { 876 printf("%s: unable to map PRD, error = %d\n", 877 sc->sc_dev.dv_xname, error); 878 goto fail_1; 879 } 880 881 if ((error = bus_dmamap_create(sc->sc_dmat, size, 882 1, size, 0, 0, &bm->sc_prd)) != 0) { 883 printf("%s: unable to create PRD DMA map, " 884 "error = %d\n", sc->sc_dev.dv_xname, error); 885 goto fail_2; 886 } 887 888 if ((error = bus_dmamap_load(sc->sc_dmat, bm->sc_prd, bm->sc_vprd, 889 size, NULL, 0)) != 0) { 890 printf("%s: unable tp load control data DMA map, " 891 "error = %d\n", sc->sc_dev.dv_xname, error); 892 goto fail_3; 893 } 894 895 return 0; 896 897 fail_3: 898 bus_dmamap_destroy(sc->sc_dmat, bm->sc_prd); 899 fail_2: 900 bus_dmamem_unmap(sc->sc_dmat, (caddr_t)bm->sc_vprd, 901 sizeof(struct auglx_prd)); 902 fail_1: 903 bus_dmamem_free(sc->sc_dmat, &bm->seg, rseg); 904 fail_0: 905 return error; 906 } 907 908 void 909 auglx_free_prd(struct auglx_softc *sc, struct auglx_ring *bm) 910 { 911 bus_dmamap_unload(sc->sc_dmat, bm->sc_prd); 912 bus_dmamap_destroy(sc->sc_dmat, bm->sc_prd); 913 bus_dmamem_unmap(sc->sc_dmat, (caddr_t)bm->sc_vprd, bm->sc_size); 914 bus_dmamem_free(sc->sc_dmat, &bm->seg, bm->nsegs); 915 } 916 917 int 918 auglx_activate(struct device *self, int act) 919 { 920 struct auglx_softc *sc = (struct auglx_softc *)self; 921 int rv = 0; 922 923 switch (act) { 924 case DVACT_RESUME: 925 ac97_resume(&sc->host_if, sc->codec_if); 926 rv = config_activate_children(self, act); 927 break; 928 default: 929 rv = config_activate_children(self, act); 930 break; 931 } 932 return (rv); 933 } 934