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