xref: /freebsd/sys/dev/sound/macio/davbus.c (revision 39ee7a7a6bdd1557b1c3532abf60d139798ac88b)
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 
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 
59 struct 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 
71 static int 	davbus_probe(device_t);
72 static int 	davbus_attach(device_t);
73 static void	davbus_cint(void *);
74 
75 static 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 
83 static driver_t pcm_davbus_driver = {
84 	"pcm",
85 	pcm_davbus_methods,
86 	PCM_SOFTC_SIZE
87 };
88 
89 DRIVER_MODULE(pcm_davbus, macio, pcm_davbus_driver, pcm_devclass, 0, 0);
90 MODULE_DEPEND(pcm_davbus, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
91 
92 /*****************************************************************************
93 			Probe and attachment routines.
94  *****************************************************************************/
95 static int
96 davbus_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 
116 static int	burgundy_init(struct snd_mixer *m);
117 static int	burgundy_uninit(struct snd_mixer *m);
118 static int	burgundy_reinit(struct snd_mixer *m);
119 static void 	burgundy_write_locked(struct davbus_softc *, u_int, u_int);
120 static void	burgundy_set_outputs(struct davbus_softc *d, u_int mask);
121 static u_int	burgundy_read_status(struct davbus_softc *d, u_int status);
122 static int	burgundy_set(struct snd_mixer *m, unsigned dev, unsigned left,
123 		    unsigned right);
124 static u_int32_t	burgundy_setrecsrc(struct snd_mixer *m, u_int32_t src);
125 
126 static 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 
135 MIXER_DECLARE(burgundy_mixer);
136 
137 static int
138 burgundy_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 
191 static int
192 burgundy_uninit(struct snd_mixer *m)
193 {
194 	return (0);
195 }
196 
197 static int
198 burgundy_reinit(struct snd_mixer *m)
199 {
200 	return (0);
201 }
202 
203 static void
204 burgundy_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. */
229 static void
230 burgundy_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 
263 static u_int
264 burgundy_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 
272 static int
273 burgundy_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 
302 static u_int32_t
303 burgundy_setrecsrc(struct snd_mixer *m, u_int32_t src)
304 {
305 	return (0);
306 }
307 
308 /*
309  * Screamer Codec Control
310  */
311 
312 static int	screamer_init(struct snd_mixer *m);
313 static int	screamer_uninit(struct snd_mixer *m);
314 static int	screamer_reinit(struct snd_mixer *m);
315 static void 	screamer_write_locked(struct davbus_softc *, u_int, u_int);
316 static void	screamer_set_outputs(struct davbus_softc *d, u_int mask);
317 static u_int	screamer_read_status(struct davbus_softc *d, u_int status);
318 static int	screamer_set(struct snd_mixer *m, unsigned dev, unsigned left,
319 		    unsigned right);
320 static u_int32_t	screamer_setrecsrc(struct snd_mixer *m, u_int32_t src);
321 
322 static 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 
331 MIXER_DECLARE(screamer_mixer);
332 
333 static int
334 screamer_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 
363 static int
364 screamer_uninit(struct snd_mixer *m)
365 {
366 	return (0);
367 }
368 
369 static int
370 screamer_reinit(struct snd_mixer *m)
371 {
372 	return (0);
373 }
374 
375 
376 static void
377 screamer_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. */
396 static void
397 screamer_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 
435 static u_int
436 screamer_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 
461 static int
462 screamer_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 
488 static u_int32_t
489 screamer_setrecsrc(struct snd_mixer *m, u_int32_t src)
490 {
491 	return (0);
492 }
493 
494 static int
495 davbus_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 
576 static void
577 davbus_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