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
59struct 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
71static int 	davbus_probe(device_t);
72static int 	davbus_attach(device_t);
73static void	davbus_cint(void *);
74
75static 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
82static driver_t pcm_davbus_driver = {
83	"pcm",
84	pcm_davbus_methods,
85	PCM_SOFTC_SIZE
86};
87
88DRIVER_MODULE(pcm_davbus, macio, pcm_davbus_driver, 0, 0);
89MODULE_DEPEND(pcm_davbus, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
90
91/*****************************************************************************
92			Probe and attachment routines.
93 *****************************************************************************/
94static int
95davbus_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
115static int	burgundy_init(struct snd_mixer *m);
116static int	burgundy_uninit(struct snd_mixer *m);
117static int	burgundy_reinit(struct snd_mixer *m);
118static void 	burgundy_write_locked(struct davbus_softc *, u_int, u_int);
119static void	burgundy_set_outputs(struct davbus_softc *d, u_int mask);
120static u_int	burgundy_read_status(struct davbus_softc *d, u_int status);
121static int	burgundy_set(struct snd_mixer *m, unsigned dev, unsigned left,
122		    unsigned right);
123static u_int32_t	burgundy_setrecsrc(struct snd_mixer *m, u_int32_t src);
124
125static 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
134MIXER_DECLARE(burgundy_mixer);
135
136static int
137burgundy_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
190static int
191burgundy_uninit(struct snd_mixer *m)
192{
193	return (0);
194}
195
196static int
197burgundy_reinit(struct snd_mixer *m)
198{
199	return (0);
200}
201
202static void
203burgundy_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. */
228static void
229burgundy_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
262static u_int
263burgundy_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
271static int
272burgundy_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
301static u_int32_t
302burgundy_setrecsrc(struct snd_mixer *m, u_int32_t src)
303{
304	return (0);
305}
306
307/*
308 * Screamer Codec Control
309 */
310
311static int	screamer_init(struct snd_mixer *m);
312static int	screamer_uninit(struct snd_mixer *m);
313static int	screamer_reinit(struct snd_mixer *m);
314static void 	screamer_write_locked(struct davbus_softc *, u_int, u_int);
315static void	screamer_set_outputs(struct davbus_softc *d, u_int mask);
316static u_int	screamer_read_status(struct davbus_softc *d, u_int status);
317static int	screamer_set(struct snd_mixer *m, unsigned dev, unsigned left,
318		    unsigned right);
319static u_int32_t	screamer_setrecsrc(struct snd_mixer *m, u_int32_t src);
320
321static 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
330MIXER_DECLARE(screamer_mixer);
331
332static int
333screamer_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
362static int
363screamer_uninit(struct snd_mixer *m)
364{
365	return (0);
366}
367
368static int
369screamer_reinit(struct snd_mixer *m)
370{
371	return (0);
372}
373
374static void
375screamer_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. */
394static void
395screamer_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
433static u_int
434screamer_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
459static int
460screamer_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
486static u_int32_t
487screamer_setrecsrc(struct snd_mixer *m, u_int32_t src)
488{
489	return (0);
490}
491
492static int
493davbus_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
574static void
575davbus_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