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
davbus_probe(device_t self)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
burgundy_init(struct snd_mixer * m)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
burgundy_uninit(struct snd_mixer * m)191 burgundy_uninit(struct snd_mixer *m)
192 {
193 return (0);
194 }
195
196 static int
burgundy_reinit(struct snd_mixer * m)197 burgundy_reinit(struct snd_mixer *m)
198 {
199 return (0);
200 }
201
202 static void
burgundy_write_locked(struct davbus_softc * d,u_int reg,u_int val)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
burgundy_set_outputs(struct davbus_softc * d,u_int mask)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
burgundy_read_status(struct davbus_softc * d,u_int status)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
burgundy_set(struct snd_mixer * m,unsigned dev,unsigned left,unsigned right)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
burgundy_setrecsrc(struct snd_mixer * m,u_int32_t src)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
screamer_init(struct snd_mixer * m)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
screamer_uninit(struct snd_mixer * m)363 screamer_uninit(struct snd_mixer *m)
364 {
365 return (0);
366 }
367
368 static int
screamer_reinit(struct snd_mixer * m)369 screamer_reinit(struct snd_mixer *m)
370 {
371 return (0);
372 }
373
374 static void
screamer_write_locked(struct davbus_softc * d,u_int reg,u_int val)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
screamer_set_outputs(struct davbus_softc * d,u_int mask)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
screamer_read_status(struct davbus_softc * d,u_int status)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
screamer_set(struct snd_mixer * m,unsigned dev,unsigned left,unsigned right)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
screamer_setrecsrc(struct snd_mixer * m,u_int32_t src)487 screamer_setrecsrc(struct snd_mixer *m, u_int32_t src)
488 {
489 return (0);
490 }
491
492 static int
davbus_attach(device_t self)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
davbus_cint(void * ptr)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