vraiu.c revision 1.16.2.1 1 /* $NetBSD: vraiu.c,v 1.16.2.1 2019/04/21 09:54:00 isaki Exp $ */
2
3 /*
4 * Copyright (c) 2001 HAMAJIMA Katsuomi. 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 AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, 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 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: vraiu.c,v 1.16.2.1 2019/04/21 09:54:00 isaki Exp $");
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/device.h>
34 #include <sys/bswap.h>
35
36 #include <machine/cpu.h>
37 #include <machine/intr.h>
38 #include <machine/bus.h>
39 #include <machine/platid.h>
40 #include <machine/platid_mask.h>
41 #include <machine/config_hook.h>
42
43 #include <sys/audioio.h>
44 #include <dev/audio_if.h>
45
46 #include <hpcmips/vr/vr.h>
47 #include <hpcmips/vr/vripif.h>
48 #include <hpcmips/vr/icureg.h>
49 #include <hpcmips/vr/cmureg.h>
50 #include <hpcmips/vr/vraiureg.h>
51
52 #ifdef VRAIU_DEBUG
53 int vraiu_debug = VRAIU_DEBUG;
54 #define DPRINTFN(n,x) if (vraiu_debug>(n)) printf x;
55 #else
56 #define DPRINTFN(n,x)
57 #endif
58
59 #define AUDIO_BUF_SIZE 2048
60
61 struct vraiu_softc {
62 device_t sc_dev;
63 kmutex_t sc_lock;
64 kmutex_t sc_intr_lock;
65 bus_space_tag_t sc_iot;
66 bus_space_handle_t sc_ioh;
67 bus_dma_tag_t sc_dmat;
68 bus_dmamap_t sc_dmap;
69 vrip_chipset_tag_t sc_vrip;
70 vrdcu_chipset_tag_t sc_dc;
71 vrdmaau_chipset_tag_t sc_ac;
72 vrcmu_chipset_tag_t sc_cc;
73 void *sc_handler;
74 u_short *sc_buf; /* DMA buffer pointer */
75 int sc_status; /* status */
76 u_int sc_rate; /* sampling rate */
77 u_char sc_volume; /* volume */
78 void (*sc_intr)(void *); /* interrupt routine */
79 void *sc_intrdata; /* interrupt data */
80 };
81
82 int vraiu_match(device_t, cfdata_t, void *);
83 void vraiu_attach(device_t, device_t, void *);
84 int vraiu_intr(void *);
85
86 CFATTACH_DECL_NEW(vraiu, sizeof(struct vraiu_softc),
87 vraiu_match, vraiu_attach, NULL, NULL);
88
89 struct audio_device aiu_device = {
90 "VR4121 AIU",
91 "0.1",
92 "aiu"
93 };
94
95 const struct audio_format vraiu_formats = {
96 .mode = AUMODE_PLAY,
97 .encoding = AUDIO_ENCODING_SLINEAR_NE,
98 .validbits = 10,
99 .precision = 16,
100 .channels = 1,
101 .channel_mask = AUFMT_MONAURAL,
102 .frequency_type = 4,
103 .frequency = { 8000, 11025, 22050, 44100 },
104 };
105
106 /*
107 * Define our interface to the higher level audio driver.
108 */
109 int vraiu_open(void *, int);
110 void vraiu_close(void *);
111 int vraiu_query_format(void *, audio_format_query_t *);
112 int vraiu_round_blocksize(void *, int, int, const audio_params_t *);
113 int vraiu_commit_settings(void *);
114 int vraiu_init_output(void *, void*, int);
115 int vraiu_start_output(void *, void *, int, void (*)(void *), void *);
116 int vraiu_start_input(void *, void *, int, void (*)(void *), void *);
117 int vraiu_halt_output(void *);
118 int vraiu_halt_input(void *);
119 int vraiu_getdev(void *, struct audio_device *);
120 int vraiu_set_port(void *, mixer_ctrl_t *);
121 int vraiu_get_port(void *, mixer_ctrl_t *);
122 int vraiu_query_devinfo(void *, mixer_devinfo_t *);
123 int vraiu_set_format(void *, int,
124 const audio_params_t *, const audio_params_t *,
125 audio_filter_reg_t *, audio_filter_reg_t *);
126 int vraiu_get_props(void *);
127 void vraiu_get_locks(void *, kmutex_t **, kmutex_t **);
128
129 const struct audio_hw_if vraiu_hw_if = {
130 .open = vraiu_open,
131 .close = vraiu_close,
132 .query_format = vraiu_query_format,
133 .set_format = vraiu_set_format,
134 .round_blocksize = vraiu_round_blocksize,
135 .commit_settings = vraiu_commit_settings,
136 .init_output = vraiu_init_output,
137 .init_input = NULL,
138 .start_output = vraiu_start_output,
139 .start_input = vraiu_start_input,
140 .halt_output = vraiu_halt_output,
141 .halt_input = vraiu_halt_input,
142 .getdev = vraiu_getdev,
143 .set_port = vraiu_set_port,
144 .get_port = vraiu_get_port,
145 .query_devinfo = vraiu_query_devinfo,
146 .get_props = vraiu_get_props,
147 .get_locks = vraiu_get_locks,
148 };
149
150 /*
151 * convert to 1ch 10bit unsigned PCM data.
152 */
153 static void vraiu_slinear16_1(struct vraiu_softc *, u_short *, void *, int);
154
155 int
156 vraiu_match(device_t parent, cfdata_t cf, void *aux)
157 {
158 return 1;
159 }
160
161 void
162 vraiu_attach(device_t parent, device_t self, void *aux)
163 {
164 struct vrip_attach_args *va;
165 struct vraiu_softc *sc;
166 bus_dma_segment_t segs;
167 int rsegs;
168
169 va = aux;
170 sc = device_private(self);
171 sc->sc_dev = self;
172 sc->sc_status = ENXIO;
173 sc->sc_intr = NULL;
174 sc->sc_iot = va->va_iot;
175 sc->sc_vrip = va->va_vc;
176 sc->sc_cc = va->va_cc;
177 sc->sc_dc = va->va_dc;
178 sc->sc_ac = va->va_ac;
179 sc->sc_dmat = &vrdcu_bus_dma_tag;
180 sc->sc_volume = 127;
181 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
182 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO);
183
184 if (!sc->sc_cc) {
185 printf(" not configured: cmu not found\n");
186 return;
187 }
188 if (!sc->sc_dc) {
189 printf(" not configured: dcu not found\n");
190 return;
191 }
192 if (!sc->sc_ac) {
193 printf(" not configured: dmaau not found\n");
194 return;
195 }
196 if (bus_space_map(sc->sc_iot, va->va_addr, va->va_size,
197 0 /* no flags */, &sc->sc_ioh)) {
198 printf(": can't map i/o space\n");
199 return;
200 }
201
202 /* install interrupt handler and enable interrupt */
203 if (!(sc->sc_handler = vrip_intr_establish(va->va_vc, va->va_unit,
204 0, IPL_AUDIO, vraiu_intr, sc))) {
205 printf(": can't map interrupt line.\n");
206 return;
207 }
208 vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, (AIUINT_INTMEND | \
209 AIUINT_INTM | \
210 AIUINT_INTMIDLE | \
211 AIUINT_INTMST | \
212 AIUINT_INTSEND | \
213 AIUINT_INTS | \
214 AIUINT_INTSIDLE), 0);
215
216 if (bus_dmamem_alloc(sc->sc_dmat, AUDIO_BUF_SIZE, 0, 0, &segs, 1,
217 &rsegs, BUS_DMA_WAITOK)) {
218 printf(": can't allocate memory.\n");
219 return;
220 }
221 if (bus_dmamem_map(sc->sc_dmat, &segs, rsegs, AUDIO_BUF_SIZE,
222 (void **)&sc->sc_buf,
223 BUS_DMA_WAITOK | BUS_DMA_COHERENT)) {
224 printf(": can't map memory.\n");
225 bus_dmamem_free(sc->sc_dmat, &segs, rsegs);
226 return;
227 }
228 if (bus_dmamap_create(sc->sc_dmat, AUDIO_BUF_SIZE, 1, AUDIO_BUF_SIZE,
229 0, BUS_DMA_WAITOK, &sc->sc_dmap)) {
230 printf(": can't create DMA map.\n");
231 bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_buf,
232 AUDIO_BUF_SIZE);
233 bus_dmamem_free(sc->sc_dmat, &segs, rsegs);
234 return;
235 }
236 if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmap, sc->sc_buf,
237 AUDIO_BUF_SIZE, NULL, BUS_DMA_WAITOK)) {
238 printf(": can't load DMA map.\n");
239 bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmap);
240 bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_buf,
241 AUDIO_BUF_SIZE);
242 bus_dmamem_free(sc->sc_dmat, &segs, rsegs);
243 return;
244 }
245 if (sc->sc_ac->ac_set_aiuout(sc->sc_ac, sc->sc_buf)) {
246 printf(": can't set DMA address.\n");
247 bus_dmamap_unload(sc->sc_dmat, sc->sc_dmap);
248 bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmap);
249 bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_buf,
250 AUDIO_BUF_SIZE);
251 bus_dmamem_free(sc->sc_dmat, &segs, rsegs);
252 return;
253 }
254 printf("\n");
255
256 sc->sc_status = 0;
257 sc->sc_rate = SPS8000;
258 DPRINTFN(1, ("vraiu_attach: reset AIU\n"))
259 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SEQ_REG_W, AIURST);
260 /* attach audio subsystem */
261 audio_attach_mi(&vraiu_hw_if, sc, self);
262 }
263
264 int
265 vraiu_open(void *self, int flags)
266 {
267 struct vraiu_softc *sc;
268
269 DPRINTFN(1, ("vraiu_open\n"));
270 sc = self;
271 if (sc->sc_status) {
272 DPRINTFN(0, ("vraiu_open: device error\n"));
273 return sc->sc_status;
274 }
275 sc->sc_status = EBUSY;
276 return 0;
277 }
278
279 void
280 vraiu_close(void *self)
281 {
282 struct vraiu_softc *sc;
283
284 DPRINTFN(1, ("vraiu_close\n"));
285 sc = self;
286 sc->sc_status = 0;
287 }
288
289 int
290 vraiu_query_format(void *self, audio_format_query_t *afp)
291 {
292
293 return audio_query_format(&vraiu_formats, 1, afp);
294 }
295
296 int
297 vraiu_set_format(void *self, int setmode,
298 const audio_params_t *play, const audio_params_t *rec,
299 audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
300 {
301 struct vraiu_softc *sc;
302
303 DPRINTFN(1, ("%s: %ubit, %uch, %uHz, encoding %u\n", __func__,
304 play->precision, play->channels, play->sample_rate,
305 play->encoding));
306 sc = self;
307
308 switch (play->sample_rate) {
309 case 8000:
310 sc->sc_rate = SPS8000;
311 break;
312 case 11025:
313 sc->sc_rate = SPS11025;
314 break;
315 case 22050:
316 sc->sc_rate = SPS22050;
317 break;
318 case 44100:
319 sc->sc_rate = SPS44100;
320 break;
321 default:
322 /* NOTREACHED */
323 panic("%s: rate error (%d)\n", __func__, play->sample_rate);
324 }
325
326 return 0;
327 }
328
329 int
330 vraiu_round_blocksize(void *self, int bs, int mode, const audio_params_t *param)
331 {
332 return AUDIO_BUF_SIZE;
333 }
334
335 int
336 vraiu_commit_settings(void *self)
337 {
338 struct vraiu_softc *sc;
339 int err;
340
341 DPRINTFN(1, ("vraiu_commit_settings\n"));
342 sc = self;
343 if (sc->sc_status != EBUSY)
344 return sc->sc_status;
345
346 DPRINTFN(1, ("vraiu_commit_settings: set conversion rate %d\n",
347 sc->sc_rate))
348 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCNVR_REG_W, sc->sc_rate);
349 DPRINTFN(1, ("vraiu_commit_settings: clock supply start\n"))
350 if ((err = sc->sc_cc->cc_clock(sc->sc_cc, VR4102_CMUMSKAIU, 1))) {
351 DPRINTFN(0, ("vraiu_commit_settings: clock supply error\n"));
352 return err;
353 }
354 DPRINTFN(1, ("vraiu_commit_settings: enable DMA\n"))
355 if ((err = sc->sc_dc->dc_enable_aiuout(sc->sc_dc))) {
356 sc->sc_cc->cc_clock(sc->sc_cc, VR4102_CMUMSKAIU, 0);
357 DPRINTFN(0, ("vraiu_commit_settings: enable DMA error\n"));
358 return err;
359 }
360 DPRINTFN(1, ("vraiu_commit_settings: Vref on\n"))
361 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCNT_REG_W, DAENAIU);
362 return 0;
363 }
364
365 int
366 vraiu_init_output(void *self, void *buffer, int size)
367 {
368 struct vraiu_softc *sc;
369
370 DPRINTFN(1, ("vraiu_init_output: buffer %p, size %d\n", buffer, size));
371 sc = self;
372 sc->sc_intr = NULL;
373 DPRINTFN(1, ("vraiu_init_output: speaker power on\n"))
374 config_hook_call(CONFIG_HOOK_POWERCONTROL,
375 CONFIG_HOOK_POWERCONTROL_SPEAKER, (void*)1);
376 DPRINTFN(1, ("vraiu_init_output: start output\n"))
377 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SEQ_REG_W, AIUSEN);
378 return 0;
379 }
380
381 int
382 vraiu_start_output(void *self, void *block, int bsize,
383 void (*intr)(void *), void *intrarg)
384 {
385 struct vraiu_softc *sc;
386
387 DPRINTFN(2, ("vraiu_start_output: block %p, bsize %d\n",
388 block, bsize));
389 sc = self;
390 vraiu_slinear16_1(sc, sc->sc_buf, block, bsize);
391 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, AUDIO_BUF_SIZE,
392 BUS_DMASYNC_PREWRITE);
393 sc->sc_intr = intr;
394 sc->sc_intrdata = intrarg;
395 /* clear interrupt status */
396 bus_space_write_2(sc->sc_iot, sc->sc_ioh, INT_REG_W,
397 SENDINTR | SINTR | SIDLEINTR);
398 /* enable interrupt */
399 vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AIUINT_INTSEND, 1);
400 return 0;
401 }
402
403 int
404 vraiu_start_input(void *self, void *block, int bsize,
405 void (*intr)(void *), void *intrarg)
406 {
407
408 DPRINTFN(3, ("vraiu_start_input\n"));
409 /* no input */
410 return ENXIO;
411 }
412
413 int
414 vraiu_intr(void* self)
415 {
416 struct vraiu_softc *sc;
417 uint32_t reg;
418
419 DPRINTFN(2, ("vraiu_intr"));
420 sc = self;
421
422 mutex_spin_enter(&sc->sc_intr_lock);
423
424 vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AIUINT_INTSEND, 0);
425 vrip_intr_getstatus2(sc->sc_vrip, sc->sc_handler, ®);
426 if (reg & AIUINT_INTSEND) {
427 DPRINTFN(2, (": AIUINT_INTSEND"));
428 if (sc->sc_intr) {
429 void (*intr)(void *);
430 intr = sc->sc_intr;
431 sc->sc_intr = NULL;
432 (*(intr))(sc->sc_intrdata);
433 }
434 bus_space_write_2(sc->sc_iot, sc->sc_ioh, INT_REG_W, SENDINTR);
435 }
436 DPRINTFN(2, ("\n"));
437
438 mutex_spin_exit(&sc->sc_intr_lock);
439
440 return 0;
441 }
442
443 int
444 vraiu_halt_output(void *self)
445 {
446 struct vraiu_softc *sc;
447
448 DPRINTFN(1, ("vraiu_halt_output\n"));
449 sc =self;
450 DPRINTFN(1, ("vraiu_halt_output: disable interrupt\n"))
451 vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AIUINT_INTSEND, 0);
452 DPRINTFN(1, ("vraiu_halt_output: stop output\n"))
453 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SEQ_REG_W, 0);
454 DPRINTFN(1, ("vraiu_halt_output: speaker power off\n"))
455 config_hook_call(CONFIG_HOOK_POWERCONTROL,
456 CONFIG_HOOK_POWERCONTROL_SPEAKER, (void*)0);
457 DPRINTFN(1, ("vraiu_halt_output: Vref off\n"))
458 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCNT_REG_W, 0);
459 DPRINTFN(1, ("vraiu_halt_output: disable DMA\n"))
460 sc->sc_dc->dc_disable(sc->sc_dc);
461 DPRINTFN(1, ("vraiu_halt_output: clock supply stop\n"))
462 sc->sc_cc->cc_clock(sc->sc_cc, VR4102_CMUMSKAIU, 0);
463 sc->sc_intr = NULL;
464 return 0;
465 }
466
467 int
468 vraiu_halt_input(void *self)
469 {
470
471 DPRINTFN(3, ("vraiu_halt_input\n"));
472 /* no input */
473 return ENXIO;
474 }
475
476
477 int
478 vraiu_getdev(void *self, struct audio_device *ret)
479 {
480
481 DPRINTFN(3, ("vraiu_getdev\n"));
482 *ret = aiu_device;
483 return 0;
484 }
485
486 int
487 vraiu_set_port(void *self, mixer_ctrl_t *mc)
488 {
489 struct vraiu_softc *sc;
490
491 DPRINTFN(3, ("vraiu_set_port\n"));
492 sc = self;
493 /* software mixer, 1ch */
494 if (mc->dev == 0) {
495 if (mc->type != AUDIO_MIXER_VALUE)
496 return EINVAL;
497 if (mc->un.value.num_channels != 1)
498 return EINVAL;
499 sc->sc_volume = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO];
500 return 0;
501 }
502
503 return EINVAL;
504 }
505
506 int
507 vraiu_get_port(void *self, mixer_ctrl_t *mc)
508 {
509 struct vraiu_softc *sc;
510
511 DPRINTFN(3, ("vraiu_get_port\n"));
512 sc = self;
513 /* software mixer, 1ch */
514 if (mc->dev == 0) {
515 if (mc->un.value.num_channels != 1)
516 return EINVAL;
517 mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_volume;
518 return 0;
519 }
520
521 return EINVAL;
522 }
523
524 int
525 vraiu_query_devinfo(void *self, mixer_devinfo_t *di)
526 {
527
528 DPRINTFN(3, ("vraiu_query_devinfo\n"));
529 /* software mixer, 1ch */
530 switch (di->index) {
531 case 0: /* inputs.dac mixer value */
532 di->mixer_class = 1;
533 di->next = di->prev = AUDIO_MIXER_LAST;
534 strcpy(di->label.name, AudioNdac);
535 di->type = AUDIO_MIXER_VALUE;
536 di->un.v.num_channels = 1;
537 strcpy(di->un.v.units.name, AudioNvolume);
538 return 0;
539 case 1: /* outputs class */
540 di->mixer_class = 1;
541 di->next = di->prev = AUDIO_MIXER_LAST;
542 strcpy(di->label.name, AudioCinputs);
543 di->type = AUDIO_MIXER_CLASS;
544 return 0;
545 }
546
547 return ENXIO;
548 }
549
550 int
551 vraiu_get_props(void *self)
552 {
553 DPRINTFN(3, ("vraiu_get_props\n"));
554
555 return 0;
556 }
557
558 void
559 vraiu_get_locks(void *self, kmutex_t **intr, kmutex_t **thread)
560 {
561 struct vraiu_softc *sc;
562
563 DPRINTFN(3, ("vraiu_get_locks\n"));
564 sc = self;
565
566 *intr = &sc->sc_intr_lock;
567 *thread = &sc->sc_lock;
568 }
569
570 /* slinear16/mono -> ulinear10/mono with volume */
571 static void
572 vraiu_slinear16_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
573 {
574 short *q;
575
576 DPRINTFN(3, ("vraiu_slinear16_1\n"));
577 q = p;
578 #ifdef DIAGNOSTIC
579 if (n > AUDIO_BUF_SIZE) {
580 printf("%s: output data too large (%d > %d)\n",
581 device_xname(sc->sc_dev), n, AUDIO_BUF_SIZE);
582 n = AUDIO_BUF_SIZE;
583 }
584 #endif
585 n /= 2;
586 while (n--) {
587 int i = *q++;
588 i = i * sc->sc_volume / 255;
589 *dmap++ = (i >> 6) + 0x200;
590 }
591 }
592