davbus.c revision 187717
1/*-
2 * Copyright 2008 by Marco Trillo. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
18 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
20 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
21 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 *
25 * $FreeBSD: head/sys/dev/sound/macio/davbus.c 187717 2009-01-26 14:43:18Z nwhitehorn $
26 */
27
28/*
29 *	Apple DAVbus audio controller.
30 */
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/bus.h>
35#include <sys/kernel.h>
36#include <sys/lock.h>
37#include <sys/malloc.h>
38#include <sys/module.h>
39#include <sys/mutex.h>
40#include <sys/rman.h>
41
42#include <dev/ofw/ofw_bus.h>
43#include <dev/sound/pcm/sound.h>
44#include <dev/sound/macio/aoa.h>
45#include <dev/sound/macio/davbusreg.h>
46
47#include <machine/intr_machdep.h>
48#include <machine/resource.h>
49#include <machine/bus.h>
50
51#include "mixer_if.h"
52
53struct davbus_softc {
54	struct aoa_softc 	 aoa;
55	device_t 		 dev;
56	phandle_t 		 node;
57	phandle_t 		 soundnode;
58	struct resource 	*reg;
59	struct mtx 		 mutex;
60	int 			 device_id;
61	u_int 			 output_mask;
62	u_int 			(*read_status)(struct davbus_softc *, u_int);
63	void			(*set_outputs)(struct davbus_softc *, u_int);
64};
65
66static int 	davbus_probe(device_t);
67static int 	davbus_attach(device_t);
68static void	davbus_cint(void *);
69
70static device_method_t pcm_davbus_methods[] = {
71	/* Device interface. */
72	DEVMETHOD(device_probe,		davbus_probe),
73	DEVMETHOD(device_attach, 	davbus_attach),
74
75	{ 0, 0 }
76};
77
78static driver_t pcm_davbus_driver = {
79	"pcm",
80	pcm_davbus_methods,
81	PCM_SOFTC_SIZE
82};
83
84DRIVER_MODULE(pcm_davbus, macio, pcm_davbus_driver, pcm_devclass, 0, 0);
85MODULE_DEPEND(pcm_davbus, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
86
87/*****************************************************************************
88			Probe and attachment routines.
89 *****************************************************************************/
90static int
91davbus_probe(device_t self)
92{
93	const char 		*name;
94
95	name = ofw_bus_get_name(self);
96	if (!name)
97		return (ENXIO);
98
99	if (strcmp(name, "davbus") != 0)
100		return (ENXIO);
101
102	device_set_desc(self, "Apple DAVBus Audio Controller");
103
104	return (0);
105}
106
107/*
108 * Burgundy codec control
109 */
110
111static int	burgundy_init(struct snd_mixer *m);
112static int	burgundy_uninit(struct snd_mixer *m);
113static int	burgundy_reinit(struct snd_mixer *m);
114static void 	burgundy_write_locked(struct davbus_softc *, u_int, u_int);
115static void	burgundy_set_outputs(struct davbus_softc *d, u_int mask);
116static u_int	burgundy_read_status(struct davbus_softc *d, u_int status);
117static int	burgundy_set(struct snd_mixer *m, unsigned dev, unsigned left,
118		    unsigned right);
119static int	burgundy_setrecsrc(struct snd_mixer *m, u_int32_t src);
120
121static kobj_method_t burgundy_mixer_methods[] = {
122	KOBJMETHOD(mixer_init, 		burgundy_init),
123	KOBJMETHOD(mixer_uninit, 	burgundy_uninit),
124	KOBJMETHOD(mixer_reinit, 	burgundy_reinit),
125	KOBJMETHOD(mixer_set, 		burgundy_set),
126	KOBJMETHOD(mixer_setrecsrc,	burgundy_setrecsrc),
127	{ 0, 0 }
128};
129
130MIXER_DECLARE(burgundy_mixer);
131
132static int
133burgundy_init(struct snd_mixer *m)
134{
135	struct davbus_softc *d;
136
137	d = mix_getdevinfo(m);
138
139	d->read_status = burgundy_read_status;
140	d->set_outputs = burgundy_set_outputs;
141
142	/*
143	 * We configure the Burgundy codec as follows:
144	 *
145	 * 	o Input subframe 0 is connected to input digital
146	 *	  stream A (ISA).
147	 *	o Stream A (ISA) is mixed in mixer 2 (MIX2).
148	 *	o Output of mixer 2 (MIX2) is routed to output sources
149	 *	  OS0 and OS1 which can be converted to analog.
150	 *
151	 */
152	mtx_lock(&d->mutex);
153
154	burgundy_write_locked(d, 0x16700, 0x40);
155
156	burgundy_write_locked(d, BURGUNDY_MIX0_REG, 0);
157	burgundy_write_locked(d, BURGUNDY_MIX1_REG, 0);
158	burgundy_write_locked(d, BURGUNDY_MIX2_REG, BURGUNDY_MIX_ISA);
159	burgundy_write_locked(d, BURGUNDY_MIX3_REG, 0);
160
161	burgundy_write_locked(d, BURGUNDY_OS_REG, BURGUNDY_OS0_MIX2 |
162	    BURGUNDY_OS1_MIX2);
163
164	burgundy_write_locked(d, BURGUNDY_SDIN_REG, BURGUNDY_ISA_SF0);
165
166	/* Set several digital scalers to unity gain. */
167	burgundy_write_locked(d, BURGUNDY_MXS2L_REG, BURGUNDY_MXS_UNITY);
168	burgundy_write_locked(d, BURGUNDY_MXS2R_REG, BURGUNDY_MXS_UNITY);
169	burgundy_write_locked(d, BURGUNDY_OSS0L_REG, BURGUNDY_OSS_UNITY);
170	burgundy_write_locked(d, BURGUNDY_OSS0R_REG, BURGUNDY_OSS_UNITY);
171	burgundy_write_locked(d, BURGUNDY_OSS1L_REG, BURGUNDY_OSS_UNITY);
172	burgundy_write_locked(d, BURGUNDY_OSS1R_REG, BURGUNDY_OSS_UNITY);
173	burgundy_write_locked(d, BURGUNDY_ISSAL_REG, BURGUNDY_ISS_UNITY);
174	burgundy_write_locked(d, BURGUNDY_ISSAR_REG, BURGUNDY_ISS_UNITY);
175
176	burgundy_set_outputs(d, burgundy_read_status(d,
177	    bus_read_4(d->reg, DAVBUS_CODEC_STATUS)));
178
179	mtx_unlock(&d->mutex);
180
181	mix_setdevs(m, SOUND_MASK_VOLUME);
182
183	return (0);
184}
185
186static int
187burgundy_uninit(struct snd_mixer *m)
188{
189	return (0);
190}
191
192static int
193burgundy_reinit(struct snd_mixer *m)
194{
195	return (0);
196}
197
198static void
199burgundy_write_locked(struct davbus_softc *d, u_int reg, u_int val)
200{
201	u_int size, addr, offset, data, i;
202
203	size = (reg & 0x00FF0000) >> 16;
204	addr = (reg & 0x0000FF00) >> 8;
205	offset = reg & 0xFF;
206
207	for (i = offset; i < offset + size; ++i) {
208		data = BURGUNDY_CTRL_WRITE | (addr << 12) |
209		    ((size + offset - 1) << 10) | (i << 8) | (val & 0xFF);
210		if (i == offset)
211			data |= BURGUNDY_CTRL_RESET;
212
213		bus_write_4(d->reg, DAVBUS_CODEC_CTRL, data);
214
215		while (bus_read_4(d->reg, DAVBUS_CODEC_CTRL) &
216		    DAVBUS_CODEC_BUSY)
217			DELAY(1);
218
219		val >>= 8; /* next byte. */
220	}
221}
222
223/* Must be called with d->mutex held. */
224static void
225burgundy_set_outputs(struct davbus_softc *d, u_int mask)
226{
227	u_int	x = 0;
228
229	if (mask == d->output_mask)
230		return;
231
232	/*
233	 *	Bordeaux card wirings:
234	 *		Port 15:	RCA out
235	 *		Port 16:	Minijack out
236	 *		Port 17:	Internal speaker
237	 *
238	 *	B&W G3 wirings:
239	 *		Port 14:	Minijack out
240	 *		Port 17:	Internal speaker
241	 */
242
243	DPRINTF(("Enabled outputs:"));
244	if (mask & (1 << 0)) {
245		DPRINTF((" SPEAKER"));
246		x |= BURGUNDY_P17M_EN;
247	}
248	if (mask & (1 << 1)) {
249		DPRINTF((" HEADPHONES"));
250		x |= BURGUNDY_P14L_EN | BURGUNDY_P14R_EN;
251	}
252	DPRINTF(("\n"));
253
254	burgundy_write_locked(d, BURGUNDY_MUTE_REG, x);
255	d->output_mask = mask;
256}
257
258static u_int
259burgundy_read_status(struct davbus_softc *d, u_int status)
260{
261	if (status & 0x4)
262		return (1 << 1);
263	else
264		return (1 << 0);
265}
266
267static int
268burgundy_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
269{
270	struct davbus_softc *d;
271	int lval, rval;
272
273	lval = ((100 - left) * 15 / 100) & 0xf;
274	rval = ((100 - right) * 15 / 100) & 0xf;
275	DPRINTF(("volume %d %d\n", lval, rval));
276
277	d = mix_getdevinfo(m);
278
279	switch (dev) {
280	case SOUND_MIXER_VOLUME:
281		mtx_lock(&d->mutex);
282
283		burgundy_write_locked(d, BURGUNDY_OL13_REG, lval);
284		burgundy_write_locked(d, BURGUNDY_OL14_REG, (rval << 4) | lval);
285		burgundy_write_locked(d, BURGUNDY_OL15_REG, (rval << 4) | lval);
286		burgundy_write_locked(d, BURGUNDY_OL16_REG, (rval << 4) | lval);
287		burgundy_write_locked(d, BURGUNDY_OL17_REG, lval);
288
289		mtx_unlock(&d->mutex);
290
291		return (left | (right << 8));
292	}
293
294	return (0);
295}
296
297static int
298burgundy_setrecsrc(struct snd_mixer *m, u_int32_t src)
299{
300	return (0);
301}
302
303/*
304 * Screamer Codec Control
305 */
306
307static int	screamer_init(struct snd_mixer *m);
308static int	screamer_uninit(struct snd_mixer *m);
309static int	screamer_reinit(struct snd_mixer *m);
310static void 	screamer_write_locked(struct davbus_softc *, u_int, u_int);
311static void	screamer_set_outputs(struct davbus_softc *d, u_int mask);
312static u_int	screamer_read_status(struct davbus_softc *d, u_int status);
313static int	screamer_set(struct snd_mixer *m, unsigned dev, unsigned left,
314		    unsigned right);
315static int	screamer_setrecsrc(struct snd_mixer *m, u_int32_t src);
316
317static kobj_method_t screamer_mixer_methods[] = {
318	KOBJMETHOD(mixer_init, 		screamer_init),
319	KOBJMETHOD(mixer_uninit, 	screamer_uninit),
320	KOBJMETHOD(mixer_reinit, 	screamer_reinit),
321	KOBJMETHOD(mixer_set, 		screamer_set),
322	KOBJMETHOD(mixer_setrecsrc,	screamer_setrecsrc),
323	{ 0, 0 }
324};
325
326MIXER_DECLARE(screamer_mixer);
327
328static int
329screamer_init(struct snd_mixer *m)
330{
331	struct davbus_softc *d;
332
333	d = mix_getdevinfo(m);
334
335	d->read_status = screamer_read_status;
336	d->set_outputs = screamer_set_outputs;
337
338	mtx_lock(&d->mutex);
339
340	screamer_write_locked(d, SCREAMER_CODEC_ADDR0, SCREAMER_INPUT_CD |
341	    SCREAMER_DEFAULT_CD_GAIN);
342
343	screamer_set_outputs(d, screamer_read_status(d,
344	    bus_read_4(d->reg, DAVBUS_CODEC_STATUS)));
345
346	screamer_write_locked(d, SCREAMER_CODEC_ADDR2, 0);
347	screamer_write_locked(d, SCREAMER_CODEC_ADDR4, 0);
348	screamer_write_locked(d, SCREAMER_CODEC_ADDR5, 0);
349	screamer_write_locked(d, SCREAMER_CODEC_ADDR6, 0);
350
351	mtx_unlock(&d->mutex);
352
353	mix_setdevs(m, SOUND_MASK_VOLUME);
354
355	return (0);
356}
357
358static int
359screamer_uninit(struct snd_mixer *m)
360{
361	return (0);
362}
363
364static int
365screamer_reinit(struct snd_mixer *m)
366{
367	return (0);
368}
369
370
371static void
372screamer_write_locked(struct davbus_softc *d, u_int reg, u_int val)
373{
374	u_int 		x;
375
376	KASSERT(val == (val & 0xfff), ("bad val"));
377
378	while (bus_read_4(d->reg, DAVBUS_CODEC_CTRL) & DAVBUS_CODEC_BUSY)
379		DELAY(100);
380
381	x = reg;
382	x |= SCREAMER_CODEC_EMSEL0;
383	x |= val;
384	bus_write_4(d->reg, DAVBUS_CODEC_CTRL, x);
385
386	while (bus_read_4(d->reg, DAVBUS_CODEC_CTRL) & DAVBUS_CODEC_BUSY)
387		DELAY(100);
388}
389
390/* Must be called with d->mutex held. */
391static void
392screamer_set_outputs(struct davbus_softc *d, u_int mask)
393{
394	u_int 	x;
395
396	if (mask == d->output_mask) {
397		return;
398	}
399
400	x = SCREAMER_MUTE_SPEAKER | SCREAMER_MUTE_HEADPHONES;
401
402	DPRINTF(("Enabled outputs: "));
403
404	if (mask & (1 << 0)) {
405		DPRINTF(("SPEAKER "));
406		x &= ~SCREAMER_MUTE_SPEAKER;
407	}
408	if (mask & (1 << 1)) {
409		DPRINTF(("HEADPHONES "));
410		x &= ~SCREAMER_MUTE_HEADPHONES;
411	}
412
413	DPRINTF(("\n"));
414
415	if (d->device_id == 5 || d->device_id == 11) {
416		DPRINTF(("Enabling programmable output.\n"));
417		x |= SCREAMER_PROG_OUTPUT0;
418	}
419	if (d->device_id == 8 || d->device_id == 11) {
420		x &= ~SCREAMER_MUTE_SPEAKER;
421
422		if (mask & (1 << 0))
423			x |= SCREAMER_PROG_OUTPUT1; /* enable speaker. */
424	}
425
426	screamer_write_locked(d, SCREAMER_CODEC_ADDR1, x);
427	d->output_mask = mask;
428}
429
430static u_int
431screamer_read_status(struct davbus_softc *d, u_int status)
432{
433	int 	headphones;
434
435	switch (d->device_id) {
436	case 5: /* Sawtooth */
437		headphones = (status & 0x4);
438		break;
439
440	case 8:
441	case 11: /* iMac DV */
442		/* The iMac DV has 2 headphone outputs. */
443		headphones = (status & 0x7);
444		break;
445
446	default:
447		headphones = (status & 0x8);
448	}
449
450	if (headphones)
451		return (1 << 1);
452	else
453		return (1 << 0);
454}
455
456static int
457screamer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
458{
459	struct davbus_softc *d;
460	int lval, rval;
461
462	lval = ((100 - left) * 15 / 100) & 0xf;
463	rval = ((100 - right) * 15 / 100) & 0xf;
464	DPRINTF(("volume %d %d\n", lval, rval));
465
466	d = mix_getdevinfo(m);
467
468	switch (dev) {
469	case SOUND_MIXER_VOLUME:
470		mtx_lock(&d->mutex);
471		screamer_write_locked(d, SCREAMER_CODEC_ADDR2, (lval << 6) |
472		    rval);
473		screamer_write_locked(d, SCREAMER_CODEC_ADDR4, (lval << 6) |
474		    rval);
475		mtx_unlock(&d->mutex);
476
477		return (left | (right << 8));
478	}
479
480	return (0);
481}
482
483static int
484screamer_setrecsrc(struct snd_mixer *m, u_int32_t src)
485{
486	return (0);
487}
488
489static int
490davbus_attach(device_t self)
491{
492	struct davbus_softc 	*sc;
493	struct resource 	*dbdma_irq, *cintr;
494	void 			*cookie;
495	char			 compat[64];
496	int 			 rid, oirq, err;
497
498	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
499
500	sc->dev = self;
501	sc->node = ofw_bus_get_node(self);
502	sc->soundnode = OF_child(sc->node);
503
504	/* Map the controller register space. */
505	rid = 0;
506	sc->reg = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE);
507	if (sc->reg == NULL)
508		return (ENXIO);
509
510	/* Map the DBDMA channel register space. */
511	rid = 1;
512	sc->aoa.sc_odma = bus_alloc_resource_any(self, SYS_RES_MEMORY,
513	    &rid, RF_ACTIVE);
514	if (sc->aoa.sc_odma == NULL)
515		return (ENXIO);
516
517	/* Establish the DBDMA channel edge-triggered interrupt. */
518	rid = 1;
519	dbdma_irq = bus_alloc_resource_any(self, SYS_RES_IRQ,
520	    &rid, RF_SHAREABLE | RF_ACTIVE);
521	if (dbdma_irq == NULL)
522		return (ENXIO);
523
524	oirq = rman_get_start(dbdma_irq);
525
526	DPRINTF(("interrupting at irq %d\n", oirq));
527
528	err = powerpc_config_intr(oirq, INTR_TRIGGER_EDGE, INTR_POLARITY_LOW);
529	if (err != 0)
530		return (err);
531
532	bus_setup_intr(self, dbdma_irq, INTR_TYPE_AV | INTR_MPSAFE,
533	    NULL, aoa_interrupt, sc, &cookie);
534
535	/* Now initialize the controller. */
536
537	bzero(compat, sizeof(compat));
538	OF_getprop(sc->soundnode, "compatible", compat, sizeof(compat));
539	OF_getprop(sc->soundnode, "device-id", &sc->device_id, sizeof(u_int));
540
541	mtx_init(&sc->mutex, "DAVbus", NULL, MTX_DEF);
542
543	device_printf(self, "codec: <%s>\n", compat);
544
545	/* Setup the control interrupt. */
546	rid = 0;
547	cintr = bus_alloc_resource_any(self, SYS_RES_IRQ,
548	     &rid, RF_SHAREABLE | RF_ACTIVE);
549	if (cintr != NULL)
550		bus_setup_intr(self, cintr, INTR_TYPE_MISC | INTR_MPSAFE,
551		    NULL, davbus_cint, sc, &cookie);
552
553	/* Initialize controller registers. */
554        bus_write_4(sc->reg, DAVBUS_SOUND_CTRL, DAVBUS_INPUT_SUBFRAME0 |
555	    DAVBUS_OUTPUT_SUBFRAME0 | DAVBUS_RATE_44100 | DAVBUS_INTR_PORTCHG);
556
557	/* Attach DBDMA engine and PCM layer */
558	err = aoa_attach(self,sc);
559	if (err)
560		return (err);
561
562	/* Install codec module */
563	if (strcmp(compat, "screamer") == 0)
564		mixer_init(self, &screamer_mixer_class, sc);
565	else if (strcmp(compat, "burgundy") == 0)
566		mixer_init(self, &burgundy_mixer_class, sc);
567
568	return (0);
569}
570
571static void
572davbus_cint(void *ptr)
573{
574	struct davbus_softc *d = ptr;
575	u_int	reg, status, mask;
576
577	mtx_lock(&d->mutex);
578
579	reg = bus_read_4(d->reg, DAVBUS_SOUND_CTRL);
580	if (reg & DAVBUS_PORTCHG) {
581
582		status = bus_read_4(d->reg, DAVBUS_CODEC_STATUS);
583
584		if (d->read_status && d->set_outputs) {
585
586			mask = (*d->read_status)(d, status);
587			(*d->set_outputs)(d, mask);
588		}
589
590		/* Clear the interrupt. */
591		bus_write_4(d->reg, DAVBUS_SOUND_CTRL, reg);
592	}
593
594	mtx_unlock(&d->mutex);
595}
596
597