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