audiovia823x.c revision 9484:fbd5ddc28e96
1233294Sstas/* 272445Sassar * CDDL HEADER START 372445Sassar * 472445Sassar * The contents of this file are subject to the terms of the 572445Sassar * Common Development and Distribution License (the "License"). 672445Sassar * You may not use this file except in compliance with the License. 772445Sassar * 872445Sassar * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 972445Sassar * or http://www.opensolaris.org/os/licensing. 1072445Sassar * See the License for the specific language governing permissions 1172445Sassar * and limitations under the License. 1272445Sassar * 1372445Sassar * When distributing Covered Code, include this CDDL HEADER in each 1472445Sassar * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15178825Sdfr * If applicable, add the following below this CDDL HEADER, with the 16178825Sdfr * fields enclosed by brackets "[]" replaced with your own identifying 17178825Sdfr * information: Portions Copyright [yyyy] [name of copyright owner] 18178825Sdfr * 19178825Sdfr * CDDL HEADER END 20178825Sdfr */ 21178825Sdfr 22178825Sdfr/* 23178825Sdfr * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24178825Sdfr * Use is subject to license terms. 25178825Sdfr */ 26178825Sdfr 27178825Sdfr/* 28178825Sdfr * Purpose: Driver for the VIA8233/8235 AC97 audio controller 29178825Sdfr */ 30178825Sdfr/* 31178825Sdfr * This file is part of Open Sound System 32178825Sdfr * 33233294Sstas * Copyright (C) 4Front Technologies 1996-2008. 34233294Sstas * 35178825Sdfr * This software is released under CDDL 1.0 source license. 36178825Sdfr * See the COPYING file included in the main directory of this source 37178825Sdfr * distribution for the license terms and conditions. 38178825Sdfr */ 39178825Sdfr 40178825Sdfr#include <sys/types.h> 41178825Sdfr#include <sys/modctl.h> 42178825Sdfr#include <sys/kmem.h> 43178825Sdfr#include <sys/conf.h> 4472445Sassar#include <sys/ddi.h> 45233294Sstas#include <sys/sunddi.h> 46233294Sstas#include <sys/pci.h> 47233294Sstas#include <sys/note.h> 48233294Sstas#include <sys/audio/audio_driver.h> 49233294Sstas#include <sys/audio/ac97.h> 50233294Sstas 51233294Sstas#include "audiovia823x.h" 52233294Sstas 53233294Sstasstatic struct ddi_device_acc_attr dev_attr = { 54233294Sstas DDI_DEVICE_ATTR_V0, 55233294Sstas DDI_STRUCTURE_LE_ACC, 5672445Sassar DDI_STRICTORDER_ACC 5772445Sassar}; 5872445Sassar 5972445Sassarstatic struct ddi_device_acc_attr buf_attr = { 60178825Sdfr DDI_DEVICE_ATTR_V0, 6172445Sassar DDI_NEVERSWAP_ACC, 6272445Sassar DDI_STRICTORDER_ACC 6372445Sassar}; 64233294Sstas 6572445Sassarstatic ddi_dma_attr_t dma_attr_sgd = { 66233294Sstas DMA_ATTR_V0, /* version number */ 67233294Sstas 0x00000000, /* low DMA address range */ 68233294Sstas 0xffffffff, /* high DMA address range */ 6972445Sassar 0x0000ffff, /* DMA counter register */ 7072445Sassar 8, /* DMA address alignment */ 71233294Sstas 0x3c, /* DMA burstsizes */ 72233294Sstas 8, /* min effective DMA size */ 7372445Sassar 0xffffffff, /* max DMA xfer size */ 7472445Sassar 0x00000fff, /* segment boundary */ 7572445Sassar 1, /* s/g length */ 7672445Sassar 8, /* granularity of device */ 7772445Sassar 0 /* Bus specific DMA flags */ 7872445Sassar}; 7972445Sassar 8072445Sassarstatic ddi_dma_attr_t dma_attr_buf = { 81233294Sstas DMA_ATTR_V0, /* version number */ 8272445Sassar 0x00000000, /* low DMA address range */ 8372445Sassar 0xffffffff, /* high DMA address range */ 8472445Sassar 0x0001fffe, /* DMA counter register */ 8572445Sassar 4, /* DMA address alignment */ 8672445Sassar 0x3c, /* DMA burstsizes */ 8772445Sassar 4, /* min effective DMA size */ 8872445Sassar 0x0001ffff, /* max DMA xfer size */ 8972445Sassar 0x0001ffff, /* segment boundary */ 9072445Sassar 1, /* s/g length */ 9172445Sassar 4, /* granularity of device */ 9272445Sassar 0 /* Bus specific DMA flags */ 9372445Sassar}; 94233294Sstas 95233294Sstasstatic int auvia_attach(dev_info_t *); 96233294Sstasstatic int auvia_resume(dev_info_t *); 97233294Sstasstatic int auvia_detach(auvia_devc_t *); 98233294Sstasstatic int auvia_suspend(auvia_devc_t *); 99233294Sstas 100233294Sstasstatic int auvia_open(void *, int, unsigned *, unsigned *, caddr_t *); 101233294Sstasstatic void auvia_close(void *); 10272445Sassarstatic int auvia_start(void *); 10372445Sassarstatic void auvia_stop(void *); 10472445Sassarstatic int auvia_format(void *); 10572445Sassarstatic int auvia_channels(void *); 10672445Sassarstatic int auvia_rate(void *); 10772445Sassarstatic uint64_t auvia_count(void *); 10872445Sassarstatic void auvia_sync(void *, unsigned); 109233294Sstasstatic size_t auvia_qlen(void *); 110233294Sstas 111233294Sstasstatic uint16_t auvia_read_ac97(void *, uint8_t); 112233294Sstasstatic void auvia_write_ac97(void *, uint8_t, uint16_t); 113233294Sstasstatic int auvia_alloc_port(auvia_devc_t *, int); 114178825Sdfrstatic void auvia_start_port(auvia_portc_t *); 115233294Sstasstatic void auvia_stop_port(auvia_portc_t *); 116178825Sdfrstatic void auvia_update_port(auvia_portc_t *); 117233294Sstasstatic void auvia_reset_input(auvia_portc_t *); 118178825Sdfrstatic void auvia_reset_output(auvia_portc_t *); 119233294Sstasstatic void auvia_destroy(auvia_devc_t *); 120178825Sdfrstatic int auvia_setup_intrs(auvia_devc_t *); 121178825Sdfrstatic void auvia_hwinit(auvia_devc_t *); 122178825Sdfrstatic uint_t auvia_intr(caddr_t, caddr_t); 12372445Sassar 12472445Sassarstatic audio_engine_ops_t auvia_engine_ops = { 12572445Sassar AUDIO_ENGINE_VERSION, 126233294Sstas auvia_open, 12772445Sassar auvia_close, 128233294Sstas auvia_start, 12972445Sassar auvia_stop, 130233294Sstas auvia_count, 13172445Sassar auvia_format, 132233294Sstas auvia_channels, 133233294Sstas auvia_rate, 134233294Sstas auvia_sync, 135233294Sstas auvia_qlen 136233294Sstas}; 137233294Sstas 138233294Sstasstatic uint16_t 139233294Sstasauvia_read_ac97(void *arg, uint8_t index) 140233294Sstas{ 141233294Sstas auvia_devc_t *devc = arg; 142233294Sstas uint32_t val = 0; 143233294Sstas int i; 144233294Sstas 145233294Sstas mutex_enter(&devc->low_mutex); 146233294Sstas 14772445Sassar val = ((uint32_t)index << 16) | CODEC_RD; 14872445Sassar OUTL(devc, devc->base + REG_CODEC, val); 14972445Sassar drv_usecwait(100); 150233294Sstas 151233294Sstas /* Check AC CODEC access time out */ 152233294Sstas for (i = 0; i < CODEC_TIMEOUT_COUNT; i++) { 153233294Sstas 154233294Sstas /* if send command over, break */ 155233294Sstas if (INL(devc, devc->base + REG_CODEC) & CODEC_STA_VALID) 156233294Sstas break; 157233294Sstas drv_usecwait(50); 158233294Sstas } 159233294Sstas 160233294Sstas if (i == CODEC_TIMEOUT_COUNT) { 161233294Sstas goto failed; 162233294Sstas } 163233294Sstas 164233294Sstas /* Check if Index still ours? If yes, return data, else return FAIL */ 165233294Sstas val = INL(devc, devc->base + REG_CODEC); 166233294Sstas OUTB(devc, devc->base + REG_CODEC + 3, 0x02); 16772445Sassar if (((val & CODEC_INDEX) >> 16) == index) { 16872445Sassar mutex_exit(&devc->low_mutex); 16972445Sassar return (val & CODEC_DATA); 17072445Sassar } 17172445Sassar 17272445Sassarfailed: 17372445Sassar mutex_exit(&devc->low_mutex); 174233294Sstas return (0xffff); 175233294Sstas} 176233294Sstas 177233294Sstasstatic void 178233294Sstasauvia_write_ac97(void *arg, uint8_t index, uint16_t data) 179233294Sstas{ 180233294Sstas auvia_devc_t *devc = arg; 181233294Sstas uint32_t val = 0; 182233294Sstas int i = 0; 183233294Sstas 184233294Sstas mutex_enter(&devc->low_mutex); 185233294Sstas 186233294Sstas val = ((uint32_t)index << 16) | data | CODEC_WR; 187233294Sstas OUTL(devc, devc->base + REG_CODEC, val); 188233294Sstas drv_usecwait(100); 189233294Sstas 190233294Sstas /* Check AC CODEC access time out */ 191233294Sstas for (i = 0; i < CODEC_TIMEOUT_COUNT; i++) { 192233294Sstas /* if send command over, break */ 193233294Sstas if (!(INL(devc, devc->base + REG_CODEC) & CODEC_IN_CMD)) 194233294Sstas break; 195233294Sstas drv_usecwait(50); 196233294Sstas } 197233294Sstas 198233294Sstas mutex_exit(&devc->low_mutex); 199233294Sstas} 200233294Sstas 201233294Sstasstatic uint_t 202233294Sstasauvia_intr(caddr_t argp, caddr_t nocare) 203233294Sstas{ 204233294Sstas auvia_devc_t *devc = (void *)argp; 205233294Sstas auvia_portc_t *portc; 206233294Sstas uint32_t gstat; 207233294Sstas uint8_t status; 208233294Sstas unsigned intrs = 0; 209233294Sstas 210233294Sstas _NOTE(ARGUNUSED(nocare)); 211233294Sstas 212233294Sstas mutex_enter(&devc->mutex); 213233294Sstas if (devc->suspended) { 214233294Sstas mutex_exit(&devc->mutex); 215233294Sstas return (DDI_INTR_UNCLAIMED); 216233294Sstas } 217233294Sstas 218233294Sstas gstat = INL(devc, devc->base + REG_GSTAT); 219233294Sstas if (gstat == 0) { 220233294Sstas mutex_exit(&devc->mutex); 221233294Sstas return (DDI_INTR_UNCLAIMED); 222233294Sstas } 223233294Sstas 224233294Sstas for (int i = 0; i < AUVIA_NUM_PORTC; i++) { 225233294Sstas 226233294Sstas portc = devc->portc[i]; 227233294Sstas 228233294Sstas status = INB(devc, portc->base + OFF_STATUS); 229233294Sstas if ((status & STATUS_INTR) == 0) { 230233294Sstas /* clear any other interrupts */ 231233294Sstas continue; 232233294Sstas } 233233294Sstas 234233294Sstas /* 235233294Sstas * NB: The old code did some goofy things to update 236233294Sstas * the last valid SGD. However, since we don't ever 237233294Sstas * reach the last valid SGD (because we loop first), I 238233294Sstas * don't believe we need to do that. It would appear 239233294Sstas * that NetBSD does the same. 240233294Sstas */ 241233294Sstas /* port interrupt */ 242233294Sstas if (portc->started) { 243233294Sstas intrs |= (1U << i); 244233294Sstas } 245233294Sstas /* XXX: do we really need to do this? */ 24672445Sassar OUTB(devc, portc->base + OFF_STATUS, status); 24772445Sassar } 24872445Sassar 24972445Sassar OUTL(devc, devc->base + REG_GSTAT, gstat); 250233294Sstas 25172445Sassar mutex_exit(&devc->mutex); 252233294Sstas if (intrs & (1U << AUVIA_PLAY_SGD_NUM)) { 253178825Sdfr audio_engine_consume(devc->portc[AUVIA_PLAY_SGD_NUM]->engine); 25472445Sassar } 255233294Sstas if (intrs & (1U << AUVIA_REC_SGD_NUM)) { 256233294Sstas audio_engine_produce(devc->portc[AUVIA_REC_SGD_NUM]->engine); 25772445Sassar } 25872445Sassar if (devc->ksp) { 259233294Sstas AUVIA_KIOP(devc)->intrs[KSTAT_INTR_HARD]++; 260233294Sstas } 261233294Sstas 262233294Sstas return (DDI_INTR_CLAIMED); 263233294Sstas} 264233294Sstas 265233294Sstas/* 266233294Sstas * Audio routines 267233294Sstas */ 268233294Sstas 26972445Sassarint 270233294Sstasauvia_open(void *arg, int flag, 27172445Sassar unsigned *fragfrp, unsigned *nfragsp, caddr_t *bufp) 27272445Sassar{ 27372445Sassar auvia_portc_t *portc = arg; 27472445Sassar auvia_devc_t *devc = portc->devc; 27572445Sassar 27672445Sassar _NOTE(ARGUNUSED(flag)); 27772445Sassar 27872445Sassar portc->started = B_FALSE; 27972445Sassar portc->count = 0; 28072445Sassar *fragfrp = portc->fragfr; 281233294Sstas *nfragsp = AUVIA_NUM_SGD; 28272445Sassar *bufp = portc->buf_kaddr; 28372445Sassar 284233294Sstas mutex_enter(&devc->mutex); 28572445Sassar portc->reset(portc); 28672445Sassar mutex_exit(&devc->mutex); 28772445Sassar 28872445Sassar return (0); 289178825Sdfr} 290233294Sstas 291233294Sstasvoid 29272445Sassarauvia_close(void *arg) 293233294Sstas{ 29472445Sassar auvia_portc_t *portc = arg; 295233294Sstas auvia_devc_t *devc = portc->devc; 296233294Sstas 29772445Sassar mutex_enter(&devc->mutex); 29872445Sassar auvia_stop_port(portc); 29972445Sassar portc->started = B_FALSE; 30072445Sassar mutex_exit(&devc->mutex); 301233294Sstas} 302233294Sstas 303233294Sstasint 304233294Sstasauvia_start(void *arg) 305233294Sstas{ 306233294Sstas auvia_portc_t *portc = arg; 307233294Sstas auvia_devc_t *devc = portc->devc; 308233294Sstas 309233294Sstas mutex_enter(&devc->mutex); 310233294Sstas if (!portc->started) { 311233294Sstas auvia_start_port(portc); 312233294Sstas portc->started = B_TRUE; 313233294Sstas } 31472445Sassar mutex_exit(&devc->mutex); 31572445Sassar return (0); 31672445Sassar} 31772445Sassar 31872445Sassarvoid 319233294Sstasauvia_stop(void *arg) 320233294Sstas{ 32172445Sassar auvia_portc_t *portc = arg; 322233294Sstas auvia_devc_t *devc = portc->devc; 32372445Sassar 324233294Sstas mutex_enter(&devc->mutex); 325233294Sstas if (portc->started) { 32672445Sassar auvia_stop_port(portc); 32772445Sassar portc->started = B_FALSE; 32872445Sassar } 32972445Sassar mutex_exit(&devc->mutex); 330233294Sstas} 331233294Sstas 332233294Sstasint 333233294Sstasauvia_format(void *arg) 334233294Sstas{ 33572445Sassar _NOTE(ARGUNUSED(arg)); 336233294Sstas 337233294Sstas return (AUDIO_FORMAT_S16_LE); 338233294Sstas} 339233294Sstas 340233294Sstasint 341233294Sstasauvia_channels(void *arg) 342233294Sstas{ 343233294Sstas auvia_portc_t *portc = arg; 344233294Sstas 345233294Sstas return (portc->nchan); 34672445Sassar} 347233294Sstas 34872445Sassarint 34972445Sassarauvia_rate(void *arg) 35072445Sassar{ 351233294Sstas _NOTE(ARGUNUSED(arg)); 35272445Sassar 353233294Sstas return (48000); 35472445Sassar} 35572445Sassar 35672445Sassarvoid 357233294Sstasauvia_sync(void *arg, unsigned nframes) 358178825Sdfr{ 35972445Sassar auvia_portc_t *portc = arg; 360233294Sstas _NOTE(ARGUNUSED(nframes)); 361233294Sstas 36272445Sassar (void) ddi_dma_sync(portc->buf_dmah, 0, 0, portc->syncdir); 36372445Sassar} 36472445Sassar 365233294Sstassize_t 366233294Sstasauvia_qlen(void *arg) 367233294Sstas{ 368233294Sstas _NOTE(ARGUNUSED(arg)); 369233294Sstas return (0); 370233294Sstas} 371233294Sstas 372233294Sstasuint64_t 373233294Sstasauvia_count(void *arg) 374233294Sstas{ 37572445Sassar auvia_portc_t *portc = arg; 376233294Sstas auvia_devc_t *devc = portc->devc; 37772445Sassar uint64_t val; 37872445Sassar 37972445Sassar mutex_enter(&devc->mutex); 38072445Sassar auvia_update_port(portc); 38172445Sassar /* 382233294Sstas * The residual is in bytes. We have to convert to frames, 38372445Sassar * and then subtract it from the fragment size to get the 38472445Sassar * number of frames processed. It is somewhat unfortunate thta 385233294Sstas * this (the division) has to happen under the lock. If we 38672445Sassar * restricted ourself to stereo out, this would be a simple 38772445Sassar * shift. 38872445Sassar */ 38972445Sassar val = portc->count + 390233294Sstas (portc->fragfr - (portc->resid / (portc->nchan * 2))); 391178825Sdfr mutex_exit(&devc->mutex); 39272445Sassar 393233294Sstas return (val); 394233294Sstas} 39572445Sassar 396233294Sstas 397233294Sstas/* private implementation bits */ 398233294Sstas 399233294Sstasvoid 400233294Sstasauvia_start_port(auvia_portc_t *portc) 401233294Sstas{ 402233294Sstas auvia_devc_t *devc = portc->devc; 403233294Sstas 40472445Sassar ASSERT(mutex_owned(&devc->mutex)); 40572445Sassar 40672445Sassar if (devc->suspended) 407233294Sstas return; 408178825Sdfr 40972445Sassar /* 410233294Sstas * Start with autoinit and SGD flag 411233294Sstas * interrupts enabled. 41272445Sassar */ 413233294Sstas OUTB(devc, portc->base + OFF_CTRL, 414233294Sstas CTRL_START | CTRL_AUTOSTART | CTRL_FLAG); 415233294Sstas} 416233294Sstas 417233294Sstasvoid 418233294Sstasauvia_stop_port(auvia_portc_t *portc) 419233294Sstas{ 420233294Sstas auvia_devc_t *devc = portc->devc; 42172445Sassar 422233294Sstas if (devc->suspended) 423 return; 424 425 OUTB(devc, portc->base + OFF_CTRL, CTRL_TERMINATE); 426} 427 428void 429auvia_update_port(auvia_portc_t *portc) 430{ 431 auvia_devc_t *devc = portc->devc; 432 uint32_t frag; 433 uint32_t n; 434 435 ASSERT(mutex_owned(&devc->mutex)); 436 if (devc->suspended) { 437 portc->cur_frag = 0; 438 portc->resid = portc->fragsz; 439 n = 0; 440 } else { 441 frag = INL(devc, portc->base + OFF_COUNT); 442 portc->resid = (frag & 0xffffff); 443 frag >>= 24; 444 frag &= 0xff; 445 446 if (frag >= portc->cur_frag) { 447 n = frag - portc->cur_frag; 448 } else { 449 n = frag + AUVIA_NUM_SGD - portc->cur_frag; 450 } 451 portc->count += (n * portc->fragfr); 452 portc->cur_frag = frag; 453 } 454} 455 456void 457auvia_reset_output(auvia_portc_t *portc) 458{ 459 auvia_devc_t *devc = portc->devc; 460 uint32_t cmap; 461 462 portc->cur_frag = 0; 463 portc->resid = portc->fragsz; 464 465 if (devc->suspended) 466 return; 467 468 OUTB(devc, portc->base + OFF_CTRL, CTRL_TERMINATE); /* Stop */ 469 OUTL(devc, portc->base + OFF_DMA, portc->sgd_paddr); 470 471 OUTB(devc, portc->base + OFF_PLAYFMT, 472 PLAYFMT_16BIT | (portc->nchan << 4)); 473 474 /* Select channel assignment - not valid for 8233A */ 475 if (devc->chip_type != CHIP_8233A) { 476 /* 477 * Undocumented slot mapping table: 478 * 479 * slot 3 = 1 (left) 480 * slot 4 = 2 (right) 481 * slot 6 = 5 (center) 482 * slot 9 = 6 (lfe) 483 * slot 7 = 3 (left rear) 484 * slot 8 = 4 (right rear) 485 */ 486 switch (portc->nchan) { 487 case 1: 488 cmap = (1 << 0) | (1 << 4); 489 break; 490 case 2: 491 cmap = (1 << 0) | (2 << 4); 492 break; 493 case 4: 494 cmap = (1 << 0) | (2 << 4) | (3 << 8) | (4 << 12); 495 break; 496 case 6: 497 cmap = (1 << 0) | (2 << 4) | 498 (5 << 8) | (6 << 12) | (3 << 16) | (4 << 20); 499 break; 500 default: 501 cmap = 0; 502 break; 503 } 504 OUTL(devc, portc->base + OFF_CHANNELS, cmap | 0xFF000000U); 505 } 506} 507 508static void 509auvia_reset_input(auvia_portc_t *portc) 510{ 511 auvia_devc_t *devc = portc->devc; 512 uint32_t fmt; 513 514 portc->cur_frag = 0; 515 portc->resid = portc->fragsz; 516 517 if (devc->suspended) 518 return; 519 520 OUTB(devc, portc->base + OFF_CTRL, CTRL_TERMINATE); /* Stop */ 521 OUTL(devc, portc->base + OFF_DMA, portc->sgd_paddr); 522 523 fmt = RECFMT_STEREO | RECFMT_16BIT; 524 525 if (devc->chip_type != CHIP_8233A) { 526 fmt |= RECFMT_48K; 527 } 528 fmt |= (0xffU << 24); 529 OUTB(devc, portc->base + OFF_RECFIFO, RECFIFO_ENABLE); 530 OUTL(devc, portc->base + OFF_RECFMT, fmt); 531} 532 533int 534auvia_alloc_port(auvia_devc_t *devc, int num) 535{ 536 auvia_portc_t *portc; 537 size_t len; 538 ddi_dma_cookie_t cookie; 539 uint_t count; 540 int dir; 541 char *prop; 542 unsigned caps; 543 audio_dev_t *adev; 544 uint32_t *desc; 545 uint32_t paddr; 546 547 adev = devc->adev; 548 portc = kmem_zalloc(sizeof (*portc), KM_SLEEP); 549 devc->portc[num] = portc; 550 portc->devc = devc; 551 portc->started = B_FALSE; 552 553 switch (num) { 554 case AUVIA_REC_SGD_NUM: 555 prop = "record-interrupts"; 556 portc->base = devc->base + REG_RECBASE; 557 portc->syncdir = DDI_DMA_SYNC_FORKERNEL; 558 portc->nchan = 2; 559 portc->reset = auvia_reset_input; 560 caps = ENGINE_INPUT_CAP; 561 dir = DDI_DMA_READ; 562 break; 563 case AUVIA_PLAY_SGD_NUM: 564 prop = "play-interrupts"; 565 portc->base = devc->base + REG_PLAYBASE; 566 portc->syncdir = DDI_DMA_SYNC_FORDEV; 567 portc->nchan = 6; 568 portc->reset = auvia_reset_output; 569 caps = ENGINE_OUTPUT_CAP; 570 dir = DDI_DMA_WRITE; 571 break; 572 default: 573 return (DDI_FAILURE); 574 } 575 576 /* make sure port is shut down */ 577 OUTB(portc->devc, portc->base + OFF_CTRL, CTRL_TERMINATE); 578 579 /* figure out fragment configuration */ 580 portc->intrs = ddi_prop_get_int(DDI_DEV_T_ANY, devc->dip, 581 DDI_PROP_DONTPASS, prop, AUVIA_INTRS); 582 583 /* make sure the values are good */ 584 if (portc->intrs < AUVIA_MIN_INTRS) { 585 audio_dev_warn(adev, "%s too low, %d, reset to %d", 586 prop, portc->intrs, AUVIA_INTRS); 587 portc->intrs = AUVIA_INTRS; 588 } else if (portc->intrs > AUVIA_MAX_INTRS) { 589 audio_dev_warn(adev, "%s too high, %d, reset to %d", 590 prop, portc->intrs, AUVIA_INTRS); 591 portc->intrs = AUVIA_INTRS; 592 } 593 594 portc->fragfr = 48000 / portc->intrs; 595 portc->fragsz = portc->fragfr * portc->nchan * 2; 596 portc->buf_size = portc->fragsz * AUVIA_NUM_SGD; 597 598 /* first allocate up space for SGD list */ 599 if (ddi_dma_alloc_handle(devc->dip, &dma_attr_sgd, 600 DDI_DMA_SLEEP, NULL, &portc->sgd_dmah) != DDI_SUCCESS) { 601 audio_dev_warn(adev, "failed to allocate SGD handle"); 602 return (DDI_FAILURE); 603 } 604 605 if (ddi_dma_mem_alloc(portc->sgd_dmah, 606 AUVIA_NUM_SGD * 2 * sizeof (uint32_t), &dev_attr, 607 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &portc->sgd_kaddr, 608 &len, &portc->sgd_acch) != DDI_SUCCESS) { 609 audio_dev_warn(adev, "failed to allocate SGD memory"); 610 return (DDI_FAILURE); 611 } 612 613 if (ddi_dma_addr_bind_handle(portc->sgd_dmah, NULL, 614 portc->sgd_kaddr, len, DDI_DMA_CONSISTENT | DDI_DMA_WRITE, 615 DDI_DMA_SLEEP, NULL, &cookie, &count) != DDI_SUCCESS) { 616 audio_dev_warn(adev, "failed binding SGD DMA handle"); 617 return (DDI_FAILURE); 618 } 619 portc->sgd_paddr = cookie.dmac_address; 620 621 /* now buffers */ 622 if (ddi_dma_alloc_handle(devc->dip, &dma_attr_buf, DDI_DMA_SLEEP, NULL, 623 &portc->buf_dmah) != DDI_SUCCESS) { 624 audio_dev_warn(adev, "failed to allocate BUF handle"); 625 return (DDI_FAILURE); 626 } 627 628 if (ddi_dma_mem_alloc(portc->buf_dmah, portc->buf_size, 629 &buf_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, 630 &portc->buf_kaddr, &len, &portc->buf_acch) != DDI_SUCCESS) { 631 audio_dev_warn(adev, "failed to allocate BUF memory"); 632 return (DDI_FAILURE); 633 } 634 635 if (ddi_dma_addr_bind_handle(portc->buf_dmah, NULL, portc->buf_kaddr, 636 len, DDI_DMA_CONSISTENT | dir, DDI_DMA_SLEEP, NULL, &cookie, 637 &count) != DDI_SUCCESS) { 638 audio_dev_warn(adev, "failed binding BUF DMA handle"); 639 return (DDI_FAILURE); 640 } 641 portc->buf_paddr = cookie.dmac_address; 642 643 /* now wire descriptors up */ 644 desc = (void *)portc->sgd_kaddr; 645 paddr = portc->buf_paddr; 646 for (int i = 0; i < AUVIA_NUM_SGD; i++) { 647 uint32_t flags; 648 649 flags = AUVIA_SGD_FLAG | portc->fragsz; 650 651 if (i == (AUVIA_NUM_SGD - 1)) { 652 flags |= AUVIA_SGD_EOL; 653 } 654 ddi_put32(portc->sgd_acch, desc++, paddr); 655 ddi_put32(portc->sgd_acch, desc++, flags); 656 paddr += portc->fragsz; 657 } 658 659 ddi_dma_sync(portc->sgd_dmah, 0, 0, DDI_DMA_SYNC_FORDEV); 660 661 portc->engine = audio_engine_alloc(&auvia_engine_ops, caps); 662 if (portc->engine == NULL) { 663 audio_dev_warn(adev, "audio_engine_alloc failed"); 664 return (DDI_FAILURE); 665 } 666 667 audio_engine_set_private(portc->engine, portc); 668 audio_dev_add_engine(adev, portc->engine); 669 670 return (DDI_SUCCESS); 671} 672 673int 674auvia_setup_intrs(auvia_devc_t *devc) 675{ 676 uint_t ipri; 677 int actual; 678 int rv; 679 ddi_intr_handle_t ih[1]; 680 681 rv = ddi_intr_alloc(devc->dip, ih, DDI_INTR_TYPE_FIXED, 682 0, 1, &actual, DDI_INTR_ALLOC_STRICT); 683 if ((rv != DDI_SUCCESS) || (actual != 1)) { 684 audio_dev_warn(devc->adev, 685 "Can't alloc interrupt handle (rv %d actual %d)", 686 rv, actual); 687 return (DDI_FAILURE); 688 } 689 690 if (ddi_intr_get_pri(ih[0], &ipri) != DDI_SUCCESS) { 691 audio_dev_warn(devc->adev, "Can't get interrupt priority"); 692 (void) ddi_intr_free(ih[0]); 693 return (DDI_FAILURE); 694 } 695 696 if (ddi_intr_add_handler(ih[0], auvia_intr, devc, NULL) != 697 DDI_SUCCESS) { 698 audio_dev_warn(devc->adev, "Can't add interrupt handler"); 699 (void) ddi_intr_free(ih[0]); 700 return (DDI_FAILURE); 701 } 702 703 devc->ih = ih[0]; 704 mutex_init(&devc->mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri)); 705 mutex_init(&devc->low_mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri)); 706 return (DDI_SUCCESS); 707} 708 709void 710auvia_destroy(auvia_devc_t *devc) 711{ 712 if (devc->ih != NULL) { 713 (void) ddi_intr_disable(devc->ih); 714 (void) ddi_intr_remove_handler(devc->ih); 715 (void) ddi_intr_free(devc->ih); 716 mutex_destroy(&devc->mutex); 717 mutex_destroy(&devc->low_mutex); 718 } 719 720 if (devc->ksp) { 721 kstat_delete(devc->ksp); 722 } 723 724 for (int i = 0; i < AUVIA_NUM_PORTC; i++) { 725 auvia_portc_t *portc = devc->portc[i]; 726 if (!portc) 727 continue; 728 if (portc->engine) { 729 audio_dev_remove_engine(devc->adev, portc->engine); 730 audio_engine_free(portc->engine); 731 } 732 if (portc->sgd_paddr) { 733 (void) ddi_dma_unbind_handle(portc->sgd_dmah); 734 } 735 if (portc->sgd_acch) { 736 ddi_dma_mem_free(&portc->sgd_acch); 737 } 738 if (portc->sgd_dmah) { 739 ddi_dma_free_handle(&portc->sgd_dmah); 740 } 741 if (portc->buf_paddr) { 742 (void) ddi_dma_unbind_handle(portc->buf_dmah); 743 } 744 if (portc->buf_acch) { 745 ddi_dma_mem_free(&portc->buf_acch); 746 } 747 if (portc->buf_dmah) { 748 ddi_dma_free_handle(&portc->buf_dmah); 749 } 750 kmem_free(portc, sizeof (*portc)); 751 } 752 753 if (devc->ac97 != NULL) { 754 ac97_free(devc->ac97); 755 } 756 if (devc->adev != NULL) { 757 audio_dev_free(devc->adev); 758 } 759 if (devc->regsh != NULL) { 760 ddi_regs_map_free(&devc->regsh); 761 } 762 if (devc->pcih != NULL) { 763 pci_config_teardown(&devc->pcih); 764 } 765 kmem_free(devc, sizeof (*devc)); 766} 767 768void 769auvia_hwinit(auvia_devc_t *devc) 770{ 771 ddi_acc_handle_t pcih = devc->pcih; 772 uint32_t val; 773 774 val = pci_config_get32(pcih, AUVIA_PCICFG); 775 /* we want to disable all legacy */ 776 val &= ~AUVIA_PCICFG_LEGACY; 777 val &= ~(AUVIA_PCICFG_FMEN | AUVIA_PCICFG_SBEN); 778 779 /* enable AC'97 link and clear the reset bit */ 780 val |= (AUVIA_PCICFG_ACLINKEN | AUVIA_PCICFG_NRST); 781 /* disable SRC (we won't use it) */ 782 val &= ~AUVIA_PCICFG_SRCEN; 783 /* enable the SGD engines */ 784 val |= AUVIA_PCICFG_SGDEN; 785 786 pci_config_put32(pcih, AUVIA_PCICFG, val); 787 788 drv_usecwait(10); 789} 790 791int 792auvia_attach(dev_info_t *dip) 793{ 794 uint8_t pci_revision; 795 uint16_t pci_command, vendor, device; 796 auvia_devc_t *devc; 797 ddi_acc_handle_t pcih; 798 const char *version; 799 800 devc = kmem_zalloc(sizeof (*devc), KM_SLEEP); 801 devc->dip = dip; 802 ddi_set_driver_private(dip, devc); 803 804 if ((devc->adev = audio_dev_alloc(dip, 0)) == NULL) { 805 cmn_err(CE_WARN, "audio_dev_alloc failed"); 806 goto error; 807 } 808 809 if (pci_config_setup(dip, &pcih) != DDI_SUCCESS) { 810 audio_dev_warn(devc->adev, "pci_config_setup failed"); 811 goto error; 812 } 813 devc->pcih = pcih; 814 815 vendor = pci_config_get16(pcih, PCI_CONF_VENID); 816 device = pci_config_get16(pcih, PCI_CONF_DEVID); 817 if ((vendor != VIA_VENDOR_ID) || (device != VIA_8233_ID && 818 device != VIA_8233A_ID)) { 819 audio_dev_warn(devc->adev, "Hardware not recognized " 820 "(vendor=%x, dev=%x)", vendor, device); 821 goto error; 822 } 823 824 devc->chip_type = CHIP_8233; 825 devc->chip_name = "VIA VT8233"; 826 version = "8233"; 827 828 pci_revision = pci_config_get8(pcih, PCI_CONF_REVID); 829 830 if (pci_revision == 0x50) { 831 devc->chip_name = "VIA VT8235"; 832 version = "8235"; 833 } 834 835 if (pci_revision == 0x60) { 836 devc->chip_name = "VIA VT8237"; 837 version = "8237"; 838 } 839 840 if ((device == VIA_8233A_ID) || 841 (device == VIA_8233_ID && pci_revision == 0x40)) { 842 devc->chip_type = CHIP_8233A; 843 devc->chip_name = "VIA VT8233A"; 844 version = "8233A"; 845 } 846 audio_dev_set_description(devc->adev, devc->chip_name); 847 audio_dev_set_version(devc->adev, version); 848 849 pci_command = pci_config_get16(pcih, PCI_CONF_COMM); 850 pci_command |= PCI_COMM_ME | PCI_COMM_IO | PCI_COMM_MAE; 851 pci_config_put16(pcih, PCI_CONF_COMM, pci_command); 852 853 if ((ddi_regs_map_setup(dip, 1, &devc->base, 0, 0, &dev_attr, 854 &devc->regsh)) != DDI_SUCCESS) { 855 audio_dev_warn(devc->adev, "failed to map registers"); 856 goto error; 857 } 858 859 auvia_hwinit(devc); 860 861 if ((auvia_alloc_port(devc, AUVIA_PLAY_SGD_NUM) != DDI_SUCCESS) || 862 (auvia_alloc_port(devc, AUVIA_REC_SGD_NUM) != DDI_SUCCESS)) { 863 goto error; 864 } 865 866 if (auvia_setup_intrs(devc) != DDI_SUCCESS) { 867 goto error; 868 } 869 870 devc->ac97 = ac97_alloc(dip, auvia_read_ac97, auvia_write_ac97, devc); 871 if (devc->ac97 == NULL) { 872 audio_dev_warn(devc->adev, "failed to allocate ac97 handle"); 873 goto error; 874 } 875 876 if (ac97_init(devc->ac97, devc->adev) != DDI_SUCCESS) { 877 audio_dev_warn(devc->adev, "failed to init ac97"); 878 goto error; 879 } 880 881 /* set up kernel statistics */ 882 if ((devc->ksp = kstat_create(AUVIA_NAME, ddi_get_instance(dip), 883 AUVIA_NAME, "controller", KSTAT_TYPE_INTR, 1, 884 KSTAT_FLAG_PERSISTENT)) != NULL) { 885 kstat_install(devc->ksp); 886 } 887 888 if (audio_dev_register(devc->adev) != DDI_SUCCESS) { 889 audio_dev_warn(devc->adev, "unable to register with framework"); 890 goto error; 891 } 892 893 (void) ddi_intr_enable(devc->ih); 894 ddi_report_dev(dip); 895 896 return (DDI_SUCCESS); 897 898error: 899 auvia_destroy(devc); 900 return (DDI_FAILURE); 901} 902 903int 904auvia_resume(dev_info_t *dip) 905{ 906 auvia_devc_t *devc; 907 908 devc = ddi_get_driver_private(dip); 909 910 auvia_hwinit(devc); 911 912 /* allow ac97 operations again */ 913 ac97_resume(devc->ac97); 914 915 mutex_enter(&devc->mutex); 916 devc->suspended = B_TRUE; 917 for (int i = 0; i < AUVIA_NUM_PORTC; i++) { 918 919 auvia_portc_t *portc = devc->portc[i]; 920 921 if (portc->engine != NULL) 922 audio_engine_reset(portc->engine); 923 924 /* reset the port */ 925 portc->reset(portc); 926 927 if (portc->started) { 928 auvia_start_port(portc); 929 } else { 930 auvia_stop_port(portc); 931 } 932 } 933 mutex_exit(&devc->mutex); 934 return (DDI_SUCCESS); 935} 936 937 938int 939auvia_detach(auvia_devc_t *devc) 940{ 941 if (audio_dev_unregister(devc->adev) != DDI_SUCCESS) 942 return (DDI_FAILURE); 943 944 auvia_destroy(devc); 945 return (DDI_SUCCESS); 946} 947 948int 949auvia_suspend(auvia_devc_t *devc) 950{ 951 ac97_suspend(devc->ac97); 952 953 mutex_enter(&devc->mutex); 954 for (int i = 0; i < AUVIA_NUM_PORTC; i++) { 955 956 auvia_portc_t *portc = devc->portc[i]; 957 auvia_stop_port(portc); 958 } 959 devc->suspended = B_TRUE; 960 mutex_exit(&devc->mutex); 961 return (DDI_SUCCESS); 962} 963 964static int auvia_ddi_attach(dev_info_t *, ddi_attach_cmd_t); 965static int auvia_ddi_detach(dev_info_t *, ddi_detach_cmd_t); 966static int auvia_ddi_quiesce(dev_info_t *); 967 968static struct dev_ops auvia_dev_ops = { 969 DEVO_REV, /* rev */ 970 0, /* refcnt */ 971 NULL, /* getinfo */ 972 nulldev, /* identify */ 973 nulldev, /* probe */ 974 auvia_ddi_attach, /* attach */ 975 auvia_ddi_detach, /* detach */ 976 nodev, /* reset */ 977 NULL, /* cb_ops */ 978 NULL, /* bus_ops */ 979 NULL, /* power */ 980 auvia_ddi_quiesce, /* quiesce */ 981}; 982 983static struct modldrv auvia_modldrv = { 984 &mod_driverops, /* drv_modops */ 985 "Via 823x Audio", /* linkinfo */ 986 &auvia_dev_ops, /* dev_ops */ 987}; 988 989static struct modlinkage modlinkage = { 990 MODREV_1, 991 { &auvia_modldrv, NULL } 992}; 993 994int 995_init(void) 996{ 997 int rv; 998 999 audio_init_ops(&auvia_dev_ops, AUVIA_NAME); 1000 if ((rv = mod_install(&modlinkage)) != 0) { 1001 audio_fini_ops(&auvia_dev_ops); 1002 } 1003 return (rv); 1004} 1005 1006int 1007_fini(void) 1008{ 1009 int rv; 1010 1011 if ((rv = mod_remove(&modlinkage)) == 0) { 1012 audio_fini_ops(&auvia_dev_ops); 1013 } 1014 return (rv); 1015} 1016 1017int 1018_info(struct modinfo *modinfop) 1019{ 1020 return (mod_info(&modlinkage, modinfop)); 1021} 1022 1023int 1024auvia_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 1025{ 1026 switch (cmd) { 1027 case DDI_ATTACH: 1028 return (auvia_attach(dip)); 1029 1030 case DDI_RESUME: 1031 return (auvia_resume(dip)); 1032 1033 default: 1034 return (DDI_FAILURE); 1035 } 1036} 1037 1038int 1039auvia_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 1040{ 1041 auvia_devc_t *devc; 1042 1043 devc = ddi_get_driver_private(dip); 1044 1045 switch (cmd) { 1046 case DDI_DETACH: 1047 return (auvia_detach(devc)); 1048 1049 case DDI_SUSPEND: 1050 return (auvia_suspend(devc)); 1051 1052 default: 1053 return (DDI_FAILURE); 1054 } 1055} 1056 1057int 1058auvia_ddi_quiesce(dev_info_t *dip) 1059{ 1060 auvia_devc_t *devc; 1061 1062 devc = ddi_get_driver_private(dip); 1063 1064 for (int i = 0; i < AUVIA_NUM_PORTC; i++) { 1065 1066 auvia_portc_t *portc = devc->portc[i]; 1067 auvia_stop_port(portc); 1068 } 1069 return (DDI_SUCCESS); 1070} 1071