1 /* $NetBSD: auacer.c,v 1.39 2020/02/29 06:34:30 isaki Exp $ */
2
3 /*-
4 * Copyright (c) 2004, 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * Acer Labs M5455 audio driver
34 *
35 * Acer provides data sheets after signing an NDA, so this is guess work.
36 * The chip behaves somewhat like the Intel i8x0, so this driver
37 * is loosely based on the auich driver. Additional information taken from
38 * the ALSA intel8x0.c driver (which handles M5455 as well).
39 *
40 * As an historical note one can observe that the auich driver borrows
41 * lot from the first NetBSD PCI audio driver, the eap driver. But this
42 * is not attributed anywhere.
43 */
44
45
46 #include <sys/cdefs.h>
47 __KERNEL_RCSID(0, "$NetBSD: auacer.c,v 1.39 2020/02/29 06:34:30 isaki Exp $");
48
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/kernel.h>
52 #include <sys/kmem.h>
53 #include <sys/device.h>
54 #include <sys/fcntl.h>
55 #include <sys/proc.h>
56
57 #include <dev/pci/pcidevs.h>
58 #include <dev/pci/pcivar.h>
59 #include <dev/pci/auacerreg.h>
60
61 #include <sys/audioio.h>
62 #include <dev/audio/audio_if.h>
63
64 #include <sys/bus.h>
65
66 #include <dev/ic/ac97reg.h>
67 #include <dev/ic/ac97var.h>
68
69 struct auacer_dma {
70 bus_dmamap_t map;
71 void *addr;
72 bus_dma_segment_t segs[1];
73 int nsegs;
74 size_t size;
75 struct auacer_dma *next;
76 };
77
78 #define DMAADDR(p) ((p)->map->dm_segs[0].ds_addr)
79 #define KERNADDR(p) ((void *)((p)->addr))
80
81 struct auacer_cdata {
82 struct auacer_dmalist ic_dmalist_pcmo[ALI_DMALIST_MAX];
83 };
84
85 struct auacer_chan {
86 uint32_t ptr;
87 uint32_t start, p, end;
88 uint32_t blksize, fifoe;
89 uint32_t ack;
90 uint32_t port;
91 struct auacer_dmalist *dmalist;
92 void (*intr)(void *);
93 void *arg;
94 };
95
96 struct auacer_softc {
97 device_t sc_dev;
98 void *sc_ih;
99 kmutex_t sc_lock;
100 kmutex_t sc_intr_lock;
101
102 audio_device_t sc_audev;
103
104 bus_space_tag_t iot;
105 bus_space_handle_t mix_ioh;
106 bus_space_handle_t aud_ioh;
107 bus_dma_tag_t dmat;
108
109 struct ac97_codec_if *codec_if;
110 struct ac97_host_if host_if;
111
112 /* DMA scatter-gather lists. */
113 bus_dmamap_t sc_cddmamap;
114 #define sc_cddma sc_cddmamap->dm_segs[0].ds_addr
115
116 struct auacer_cdata *sc_cdata;
117
118 struct auacer_chan sc_pcmo;
119
120 struct auacer_dma *sc_dmas;
121
122 pci_chipset_tag_t sc_pc;
123 pcitag_t sc_pt;
124
125 int sc_dmamap_flags;
126
127 #define AUACER_NFORMATS 3
128 struct audio_format sc_formats[AUACER_NFORMATS];
129 };
130
131 #define READ1(sc, a) bus_space_read_1(sc->iot, sc->aud_ioh, a)
132 #define READ2(sc, a) bus_space_read_2(sc->iot, sc->aud_ioh, a)
133 #define READ4(sc, a) bus_space_read_4(sc->iot, sc->aud_ioh, a)
134 #define WRITE1(sc, a, v) bus_space_write_1(sc->iot, sc->aud_ioh, a, v)
135 #define WRITE2(sc, a, v) bus_space_write_2(sc->iot, sc->aud_ioh, a, v)
136 #define WRITE4(sc, a, v) bus_space_write_4(sc->iot, sc->aud_ioh, a, v)
137
138 /* Debug */
139 #ifdef AUACER_DEBUG
140 #define DPRINTF(l,x) do { if (auacer_debug & (l)) printf x; } while(0)
141 int auacer_debug = 0;
142 #define ALI_DEBUG_CODECIO 0x0001
143 #define ALI_DEBUG_DMA 0x0002
144 #define ALI_DEBUG_INTR 0x0004
145 #define ALI_DEBUG_API 0x0008
146 #define ALI_DEBUG_MIXERAPI 0x0010
147 #else
148 #define DPRINTF(x,y) /* nothing */
149 #endif
150
151 static int auacer_intr(void *);
152
153 static int auacer_query_format(void *, audio_format_query_t *);
154 static int auacer_set_format(void *, int,
155 const audio_params_t *, const audio_params_t *,
156 audio_filter_reg_t *, audio_filter_reg_t *);
157 static int auacer_halt_output(void *);
158 static int auacer_halt_input(void *);
159 static int auacer_getdev(void *, struct audio_device *);
160 static int auacer_set_port(void *, mixer_ctrl_t *);
161 static int auacer_get_port(void *, mixer_ctrl_t *);
162 static int auacer_query_devinfo(void *, mixer_devinfo_t *);
163 static void *auacer_allocm(void *, int, size_t);
164 static void auacer_freem(void *, void *, size_t);
165 static size_t auacer_round_buffersize(void *, int, size_t);
166 static int auacer_get_props(void *);
167 static int auacer_trigger_output(void *, void *, void *, int,
168 void (*)(void *), void *,
169 const audio_params_t *);
170 static int auacer_trigger_input(void *, void *, void *, int,
171 void (*)(void *), void *,
172 const audio_params_t *);
173
174 static int auacer_alloc_cdata(struct auacer_softc *);
175
176 static int auacer_allocmem(struct auacer_softc *, size_t, size_t,
177 struct auacer_dma *);
178 static int auacer_freemem(struct auacer_softc *, struct auacer_dma *);
179 static void auacer_get_locks(void *, kmutex_t **, kmutex_t **);
180
181 static bool auacer_resume(device_t, const pmf_qual_t *);
182 static int auacer_set_rate(struct auacer_softc *, int, u_int);
183
184 static void auacer_reset(struct auacer_softc *sc);
185
186 static const struct audio_hw_if auacer_hw_if = {
187 .query_format = auacer_query_format,
188 .set_format = auacer_set_format,
189 .halt_output = auacer_halt_output,
190 .halt_input = auacer_halt_input,
191 .getdev = auacer_getdev,
192 .set_port = auacer_set_port,
193 .get_port = auacer_get_port,
194 .query_devinfo = auacer_query_devinfo,
195 .allocm = auacer_allocm,
196 .freem = auacer_freem,
197 .round_buffersize = auacer_round_buffersize,
198 .get_props = auacer_get_props,
199 .trigger_output = auacer_trigger_output,
200 .trigger_input = auacer_trigger_input,
201 .get_locks = auacer_get_locks,
202 };
203
204 #define AUACER_FORMATS_4CH 1
205 #define AUACER_FORMATS_6CH 2
206 #define AUACER_FORMAT(aumode, ch, chmask) \
207 { \
208 .mode = (aumode), \
209 .encoding = AUDIO_ENCODING_SLINEAR_LE, \
210 .validbits = 16, \
211 .precision = 16, \
212 .channels = (ch), \
213 .channel_mask = (chmask), \
214 .frequency_type = 9, \
215 .frequency = { 8000, 11025, 12000, 16000, 22050, \
216 24000, 32000, 44100, 48000, }, \
217 }
218 static const struct audio_format auacer_formats[AUACER_NFORMATS] = {
219 AUACER_FORMAT(AUMODE_PLAY | AUMODE_RECORD, 2, AUFMT_STEREO),
220 AUACER_FORMAT(AUMODE_PLAY , 4, AUFMT_SURROUND4),
221 AUACER_FORMAT(AUMODE_PLAY , 6, AUFMT_DOLBY_5_1),
222 };
223
224 static int auacer_attach_codec(void *, struct ac97_codec_if *);
225 static int auacer_read_codec(void *, uint8_t, uint16_t *);
226 static int auacer_write_codec(void *, uint8_t, uint16_t);
227 static int auacer_reset_codec(void *);
228
229 static int
auacer_match(device_t parent,cfdata_t match,void * aux)230 auacer_match(device_t parent, cfdata_t match, void *aux)
231 {
232 struct pci_attach_args *pa;
233
234 pa = (struct pci_attach_args *)aux;
235 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ALI &&
236 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ALI_M5455)
237 return 1;
238 return 0;
239 }
240
241 static void
auacer_attach(device_t parent,device_t self,void * aux)242 auacer_attach(device_t parent, device_t self, void *aux)
243 {
244 struct auacer_softc *sc;
245 struct pci_attach_args *pa;
246 pci_intr_handle_t ih;
247 bus_size_t aud_size;
248 pcireg_t v;
249 const char *intrstr;
250 int i;
251 char intrbuf[PCI_INTRSTR_LEN];
252
253 sc = device_private(self);
254 sc->sc_dev = self;
255 pa = aux;
256 aprint_normal(": Acer Labs M5455 Audio controller\n");
257
258 if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_IO, 0, &sc->iot,
259 &sc->aud_ioh, NULL, &aud_size)) {
260 aprint_error(": can't map i/o space\n");
261 return;
262 }
263
264 sc->sc_pc = pa->pa_pc;
265 sc->sc_pt = pa->pa_tag;
266 sc->dmat = pa->pa_dmat;
267
268 sc->sc_dmamap_flags = BUS_DMA_COHERENT; /* XXX remove */
269
270 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
271 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO);
272
273 /* enable bus mastering */
274 v = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
275 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
276 v | PCI_COMMAND_MASTER_ENABLE);
277
278 /* Map and establish the interrupt. */
279 if (pci_intr_map(pa, &ih)) {
280 aprint_error_dev(sc->sc_dev, "can't map interrupt\n");
281 mutex_destroy(&sc->sc_lock);
282 mutex_destroy(&sc->sc_intr_lock);
283 return;
284 }
285 intrstr = pci_intr_string(pa->pa_pc, ih, intrbuf, sizeof(intrbuf));
286 sc->sc_ih = pci_intr_establish_xname(pa->pa_pc, ih, IPL_AUDIO,
287 auacer_intr, sc, device_xname(self));
288 if (sc->sc_ih == NULL) {
289 aprint_error_dev(sc->sc_dev, "can't establish interrupt");
290 if (intrstr != NULL)
291 aprint_error(" at %s", intrstr);
292 aprint_error("\n");
293 mutex_destroy(&sc->sc_lock);
294 mutex_destroy(&sc->sc_intr_lock);
295 return;
296 }
297 aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr);
298
299 strlcpy(sc->sc_audev.name, "M5455 AC97", MAX_AUDIO_DEV_LEN);
300 snprintf(sc->sc_audev.version, MAX_AUDIO_DEV_LEN,
301 "0x%02x", PCI_REVISION(pa->pa_class));
302 strlcpy(sc->sc_audev.config, device_xname(sc->sc_dev), MAX_AUDIO_DEV_LEN);
303
304 /* Set up DMA lists. */
305 auacer_alloc_cdata(sc);
306 sc->sc_pcmo.dmalist = sc->sc_cdata->ic_dmalist_pcmo;
307 sc->sc_pcmo.ptr = 0;
308 sc->sc_pcmo.port = ALI_BASE_PO;
309
310 DPRINTF(ALI_DEBUG_DMA, ("auacer_attach: lists %p\n",
311 sc->sc_pcmo.dmalist));
312
313 sc->host_if.arg = sc;
314 sc->host_if.attach = auacer_attach_codec;
315 sc->host_if.read = auacer_read_codec;
316 sc->host_if.write = auacer_write_codec;
317 sc->host_if.reset = auacer_reset_codec;
318
319 if (ac97_attach(&sc->host_if, self, &sc->sc_lock) != 0) {
320 mutex_destroy(&sc->sc_lock);
321 mutex_destroy(&sc->sc_intr_lock);
322 return;
323 }
324
325 /* setup audio_format */
326 memcpy(sc->sc_formats, auacer_formats, sizeof(auacer_formats));
327 mutex_enter(&sc->sc_lock);
328 if (!AC97_IS_4CH(sc->codec_if))
329 AUFMT_INVALIDATE(&sc->sc_formats[AUACER_FORMATS_4CH]);
330 if (!AC97_IS_6CH(sc->codec_if))
331 AUFMT_INVALIDATE(&sc->sc_formats[AUACER_FORMATS_6CH]);
332 if (AC97_IS_FIXED_RATE(sc->codec_if)) {
333 for (i = 0; i < AUACER_NFORMATS; i++) {
334 sc->sc_formats[i].frequency_type = 1;
335 sc->sc_formats[i].frequency[0] = 48000;
336 }
337 }
338
339 mutex_spin_enter(&sc->sc_intr_lock);
340 auacer_reset(sc);
341 mutex_spin_exit(&sc->sc_intr_lock);
342 mutex_exit(&sc->sc_lock);
343
344 audio_attach_mi(&auacer_hw_if, sc, sc->sc_dev);
345
346 if (!pmf_device_register(self, NULL, auacer_resume))
347 aprint_error_dev(self, "couldn't establish power handler\n");
348 }
349
350 CFATTACH_DECL_NEW(auacer, sizeof(struct auacer_softc),
351 auacer_match, auacer_attach, NULL, NULL);
352
353 static int
auacer_ready_codec(struct auacer_softc * sc,int mask)354 auacer_ready_codec(struct auacer_softc *sc, int mask)
355 {
356 int count;
357
358 for (count = 0; count < 0x7f; count++) {
359 int val = READ1(sc, ALI_CSPSR);
360 if (val & mask)
361 return 0;
362 }
363
364 aprint_normal("auacer_ready_codec: AC97 codec ready timeout.\n");
365 return EBUSY;
366 }
367
368 static int
auacer_sema_codec(struct auacer_softc * sc)369 auacer_sema_codec(struct auacer_softc *sc)
370 {
371 int ttime;
372
373 ttime = 100;
374 while (ttime-- && (READ4(sc, ALI_CAS) & ALI_CAS_SEM_BUSY))
375 delay(1);
376 if (!ttime)
377 aprint_normal("auacer_sema_codec: timeout\n");
378 return auacer_ready_codec(sc, ALI_CSPSR_CODEC_READY);
379 }
380
381 static int
auacer_read_codec(void * v,uint8_t reg,uint16_t * val)382 auacer_read_codec(void *v, uint8_t reg, uint16_t *val)
383 {
384 struct auacer_softc *sc;
385
386 sc = v;
387 if (auacer_sema_codec(sc))
388 return EIO;
389
390 reg |= ALI_CPR_ADDR_READ;
391 #if 0
392 if (ac97->num)
393 reg |= ALI_CPR_ADDR_SECONDARY;
394 #endif
395 WRITE2(sc, ALI_CPR_ADDR, reg);
396 if (auacer_ready_codec(sc, ALI_CSPSR_READ_OK))
397 return EIO;
398 *val = READ2(sc, ALI_SPR);
399
400 DPRINTF(ALI_DEBUG_CODECIO, ("auacer_read_codec: reg=0x%x val=0x%x\n",
401 reg, *val));
402
403 return 0;
404 }
405
406 int
auacer_write_codec(void * v,uint8_t reg,uint16_t val)407 auacer_write_codec(void *v, uint8_t reg, uint16_t val)
408 {
409 struct auacer_softc *sc;
410
411 DPRINTF(ALI_DEBUG_CODECIO, ("auacer_write_codec: reg=0x%x val=0x%x\n",
412 reg, val));
413 sc = v;
414 if (auacer_sema_codec(sc))
415 return EIO;
416 WRITE2(sc, ALI_CPR, val);
417 #if 0
418 if (ac97->num)
419 reg |= ALI_CPR_ADDR_SECONDARY;
420 #endif
421 WRITE2(sc, ALI_CPR_ADDR, reg);
422 auacer_ready_codec(sc, ALI_CSPSR_WRITE_OK);
423 return 0;
424 }
425
426 static int
auacer_attach_codec(void * v,struct ac97_codec_if * cif)427 auacer_attach_codec(void *v, struct ac97_codec_if *cif)
428 {
429 struct auacer_softc *sc;
430
431 sc = v;
432 sc->codec_if = cif;
433 return 0;
434 }
435
436 static int
auacer_reset_codec(void * v)437 auacer_reset_codec(void *v)
438 {
439 struct auacer_softc *sc;
440 uint32_t reg;
441 int i;
442
443 sc = v;
444 i = 0;
445 reg = READ4(sc, ALI_SCR);
446 if ((reg & 2) == 0) /* Cold required */
447 reg |= 2;
448 else
449 reg |= 1; /* Warm */
450 reg &= ~0x80000000; /* ACLink on */
451 WRITE4(sc, ALI_SCR, reg);
452
453 while (i < 10) {
454 if ((READ4(sc, ALI_INTERRUPTSR) & ALI_INT_GPIO) == 0)
455 break;
456 delay(50000); /* XXX */
457 i++;
458 }
459 if (i == 10) {
460 return EIO;
461 }
462
463 for (i = 0; i < 10; i++) {
464 reg = READ4(sc, ALI_RTSR);
465 if (reg & 0x80) /* primary codec */
466 break;
467 WRITE4(sc, ALI_RTSR, reg | 0x80);
468 delay(50000); /* XXX */
469 }
470
471 return 0;
472 }
473
474 static void
auacer_reset(struct auacer_softc * sc)475 auacer_reset(struct auacer_softc *sc)
476 {
477 WRITE4(sc, ALI_SCR, ALI_SCR_RESET);
478 WRITE4(sc, ALI_FIFOCR1, 0x83838383);
479 WRITE4(sc, ALI_FIFOCR2, 0x83838383);
480 WRITE4(sc, ALI_FIFOCR3, 0x83838383);
481 WRITE4(sc, ALI_INTERFACECR, ALI_IF_PO); /* XXX pcm out only */
482 WRITE4(sc, ALI_INTERRUPTCR, 0x00000000);
483 WRITE4(sc, ALI_INTERRUPTSR, 0x00000000);
484 }
485
486 static int
auacer_query_format(void * v,audio_format_query_t * afp)487 auacer_query_format(void *v, audio_format_query_t *afp)
488 {
489 struct auacer_softc *sc;
490
491 DPRINTF(ALI_DEBUG_API, ("%s\n", __func__));
492 sc = v;
493 return audio_query_format(sc->sc_formats, AUACER_NFORMATS, afp);
494 }
495
496 static int
auacer_set_rate(struct auacer_softc * sc,int mode,u_int srate)497 auacer_set_rate(struct auacer_softc *sc, int mode, u_int srate)
498 {
499 int ret;
500 u_int ratetmp;
501
502 DPRINTF(ALI_DEBUG_API, ("auacer_set_rate: srate=%u\n", srate));
503
504 ratetmp = srate;
505 if (mode == AUMODE_RECORD)
506 return sc->codec_if->vtbl->set_rate(sc->codec_if,
507 AC97_REG_PCM_LR_ADC_RATE, &ratetmp);
508 ret = sc->codec_if->vtbl->set_rate(sc->codec_if,
509 AC97_REG_PCM_FRONT_DAC_RATE, &ratetmp);
510 if (ret)
511 return ret;
512 ratetmp = srate;
513 ret = sc->codec_if->vtbl->set_rate(sc->codec_if,
514 AC97_REG_PCM_SURR_DAC_RATE, &ratetmp);
515 if (ret)
516 return ret;
517 ratetmp = srate;
518 ret = sc->codec_if->vtbl->set_rate(sc->codec_if,
519 AC97_REG_PCM_LFE_DAC_RATE, &ratetmp);
520 return ret;
521 }
522
523 static int
auacer_set_format(void * v,int setmode,const audio_params_t * play,const audio_params_t * rec,audio_filter_reg_t * pfil,audio_filter_reg_t * rfil)524 auacer_set_format(void *v, int setmode,
525 const audio_params_t *play, const audio_params_t *rec,
526 audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
527 {
528 struct auacer_softc *sc;
529 const audio_params_t *p;
530 uint32_t control;
531 int mode, index;
532
533 DPRINTF(ALI_DEBUG_API, ("%s\n", __func__));
534 sc = v;
535 for (mode = AUMODE_RECORD; mode != -1;
536 mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
537 if ((setmode & mode) == 0)
538 continue;
539
540 p = mode == AUMODE_PLAY ? play : rec;
541
542 index = audio_indexof_format(sc->sc_formats, AUACER_NFORMATS,
543 mode, p);
544 /* p points HW encoding */
545 if (sc->sc_formats[index].frequency_type != 1
546 && auacer_set_rate(sc, mode, p->sample_rate))
547 return EINVAL;
548 if (mode == AUMODE_PLAY) {
549 control = READ4(sc, ALI_SCR);
550 control &= ~ALI_SCR_PCM_246_MASK;
551 if (p->channels == 4)
552 control |= ALI_SCR_PCM_4;
553 else if (p->channels == 6)
554 control |= ALI_SCR_PCM_6;
555 WRITE4(sc, ALI_SCR, control);
556 }
557 }
558
559 return 0;
560 }
561
562 static void
auacer_halt(struct auacer_softc * sc,struct auacer_chan * chan)563 auacer_halt(struct auacer_softc *sc, struct auacer_chan *chan)
564 {
565 uint32_t val;
566 uint8_t port;
567 uint32_t slot;
568
569 port = chan->port;
570 DPRINTF(ALI_DEBUG_API, ("auacer_halt: port=0x%x\n", port));
571 chan->intr = 0;
572
573 slot = ALI_PORT2SLOT(port);
574
575 val = READ4(sc, ALI_DMACR);
576 val |= 1 << (slot+16); /* pause */
577 val &= ~(1 << slot); /* no start */
578 WRITE4(sc, ALI_DMACR, val);
579 WRITE1(sc, port + ALI_OFF_CR, 0);
580 while (READ1(sc, port + ALI_OFF_CR))
581 ;
582 /* reset whole DMA things */
583 WRITE1(sc, port + ALI_OFF_CR, ALI_CR_RR);
584 /* clear interrupts */
585 WRITE1(sc, port + ALI_OFF_SR, READ1(sc, port+ALI_OFF_SR) | ALI_SR_W1TC);
586 WRITE4(sc, ALI_INTERRUPTSR, ALI_PORT2INTR(port));
587 }
588
589 static int
auacer_halt_output(void * v)590 auacer_halt_output(void *v)
591 {
592 struct auacer_softc *sc;
593
594 DPRINTF(ALI_DEBUG_DMA, ("auacer_halt_output\n"));
595 sc = v;
596 auacer_halt(sc, &sc->sc_pcmo);
597
598 return 0;
599 }
600
601 static int
auacer_halt_input(void * v)602 auacer_halt_input(void *v)
603 {
604 DPRINTF(ALI_DEBUG_DMA, ("auacer_halt_input\n"));
605
606 return 0;
607 }
608
609 static int
auacer_getdev(void * v,struct audio_device * adp)610 auacer_getdev(void *v, struct audio_device *adp)
611 {
612 struct auacer_softc *sc;
613
614 DPRINTF(ALI_DEBUG_API, ("auacer_getdev\n"));
615 sc = v;
616 *adp = sc->sc_audev;
617 return 0;
618 }
619
620 static int
auacer_set_port(void * v,mixer_ctrl_t * cp)621 auacer_set_port(void *v, mixer_ctrl_t *cp)
622 {
623 struct auacer_softc *sc;
624
625 DPRINTF(ALI_DEBUG_MIXERAPI, ("auacer_set_port\n"));
626 sc = v;
627 return sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp);
628 }
629
630 static int
auacer_get_port(void * v,mixer_ctrl_t * cp)631 auacer_get_port(void *v, mixer_ctrl_t *cp)
632 {
633 struct auacer_softc *sc;
634
635 DPRINTF(ALI_DEBUG_MIXERAPI, ("auacer_get_port\n"));
636 sc = v;
637 return sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp);
638 }
639
640 static int
auacer_query_devinfo(void * v,mixer_devinfo_t * dp)641 auacer_query_devinfo(void *v, mixer_devinfo_t *dp)
642 {
643 struct auacer_softc *sc;
644
645 DPRINTF(ALI_DEBUG_MIXERAPI, ("auacer_query_devinfo\n"));
646 sc = v;
647 return sc->codec_if->vtbl->query_devinfo(sc->codec_if, dp);
648 }
649
650 static void *
auacer_allocm(void * v,int direction,size_t size)651 auacer_allocm(void *v, int direction, size_t size)
652 {
653 struct auacer_softc *sc;
654 struct auacer_dma *p;
655 int error;
656
657 if (size > (ALI_DMALIST_MAX * ALI_DMASEG_MAX))
658 return NULL;
659
660 p = kmem_zalloc(sizeof(*p), KM_SLEEP);
661 sc = v;
662 error = auacer_allocmem(sc, size, 0, p);
663 if (error) {
664 kmem_free(p, sizeof(*p));
665 return NULL;
666 }
667
668 p->next = sc->sc_dmas;
669 sc->sc_dmas = p;
670
671 return KERNADDR(p);
672 }
673
674 static void
auacer_freem(void * v,void * ptr,size_t size)675 auacer_freem(void *v, void *ptr, size_t size)
676 {
677 struct auacer_softc *sc;
678 struct auacer_dma *p, **pp;
679
680 sc = v;
681 for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->next) {
682 if (KERNADDR(p) == ptr) {
683 auacer_freemem(sc, p);
684 *pp = p->next;
685 kmem_free(p, sizeof(*p));
686 return;
687 }
688 }
689 }
690
691 static size_t
auacer_round_buffersize(void * v,int direction,size_t size)692 auacer_round_buffersize(void *v, int direction, size_t size)
693 {
694
695 if (size > (ALI_DMALIST_MAX * ALI_DMASEG_MAX))
696 size = ALI_DMALIST_MAX * ALI_DMASEG_MAX;
697
698 return size;
699 }
700
701 static int
auacer_get_props(void * v)702 auacer_get_props(void *v)
703 {
704
705 return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE |
706 AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX;
707 }
708
709 static void
auacer_get_locks(void * v,kmutex_t ** intr,kmutex_t ** proc)710 auacer_get_locks(void *v, kmutex_t **intr, kmutex_t **proc)
711 {
712 struct auacer_softc *sc;
713
714 sc = v;
715 *intr = &sc->sc_intr_lock;
716 *proc = &sc->sc_lock;
717 }
718
719 static void
auacer_add_entry(struct auacer_chan * chan)720 auacer_add_entry(struct auacer_chan *chan)
721 {
722 struct auacer_dmalist *q;
723
724 q = &chan->dmalist[chan->ptr];
725
726 DPRINTF(ALI_DEBUG_INTR,
727 ("auacer_add_entry: %p = %x @ 0x%x\n",
728 q, chan->blksize / 2, chan->p));
729
730 q->base = htole32(chan->p);
731 q->len = htole32((chan->blksize / ALI_SAMPLE_SIZE) | ALI_DMAF_IOC);
732 chan->p += chan->blksize;
733 if (chan->p >= chan->end)
734 chan->p = chan->start;
735
736 if (++chan->ptr >= ALI_DMALIST_MAX)
737 chan->ptr = 0;
738 }
739
740 static void
auacer_upd_chan(struct auacer_softc * sc,struct auacer_chan * chan)741 auacer_upd_chan(struct auacer_softc *sc, struct auacer_chan *chan)
742 {
743 uint32_t sts;
744 uint32_t civ;
745
746 sts = READ2(sc, chan->port + ALI_OFF_SR);
747 /* intr ack */
748 WRITE2(sc, chan->port + ALI_OFF_SR, sts & ALI_SR_W1TC);
749 WRITE4(sc, ALI_INTERRUPTSR, ALI_PORT2INTR(chan->port));
750
751 DPRINTF(ALI_DEBUG_INTR, ("auacer_upd_chan: sts=0x%x\n", sts));
752
753 if (sts & ALI_SR_DMA_INT_FIFO) {
754 printf("%s: fifo underrun # %u\n",
755 device_xname(sc->sc_dev), ++chan->fifoe);
756 }
757
758 civ = READ1(sc, chan->port + ALI_OFF_CIV);
759
760 DPRINTF(ALI_DEBUG_INTR,("auacer_intr: civ=%u ptr=%u\n",civ,chan->ptr));
761
762 /* XXX */
763 while (chan->ptr != civ) {
764 auacer_add_entry(chan);
765 }
766
767 WRITE1(sc, chan->port + ALI_OFF_LVI, (chan->ptr - 1) & ALI_LVI_MASK);
768
769 while (chan->ack != civ) {
770 if (chan->intr) {
771 DPRINTF(ALI_DEBUG_INTR,("auacer_upd_chan: callback\n"));
772 chan->intr(chan->arg);
773 }
774 chan->ack++;
775 if (chan->ack >= ALI_DMALIST_MAX)
776 chan->ack = 0;
777 }
778 }
779
780 static int
auacer_intr(void * v)781 auacer_intr(void *v)
782 {
783 struct auacer_softc *sc;
784 int ret, intrs;
785
786 sc = v;
787
788 DPRINTF(ALI_DEBUG_INTR, ("auacer_intr: intrs=0x%x\n",
789 READ4(sc, ALI_INTERRUPTSR)));
790
791 mutex_spin_enter(&sc->sc_intr_lock);
792 intrs = READ4(sc, ALI_INTERRUPTSR);
793 ret = 0;
794 if (intrs & ALI_INT_PCMOUT) {
795 auacer_upd_chan(sc, &sc->sc_pcmo);
796 ret++;
797 }
798 mutex_spin_exit(&sc->sc_intr_lock);
799
800 return ret != 0;
801 }
802
803 static void
auacer_setup_chan(struct auacer_softc * sc,struct auacer_chan * chan,uint32_t start,uint32_t size,uint32_t blksize,void (* intr)(void *),void * arg)804 auacer_setup_chan(struct auacer_softc *sc, struct auacer_chan *chan,
805 uint32_t start, uint32_t size, uint32_t blksize,
806 void (*intr)(void *), void *arg)
807 {
808 uint32_t port, slot;
809 uint32_t offs, val;
810
811 chan->start = start;
812 chan->ptr = 0;
813 chan->p = chan->start;
814 chan->end = chan->start + size;
815 chan->blksize = blksize;
816 chan->ack = 0;
817 chan->intr = intr;
818 chan->arg = arg;
819
820 auacer_add_entry(chan);
821 auacer_add_entry(chan);
822
823 port = chan->port;
824 slot = ALI_PORT2SLOT(port);
825
826 WRITE1(sc, port + ALI_OFF_CIV, 0);
827 WRITE1(sc, port + ALI_OFF_LVI, (chan->ptr - 1) & ALI_LVI_MASK);
828 offs = (char *)chan->dmalist - (char *)sc->sc_cdata;
829 WRITE4(sc, port + ALI_OFF_BDBAR, sc->sc_cddma + offs);
830 WRITE1(sc, port + ALI_OFF_CR,
831 ALI_CR_IOCE | ALI_CR_FEIE | ALI_CR_LVBIE | ALI_CR_RPBM);
832 val = READ4(sc, ALI_DMACR);
833 val &= ~(1 << (slot+16)); /* no pause */
834 val |= 1 << slot; /* start */
835 WRITE4(sc, ALI_DMACR, val);
836 }
837
838 static int
auacer_trigger_output(void * v,void * start,void * end,int blksize,void (* intr)(void *),void * arg,const audio_params_t * param)839 auacer_trigger_output(void *v, void *start, void *end, int blksize,
840 void (*intr)(void *), void *arg, const audio_params_t *param)
841 {
842 struct auacer_softc *sc;
843 struct auacer_dma *p;
844 uint32_t size;
845
846 DPRINTF(ALI_DEBUG_DMA,
847 ("auacer_trigger_output(%p, %p, %d, %p, %p, %p)\n",
848 start, end, blksize, intr, arg, param));
849 sc = v;
850 for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next)
851 continue;
852 if (!p) {
853 printf("auacer_trigger_output: bad addr %p\n", start);
854 return (EINVAL);
855 }
856
857 size = (char *)end - (char *)start;
858 auacer_setup_chan(sc, &sc->sc_pcmo, DMAADDR(p), size, blksize,
859 intr, arg);
860
861 return 0;
862 }
863
864 static int
auacer_trigger_input(void * v,void * start,void * end,int blksize,void (* intr)(void *),void * arg,const audio_params_t * param)865 auacer_trigger_input(void *v, void *start, void *end,
866 int blksize, void (*intr)(void *), void *arg,
867 const audio_params_t *param)
868 {
869 return EINVAL;
870 }
871
872 static int
auacer_allocmem(struct auacer_softc * sc,size_t size,size_t align,struct auacer_dma * p)873 auacer_allocmem(struct auacer_softc *sc, size_t size, size_t align,
874 struct auacer_dma *p)
875 {
876 int error;
877
878 p->size = size;
879 error = bus_dmamem_alloc(sc->dmat, p->size, align, 0,
880 p->segs, sizeof(p->segs)/sizeof(p->segs[0]),
881 &p->nsegs, BUS_DMA_WAITOK);
882 if (error)
883 return error;
884
885 error = bus_dmamem_map(sc->dmat, p->segs, p->nsegs, p->size,
886 &p->addr, BUS_DMA_WAITOK|sc->sc_dmamap_flags);
887 if (error)
888 goto free;
889
890 error = bus_dmamap_create(sc->dmat, p->size, 1, p->size,
891 0, BUS_DMA_WAITOK, &p->map);
892 if (error)
893 goto unmap;
894
895 error = bus_dmamap_load(sc->dmat, p->map, p->addr, p->size, NULL,
896 BUS_DMA_WAITOK);
897 if (error)
898 goto destroy;
899 return (0);
900
901 destroy:
902 bus_dmamap_destroy(sc->dmat, p->map);
903 unmap:
904 bus_dmamem_unmap(sc->dmat, p->addr, p->size);
905 free:
906 bus_dmamem_free(sc->dmat, p->segs, p->nsegs);
907 return error;
908 }
909
910 static int
auacer_freemem(struct auacer_softc * sc,struct auacer_dma * p)911 auacer_freemem(struct auacer_softc *sc, struct auacer_dma *p)
912 {
913
914 bus_dmamap_unload(sc->dmat, p->map);
915 bus_dmamap_destroy(sc->dmat, p->map);
916 bus_dmamem_unmap(sc->dmat, p->addr, p->size);
917 bus_dmamem_free(sc->dmat, p->segs, p->nsegs);
918 return 0;
919 }
920
921 static int
auacer_alloc_cdata(struct auacer_softc * sc)922 auacer_alloc_cdata(struct auacer_softc *sc)
923 {
924 bus_dma_segment_t seg;
925 int error, rseg;
926
927 /*
928 * Allocate the control data structure, and create and load the
929 * DMA map for it.
930 */
931 if ((error = bus_dmamem_alloc(sc->dmat,
932 sizeof(struct auacer_cdata),
933 PAGE_SIZE, 0, &seg, 1, &rseg, 0)) != 0) {
934 aprint_error_dev(sc->sc_dev, "unable to allocate control data, error = %d\n",
935 error);
936 goto fail_0;
937 }
938
939 if ((error = bus_dmamem_map(sc->dmat, &seg, rseg,
940 sizeof(struct auacer_cdata),
941 (void **) &sc->sc_cdata,
942 sc->sc_dmamap_flags)) != 0) {
943 aprint_error_dev(sc->sc_dev, "unable to map control data, error = %d\n",
944 error);
945 goto fail_1;
946 }
947
948 if ((error = bus_dmamap_create(sc->dmat, sizeof(struct auacer_cdata), 1,
949 sizeof(struct auacer_cdata), 0, 0,
950 &sc->sc_cddmamap)) != 0) {
951 aprint_error_dev(sc->sc_dev, "unable to create control data DMA map, "
952 "error = %d\n", error);
953 goto fail_2;
954 }
955
956 if ((error = bus_dmamap_load(sc->dmat, sc->sc_cddmamap,
957 sc->sc_cdata, sizeof(struct auacer_cdata),
958 NULL, 0)) != 0) {
959 aprint_error_dev(sc->sc_dev, "unable to load control data DMA map, "
960 "error = %d\n", error);
961 goto fail_3;
962 }
963
964 return 0;
965
966 fail_3:
967 bus_dmamap_destroy(sc->dmat, sc->sc_cddmamap);
968 fail_2:
969 bus_dmamem_unmap(sc->dmat, (void *) sc->sc_cdata,
970 sizeof(struct auacer_cdata));
971 fail_1:
972 bus_dmamem_free(sc->dmat, &seg, rseg);
973 fail_0:
974 return error;
975 }
976
977 static bool
auacer_resume(device_t dv,const pmf_qual_t * qual)978 auacer_resume(device_t dv, const pmf_qual_t *qual)
979 {
980 struct auacer_softc *sc = device_private(dv);
981
982 mutex_enter(&sc->sc_lock);
983 mutex_spin_enter(&sc->sc_intr_lock);
984 auacer_reset_codec(sc);
985 mutex_spin_exit(&sc->sc_intr_lock);
986 delay(1000);
987 sc->codec_if->vtbl->restore_ports(sc->codec_if);
988 mutex_exit(&sc->sc_lock);
989
990 return true;
991 }
992