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