audiovia97.c revision 11936:54dc8a89ba0d
1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22/* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27/* 28 * Purpose: Driver for the VIA VT82C686A AC97 audio controller 29 */ 30/* 31 * 32 * Copyright (C) 4Front Technologies 1996-2009. 33 */ 34 35#include <sys/types.h> 36#include <sys/modctl.h> 37#include <sys/kmem.h> 38#include <sys/conf.h> 39#include <sys/ddi.h> 40#include <sys/sunddi.h> 41#include <sys/pci.h> 42#include <sys/note.h> 43#include <sys/audio/audio_driver.h> 44#include <sys/audio/ac97.h> 45 46#include "audiovia97.h" 47 48static struct ddi_device_acc_attr dev_attr = { 49 DDI_DEVICE_ATTR_V0, 50 DDI_STRUCTURE_LE_ACC, 51 DDI_STRICTORDER_ACC 52}; 53 54static struct ddi_device_acc_attr buf_attr = { 55 DDI_DEVICE_ATTR_V0, 56 DDI_NEVERSWAP_ACC, 57 DDI_STRICTORDER_ACC 58}; 59 60static ddi_dma_attr_t dma_attr_sgd = { 61 DMA_ATTR_V0, /* version number */ 62 0x00000000, /* low DMA address range */ 63 0xffffffff, /* high DMA address range */ 64 0x0000ffff, /* DMA counter register */ 65 8, /* DMA address alignment */ 66 0x3c, /* DMA burstsizes */ 67 8, /* min effective DMA size */ 68 0xffffffff, /* max DMA xfer size */ 69 0x00000fff, /* segment boundary */ 70 1, /* s/g length */ 71 8, /* granularity of device */ 72 0 /* Bus specific DMA flags */ 73}; 74 75static ddi_dma_attr_t dma_attr_buf = { 76 DMA_ATTR_V0, /* version number */ 77 0x00000000, /* low DMA address range */ 78 0xffffffff, /* high DMA address range */ 79 0xfffffffe, /* DMA counter register */ 80 4, /* DMA address alignment */ 81 0x3c, /* DMA burstsizes */ 82 4, /* min effective DMA size */ 83 0xffffffff, /* max DMA xfer size */ 84 0xffffffff, /* segment boundary */ 85 1, /* s/g length */ 86 4, /* granularity of device */ 87 0 /* Bus specific DMA flags */ 88}; 89 90static int via97_attach(dev_info_t *); 91static int via97_resume(dev_info_t *); 92static int via97_detach(via97_devc_t *); 93static int via97_suspend(via97_devc_t *); 94 95static int via97_open(void *, int, unsigned *, caddr_t *); 96static void via97_close(void *); 97static int via97_start(void *); 98static void via97_stop(void *); 99static int via97_format(void *); 100static int via97_channels(void *); 101static int via97_rate(void *); 102static uint64_t via97_count(void *); 103static void via97_sync(void *, unsigned); 104static uint_t via97_playahead(void *); 105 106static uint16_t via97_read_ac97(void *, uint8_t); 107static void via97_write_ac97(void *, uint8_t, uint16_t); 108static int via97_alloc_port(via97_devc_t *, int); 109static void via97_destroy(via97_devc_t *); 110static void via97_hwinit(via97_devc_t *); 111 112static audio_engine_ops_t via97_engine_ops = { 113 AUDIO_ENGINE_VERSION, 114 via97_open, 115 via97_close, 116 via97_start, 117 via97_stop, 118 via97_count, 119 via97_format, 120 via97_channels, 121 via97_rate, 122 via97_sync, 123 NULL, 124 NULL, 125 via97_playahead 126}; 127 128static uint16_t 129via97_read_ac97(void *arg, uint8_t index) 130{ 131 via97_devc_t *devc = arg; 132 int tmp, addr, i; 133 134 /* Index has only 7 bits */ 135 if (index > 0x7F) 136 return (0xffff); 137 138 addr = (index << 16) + CODEC_RD; 139 OUTL(devc, devc->base + AC97CODEC, addr); 140 drv_usecwait(100); 141 142 /* Check AC CODEC access time out */ 143 for (i = 0; i < CODEC_TIMEOUT_COUNT; i++) { 144 /* if send command over, break */ 145 if (INL(devc, devc->base + AC97CODEC) & STA_VALID) 146 break; 147 drv_usecwait(50); 148 } 149 if (i == CODEC_TIMEOUT_COUNT) { 150 return (0xffff); 151 } 152 153 /* Check if Index still ours? If yes, return data, else return FAIL */ 154 tmp = INL(devc, devc->base + AC97CODEC); 155 OUTB(devc, devc->base + AC97CODEC + 3, 0x02); 156 if (((tmp & CODEC_INDEX) >> 16) == index) { 157 return ((int)tmp & CODEC_DATA); 158 } 159 return (0xffff); 160} 161 162static void 163via97_write_ac97(void *arg, uint8_t index, uint16_t data) 164{ 165 via97_devc_t *devc = arg; 166 int value = 0; 167 unsigned int i = 0; 168 169 value = (index << 16) + data; 170 OUTL(devc, devc->base + AC97CODEC, value); 171 drv_usecwait(100); 172 173 /* Check AC CODEC access time out */ 174 for (i = 0; i < CODEC_TIMEOUT_COUNT; i++) { 175 /* if send command over, break */ 176 if (!(INL(devc, devc->base + AC97CODEC) & IN_CMD)) 177 break; 178 drv_usecwait(50); 179 } 180} 181 182/* 183 * Audio routines 184 */ 185 186int 187via97_open(void *arg, int flag, unsigned *nframesp, caddr_t *bufp) 188{ 189 via97_portc_t *portc = arg; 190 191 _NOTE(ARGUNUSED(flag)); 192 193 portc->count = 0; 194 *nframesp = portc->nframes; 195 *bufp = portc->buf_kaddr; 196 197 return (0); 198} 199 200void 201via97_close(void *arg) 202{ 203 _NOTE(ARGUNUSED(arg)); 204} 205 206int 207via97_start(void *arg) 208{ 209 via97_portc_t *portc = arg; 210 via97_devc_t *devc = portc->devc; 211 212 portc->pos = 0; 213 214 OUTB(devc, portc->base + 0x01, 0x40); /* Stop */ 215 OUTL(devc, portc->base + 4, portc->sgd_paddr); 216 /* Set autostart at EOL, stereo, 16 bits */ 217 OUTB(devc, portc->base + 0x02, 218 0x80 | /* Set autostart at EOL */ 219 0x20 | /* 16 bits */ 220 0x10); /* Stereo */ 221 222 OUTB(devc, portc->base + 0x01, 0x80); /* Start */ 223 224 return (0); 225} 226 227void 228via97_stop(void *arg) 229{ 230 via97_portc_t *portc = arg; 231 via97_devc_t *devc = portc->devc; 232 233 OUTB(devc, portc->base + 0x01, 0x40); /* Stop */ 234} 235 236int 237via97_format(void *arg) 238{ 239 _NOTE(ARGUNUSED(arg)); 240 241 return (AUDIO_FORMAT_S16_LE); 242} 243 244int 245via97_channels(void *arg) 246{ 247 _NOTE(ARGUNUSED(arg)); 248 249 return (2); 250} 251 252int 253via97_rate(void *arg) 254{ 255 _NOTE(ARGUNUSED(arg)); 256 257 return (48000); 258} 259 260void 261via97_sync(void *arg, unsigned nframes) 262{ 263 via97_portc_t *portc = arg; 264 _NOTE(ARGUNUSED(nframes)); 265 266 (void) ddi_dma_sync(portc->buf_dmah, 0, 0, portc->syncdir); 267} 268 269uint_t 270via97_playahead(void *arg) 271{ 272 _NOTE(ARGUNUSED(arg)); 273 274 /* 275 * We see some situations where the default 1.5 fragments from 276 * the framework is not enough. 800-900 frame jitter is not 277 * uncommon. Especially at startup. 278 */ 279 return (1024); 280} 281 282uint64_t 283via97_count(void *arg) 284{ 285 via97_portc_t *portc = arg; 286 via97_devc_t *devc = portc->devc; 287 uint32_t pos; 288 uint32_t n; 289 290 pos = INL(devc, portc->base + 0x0c) & 0xffffff; 291 /* convert from bytes to 16-bit stereo frames */ 292 pos /= (sizeof (int16_t) * 2); 293 294 if (pos >= portc->pos) { 295 n = portc->nframes - (pos - portc->pos); 296 } else { 297 n = portc->pos - pos; 298 } 299 portc->pos = pos; 300 portc->count += n; 301 302 return (portc->count); 303} 304 305 306/* private implementation bits */ 307 308int 309via97_alloc_port(via97_devc_t *devc, int num) 310{ 311 via97_portc_t *portc; 312 size_t len; 313 ddi_dma_cookie_t cookie; 314 uint_t count; 315 int dir; 316 unsigned caps; 317 audio_dev_t *adev; 318 uint32_t *desc; 319 320 adev = devc->adev; 321 portc = kmem_zalloc(sizeof (*portc), KM_SLEEP); 322 devc->portc[num] = portc; 323 portc->devc = devc; 324 portc->base = devc->base + num * 0x10; 325 326 switch (num) { 327 case VIA97_REC_SGD_NUM: 328 portc->syncdir = DDI_DMA_SYNC_FORKERNEL; 329 caps = ENGINE_INPUT_CAP; 330 dir = DDI_DMA_READ; 331 break; 332 case VIA97_PLAY_SGD_NUM: 333 portc->syncdir = DDI_DMA_SYNC_FORDEV; 334 caps = ENGINE_OUTPUT_CAP; 335 dir = DDI_DMA_WRITE; 336 break; 337 default: 338 return (DDI_FAILURE); 339 } 340 341 /* Simplicity -- a single contiguous looping buffer */ 342 portc->nframes = 2048; 343 portc->buf_size = portc->nframes * sizeof (int16_t) * 2; 344 345 /* first allocate up space for SGD list */ 346 if (ddi_dma_alloc_handle(devc->dip, &dma_attr_sgd, 347 DDI_DMA_SLEEP, NULL, &portc->sgd_dmah) != DDI_SUCCESS) { 348 audio_dev_warn(adev, "failed to allocate SGD handle"); 349 return (DDI_FAILURE); 350 } 351 352 /* a single SGD entry is only 8 bytes long */ 353 if (ddi_dma_mem_alloc(portc->sgd_dmah, 8, &dev_attr, 354 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &portc->sgd_kaddr, 355 &len, &portc->sgd_acch) != DDI_SUCCESS) { 356 audio_dev_warn(adev, "failed to allocate SGD memory"); 357 return (DDI_FAILURE); 358 } 359 360 if (ddi_dma_addr_bind_handle(portc->sgd_dmah, NULL, 361 portc->sgd_kaddr, len, DDI_DMA_CONSISTENT | DDI_DMA_WRITE, 362 DDI_DMA_SLEEP, NULL, &cookie, &count) != DDI_SUCCESS) { 363 audio_dev_warn(adev, "failed binding SGD DMA handle"); 364 return (DDI_FAILURE); 365 } 366 portc->sgd_paddr = cookie.dmac_address; 367 368 /* now buffers */ 369 if (ddi_dma_alloc_handle(devc->dip, &dma_attr_buf, DDI_DMA_SLEEP, NULL, 370 &portc->buf_dmah) != DDI_SUCCESS) { 371 audio_dev_warn(adev, "failed to allocate BUF handle"); 372 return (DDI_FAILURE); 373 } 374 375 if (ddi_dma_mem_alloc(portc->buf_dmah, portc->buf_size, 376 &buf_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, 377 &portc->buf_kaddr, &len, &portc->buf_acch) != DDI_SUCCESS) { 378 audio_dev_warn(adev, "failed to allocate BUF memory"); 379 return (DDI_FAILURE); 380 } 381 382 if (ddi_dma_addr_bind_handle(portc->buf_dmah, NULL, portc->buf_kaddr, 383 len, DDI_DMA_CONSISTENT | dir, DDI_DMA_SLEEP, NULL, &cookie, 384 &count) != DDI_SUCCESS) { 385 audio_dev_warn(adev, "failed binding BUF DMA handle"); 386 return (DDI_FAILURE); 387 } 388 portc->buf_paddr = cookie.dmac_address; 389 390 /* now wire descriptor up -- we only use one (which has EOL set)! */ 391 desc = (void *)portc->sgd_kaddr; 392 ddi_put32(portc->sgd_acch, desc++, portc->buf_paddr); 393 ddi_put32(portc->sgd_acch, desc++, 0x80000000U | portc->buf_size); 394 395 OUTL(devc, portc->base + 4, portc->sgd_paddr); 396 (void) ddi_dma_sync(portc->sgd_dmah, 0, 0, DDI_DMA_SYNC_FORDEV); 397 398 portc->engine = audio_engine_alloc(&via97_engine_ops, caps); 399 if (portc->engine == NULL) { 400 audio_dev_warn(adev, "audio_engine_alloc failed"); 401 return (DDI_FAILURE); 402 } 403 404 audio_engine_set_private(portc->engine, portc); 405 audio_dev_add_engine(adev, portc->engine); 406 407 return (DDI_SUCCESS); 408} 409 410void 411via97_destroy(via97_devc_t *devc) 412{ 413 for (int i = 0; i < VIA97_NUM_PORTC; i++) { 414 via97_portc_t *portc = devc->portc[i]; 415 if (!portc) 416 continue; 417 if (portc->engine) { 418 audio_dev_remove_engine(devc->adev, portc->engine); 419 audio_engine_free(portc->engine); 420 } 421 if (portc->sgd_paddr) { 422 (void) ddi_dma_unbind_handle(portc->sgd_dmah); 423 } 424 if (portc->sgd_acch) { 425 ddi_dma_mem_free(&portc->sgd_acch); 426 } 427 if (portc->sgd_dmah) { 428 ddi_dma_free_handle(&portc->sgd_dmah); 429 } 430 if (portc->buf_paddr) { 431 (void) ddi_dma_unbind_handle(portc->buf_dmah); 432 } 433 if (portc->buf_acch) { 434 ddi_dma_mem_free(&portc->buf_acch); 435 } 436 if (portc->buf_dmah) { 437 ddi_dma_free_handle(&portc->buf_dmah); 438 } 439 kmem_free(portc, sizeof (*portc)); 440 } 441 442 if (devc->ac97 != NULL) { 443 ac97_free(devc->ac97); 444 } 445 if (devc->adev != NULL) { 446 audio_dev_free(devc->adev); 447 } 448 if (devc->regsh != NULL) { 449 ddi_regs_map_free(&devc->regsh); 450 } 451 if (devc->pcih != NULL) { 452 pci_config_teardown(&devc->pcih); 453 } 454 kmem_free(devc, sizeof (*devc)); 455} 456 457void 458via97_hwinit(via97_devc_t *devc) 459{ 460 ddi_acc_handle_t pcih = devc->pcih; 461 uint32_t tmp; 462 463 /* Enable codec, etc */ 464 465 pci_config_put8(pcih, 0x41, 0xc0); 466 drv_usecwait(10); 467 tmp = pci_config_get8(pcih, 0x41); 468 pci_config_put8(pcih, 0x41, tmp | 0x0c); 469 drv_usecwait(10); 470 471 /* disable game port/MIDI */ 472 pci_config_put8(pcih, 0x42, 0x00); 473 /* disable FM io */ 474 pci_config_put8(pcih, 0x48, 0x00); 475 476 /* Enable interrupt on FLAG and on EOL */ 477 tmp = INB(devc, devc->base + 0x22); 478 OUTB(devc, devc->base + 0x22, tmp | 0x83); 479} 480 481int 482via97_attach(dev_info_t *dip) 483{ 484 uint16_t pci_command, vendor, device; 485 via97_devc_t *devc; 486 ddi_acc_handle_t pcih; 487 488 devc = kmem_zalloc(sizeof (*devc), KM_SLEEP); 489 devc->dip = dip; 490 ddi_set_driver_private(dip, devc); 491 492 if ((devc->adev = audio_dev_alloc(dip, 0)) == NULL) { 493 cmn_err(CE_WARN, "audio_dev_alloc failed"); 494 goto error; 495 } 496 497 if (pci_config_setup(dip, &pcih) != DDI_SUCCESS) { 498 audio_dev_warn(devc->adev, "pci_config_setup failed"); 499 goto error; 500 } 501 devc->pcih = pcih; 502 503 vendor = pci_config_get16(pcih, PCI_CONF_VENID); 504 device = pci_config_get16(pcih, PCI_CONF_DEVID); 505 if (vendor != VIA_VENDOR_ID || 506 device != VIA_82C686) { 507 audio_dev_warn(devc->adev, "Hardware not recognized " 508 "(vendor=%x, dev=%x)", vendor, device); 509 goto error; 510 } 511 512 pci_command = pci_config_get16(pcih, PCI_CONF_COMM); 513 pci_command |= PCI_COMM_ME | PCI_COMM_IO; 514 pci_config_put16(pcih, PCI_CONF_COMM, pci_command); 515 516 if ((ddi_regs_map_setup(dip, 1, &devc->base, 0, 0, &dev_attr, 517 &devc->regsh)) != DDI_SUCCESS) { 518 audio_dev_warn(devc->adev, "failed to map registers"); 519 goto error; 520 } 521 522 audio_dev_set_description(devc->adev, "VIA 82C686 Audio"); 523 524 via97_hwinit(devc); 525 526 if ((via97_alloc_port(devc, VIA97_PLAY_SGD_NUM) != DDI_SUCCESS) || 527 (via97_alloc_port(devc, VIA97_REC_SGD_NUM) != DDI_SUCCESS)) { 528 goto error; 529 } 530 531 devc->ac97 = ac97_alloc(dip, via97_read_ac97, via97_write_ac97, devc); 532 if (devc->ac97 == NULL) { 533 audio_dev_warn(devc->adev, "failed to allocate ac97 handle"); 534 goto error; 535 } 536 537 if (ac97_init(devc->ac97, devc->adev) != DDI_SUCCESS) { 538 audio_dev_warn(devc->adev, "failed to init ac97"); 539 goto error; 540 } 541 542 if (audio_dev_register(devc->adev) != DDI_SUCCESS) { 543 audio_dev_warn(devc->adev, "unable to register with framework"); 544 goto error; 545 } 546 547 ddi_report_dev(dip); 548 549 return (DDI_SUCCESS); 550 551error: 552 via97_destroy(devc); 553 return (DDI_FAILURE); 554} 555 556int 557via97_resume(dev_info_t *dip) 558{ 559 via97_devc_t *devc; 560 561 devc = ddi_get_driver_private(dip); 562 563 via97_hwinit(devc); 564 565 ac97_reset(devc->ac97); 566 567 audio_dev_resume(devc->adev); 568 return (DDI_SUCCESS); 569} 570 571int 572via97_detach(via97_devc_t *devc) 573{ 574 if (audio_dev_unregister(devc->adev) != DDI_SUCCESS) 575 return (DDI_FAILURE); 576 577 via97_destroy(devc); 578 return (DDI_SUCCESS); 579} 580 581int 582via97_suspend(via97_devc_t *devc) 583{ 584 audio_dev_suspend(devc->adev); 585 return (DDI_SUCCESS); 586} 587 588static int via97_ddi_attach(dev_info_t *, ddi_attach_cmd_t); 589static int via97_ddi_detach(dev_info_t *, ddi_detach_cmd_t); 590static int via97_ddi_quiesce(dev_info_t *); 591 592static struct dev_ops via97_dev_ops = { 593 DEVO_REV, /* rev */ 594 0, /* refcnt */ 595 NULL, /* getinfo */ 596 nulldev, /* identify */ 597 nulldev, /* probe */ 598 via97_ddi_attach, /* attach */ 599 via97_ddi_detach, /* detach */ 600 nodev, /* reset */ 601 NULL, /* cb_ops */ 602 NULL, /* bus_ops */ 603 NULL, /* power */ 604 via97_ddi_quiesce, /* quiesce */ 605}; 606 607static struct modldrv via97_modldrv = { 608 &mod_driverops, /* drv_modops */ 609 "Via 82C686 Audio", /* linkinfo */ 610 &via97_dev_ops, /* dev_ops */ 611}; 612 613static struct modlinkage modlinkage = { 614 MODREV_1, 615 { &via97_modldrv, NULL } 616}; 617 618int 619_init(void) 620{ 621 int rv; 622 623 audio_init_ops(&via97_dev_ops, VIA97_NAME); 624 if ((rv = mod_install(&modlinkage)) != 0) { 625 audio_fini_ops(&via97_dev_ops); 626 } 627 return (rv); 628} 629 630int 631_fini(void) 632{ 633 int rv; 634 635 if ((rv = mod_remove(&modlinkage)) == 0) { 636 audio_fini_ops(&via97_dev_ops); 637 } 638 return (rv); 639} 640 641int 642_info(struct modinfo *modinfop) 643{ 644 return (mod_info(&modlinkage, modinfop)); 645} 646 647int 648via97_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 649{ 650 switch (cmd) { 651 case DDI_ATTACH: 652 return (via97_attach(dip)); 653 654 case DDI_RESUME: 655 return (via97_resume(dip)); 656 657 default: 658 return (DDI_FAILURE); 659 } 660} 661 662int 663via97_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 664{ 665 via97_devc_t *devc; 666 667 devc = ddi_get_driver_private(dip); 668 669 switch (cmd) { 670 case DDI_DETACH: 671 return (via97_detach(devc)); 672 673 case DDI_SUSPEND: 674 return (via97_suspend(devc)); 675 676 default: 677 return (DDI_FAILURE); 678 } 679} 680 681int 682via97_ddi_quiesce(dev_info_t *dip) 683{ 684 via97_devc_t *devc; 685 686 devc = ddi_get_driver_private(dip); 687 688 /* 689 * Turn off the hardware 690 */ 691 OUTB(devc, devc->base + 0x01, 0x40); 692 OUTB(devc, devc->base + 0x11, 0x40); 693 OUTB(devc, devc->base + 0x02, 0); 694 OUTB(devc, devc->base + 0x12, 0); 695 OUTL(devc, devc->base + 0x04, 0); 696 OUTL(devc, devc->base + 0x14, 0); 697 OUTL(devc, devc->base + 0x22, 0); 698 return (DDI_SUCCESS); 699} 700