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