cs4231_ebus.c revision 1.16
1/*	$NetBSD: cs4231_ebus.c,v 1.16 2005/01/11 03:45:17 kent Exp $ */
2
3/*
4 * Copyright (c) 2002 Valeriy E. Ushakov
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 *    derived from this software without specific prior written permission
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__KERNEL_RCSID(0, "$NetBSD: cs4231_ebus.c,v 1.16 2005/01/11 03:45:17 kent Exp $");
32
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/errno.h>
36#include <sys/device.h>
37#include <sys/malloc.h>
38
39#include <machine/autoconf.h>
40#include <machine/cpu.h>
41#include <dev/ebus/ebusreg.h>
42#include <dev/ebus/ebusvar.h>
43
44#include <sys/audioio.h>
45#include <dev/audio_if.h>
46
47#include <dev/ic/ad1848reg.h>
48#include <dev/ic/cs4231reg.h>
49#include <dev/ic/ad1848var.h>
50#include <dev/ic/cs4231var.h>
51
52#ifdef AUDIO_DEBUG
53int cs4231_ebus_debug = 0;
54#define DPRINTF(x)	if (cs4231_ebus_debug) printf x
55#else
56#define DPRINTF(x)
57#endif
58
59
60struct cs4231_ebus_softc {
61	struct cs4231_softc sc_cs4231;
62
63	bus_space_tag_t sc_bt;
64	bus_space_handle_t sc_pdmareg; /* playback DMA */
65	bus_space_handle_t sc_cdmareg; /* record DMA */
66};
67
68
69void	cs4231_ebus_attach(struct device *, struct device *, void *);
70int	cs4231_ebus_match(struct device *, struct cfdata *, void *);
71
72CFATTACH_DECL(audiocs_ebus, sizeof(struct cs4231_ebus_softc),
73    cs4231_ebus_match, cs4231_ebus_attach, NULL, NULL);
74
75/* audio_hw_if methods specific to ebus DMA */
76static int	cs4231_ebus_round_blocksize(void *, int, int,
77					    const audio_params_t *);
78static int	cs4231_ebus_trigger_output(void *, void *, void *, int,
79					   void (*)(void *), void *,
80					   const audio_params_t *);
81static int	cs4231_ebus_trigger_input(void *, void *, void *, int,
82					  void (*)(void *), void *,
83					  const audio_params_t *);
84static int	cs4231_ebus_halt_output(void *);
85static int	cs4231_ebus_halt_input(void *);
86
87const struct audio_hw_if audiocs_ebus_hw_if = {
88	cs4231_open,
89	cs4231_close,
90	NULL,			/* drain */
91	ad1848_query_encoding,
92	ad1848_set_params,
93	cs4231_ebus_round_blocksize,
94	ad1848_commit_settings,
95	NULL,			/* init_output */
96	NULL,			/* init_input */
97	NULL,			/* start_output */
98	NULL,			/* start_input */
99	cs4231_ebus_halt_output,
100	cs4231_ebus_halt_input,
101	NULL,			/* speaker_ctl */
102	cs4231_getdev,
103	NULL,			/* setfd */
104	cs4231_set_port,
105	cs4231_get_port,
106	cs4231_query_devinfo,
107	cs4231_malloc,
108	cs4231_free,
109	NULL,			/* round_buffersize */
110	NULL,			/* mappage */
111	cs4231_get_props,
112	cs4231_ebus_trigger_output,
113	cs4231_ebus_trigger_input,
114	NULL,			/* dev_ioctl */
115};
116
117#ifdef AUDIO_DEBUG
118static void	cs4231_ebus_regdump(char *, struct cs4231_ebus_softc *);
119#endif
120
121static int	cs4231_ebus_dma_reset(bus_space_tag_t, bus_space_handle_t);
122static int	cs4231_ebus_trigger_transfer(struct cs4231_softc *,
123			struct cs_transfer *,
124			bus_space_tag_t, bus_space_handle_t,
125			int, void *, void *, int, void (*)(void *), void *,
126			const audio_params_t *);
127static void	cs4231_ebus_dma_advance(struct cs_transfer *,
128					bus_space_tag_t, bus_space_handle_t);
129static int	cs4231_ebus_dma_intr(struct cs_transfer *,
130				     bus_space_tag_t, bus_space_handle_t);
131static int	cs4231_ebus_intr(void *);
132
133
134int
135cs4231_ebus_match(parent, cf, aux)
136	struct device *parent;
137	struct cfdata *cf;
138	void *aux;
139{
140	struct ebus_attach_args *ea = aux;
141
142	if (strcmp(ea->ea_name, AUDIOCS_PROM_NAME) == 0)
143		return (1);
144#ifdef __sparc__		/* XXX: Krups */
145	if (strcmp(ea->ea_name, "sound") == 0)
146		return (1);
147#endif
148
149	return (0);
150}
151
152
153void
154cs4231_ebus_attach(parent, self, aux)
155	struct device *parent, *self;
156	void *aux;
157{
158	struct cs4231_ebus_softc *ebsc = (struct cs4231_ebus_softc *)self;
159	struct cs4231_softc *sc = &ebsc->sc_cs4231;
160	struct ebus_attach_args *ea = aux;
161	bus_space_handle_t bh;
162	int i;
163
164	sc->sc_bustag = ebsc->sc_bt = ea->ea_bustag;
165	sc->sc_dmatag = ea->ea_dmatag;
166
167	/*
168	 * These are the register we get from the prom:
169	 *	- CS4231 registers
170	 *	- Playback EBus DMA controller
171	 *	- Capture EBus DMA controller
172	 *	- AUXIO audio register (codec powerdown)
173	 *
174	 * Map my registers in, if they aren't already in virtual
175	 * address space.
176	 */
177	if (bus_space_map(ea->ea_bustag, EBUS_ADDR_FROM_REG(&ea->ea_reg[0]),
178		ea->ea_reg[0].size, 0, &bh) != 0) {
179		printf(": unable to map registers\n");
180		return;
181	}
182
183	/* XXX: map playback DMA registers (we just know where they are) */
184	if (bus_space_map(ea->ea_bustag,
185			  BUS_ADDR(0x14, 0x702000), /* XXX: magic num */
186			  EBUS_DMAC_SIZE,
187			  0, &ebsc->sc_pdmareg) != 0)
188	{
189		printf(": unable to map playback DMA registers\n");
190		return;
191	}
192
193	/* XXX: map capture DMA registers (we just know where they are) */
194	if (bus_space_map(ea->ea_bustag,
195			  BUS_ADDR(0x14, 0x704000), /* XXX: magic num */
196			  EBUS_DMAC_SIZE,
197			  0, &ebsc->sc_cdmareg) != 0)
198	{
199		printf(": unable to map capture DMA registers\n");
200		return;
201	}
202
203	/* establish interrupt channels */
204	for (i = 0; i < ea->ea_nintr; ++i)
205		bus_intr_establish(ea->ea_bustag,
206				   ea->ea_intr[i], IPL_AUDIO,
207				   cs4231_ebus_intr, ebsc);
208
209	cs4231_common_attach(sc, bh);
210	printf("\n");
211
212	/* XXX: todo: move to cs4231_common_attach, pass hw_if as arg? */
213	audio_attach_mi(&audiocs_ebus_hw_if, sc, &sc->sc_ad1848.sc_dev);
214}
215
216
217static int
218cs4231_ebus_round_blocksize(addr, blk, mode, param)
219	void *addr;
220	int blk;
221	int mode;
222	const audio_params_t *param;
223{
224
225	/* we want to use DMA burst size of 16 words */
226	return (blk & -64);
227}
228
229
230#ifdef AUDIO_DEBUG
231static void
232cs4231_ebus_regdump(label, ebsc)
233	char *label;
234	struct cs4231_ebus_softc *ebsc;
235{
236	/* char bits[128]; */
237
238	printf("cs4231regdump(%s): regs:", label);
239	/* XXX: dump ebus DMA and aux registers */
240	ad1848_dump_regs(&ebsc->sc_cs4231.sc_ad1848);
241}
242#endif /* AUDIO_DEBUG */
243
244
245/* XXX: nothing CS4231-specific in this code... */
246static int
247cs4231_ebus_dma_reset(dt, dh)
248	bus_space_tag_t dt;
249	bus_space_handle_t dh;
250{
251	u_int32_t csr;
252	int timo;
253
254	/* reset, also clear TC, just in case */
255	bus_space_write_4(dt, dh, EBUS_DMAC_DCSR, EBDMA_RESET | EBDMA_TC);
256
257	for (timo = 50000; timo != 0; --timo) {
258		csr = bus_space_read_4(dt, dh, EBUS_DMAC_DCSR);
259		if ((csr & (EBDMA_CYC_PEND | EBDMA_DRAIN)) == 0)
260			break;
261	}
262
263	if (timo == 0) {
264		char bits[128];
265
266		printf("cs4231_ebus_dma_reset: timed out: csr=%s\n",
267		       bitmask_snprintf(csr, EBUS_DCSR_BITS,
268					bits, sizeof(bits)));
269		return (ETIMEDOUT);
270	}
271
272	bus_space_write_4(dt, dh, EBUS_DMAC_DCSR, csr & ~EBDMA_RESET);
273	return (0);
274}
275
276
277static void
278cs4231_ebus_dma_advance(t, dt, dh)
279	struct cs_transfer *t;
280	bus_space_tag_t dt;
281	bus_space_handle_t dh;
282{
283	bus_addr_t dmaaddr;
284	bus_size_t dmasize;
285
286	cs4231_transfer_advance(t, &dmaaddr, &dmasize);
287
288	bus_space_write_4(dt, dh, EBUS_DMAC_DNBR, (u_int32_t)dmasize);
289	bus_space_write_4(dt, dh, EBUS_DMAC_DNAR, (u_int32_t)dmaaddr);
290}
291
292
293/*
294 * Trigger transfer "t" using DMA controller at "dt"/"dh".
295 * "iswrite" defines direction of the transfer.
296 */
297static int
298cs4231_ebus_trigger_transfer(sc, t, dt, dh, iswrite,
299			     start, end, blksize,
300			     intr, arg, param)
301	struct cs4231_softc *sc;
302	struct cs_transfer *t;
303	bus_space_tag_t dt;
304	bus_space_handle_t dh;
305	int iswrite;
306	void *start, *end;
307	int blksize;
308	void (*intr)(void *);
309	void *arg;
310	const audio_params_t *param;
311{
312	u_int32_t csr;
313	bus_addr_t dmaaddr;
314	bus_size_t dmasize;
315	int ret;
316
317	ret = cs4231_transfer_init(sc, t, &dmaaddr, &dmasize,
318				   start, end, blksize, intr, arg);
319	if (ret != 0)
320		return (ret);
321
322	ret = cs4231_ebus_dma_reset(dt, dh);
323	if (ret != 0)
324		return (ret);
325
326	csr = bus_space_read_4(dt, dh, EBUS_DMAC_DCSR);
327	bus_space_write_4(dt, dh, EBUS_DMAC_DCSR,
328			  csr | EBDMA_EN_NEXT | (iswrite ? EBDMA_WRITE : 0)
329			  | EBDMA_EN_DMA | EBDMA_EN_CNT | EBDMA_INT_EN
330			  | EBDMA_BURST_SIZE_16);
331
332	/* first load: propagated to DACR/DBCR */
333	bus_space_write_4(dt, dh, EBUS_DMAC_DNBR, (u_int32_t)dmasize);
334	bus_space_write_4(dt, dh, EBUS_DMAC_DNAR, (u_int32_t)dmaaddr);
335
336	/* next load: goes to DNAR/DNBR */
337	cs4231_ebus_dma_advance(t, dt, dh);
338
339	return (0);
340}
341
342
343static int
344cs4231_ebus_trigger_output(addr, start, end, blksize, intr, arg, param)
345	void *addr;
346	void *start, *end;
347	int blksize;
348	void (*intr)(void *);
349	void *arg;
350	const audio_params_t *param;
351{
352	struct cs4231_ebus_softc *ebsc = addr;
353	struct cs4231_softc *sc = &ebsc->sc_cs4231;
354	int cfg, ret;
355
356	ret = cs4231_ebus_trigger_transfer(sc, &sc->sc_playback,
357					   ebsc->sc_bt, ebsc->sc_pdmareg,
358					   0, /* iswrite */
359					   start, end, blksize,
360					   intr, arg, param);
361	if (ret != 0)
362		return (ret);
363
364	ad_write(&sc->sc_ad1848, SP_LOWER_BASE_COUNT, 0xff);
365	ad_write(&sc->sc_ad1848, SP_UPPER_BASE_COUNT, 0xff);
366
367	cfg = ad_read(&sc->sc_ad1848, SP_INTERFACE_CONFIG);
368	ad_write(&sc->sc_ad1848, SP_INTERFACE_CONFIG, cfg | PLAYBACK_ENABLE);
369
370	return (0);
371}
372
373
374static int
375cs4231_ebus_trigger_input(addr, start, end, blksize, intr, arg, param)
376	void *addr;
377	void *start, *end;
378	int blksize;
379	void (*intr)(void *);
380	void *arg;
381	const audio_params_t *param;
382{
383	struct cs4231_ebus_softc *ebsc = addr;
384	struct cs4231_softc *sc = &ebsc->sc_cs4231;
385	int cfg, ret;
386
387	ret = cs4231_ebus_trigger_transfer(sc, &sc->sc_capture,
388					   ebsc->sc_bt, ebsc->sc_cdmareg,
389					   1, /* iswrite */
390					   start, end, blksize,
391					   intr, arg, param);
392	if (ret != 0)
393		return (ret);
394
395	ad_write(&sc->sc_ad1848, CS_LOWER_REC_CNT, 0xff);
396	ad_write(&sc->sc_ad1848, CS_UPPER_REC_CNT, 0xff);
397
398	cfg = ad_read(&sc->sc_ad1848, SP_INTERFACE_CONFIG);
399	ad_write(&sc->sc_ad1848, SP_INTERFACE_CONFIG, cfg | CAPTURE_ENABLE);
400
401	return (0);
402}
403
404
405static int
406cs4231_ebus_halt_output(addr)
407	void *addr;
408{
409	struct cs4231_ebus_softc *ebsc = addr;
410	struct cs4231_softc *sc = &ebsc->sc_cs4231;
411	u_int32_t csr;
412	int cfg;
413
414	sc->sc_playback.t_active = 0;
415
416	csr = bus_space_read_4(ebsc->sc_bt, ebsc->sc_pdmareg, EBUS_DMAC_DCSR);
417	bus_space_write_4(ebsc->sc_bt, ebsc->sc_pdmareg, EBUS_DMAC_DCSR,
418			  csr & ~EBDMA_EN_DMA);
419
420	cfg = ad_read(&sc->sc_ad1848, SP_INTERFACE_CONFIG);
421	ad_write(&sc->sc_ad1848, SP_INTERFACE_CONFIG,
422		 cfg & ~PLAYBACK_ENABLE);
423
424	return (0);
425}
426
427
428static int
429cs4231_ebus_halt_input(addr)
430	void *addr;
431{
432	struct cs4231_ebus_softc *ebsc = addr;
433	struct cs4231_softc *sc = &ebsc->sc_cs4231;
434	u_int32_t csr;
435	int cfg;
436
437	sc->sc_capture.t_active = 0;
438
439	csr = bus_space_read_4(ebsc->sc_bt, ebsc->sc_cdmareg, EBUS_DMAC_DCSR);
440	bus_space_write_4(ebsc->sc_bt, ebsc->sc_cdmareg, EBUS_DMAC_DCSR,
441			  csr & ~EBDMA_EN_DMA);
442
443	cfg = ad_read(&sc->sc_ad1848, SP_INTERFACE_CONFIG);
444	ad_write(&sc->sc_ad1848, SP_INTERFACE_CONFIG,
445		 cfg & ~CAPTURE_ENABLE);
446
447	return (0);
448}
449
450
451static int
452cs4231_ebus_dma_intr(t, dt, dh)
453	struct cs_transfer *t;
454	bus_space_tag_t dt;
455	bus_space_handle_t dh;
456{
457	u_int32_t csr;
458#ifdef AUDIO_DEBUG
459	char bits[128];
460#endif
461
462	/* read DMA status, clear TC bit by writing it back */
463	csr = bus_space_read_4(dt, dh, EBUS_DMAC_DCSR);
464	bus_space_write_4(dt, dh, EBUS_DMAC_DCSR, csr);
465	DPRINTF(("audiocs: %s dcsr=%s\n", t->t_name,
466		 bitmask_snprintf(csr, EBUS_DCSR_BITS, bits, sizeof(bits))));
467
468	if (csr & EBDMA_ERR_PEND) {
469		++t->t_ierrcnt.ev_count;
470		printf("audiocs: %s DMA error, resetting\n", t->t_name);
471		cs4231_ebus_dma_reset(dt, dh);
472		/* how to notify audio(9)??? */
473		return (1);
474	}
475
476	if ((csr & EBDMA_INT_PEND) == 0)
477		return (0);
478
479	++t->t_intrcnt.ev_count;
480
481	if ((csr & EBDMA_TC) == 0) { /* can this happen? */
482		printf("audiocs: %s INT_PEND but !TC\n", t->t_name);
483		return (1);
484	}
485
486	if (!t->t_active)
487		return (1);
488
489	cs4231_ebus_dma_advance(t, dt, dh);
490
491	/* call audio(9) framework while DMA is chugging along */
492	if (t->t_intr != NULL)
493		(*t->t_intr)(t->t_arg);
494	return (1);
495}
496
497
498static int
499cs4231_ebus_intr(arg)
500	void *arg;
501{
502	struct cs4231_ebus_softc *ebsc = arg;
503	struct cs4231_softc *sc = &ebsc->sc_cs4231;
504	int status;
505	int ret;
506#ifdef AUDIO_DEBUG
507	char bits[128];
508#endif
509
510	status = ADREAD(&sc->sc_ad1848, AD1848_STATUS);
511
512#ifdef AUDIO_DEBUG
513	if (cs4231_ebus_debug > 1)
514		cs4231_ebus_regdump("audiointr", ebsc);
515
516	DPRINTF(("%s: status: %s\n", sc->sc_ad1848.sc_dev.dv_xname,
517		 bitmask_snprintf(status, AD_R2_BITS, bits, sizeof(bits))));
518#endif
519
520	if (status & INTERRUPT_STATUS) {
521#ifdef AUDIO_DEBUG
522		int reason;
523
524		reason = ad_read(&sc->sc_ad1848, CS_IRQ_STATUS);
525		DPRINTF(("%s: i24: %s\n", sc->sc_ad1848.sc_dev.dv_xname,
526		  bitmask_snprintf(reason, CS_I24_BITS, bits, sizeof(bits))));
527#endif
528		/* clear interrupt from ad1848 */
529		ADWRITE(&sc->sc_ad1848, AD1848_STATUS, 0);
530	}
531
532	ret = 0;
533
534	if (cs4231_ebus_dma_intr(&sc->sc_capture,
535				 ebsc->sc_bt, ebsc->sc_cdmareg) != 0)
536	{
537		++sc->sc_intrcnt.ev_count;
538		ret = 1;
539	}
540
541	if (cs4231_ebus_dma_intr(&sc->sc_playback,
542				 ebsc->sc_bt, ebsc->sc_pdmareg) != 0)
543	{
544		++sc->sc_intrcnt.ev_count;
545		ret = 1;
546	}
547
548	return (ret);
549}
550