xref: /freebsd/sys/dev/sound/macio/davbus.c (revision ca6a6373bdaed010d6cbfb27f7249ae96009409d)
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 	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 	{ 0, 0 }
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, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
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 *, u_int, u_int);
119 static void	burgundy_set_outputs(struct davbus_softc *d, u_int mask);
120 static u_int	burgundy_read_status(struct davbus_softc *d, u_int status);
121 static int	burgundy_set(struct snd_mixer *m, unsigned dev, unsigned left,
122 		    unsigned right);
123 static u_int32_t	burgundy_setrecsrc(struct snd_mixer *m, u_int32_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, u_int reg, u_int val)
204 {
205 	u_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, u_int mask)
230 {
231 	u_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 u_int
263 burgundy_read_status(struct davbus_softc *d, u_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 u_int32_t
302 burgundy_setrecsrc(struct snd_mixer *m, u_int32_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 *, u_int, u_int);
315 static void	screamer_set_outputs(struct davbus_softc *d, u_int mask);
316 static u_int	screamer_read_status(struct davbus_softc *d, u_int status);
317 static int	screamer_set(struct snd_mixer *m, unsigned dev, unsigned left,
318 		    unsigned right);
319 static u_int32_t	screamer_setrecsrc(struct snd_mixer *m, u_int32_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, u_int reg, u_int val)
376 {
377 	u_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, u_int mask)
396 {
397 	u_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 u_int
434 screamer_read_status(struct davbus_softc *d, u_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 u_int32_t
487 screamer_setrecsrc(struct snd_mixer *m, u_int32_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 	char			 compat[64];
499 	int 			 rid, oirq, err;
500 
501 	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
502 
503 	sc->aoa.sc_dev = self;
504 	sc->node = ofw_bus_get_node(self);
505 	sc->soundnode = OF_child(sc->node);
506 
507 	/* Map the controller register space. */
508 	rid = 0;
509 	sc->reg = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE);
510 	if (sc->reg == NULL)
511 		return (ENXIO);
512 
513 	/* Map the DBDMA channel register space. */
514 	rid = 1;
515 	sc->aoa.sc_odma = bus_alloc_resource_any(self, SYS_RES_MEMORY,
516 	    &rid, RF_ACTIVE);
517 	if (sc->aoa.sc_odma == NULL)
518 		return (ENXIO);
519 
520 	/* Establish the DBDMA channel edge-triggered interrupt. */
521 	rid = 1;
522 	dbdma_irq = bus_alloc_resource_any(self, SYS_RES_IRQ,
523 	    &rid, RF_SHAREABLE | RF_ACTIVE);
524 	if (dbdma_irq == NULL)
525 		return (ENXIO);
526 
527 	oirq = rman_get_start(dbdma_irq);
528 
529 	DPRINTF(("interrupting at irq %d\n", oirq));
530 
531 	err = powerpc_config_intr(oirq, INTR_TRIGGER_EDGE, INTR_POLARITY_LOW);
532 	if (err != 0)
533 		return (err);
534 
535 	snd_setup_intr(self, dbdma_irq, INTR_MPSAFE, aoa_interrupt,
536 	    sc, &cookie);
537 
538 	/* Now initialize the controller. */
539 
540 	bzero(compat, sizeof(compat));
541 	OF_getprop(sc->soundnode, "compatible", compat, sizeof(compat));
542 	OF_getprop(sc->soundnode, "device-id", &sc->device_id, sizeof(u_int));
543 
544 	mtx_init(&sc->mutex, "DAVbus", NULL, MTX_DEF);
545 
546 	device_printf(self, "codec: <%s>\n", compat);
547 
548 	/* Setup the control interrupt. */
549 	rid = 0;
550 	cintr = bus_alloc_resource_any(self, SYS_RES_IRQ,
551 	     &rid, RF_SHAREABLE | RF_ACTIVE);
552 	if (cintr != NULL)
553 		bus_setup_intr(self, cintr, INTR_TYPE_MISC | INTR_MPSAFE,
554 		    NULL, davbus_cint, sc, &cookie);
555 
556 	/* Initialize controller registers. */
557         bus_write_4(sc->reg, DAVBUS_SOUND_CTRL, DAVBUS_INPUT_SUBFRAME0 |
558 	    DAVBUS_OUTPUT_SUBFRAME0 | DAVBUS_RATE_44100 | DAVBUS_INTR_PORTCHG);
559 
560 	/* Attach DBDMA engine and PCM layer */
561 	err = aoa_attach(sc);
562 	if (err)
563 		return (err);
564 
565 	/* Install codec module */
566 	if (strcmp(compat, "screamer") == 0)
567 		mixer_init(self, &screamer_mixer_class, sc);
568 	else if (strcmp(compat, "burgundy") == 0)
569 		mixer_init(self, &burgundy_mixer_class, sc);
570 
571 	return (0);
572 }
573 
574 static void
575 davbus_cint(void *ptr)
576 {
577 	struct davbus_softc *d = ptr;
578 	u_int	reg, status, mask;
579 
580 	mtx_lock(&d->mutex);
581 
582 	reg = bus_read_4(d->reg, DAVBUS_SOUND_CTRL);
583 	if (reg & DAVBUS_PORTCHG) {
584 
585 		status = bus_read_4(d->reg, DAVBUS_CODEC_STATUS);
586 
587 		if (d->read_status && d->set_outputs) {
588 			mask = (*d->read_status)(d, status);
589 			(*d->set_outputs)(d, mask);
590 		}
591 
592 		/* Clear the interrupt. */
593 		bus_write_4(d->reg, DAVBUS_SOUND_CTRL, reg);
594 	}
595 
596 	mtx_unlock(&d->mutex);
597 }
598