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