haltwo.c revision 1.21 1 /* $NetBSD: haltwo.c,v 1.21 2011/11/23 23:07:30 jmcneill Exp $ */
2
3 /*
4 * Copyright (c) 2003 Ilpo Ruotsalainen
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * <<Id: LICENSE_GC,v 1.1 2001/10/01 23:24:05 cgd Exp>>
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: haltwo.c,v 1.21 2011/11/23 23:07:30 jmcneill Exp $");
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/device.h>
38 #include <sys/audioio.h>
39 #include <sys/kmem.h>
40 #include <dev/audio_if.h>
41 #include <dev/auconv.h>
42 #include <dev/mulaw.h>
43
44 #include <uvm/uvm_extern.h>
45
46 #include <sys/bus.h>
47 #include <machine/sysconf.h>
48
49 #include <sgimips/hpc/hpcvar.h>
50 #include <sgimips/hpc/hpcreg.h>
51
52 #include <sgimips/hpc/haltworeg.h>
53 #include <sgimips/hpc/haltwovar.h>
54
55 #ifdef AUDIO_DEBUG
56 #define DPRINTF(x) printf x
57 #else
58 #define DPRINTF(x)
59 #endif
60
61 static int haltwo_query_encoding(void *, struct audio_encoding *);
62 static int haltwo_set_params(void *, int, int, audio_params_t *,
63 audio_params_t *, stream_filter_list_t *, stream_filter_list_t *);
64 static int haltwo_round_blocksize(void *, int, int, const audio_params_t *);
65 static int haltwo_halt_output(void *);
66 static int haltwo_halt_input(void *);
67 static int haltwo_getdev(void *, struct audio_device *);
68 static int haltwo_set_port(void *, mixer_ctrl_t *);
69 static int haltwo_get_port(void *, mixer_ctrl_t *);
70 static int haltwo_query_devinfo(void *, mixer_devinfo_t *);
71 static void *haltwo_malloc(void *, int, size_t);
72 static void haltwo_free(void *, void *, size_t);
73 static int haltwo_get_props(void *);
74 static int haltwo_trigger_output(void *, void *, void *, int, void (*)(void *),
75 void *, const audio_params_t *);
76 static int haltwo_trigger_input(void *, void *, void *, int, void (*)(void *),
77 void *, const audio_params_t *);
78 static void haltwo_get_locks(void *, kmutex_t **, kmutex_t **);
79 static bool haltwo_shutdown(device_t, int);
80
81 static const struct audio_hw_if haltwo_hw_if = {
82 NULL, /* open */
83 NULL, /* close */
84 NULL, /* drain */
85 haltwo_query_encoding,
86 haltwo_set_params,
87 haltwo_round_blocksize,
88 NULL, /* commit_settings */
89 NULL, /* init_output */
90 NULL, /* init_input */
91 NULL, /* start_output */
92 NULL, /* start_input */
93 haltwo_halt_output,
94 haltwo_halt_input,
95 NULL, /* speaker_ctl */
96 haltwo_getdev,
97 NULL, /* setfd */
98 haltwo_set_port,
99 haltwo_get_port,
100 haltwo_query_devinfo,
101 haltwo_malloc,
102 haltwo_free,
103 NULL, /* round_buffersize */
104 NULL, /* mappage */
105 haltwo_get_props,
106 haltwo_trigger_output,
107 haltwo_trigger_input,
108 NULL, /* dev_ioctl */
109 haltwo_get_locks,
110 };
111
112 static const struct audio_device haltwo_device = {
113 "HAL2",
114 "",
115 "haltwo"
116 };
117
118 static int haltwo_match(device_t, cfdata_t, void *);
119 static void haltwo_attach(device_t, device_t, void *);
120 static int haltwo_intr(void *);
121
122 CFATTACH_DECL_NEW(haltwo, sizeof(struct haltwo_softc),
123 haltwo_match, haltwo_attach, NULL, NULL);
124
125 #define haltwo_write(sc,type,off,val) \
126 bus_space_write_4(sc->sc_st, sc->sc_##type##_sh, off, val)
127
128 #define haltwo_read(sc,type,off) \
129 bus_space_read_4(sc->sc_st, sc->sc_##type##_sh, off)
130
131 static void
132 haltwo_write_indirect(struct haltwo_softc *sc, uint32_t ireg, uint16_t low,
133 uint16_t high)
134 {
135
136 haltwo_write(sc, ctl, HAL2_REG_CTL_IDR0, low);
137 haltwo_write(sc, ctl, HAL2_REG_CTL_IDR1, high);
138 haltwo_write(sc, ctl, HAL2_REG_CTL_IDR2, 0);
139 haltwo_write(sc, ctl, HAL2_REG_CTL_IDR3, 0);
140 haltwo_write(sc, ctl, HAL2_REG_CTL_IAR, ireg);
141
142 while (haltwo_read(sc, ctl, HAL2_REG_CTL_ISR) & HAL2_ISR_TSTATUS)
143 continue;
144 }
145
146 static void
147 haltwo_read_indirect(struct haltwo_softc *sc, uint32_t ireg, uint16_t *low,
148 uint16_t *high)
149 {
150
151 haltwo_write(sc, ctl, HAL2_REG_CTL_IAR,
152 ireg | HAL2_IAR_READ);
153
154 while (haltwo_read(sc, ctl, HAL2_REG_CTL_ISR) & HAL2_ISR_TSTATUS)
155 continue;
156
157 if (low)
158 *low = haltwo_read(sc, ctl, HAL2_REG_CTL_IDR0);
159
160 if (high)
161 *high = haltwo_read(sc, ctl, HAL2_REG_CTL_IDR1);
162 }
163
164 static int
165 haltwo_init_codec(struct haltwo_softc *sc, struct haltwo_codec *codec)
166 {
167 int err;
168 int rseg;
169 size_t allocsz;
170
171 allocsz = sizeof(struct hpc_dma_desc) * HALTWO_MAX_DMASEGS;
172 KASSERT(allocsz <= PAGE_SIZE);
173
174 err = bus_dmamem_alloc(sc->sc_dma_tag, allocsz, 0, 0, &codec->dma_seg,
175 1, &rseg, BUS_DMA_NOWAIT);
176 if (err)
177 goto out;
178
179 err = bus_dmamem_map(sc->sc_dma_tag, &codec->dma_seg, rseg, allocsz,
180 (void **)&codec->dma_descs, BUS_DMA_NOWAIT);
181 if (err)
182 goto out_free;
183
184 err = bus_dmamap_create(sc->sc_dma_tag, allocsz, 1, PAGE_SIZE, 0,
185 BUS_DMA_NOWAIT, &codec->dma_map);
186 if (err)
187 goto out_free;
188
189 err = bus_dmamap_load(sc->sc_dma_tag, codec->dma_map, codec->dma_descs,
190 allocsz, NULL, BUS_DMA_NOWAIT);
191 if (err)
192 goto out_destroy;
193
194 DPRINTF(("haltwo_init_codec: allocated %d descriptors (%d bytes)"
195 " at %p\n", HALTWO_MAX_DMASEGS, allocsz, codec->dma_descs));
196
197 memset(codec->dma_descs, 0, allocsz);
198
199 return 0;
200
201 out_destroy:
202 bus_dmamap_destroy(sc->sc_dma_tag, codec->dma_map);
203 out_free:
204 bus_dmamem_free(sc->sc_dma_tag, &codec->dma_seg, rseg);
205 out:
206 DPRINTF(("haltwo_init_codec failed: %d\n",err));
207
208 return err;
209 }
210
211 static void
212 haltwo_setup_dma(struct haltwo_softc *sc, struct haltwo_codec *codec,
213 struct haltwo_dmabuf *dmabuf, size_t len, int blksize,
214 void (*intr)(void *), void *intrarg)
215 {
216 int i;
217 bus_dma_segment_t *segp;
218 struct hpc_dma_desc *descp;
219 int next_intr;
220
221 KASSERT(len % blksize == 0);
222
223 next_intr = blksize;
224 codec->intr = intr;
225 codec->intr_arg = intrarg;
226
227 segp = dmabuf->dma_map->dm_segs;
228 descp = codec->dma_descs;
229
230 /* Build descriptor chain for looping DMA, triggering interrupt every
231 * blksize bytes */
232 for (i = 0; i < dmabuf->dma_map->dm_nsegs; i++) {
233 descp->hpc3_hdd_bufptr = segp->ds_addr;
234 descp->hpc3_hdd_ctl = segp->ds_len;
235
236 KASSERT(next_intr >= segp->ds_len);
237
238 if (next_intr == segp->ds_len) {
239 /* Generate intr after this DMA buffer */
240 descp->hpc3_hdd_ctl |= HPC3_HDD_CTL_INTR;
241 next_intr = blksize;
242 } else
243 next_intr -= segp->ds_len;
244
245 if (i < dmabuf->dma_map->dm_nsegs - 1)
246 descp->hdd_descptr = codec->dma_seg.ds_addr +
247 sizeof(struct hpc_dma_desc) * (i + 1);
248 else
249 descp->hdd_descptr = codec->dma_seg.ds_addr;
250
251 DPRINTF(("haltwo_setup_dma: hdd_bufptr = %x hdd_ctl = %x"
252 " hdd_descptr = %x\n", descp->hpc3_hdd_bufptr,
253 descp->hpc3_hdd_ctl, descp->hdd_descptr));
254
255 segp++;
256 descp++;
257 }
258
259 bus_dmamap_sync(sc->sc_dma_tag, codec->dma_map, 0,
260 codec->dma_map->dm_mapsize, BUS_DMASYNC_PREWRITE);
261 }
262
263 static int
264 haltwo_match(device_t parent, cfdata_t cf, void *aux)
265 {
266 struct hpc_attach_args *haa;
267 uint32_t rev;
268
269 haa = aux;
270 if (strcmp(haa->ha_name, cf->cf_name))
271 return 0;
272
273 if ( platform.badaddr((void *)(vaddr_t)(haa->ha_sh + haa->ha_devoff),
274 sizeof(uint32_t)) )
275 return 0;
276
277 if ( platform.badaddr(
278 (void *)(vaddr_t)(haa->ha_sh + haa->ha_devoff + HAL2_REG_CTL_REV),
279 sizeof(uint32_t)) )
280 return 0;
281
282 rev = *(uint32_t *)MIPS_PHYS_TO_KSEG1(haa->ha_sh + haa->ha_devoff +
283 HAL2_REG_CTL_REV);
284
285 /* This bit is inverted, the test is correct */
286 if (rev & HAL2_REV_AUDIO_PRESENT_N)
287 return 0;
288
289 return 1;
290 }
291
292 static void
293 haltwo_attach(device_t parent, device_t self, void *aux)
294 {
295 struct haltwo_softc *sc;
296 struct hpc_attach_args *haa;
297 uint32_t rev;
298
299 sc = device_private(self);
300 haa = aux;
301 sc->sc_dev = self;
302 sc->sc_st = haa->ha_st;
303 sc->sc_dma_tag = haa->ha_dmat;
304
305 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
306 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
307
308 if (bus_space_subregion(haa->ha_st, haa->ha_sh, haa->ha_devoff,
309 HPC3_PBUS_CH0_DEVREGS_SIZE, &sc->sc_ctl_sh)) {
310 aprint_error(": unable to map control registers\n");
311 return;
312 }
313
314 if (bus_space_subregion(haa->ha_st, haa->ha_sh, HPC3_PBUS_CH2_DEVREGS,
315 HPC3_PBUS_CH2_DEVREGS_SIZE, &sc->sc_vol_sh)) {
316 aprint_error(": unable to map volume registers\n");
317 return;
318 }
319
320 if (bus_space_subregion(haa->ha_st, haa->ha_sh, haa->ha_dmaoff,
321 HPC3_PBUS_DMAREGS_SIZE, &sc->sc_dma_sh)) {
322 aprint_error(": unable to map DMA registers\n");
323 return;
324 }
325
326 haltwo_write(sc, ctl, HAL2_REG_CTL_ISR, 0);
327 haltwo_write(sc, ctl, HAL2_REG_CTL_ISR,
328 HAL2_ISR_GLOBAL_RESET_N | HAL2_ISR_CODEC_RESET_N);
329 haltwo_write_indirect(sc, HAL2_IREG_RELAY_C, HAL2_RELAY_C_STATE, 0);
330
331 rev = haltwo_read(sc, ctl, HAL2_REG_CTL_REV);
332
333 if (cpu_intr_establish(haa->ha_irq, IPL_SCHED, haltwo_intr, sc)
334 == NULL) {
335 aprint_error(": unable to establish interrupt\n");
336 return;
337 }
338
339 aprint_naive(": Audio controller\n");
340
341 aprint_normal(": HAL2 revision %d.%d.%d\n", (rev & 0x7000) >> 12,
342 (rev & 0x00F0) >> 4, rev & 0x000F);
343
344 if (haltwo_init_codec(sc, &sc->sc_dac)) {
345 aprint_error(
346 "haltwo_attach: unable to create DMA descriptor list\n");
347 return;
348 }
349
350 /* XXX Magic PBUS CFGDMA values from Linux HAL2 driver XXX */
351 bus_space_write_4(haa->ha_st, haa->ha_sh, HPC3_PBUS_CH0_CFGDMA,
352 0x8208844);
353 bus_space_write_4(haa->ha_st, haa->ha_sh, HPC3_PBUS_CH1_CFGDMA,
354 0x8208844);
355
356 /* Unmute output */
357 /* XXX Add mute/unmute support to mixer ops? XXX */
358 haltwo_write_indirect(sc, HAL2_IREG_DAC_C2, 0, 0);
359
360 /* Set master volume to zero */
361 sc->sc_vol_left = sc->sc_vol_right = 0;
362 haltwo_write(sc, vol, HAL2_REG_VOL_LEFT, sc->sc_vol_left);
363 haltwo_write(sc, vol, HAL2_REG_VOL_RIGHT, sc->sc_vol_right);
364
365 audio_attach_mi(&haltwo_hw_if, sc, self);
366
367 if (!pmf_device_register1(self, NULL, NULL, haltwo_shutdown))
368 aprint_error_dev(self,
369 "couldn't establish power handler\n");
370 }
371
372 static int
373 haltwo_intr(void *v)
374 {
375 struct haltwo_softc *sc;
376 int ret;
377
378 sc = v;
379 ret = 0;
380
381 mutex_spin_enter(&sc->sc_intr_lock);
382
383 if (bus_space_read_4(sc->sc_st, sc->sc_dma_sh, HPC3_PBUS_CH0_CTL)
384 & HPC3_PBUS_DMACTL_IRQ) {
385 sc->sc_dac.intr(sc->sc_dac.intr_arg);
386
387 ret = 1;
388 } else
389 DPRINTF(("haltwo_intr: Huh?\n"));
390
391 mutex_spin_exit(&sc->sc_intr_lock);
392
393 return ret;
394 }
395
396 static int
397 haltwo_query_encoding(void *v, struct audio_encoding *e)
398 {
399
400 switch (e->index) {
401 case 0:
402 strcpy(e->name, AudioEslinear_le);
403 e->encoding = AUDIO_ENCODING_SLINEAR_LE;
404 e->precision = 16;
405 e->flags = 0;
406 break;
407
408 case 1:
409 strcpy(e->name, AudioEslinear_be);
410 e->encoding = AUDIO_ENCODING_SLINEAR_BE;
411 e->precision = 16;
412 e->flags = 0;
413 break;
414
415 case 2:
416 strcpy(e->name, AudioEmulaw);
417 e->encoding = AUDIO_ENCODING_ULAW;
418 e->precision = 8;
419 e->flags = AUDIO_ENCODINGFLAG_EMULATED;
420 break;
421
422 default:
423 return EINVAL;
424 }
425
426 return 0;
427 }
428
429 static int
430 haltwo_set_params(void *v, int setmode, int usemode,
431 audio_params_t *play, audio_params_t *rec,
432 stream_filter_list_t *pfil, stream_filter_list_t *rfil)
433 {
434 audio_params_t hw;
435 struct haltwo_softc *sc;
436 int master, inc, mod;
437 uint16_t tmp;
438
439 sc = v;
440 if (play->sample_rate < 4000)
441 play->sample_rate = 4000;
442 if (play->sample_rate > 48000)
443 play->sample_rate = 48000;
444
445 if (44100 % play->sample_rate < 48000 % play->sample_rate)
446 master = 44100;
447 else
448 master = 48000;
449
450 /* HAL2 specification 3.1.2.21: Codecs should be driven with INC/MOD
451 * fractions equivalent to 4/N, where N is a positive integer. */
452 inc = 4;
453 mod = master * inc / play->sample_rate;
454
455 /* Fixup upper layers idea of HW sample rate to the actual final rate */
456 play->sample_rate = master * inc / mod;
457
458 DPRINTF(("haltwo_set_params: master = %d inc = %d mod = %d"
459 " sample_rate = %ld\n", master, inc, mod,
460 play->sample_rate));
461
462 hw = *play;
463 switch (play->encoding) {
464 case AUDIO_ENCODING_ULAW:
465 if (play->precision != 8)
466 return EINVAL;
467
468 hw.encoding = AUDIO_ENCODING_SLINEAR_LE;
469 pfil->append(pfil, mulaw_to_linear16, &hw);
470 play = &hw;
471 break;
472 case AUDIO_ENCODING_SLINEAR_BE:
473 case AUDIO_ENCODING_SLINEAR_LE:
474 break;
475
476 default:
477 return EINVAL;
478 }
479 /* play points HW encoding */
480
481 /* Setup samplerate to HW */
482 haltwo_write_indirect(sc, HAL2_IREG_BRES1_C1,
483 master == 44100 ? 1 : 0, 0);
484 /* XXX Documentation disagrees but this seems to work XXX */
485 haltwo_write_indirect(sc, HAL2_IREG_BRES1_C2,
486 inc, 0xFFFF & (inc - mod - 1));
487
488 /* Setup endianness to HW */
489 haltwo_read_indirect(sc, HAL2_IREG_DMA_END, &tmp, NULL);
490 if (play->encoding == AUDIO_ENCODING_SLINEAR_LE)
491 tmp |= HAL2_DMA_END_CODECTX;
492 else
493 tmp &= ~HAL2_DMA_END_CODECTX;
494 haltwo_write_indirect(sc, HAL2_IREG_DMA_END, tmp, 0);
495
496 /* Set PBUS channel, Bresenham clock source, number of channels to HW */
497 haltwo_write_indirect(sc, HAL2_IREG_DAC_C1,
498 (0 << HAL2_C1_DMA_SHIFT) |
499 (1 << HAL2_C1_CLKID_SHIFT) |
500 (play->channels << HAL2_C1_DATAT_SHIFT), 0);
501
502 DPRINTF(("haltwo_set_params: hw_encoding = %d hw_channels = %d\n",
503 play->encoding, play->channels));
504
505 return 0;
506 }
507
508 static int
509 haltwo_round_blocksize(void *v, int blocksize,
510 int mode, const audio_params_t *param)
511 {
512
513 /* XXX Make this smarter and support DMA descriptor chaining XXX */
514 /* XXX Rounding to nearest PAGE_SIZE might work? XXX */
515 return PAGE_SIZE;
516 }
517
518 static int
519 haltwo_halt_output(void *v)
520 {
521 struct haltwo_softc *sc;
522
523 sc = v;
524 /* Disable PBUS DMA */
525 bus_space_write_4(sc->sc_st, sc->sc_dma_sh, HPC3_PBUS_CH0_CTL,
526 HPC3_PBUS_DMACTL_ACT_LD);
527
528 return 0;
529 }
530
531 static int
532 haltwo_halt_input(void *v)
533 {
534
535 return ENXIO;
536 }
537
538 static int
539 haltwo_getdev(void *v, struct audio_device *dev)
540 {
541
542 *dev = haltwo_device;
543 return 0;
544 }
545
546 static int
547 haltwo_set_port(void *v, mixer_ctrl_t *mc)
548 {
549 struct haltwo_softc *sc;
550 int lval, rval;
551
552 if (mc->type != AUDIO_MIXER_VALUE)
553 return EINVAL;
554
555 if (mc->un.value.num_channels == 1)
556 lval = rval = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO];
557 else if (mc->un.value.num_channels == 2) {
558 lval = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
559 rval = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
560 } else
561 return EINVAL;
562
563 sc = v;
564 switch (mc->dev) {
565 case HALTWO_MASTER_VOL:
566 sc->sc_vol_left = lval;
567 sc->sc_vol_right = rval;
568
569 haltwo_write(sc, vol, HAL2_REG_VOL_LEFT,
570 sc->sc_vol_left);
571 haltwo_write(sc, vol, HAL2_REG_VOL_RIGHT,
572 sc->sc_vol_right);
573 break;
574
575 default:
576 return EINVAL;
577 }
578
579 return 0;
580 }
581
582 static int
583 haltwo_get_port(void *v, mixer_ctrl_t *mc)
584 {
585 struct haltwo_softc *sc;
586 int l, r;
587
588 switch (mc->dev) {
589 case HALTWO_MASTER_VOL:
590 sc = v;
591 l = sc->sc_vol_left;
592 r = sc->sc_vol_right;
593 break;
594
595 default:
596 return EINVAL;
597 }
598
599 if (mc->un.value.num_channels == 1)
600 mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = (l+r) / 2;
601 else if (mc->un.value.num_channels == 2) {
602 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
603 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
604 } else
605 return EINVAL;
606
607 return 0;
608 }
609
610 static int
611 haltwo_query_devinfo(void *v, mixer_devinfo_t *dev)
612 {
613
614 switch (dev->index) {
615 /* Mixer values */
616 case HALTWO_MASTER_VOL:
617 dev->type = AUDIO_MIXER_VALUE;
618 dev->mixer_class = HALTWO_OUTPUT_CLASS;
619 dev->prev = dev->next = AUDIO_MIXER_LAST;
620 strcpy(dev->label.name, AudioNmaster);
621 dev->un.v.num_channels = 2;
622 dev->un.v.delta = 16;
623 strcpy(dev->un.v.units.name, AudioNvolume);
624 break;
625
626 /* Mixer classes */
627 case HALTWO_OUTPUT_CLASS:
628 dev->type = AUDIO_MIXER_CLASS;
629 dev->mixer_class = HALTWO_OUTPUT_CLASS;
630 dev->next = dev->prev = AUDIO_MIXER_LAST;
631 strcpy(dev->label.name, AudioCoutputs);
632 break;
633
634 default:
635 return EINVAL;
636 }
637
638 return 0;
639 }
640
641 static int
642 haltwo_alloc_dmamem(struct haltwo_softc *sc, size_t size,
643 struct haltwo_dmabuf *p)
644 {
645 int err;
646
647 p->size = size;
648
649 /* XXX Check align/boundary XXX */
650 err = bus_dmamem_alloc(sc->sc_dma_tag, p->size, 0, 0, p->dma_segs,
651 HALTWO_MAX_DMASEGS, &p->dma_segcount, BUS_DMA_WAITOK);
652 if (err)
653 goto out;
654
655 /* XXX BUS_DMA_COHERENT? XXX */
656 err = bus_dmamem_map(sc->sc_dma_tag, p->dma_segs, p->dma_segcount,
657 p->size, &p->kern_addr, BUS_DMA_WAITOK | BUS_DMA_COHERENT);
658 if (err)
659 goto out_free;
660
661 /* XXX Just guessing ... XXX */
662 err = bus_dmamap_create(sc->sc_dma_tag, p->size, HALTWO_MAX_DMASEGS,
663 PAGE_SIZE, 0, BUS_DMA_WAITOK, &p->dma_map);
664 if (err)
665 goto out_free;
666
667 err = bus_dmamap_load(sc->sc_dma_tag, p->dma_map, p->kern_addr,
668 p->size, NULL, BUS_DMA_WAITOK);
669 if (err)
670 goto out_destroy;
671
672 return 0;
673
674 out_destroy:
675 bus_dmamap_destroy(sc->sc_dma_tag, p->dma_map);
676 out_free:
677 bus_dmamem_free(sc->sc_dma_tag, p->dma_segs, p->dma_segcount);
678 out:
679 DPRINTF(("haltwo_alloc_dmamem failed: %d\n",err));
680
681 return err;
682 }
683
684 static void *
685 haltwo_malloc(void *v, int direction, size_t size)
686 {
687 struct haltwo_softc *sc;
688 struct haltwo_dmabuf *p;
689
690 DPRINTF(("haltwo_malloc size = %d\n", size));
691 sc = v;
692 p = kmem_alloc(sizeof(*p), KM_SLEEP);
693 if (p == NULL)
694 return NULL;
695
696 if (haltwo_alloc_dmamem(sc, size, p)) {
697 kmem_free(p, sizeof(*p));
698 return NULL;
699 }
700
701 p->next = sc->sc_dma_bufs;
702 sc->sc_dma_bufs = p;
703
704 return p->kern_addr;
705 }
706
707 static void
708 haltwo_free(void *v, void *addr, size_t size)
709 {
710 struct haltwo_softc *sc;
711 struct haltwo_dmabuf *p, **pp;
712
713 sc = v;
714 for (pp = &sc->sc_dma_bufs; (p = *pp) != NULL; pp = &p->next) {
715 if (p->kern_addr == addr) {
716 *pp = p->next;
717 kmem_free(p, sizeof(*p));
718 return;
719 }
720 }
721
722 panic("haltwo_free: buffer not in list");
723 }
724
725 static int
726 haltwo_get_props(void *v)
727 {
728
729 return 0;
730 }
731
732 static int
733 haltwo_trigger_output(void *v, void *start, void *end, int blksize,
734 void (*intr)(void *), void *intrarg, const audio_params_t *param)
735 {
736 struct haltwo_softc *sc;
737 struct haltwo_dmabuf *p;
738 uint16_t tmp;
739 uint32_t ctrl;
740 unsigned int fifobeg, fifoend, highwater;
741
742 DPRINTF(("haltwo_trigger_output start = %p end = %p blksize = %d"
743 " param = %p\n", start, end, blksize, param));
744 sc = v;
745 for (p = sc->sc_dma_bufs; p != NULL; p = p->next)
746 if (p->kern_addr == start)
747 break;
748
749 if (p == NULL) {
750 printf("haltwo_trigger_output: buffer not in list\n");
751
752 return EINVAL;
753 }
754
755 /* Disable PBUS DMA */
756 bus_space_write_4(sc->sc_st, sc->sc_dma_sh, HPC3_PBUS_CH0_CTL,
757 HPC3_PBUS_DMACTL_ACT_LD);
758
759 /* Disable HAL2 codec DMA */
760 haltwo_read_indirect(sc, HAL2_IREG_DMA_PORT_EN, &tmp, NULL);
761 haltwo_write_indirect(sc, HAL2_IREG_DMA_PORT_EN,
762 tmp & ~HAL2_DMA_PORT_EN_CODECTX, 0);
763
764 haltwo_setup_dma(sc, &sc->sc_dac, p, (char *)end - (char *)start,
765 blksize, intr, intrarg);
766
767 highwater = (param->channels * 4) >> 1;
768 fifobeg = 0;
769 fifoend = (param->channels * 8) >> 3;
770
771 DPRINTF(("haltwo_trigger_output: hw_channels = %d highwater = %d"
772 " fifobeg = %d fifoend = %d\n", param->hw_channels, highwater,
773 fifobeg, fifoend));
774
775 ctrl = HPC3_PBUS_DMACTL_RT
776 | HPC3_PBUS_DMACTL_ACT_LD
777 | (highwater << HPC3_PBUS_DMACTL_HIGHWATER_SHIFT)
778 | (fifobeg << HPC3_PBUS_DMACTL_FIFOBEG_SHIFT)
779 | (fifoend << HPC3_PBUS_DMACTL_FIFOEND_SHIFT);
780
781 /* Using PBUS CH0 for DAC DMA */
782 haltwo_write_indirect(sc, HAL2_IREG_DMA_DRV, 1, 0);
783
784 /* HAL2 is ready for action, now setup PBUS for DMA transfer */
785 bus_space_write_4(sc->sc_st, sc->sc_dma_sh, HPC3_PBUS_CH0_DP,
786 sc->sc_dac.dma_seg.ds_addr);
787 bus_space_write_4(sc->sc_st, sc->sc_dma_sh, HPC3_PBUS_CH0_CTL,
788 ctrl | HPC3_PBUS_DMACTL_ACT);
789
790 /* Both HAL2 and PBUS have been setup, now start it up */
791 haltwo_read_indirect(sc, HAL2_IREG_DMA_PORT_EN, &tmp, NULL);
792 haltwo_write_indirect(sc, HAL2_IREG_DMA_PORT_EN,
793 tmp | HAL2_DMA_PORT_EN_CODECTX, 0);
794
795 return 0;
796 }
797
798 static int
799 haltwo_trigger_input(void *v, void *start, void *end, int blksize,
800 void (*intr)(void *), void *intrarg, const audio_params_t *param)
801 {
802 struct haltwo_softc *sc;
803 struct haltwo_dmabuf *p;
804
805 DPRINTF(("haltwo_trigger_input start = %p end = %p blksize = %d\n",
806 start, end, blksize));
807 sc = v;
808 for (p = sc->sc_dma_bufs; p != NULL; p = p->next)
809 if (p->kern_addr == start)
810 break;
811
812 if (p == NULL) {
813 printf("haltwo_trigger_input: buffer not in list\n");
814
815 return EINVAL;
816 }
817
818 #if 0
819 haltwo_setup_dma(sc, &sc->sc_adc, p, (char *)end - (char *)start,
820 blksize, intr, intrarg);
821 #endif
822
823 return ENXIO;
824 }
825
826 static void
827 haltwo_get_locks(void *v, kmutex_t **intr, kmutex_t **thread)
828 {
829 struct haltwo_softc *sc;
830
831 DPRINTF(("haltwo_get_locks\n"));
832 sc = v;
833
834 *intr = &sc->sc_intr_lock;
835 *thread = &sc->sc_lock;
836 }
837
838 bool
839 haltwo_shutdown(device_t self, int howto)
840 {
841 struct haltwo_softc *sc;
842
843 sc = device_private(self);
844 haltwo_write(sc, ctl, HAL2_REG_CTL_ISR, 0);
845 haltwo_write(sc, ctl, HAL2_REG_CTL_ISR,
846 HAL2_ISR_GLOBAL_RESET_N | HAL2_ISR_CODEC_RESET_N);
847
848 return true;
849 }
850