xref: /netbsd-src/sys/dev/ic/tms320av110.c (revision aaf4ece63a859a04e37cf3a7229b5fab0157cc06)
1 /*	$NetBSD: tms320av110.c,v 1.18 2005/12/11 12:21:28 christos 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.18 2005/12/11 12:21:28 christos 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 }
496