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