xref: /freebsd/sys/dev/sound/macio/davbus.c (revision e32fecd0c2c3ee37c47ee100f169e7eb0282a873)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright 2008 by Marco Trillo. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD$
28  */
29 
30 /*
31  *	Apple DAVbus audio controller.
32  */
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/bus.h>
37 #include <sys/kernel.h>
38 #include <sys/lock.h>
39 #include <sys/malloc.h>
40 #include <sys/module.h>
41 #include <sys/mutex.h>
42 #include <sys/rman.h>
43 
44 #include <dev/ofw/ofw_bus.h>
45 
46 #ifdef HAVE_KERNEL_OPTION_HEADERS
47 #include "opt_snd.h"
48 #endif
49 
50 #include <dev/sound/pcm/sound.h>
51 
52 #include <dev/sound/macio/aoa.h>
53 #include <dev/sound/macio/davbusreg.h>
54 
55 #include <machine/intr_machdep.h>
56 #include <machine/resource.h>
57 #include <machine/bus.h>
58 
59 #include "mixer_if.h"
60 
61 struct davbus_softc {
62 	struct aoa_softc 	 aoa;
63 	phandle_t 		 node;
64 	phandle_t 		 soundnode;
65 	struct resource 	*reg;
66 	struct mtx 		 mutex;
67 	int 			 device_id;
68 	u_int 			 output_mask;
69 	u_int 			(*read_status)(struct davbus_softc *, u_int);
70 	void			(*set_outputs)(struct davbus_softc *, u_int);
71 };
72 
73 static int 	davbus_probe(device_t);
74 static int 	davbus_attach(device_t);
75 static void	davbus_cint(void *);
76 
77 static device_method_t pcm_davbus_methods[] = {
78 	/* Device interface. */
79 	DEVMETHOD(device_probe,		davbus_probe),
80 	DEVMETHOD(device_attach, 	davbus_attach),
81 	{ 0, 0 }
82 };
83 
84 static driver_t pcm_davbus_driver = {
85 	"pcm",
86 	pcm_davbus_methods,
87 	PCM_SOFTC_SIZE
88 };
89 
90 DRIVER_MODULE(pcm_davbus, macio, pcm_davbus_driver, 0, 0);
91 MODULE_DEPEND(pcm_davbus, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
92 
93 /*****************************************************************************
94 			Probe and attachment routines.
95  *****************************************************************************/
96 static int
97 davbus_probe(device_t self)
98 {
99 	const char 		*name;
100 
101 	name = ofw_bus_get_name(self);
102 	if (!name)
103 		return (ENXIO);
104 
105 	if (strcmp(name, "davbus") != 0)
106 		return (ENXIO);
107 
108 	device_set_desc(self, "Apple DAVBus Audio Controller");
109 
110 	return (0);
111 }
112 
113 /*
114  * Burgundy codec control
115  */
116 
117 static int	burgundy_init(struct snd_mixer *m);
118 static int	burgundy_uninit(struct snd_mixer *m);
119 static int	burgundy_reinit(struct snd_mixer *m);
120 static void 	burgundy_write_locked(struct davbus_softc *, u_int, u_int);
121 static void	burgundy_set_outputs(struct davbus_softc *d, u_int mask);
122 static u_int	burgundy_read_status(struct davbus_softc *d, u_int status);
123 static int	burgundy_set(struct snd_mixer *m, unsigned dev, unsigned left,
124 		    unsigned right);
125 static u_int32_t	burgundy_setrecsrc(struct snd_mixer *m, u_int32_t src);
126 
127 static kobj_method_t burgundy_mixer_methods[] = {
128 	KOBJMETHOD(mixer_init, 		burgundy_init),
129 	KOBJMETHOD(mixer_uninit, 	burgundy_uninit),
130 	KOBJMETHOD(mixer_reinit, 	burgundy_reinit),
131 	KOBJMETHOD(mixer_set, 		burgundy_set),
132 	KOBJMETHOD(mixer_setrecsrc,	burgundy_setrecsrc),
133 	KOBJMETHOD_END
134 };
135 
136 MIXER_DECLARE(burgundy_mixer);
137 
138 static int
139 burgundy_init(struct snd_mixer *m)
140 {
141 	struct davbus_softc *d;
142 
143 	d = mix_getdevinfo(m);
144 
145 	d->read_status = burgundy_read_status;
146 	d->set_outputs = burgundy_set_outputs;
147 
148 	/*
149 	 * We configure the Burgundy codec as follows:
150 	 *
151 	 * 	o Input subframe 0 is connected to input digital
152 	 *	  stream A (ISA).
153 	 *	o Stream A (ISA) is mixed in mixer 2 (MIX2).
154 	 *	o Output of mixer 2 (MIX2) is routed to output sources
155 	 *	  OS0 and OS1 which can be converted to analog.
156 	 *
157 	 */
158 	mtx_lock(&d->mutex);
159 
160 	burgundy_write_locked(d, 0x16700, 0x40);
161 
162 	burgundy_write_locked(d, BURGUNDY_MIX0_REG, 0);
163 	burgundy_write_locked(d, BURGUNDY_MIX1_REG, 0);
164 	burgundy_write_locked(d, BURGUNDY_MIX2_REG, BURGUNDY_MIX_ISA);
165 	burgundy_write_locked(d, BURGUNDY_MIX3_REG, 0);
166 
167 	burgundy_write_locked(d, BURGUNDY_OS_REG, BURGUNDY_OS0_MIX2 |
168 	    BURGUNDY_OS1_MIX2);
169 
170 	burgundy_write_locked(d, BURGUNDY_SDIN_REG, BURGUNDY_ISA_SF0);
171 
172 	/* Set several digital scalers to unity gain. */
173 	burgundy_write_locked(d, BURGUNDY_MXS2L_REG, BURGUNDY_MXS_UNITY);
174 	burgundy_write_locked(d, BURGUNDY_MXS2R_REG, BURGUNDY_MXS_UNITY);
175 	burgundy_write_locked(d, BURGUNDY_OSS0L_REG, BURGUNDY_OSS_UNITY);
176 	burgundy_write_locked(d, BURGUNDY_OSS0R_REG, BURGUNDY_OSS_UNITY);
177 	burgundy_write_locked(d, BURGUNDY_OSS1L_REG, BURGUNDY_OSS_UNITY);
178 	burgundy_write_locked(d, BURGUNDY_OSS1R_REG, BURGUNDY_OSS_UNITY);
179 	burgundy_write_locked(d, BURGUNDY_ISSAL_REG, BURGUNDY_ISS_UNITY);
180 	burgundy_write_locked(d, BURGUNDY_ISSAR_REG, BURGUNDY_ISS_UNITY);
181 
182 	burgundy_set_outputs(d, burgundy_read_status(d,
183 	    bus_read_4(d->reg, DAVBUS_CODEC_STATUS)));
184 
185 	mtx_unlock(&d->mutex);
186 
187 	mix_setdevs(m, SOUND_MASK_VOLUME);
188 
189 	return (0);
190 }
191 
192 static int
193 burgundy_uninit(struct snd_mixer *m)
194 {
195 	return (0);
196 }
197 
198 static int
199 burgundy_reinit(struct snd_mixer *m)
200 {
201 	return (0);
202 }
203 
204 static void
205 burgundy_write_locked(struct davbus_softc *d, u_int reg, u_int val)
206 {
207 	u_int size, addr, offset, data, i;
208 
209 	size = (reg & 0x00FF0000) >> 16;
210 	addr = (reg & 0x0000FF00) >> 8;
211 	offset = reg & 0xFF;
212 
213 	for (i = offset; i < offset + size; ++i) {
214 		data = BURGUNDY_CTRL_WRITE | (addr << 12) |
215 		    ((size + offset - 1) << 10) | (i << 8) | (val & 0xFF);
216 		if (i == offset)
217 			data |= BURGUNDY_CTRL_RESET;
218 
219 		bus_write_4(d->reg, DAVBUS_CODEC_CTRL, data);
220 
221 		while (bus_read_4(d->reg, DAVBUS_CODEC_CTRL) &
222 		    DAVBUS_CODEC_BUSY)
223 			DELAY(1);
224 
225 		val >>= 8; /* next byte. */
226 	}
227 }
228 
229 /* Must be called with d->mutex held. */
230 static void
231 burgundy_set_outputs(struct davbus_softc *d, u_int mask)
232 {
233 	u_int	x = 0;
234 
235 	if (mask == d->output_mask)
236 		return;
237 
238 	/*
239 	 *	Bordeaux card wirings:
240 	 *		Port 15:	RCA out
241 	 *		Port 16:	Minijack out
242 	 *		Port 17:	Internal speaker
243 	 *
244 	 *	B&W G3 wirings:
245 	 *		Port 14:	Minijack out
246 	 *		Port 17:	Internal speaker
247 	 */
248 
249 	DPRINTF(("Enabled outputs:"));
250 	if (mask & (1 << 0)) {
251 		DPRINTF((" SPEAKER"));
252 		x |= BURGUNDY_P17M_EN;
253 	}
254 	if (mask & (1 << 1)) {
255 		DPRINTF((" HEADPHONES"));
256 		x |= BURGUNDY_P14L_EN | BURGUNDY_P14R_EN;
257 	}
258 	DPRINTF(("\n"));
259 
260 	burgundy_write_locked(d, BURGUNDY_MUTE_REG, x);
261 	d->output_mask = mask;
262 }
263 
264 static u_int
265 burgundy_read_status(struct davbus_softc *d, u_int status)
266 {
267 	if (status & 0x4)
268 		return (1 << 1);
269 	else
270 		return (1 << 0);
271 }
272 
273 static int
274 burgundy_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
275 {
276 	struct davbus_softc *d;
277 	int lval, rval;
278 
279 	lval = ((100 - left) * 15 / 100) & 0xf;
280 	rval = ((100 - right) * 15 / 100) & 0xf;
281 	DPRINTF(("volume %d %d\n", lval, rval));
282 
283 	d = mix_getdevinfo(m);
284 
285 	switch (dev) {
286 	case SOUND_MIXER_VOLUME:
287 		mtx_lock(&d->mutex);
288 
289 		burgundy_write_locked(d, BURGUNDY_OL13_REG, lval);
290 		burgundy_write_locked(d, BURGUNDY_OL14_REG, (rval << 4) | lval);
291 		burgundy_write_locked(d, BURGUNDY_OL15_REG, (rval << 4) | lval);
292 		burgundy_write_locked(d, BURGUNDY_OL16_REG, (rval << 4) | lval);
293 		burgundy_write_locked(d, BURGUNDY_OL17_REG, lval);
294 
295 		mtx_unlock(&d->mutex);
296 
297 		return (left | (right << 8));
298 	}
299 
300 	return (0);
301 }
302 
303 static u_int32_t
304 burgundy_setrecsrc(struct snd_mixer *m, u_int32_t src)
305 {
306 	return (0);
307 }
308 
309 /*
310  * Screamer Codec Control
311  */
312 
313 static int	screamer_init(struct snd_mixer *m);
314 static int	screamer_uninit(struct snd_mixer *m);
315 static int	screamer_reinit(struct snd_mixer *m);
316 static void 	screamer_write_locked(struct davbus_softc *, u_int, u_int);
317 static void	screamer_set_outputs(struct davbus_softc *d, u_int mask);
318 static u_int	screamer_read_status(struct davbus_softc *d, u_int status);
319 static int	screamer_set(struct snd_mixer *m, unsigned dev, unsigned left,
320 		    unsigned right);
321 static u_int32_t	screamer_setrecsrc(struct snd_mixer *m, u_int32_t src);
322 
323 static kobj_method_t screamer_mixer_methods[] = {
324 	KOBJMETHOD(mixer_init, 		screamer_init),
325 	KOBJMETHOD(mixer_uninit, 	screamer_uninit),
326 	KOBJMETHOD(mixer_reinit, 	screamer_reinit),
327 	KOBJMETHOD(mixer_set, 		screamer_set),
328 	KOBJMETHOD(mixer_setrecsrc,	screamer_setrecsrc),
329 	KOBJMETHOD_END
330 };
331 
332 MIXER_DECLARE(screamer_mixer);
333 
334 static int
335 screamer_init(struct snd_mixer *m)
336 {
337 	struct davbus_softc *d;
338 
339 	d = mix_getdevinfo(m);
340 
341 	d->read_status = screamer_read_status;
342 	d->set_outputs = screamer_set_outputs;
343 
344 	mtx_lock(&d->mutex);
345 
346 	screamer_write_locked(d, SCREAMER_CODEC_ADDR0, SCREAMER_INPUT_CD |
347 	    SCREAMER_DEFAULT_CD_GAIN);
348 
349 	screamer_set_outputs(d, screamer_read_status(d,
350 	    bus_read_4(d->reg, DAVBUS_CODEC_STATUS)));
351 
352 	screamer_write_locked(d, SCREAMER_CODEC_ADDR2, 0);
353 	screamer_write_locked(d, SCREAMER_CODEC_ADDR4, 0);
354 	screamer_write_locked(d, SCREAMER_CODEC_ADDR5, 0);
355 	screamer_write_locked(d, SCREAMER_CODEC_ADDR6, 0);
356 
357 	mtx_unlock(&d->mutex);
358 
359 	mix_setdevs(m, SOUND_MASK_VOLUME);
360 
361 	return (0);
362 }
363 
364 static int
365 screamer_uninit(struct snd_mixer *m)
366 {
367 	return (0);
368 }
369 
370 static int
371 screamer_reinit(struct snd_mixer *m)
372 {
373 	return (0);
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 			mask = (*d->read_status)(d, status);
591 			(*d->set_outputs)(d, mask);
592 		}
593 
594 		/* Clear the interrupt. */
595 		bus_write_4(d->reg, DAVBUS_SOUND_CTRL, reg);
596 	}
597 
598 	mtx_unlock(&d->mutex);
599 }
600