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.
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.
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]
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Purpose: Driver for the VIA8233/8235 AC97 audio controller
31 * This file is part of Open Sound System
33 * Copyright (C) 4Front Technologies 1996-2008.
35 * This software is released under CDDL 1.0 source license.
36 * See the COPYING file included in the main directory of this source
37 * distribution for the license terms and conditions.
40 #include <sys/types.h>
41 #include <sys/modctl.h>
45 #include <sys/sunddi.h>
48 #include <sys/audio/audio_driver.h>
49 #include <sys/audio/ac97.h>
51 #include "audiovia823x.h"
53 static struct ddi_device_acc_attr dev_attr
= {
59 static struct ddi_device_acc_attr buf_attr
= {
65 static ddi_dma_attr_t dma_attr_sgd
= {
66 DMA_ATTR_V0
, /* version number */
67 0x00000000, /* low DMA address range */
68 0xffffffff, /* high DMA address range */
69 0x0000ffff, /* DMA counter register */
70 8, /* DMA address alignment */
71 0x3c, /* DMA burstsizes */
72 8, /* min effective DMA size */
73 0xffffffff, /* max DMA xfer size */
74 0x00000fff, /* segment boundary */
76 8, /* granularity of device */
77 0 /* Bus specific DMA flags */
80 static ddi_dma_attr_t dma_attr_buf
= {
81 DMA_ATTR_V0
, /* version number */
82 0x00000000, /* low DMA address range */
83 0xffffffff, /* high DMA address range */
84 0x0001fffe, /* DMA counter register */
85 4, /* DMA address alignment */
86 0x3c, /* DMA burstsizes */
87 4, /* min effective DMA size */
88 0x0001ffff, /* max DMA xfer size */
89 0x0001ffff, /* segment boundary */
91 4, /* granularity of device */
92 0 /* Bus specific DMA flags */
95 static int auvia_attach(dev_info_t
*);
96 static int auvia_resume(dev_info_t
*);
97 static int auvia_detach(auvia_devc_t
*);
98 static int auvia_suspend(auvia_devc_t
*);
100 static int auvia_open(void *, int, unsigned *, caddr_t
*);
101 static void auvia_close(void *);
102 static int auvia_start(void *);
103 static void auvia_stop(void *);
104 static int auvia_format(void *);
105 static int auvia_channels(void *);
106 static int auvia_rate(void *);
107 static uint64_t auvia_count(void *);
108 static void auvia_sync(void *, unsigned);
110 static uint16_t auvia_read_ac97(void *, uint8_t);
111 static void auvia_write_ac97(void *, uint8_t, uint16_t);
112 static int auvia_alloc_port(auvia_devc_t
*, int);
113 static void auvia_reset_input(auvia_portc_t
*);
114 static void auvia_reset_output(auvia_portc_t
*);
115 static void auvia_destroy(auvia_devc_t
*);
116 static void auvia_hwinit(auvia_devc_t
*);
118 static audio_engine_ops_t auvia_engine_ops
= {
119 AUDIO_ENGINE_VERSION
,
135 auvia_read_ac97(void *arg
, uint8_t index
)
137 auvia_devc_t
*devc
= arg
;
141 val
= ((uint32_t)index
<< 16) | CODEC_RD
;
142 OUTL(devc
, devc
->base
+ REG_CODEC
, val
);
145 /* Check AC CODEC access time out */
146 for (i
= 0; i
< CODEC_TIMEOUT_COUNT
; i
++) {
148 /* if send command over, break */
149 if (INL(devc
, devc
->base
+ REG_CODEC
) & CODEC_STA_VALID
)
154 if (i
== CODEC_TIMEOUT_COUNT
) {
158 /* Check if Index still ours? If yes, return data, else return FAIL */
159 val
= INL(devc
, devc
->base
+ REG_CODEC
);
160 OUTB(devc
, devc
->base
+ REG_CODEC
+ 3, 0x02);
161 if (((val
& CODEC_INDEX
) >> 16) == index
) {
162 return (val
& CODEC_DATA
);
170 auvia_write_ac97(void *arg
, uint8_t index
, uint16_t data
)
172 auvia_devc_t
*devc
= arg
;
176 val
= ((uint32_t)index
<< 16) | data
| CODEC_WR
;
177 OUTL(devc
, devc
->base
+ REG_CODEC
, val
);
180 /* Check AC CODEC access time out */
181 for (i
= 0; i
< CODEC_TIMEOUT_COUNT
; i
++) {
182 /* if send command over, break */
183 if (!(INL(devc
, devc
->base
+ REG_CODEC
) & CODEC_IN_CMD
))
195 auvia_open(void *arg
, int flag
, unsigned *nframesp
, caddr_t
*bufp
)
197 auvia_portc_t
*portc
= arg
;
199 _NOTE(ARGUNUSED(flag
));
202 *nframesp
= portc
->nframes
;
203 *bufp
= portc
->buf_kaddr
;
209 auvia_close(void *arg
)
211 _NOTE(ARGUNUSED(arg
));
215 auvia_start(void *arg
)
217 auvia_portc_t
*portc
= arg
;
218 auvia_devc_t
*devc
= portc
->devc
;
221 OUTB(devc
, portc
->base
+ OFF_CTRL
, CTRL_START
| CTRL_AUTOSTART
);
226 auvia_stop(void *arg
)
228 auvia_portc_t
*portc
= arg
;
229 auvia_devc_t
*devc
= portc
->devc
;
231 OUTB(devc
, portc
->base
+ OFF_CTRL
, CTRL_TERMINATE
);
235 auvia_format(void *arg
)
237 _NOTE(ARGUNUSED(arg
));
239 return (AUDIO_FORMAT_S16_LE
);
243 auvia_channels(void *arg
)
245 auvia_portc_t
*portc
= arg
;
247 return (portc
->nchan
);
251 auvia_rate(void *arg
)
253 _NOTE(ARGUNUSED(arg
));
259 auvia_sync(void *arg
, unsigned nframes
)
261 auvia_portc_t
*portc
= arg
;
262 _NOTE(ARGUNUSED(nframes
));
264 (void) ddi_dma_sync(portc
->buf_dmah
, 0, 0, portc
->syncdir
);
268 auvia_count(void *arg
)
270 auvia_portc_t
*portc
= arg
;
271 auvia_devc_t
*devc
= portc
->devc
;
275 pos
= INL(devc
, portc
->base
+ OFF_COUNT
);
277 pos
/= (sizeof (int16_t) * portc
->nchan
);
279 if (pos
>= portc
->pos
) {
280 n
= portc
->nframes
- (pos
- portc
->pos
);
282 n
= portc
->pos
- pos
;
287 return (portc
->count
);
291 /* private implementation bits */
294 auvia_reset_output(auvia_portc_t
*portc
)
296 auvia_devc_t
*devc
= portc
->devc
;
301 OUTB(devc
, portc
->base
+ OFF_CTRL
, CTRL_TERMINATE
); /* Stop */
302 OUTL(devc
, portc
->base
+ OFF_DMA
, portc
->sgd_paddr
);
304 OUTB(devc
, portc
->base
+ OFF_PLAYFMT
,
305 PLAYFMT_16BIT
| (portc
->nchan
<< 4));
307 /* Select channel assignment - not valid for 8233A */
308 if (devc
->chip_type
!= CHIP_8233A
) {
310 * Undocumented slot mapping table:
314 * slot 6 = 5 (center)
316 * slot 7 = 3 (left rear)
317 * slot 8 = 4 (right rear)
319 switch (portc
->nchan
) {
321 cmap
= (1 << 0) | (1 << 4);
324 cmap
= (1 << 0) | (2 << 4);
327 cmap
= (1 << 0) | (2 << 4) | (3 << 8) | (4 << 12);
330 cmap
= (1 << 0) | (2 << 4) |
331 (5 << 8) | (6 << 12) | (3 << 16) | (4 << 20);
337 OUTL(devc
, portc
->base
+ OFF_CHANNELS
, cmap
| 0xFF000000U
);
342 auvia_reset_input(auvia_portc_t
*portc
)
344 auvia_devc_t
*devc
= portc
->devc
;
349 OUTB(devc
, portc
->base
+ OFF_CTRL
, CTRL_TERMINATE
); /* Stop */
350 OUTL(devc
, portc
->base
+ OFF_DMA
, portc
->sgd_paddr
);
352 fmt
= RECFMT_STEREO
| RECFMT_16BIT
;
354 if (devc
->chip_type
!= CHIP_8233A
) {
357 fmt
|= (0xffU
<< 24);
358 OUTB(devc
, portc
->base
+ OFF_RECFIFO
, RECFIFO_ENABLE
);
359 OUTL(devc
, portc
->base
+ OFF_RECFMT
, fmt
);
363 auvia_alloc_port(auvia_devc_t
*devc
, int num
)
365 auvia_portc_t
*portc
;
367 ddi_dma_cookie_t cookie
;
375 portc
= kmem_zalloc(sizeof (*portc
), KM_SLEEP
);
376 devc
->portc
[num
] = portc
;
380 case AUVIA_REC_SGD_NUM
:
381 portc
->base
= devc
->base
+ REG_RECBASE
;
382 portc
->syncdir
= DDI_DMA_SYNC_FORKERNEL
;
384 portc
->reset
= auvia_reset_input
;
385 caps
= ENGINE_INPUT_CAP
;
388 case AUVIA_PLAY_SGD_NUM
:
389 portc
->base
= devc
->base
+ REG_PLAYBASE
;
390 portc
->syncdir
= DDI_DMA_SYNC_FORDEV
;
392 portc
->reset
= auvia_reset_output
;
393 caps
= ENGINE_OUTPUT_CAP
;
397 return (DDI_FAILURE
);
400 /* make sure port is shut down */
401 OUTB(portc
->devc
, portc
->base
+ OFF_CTRL
, CTRL_TERMINATE
);
403 portc
->nframes
= 4096;
404 portc
->buf_size
= portc
->nframes
* portc
->nchan
* sizeof (int16_t);
406 /* first allocate up space for SGD list */
407 if (ddi_dma_alloc_handle(devc
->dip
, &dma_attr_sgd
,
408 DDI_DMA_SLEEP
, NULL
, &portc
->sgd_dmah
) != DDI_SUCCESS
) {
409 audio_dev_warn(adev
, "failed to allocate SGD handle");
410 return (DDI_FAILURE
);
413 if (ddi_dma_mem_alloc(portc
->sgd_dmah
, 2 * sizeof (uint32_t), &dev_attr
,
414 DDI_DMA_CONSISTENT
, DDI_DMA_SLEEP
, NULL
, &portc
->sgd_kaddr
,
415 &len
, &portc
->sgd_acch
) != DDI_SUCCESS
) {
416 audio_dev_warn(adev
, "failed to allocate SGD memory");
417 return (DDI_FAILURE
);
420 if (ddi_dma_addr_bind_handle(portc
->sgd_dmah
, NULL
,
421 portc
->sgd_kaddr
, len
, DDI_DMA_CONSISTENT
| DDI_DMA_WRITE
,
422 DDI_DMA_SLEEP
, NULL
, &cookie
, &count
) != DDI_SUCCESS
) {
423 audio_dev_warn(adev
, "failed binding SGD DMA handle");
424 return (DDI_FAILURE
);
426 portc
->sgd_paddr
= cookie
.dmac_address
;
429 if (ddi_dma_alloc_handle(devc
->dip
, &dma_attr_buf
, DDI_DMA_SLEEP
, NULL
,
430 &portc
->buf_dmah
) != DDI_SUCCESS
) {
431 audio_dev_warn(adev
, "failed to allocate BUF handle");
432 return (DDI_FAILURE
);
435 if (ddi_dma_mem_alloc(portc
->buf_dmah
, portc
->buf_size
,
436 &buf_attr
, DDI_DMA_CONSISTENT
, DDI_DMA_SLEEP
, NULL
,
437 &portc
->buf_kaddr
, &len
, &portc
->buf_acch
) != DDI_SUCCESS
) {
438 audio_dev_warn(adev
, "failed to allocate BUF memory");
439 return (DDI_FAILURE
);
442 if (ddi_dma_addr_bind_handle(portc
->buf_dmah
, NULL
, portc
->buf_kaddr
,
443 len
, DDI_DMA_CONSISTENT
| dir
, DDI_DMA_SLEEP
, NULL
, &cookie
,
444 &count
) != DDI_SUCCESS
) {
445 audio_dev_warn(adev
, "failed binding BUF DMA handle");
446 return (DDI_FAILURE
);
448 portc
->buf_paddr
= cookie
.dmac_address
;
450 /* now wire up descriptor -- just one */
451 desc
= (void *)portc
->sgd_kaddr
;
453 ddi_put32(portc
->sgd_acch
, desc
++, portc
->buf_paddr
);
454 ddi_put32(portc
->sgd_acch
, desc
++, AUVIA_SGD_EOL
| portc
->buf_size
);
456 (void) ddi_dma_sync(portc
->sgd_dmah
, 0, 0, DDI_DMA_SYNC_FORDEV
);
458 portc
->engine
= audio_engine_alloc(&auvia_engine_ops
, caps
);
459 if (portc
->engine
== NULL
) {
460 audio_dev_warn(adev
, "audio_engine_alloc failed");
461 return (DDI_FAILURE
);
464 audio_engine_set_private(portc
->engine
, portc
);
465 audio_dev_add_engine(adev
, portc
->engine
);
467 return (DDI_SUCCESS
);
471 auvia_destroy(auvia_devc_t
*devc
)
473 for (int i
= 0; i
< AUVIA_NUM_PORTC
; i
++) {
474 auvia_portc_t
*portc
= devc
->portc
[i
];
478 audio_dev_remove_engine(devc
->adev
, portc
->engine
);
479 audio_engine_free(portc
->engine
);
481 if (portc
->sgd_paddr
) {
482 (void) ddi_dma_unbind_handle(portc
->sgd_dmah
);
484 if (portc
->sgd_acch
) {
485 ddi_dma_mem_free(&portc
->sgd_acch
);
487 if (portc
->sgd_dmah
) {
488 ddi_dma_free_handle(&portc
->sgd_dmah
);
490 if (portc
->buf_paddr
) {
491 (void) ddi_dma_unbind_handle(portc
->buf_dmah
);
493 if (portc
->buf_acch
) {
494 ddi_dma_mem_free(&portc
->buf_acch
);
496 if (portc
->buf_dmah
) {
497 ddi_dma_free_handle(&portc
->buf_dmah
);
499 kmem_free(portc
, sizeof (*portc
));
502 if (devc
->ac97
!= NULL
) {
503 ac97_free(devc
->ac97
);
505 if (devc
->adev
!= NULL
) {
506 audio_dev_free(devc
->adev
);
508 if (devc
->regsh
!= NULL
) {
509 ddi_regs_map_free(&devc
->regsh
);
511 if (devc
->pcih
!= NULL
) {
512 pci_config_teardown(&devc
->pcih
);
514 kmem_free(devc
, sizeof (*devc
));
518 auvia_hwinit(auvia_devc_t
*devc
)
520 ddi_acc_handle_t pcih
= devc
->pcih
;
523 val
= pci_config_get32(pcih
, AUVIA_PCICFG
);
524 /* we want to disable all legacy */
525 val
&= ~AUVIA_PCICFG_LEGACY
;
526 val
&= ~(AUVIA_PCICFG_FMEN
| AUVIA_PCICFG_SBEN
);
528 /* enable AC'97 link and clear the reset bit */
529 val
|= (AUVIA_PCICFG_ACLINKEN
| AUVIA_PCICFG_NRST
);
530 /* disable SRC (we won't use it) */
531 val
&= ~AUVIA_PCICFG_SRCEN
;
532 /* enable the SGD engines */
533 val
|= AUVIA_PCICFG_SGDEN
;
535 pci_config_put32(pcih
, AUVIA_PCICFG
, val
);
541 auvia_attach(dev_info_t
*dip
)
543 uint8_t pci_revision
;
544 uint16_t pci_command
, vendor
, device
;
546 ddi_acc_handle_t pcih
;
549 devc
= kmem_zalloc(sizeof (*devc
), KM_SLEEP
);
551 ddi_set_driver_private(dip
, devc
);
553 if ((devc
->adev
= audio_dev_alloc(dip
, 0)) == NULL
) {
554 cmn_err(CE_WARN
, "audio_dev_alloc failed");
558 if (pci_config_setup(dip
, &pcih
) != DDI_SUCCESS
) {
559 audio_dev_warn(devc
->adev
, "pci_config_setup failed");
564 vendor
= pci_config_get16(pcih
, PCI_CONF_VENID
);
565 device
= pci_config_get16(pcih
, PCI_CONF_DEVID
);
566 if ((vendor
!= VIA_VENDOR_ID
) || (device
!= VIA_8233_ID
&&
567 device
!= VIA_8233A_ID
)) {
568 audio_dev_warn(devc
->adev
, "Hardware not recognized "
569 "(vendor=%x, dev=%x)", vendor
, device
);
573 devc
->chip_type
= CHIP_8233
;
574 devc
->chip_name
= "VIA VT8233";
577 pci_revision
= pci_config_get8(pcih
, PCI_CONF_REVID
);
579 if (pci_revision
== 0x50) {
580 devc
->chip_name
= "VIA VT8235";
584 if (pci_revision
== 0x60) {
585 devc
->chip_name
= "VIA VT8237";
589 if ((device
== VIA_8233A_ID
) ||
590 (device
== VIA_8233_ID
&& pci_revision
== 0x40)) {
591 devc
->chip_type
= CHIP_8233A
;
592 devc
->chip_name
= "VIA VT8233A";
595 audio_dev_set_description(devc
->adev
, devc
->chip_name
);
596 audio_dev_set_version(devc
->adev
, version
);
598 pci_command
= pci_config_get16(pcih
, PCI_CONF_COMM
);
599 pci_command
|= PCI_COMM_ME
| PCI_COMM_IO
| PCI_COMM_MAE
;
600 pci_config_put16(pcih
, PCI_CONF_COMM
, pci_command
);
602 if ((ddi_regs_map_setup(dip
, 1, &devc
->base
, 0, 0, &dev_attr
,
603 &devc
->regsh
)) != DDI_SUCCESS
) {
604 audio_dev_warn(devc
->adev
, "failed to map registers");
610 if ((auvia_alloc_port(devc
, AUVIA_PLAY_SGD_NUM
) != DDI_SUCCESS
) ||
611 (auvia_alloc_port(devc
, AUVIA_REC_SGD_NUM
) != DDI_SUCCESS
)) {
615 devc
->ac97
= ac97_alloc(dip
, auvia_read_ac97
, auvia_write_ac97
, devc
);
616 if (devc
->ac97
== NULL
) {
617 audio_dev_warn(devc
->adev
, "failed to allocate ac97 handle");
621 if (ac97_init(devc
->ac97
, devc
->adev
) != DDI_SUCCESS
) {
622 audio_dev_warn(devc
->adev
, "failed to init ac97");
626 if (audio_dev_register(devc
->adev
) != DDI_SUCCESS
) {
627 audio_dev_warn(devc
->adev
, "unable to register with framework");
633 return (DDI_SUCCESS
);
637 return (DDI_FAILURE
);
641 auvia_resume(dev_info_t
*dip
)
645 devc
= ddi_get_driver_private(dip
);
649 ac97_reset(devc
->ac97
);
651 audio_dev_resume(devc
->adev
);
653 return (DDI_SUCCESS
);
658 auvia_detach(auvia_devc_t
*devc
)
660 if (audio_dev_unregister(devc
->adev
) != DDI_SUCCESS
)
661 return (DDI_FAILURE
);
664 return (DDI_SUCCESS
);
668 auvia_suspend(auvia_devc_t
*devc
)
670 audio_dev_suspend(devc
->adev
);
672 return (DDI_SUCCESS
);
675 static int auvia_ddi_attach(dev_info_t
*, ddi_attach_cmd_t
);
676 static int auvia_ddi_detach(dev_info_t
*, ddi_detach_cmd_t
);
677 static int auvia_ddi_quiesce(dev_info_t
*);
679 static struct dev_ops auvia_dev_ops
= {
683 nulldev
, /* identify */
685 auvia_ddi_attach
, /* attach */
686 auvia_ddi_detach
, /* detach */
691 auvia_ddi_quiesce
, /* quiesce */
694 static struct modldrv auvia_modldrv
= {
695 &mod_driverops
, /* drv_modops */
696 "Via 823x Audio", /* linkinfo */
697 &auvia_dev_ops
, /* dev_ops */
700 static struct modlinkage modlinkage
= {
702 { &auvia_modldrv
, NULL
}
710 audio_init_ops(&auvia_dev_ops
, AUVIA_NAME
);
711 if ((rv
= mod_install(&modlinkage
)) != 0) {
712 audio_fini_ops(&auvia_dev_ops
);
722 if ((rv
= mod_remove(&modlinkage
)) == 0) {
723 audio_fini_ops(&auvia_dev_ops
);
729 _info(struct modinfo
*modinfop
)
731 return (mod_info(&modlinkage
, modinfop
));
735 auvia_ddi_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
739 return (auvia_attach(dip
));
742 return (auvia_resume(dip
));
745 return (DDI_FAILURE
);
750 auvia_ddi_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
754 devc
= ddi_get_driver_private(dip
);
758 return (auvia_detach(devc
));
761 return (auvia_suspend(devc
));
764 return (DDI_FAILURE
);
769 auvia_ddi_quiesce(dev_info_t
*dip
)
773 devc
= ddi_get_driver_private(dip
);
775 for (int i
= 0; i
< AUVIA_NUM_PORTC
; i
++) {
777 auvia_portc_t
*portc
= devc
->portc
[i
];
778 OUTB(devc
, portc
->base
+ OFF_CTRL
, CTRL_TERMINATE
);
780 return (DDI_SUCCESS
);