cs4231_ebus.c revision 1.22
1/* $NetBSD: cs4231_ebus.c,v 1.22 2006/10/15 19:43:45 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.22 2006/10/15 19:43:45 martin 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 NULL, /* powerstate */ 116}; 117 118#ifdef AUDIO_DEBUG 119static void cs4231_ebus_regdump(char *, struct cs4231_ebus_softc *); 120#endif 121 122static int cs4231_ebus_dma_reset(bus_space_tag_t, bus_space_handle_t); 123static int cs4231_ebus_trigger_transfer(struct cs4231_softc *, 124 struct cs_transfer *, 125 bus_space_tag_t, bus_space_handle_t, 126 int, void *, void *, int, void (*)(void *), void *, 127 const audio_params_t *); 128static void cs4231_ebus_dma_advance(struct cs_transfer *, 129 bus_space_tag_t, bus_space_handle_t); 130static int cs4231_ebus_dma_intr(struct cs_transfer *, 131 bus_space_tag_t, bus_space_handle_t); 132static int cs4231_ebus_intr(void *); 133 134 135int 136cs4231_ebus_match(struct device *parent, struct cfdata *cf, void *aux) 137{ 138 struct ebus_attach_args *ea; 139 140 ea = aux; 141 if (strcmp(ea->ea_name, AUDIOCS_PROM_NAME) == 0) 142 return 1; 143#ifdef __sparc__ /* XXX: Krups */ 144 if (strcmp(ea->ea_name, "sound") == 0) 145 return 1; 146#endif 147 148 return 0; 149} 150 151 152void 153cs4231_ebus_attach(struct device *parent, struct device *self, void *aux) 154{ 155 struct cs4231_ebus_softc *ebsc; 156 struct cs4231_softc *sc; 157 struct ebus_attach_args *ea; 158 bus_space_handle_t bh; 159 int i; 160 161 ebsc = device_private(self); 162 sc = &ebsc->sc_cs4231; 163 ea = aux; 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(void *addr, int blk, int mode, 219 const audio_params_t *param) 220{ 221 222 /* we want to use DMA burst size of 16 words */ 223 return blk & -64; 224} 225 226 227#ifdef AUDIO_DEBUG 228static void 229cs4231_ebus_regdump(char *label, struct cs4231_ebus_softc *ebsc) 230{ 231 /* char bits[128]; */ 232 233 printf("cs4231regdump(%s): regs:", label); 234 /* XXX: dump ebus DMA and aux registers */ 235 ad1848_dump_regs(&ebsc->sc_cs4231.sc_ad1848); 236} 237#endif /* AUDIO_DEBUG */ 238 239 240/* XXX: nothing CS4231-specific in this code... */ 241static int 242cs4231_ebus_dma_reset(bus_space_tag_t dt, bus_space_handle_t dh) 243{ 244 u_int32_t csr; 245 int timo; 246 247 /* reset, also clear TC, just in case */ 248 bus_space_write_4(dt, dh, EBUS_DMAC_DCSR, EBDMA_RESET | EBDMA_TC); 249 250 for (timo = 50000; timo != 0; --timo) { 251 csr = bus_space_read_4(dt, dh, EBUS_DMAC_DCSR); 252 if ((csr & (EBDMA_CYC_PEND | EBDMA_DRAIN)) == 0) 253 break; 254 } 255 256 if (timo == 0) { 257 char bits[128]; 258 259 printf("cs4231_ebus_dma_reset: timed out: csr=%s\n", 260 bitmask_snprintf(csr, EBUS_DCSR_BITS, 261 bits, sizeof(bits))); 262 return ETIMEDOUT; 263 } 264 265 bus_space_write_4(dt, dh, EBUS_DMAC_DCSR, csr & ~EBDMA_RESET); 266 return 0; 267} 268 269 270static void 271cs4231_ebus_dma_advance(struct cs_transfer *t, bus_space_tag_t dt, 272 bus_space_handle_t dh) 273{ 274 bus_addr_t dmaaddr; 275 bus_size_t dmasize; 276 277 cs4231_transfer_advance(t, &dmaaddr, &dmasize); 278 279 bus_space_write_4(dt, dh, EBUS_DMAC_DNBR, (u_int32_t)dmasize); 280 bus_space_write_4(dt, dh, EBUS_DMAC_DNAR, (u_int32_t)dmaaddr); 281} 282 283 284/* 285 * Trigger transfer "t" using DMA controller at "dt"/"dh". 286 * "iswrite" defines direction of the transfer. 287 */ 288static int 289cs4231_ebus_trigger_transfer( 290 struct cs4231_softc *sc, 291 struct cs_transfer *t, 292 bus_space_tag_t dt, 293 bus_space_handle_t dh, 294 int iswrite, 295 void *start, void *end, 296 int blksize, 297 void (*intr)(void *), 298 void *arg, 299 const audio_params_t *param) 300{ 301 uint32_t csr; 302 bus_addr_t dmaaddr; 303 bus_size_t dmasize; 304 int ret; 305 306 ret = cs4231_transfer_init(sc, t, &dmaaddr, &dmasize, 307 start, end, blksize, intr, arg); 308 if (ret != 0) 309 return ret; 310 311 ret = cs4231_ebus_dma_reset(dt, dh); 312 if (ret != 0) 313 return ret; 314 315 csr = bus_space_read_4(dt, dh, EBUS_DMAC_DCSR); 316 bus_space_write_4(dt, dh, EBUS_DMAC_DCSR, 317 csr | EBDMA_EN_NEXT | (iswrite ? EBDMA_WRITE : 0) 318 | EBDMA_EN_DMA | EBDMA_EN_CNT | EBDMA_INT_EN 319 | EBDMA_BURST_SIZE_16); 320 321 /* first load: propagated to DACR/DBCR */ 322 bus_space_write_4(dt, dh, EBUS_DMAC_DNBR, (uint32_t)dmasize); 323 bus_space_write_4(dt, dh, EBUS_DMAC_DNAR, (uint32_t)dmaaddr); 324 325 /* next load: goes to DNAR/DNBR */ 326 cs4231_ebus_dma_advance(t, dt, dh); 327 328 return 0; 329} 330 331 332static int 333cs4231_ebus_trigger_output(void *addr, void *start, void *end, int blksize, 334 void (*intr)(void *), void *arg, 335 const audio_params_t *param) 336{ 337 struct cs4231_ebus_softc *ebsc; 338 struct cs4231_softc *sc; 339 int cfg, ret; 340 341 ebsc = addr; 342 sc = &ebsc->sc_cs4231; 343 ret = cs4231_ebus_trigger_transfer(sc, &sc->sc_playback, 344 ebsc->sc_bt, ebsc->sc_pdmareg, 345 0, /* iswrite */ 346 start, end, blksize, 347 intr, arg, param); 348 if (ret != 0) 349 return ret; 350 351 ad_write(&sc->sc_ad1848, SP_LOWER_BASE_COUNT, 0xff); 352 ad_write(&sc->sc_ad1848, SP_UPPER_BASE_COUNT, 0xff); 353 354 cfg = ad_read(&sc->sc_ad1848, SP_INTERFACE_CONFIG); 355 ad_write(&sc->sc_ad1848, SP_INTERFACE_CONFIG, cfg | PLAYBACK_ENABLE); 356 357 return 0; 358} 359 360 361static int 362cs4231_ebus_trigger_input(void *addr, void *start, void *end, int blksize, 363 void (*intr)(void *), void *arg, 364 const audio_params_t *param) 365{ 366 struct cs4231_ebus_softc *ebsc; 367 struct cs4231_softc *sc; 368 int cfg, ret; 369 370 ebsc = addr; 371 sc = &ebsc->sc_cs4231; 372 ret = cs4231_ebus_trigger_transfer(sc, &sc->sc_capture, 373 ebsc->sc_bt, ebsc->sc_cdmareg, 374 1, /* iswrite */ 375 start, end, blksize, 376 intr, arg, param); 377 if (ret != 0) 378 return ret; 379 380 ad_write(&sc->sc_ad1848, CS_LOWER_REC_CNT, 0xff); 381 ad_write(&sc->sc_ad1848, CS_UPPER_REC_CNT, 0xff); 382 383 cfg = ad_read(&sc->sc_ad1848, SP_INTERFACE_CONFIG); 384 ad_write(&sc->sc_ad1848, SP_INTERFACE_CONFIG, cfg | CAPTURE_ENABLE); 385 386 return 0; 387} 388 389 390static int 391cs4231_ebus_halt_output(void *addr) 392{ 393 struct cs4231_ebus_softc *ebsc; 394 struct cs4231_softc *sc; 395 u_int32_t csr; 396 int cfg; 397 398 ebsc = addr; 399 sc = &ebsc->sc_cs4231; 400 sc->sc_playback.t_active = 0; 401 402 csr = bus_space_read_4(ebsc->sc_bt, ebsc->sc_pdmareg, EBUS_DMAC_DCSR); 403 bus_space_write_4(ebsc->sc_bt, ebsc->sc_pdmareg, EBUS_DMAC_DCSR, 404 csr & ~EBDMA_EN_DMA); 405 406 cfg = ad_read(&sc->sc_ad1848, SP_INTERFACE_CONFIG); 407 ad_write(&sc->sc_ad1848, SP_INTERFACE_CONFIG, 408 cfg & ~PLAYBACK_ENABLE); 409 410 return 0; 411} 412 413 414static int 415cs4231_ebus_halt_input(void *addr) 416{ 417 struct cs4231_ebus_softc *ebsc; 418 struct cs4231_softc *sc; 419 uint32_t csr; 420 int cfg; 421 422 ebsc = addr; 423 sc = &ebsc->sc_cs4231; 424 sc->sc_capture.t_active = 0; 425 426 csr = bus_space_read_4(ebsc->sc_bt, ebsc->sc_cdmareg, EBUS_DMAC_DCSR); 427 bus_space_write_4(ebsc->sc_bt, ebsc->sc_cdmareg, EBUS_DMAC_DCSR, 428 csr & ~EBDMA_EN_DMA); 429 430 cfg = ad_read(&sc->sc_ad1848, SP_INTERFACE_CONFIG); 431 ad_write(&sc->sc_ad1848, SP_INTERFACE_CONFIG, 432 cfg & ~CAPTURE_ENABLE); 433 434 return 0; 435} 436 437 438static int 439cs4231_ebus_dma_intr(struct cs_transfer *t, bus_space_tag_t dt, 440 bus_space_handle_t dh) 441{ 442 uint32_t csr; 443#ifdef AUDIO_DEBUG 444 char bits[128]; 445#endif 446 447 /* read DMA status, clear TC bit by writing it back */ 448 csr = bus_space_read_4(dt, dh, EBUS_DMAC_DCSR); 449 bus_space_write_4(dt, dh, EBUS_DMAC_DCSR, csr); 450 DPRINTF(("audiocs: %s dcsr=%s\n", t->t_name, 451 bitmask_snprintf(csr, EBUS_DCSR_BITS, bits, sizeof(bits)))); 452 453 if (csr & EBDMA_ERR_PEND) { 454 ++t->t_ierrcnt.ev_count; 455 printf("audiocs: %s DMA error, resetting\n", t->t_name); 456 cs4231_ebus_dma_reset(dt, dh); 457 /* how to notify audio(9)??? */ 458 return 1; 459 } 460 461 if ((csr & EBDMA_INT_PEND) == 0) 462 return 0; 463 464 ++t->t_intrcnt.ev_count; 465 466 if ((csr & EBDMA_TC) == 0) { /* can this happen? */ 467 printf("audiocs: %s INT_PEND but !TC\n", t->t_name); 468 return 1; 469 } 470 471 if (!t->t_active) 472 return 1; 473 474 cs4231_ebus_dma_advance(t, dt, dh); 475 476 /* call audio(9) framework while DMA is chugging along */ 477 if (t->t_intr != NULL) 478 (*t->t_intr)(t->t_arg); 479 return 1; 480} 481 482 483static int 484cs4231_ebus_intr(void *arg) 485{ 486 struct cs4231_ebus_softc *ebsc; 487 struct cs4231_softc *sc; 488 int status; 489 int ret; 490#ifdef AUDIO_DEBUG 491 char bits[128]; 492#endif 493 494 ebsc = arg; 495 sc = &ebsc->sc_cs4231; 496 status = ADREAD(&sc->sc_ad1848, AD1848_STATUS); 497 498#ifdef AUDIO_DEBUG 499 if (cs4231_ebus_debug > 1) 500 cs4231_ebus_regdump("audiointr", ebsc); 501 502 DPRINTF(("%s: status: %s\n", sc->sc_ad1848.sc_dev.dv_xname, 503 bitmask_snprintf(status, AD_R2_BITS, bits, sizeof(bits)))); 504#endif 505 506 if (status & INTERRUPT_STATUS) { 507#ifdef AUDIO_DEBUG 508 int reason; 509 510 reason = ad_read(&sc->sc_ad1848, CS_IRQ_STATUS); 511 DPRINTF(("%s: i24: %s\n", sc->sc_ad1848.sc_dev.dv_xname, 512 bitmask_snprintf(reason, CS_I24_BITS, bits, sizeof(bits)))); 513#endif 514 /* clear interrupt from ad1848 */ 515 ADWRITE(&sc->sc_ad1848, AD1848_STATUS, 0); 516 } 517 518 ret = 0; 519 520 if (cs4231_ebus_dma_intr(&sc->sc_capture, 521 ebsc->sc_bt, ebsc->sc_cdmareg) != 0) 522 { 523 ++sc->sc_intrcnt.ev_count; 524 ret = 1; 525 } 526 527 if (cs4231_ebus_dma_intr(&sc->sc_playback, 528 ebsc->sc_bt, ebsc->sc_pdmareg) != 0) 529 { 530 ++sc->sc_intrcnt.ev_count; 531 ret = 1; 532 } 533 534 return ret; 535} 536