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