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