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