atiixp.c revision 167648
1168404Spjd/*- 2168404Spjd * Copyright (c) 2005 Ariff Abdullah <ariff@FreeBSD.org> 3168404Spjd * All rights reserved. 4168404Spjd * 5168404Spjd * Redistribution and use in source and binary forms, with or without 6168404Spjd * modification, are permitted provided that the following conditions 7168404Spjd * are met: 8168404Spjd * 1. Redistributions of source code must retain the above copyright 9168404Spjd * notice, this list of conditions and the following disclaimer. 10168404Spjd * 2. Redistributions in binary form must reproduce the above copyright 11168404Spjd * notice, this list of conditions and the following disclaimer in the 12168404Spjd * documentation and/or other materials provided with the distribution. 13168404Spjd * 14168404Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15168404Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16168404Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17168404Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18168404Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19168404Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20168404Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21168404Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT 22185029Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23168404Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF 24168404Spjd * SUCH DAMAGE. 25168404Spjd */ 26168404Spjd 27168404Spjd/* 28168404Spjd * FreeBSD pcm driver for ATI IXP 150/200/250/300 AC97 controllers 29168404Spjd * 30168404Spjd * Features 31168404Spjd * * 16bit playback / recording 32168404Spjd * * 32bit native playback - yay! 33168404Spjd * * 32bit native recording (seems broken on few hardwares) 34168404Spjd * 35168404Spjd * Issues / TODO: 36168404Spjd * * SPDIF 37168404Spjd * * Support for more than 2 channels. 38168404Spjd * * VRA ? VRM ? DRA ? 39168404Spjd * * 32bit native recording seems broken on few hardwares, most 40168404Spjd * probably because of incomplete VRA/DRA cleanup. 41168404Spjd * 42168404Spjd * 43168404Spjd * Thanks goes to: 44168404Spjd * 45168404Spjd * Shaharil @ SCAN Associates whom relentlessly providing me the 46168404Spjd * mind blowing Acer Ferrari 4002 WLMi with this ATI IXP hardware. 47168404Spjd * 48168404Spjd * Reinoud Zandijk <reinoud@NetBSD.org> (auixp), which this driver is 49168404Spjd * largely based upon although large part of it has been reworked. His 50168404Spjd * driver is the primary reference and pretty much well documented. 51168404Spjd * 52168404Spjd * Takashi Iwai (ALSA snd-atiixp), for register definitions and some 53168404Spjd * random ninja hackery. 54168404Spjd */ 55168404Spjd 56168404Spjd#include <dev/sound/pcm/sound.h> 57168404Spjd#include <dev/sound/pcm/ac97.h> 58168404Spjd 59208372Smm#include <dev/pci/pcireg.h> 60208372Smm#include <dev/pci/pcivar.h> 61168404Spjd#include <sys/sysctl.h> 62168404Spjd#include <sys/endian.h> 63168404Spjd 64168404Spjd#include <dev/sound/pci/atiixp.h> 65168404Spjd 66168404SpjdSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/atiixp.c 167648 2007-03-16 17:18:17Z ariff $"); 67168404Spjd 68168404Spjd#define ATI_IXP_DMA_RETRY_MAX 100 69168404Spjd 70168404Spjd#define ATI_IXP_BUFSZ_MIN 4096 71168404Spjd#define ATI_IXP_BUFSZ_MAX 65536 72168404Spjd#define ATI_IXP_BUFSZ_DEFAULT 16384 73168404Spjd 74168404Spjd#define ATI_IXP_BLK_MIN 32 75168404Spjd#define ATI_IXP_BLK_ALIGN (~(ATI_IXP_BLK_MIN - 1)) 76168404Spjd 77168404Spjdstruct atiixp_dma_op { 78168404Spjd volatile uint32_t addr; 79168404Spjd volatile uint16_t status; 80168404Spjd volatile uint16_t size; 81168404Spjd volatile uint32_t next; 82168404Spjd}; 83168404Spjd 84168404Spjdstruct atiixp_info; 85168404Spjd 86168404Spjdstruct atiixp_chinfo { 87168404Spjd struct snd_dbuf *buffer; 88168404Spjd struct pcm_channel *channel; 89208372Smm struct atiixp_info *parent; 90168404Spjd struct atiixp_dma_op *sgd_table; 91168404Spjd bus_addr_t sgd_addr; 92168404Spjd uint32_t enable_bit, flush_bit, linkptr_bit, dt_cur_bit; 93168404Spjd uint32_t blksz, blkcnt; 94168404Spjd uint32_t ptr, prevptr; 95168404Spjd uint32_t fmt; 96168404Spjd int caps_32bit, dir, active; 97168404Spjd}; 98168404Spjd 99168404Spjdstruct atiixp_info { 100168404Spjd device_t dev; 101168404Spjd 102168404Spjd bus_space_tag_t st; 103168404Spjd bus_space_handle_t sh; 104168404Spjd bus_dma_tag_t parent_dmat; 105168404Spjd bus_dma_tag_t sgd_dmat; 106168404Spjd bus_dmamap_t sgd_dmamap; 107168404Spjd bus_addr_t sgd_addr; 108168404Spjd 109168404Spjd struct resource *reg, *irq; 110168404Spjd int regtype, regid, irqid; 111168404Spjd void *ih; 112168404Spjd struct ac97_info *codec; 113168404Spjd 114168404Spjd struct atiixp_chinfo pch; 115168404Spjd struct atiixp_chinfo rch; 116168404Spjd struct atiixp_dma_op *sgd_table; 117168404Spjd struct intr_config_hook delayed_attach; 118168404Spjd 119168404Spjd uint32_t bufsz; 120168404Spjd uint32_t codec_not_ready_bits, codec_idx, codec_found; 121168404Spjd uint32_t blkcnt; 122168404Spjd int registered_channels; 123168404Spjd 124168404Spjd struct mtx *lock; 125168404Spjd struct callout poll_timer; 126168404Spjd int poll_ticks, polling; 127168404Spjd}; 128168404Spjd 129168404Spjd#define atiixp_rd(_sc, _reg) \ 130168404Spjd bus_space_read_4((_sc)->st, (_sc)->sh, _reg) 131168404Spjd#define atiixp_wr(_sc, _reg, _val) \ 132168404Spjd bus_space_write_4((_sc)->st, (_sc)->sh, _reg, _val) 133168404Spjd 134168404Spjd#define atiixp_lock(_sc) snd_mtxlock((_sc)->lock) 135168404Spjd#define atiixp_unlock(_sc) snd_mtxunlock((_sc)->lock) 136168404Spjd#define atiixp_assert(_sc) snd_mtxassert((_sc)->lock) 137168404Spjd 138168404Spjdstatic uint32_t atiixp_fmt_32bit[] = { 139168404Spjd AFMT_STEREO | AFMT_S16_LE, 140168404Spjd AFMT_STEREO | AFMT_S32_LE, 141168404Spjd 0 142168404Spjd}; 143168404Spjd 144168404Spjdstatic uint32_t atiixp_fmt[] = { 145168404Spjd AFMT_STEREO | AFMT_S16_LE, 146168404Spjd 0 147168404Spjd}; 148168404Spjd 149168404Spjdstatic struct pcmchan_caps atiixp_caps_32bit = { 150168404Spjd ATI_IXP_BASE_RATE, 151168404Spjd ATI_IXP_BASE_RATE, 152168404Spjd atiixp_fmt_32bit, 0 153168404Spjd}; 154168404Spjd 155168404Spjdstatic struct pcmchan_caps atiixp_caps = { 156168404Spjd ATI_IXP_BASE_RATE, 157168404Spjd ATI_IXP_BASE_RATE, 158168404Spjd atiixp_fmt, 0 159168404Spjd}; 160168404Spjd 161168404Spjdstatic const struct { 162168404Spjd uint16_t vendor; 163168404Spjd uint16_t devid; 164168404Spjd char *desc; 165168404Spjd} atiixp_hw[] = { 166168404Spjd { ATI_VENDOR_ID, ATI_IXP_200_ID, "ATI IXP 200" }, 167168404Spjd { ATI_VENDOR_ID, ATI_IXP_300_ID, "ATI IXP 300" }, 168168404Spjd { ATI_VENDOR_ID, ATI_IXP_400_ID, "ATI IXP 400" }, 169168404Spjd}; 170168404Spjd 171168404Spjdstatic void atiixp_enable_interrupts(struct atiixp_info *); 172168404Spjdstatic void atiixp_disable_interrupts(struct atiixp_info *); 173168404Spjdstatic void atiixp_reset_aclink(struct atiixp_info *); 174168404Spjdstatic void atiixp_flush_dma(struct atiixp_chinfo *); 175168404Spjdstatic void atiixp_enable_dma(struct atiixp_chinfo *); 176168404Spjdstatic void atiixp_disable_dma(struct atiixp_chinfo *); 177168404Spjd 178168404Spjdstatic int atiixp_waitready_codec(struct atiixp_info *); 179168404Spjdstatic int atiixp_rdcd(kobj_t, void *, int); 180168404Spjdstatic int atiixp_wrcd(kobj_t, void *, int, uint32_t); 181168404Spjd 182168404Spjdstatic void *atiixp_chan_init(kobj_t, void *, struct snd_dbuf *, 183168404Spjd struct pcm_channel *, int); 184168404Spjdstatic int atiixp_chan_setformat(kobj_t, void *, uint32_t); 185168404Spjdstatic int atiixp_chan_setspeed(kobj_t, void *, uint32_t); 186168404Spjdstatic int atiixp_chan_setfragments(kobj_t, void *, uint32_t, uint32_t); 187168404Spjdstatic int atiixp_chan_setblocksize(kobj_t, void *, uint32_t); 188168404Spjdstatic void atiixp_buildsgdt(struct atiixp_chinfo *); 189168404Spjdstatic int atiixp_chan_trigger(kobj_t, void *, int); 190168404Spjdstatic __inline uint32_t atiixp_dmapos(struct atiixp_chinfo *); 191168404Spjdstatic int atiixp_chan_getptr(kobj_t, void *); 192168404Spjdstatic struct pcmchan_caps *atiixp_chan_getcaps(kobj_t, void *); 193168404Spjd 194168404Spjdstatic void atiixp_intr(void *); 195168404Spjdstatic void atiixp_dma_cb(void *, bus_dma_segment_t *, int, int); 196168404Spjdstatic void atiixp_chip_pre_init(struct atiixp_info *); 197168404Spjdstatic void atiixp_chip_post_init(void *); 198168404Spjdstatic void atiixp_release_resource(struct atiixp_info *); 199168404Spjdstatic int atiixp_pci_probe(device_t); 200168404Spjdstatic int atiixp_pci_attach(device_t); 201168404Spjdstatic int atiixp_pci_detach(device_t); 202168404Spjdstatic int atiixp_pci_suspend(device_t); 203168404Spjdstatic int atiixp_pci_resume(device_t); 204168404Spjd 205168404Spjd/* 206168404Spjd * ATI IXP helper functions 207168404Spjd */ 208168404Spjdstatic void 209168404Spjdatiixp_enable_interrupts(struct atiixp_info *sc) 210168404Spjd{ 211168404Spjd uint32_t value; 212168404Spjd 213168404Spjd /* clear all pending */ 214168404Spjd atiixp_wr(sc, ATI_REG_ISR, 0xffffffff); 215168404Spjd 216168404Spjd /* enable all relevant interrupt sources we can handle */ 217168404Spjd value = atiixp_rd(sc, ATI_REG_IER); 218168404Spjd 219168404Spjd value |= ATI_REG_IER_IO_STATUS_EN; 220168404Spjd 221168404Spjd /* 222168404Spjd * Disable / ignore internal xrun/spdf interrupt flags 223168404Spjd * since it doesn't interest us (for now). 224168404Spjd */ 225168404Spjd#if 1 226168404Spjd value &= ~(ATI_REG_IER_IN_XRUN_EN | ATI_REG_IER_OUT_XRUN_EN | 227168404Spjd ATI_REG_IER_SPDF_XRUN_EN | ATI_REG_IER_SPDF_STATUS_EN); 228168404Spjd#else 229168404Spjd value |= ATI_REG_IER_IN_XRUN_EN; 230168404Spjd value |= ATI_REG_IER_OUT_XRUN_EN; 231168404Spjd 232168404Spjd value |= ATI_REG_IER_SPDF_XRUN_EN; 233168404Spjd value |= ATI_REG_IER_SPDF_STATUS_EN; 234168404Spjd#endif 235168404Spjd 236168404Spjd atiixp_wr(sc, ATI_REG_IER, value); 237168404Spjd} 238168404Spjd 239168404Spjdstatic void 240168404Spjdatiixp_disable_interrupts(struct atiixp_info *sc) 241168404Spjd{ 242168404Spjd /* disable all interrupt sources */ 243168404Spjd atiixp_wr(sc, ATI_REG_IER, 0); 244185029Spjd 245185029Spjd /* clear all pending */ 246185029Spjd atiixp_wr(sc, ATI_REG_ISR, 0xffffffff); 247185029Spjd} 248185029Spjd 249185029Spjdstatic void 250185029Spjdatiixp_reset_aclink(struct atiixp_info *sc) 251185029Spjd{ 252185029Spjd uint32_t value, timeout; 253185029Spjd 254185029Spjd /* if power is down, power it up */ 255185029Spjd value = atiixp_rd(sc, ATI_REG_CMD); 256185029Spjd if (value & ATI_REG_CMD_POWERDOWN) { 257185029Spjd /* explicitly enable power */ 258185029Spjd value &= ~ATI_REG_CMD_POWERDOWN; 259185029Spjd atiixp_wr(sc, ATI_REG_CMD, value); 260185029Spjd 261168404Spjd /* have to wait at least 10 usec for it to initialise */ 262168404Spjd DELAY(20); 263168404Spjd } 264168404Spjd 265168404Spjd /* perform a soft reset */ 266168404Spjd value = atiixp_rd(sc, ATI_REG_CMD); 267168404Spjd value |= ATI_REG_CMD_AC_SOFT_RESET; 268168404Spjd atiixp_wr(sc, ATI_REG_CMD, value); 269168404Spjd 270168404Spjd /* need to read the CMD reg and wait aprox. 10 usec to init */ 271168404Spjd value = atiixp_rd(sc, ATI_REG_CMD); 272168404Spjd DELAY(20); 273168404Spjd 274168404Spjd /* clear soft reset flag again */ 275168404Spjd value = atiixp_rd(sc, ATI_REG_CMD); 276168404Spjd value &= ~ATI_REG_CMD_AC_SOFT_RESET; 277168404Spjd atiixp_wr(sc, ATI_REG_CMD, value); 278168404Spjd 279168404Spjd /* check if the ac-link is working; reset device otherwise */ 280168404Spjd timeout = 10; 281168404Spjd value = atiixp_rd(sc, ATI_REG_CMD); 282168404Spjd while (!(value & ATI_REG_CMD_ACLINK_ACTIVE) && --timeout) { 283168404Spjd#if 0 284168404Spjd device_printf(sc->dev, "not up; resetting aclink hardware\n"); 285168404Spjd#endif 286168404Spjd 287168404Spjd /* dip aclink reset but keep the acsync */ 288168404Spjd value &= ~ATI_REG_CMD_AC_RESET; 289168404Spjd value |= ATI_REG_CMD_AC_SYNC; 290168404Spjd atiixp_wr(sc, ATI_REG_CMD, value); 291168404Spjd 292168404Spjd /* need to read CMD again and wait again (clocking in issue?) */ 293168404Spjd value = atiixp_rd(sc, ATI_REG_CMD); 294168404Spjd DELAY(20); 295168404Spjd 296168404Spjd /* assert aclink reset again */ 297168404Spjd value = atiixp_rd(sc, ATI_REG_CMD); 298168404Spjd value |= ATI_REG_CMD_AC_RESET; 299168404Spjd atiixp_wr(sc, ATI_REG_CMD, value); 300168404Spjd 301168404Spjd /* check if its active now */ 302168404Spjd value = atiixp_rd(sc, ATI_REG_CMD); 303168404Spjd } 304185029Spjd 305168404Spjd if (timeout == 0) 306168404Spjd device_printf(sc->dev, "giving up aclink reset\n"); 307168404Spjd#if 0 308168404Spjd if (timeout != 10) 309168404Spjd device_printf(sc->dev, "aclink hardware reset successful\n"); 310168404Spjd#endif 311168404Spjd 312168404Spjd /* assert reset and sync for safety */ 313168404Spjd value = atiixp_rd(sc, ATI_REG_CMD); 314168404Spjd value |= ATI_REG_CMD_AC_SYNC | ATI_REG_CMD_AC_RESET; 315168404Spjd atiixp_wr(sc, ATI_REG_CMD, value); 316168404Spjd} 317168404Spjd 318168404Spjdstatic void 319168404Spjdatiixp_flush_dma(struct atiixp_chinfo *ch) 320168404Spjd{ 321168404Spjd atiixp_wr(ch->parent, ATI_REG_FIFO_FLUSH, ch->flush_bit); 322168404Spjd} 323168404Spjd 324168404Spjdstatic void 325168404Spjdatiixp_enable_dma(struct atiixp_chinfo *ch) 326168404Spjd{ 327168404Spjd uint32_t value; 328168404Spjd 329168404Spjd value = atiixp_rd(ch->parent, ATI_REG_CMD); 330168404Spjd if (!(value & ch->enable_bit)) { 331168404Spjd value |= ch->enable_bit; 332168404Spjd atiixp_wr(ch->parent, ATI_REG_CMD, value); 333168404Spjd } 334168404Spjd} 335168404Spjd 336168404Spjdstatic void 337168404Spjdatiixp_disable_dma(struct atiixp_chinfo *ch) 338168404Spjd{ 339185029Spjd uint32_t value; 340168404Spjd 341168404Spjd value = atiixp_rd(ch->parent, ATI_REG_CMD); 342168404Spjd if (value & ch->enable_bit) { 343168404Spjd value &= ~ch->enable_bit; 344168404Spjd atiixp_wr(ch->parent, ATI_REG_CMD, value); 345168404Spjd } 346168404Spjd} 347168404Spjd 348168404Spjd/* 349168404Spjd * AC97 interface 350168404Spjd */ 351168404Spjdstatic int 352168404Spjdatiixp_waitready_codec(struct atiixp_info *sc) 353168404Spjd{ 354168404Spjd int timeout = 500; 355168404Spjd 356168404Spjd do { 357168404Spjd if ((atiixp_rd(sc, ATI_REG_PHYS_OUT_ADDR) & 358168404Spjd ATI_REG_PHYS_OUT_ADDR_EN) == 0) 359168404Spjd return (0); 360168404Spjd DELAY(1); 361168404Spjd } while (--timeout); 362168404Spjd 363168404Spjd return (-1); 364168404Spjd} 365168404Spjd 366168404Spjdstatic int 367168404Spjdatiixp_rdcd(kobj_t obj, void *devinfo, int reg) 368168404Spjd{ 369168404Spjd struct atiixp_info *sc = devinfo; 370168404Spjd uint32_t data; 371168404Spjd int timeout; 372168404Spjd 373168404Spjd if (atiixp_waitready_codec(sc)) 374168404Spjd return (-1); 375168404Spjd 376168404Spjd data = (reg << ATI_REG_PHYS_OUT_ADDR_SHIFT) | 377168404Spjd ATI_REG_PHYS_OUT_ADDR_EN | ATI_REG_PHYS_OUT_RW | sc->codec_idx; 378168404Spjd 379168404Spjd atiixp_wr(sc, ATI_REG_PHYS_OUT_ADDR, data); 380168404Spjd 381168404Spjd if (atiixp_waitready_codec(sc)) 382168404Spjd return (-1); 383185029Spjd 384168404Spjd timeout = 500; 385168404Spjd do { 386168404Spjd data = atiixp_rd(sc, ATI_REG_PHYS_IN_ADDR); 387168404Spjd if (data & ATI_REG_PHYS_IN_READ_FLAG) 388168404Spjd return (data >> ATI_REG_PHYS_IN_DATA_SHIFT); 389168404Spjd DELAY(1); 390168404Spjd } while (--timeout); 391168404Spjd 392168404Spjd if (reg < 0x7c) 393168404Spjd device_printf(sc->dev, "codec read timeout! (reg 0x%x)\n", reg); 394168404Spjd 395168404Spjd return (-1); 396168404Spjd} 397168404Spjd 398168404Spjdstatic int 399168404Spjdatiixp_wrcd(kobj_t obj, void *devinfo, int reg, uint32_t data) 400168404Spjd{ 401168404Spjd struct atiixp_info *sc = devinfo; 402168404Spjd 403168404Spjd if (atiixp_waitready_codec(sc)) 404168404Spjd return (-1); 405168404Spjd 406168404Spjd data = (data << ATI_REG_PHYS_OUT_DATA_SHIFT) | 407168404Spjd (((uint32_t)reg) << ATI_REG_PHYS_OUT_ADDR_SHIFT) | 408168404Spjd ATI_REG_PHYS_OUT_ADDR_EN | sc->codec_idx; 409168404Spjd 410168404Spjd atiixp_wr(sc, ATI_REG_PHYS_OUT_ADDR, data); 411185029Spjd 412168404Spjd return (0); 413168404Spjd} 414168404Spjd 415168404Spjdstatic kobj_method_t atiixp_ac97_methods[] = { 416168404Spjd KOBJMETHOD(ac97_read, atiixp_rdcd), 417168404Spjd KOBJMETHOD(ac97_write, atiixp_wrcd), 418168404Spjd { 0, 0 } 419200726Sdelphij}; 420168404SpjdAC97_DECLARE(atiixp_ac97); 421168404Spjd 422168404Spjd/* 423168404Spjd * Playback / Record channel interface 424168404Spjd */ 425168404Spjdstatic void * 426168404Spjdatiixp_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, 427168404Spjd struct pcm_channel *c, int dir) 428168404Spjd{ 429168404Spjd struct atiixp_info *sc = devinfo; 430168404Spjd struct atiixp_chinfo *ch; 431168404Spjd int num; 432185029Spjd 433168404Spjd atiixp_lock(sc); 434200726Sdelphij 435200726Sdelphij if (dir == PCMDIR_PLAY) { 436200726Sdelphij ch = &sc->pch; 437200726Sdelphij ch->linkptr_bit = ATI_REG_OUT_DMA_LINKPTR; 438200726Sdelphij ch->enable_bit = ATI_REG_CMD_OUT_DMA_EN | ATI_REG_CMD_SEND_EN; 439200726Sdelphij ch->flush_bit = ATI_REG_FIFO_OUT_FLUSH; 440200726Sdelphij ch->dt_cur_bit = ATI_REG_OUT_DMA_DT_CUR; 441200726Sdelphij /* Native 32bit playback working properly */ 442200726Sdelphij ch->caps_32bit = 1; 443168404Spjd } else { 444200726Sdelphij ch = &sc->rch; 445200726Sdelphij ch->linkptr_bit = ATI_REG_IN_DMA_LINKPTR; 446196703Spjd ch->enable_bit = ATI_REG_CMD_IN_DMA_EN | ATI_REG_CMD_RECEIVE_EN; 447196703Spjd ch->flush_bit = ATI_REG_FIFO_IN_FLUSH; 448196703Spjd ch->dt_cur_bit = ATI_REG_IN_DMA_DT_CUR; 449168404Spjd /* XXX Native 32bit recording appear to be broken */ 450168404Spjd ch->caps_32bit = 1; 451168404Spjd } 452168404Spjd 453168404Spjd ch->buffer = b; 454168404Spjd ch->parent = sc; 455168404Spjd ch->channel = c; 456168404Spjd ch->dir = dir; 457168404Spjd ch->blkcnt = sc->blkcnt; 458196703Spjd ch->blksz = sc->bufsz / ch->blkcnt; 459168404Spjd 460168404Spjd atiixp_unlock(sc); 461168404Spjd 462168404Spjd if (sndbuf_alloc(ch->buffer, sc->parent_dmat, sc->bufsz) == -1) 463196703Spjd return (NULL); 464196703Spjd 465185029Spjd atiixp_lock(sc); 466185029Spjd num = sc->registered_channels++; 467185029Spjd ch->sgd_table = &sc->sgd_table[num * ATI_IXP_DMA_CHSEGS_MAX]; 468185029Spjd ch->sgd_addr = sc->sgd_addr + (num * ATI_IXP_DMA_CHSEGS_MAX * 469185029Spjd sizeof(struct atiixp_dma_op)); 470168404Spjd atiixp_disable_dma(ch); 471168404Spjd atiixp_unlock(sc); 472168404Spjd 473168404Spjd return (ch); 474168404Spjd} 475168404Spjd 476168404Spjdstatic int 477168404Spjdatiixp_chan_setformat(kobj_t obj, void *data, uint32_t format) 478168404Spjd{ 479168404Spjd struct atiixp_chinfo *ch = data; 480168404Spjd struct atiixp_info *sc = ch->parent; 481168404Spjd uint32_t value; 482168404Spjd 483168404Spjd atiixp_lock(sc); 484168404Spjd if (ch->dir == PCMDIR_REC) { 485168404Spjd value = atiixp_rd(sc, ATI_REG_CMD); 486168404Spjd value &= ~ATI_REG_CMD_INTERLEAVE_IN; 487168404Spjd if ((format & AFMT_32BIT) == 0) 488168404Spjd value |= ATI_REG_CMD_INTERLEAVE_IN; 489168404Spjd atiixp_wr(sc, ATI_REG_CMD, value); 490168404Spjd } else { 491168404Spjd value = atiixp_rd(sc, ATI_REG_OUT_DMA_SLOT); 492168404Spjd value &= ~ATI_REG_OUT_DMA_SLOT_MASK; 493168404Spjd /* We do not have support for more than 2 channels, _yet_. */ 494168404Spjd value |= ATI_REG_OUT_DMA_SLOT_BIT(3) | 495168404Spjd ATI_REG_OUT_DMA_SLOT_BIT(4); 496168404Spjd value |= 0x04 << ATI_REG_OUT_DMA_THRESHOLD_SHIFT; 497168404Spjd atiixp_wr(sc, ATI_REG_OUT_DMA_SLOT, value); 498168404Spjd value = atiixp_rd(sc, ATI_REG_CMD); 499168404Spjd value &= ~ATI_REG_CMD_INTERLEAVE_OUT; 500168404Spjd if ((format & AFMT_32BIT) == 0) 501168404Spjd value |= ATI_REG_CMD_INTERLEAVE_OUT; 502168404Spjd atiixp_wr(sc, ATI_REG_CMD, value); 503168404Spjd value = atiixp_rd(sc, ATI_REG_6CH_REORDER); 504168404Spjd value &= ~ATI_REG_6CH_REORDER_EN; 505168404Spjd atiixp_wr(sc, ATI_REG_6CH_REORDER, value); 506168404Spjd } 507168404Spjd ch->fmt = format; 508168404Spjd atiixp_unlock(sc); 509168404Spjd 510168404Spjd return (0); 511168404Spjd} 512168404Spjd 513168404Spjdstatic int 514168404Spjdatiixp_chan_setspeed(kobj_t obj, void *data, uint32_t spd) 515168404Spjd{ 516168404Spjd /* XXX We're supposed to do VRA/DRA processing right here */ 517168404Spjd return (ATI_IXP_BASE_RATE); 518168404Spjd} 519168404Spjd 520168404Spjdstatic int 521168404Spjdatiixp_chan_setfragments(kobj_t obj, void *data, 522168404Spjd uint32_t blksz, uint32_t blkcnt) 523168404Spjd{ 524168404Spjd struct atiixp_chinfo *ch = data; 525168404Spjd struct atiixp_info *sc = ch->parent; 526168404Spjd 527168404Spjd blksz &= ATI_IXP_BLK_ALIGN; 528168404Spjd 529168404Spjd if (blksz > (sndbuf_getmaxsize(ch->buffer) / ATI_IXP_DMA_CHSEGS_MIN)) 530168404Spjd blksz = sndbuf_getmaxsize(ch->buffer) / ATI_IXP_DMA_CHSEGS_MIN; 531168404Spjd if (blksz < ATI_IXP_BLK_MIN) 532168404Spjd blksz = ATI_IXP_BLK_MIN; 533168404Spjd if (blkcnt > ATI_IXP_DMA_CHSEGS_MAX) 534168404Spjd blkcnt = ATI_IXP_DMA_CHSEGS_MAX; 535168404Spjd if (blkcnt < ATI_IXP_DMA_CHSEGS_MIN) 536168404Spjd blkcnt = ATI_IXP_DMA_CHSEGS_MIN; 537168404Spjd 538168404Spjd while ((blksz * blkcnt) > sndbuf_getmaxsize(ch->buffer)) { 539168404Spjd if ((blkcnt >> 1) >= ATI_IXP_DMA_CHSEGS_MIN) 540168404Spjd blkcnt >>= 1; 541168404Spjd else if ((blksz >> 1) >= ATI_IXP_BLK_MIN) 542168404Spjd blksz >>= 1; 543168404Spjd else 544168404Spjd break; 545168404Spjd } 546168404Spjd 547185029Spjd if ((sndbuf_getblksz(ch->buffer) != blksz || 548185029Spjd sndbuf_getblkcnt(ch->buffer) != blkcnt) && 549185029Spjd sndbuf_resize(ch->buffer, blkcnt, blksz) != 0) 550185029Spjd device_printf(sc->dev, "%s: failed blksz=%u blkcnt=%u\n", 551185029Spjd __func__, blksz, blkcnt); 552185029Spjd 553168404Spjd ch->blksz = sndbuf_getblksz(ch->buffer); 554168404Spjd ch->blkcnt = sndbuf_getblkcnt(ch->buffer); 555168404Spjd 556168404Spjd return (1); 557168404Spjd} 558168404Spjd 559168404Spjdstatic int 560168404Spjdatiixp_chan_setblocksize(kobj_t obj, void *data, uint32_t blksz) 561168404Spjd{ 562168404Spjd struct atiixp_chinfo *ch = data; 563168404Spjd struct atiixp_info *sc = ch->parent; 564168404Spjd 565168404Spjd atiixp_chan_setfragments(obj, data, blksz, sc->blkcnt); 566168404Spjd 567168404Spjd return (ch->blksz); 568168404Spjd} 569168404Spjd 570168404Spjdstatic void 571168404Spjdatiixp_buildsgdt(struct atiixp_chinfo *ch) 572168404Spjd{ 573168404Spjd struct atiixp_info *sc = ch->parent; 574168404Spjd uint32_t addr, blksz, blkcnt; 575168404Spjd int i; 576168404Spjd 577168404Spjd addr = sndbuf_getbufaddr(ch->buffer); 578168404Spjd 579168404Spjd if (sc->polling != 0) { 580168404Spjd blksz = ch->blksz * ch->blkcnt; 581168404Spjd blkcnt = 1; 582168404Spjd } else { 583168404Spjd blksz = ch->blksz; 584168404Spjd blkcnt = ch->blkcnt; 585168404Spjd } 586168404Spjd 587168404Spjd for (i = 0; i < blkcnt; i++) { 588168404Spjd ch->sgd_table[i].addr = htole32(addr + (i * blksz)); 589168404Spjd ch->sgd_table[i].status = htole16(0); 590168404Spjd ch->sgd_table[i].size = htole16(blksz >> 2); 591168404Spjd ch->sgd_table[i].next = htole32((uint32_t)ch->sgd_addr + 592168404Spjd (((i + 1) % blkcnt) * sizeof(struct atiixp_dma_op))); 593168404Spjd } 594168404Spjd} 595168404Spjd 596185029Spjdstatic __inline uint32_t 597168404Spjdatiixp_dmapos(struct atiixp_chinfo *ch) 598185029Spjd{ 599185029Spjd struct atiixp_info *sc = ch->parent; 600168404Spjd uint32_t reg, addr, sz, retry; 601168404Spjd volatile uint32_t ptr; 602168404Spjd 603168404Spjd reg = ch->dt_cur_bit; 604168404Spjd addr = sndbuf_getbufaddr(ch->buffer); 605168404Spjd sz = ch->blkcnt * ch->blksz; 606168404Spjd retry = ATI_IXP_DMA_RETRY_MAX; 607168404Spjd 608168404Spjd do { 609168404Spjd ptr = atiixp_rd(sc, reg); 610168404Spjd if (ptr < addr) 611168404Spjd continue; 612168404Spjd ptr -= addr; 613168404Spjd if (ptr < sz) { 614168404Spjd#if 0 615168404Spjd#ifdef ATI_IXP_DEBUG 616168404Spjd if ((ptr & ~(ch->blksz - 1)) != ch->ptr) { 617168404Spjd uint32_t delta; 618168404Spjd 619168404Spjd delta = (sz + ptr - ch->prevptr) % sz; 620168404Spjd#ifndef ATI_IXP_DEBUG_VERBOSE 621168404Spjd if (delta < ch->blksz) 622168404Spjd#endif 623168404Spjd device_printf(sc->dev, 624168404Spjd "PCMDIR_%s: incoherent DMA " 625168404Spjd "prevptr=%u ptr=%u " 626168404Spjd "ptr=%u blkcnt=%u " 627168404Spjd "[delta=%u != blksz=%u] " 628168404Spjd "(%s)\n", 629168404Spjd (ch->dir == PCMDIR_PLAY) ? 630168404Spjd "PLAY" : "REC", 631168404Spjd ch->prevptr, ptr, 632168404Spjd ch->ptr, ch->blkcnt, 633168404Spjd delta, ch->blksz, 634168404Spjd (delta < ch->blksz) ? 635168404Spjd "OVERLAPPED!" : "Ok"); 636168404Spjd ch->ptr = ptr & ~(ch->blksz - 1); 637168404Spjd } 638168404Spjd ch->prevptr = ptr; 639185029Spjd#endif 640185029Spjd#endif 641185029Spjd return (ptr); 642185029Spjd } 643185029Spjd } while (--retry); 644185029Spjd 645168404Spjd device_printf(sc->dev, "PCMDIR_%s: invalid DMA pointer ptr=%u\n", 646168404Spjd (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC", ptr); 647185029Spjd 648185029Spjd return (0); 649185029Spjd} 650185029Spjd 651185029Spjdstatic __inline int 652185029Spjdatiixp_poll_channel(struct atiixp_chinfo *ch) 653185029Spjd{ 654185029Spjd uint32_t sz, delta; 655168404Spjd volatile uint32_t ptr; 656168404Spjd 657168404Spjd if (ch->active == 0) 658168404Spjd return (0); 659168404Spjd 660168404Spjd sz = ch->blksz * ch->blkcnt; 661168404Spjd ptr = atiixp_dmapos(ch); 662185029Spjd ch->ptr = ptr; 663168404Spjd ptr %= sz; 664185029Spjd ptr &= ~(ch->blksz - 1); 665168404Spjd delta = (sz + ptr - ch->prevptr) % sz; 666168404Spjd 667168404Spjd if (delta < ch->blksz) 668168404Spjd return (0); 669168404Spjd 670168404Spjd ch->prevptr = ptr; 671168404Spjd 672168404Spjd return (1); 673168404Spjd} 674168404Spjd 675168404Spjd#define atiixp_chan_active(sc) ((sc)->pch.active + (sc)->rch.active) 676168404Spjd 677168404Spjdstatic void 678168404Spjdatiixp_poll_callback(void *arg) 679168404Spjd{ 680168404Spjd struct atiixp_info *sc = arg; 681168404Spjd uint32_t trigger = 0; 682168404Spjd 683168404Spjd if (sc == NULL) 684168404Spjd return; 685168404Spjd 686168404Spjd atiixp_lock(sc); 687168404Spjd if (sc->polling == 0 || atiixp_chan_active(sc) == 0) { 688168404Spjd atiixp_unlock(sc); 689168404Spjd return; 690168404Spjd } 691168404Spjd 692168404Spjd trigger |= (atiixp_poll_channel(&sc->pch) != 0) ? 1 : 0; 693168404Spjd trigger |= (atiixp_poll_channel(&sc->rch) != 0) ? 2 : 0; 694168404Spjd 695168404Spjd /* XXX */ 696168404Spjd callout_reset(&sc->poll_timer, 1/*sc->poll_ticks*/, 697168404Spjd atiixp_poll_callback, sc); 698168404Spjd 699168404Spjd atiixp_unlock(sc); 700185029Spjd 701168404Spjd if (trigger & 1) 702168404Spjd chn_intr(sc->pch.channel); 703168404Spjd if (trigger & 2) 704168404Spjd chn_intr(sc->rch.channel); 705168404Spjd} 706168404Spjd 707168404Spjdstatic int 708168404Spjdatiixp_chan_trigger(kobj_t obj, void *data, int go) 709168404Spjd{ 710168404Spjd struct atiixp_chinfo *ch = data; 711168404Spjd struct atiixp_info *sc = ch->parent; 712168404Spjd uint32_t value; 713168404Spjd int pollticks; 714168404Spjd 715168404Spjd atiixp_lock(sc); 716168404Spjd 717168404Spjd switch (go) { 718168404Spjd case PCMTRIG_START: 719168404Spjd atiixp_flush_dma(ch); 720168404Spjd atiixp_buildsgdt(ch); 721168404Spjd atiixp_wr(sc, ch->linkptr_bit, 0); 722168404Spjd atiixp_enable_dma(ch); 723185029Spjd atiixp_wr(sc, ch->linkptr_bit, 724168404Spjd (uint32_t)ch->sgd_addr | ATI_REG_LINKPTR_EN); 725168404Spjd if (sc->polling != 0) { 726168404Spjd ch->ptr = 0; 727168404Spjd ch->prevptr = 0; 728168404Spjd pollticks = ((uint64_t)hz * ch->blksz) / 729168404Spjd ((uint64_t)sndbuf_getbps(ch->buffer) * 730168404Spjd sndbuf_getspd(ch->buffer)); 731168404Spjd pollticks >>= 2; 732168404Spjd if (pollticks > hz) 733168404Spjd pollticks = hz; 734168404Spjd if (pollticks < 1) 735168404Spjd pollticks = 1; 736168404Spjd if (atiixp_chan_active(sc) == 0 || 737168404Spjd pollticks < sc->poll_ticks) { 738168404Spjd if (bootverbose) { 739168404Spjd if (atiixp_chan_active(sc) == 0) 740168404Spjd device_printf(sc->dev, 741168404Spjd "%s: pollticks=%d\n", 742168404Spjd __func__, pollticks); 743168404Spjd else 744168404Spjd device_printf(sc->dev, 745168404Spjd "%s: pollticks %d -> %d\n", 746168404Spjd __func__, sc->poll_ticks, 747168404Spjd pollticks); 748168404Spjd } 749168404Spjd sc->poll_ticks = pollticks; 750168404Spjd callout_reset(&sc->poll_timer, 1, 751168404Spjd atiixp_poll_callback, sc); 752168404Spjd } 753168404Spjd } 754168404Spjd ch->active = 1; 755168404Spjd break; 756168404Spjd case PCMTRIG_STOP: 757168404Spjd case PCMTRIG_ABORT: 758168404Spjd atiixp_disable_dma(ch); 759168404Spjd atiixp_flush_dma(ch); 760168404Spjd ch->active = 0; 761168404Spjd if (sc->polling != 0) { 762168404Spjd if (atiixp_chan_active(sc) == 0) { 763168404Spjd callout_stop(&sc->poll_timer); 764168404Spjd sc->poll_ticks = 1; 765168404Spjd } else { 766168404Spjd if (sc->pch.active != 0) 767168404Spjd ch = &sc->pch; 768168404Spjd else 769168404Spjd ch = &sc->rch; 770168404Spjd pollticks = ((uint64_t)hz * ch->blksz) / 771185029Spjd ((uint64_t)sndbuf_getbps(ch->buffer) * 772168404Spjd sndbuf_getspd(ch->buffer)); 773168404Spjd pollticks >>= 2; 774168404Spjd if (pollticks > hz) 775168404Spjd pollticks = hz; 776168404Spjd if (pollticks < 1) 777168404Spjd pollticks = 1; 778168404Spjd if (pollticks > sc->poll_ticks) { 779168404Spjd if (bootverbose) 780168404Spjd device_printf(sc->dev, 781168404Spjd "%s: pollticks %d -> %d\n", 782168404Spjd __func__, sc->poll_ticks, 783168404Spjd pollticks); 784168404Spjd sc->poll_ticks = pollticks; 785168404Spjd callout_reset(&sc->poll_timer, 786168404Spjd 1, atiixp_poll_callback, 787168404Spjd sc); 788168404Spjd } 789168404Spjd } 790168404Spjd } 791168404Spjd break; 792168404Spjd default: 793168404Spjd atiixp_unlock(sc); 794168404Spjd return (0); 795168404Spjd break; 796185029Spjd } 797168404Spjd 798168404Spjd /* Update bus busy status */ 799168404Spjd value = atiixp_rd(sc, ATI_REG_IER); 800168404Spjd if (atiixp_rd(sc, ATI_REG_CMD) & (ATI_REG_CMD_SEND_EN | 801168404Spjd ATI_REG_CMD_RECEIVE_EN | ATI_REG_CMD_SPDF_OUT_EN)) 802168404Spjd value |= ATI_REG_IER_SET_BUS_BUSY; 803168404Spjd else 804168404Spjd value &= ~ATI_REG_IER_SET_BUS_BUSY; 805168404Spjd atiixp_wr(sc, ATI_REG_IER, value); 806185029Spjd 807185029Spjd atiixp_unlock(sc); 808185029Spjd 809168404Spjd return (0); 810185029Spjd} 811185029Spjd 812168404Spjdstatic int 813168404Spjdatiixp_chan_getptr(kobj_t obj, void *data) 814168404Spjd{ 815168404Spjd struct atiixp_chinfo *ch = data; 816168404Spjd struct atiixp_info *sc = ch->parent; 817168404Spjd uint32_t ptr; 818168404Spjd 819168404Spjd atiixp_lock(sc); 820185029Spjd if (sc->polling != 0) 821168404Spjd ptr = ch->ptr; 822168404Spjd else 823168404Spjd ptr = atiixp_dmapos(ch); 824168404Spjd atiixp_unlock(sc); 825168404Spjd 826168404Spjd return (ptr); 827168404Spjd} 828168404Spjd 829168404Spjdstatic struct pcmchan_caps * 830168404Spjdatiixp_chan_getcaps(kobj_t obj, void *data) 831168404Spjd{ 832185029Spjd struct atiixp_chinfo *ch = data; 833168404Spjd 834185029Spjd if (ch->caps_32bit) 835168404Spjd return (&atiixp_caps_32bit); 836168404Spjd return (&atiixp_caps); 837168404Spjd} 838168404Spjd 839168404Spjdstatic kobj_method_t atiixp_chan_methods[] = { 840168404Spjd KOBJMETHOD(channel_init, atiixp_chan_init), 841168404Spjd KOBJMETHOD(channel_setformat, atiixp_chan_setformat), 842185029Spjd KOBJMETHOD(channel_setspeed, atiixp_chan_setspeed), 843185029Spjd KOBJMETHOD(channel_setblocksize, atiixp_chan_setblocksize), 844185029Spjd KOBJMETHOD(channel_setfragments, atiixp_chan_setfragments), 845185029Spjd KOBJMETHOD(channel_trigger, atiixp_chan_trigger), 846185029Spjd KOBJMETHOD(channel_getptr, atiixp_chan_getptr), 847185029Spjd KOBJMETHOD(channel_getcaps, atiixp_chan_getcaps), 848185029Spjd { 0, 0 } 849185029Spjd}; 850185029SpjdCHANNEL_DECLARE(atiixp_chan); 851185029Spjd 852185029Spjd/* 853185029Spjd * PCI driver interface 854185029Spjd */ 855185029Spjdstatic void 856185029Spjdatiixp_intr(void *p) 857185029Spjd{ 858168404Spjd struct atiixp_info *sc = p; 859168404Spjd uint32_t status, enable, detected_codecs; 860168404Spjd uint32_t trigger = 0; 861168404Spjd 862168404Spjd atiixp_lock(sc); 863168404Spjd if (sc->polling != 0) { 864168404Spjd atiixp_unlock(sc); 865168404Spjd return; 866168404Spjd } 867168404Spjd status = atiixp_rd(sc, ATI_REG_ISR); 868168404Spjd 869168404Spjd if (status == 0) { 870168404Spjd atiixp_unlock(sc); 871168404Spjd return; 872168404Spjd } 873168404Spjd 874168404Spjd if ((status & ATI_REG_ISR_OUT_STATUS) && sc->pch.active != 0) 875168404Spjd trigger |= 1; 876168404Spjd if ((status & ATI_REG_ISR_IN_STATUS) && sc->rch.active != 0) 877168404Spjd trigger |= 2; 878168404Spjd 879168404Spjd#if 0 880168404Spjd if (status & ATI_REG_ISR_IN_XRUN) { 881168404Spjd device_printf(sc->dev, 882168404Spjd "Recieve IN XRUN interrupt\n"); 883168404Spjd } 884168404Spjd if (status & ATI_REG_ISR_OUT_XRUN) { 885168404Spjd device_printf(sc->dev, 886168404Spjd "Recieve OUT XRUN interrupt\n"); 887168404Spjd } 888168404Spjd#endif 889168404Spjd 890168404Spjd if (status & CODEC_CHECK_BITS) { 891168404Spjd /* mark missing codecs as not ready */ 892168404Spjd detected_codecs = status & CODEC_CHECK_BITS; 893168404Spjd sc->codec_not_ready_bits |= detected_codecs; 894168404Spjd 895168404Spjd /* disable detected interupt sources */ 896168404Spjd enable = atiixp_rd(sc, ATI_REG_IER); 897168404Spjd enable &= ~detected_codecs; 898168404Spjd atiixp_wr(sc, ATI_REG_IER, enable); 899168404Spjd } 900168404Spjd 901168404Spjd /* acknowledge */ 902168404Spjd atiixp_wr(sc, ATI_REG_ISR, status); 903168404Spjd atiixp_unlock(sc); 904168404Spjd 905168404Spjd if (trigger & 1) 906168404Spjd chn_intr(sc->pch.channel); 907168404Spjd if (trigger & 2) 908168404Spjd chn_intr(sc->rch.channel); 909185029Spjd} 910185029Spjd 911168404Spjdstatic void 912168404Spjdatiixp_dma_cb(void *p, bus_dma_segment_t *bds, int a, int b) 913168404Spjd{ 914168404Spjd struct atiixp_info *sc = (struct atiixp_info *)p; 915168404Spjd sc->sgd_addr = bds->ds_addr; 916168404Spjd} 917168404Spjd 918168404Spjdstatic void 919168404Spjdatiixp_chip_pre_init(struct atiixp_info *sc) 920168404Spjd{ 921168404Spjd uint32_t value; 922168404Spjd 923168404Spjd atiixp_lock(sc); 924168404Spjd 925168404Spjd /* disable interrupts */ 926168404Spjd atiixp_disable_interrupts(sc); 927168404Spjd 928168404Spjd /* clear all DMA enables (preserving rest of settings) */ 929168404Spjd value = atiixp_rd(sc, ATI_REG_CMD); 930168404Spjd value &= ~(ATI_REG_CMD_IN_DMA_EN | ATI_REG_CMD_OUT_DMA_EN | 931168404Spjd ATI_REG_CMD_SPDF_OUT_EN ); 932168404Spjd atiixp_wr(sc, ATI_REG_CMD, value); 933168404Spjd 934168404Spjd /* reset aclink */ 935168404Spjd atiixp_reset_aclink(sc); 936168404Spjd 937168404Spjd sc->codec_not_ready_bits = 0; 938168404Spjd 939168404Spjd /* enable all codecs to interrupt as well as the new frame interrupt */ 940168404Spjd atiixp_wr(sc, ATI_REG_IER, CODEC_CHECK_BITS); 941168404Spjd 942168404Spjd atiixp_unlock(sc); 943168404Spjd} 944168404Spjd 945168404Spjd#ifdef SND_DYNSYSCTL 946168404Spjdstatic int 947168404Spjdsysctl_atiixp_polling(SYSCTL_HANDLER_ARGS) 948168404Spjd{ 949168404Spjd struct atiixp_info *sc; 950168404Spjd device_t dev; 951168404Spjd int err, val; 952168404Spjd 953168404Spjd dev = oidp->oid_arg1; 954168404Spjd sc = pcm_getdevinfo(dev); 955168404Spjd if (sc == NULL) 956168404Spjd return (EINVAL); 957168404Spjd atiixp_lock(sc); 958168404Spjd val = sc->polling; 959168404Spjd atiixp_unlock(sc); 960168404Spjd err = sysctl_handle_int(oidp, &val, sizeof(val), req); 961168404Spjd 962168404Spjd if (err || req->newptr == NULL) 963168404Spjd return (err); 964168404Spjd if (val < 0 || val > 1) 965168404Spjd return (EINVAL); 966168404Spjd 967168404Spjd atiixp_lock(sc); 968168404Spjd if (val != sc->polling) { 969168404Spjd if (atiixp_chan_active(sc) != 0) 970168404Spjd err = EBUSY; 971185029Spjd else if (val == 0) { 972168404Spjd atiixp_enable_interrupts(sc); 973185029Spjd sc->polling = 0; 974168404Spjd DELAY(1000); 975168404Spjd } else { 976168404Spjd atiixp_disable_interrupts(sc); 977185029Spjd sc->polling = 1; 978185029Spjd DELAY(1000); 979168404Spjd } 980168404Spjd } 981168404Spjd atiixp_unlock(sc); 982168404Spjd 983168404Spjd return (err); 984168404Spjd} 985168404Spjd#endif 986168404Spjd 987168404Spjdstatic void 988168404Spjdatiixp_chip_post_init(void *arg) 989168404Spjd{ 990168404Spjd struct atiixp_info *sc = (struct atiixp_info *)arg; 991185029Spjd uint32_t subdev; 992185029Spjd int i, timeout, found, polling; 993168404Spjd char status[SND_STATUSLEN]; 994168404Spjd 995168404Spjd atiixp_lock(sc); 996185029Spjd 997185029Spjd if (sc->delayed_attach.ich_func) { 998185029Spjd config_intrhook_disestablish(&sc->delayed_attach); 999185029Spjd sc->delayed_attach.ich_func = NULL; 1000185029Spjd } 1001185029Spjd 1002185029Spjd polling = sc->polling; 1003168404Spjd sc->polling = 0; 1004168404Spjd 1005168404Spjd /* wait for the interrupts to happen */ 1006168404Spjd timeout = 100; 1007168404Spjd do { 1008168404Spjd msleep(sc, sc->lock, PWAIT, "ixpslp", 1); 1009168404Spjd if (sc->codec_not_ready_bits) 1010168404Spjd break; 1011168404Spjd } while (--timeout); 1012168404Spjd 1013168404Spjd sc->polling = polling; 1014168404Spjd atiixp_disable_interrupts(sc); 1015168404Spjd 1016168404Spjd if (timeout == 0) { 1017168404Spjd device_printf(sc->dev, 1018168404Spjd "WARNING: timeout during codec detection; " 1019168404Spjd "codecs might be present but haven't interrupted\n"); 1020168404Spjd atiixp_unlock(sc); 1021168404Spjd goto postinitbad; 1022168404Spjd } 1023168404Spjd 1024168404Spjd found = 0; 1025168404Spjd 1026168404Spjd /* 1027168404Spjd * ATI IXP can have upto 3 codecs, but single codec should be 1028168404Spjd * suffice for now. 1029168404Spjd */ 1030168404Spjd if (!(sc->codec_not_ready_bits & ATI_REG_ISR_CODEC0_NOT_READY)) { 1031168404Spjd /* codec 0 present */ 1032168404Spjd sc->codec_found++; 1033168404Spjd sc->codec_idx = 0; 1034168404Spjd found++; 1035185029Spjd } 1036168404Spjd 1037168404Spjd if (!(sc->codec_not_ready_bits & ATI_REG_ISR_CODEC1_NOT_READY)) { 1038185029Spjd /* codec 1 present */ 1039185029Spjd sc->codec_found++; 1040185029Spjd } 1041168404Spjd 1042185029Spjd if (!(sc->codec_not_ready_bits & ATI_REG_ISR_CODEC2_NOT_READY)) { 1043185029Spjd /* codec 2 present */ 1044185029Spjd sc->codec_found++; 1045185029Spjd } 1046185029Spjd 1047168404Spjd atiixp_unlock(sc); 1048185029Spjd 1049185029Spjd if (found == 0) 1050185029Spjd goto postinitbad; 1051185029Spjd 1052185029Spjd /* create/init mixer */ 1053185029Spjd sc->codec = AC97_CREATE(sc->dev, sc, atiixp_ac97); 1054185029Spjd if (sc->codec == NULL) 1055185029Spjd goto postinitbad; 1056185029Spjd 1057185029Spjd subdev = (pci_get_subdevice(sc->dev) << 16) | 1058185029Spjd pci_get_subvendor(sc->dev); 1059185029Spjd switch (subdev) { 1060185029Spjd case 0x11831043: /* ASUS A6R */ 1061185029Spjd case 0x2043161f: /* Maxselect x710s - http://maxselect.ru/ */ 1062168404Spjd ac97_setflags(sc->codec, ac97_getflags(sc->codec) | 1063185029Spjd AC97_F_EAPD_INV); 1064168404Spjd break; 1065185029Spjd default: 1066185029Spjd break; 1067168404Spjd } 1068185029Spjd 1069185029Spjd mixer_init(sc->dev, ac97_getmixerclass(), sc->codec); 1070185029Spjd 1071185029Spjd if (pcm_register(sc->dev, sc, ATI_IXP_NPCHAN, ATI_IXP_NRCHAN)) 1072185029Spjd goto postinitbad; 1073185029Spjd 1074185029Spjd for (i = 0; i < ATI_IXP_NPCHAN; i++) 1075185029Spjd pcm_addchan(sc->dev, PCMDIR_PLAY, &atiixp_chan_class, sc); 1076185029Spjd for (i = 0; i < ATI_IXP_NRCHAN; i++) 1077185029Spjd pcm_addchan(sc->dev, PCMDIR_REC, &atiixp_chan_class, sc); 1078185029Spjd 1079185029Spjd#ifdef SND_DYNSYSCTL 1080185029Spjd SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev), 1081185029Spjd SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO, 1082185029Spjd "polling", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev), 1083185029Spjd sysctl_atiixp_polling, "I", "Enable polling mode"); 1084185029Spjd#endif 1085185029Spjd 1086185029Spjd snprintf(status, SND_STATUSLEN, "at memory 0x%lx irq %ld %s", 1087185029Spjd rman_get_start(sc->reg), rman_get_start(sc->irq), 1088185029Spjd PCM_KLDSTRING(snd_atiixp)); 1089185029Spjd 1090185029Spjd pcm_setstatus(sc->dev, status); 1091168404Spjd 1092168404Spjd atiixp_lock(sc); 1093168404Spjd if (sc->polling == 0) 1094185029Spjd atiixp_enable_interrupts(sc); 1095185029Spjd atiixp_unlock(sc); 1096185029Spjd 1097185029Spjd return; 1098185029Spjd 1099168404Spjdpostinitbad: 1100168404Spjd atiixp_release_resource(sc); 1101168404Spjd} 1102185029Spjd 1103185029Spjdstatic void 1104185029Spjdatiixp_release_resource(struct atiixp_info *sc) 1105168404Spjd{ 1106185029Spjd if (sc == NULL) 1107185029Spjd return; 1108185029Spjd if (sc->codec) { 1109185029Spjd ac97_destroy(sc->codec); 1110185029Spjd sc->codec = NULL; 1111185029Spjd } 1112185029Spjd if (sc->ih) { 1113185029Spjd bus_teardown_intr(sc->dev, sc->irq, sc->ih); 1114185029Spjd sc->ih = 0; 1115185029Spjd } 1116185029Spjd if (sc->reg) { 1117185029Spjd bus_release_resource(sc->dev, sc->regtype, sc->regid, sc->reg); 1118168404Spjd sc->reg = 0; 1119185029Spjd } 1120185029Spjd if (sc->irq) { 1121185029Spjd bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irqid, sc->irq); 1122185029Spjd sc->irq = 0; 1123185029Spjd } 1124168404Spjd if (sc->parent_dmat) { 1125168404Spjd bus_dma_tag_destroy(sc->parent_dmat); 1126168404Spjd sc->parent_dmat = 0; 1127168404Spjd } 1128168404Spjd if (sc->sgd_dmamap) { 1129168404Spjd bus_dmamap_unload(sc->sgd_dmat, sc->sgd_dmamap); 1130168404Spjd sc->sgd_dmamap = 0; 1131168404Spjd } 1132168404Spjd if (sc->sgd_dmat) { 1133168404Spjd bus_dma_tag_destroy(sc->sgd_dmat); 1134168404Spjd sc->sgd_dmat = 0; 1135168404Spjd } 1136168404Spjd if (sc->lock) { 1137168404Spjd snd_mtxfree(sc->lock); 1138168404Spjd sc->lock = NULL; 1139168404Spjd } 1140168404Spjd} 1141168404Spjd 1142168404Spjdstatic int 1143185029Spjdatiixp_pci_probe(device_t dev) 1144168404Spjd{ 1145168404Spjd int i; 1146185029Spjd uint16_t devid, vendor; 1147185029Spjd 1148185029Spjd vendor = pci_get_vendor(dev); 1149168404Spjd devid = pci_get_device(dev); 1150168404Spjd for (i = 0; i < sizeof(atiixp_hw) / sizeof(atiixp_hw[0]); i++) { 1151168404Spjd if (vendor == atiixp_hw[i].vendor && 1152168404Spjd devid == atiixp_hw[i].devid) { 1153168404Spjd device_set_desc(dev, atiixp_hw[i].desc); 1154168404Spjd return (BUS_PROBE_DEFAULT); 1155168404Spjd } 1156168404Spjd } 1157168404Spjd 1158168404Spjd return (ENXIO); 1159168404Spjd} 1160168404Spjd 1161168404Spjdstatic int 1162168404Spjdatiixp_pci_attach(device_t dev) 1163168404Spjd{ 1164168404Spjd struct atiixp_info *sc; 1165168404Spjd int i; 1166168404Spjd 1167168404Spjd if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) { 1168168404Spjd device_printf(dev, "cannot allocate softc\n"); 1169168404Spjd return (ENXIO); 1170168404Spjd } 1171168404Spjd 1172168404Spjd sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_atiixp softc"); 1173168404Spjd sc->dev = dev; 1174168404Spjd 1175168404Spjd callout_init(&sc->poll_timer, CALLOUT_MPSAFE); 1176168404Spjd sc->poll_ticks = 1; 1177168404Spjd 1178168404Spjd if (resource_int_value(device_get_name(sc->dev), 1179168404Spjd device_get_unit(sc->dev), "polling", &i) == 0 && i != 0) 1180168404Spjd sc->polling = 1; 1181168404Spjd else 1182168404Spjd sc->polling = 0; 1183168404Spjd 1184168404Spjd pci_set_powerstate(dev, PCI_POWERSTATE_D0); 1185168404Spjd pci_enable_busmaster(dev); 1186168404Spjd 1187168404Spjd sc->regid = PCIR_BAR(0); 1188168404Spjd sc->regtype = SYS_RES_MEMORY; 1189168404Spjd sc->reg = bus_alloc_resource_any(dev, sc->regtype, 1190168404Spjd &sc->regid, RF_ACTIVE); 1191168404Spjd 1192168404Spjd if (!sc->reg) { 1193168404Spjd device_printf(dev, "unable to allocate register space\n"); 1194168404Spjd goto bad; 1195168404Spjd } 1196168404Spjd 1197168404Spjd sc->st = rman_get_bustag(sc->reg); 1198168404Spjd sc->sh = rman_get_bushandle(sc->reg); 1199168404Spjd 1200168404Spjd sc->bufsz = pcm_getbuffersize(dev, ATI_IXP_BUFSZ_MIN, 1201168404Spjd ATI_IXP_BUFSZ_DEFAULT, ATI_IXP_BUFSZ_MAX); 1202168404Spjd 1203168404Spjd sc->irqid = 0; 1204168404Spjd sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid, 1205168404Spjd RF_ACTIVE | RF_SHAREABLE); 1206168404Spjd if (!sc->irq || snd_setup_intr(dev, sc->irq, INTR_MPSAFE, 1207168404Spjd atiixp_intr, sc, &sc->ih)) { 1208168404Spjd device_printf(dev, "unable to map interrupt\n"); 1209168404Spjd goto bad; 1210168404Spjd } 1211185029Spjd 1212168404Spjd /* 1213168404Spjd * Let the user choose the best DMA segments. 1214168404Spjd */ 1215168404Spjd if (resource_int_value(device_get_name(dev), 1216168404Spjd device_get_unit(dev), "blocksize", &i) == 0 && i > 0) { 1217168404Spjd i &= ATI_IXP_BLK_ALIGN; 1218168404Spjd if (i < ATI_IXP_BLK_MIN) 1219168404Spjd i = ATI_IXP_BLK_MIN; 1220168404Spjd sc->blkcnt = sc->bufsz / i; 1221168404Spjd i = 0; 1222168404Spjd while (sc->blkcnt >> i) 1223168404Spjd i++; 1224168404Spjd sc->blkcnt = 1 << (i - 1); 1225168404Spjd if (sc->blkcnt < ATI_IXP_DMA_CHSEGS_MIN) 1226168404Spjd sc->blkcnt = ATI_IXP_DMA_CHSEGS_MIN; 1227168404Spjd else if (sc->blkcnt > ATI_IXP_DMA_CHSEGS_MAX) 1228168404Spjd sc->blkcnt = ATI_IXP_DMA_CHSEGS_MAX; 1229168404Spjd 1230168404Spjd } else 1231168404Spjd sc->blkcnt = ATI_IXP_DMA_CHSEGS; 1232168404Spjd 1233168404Spjd /* 1234168404Spjd * DMA tag for scatter-gather buffers and link pointers 1235168404Spjd */ 1236168404Spjd if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2, 1237168404Spjd /*boundary*/0, 1238168404Spjd /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 1239168404Spjd /*highaddr*/BUS_SPACE_MAXADDR, 1240168404Spjd /*filter*/NULL, /*filterarg*/NULL, 1241168404Spjd /*maxsize*/sc->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff, 1242168404Spjd /*flags*/0, /*lockfunc*/NULL, 1243185029Spjd /*lockarg*/NULL, &sc->parent_dmat) != 0) { 1244168404Spjd device_printf(dev, "unable to create dma tag\n"); 1245168404Spjd goto bad; 1246168404Spjd } 1247168404Spjd 1248168404Spjd if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2, 1249168404Spjd /*boundary*/0, 1250168404Spjd /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 1251185029Spjd /*highaddr*/BUS_SPACE_MAXADDR, 1252185029Spjd /*filter*/NULL, /*filterarg*/NULL, 1253168404Spjd /*maxsize*/ATI_IXP_DMA_CHSEGS_MAX * ATI_IXP_NCHANS * 1254168404Spjd sizeof(struct atiixp_dma_op), 1255168404Spjd /*nsegments*/1, /*maxsegz*/0x3ffff, 1256168404Spjd /*flags*/0, /*lockfunc*/NULL, 1257185029Spjd /*lockarg*/NULL, &sc->sgd_dmat) != 0) { 1258185029Spjd device_printf(dev, "unable to create dma tag\n"); 1259185029Spjd goto bad; 1260185029Spjd } 1261168404Spjd 1262168404Spjd if (bus_dmamem_alloc(sc->sgd_dmat, (void **)&sc->sgd_table, 1263168404Spjd BUS_DMA_NOWAIT, &sc->sgd_dmamap) == -1) 1264168404Spjd goto bad; 1265168404Spjd 1266168404Spjd if (bus_dmamap_load(sc->sgd_dmat, sc->sgd_dmamap, sc->sgd_table, 1267168404Spjd ATI_IXP_DMA_CHSEGS_MAX * ATI_IXP_NCHANS * 1268168404Spjd sizeof(struct atiixp_dma_op), atiixp_dma_cb, sc, 0)) 1269185029Spjd goto bad; 1270185029Spjd 1271185029Spjd 1272185029Spjd atiixp_chip_pre_init(sc); 1273185029Spjd 1274185029Spjd sc->delayed_attach.ich_func = atiixp_chip_post_init; 1275185029Spjd sc->delayed_attach.ich_arg = sc; 1276185029Spjd if (cold == 0 || 1277185029Spjd config_intrhook_establish(&sc->delayed_attach) != 0) { 1278185029Spjd sc->delayed_attach.ich_func = NULL; 1279185029Spjd atiixp_chip_post_init(sc); 1280185029Spjd } 1281168404Spjd 1282168404Spjd return (0); 1283168404Spjd 1284168404Spjdbad: 1285168404Spjd atiixp_release_resource(sc); 1286168404Spjd return (ENXIO); 1287168404Spjd} 1288168404Spjd 1289168404Spjdstatic int 1290168404Spjdatiixp_pci_detach(device_t dev) 1291168404Spjd{ 1292185029Spjd int r; 1293185029Spjd struct atiixp_info *sc; 1294185029Spjd 1295185029Spjd sc = pcm_getdevinfo(dev); 1296168404Spjd if (sc != NULL) { 1297168404Spjd if (sc->codec != NULL) { 1298168404Spjd r = pcm_unregister(dev); 1299168404Spjd if (r) 1300168404Spjd return (r); 1301168404Spjd } 1302185029Spjd sc->codec = NULL; 1303185029Spjd if (sc->st != 0 && sc->sh != 0) 1304168404Spjd atiixp_disable_interrupts(sc); 1305168404Spjd atiixp_release_resource(sc); 1306168404Spjd free(sc, M_DEVBUF); 1307168404Spjd } 1308168404Spjd return (0); 1309168404Spjd} 1310168404Spjd 1311168404Spjdstatic int 1312168404Spjdatiixp_pci_suspend(device_t dev) 1313168404Spjd{ 1314168404Spjd struct atiixp_info *sc = pcm_getdevinfo(dev); 1315185029Spjd uint32_t value; 1316168404Spjd 1317185029Spjd /* quickly disable interrupts and save channels active state */ 1318168404Spjd atiixp_lock(sc); 1319168404Spjd atiixp_disable_interrupts(sc); 1320168404Spjd atiixp_unlock(sc); 1321168404Spjd 1322168404Spjd /* stop everything */ 1323168404Spjd if (sc->pch.active != 0) 1324168404Spjd atiixp_chan_trigger(NULL, &sc->pch, PCMTRIG_STOP); 1325168404Spjd if (sc->rch.active != 0) 1326168404Spjd atiixp_chan_trigger(NULL, &sc->rch, PCMTRIG_STOP); 1327168404Spjd 1328168404Spjd /* power down aclink and pci bus */ 1329168404Spjd atiixp_lock(sc); 1330168404Spjd value = atiixp_rd(sc, ATI_REG_CMD); 1331185029Spjd value |= ATI_REG_CMD_POWERDOWN | ATI_REG_CMD_AC_RESET; 1332168404Spjd atiixp_wr(sc, ATI_REG_CMD, ATI_REG_CMD_POWERDOWN); 1333168404Spjd pci_set_powerstate(dev, PCI_POWERSTATE_D3); 1334185029Spjd atiixp_unlock(sc); 1335168404Spjd 1336185029Spjd return (0); 1337185029Spjd} 1338185029Spjd 1339185029Spjdstatic int 1340168404Spjdatiixp_pci_resume(device_t dev) 1341185029Spjd{ 1342168404Spjd struct atiixp_info *sc = pcm_getdevinfo(dev); 1343168404Spjd 1344168404Spjd atiixp_lock(sc); 1345168404Spjd /* power up pci bus */ 1346168404Spjd pci_set_powerstate(dev, PCI_POWERSTATE_D0); 1347168404Spjd pci_enable_io(dev, SYS_RES_MEMORY); 1348168404Spjd pci_enable_busmaster(dev); 1349168404Spjd /* reset / power up aclink */ 1350168404Spjd atiixp_reset_aclink(sc); 1351168404Spjd atiixp_unlock(sc); 1352168404Spjd 1353168404Spjd if (mixer_reinit(dev) == -1) { 1354168404Spjd device_printf(dev, "unable to reinitialize the mixer\n"); 1355168404Spjd return (ENXIO); 1356168404Spjd } 1357168404Spjd 1358168404Spjd /* 1359168404Spjd * Resume channel activities. Reset channel format regardless 1360185029Spjd * of its previous state. 1361185029Spjd */ 1362168404Spjd if (sc->pch.channel != NULL) { 1363168404Spjd if (sc->pch.fmt != 0) 1364185029Spjd atiixp_chan_setformat(NULL, &sc->pch, sc->pch.fmt); 1365168404Spjd if (sc->pch.active != 0) 1366168404Spjd atiixp_chan_trigger(NULL, &sc->pch, PCMTRIG_START); 1367168404Spjd } 1368168404Spjd if (sc->rch.channel != NULL) { 1369168404Spjd if (sc->rch.fmt != 0) 1370185029Spjd atiixp_chan_setformat(NULL, &sc->rch, sc->rch.fmt); 1371168404Spjd if (sc->rch.active != 0) 1372168404Spjd atiixp_chan_trigger(NULL, &sc->rch, PCMTRIG_START); 1373168404Spjd } 1374168404Spjd 1375185029Spjd /* enable interrupts */ 1376168404Spjd atiixp_lock(sc); 1377168404Spjd if (sc->polling == 0) 1378185029Spjd atiixp_enable_interrupts(sc); 1379168404Spjd atiixp_unlock(sc); 1380168404Spjd 1381168404Spjd return (0); 1382185029Spjd} 1383185029Spjd 1384168404Spjdstatic device_method_t atiixp_methods[] = { 1385168404Spjd DEVMETHOD(device_probe, atiixp_pci_probe), 1386185029Spjd DEVMETHOD(device_attach, atiixp_pci_attach), 1387185029Spjd DEVMETHOD(device_detach, atiixp_pci_detach), 1388168404Spjd DEVMETHOD(device_suspend, atiixp_pci_suspend), 1389168404Spjd DEVMETHOD(device_resume, atiixp_pci_resume), 1390168404Spjd { 0, 0 } 1391168404Spjd}; 1392185029Spjd 1393168404Spjdstatic driver_t atiixp_driver = { 1394168404Spjd "pcm", 1395168404Spjd atiixp_methods, 1396168404Spjd PCM_SOFTC_SIZE, 1397185029Spjd}; 1398168404Spjd 1399168404SpjdDRIVER_MODULE(snd_atiixp, pci, atiixp_driver, pcm_devclass, 0, 0); 1400168404SpjdMODULE_DEPEND(snd_atiixp, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 1401168404SpjdMODULE_VERSION(snd_atiixp, 1); 1402168404Spjd