2 * Copyright (c) 2000 David Jones <dej@ox.org>
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 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $FreeBSD: src/sys/dev/sound/pci/via82c686.c,v 1.34.2.2 2007/04/26 08:21:44 ariff Exp $
27 * $DragonFly: src/sys/dev/sound/pci/via82c686.c,v 1.10 2007/06/16 20:07:19 dillon Exp $
30 #include <dev/sound/pcm/sound.h>
31 #include <dev/sound/pcm/ac97.h>
33 #include <bus/pci/pcireg.h>
34 #include <bus/pci/pcivar.h>
35 #include <sys/sysctl.h>
37 #include <dev/sound/pci/via82c686.h>
39 SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pci/via82c686.c,v 1.10 2007/06/16 20:07:19 dillon Exp $");
41 #define VIA_PCI_ID 0x30581106
42 #define NSEGS 4 /* Number of segments in SGD table */
44 #define SEGS_PER_CHAN (NSEGS/2)
47 #define VIA_DEFAULT_BUFSZ 0x1000
52 /* we rely on this struct being packed to 64 bits */
56 #define VIA_DMAOP_EOL 0x80000000
57 #define VIA_DMAOP_FLAG 0x40000000
58 #define VIA_DMAOP_STOP 0x20000000
59 #define VIA_DMAOP_COUNT(x) ((x)&0x00FFFFFF)
65 struct via_info
*parent
;
66 struct pcm_channel
*channel
;
67 struct snd_dbuf
*buffer
;
68 struct via_dma_op
*sgd_table
;
71 int base
, count
, mode
, ctrl
;
76 bus_space_handle_t sh
;
77 bus_dma_tag_t parent_dmat
;
78 bus_dma_tag_t sgd_dmat
;
79 bus_dmamap_t sgd_dmamap
;
82 struct resource
*reg
, *irq
;
85 struct ac97_info
*codec
;
89 struct via_chinfo pch
, rch
;
90 struct via_dma_op
*sgd_table
;
95 static u_int32_t via_fmt
[] = {
97 AFMT_STEREO
| AFMT_U8
,
99 AFMT_STEREO
| AFMT_S16_LE
,
102 static struct pcmchan_caps via_vracaps
= {4000, 48000, via_fmt
, 0};
103 static struct pcmchan_caps via_caps
= {48000, 48000, via_fmt
, 0};
105 static __inline u_int32_t
106 via_rd(struct via_info
*via
, int regno
, int size
)
111 return bus_space_read_1(via
->st
, via
->sh
, regno
);
113 return bus_space_read_2(via
->st
, via
->sh
, regno
);
115 return bus_space_read_4(via
->st
, via
->sh
, regno
);
123 via_wr(struct via_info
*via
, int regno
, u_int32_t data
, int size
)
128 bus_space_write_1(via
->st
, via
->sh
, regno
, data
);
131 bus_space_write_2(via
->st
, via
->sh
, regno
, data
);
134 bus_space_write_4(via
->st
, via
->sh
, regno
, data
);
139 /* -------------------------------------------------------------------- */
140 /* Codec interface */
143 via_waitready_codec(struct via_info
*via
)
147 /* poll until codec not busy */
148 for (i
= 0; (i
< TIMEOUT
) &&
149 (via_rd(via
, VIA_CODEC_CTL
, 4) & VIA_CODEC_BUSY
); i
++)
152 kprintf("via: codec busy\n");
161 via_waitvalid_codec(struct via_info
*via
)
165 /* poll until codec valid */
166 for (i
= 0; (i
< TIMEOUT
) &&
167 !(via_rd(via
, VIA_CODEC_CTL
, 4) & VIA_CODEC_PRIVALID
); i
++)
170 kprintf("via: codec invalid\n");
179 via_write_codec(kobj_t obj
, void *addr
, int reg
, u_int32_t val
)
181 struct via_info
*via
= addr
;
183 if (via_waitready_codec(via
)) return -1;
185 via_wr(via
, VIA_CODEC_CTL
, VIA_CODEC_PRIVALID
| VIA_CODEC_INDEX(reg
) | val
, 4);
192 via_read_codec(kobj_t obj
, void *addr
, int reg
)
194 struct via_info
*via
= addr
;
196 if (via_waitready_codec(via
))
199 via_wr(via
, VIA_CODEC_CTL
, VIA_CODEC_PRIVALID
| VIA_CODEC_READ
| VIA_CODEC_INDEX(reg
),4);
201 if (via_waitready_codec(via
))
204 if (via_waitvalid_codec(via
))
207 return via_rd(via
, VIA_CODEC_CTL
, 2);
210 static kobj_method_t via_ac97_methods
[] = {
211 KOBJMETHOD(ac97_read
, via_read_codec
),
212 KOBJMETHOD(ac97_write
, via_write_codec
),
215 AC97_DECLARE(via_ac97
);
217 /* -------------------------------------------------------------------- */
220 via_buildsgdt(struct via_chinfo
*ch
)
222 u_int32_t phys_addr
, flag
;
223 int i
, segs
, seg_size
;
226 * Build the scatter/gather DMA (SGD) table.
227 * There are four slots in the table: two for play, two for record.
228 * This creates two half-buffers, one of which is playing; the other
231 seg_size
= ch
->blksz
;
232 segs
= sndbuf_getsize(ch
->buffer
) / seg_size
;
233 phys_addr
= sndbuf_getbufaddr(ch
->buffer
);
235 for (i
= 0; i
< segs
; i
++) {
236 flag
= (i
== segs
- 1)? VIA_DMAOP_EOL
: VIA_DMAOP_FLAG
;
237 ch
->sgd_table
[i
].ptr
= phys_addr
+ (i
* seg_size
);
238 ch
->sgd_table
[i
].flags
= flag
| seg_size
;
244 /* channel interface */
246 viachan_init(kobj_t obj
, void *devinfo
, struct snd_dbuf
*b
, struct pcm_channel
*c
, int dir
)
248 struct via_info
*via
= devinfo
;
249 struct via_chinfo
*ch
;
251 snd_mtxlock(via
->lock
);
252 if (dir
== PCMDIR_PLAY
) {
254 ch
->base
= VIA_PLAY_DMAOPS_BASE
;
255 ch
->count
= VIA_PLAY_DMAOPS_COUNT
;
256 ch
->ctrl
= VIA_PLAY_CONTROL
;
257 ch
->mode
= VIA_PLAY_MODE
;
258 ch
->sgd_addr
= via
->sgd_addr
;
259 ch
->sgd_table
= &via
->sgd_table
[0];
262 ch
->base
= VIA_RECORD_DMAOPS_BASE
;
263 ch
->count
= VIA_RECORD_DMAOPS_COUNT
;
264 ch
->ctrl
= VIA_RECORD_CONTROL
;
265 ch
->mode
= VIA_RECORD_MODE
;
266 ch
->sgd_addr
= via
->sgd_addr
+ sizeof(struct via_dma_op
) * SEGS_PER_CHAN
;
267 ch
->sgd_table
= &via
->sgd_table
[SEGS_PER_CHAN
];
274 snd_mtxunlock(via
->lock
);
276 if (sndbuf_alloc(ch
->buffer
, via
->parent_dmat
, via
->bufsz
) != 0)
283 viachan_setformat(kobj_t obj
, void *data
, u_int32_t format
)
285 struct via_chinfo
*ch
= data
;
286 struct via_info
*via
= ch
->parent
;
290 if (format
& AFMT_STEREO
)
291 mode_set
|= VIA_RPMODE_STEREO
;
292 if (format
& AFMT_S16_LE
)
293 mode_set
|= VIA_RPMODE_16BIT
;
295 DEB(kprintf("set format: dir = %d, format=%x\n", ch
->dir
, format
));
296 snd_mtxlock(via
->lock
);
297 mode
= via_rd(via
, ch
->mode
, 1);
298 mode
&= ~(VIA_RPMODE_16BIT
| VIA_RPMODE_STEREO
);
300 via_wr(via
, ch
->mode
, mode
, 1);
301 snd_mtxunlock(via
->lock
);
307 viachan_setspeed(kobj_t obj
, void *data
, u_int32_t speed
)
309 struct via_chinfo
*ch
= data
;
310 struct via_info
*via
= ch
->parent
;
314 * Basic AC'97 defines a 48 kHz sample rate only. For other rates,
315 * upsampling is required.
317 * The VT82C686A does not perform upsampling, and neither do we.
318 * If the codec supports variable-rate audio (i.e. does the upsampling
319 * itself), then negotiate the rate with the codec. Otherwise,
320 * return 48 kHz cuz that's all you got.
322 if (via
->codec_caps
& AC97_EXTCAP_VRA
) {
323 reg
= (ch
->dir
== PCMDIR_PLAY
)? AC97_REGEXT_FDACRATE
: AC97_REGEXT_LADCRATE
;
324 return ac97_setrate(via
->codec
, reg
, speed
);
330 viachan_setblocksize(kobj_t obj
, void *data
, u_int32_t blocksize
)
332 struct via_chinfo
*ch
= data
;
334 ch
->blksz
= blocksize
;
335 sndbuf_resize(ch
->buffer
, SEGS_PER_CHAN
, ch
->blksz
);
341 viachan_trigger(kobj_t obj
, void *data
, int go
)
343 struct via_chinfo
*ch
= data
;
344 struct via_info
*via
= ch
->parent
;
345 struct via_dma_op
*ado
;
346 bus_addr_t sgd_addr
= ch
->sgd_addr
;
348 if (go
== PCMTRIG_EMLDMAWR
|| go
== PCMTRIG_EMLDMARD
)
352 DEB(kprintf("ado located at va=%p pa=%x\n", ado
, sgd_addr
));
354 snd_mtxlock(via
->lock
);
355 if (go
== PCMTRIG_START
) {
357 via_wr(via
, ch
->base
, sgd_addr
, 4);
358 via_wr(via
, ch
->ctrl
, VIA_RPCTRL_START
, 1);
360 via_wr(via
, ch
->ctrl
, VIA_RPCTRL_TERMINATE
, 1);
361 snd_mtxunlock(via
->lock
);
363 DEB(kprintf("viachan_trigger: go=%d\n", go
));
368 viachan_getptr(kobj_t obj
, void *data
)
370 struct via_chinfo
*ch
= data
;
371 struct via_info
*via
= ch
->parent
;
372 struct via_dma_op
*ado
;
373 bus_addr_t sgd_addr
= ch
->sgd_addr
;
374 int ptr
, base
, base1
, len
, seg
;
377 snd_mtxlock(via
->lock
);
378 base1
= via_rd(via
, ch
->base
, 4);
379 len
= via_rd(via
, ch
->count
, 4);
380 base
= via_rd(via
, ch
->base
, 4);
381 if (base
!= base1
) /* Avoid race hazard */
382 len
= via_rd(via
, ch
->count
, 4);
383 snd_mtxunlock(via
->lock
);
385 DEB(kprintf("viachan_getptr: len / base = %x / %x\n", len
, base
));
387 /* Base points to SGD segment to do, one past current */
389 /* Determine how many segments have been done */
390 seg
= (base
- sgd_addr
) / sizeof(struct via_dma_op
);
394 /* Now work out offset: seg less count */
395 ptr
= (seg
* sndbuf_getsize(ch
->buffer
) / SEGS_PER_CHAN
) - len
;
396 if (ch
->dir
== PCMDIR_REC
) {
397 /* DMA appears to operate on memory 'lines' of 32 bytes */
398 /* so don't return any part line - it isn't in RAM yet */
402 DEB(kprintf("return ptr=%d\n", ptr
));
406 static struct pcmchan_caps
*
407 viachan_getcaps(kobj_t obj
, void *data
)
409 struct via_chinfo
*ch
= data
;
410 struct via_info
*via
= ch
->parent
;
412 return (via
->codec_caps
& AC97_EXTCAP_VRA
)? &via_vracaps
: &via_caps
;
415 static kobj_method_t viachan_methods
[] = {
416 KOBJMETHOD(channel_init
, viachan_init
),
417 KOBJMETHOD(channel_setformat
, viachan_setformat
),
418 KOBJMETHOD(channel_setspeed
, viachan_setspeed
),
419 KOBJMETHOD(channel_setblocksize
, viachan_setblocksize
),
420 KOBJMETHOD(channel_trigger
, viachan_trigger
),
421 KOBJMETHOD(channel_getptr
, viachan_getptr
),
422 KOBJMETHOD(channel_getcaps
, viachan_getcaps
),
425 CHANNEL_DECLARE(viachan
);
427 /* -------------------------------------------------------------------- */
432 struct via_info
*via
= p
;
434 /* DEB(kprintf("viachan_intr\n")); */
436 snd_mtxlock(via
->lock
);
437 if (via_rd(via
, VIA_PLAY_STAT
, 1) & VIA_RPSTAT_INTR
) {
438 via_wr(via
, VIA_PLAY_STAT
, VIA_RPSTAT_INTR
, 1);
439 snd_mtxunlock(via
->lock
);
440 chn_intr(via
->pch
.channel
);
441 snd_mtxlock(via
->lock
);
445 if (via_rd(via
, VIA_RECORD_STAT
, 1) & VIA_RPSTAT_INTR
) {
446 via_wr(via
, VIA_RECORD_STAT
, VIA_RPSTAT_INTR
, 1);
447 snd_mtxunlock(via
->lock
);
448 chn_intr(via
->rch
.channel
);
451 snd_mtxunlock(via
->lock
);
455 * Probe and attach the card
458 via_probe(device_t dev
)
460 if (pci_get_devid(dev
) == VIA_PCI_ID
) {
461 device_set_desc(dev
, "VIA VT82C686A");
462 return BUS_PROBE_DEFAULT
;
469 dma_cb(void *p
, bus_dma_segment_t
*bds
, int a
, int b
)
471 struct via_info
*via
= (struct via_info
*)p
;
472 via
->sgd_addr
= bds
->ds_addr
;
477 via_attach(device_t dev
)
479 struct via_info
*via
= 0;
480 char status
[SND_STATUSLEN
];
483 if ((via
= kmalloc(sizeof *via
, M_DEVBUF
, M_NOWAIT
| M_ZERO
)) == NULL
) {
484 device_printf(dev
, "cannot allocate softc\n");
487 via
->lock
= snd_mtxcreate(device_get_nameunit(dev
), "sound softc");
490 data
= pci_read_config(dev
, PCIR_COMMAND
, 2);
491 data
|= (PCIM_CMD_PORTEN
| PCIM_CMD_BUSMASTEREN
);
492 pci_write_config(dev
, PCIR_COMMAND
, data
, 2);
493 data
= pci_read_config(dev
, PCIR_COMMAND
, 2);
495 /* Wake up and reset AC97 if necessary */
496 data
= pci_read_config(dev
, VIA_AC97STATUS
, 1);
498 if ((data
& VIA_AC97STATUS_RDY
) == 0) {
499 /* Cold reset per ac97r2.3 spec (page 95) */
500 pci_write_config(dev
, VIA_ACLINKCTRL
, VIA_ACLINK_EN
, 1); /* Assert low */
501 DELAY(100); /* Wait T_rst_low */
502 pci_write_config(dev
, VIA_ACLINKCTRL
, VIA_ACLINK_EN
| VIA_ACLINK_NRST
, 1); /* Assert high */
503 DELAY(5); /* Wait T_rst2clk */
504 pci_write_config(dev
, VIA_ACLINKCTRL
, VIA_ACLINK_EN
, 1); /* Assert low */
507 pci_write_config(dev
, VIA_ACLINKCTRL
, VIA_ACLINK_EN
, 1); /* Force no sync */
509 pci_write_config(dev
, VIA_ACLINKCTRL
, VIA_ACLINK_EN
| VIA_ACLINK_SYNC
, 1); /* Sync */
510 DELAY(5); /* Wait T_sync_high */
511 pci_write_config(dev
, VIA_ACLINKCTRL
, VIA_ACLINK_EN
, 1); /* Force no sync */
512 DELAY(5); /* Wait T_sync2clk */
515 /* Power everything up */
516 pci_write_config(dev
, VIA_ACLINKCTRL
, VIA_ACLINK_DESIRED
, 1);
518 /* Wait for codec to become ready (largest reported delay here 310ms) */
519 for (cnt
= 0; cnt
< 2000; cnt
++) {
520 data
= pci_read_config(dev
, VIA_AC97STATUS
, 1);
521 if (data
& VIA_AC97STATUS_RDY
)
526 via
->regid
= PCIR_BAR(0);
527 via
->reg
= bus_alloc_resource_any(dev
, SYS_RES_IOPORT
,
528 &via
->regid
, RF_ACTIVE
);
530 device_printf(dev
, "cannot allocate bus resource.");
533 via
->st
= rman_get_bustag(via
->reg
);
534 via
->sh
= rman_get_bushandle(via
->reg
);
536 via
->bufsz
= pcm_getbuffersize(dev
, 4096, VIA_DEFAULT_BUFSZ
, 65536);
539 via
->irq
= bus_alloc_resource_any(dev
, SYS_RES_IRQ
, &via
->irqid
,
540 RF_ACTIVE
| RF_SHAREABLE
);
541 if (!via
->irq
|| snd_setup_intr(dev
, via
->irq
, INTR_MPSAFE
, via_intr
, via
, &via
->ih
)) {
542 device_printf(dev
, "unable to map interrupt\n");
546 via_wr(via
, VIA_PLAY_MODE
, VIA_RPMODE_AUTOSTART
| VIA_RPMODE_INTR_FLAG
| VIA_RPMODE_INTR_EOL
, 1);
547 via_wr(via
, VIA_RECORD_MODE
, VIA_RPMODE_AUTOSTART
| VIA_RPMODE_INTR_FLAG
| VIA_RPMODE_INTR_EOL
, 1);
549 via
->codec
= AC97_CREATE(dev
, via
, via_ac97
);
553 if (mixer_init(dev
, ac97_getmixerclass(), via
->codec
))
556 via
->codec_caps
= ac97_getextcaps(via
->codec
);
557 ac97_setextmode(via
->codec
,
558 via
->codec_caps
& (AC97_EXTCAP_VRA
| AC97_EXTCAP_VRM
));
560 /* DMA tag for buffers */
561 if (bus_dma_tag_create(/*parent*/NULL
, /*alignment*/2, /*boundary*/0,
562 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT
,
563 /*highaddr*/BUS_SPACE_MAXADDR
,
564 /*filter*/NULL
, /*filterarg*/NULL
,
565 /*maxsize*/via
->bufsz
, /*nsegments*/1, /*maxsegz*/0x3ffff,
567 &via
->parent_dmat
) != 0) {
568 device_printf(dev
, "unable to create dma tag\n");
573 * DMA tag for SGD table. The 686 uses scatter/gather DMA and
574 * requires a list in memory of work to do. We need only 16 bytes
575 * for this list, and it is wasteful to allocate 16K.
577 if (bus_dma_tag_create(/*parent*/NULL
, /*alignment*/2, /*boundary*/0,
578 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT
,
579 /*highaddr*/BUS_SPACE_MAXADDR
,
580 /*filter*/NULL
, /*filterarg*/NULL
,
581 /*maxsize*/NSEGS
* sizeof(struct via_dma_op
),
582 /*nsegments*/1, /*maxsegz*/0x3ffff,
584 &via
->sgd_dmat
) != 0) {
585 device_printf(dev
, "unable to create dma tag\n");
589 if (bus_dmamem_alloc(via
->sgd_dmat
, (void **)&via
->sgd_table
,
590 BUS_DMA_NOWAIT
, &via
->sgd_dmamap
) != 0)
592 if (bus_dmamap_load(via
->sgd_dmat
, via
->sgd_dmamap
, via
->sgd_table
,
593 NSEGS
* sizeof(struct via_dma_op
), dma_cb
, via
, 0) != 0)
596 ksnprintf(status
, SND_STATUSLEN
, "at io 0x%lx irq %ld %s",
597 rman_get_start(via
->reg
), rman_get_start(via
->irq
),
598 PCM_KLDSTRING(snd_via82c686
));
601 if (pcm_register(dev
, via
, 1, 1)) goto bad
;
602 pcm_addchan(dev
, PCMDIR_PLAY
, &viachan_class
, via
);
603 pcm_addchan(dev
, PCMDIR_REC
, &viachan_class
, via
);
604 pcm_setstatus(dev
, status
);
607 if (via
->codec
) ac97_destroy(via
->codec
);
608 if (via
->reg
) bus_release_resource(dev
, SYS_RES_IOPORT
, via
->regid
, via
->reg
);
609 if (via
->ih
) bus_teardown_intr(dev
, via
->irq
, via
->ih
);
610 if (via
->irq
) bus_release_resource(dev
, SYS_RES_IRQ
, via
->irqid
, via
->irq
);
611 if (via
->parent_dmat
) bus_dma_tag_destroy(via
->parent_dmat
);
612 if (via
->sgd_dmamap
) bus_dmamap_unload(via
->sgd_dmat
, via
->sgd_dmamap
);
613 if (via
->sgd_table
) bus_dmamem_free(via
->sgd_dmat
, via
->sgd_table
, via
->sgd_dmamap
);
614 if (via
->sgd_dmat
) bus_dma_tag_destroy(via
->sgd_dmat
);
615 if (via
->lock
) snd_mtxfree(via
->lock
);
616 if (via
) kfree(via
, M_DEVBUF
);
621 via_detach(device_t dev
)
624 struct via_info
*via
= 0;
626 r
= pcm_unregister(dev
);
630 via
= pcm_getdevinfo(dev
);
631 bus_release_resource(dev
, SYS_RES_IOPORT
, via
->regid
, via
->reg
);
632 bus_teardown_intr(dev
, via
->irq
, via
->ih
);
633 bus_release_resource(dev
, SYS_RES_IRQ
, via
->irqid
, via
->irq
);
634 bus_dma_tag_destroy(via
->parent_dmat
);
635 bus_dmamap_unload(via
->sgd_dmat
, via
->sgd_dmamap
);
636 bus_dmamem_free(via
->sgd_dmat
, via
->sgd_table
, via
->sgd_dmamap
);
637 bus_dma_tag_destroy(via
->sgd_dmat
);
638 snd_mtxfree(via
->lock
);
639 kfree(via
, M_DEVBUF
);
644 static device_method_t via_methods
[] = {
645 DEVMETHOD(device_probe
, via_probe
),
646 DEVMETHOD(device_attach
, via_attach
),
647 DEVMETHOD(device_detach
, via_detach
),
651 static driver_t via_driver
= {
657 DRIVER_MODULE(snd_via82c686
, pci
, via_driver
, pcm_devclass
, 0, 0);
658 MODULE_DEPEND(snd_via82c686
, sound
, SOUND_MINVER
, SOUND_PREFVER
, SOUND_MAXVER
);
659 MODULE_VERSION(snd_via82c686
, 1);