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