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