2 * Copyright (c) 2003 Dag-Erling Coïdan Smørgrav
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer
10 * in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * $FreeBSD: src/sys/dev/sound/pci/au88x0.c,v 1.10 2005/03/01 08:58:05 imp Exp $
29 * $DragonFly: src/sys/dev/sound/pci/au88x0.c,v 1.1 2007/01/04 21:47:02 corecode Exp $
32 #include <dev/sound/pcm/sound.h>
33 #include <dev/sound/pcm/ac97.h>
34 #include <dev/sound/pci/au88x0.h>
38 #include <bus/pci/pcireg.h>
39 #include <bus/pci/pcivar.h>
42 /***************************************************************************\
44 * SUPPORTED CHIPSETS *
46 \***************************************************************************/
48 static struct au88x0_chipset au88x0_chipsets
[] = {
50 .auc_name
= "Aureal Vortex (8820)",
51 .auc_pci_id
= 0x000112eb,
53 .auc_control
= 0x1280c,
55 .auc_irq_source
= 0x12800,
56 .auc_irq_mask
= 0x12804,
57 .auc_irq_control
= 0x12808,
58 .auc_irq_status
= 0x1199c,
60 .auc_dma_control
= 0x1060c,
62 .auc_fifo_size
= 0x20,
64 .auc_wt_fifo_base
= 0x0e800,
65 .auc_wt_fifo_ctl
= 0x0f800,
66 .auc_wt_dma_ctl
= 0x10500,
68 .auc_adb_fifo_base
= 0x0e000,
69 .auc_adb_fifo_ctl
= 0x0f840,
70 .auc_adb_dma_ctl
= 0x10580,
72 .auc_adb_route_base
= 0x10800,
73 .auc_adb_route_bits
= 7,
74 .auc_adb_codec_in
= 0x48,
75 .auc_adb_codec_out
= 0x58,
78 .auc_name
= "Aureal Vortex 2 (8830)",
79 .auc_pci_id
= 0x000212eb,
81 .auc_control
= 0x2a00c,
83 .auc_irq_source
= 0x2a000,
84 .auc_irq_mask
= 0x2a004,
85 .auc_irq_control
= 0x2a008,
86 .auc_irq_status
= 0x2919c,
88 .auc_dma_control
= 0x27ae8,
90 .auc_fifo_size
= 0x40,
92 .auc_wt_fifo_base
= 0x10000,
93 .auc_wt_fifo_ctl
= 0x16000,
94 .auc_wt_dma_ctl
= 0x27900,
96 .auc_adb_fifo_base
= 0x14000,
97 .auc_adb_fifo_ctl
= 0x16100,
98 .auc_adb_dma_ctl
= 0x27a00,
100 .auc_adb_route_base
= 0x28000,
101 .auc_adb_route_bits
= 8,
102 .auc_adb_codec_in
= 0x70,
103 .auc_adb_codec_out
= 0x88,
106 .auc_name
= "Aureal Vortex Advantage (8810)",
107 .auc_pci_id
= 0x000312eb,
109 .auc_control
= 0x2a00c,
111 .auc_irq_source
= 0x2a000,
112 .auc_irq_mask
= 0x2a004,
113 .auc_irq_control
= 0x2a008,
114 .auc_irq_status
= 0x2919c,
116 .auc_dma_control
= 0x27ae8,
118 .auc_fifo_size
= 0x20,
120 .auc_wt_fifo_base
= 0x10000,
121 .auc_wt_fifo_ctl
= 0x16000,
122 .auc_wt_dma_ctl
= 0x27fd8,
124 .auc_adb_fifo_base
= 0x14000,
125 .auc_adb_fifo_ctl
= 0x16100,
126 .auc_adb_dma_ctl
= 0x27180,
128 .auc_adb_route_base
= 0x28000,
129 .auc_adb_route_bits
= 8,
130 .auc_adb_codec_in
= 0x70,
131 .auc_adb_codec_out
= 0x88,
139 /***************************************************************************\
141 * FORMATS AND CAPABILITIES *
143 \***************************************************************************/
145 static u_int32_t au88x0_formats
[] = {
147 AFMT_STEREO
| AFMT_U8
,
149 AFMT_STEREO
| AFMT_S16_LE
,
153 static struct pcmchan_caps au88x0_capabilities
= {
154 4000, /* minimum sample rate */
155 48000, /* maximum sample rate */
156 au88x0_formats
, /* supported formats */
157 0 /* no particular capabilities */
161 /***************************************************************************\
165 \***************************************************************************/
168 * Read from the au88x0 register space
171 /* all our writes are 32-bit */
172 #define au88x0_read(aui, reg, n) \
173 bus_space_read_4((aui)->aui_spct, (aui)->aui_spch, (reg))
174 #define au88x0_write(aui, reg, data, n) \
175 bus_space_write_4((aui)->aui_spct, (aui)->aui_spch, (reg), (data))
178 au88x0_read(struct au88x0_info
*aui
, int reg
, int size
)
184 data
= bus_space_read_1(aui
->aui_spct
, aui
->aui_spch
, reg
);
187 data
= bus_space_read_2(aui
->aui_spct
, aui
->aui_spch
, reg
);
190 data
= bus_space_read_4(aui
->aui_spct
, aui
->aui_spch
, reg
);
193 panic("unsupported read size %d", size
);
199 * Write to the au88x0 register space
202 au88x0_write(struct au88x0_info
*aui
, int reg
, uint32_t data
, int size
)
207 bus_space_write_1(aui
->aui_spct
, aui
->aui_spch
, reg
, data
);
210 bus_space_write_2(aui
->aui_spct
, aui
->aui_spch
, reg
, data
);
213 bus_space_write_4(aui
->aui_spct
, aui
->aui_spch
, reg
, data
);
216 panic("unsupported write size %d", size
);
222 * Reset and initialize the codec
225 au88x0_codec_init(struct au88x0_info
*aui
)
230 /* wave that chicken */
231 au88x0_write(aui
, AU88X0_CODEC_CONTROL
, 0x8068, 4);
232 DELAY(AU88X0_SETTLE_DELAY
);
233 au88x0_write(aui
, AU88X0_CODEC_CONTROL
, 0x00e8, 4);
235 for (i
= 0; i
< 32; ++i
) {
236 au88x0_write(aui
, AU88X0_CODEC_CHANNEL
+ i
* 4, 0, 4);
237 DELAY(AU88X0_SETTLE_DELAY
);
239 au88x0_write(aui
, AU88X0_CODEC_CONTROL
, 0x00e8, 4);
240 DELAY(AU88X0_SETTLE_DELAY
);
242 /* enable both codec channels */
243 data
= au88x0_read(aui
, AU88X0_CODEC_ENABLE
, 4);
244 data
|= (1 << (8 + 0)) | (1 << (8 + 1));
245 au88x0_write(aui
, AU88X0_CODEC_ENABLE
, data
, 4);
246 DELAY(AU88X0_SETTLE_DELAY
);
250 * Wait for the codec to get ready to accept a register write
251 * Should be called at spltty
254 au88x0_codec_wait(struct au88x0_info
*aui
)
259 for (i
= 0; i
< AU88X0_RETRY_COUNT
; ++i
) {
260 data
= au88x0_read(aui
, AU88X0_CODEC_CONTROL
, 4);
261 if (data
& AU88X0_CDCTL_WROK
)
263 DELAY(AU88X0_SETTLE_DELAY
);
265 device_printf(aui
->aui_dev
, "timeout while waiting for codec\n");
270 * Read from the ac97 codec
273 au88x0_codec_read(kobj_t obj
, void *arg
, int reg
)
275 struct au88x0_info
*aui
= arg
;
280 au88x0_codec_wait(aui
);
281 au88x0_write(aui
, AU88X0_CODEC_IO
, AU88X0_CDIO_READ(reg
), 4);
283 data
= au88x0_read(aui
, AU88X0_CODEC_IO
, 4);
285 data
&= AU88X0_CDIO_DATA_MASK
;
286 data
>>= AU88X0_CDIO_DATA_SHIFT
;
291 * Write to the ac97 codec
294 au88x0_codec_write(kobj_t obj
, void *arg
, int reg
, uint32_t data
)
296 struct au88x0_info
*aui
= arg
;
300 au88x0_codec_wait(aui
);
301 au88x0_write(aui
, AU88X0_CODEC_IO
, AU88X0_CDIO_WRITE(reg
, data
), 4);
307 * Codec interface glue
309 static kobj_method_t au88x0_ac97_methods
[] = {
310 KOBJMETHOD(ac97_read
, au88x0_codec_read
),
311 KOBJMETHOD(ac97_write
, au88x0_codec_write
),
314 AC97_DECLARE(au88x0_ac97
);
316 #define au88x0_channel(aui, dir) \
317 &(aui)->aui_chan[((dir) == PCMDIR_PLAY) ? 0 : 1]
320 /***************************************************************************\
322 * CHANNEL INTERFACE *
324 \***************************************************************************/
327 * Initialize a PCM channel
330 au88x0_chan_init(kobj_t obj
, void *arg
,
331 struct snd_dbuf
*buf
, struct pcm_channel
*chan
, int dir
)
333 struct au88x0_info
*aui
= arg
;
334 struct au88x0_chan_info
*auci
= au88x0_channel(aui
, dir
);
336 if (sndbuf_alloc(buf
, aui
->aui_dmat
, aui
->aui_bufsize
) != 0)
338 auci
->auci_aui
= aui
;
339 auci
->auci_pcmchan
= chan
;
340 auci
->auci_buf
= buf
;
341 auci
->auci_dir
= dir
;
346 * Set the data format for a PCM channel
349 au88x0_chan_setformat(kobj_t obj
, void *arg
, u_int32_t format
)
357 * Set the sample rate for a PCM channel
360 au88x0_chan_setspeed(kobj_t obj
, void *arg
, u_int32_t speed
)
368 * Set the block size for a PCM channel
371 au88x0_chan_setblocksize(kobj_t obj
, void *arg
, u_int32_t blocksize
)
379 * Initiate a data transfer
382 au88x0_chan_trigger(kobj_t obj
, void *arg
, int trigger
)
384 struct au88x0_chan_info
*auci
= arg
;
401 au88x0_chan_getptr(kobj_t obj
, void *arg
)
409 * Return the capabilities of a PCM channel
411 static struct pcmchan_caps
*
412 au88x0_chan_getcaps(kobj_t obj
, void *arg
)
415 return (&au88x0_capabilities
);
419 * Channel interface glue
421 static kobj_method_t au88x0_chan_methods
[] = {
422 KOBJMETHOD(channel_init
, au88x0_chan_init
),
423 KOBJMETHOD(channel_setformat
, au88x0_chan_setformat
),
424 KOBJMETHOD(channel_setspeed
, au88x0_chan_setspeed
),
425 KOBJMETHOD(channel_setblocksize
, au88x0_chan_setblocksize
),
426 KOBJMETHOD(channel_trigger
, au88x0_chan_trigger
),
427 KOBJMETHOD(channel_getptr
, au88x0_chan_getptr
),
428 KOBJMETHOD(channel_getcaps
, au88x0_chan_getcaps
),
431 CHANNEL_DECLARE(au88x0_chan
);
434 /***************************************************************************\
436 * INTERRUPT HANDLER *
438 \***************************************************************************/
441 au88x0_intr(void *arg
)
443 struct au88x0_info
*aui
= arg
;
444 struct au88x0_chipset
*auc
= aui
->aui_chipset
;
447 pending
= au88x0_read(aui
, auc
->auc_irq_control
, 4);
448 if ((pending
& AU88X0_IRQ_PENDING_BIT
) == 0)
450 source
= au88x0_read(aui
, auc
->auc_irq_source
, 4);
451 if (source
& AU88X0_IRQ_FATAL_ERR
)
452 device_printf(aui
->aui_dev
,
453 "fatal error interrupt received\n");
454 if (source
& AU88X0_IRQ_PARITY_ERR
)
455 device_printf(aui
->aui_dev
,
456 "parity error interrupt received\n");
457 /* XXX handle the others... */
459 /* acknowledge the interrupts we just handled */
460 au88x0_write(aui
, auc
->auc_irq_source
, source
, 4);
461 au88x0_read(aui
, auc
->auc_irq_source
, 4);
465 /***************************************************************************\
469 \***************************************************************************/
472 * Reset and initialize the ADB and WT FIFOs
474 * - need to find out what the magic values 0x42000 and 0x2000 mean.
477 au88x0_fifo_init(struct au88x0_info
*aui
)
479 struct au88x0_chipset
*auc
= aui
->aui_chipset
;
482 /* reset, then clear the ADB FIFOs */
483 for (i
= 0; i
< auc
->auc_adb_fifos
; ++i
)
484 au88x0_write(aui
, auc
->auc_adb_fifo_ctl
+ i
* 4, 0x42000, 4);
485 for (i
= 0; i
< auc
->auc_adb_fifos
* auc
->auc_fifo_size
; ++i
)
486 au88x0_write(aui
, auc
->auc_adb_fifo_base
+ i
* 4, 0, 4);
488 /* reset, then clear the WT FIFOs */
489 for (i
= 0; i
< auc
->auc_wt_fifos
; ++i
)
490 au88x0_write(aui
, auc
->auc_wt_fifo_ctl
+ i
* 4, 0x42000, 4);
491 for (i
= 0; i
< auc
->auc_wt_fifos
* auc
->auc_fifo_size
; ++i
)
492 au88x0_write(aui
, auc
->auc_wt_fifo_base
+ i
* 4, 0, 4);
496 * Hardware initialization
499 au88x0_init(struct au88x0_info
*aui
)
501 struct au88x0_chipset
*auc
= aui
->aui_chipset
;
504 au88x0_write(aui
, auc
->auc_control
, 0xffffffff, 4);
507 /* clear all interrupts */
508 au88x0_write(aui
, auc
->auc_irq_source
, 0xffffffff, 4);
509 au88x0_read(aui
, auc
->auc_irq_source
, 4);
510 au88x0_read(aui
, auc
->auc_irq_status
, 4);
512 /* initialize the codec */
513 au88x0_codec_init(aui
);
515 /* initialize the fifos */
516 au88x0_fifo_init(aui
);
518 /* initialize the DMA engine */
519 /* XXX chicken-waving! */
520 au88x0_write(aui
, auc
->auc_dma_control
, 0x1380000, 4);
524 * Construct and set status string
527 au88x0_set_status(device_t dev
)
529 char status
[SND_STATUSLEN
];
530 struct au88x0_info
*aui
;
532 aui
= pcm_getdevinfo(dev
);
533 snprintf(status
, sizeof status
, "at %s 0x%lx irq %ld %s",
534 (aui
->aui_regtype
== SYS_RES_IOPORT
)? "io" : "memory",
535 rman_get_start(aui
->aui_reg
), rman_get_start(aui
->aui_irq
),PCM_KLDSTRING(snd_au88x0
));
536 pcm_setstatus(dev
, status
);
540 /***************************************************************************\
544 \***************************************************************************/
550 au88x0_pci_probe(device_t dev
)
552 struct au88x0_chipset
*auc
;
555 pci_id
= pci_get_devid(dev
);
556 for (auc
= au88x0_chipsets
; auc
->auc_pci_id
; ++auc
) {
557 if (auc
->auc_pci_id
== pci_id
) {
558 device_set_desc(dev
, auc
->auc_name
);
559 return BUS_PROBE_DEFAULT
;
569 au88x0_pci_attach(device_t dev
)
571 struct au88x0_chipset
*auc
;
572 struct au88x0_info
*aui
= NULL
;
576 if ((aui
= kmalloc(sizeof *aui
, M_DEVBUF
, M_NOWAIT
|M_ZERO
)) == NULL
) {
577 device_printf(dev
, "failed to allocate softc\n");
582 /* Model-specific parameters */
583 aui
->aui_model
= pci_get_devid(dev
);
584 for (auc
= au88x0_chipsets
; auc
->auc_pci_id
; ++auc
)
585 if (auc
->auc_pci_id
== aui
->aui_model
)
586 aui
->aui_chipset
= auc
;
587 if (aui
->aui_chipset
== NULL
)
588 panic("%s() called for non-au88x0 device", __func__
);
590 /* enable pio, mmio, bus-mastering dma */
591 config
= pci_read_config(dev
, PCIR_COMMAND
, 2);
592 config
|= (PCIM_CMD_PORTEN
|PCIM_CMD_MEMEN
|PCIM_CMD_BUSMASTEREN
);
593 pci_write_config(dev
, PCIR_COMMAND
, config
, 2);
595 /* register mapping */
596 config
= pci_read_config(dev
, PCIR_COMMAND
, 2);
597 if (config
& PCIM_CMD_MEMEN
) {
598 /* try memory-mapped I/O */
599 aui
->aui_regid
= PCIR_BAR(0);
600 aui
->aui_regtype
= SYS_RES_MEMORY
;
601 aui
->aui_reg
= bus_alloc_resource_any(dev
, aui
->aui_regtype
,
602 &aui
->aui_regid
, RF_ACTIVE
);
604 if (aui
->aui_reg
== NULL
&& (config
& PCIM_CMD_PORTEN
)) {
605 /* fall back on port I/O */
606 aui
->aui_regid
= PCIR_BAR(0);
607 aui
->aui_regtype
= SYS_RES_IOPORT
;
608 aui
->aui_reg
= bus_alloc_resource_any(dev
, aui
->aui_regtype
,
609 &aui
->aui_regid
, RF_ACTIVE
);
611 if (aui
->aui_reg
== NULL
) {
612 /* both mmio and pio failed... */
613 device_printf(dev
, "failed to map registers\n");
616 aui
->aui_spct
= rman_get_bustag(aui
->aui_reg
);
617 aui
->aui_spch
= rman_get_bushandle(aui
->aui_reg
);
621 aui
->aui_irqtype
= SYS_RES_IRQ
;
622 aui
->aui_irq
= bus_alloc_resource_any(dev
, aui
->aui_irqtype
,
623 &aui
->aui_irqid
, RF_ACTIVE
| RF_SHAREABLE
);
624 if (aui
->aui_irq
== 0) {
625 device_printf(dev
, "failed to map IRQ\n");
629 /* install interrupt handler */
630 error
= snd_setup_intr(dev
, aui
->aui_irq
, 0, au88x0_intr
,
631 aui
, &aui
->aui_irqh
);
633 device_printf(dev
, "failed to install interrupt handler\n");
638 aui
->aui_bufsize
= pcm_getbuffersize(dev
, AU88X0_BUFSIZE_MIN
,
639 AU88X0_BUFSIZE_DFLT
, AU88X0_BUFSIZE_MAX
);
640 error
= bus_dma_tag_create(NULL
,
641 2, 0, /* 16-bit alignment, no boundary */
642 BUS_SPACE_MAXADDR_32BIT
, BUS_SPACE_MAXADDR
, /* restrict to 4GB */
643 NULL
, NULL
, /* no filter */
644 aui
->aui_bufsize
, 1, aui
->aui_bufsize
,
645 0, busdma_lock_mutex
, &Giant
, &aui
->aui_dmat
);
647 device_printf(dev
, "failed to create DMA tag\n");
651 /* initialize the hardware */
654 /* initialize the ac97 codec and mixer */
655 if ((aui
->aui_ac97i
= AC97_CREATE(dev
, aui
, au88x0_ac97
)) == NULL
) {
656 device_printf(dev
, "failed to initialize ac97 codec\n");
659 if (mixer_init(dev
, ac97_getmixerclass(), aui
->aui_ac97i
) != 0) {
660 device_printf(dev
, "failed to initialize ac97 mixer\n");
664 /* register with the pcm driver */
665 if (pcm_register(dev
, aui
, 0, 0))
667 pcm_addchan(dev
, PCMDIR_PLAY
, &au88x0_chan_class
, aui
);
669 pcm_addchan(dev
, PCMDIR_REC
, &au88x0_chan_class
, aui
);
671 au88x0_set_status(dev
);
675 if (aui
->aui_ac97i
!= NULL
)
676 ac97_destroy(aui
->aui_ac97i
);
678 bus_dma_tag_destroy(aui
->aui_dmat
);
679 if (aui
->aui_irqh
!= NULL
)
680 bus_teardown_intr(dev
, aui
->aui_irq
, aui
->aui_irqh
);
682 bus_release_resource(dev
, aui
->aui_irqtype
,
683 aui
->aui_irqid
, aui
->aui_irq
);
685 bus_release_resource(dev
, aui
->aui_regtype
,
686 aui
->aui_regid
, aui
->aui_reg
);
687 kfree(aui
, M_DEVBUF
);
695 au88x0_pci_detach(device_t dev
)
697 struct au88x0_info
*aui
;
700 aui
= pcm_getdevinfo(dev
);
701 if ((error
= pcm_unregister(dev
)) != 0)
704 /* release resources in reverse order */
705 bus_dma_tag_destroy(aui
->aui_dmat
);
706 bus_teardown_intr(dev
, aui
->aui_irq
, aui
->aui_irqh
);
707 bus_release_resource(dev
, aui
->aui_irqtype
,
708 aui
->aui_irqid
, aui
->aui_irq
);
709 bus_release_resource(dev
, aui
->aui_regtype
,
710 aui
->aui_regid
, aui
->aui_reg
);
711 kfree(aui
, M_DEVBUF
);
719 static device_method_t au88x0_methods
[] = {
720 DEVMETHOD(device_probe
, au88x0_pci_probe
),
721 DEVMETHOD(device_attach
, au88x0_pci_attach
),
722 DEVMETHOD(device_detach
, au88x0_pci_detach
),
726 static driver_t au88x0_driver
= {
732 DRIVER_MODULE(snd_au88x0
, pci
, au88x0_driver
, pcm_devclass
, 0, 0);
733 MODULE_DEPEND(snd_au88x0
, sound
, SOUND_MINVER
, SOUND_PREFVER
, SOUND_MAXVER
);
734 MODULE_VERSION(snd_au88x0
, 1);