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