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