1 /* $NetBSD: tms320av110.c,v 1.17 2005/01/15 15:19:52 kent Exp $ */
2
3 /*-
4 * Copyright (c) 1997 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Ignatios Souvatzis.
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 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Machine independent part of TMS320AV110 driver.
41 *
42 * Currently, only minimum support for audio output. For audio/video
43 * synchronization, more is needed.
44 */
45
46 #include <sys/cdefs.h>
47 __KERNEL_RCSID(0, "$NetBSD: tms320av110.c,v 1.17 2005/01/15 15:19:52 kent Exp $");
48
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/kernel.h>
52 #include <sys/device.h>
53 #include <sys/proc.h>
54
55 #include <sys/audioio.h>
56 #include <dev/audio_if.h>
57
58 #include <dev/ic/tms320av110reg.h>
59 #include <dev/ic/tms320av110var.h>
60
61 #include <machine/bus.h>
62
63 int tav_open(void *, int);
64 void tav_close(void *);
65 int tav_drain(void *);
66 int tav_query_encoding(void *, struct audio_encoding *);
67 int tav_set_params(void *, int, int, audio_params_t *, audio_params_t *,
68 stream_filter_list_t *, stream_filter_list_t *);
69 int tav_round_blocksize(void *, int, int, const audio_params_t *);
70 int tav_init_output(void *, void *, int);
71 int tav_start_output(void *, void *, int, void (*)(void *), void *);
72 int tav_start_input(void *, void *, int, void (*)(void *), void *);
73 int tav_halt_output(void *);
74 int tav_halt_input(void *);
75 int tav_speaker_ctl(void *, int);
76 int tav_getdev(void *, struct audio_device *);
77 int tav_setfd(void *, int);
78 int tav_set_port(void *, mixer_ctrl_t *);
79 int tav_get_port(void *, mixer_ctrl_t *);
80 int tav_query_devinfo(void *, mixer_devinfo_t *);
81 int tav_get_props(void *);
82
83 const struct audio_hw_if tav_audio_if = {
84 tav_open,
85 tav_close,
86 0 /* tav_drain*/, /* optional */
87 tav_query_encoding,
88 tav_set_params,
89 tav_round_blocksize,
90 0 /* commit_settings */, /* optional */
91 tav_init_output, /* optional */
92 0 /* tav_init_input */, /* optional */
93 tav_start_output,
94 tav_start_input,
95 tav_halt_output,
96 tav_halt_input,
97 tav_speaker_ctl, /* optional */
98 tav_getdev,
99 0 /* setfd */, /* optional */
100 tav_set_port,
101 tav_get_port,
102 tav_query_devinfo,
103 0 /* alloc */, /* optional */
104 0 /* free */, /* optional */
105 0 /* round_buffersize */, /* optional */
106 0 /* mappage */, /* optional */
107 tav_get_props,
108 0 /* dev_ioctl */ /* optional */
109 };
110
111 void
112 tms320av110_attach_mi(struct tav_softc *sc)
113 {
114 bus_space_tag_t iot;
115 bus_space_handle_t ioh;
116
117 iot = sc->sc_iot;
118 ioh = sc->sc_ioh;
119 tav_write_byte(iot, ioh, TAV_RESET, 1);
120 while (tav_read_byte(iot, ioh, TAV_RESET))
121 delay(250);
122
123 tav_write_byte(iot, ioh, TAV_PCM_ORD, sc->sc_pcm_ord);
124 tav_write_byte(iot, ioh, TAV_PCM_18, sc->sc_pcm_18);
125 tav_write_byte(iot, ioh, TAV_DIF, sc->sc_dif);
126 tav_write_byte(iot, ioh, TAV_PCM_DIV, sc->sc_pcm_div);
127
128 printf(": chip rev. %d, %d bytes buffer\n",
129 tav_read_byte(iot, ioh, TAV_VERSION),
130 TAV_DRAM_SIZE(tav_read_byte(iot, ioh, TAV_DRAM_EXT)));
131
132 tav_write_byte(iot, ioh, TAV_AUD_ID_EN, 0);
133 tav_write_byte(iot, ioh, TAV_SKIP, 0);
134 tav_write_byte(iot, ioh, TAV_REPEAT, 0);
135 tav_write_byte(iot, ioh, TAV_MUTE, 0);
136 tav_write_byte(iot, ioh, TAV_PLAY, 1);
137 tav_write_byte(iot, ioh, TAV_SYNC_ECM, 0);
138 tav_write_byte(iot, ioh, TAV_CRC_ECM, 0);
139 tav_write_byte(iot, ioh, TAV_ATTEN_L, 0);
140 tav_write_byte(iot, ioh, TAV_ATTEN_R, 0);
141 tav_write_short(iot, ioh, TAV_FREE_FORM, 0);
142 tav_write_byte(iot, ioh, TAV_SIN_EN, 0);
143 tav_write_byte(iot, ioh, TAV_SYNC_ECM, TAV_ECM_REPEAT);
144 tav_write_byte(iot, ioh, TAV_CRC_ECM, TAV_ECM_REPEAT);
145
146 audio_attach_mi(&tav_audio_if, sc, &sc->sc_dev);
147 }
148
149 int
150 tms320av110_intr(void *p)
151 {
152 struct tav_softc *sc;
153 uint16_t intlist;
154
155 sc = p;
156 intlist = tav_read_short(sc->sc_iot, sc->sc_ioh, TAV_INTR)
157 /* & tav_read_short(sc->sc_iot, sc->sc_ioh, TAV_INTR_EN)*/;
158
159 if (!intlist)
160 return 0;
161
162 /* ack now, so that we don't miss later interrupts */
163 if (sc->sc_intack)
164 (sc->sc_intack)(sc);
165
166 if (intlist & TAV_INTR_LOWWATER) {
167 (*sc->sc_intr)(sc->sc_intrarg);
168 }
169
170 if (intlist & TAV_INTR_PCM_OUTPUT_UNDERFLOW) {
171 wakeup(sc);
172 }
173
174 return 1;
175 }
176
177 struct audio_encoding tav_encodings[] = {
178 {0, AudioEmpeg_l2_stream, AUDIO_ENCODING_MPEG_L2_STREAM, 1, 0,},
179 {1, AudioEmpeg_l2_packets, AUDIO_ENCODING_MPEG_L2_PACKETS, 1, 0,},
180 {2, AudioEmpeg_l2_system, AUDIO_ENCODING_MPEG_L2_SYSTEM, 1, 0,},
181 {3, AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 16, 0,},
182 };
183
184 int
185 tav_open(void *hdl, int flags)
186 {
187
188 /* dummy */
189 return 0;
190 }
191
192 void
193 tav_close(void *hdl)
194 {
195 struct tav_softc *sc;
196 bus_space_tag_t iot;
197 bus_space_handle_t ioh;
198
199 sc = hdl;
200 iot = sc->sc_iot;
201 ioh = sc->sc_ioh;
202
203 /* re"start" chip, also clears interrupts and interrupt enable */
204 tav_write_short(iot, ioh, TAV_INTR_EN, 0);
205 if (sc->sc_intack)
206 (*sc->sc_intack)(sc);
207 }
208
209 int
210 tav_drain(void *hdl)
211 {
212 struct tav_softc *sc;
213 bus_space_tag_t iot;
214 bus_space_handle_t ioh;
215 u_int16_t mask;
216
217 sc = hdl;
218 iot = sc->sc_iot;
219 ioh = sc->sc_ioh;
220
221 /*
222 * tsleep waiting for underflow interrupt.
223 */
224 if (tav_read_short(iot, ioh, TAV_BUFF)) {
225 mask = tav_read_short(iot, ioh, TAV_INTR_EN);
226 tav_write_short(iot, ioh, TAV_INTR_EN,
227 mask|TAV_INTR_PCM_OUTPUT_UNDERFLOW);
228
229 /* still more than zero? */
230 if (tav_read_short(iot, ioh, TAV_BUFF))
231 (void)tsleep(sc, PCATCH, "tavdrain", 32*hz);
232
233 /* can be really that long for mpeg */
234
235 mask = tav_read_short(iot, ioh, TAV_INTR_EN);
236 tav_write_short(iot, ioh, TAV_INTR_EN,
237 mask & ~TAV_INTR_PCM_OUTPUT_UNDERFLOW);
238 }
239
240 return 0;
241 }
242
243 int
244 tav_query_encoding(void *hdl, struct audio_encoding *ae)
245 {
246 struct tav_softc *sc;
247
248 sc = hdl;
249 if (ae->index >= sizeof(tav_encodings)/sizeof(*ae))
250 return EINVAL;
251
252 *ae = tav_encodings[ae->index];
253
254 return 0;
255 }
256
257 int
258 tav_start_input(void *hdl, void *block, int bsize,
259 void (*intr)(void *), void *intrarg)
260 {
261
262 return ENOTTY;
263 }
264
265 int
266 tav_halt_input(void *hdl)
267 {
268
269 return ENOTTY;
270 }
271
272 int
273 tav_start_output(void *hdl, void *block, int bsize,
274 void (*intr)(void *), void *intrarg)
275 {
276 struct tav_softc *sc;
277 bus_space_tag_t iot;
278 bus_space_handle_t ioh;
279 uint8_t *ptr;
280 int count;
281
282 sc = hdl;
283 iot = sc->sc_iot;
284 ioh = sc->sc_ioh;
285 ptr = block;
286 count = bsize;
287
288 sc->sc_intr = intr;
289 sc->sc_intrarg = intrarg;
290
291 bus_space_write_multi_1(iot, ioh, TAV_DATAIN, ptr, count);
292 tav_write_short(iot, ioh, TAV_INTR_EN, TAV_INTR_LOWWATER);
293
294 return 0;
295 }
296
297 int
298 tav_init_output(void *hdl, void *buffer, int size)
299 {
300 struct tav_softc *sc;
301 bus_space_tag_t iot;
302 bus_space_handle_t ioh;
303
304 sc = hdl;
305 iot = sc->sc_iot;
306 ioh = sc->sc_ioh;
307
308 tav_write_byte(iot, ioh, TAV_PLAY, 1);
309 tav_write_byte(iot, ioh, TAV_MUTE, 0);
310
311 return 0;
312 }
313
314 int
315 tav_halt_output(void *hdl)
316 {
317 struct tav_softc *sc;
318 bus_space_tag_t iot;
319 bus_space_handle_t ioh;
320
321 sc = hdl;
322 iot = sc->sc_iot;
323 ioh = sc->sc_ioh;
324
325 tav_write_byte(iot, ioh, TAV_PLAY, 0);
326
327 return 0;
328 }
329
330 int
331 tav_getdev(void *hdl, struct audio_device *ret)
332 {
333 struct tav_softc *sc;
334 bus_space_tag_t iot;
335 bus_space_handle_t ioh;
336
337 sc = hdl;
338 iot = sc->sc_iot;
339 ioh = sc->sc_ioh;
340
341 strlcpy(ret->name, "tms320av110", sizeof(ret->name));
342 /* guaranteed to be <= 4 in length */
343 snprintf(ret->version, sizeof(ret->version), "%u",
344 tav_read_byte(iot, ioh, TAV_VERSION));
345 strlcpy(ret->config, sc->sc_dev.dv_xname, sizeof(ret->config));
346
347 return 0;
348 }
349
350 int
351 tav_round_blocksize(void *hdl, int size, int mode, const audio_params_t *param)
352 {
353 struct tav_softc *sc;
354 bus_space_tag_t iot;
355 bus_space_handle_t ioh;
356 int maxhalf;
357
358 sc = hdl;
359 iot = sc->sc_iot;
360 ioh = sc->sc_ioh;
361
362 maxhalf = TAV_DRAM_HSIZE(tav_read_byte(iot, ioh, TAV_DRAM_EXT));
363 if (size > maxhalf)
364 size = maxhalf;
365
366 /* XXX should round to 128 bytes limits for audio bypass */
367 size &= ~3;
368
369 tav_write_short(iot, ioh, TAV_BALE_LIM, size/8);
370
371 /* the buffer limits are in units of 4 bytes */
372 return (size);
373 }
374
375 int
376 tav_get_props(void *hdl)
377 {
378 return 0;
379 }
380
381 int
382 tav_set_params(void *hdl, int setmode, int usemode, audio_params_t *p,
383 audio_params_t *r, stream_filter_list_t *pfil, stream_filter_list_t *rfil)
384 {
385 struct tav_softc *sc;
386 bus_space_tag_t iot;
387 bus_space_handle_t ioh;
388
389 sc = hdl;
390 iot = sc->sc_iot;
391 ioh = sc->sc_ioh;
392
393 if (!(setmode & AUMODE_PLAY))
394 return 0;
395
396 if (p->encoding == AUDIO_ENCODING_ULAW)
397 p->encoding = AUDIO_ENCODING_MPEG_L2_STREAM;
398
399 switch(p->encoding) {
400 default:
401 return EINVAL;
402
403 case AUDIO_ENCODING_SLINEAR_BE:
404
405 /* XXX: todo: add 8bit and mono using software */
406 p->precision = 16;
407 p->channels = 2;
408
409 /* XXX: this might depend on the specific board.
410 should be handled by the backend */
411
412 p->sample_rate = 44100;
413
414 bus_space_write_1(iot, ioh, TAV_STR_SEL,
415 TAV_STR_SEL_AUDIO_BYPASS);
416 break;
417
418 /* XXX: later: add ULINEAR, and LE using software encoding */
419
420 case AUDIO_ENCODING_MPEG_L1_STREAM:
421 /* FALLTHROUGH */
422 case AUDIO_ENCODING_MPEG_L2_STREAM:
423 bus_space_write_1(iot, ioh, TAV_STR_SEL,
424 TAV_STR_SEL_MPEG_AUDIO_STREAM);
425 p->sample_rate = 44100;
426 p->precision = 1;
427 break;
428
429 case AUDIO_ENCODING_MPEG_L1_PACKETS:
430 /* FALLTHROUGH */
431 case AUDIO_ENCODING_MPEG_L2_PACKETS:
432 bus_space_write_1(iot, ioh, TAV_STR_SEL,
433 TAV_STR_SEL_MPEG_AUDIO_PACKETS);
434 p->sample_rate = 44100;
435 p->precision = 1;
436 break;
437
438 case AUDIO_ENCODING_MPEG_L1_SYSTEM:
439 /* FALLTHROUGH */
440 case AUDIO_ENCODING_MPEG_L2_SYSTEM:
441 bus_space_write_1(iot, ioh, TAV_STR_SEL,
442 TAV_STR_SEL_MPEG_SYSTEM_STREAM);
443 p->sample_rate = 44100;
444 p->precision = 1;
445 break;
446 }
447 tav_write_byte(iot, ioh, TAV_RESTART, 1);
448 do {
449 delay(10);
450 } while (tav_read_byte(iot, ioh, TAV_RESTART));
451
452 return 0;
453 }
454
455 int
456 tav_set_port(void *hdl, mixer_ctrl_t *mc)
457 {
458 struct tav_softc *sc;
459
460 sc = hdl;
461 /* dummy */
462 return 0;
463 }
464
465 int
466 tav_get_port(void *hdl, mixer_ctrl_t *mc)
467 {
468 struct tav_softc *sc;
469
470 sc = hdl;
471 /* dummy */
472 return 0;
473 }
474
475 int
476 tav_query_devinfo(void *hdl, mixer_devinfo_t *di)
477 {
478 return ENXIO;
479 }
480
481 int
482 tav_speaker_ctl(void *hdl, int value)
483 {
484 struct tav_softc *sc;
485 bus_space_tag_t iot;
486 bus_space_handle_t ioh;
487
488 sc = hdl;
489 iot = sc->sc_iot;
490 ioh = sc->sc_ioh;
491
492 tav_write_byte(iot, ioh, TAV_MUTE, !value);
493
494 return 0;
495 }
Cache object: 2c2a6c49562ded57096303e9548f21ca
|