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