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