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