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