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