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