atiixp.c revision 155800
1152851Sariff/*- 2152851Sariff * Copyright (c) 2005 Ariff Abdullah <ariff@FreeBSD.org> 3152851Sariff * All rights reserved. 4152851Sariff * 5152851Sariff * Redistribution and use in source and binary forms, with or without 6152851Sariff * modification, are permitted provided that the following conditions 7152851Sariff * are met: 8152851Sariff * 1. Redistributions of source code must retain the above copyright 9152851Sariff * notice, this list of conditions and the following disclaimer. 10152851Sariff * 2. Redistributions in binary form must reproduce the above copyright 11152851Sariff * notice, this list of conditions and the following disclaimer in the 12152851Sariff * documentation and/or other materials provided with the distribution. 13152851Sariff * 14152851Sariff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15152851Sariff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16152851Sariff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17152851Sariff * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18152851Sariff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19152851Sariff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20152851Sariff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21152851Sariff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT 22152851Sariff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23152851Sariff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF 24152851Sariff * SUCH DAMAGE. 25152851Sariff */ 26152851Sariff 27152851Sariff/* 28152851Sariff * FreeBSD pcm driver for ATI IXP 150/200/250/300 AC97 controllers 29152851Sariff * 30152851Sariff * Features 31152851Sariff * * 16bit playback / recording 32152851Sariff * * 32bit native playback - yay! 33155800Sariff * * 32bit native recording (seems broken on few hardwares) 34152851Sariff * 35152851Sariff * Issues / TODO: 36152851Sariff * * SPDIF 37152851Sariff * * Support for more than 2 channels. 38152851Sariff * * VRA ? VRM ? DRA ? 39155800Sariff * * 32bit native recording seems broken on few hardwares, most 40155800Sariff * probably because of incomplete VRA/DRA cleanup. 41152851Sariff * 42152851Sariff * 43152851Sariff * Thanks goes to: 44152851Sariff * 45152851Sariff * Shaharil @ SCAN Associates whom relentlessly providing me the 46152851Sariff * mind blowing Acer Ferrari 4002 WLMi with this ATI IXP hardware. 47152851Sariff * 48152851Sariff * Reinoud Zandijk <reinoud@NetBSD.org> (auixp), which this driver is 49152851Sariff * largely based upon although large part of it has been reworked. His 50152851Sariff * driver is the primary reference and pretty much well documented. 51152851Sariff * 52152851Sariff * Takashi Iwai (ALSA snd-atiixp), for register definitions and some 53152851Sariff * random ninja hackery. 54152851Sariff */ 55152851Sariff 56152851Sariff#include <dev/sound/pcm/sound.h> 57152851Sariff#include <dev/sound/pcm/ac97.h> 58152851Sariff 59152851Sariff#include <dev/pci/pcireg.h> 60152851Sariff#include <dev/pci/pcivar.h> 61152851Sariff#include <sys/sysctl.h> 62152851Sariff#include <sys/endian.h> 63152851Sariff 64152851Sariff#include <dev/sound/pci/atiixp.h> 65152851Sariff 66152851SariffSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/atiixp.c 155800 2006-02-18 10:24:48Z ariff $"); 67152851Sariff 68152851Sariff 69152851Sariffstruct atiixp_dma_op { 70155800Sariff volatile uint32_t addr; 71155800Sariff volatile uint16_t status; 72155800Sariff volatile uint16_t size; 73155800Sariff volatile uint32_t next; 74152851Sariff}; 75152851Sariff 76152851Sariffstruct atiixp_info; 77152851Sariff 78152851Sariffstruct atiixp_chinfo { 79152851Sariff struct snd_dbuf *buffer; 80152851Sariff struct pcm_channel *channel; 81152851Sariff struct atiixp_info *parent; 82152851Sariff struct atiixp_dma_op *sgd_table; 83152851Sariff bus_addr_t sgd_addr; 84152851Sariff uint32_t enable_bit, flush_bit, linkptr_bit, dma_dt_cur_bit; 85152851Sariff uint32_t dma_segs; 86153708Sariff uint32_t fmt; 87153708Sariff int caps_32bit, dir, active; 88152851Sariff}; 89152851Sariff 90152851Sariffstruct atiixp_info { 91152851Sariff device_t dev; 92152851Sariff 93152851Sariff bus_space_tag_t st; 94152851Sariff bus_space_handle_t sh; 95152851Sariff bus_dma_tag_t parent_dmat; 96152851Sariff bus_dma_tag_t sgd_dmat; 97152851Sariff bus_dmamap_t sgd_dmamap; 98152851Sariff bus_addr_t sgd_addr; 99152851Sariff 100152851Sariff struct resource *reg, *irq; 101152851Sariff int regtype, regid, irqid; 102152851Sariff void *ih; 103152851Sariff struct ac97_info *codec; 104152851Sariff 105152851Sariff struct atiixp_chinfo pch; 106152851Sariff struct atiixp_chinfo rch; 107152851Sariff struct atiixp_dma_op *sgd_table; 108152851Sariff struct intr_config_hook delayed_attach; 109152851Sariff 110152851Sariff uint32_t bufsz; 111152851Sariff uint32_t codec_not_ready_bits, codec_idx, codec_found; 112152851Sariff uint32_t dma_segs; 113152851Sariff int registered_channels; 114152851Sariff 115152851Sariff struct mtx *lock; 116152851Sariff}; 117152851Sariff 118152851Sariff#define atiixp_rd(_sc, _reg) \ 119152851Sariff bus_space_read_4((_sc)->st, (_sc)->sh, _reg) 120152851Sariff#define atiixp_wr(_sc, _reg, _val) \ 121152851Sariff bus_space_write_4((_sc)->st, (_sc)->sh, _reg, _val) 122152851Sariff 123152851Sariff#define atiixp_lock(_sc) snd_mtxlock((_sc)->lock) 124152851Sariff#define atiixp_unlock(_sc) snd_mtxunlock((_sc)->lock) 125152851Sariff#define atiixp_assert(_sc) snd_mtxassert((_sc)->lock) 126152851Sariff 127152851Sariffstatic uint32_t atiixp_fmt_32bit[] = { 128152851Sariff AFMT_STEREO | AFMT_S16_LE, 129152851Sariff#ifdef AFMT_S32_LE 130152851Sariff AFMT_STEREO | AFMT_S32_LE, 131152851Sariff#endif 132152851Sariff 0 133152851Sariff}; 134152851Sariff 135152851Sariffstatic uint32_t atiixp_fmt[] = { 136152851Sariff AFMT_STEREO | AFMT_S16_LE, 137152851Sariff 0 138152851Sariff}; 139152851Sariff 140152851Sariffstatic struct pcmchan_caps atiixp_caps_32bit = { 141152851Sariff ATI_IXP_BASE_RATE, 142152851Sariff ATI_IXP_BASE_RATE, 143152851Sariff atiixp_fmt_32bit, 0 144152851Sariff}; 145152851Sariff 146152851Sariffstatic struct pcmchan_caps atiixp_caps = { 147152851Sariff ATI_IXP_BASE_RATE, 148152851Sariff ATI_IXP_BASE_RATE, 149152851Sariff atiixp_fmt, 0 150152851Sariff}; 151152851Sariff 152152851Sariffstatic const struct { 153152851Sariff uint16_t vendor; 154152851Sariff uint16_t devid; 155152851Sariff char *desc; 156152851Sariff} atiixp_hw[] = { 157152851Sariff { ATI_VENDOR_ID, ATI_IXP_200_ID, "ATI IXP 200" }, 158152851Sariff { ATI_VENDOR_ID, ATI_IXP_300_ID, "ATI IXP 300" }, 159152851Sariff { ATI_VENDOR_ID, ATI_IXP_400_ID, "ATI IXP 400" }, 160152851Sariff}; 161152851Sariff 162152851Sariffstatic void atiixp_enable_interrupts(struct atiixp_info *); 163152851Sariffstatic void atiixp_disable_interrupts(struct atiixp_info *); 164152851Sariffstatic void atiixp_reset_aclink(struct atiixp_info *); 165152851Sariffstatic void atiixp_flush_dma(struct atiixp_info *, struct atiixp_chinfo *); 166152851Sariffstatic void atiixp_enable_dma(struct atiixp_info *, struct atiixp_chinfo *); 167152851Sariffstatic void atiixp_disable_dma(struct atiixp_info *, struct atiixp_chinfo *); 168152851Sariff 169152851Sariffstatic int atiixp_waitready_codec(struct atiixp_info *); 170152851Sariffstatic int atiixp_rdcd(kobj_t, void *, int); 171152851Sariffstatic int atiixp_wrcd(kobj_t, void *, int, uint32_t); 172152851Sariff 173152851Sariffstatic void *atiixp_chan_init(kobj_t, void *, struct snd_dbuf *, 174152851Sariff struct pcm_channel *, int); 175152851Sariffstatic int atiixp_chan_setformat(kobj_t, void *, uint32_t); 176152851Sariffstatic int atiixp_chan_setspeed(kobj_t, void *, uint32_t); 177152851Sariffstatic int atiixp_chan_setblocksize(kobj_t, void *, uint32_t); 178152851Sariffstatic void atiixp_buildsgdt(struct atiixp_chinfo *); 179152851Sariffstatic int atiixp_chan_trigger(kobj_t, void *, int); 180152851Sariffstatic int atiixp_chan_getptr(kobj_t, void *); 181152851Sariffstatic struct pcmchan_caps *atiixp_chan_getcaps(kobj_t, void *); 182152851Sariff 183152851Sariffstatic void atiixp_intr(void *); 184152851Sariffstatic void atiixp_dma_cb(void *, bus_dma_segment_t *, int, int); 185152851Sariffstatic void atiixp_chip_pre_init(struct atiixp_info *); 186152851Sariffstatic void atiixp_chip_post_init(void *); 187152851Sariffstatic int atiixp_pci_probe(device_t); 188152851Sariffstatic int atiixp_pci_attach(device_t); 189152851Sariffstatic int atiixp_pci_detach(device_t); 190153708Sariffstatic int atiixp_pci_suspend(device_t); 191153708Sariffstatic int atiixp_pci_resume(device_t); 192152851Sariff 193152851Sariff/* 194152851Sariff * ATI IXP helper functions 195152851Sariff */ 196152851Sariffstatic void 197152851Sariffatiixp_enable_interrupts(struct atiixp_info *sc) 198152851Sariff{ 199152851Sariff uint32_t value; 200152851Sariff 201152851Sariff /* clear all pending */ 202152851Sariff atiixp_wr(sc, ATI_REG_ISR, 0xffffffff); 203152851Sariff 204152851Sariff /* enable all relevant interrupt sources we can handle */ 205152851Sariff value = atiixp_rd(sc, ATI_REG_IER); 206152851Sariff 207152851Sariff value |= ATI_REG_IER_IO_STATUS_EN; 208152851Sariff 209152851Sariff /* 210152851Sariff * Disable / ignore internal xrun/spdf interrupt flags 211152851Sariff * since it doesn't interest us (for now). 212152851Sariff */ 213152851Sariff#if 0 214152851Sariff value |= ATI_REG_IER_IN_XRUN_EN; 215152851Sariff value |= ATI_REG_IER_OUT_XRUN_EN; 216152851Sariff 217152851Sariff value |= ATI_REG_IER_SPDF_XRUN_EN; 218152851Sariff value |= ATI_REG_IER_SPDF_STATUS_EN; 219152851Sariff#endif 220152851Sariff 221152851Sariff atiixp_wr(sc, ATI_REG_IER, value); 222152851Sariff} 223152851Sariff 224152851Sariffstatic void 225152851Sariffatiixp_disable_interrupts(struct atiixp_info *sc) 226152851Sariff{ 227152851Sariff /* disable all interrupt sources */ 228152851Sariff atiixp_wr(sc, ATI_REG_IER, 0); 229152851Sariff 230152851Sariff /* clear all pending */ 231152851Sariff atiixp_wr(sc, ATI_REG_ISR, 0xffffffff); 232152851Sariff} 233152851Sariff 234152851Sariffstatic void 235152851Sariffatiixp_reset_aclink(struct atiixp_info *sc) 236152851Sariff{ 237152851Sariff uint32_t value, timeout; 238152851Sariff 239152851Sariff /* if power is down, power it up */ 240152851Sariff value = atiixp_rd(sc, ATI_REG_CMD); 241152851Sariff if (value & ATI_REG_CMD_POWERDOWN) { 242152851Sariff /* explicitly enable power */ 243152851Sariff value &= ~ATI_REG_CMD_POWERDOWN; 244152851Sariff atiixp_wr(sc, ATI_REG_CMD, value); 245152851Sariff 246152851Sariff /* have to wait at least 10 usec for it to initialise */ 247152851Sariff DELAY(20); 248152851Sariff }; 249152851Sariff 250152851Sariff /* perform a soft reset */ 251152851Sariff value = atiixp_rd(sc, ATI_REG_CMD); 252152851Sariff value |= ATI_REG_CMD_AC_SOFT_RESET; 253152851Sariff atiixp_wr(sc, ATI_REG_CMD, value); 254152851Sariff 255152851Sariff /* need to read the CMD reg and wait aprox. 10 usec to init */ 256152851Sariff value = atiixp_rd(sc, ATI_REG_CMD); 257152851Sariff DELAY(20); 258152851Sariff 259152851Sariff /* clear soft reset flag again */ 260152851Sariff value = atiixp_rd(sc, ATI_REG_CMD); 261152851Sariff value &= ~ATI_REG_CMD_AC_SOFT_RESET; 262152851Sariff atiixp_wr(sc, ATI_REG_CMD, value); 263152851Sariff 264152851Sariff /* check if the ac-link is working; reset device otherwise */ 265152851Sariff timeout = 10; 266152851Sariff value = atiixp_rd(sc, ATI_REG_CMD); 267152851Sariff while (!(value & ATI_REG_CMD_ACLINK_ACTIVE) 268152851Sariff && --timeout) { 269153708Sariff#if 0 270152851Sariff device_printf(sc->dev, "not up; resetting aclink hardware\n"); 271153708Sariff#endif 272152851Sariff 273152851Sariff /* dip aclink reset but keep the acsync */ 274152851Sariff value &= ~ATI_REG_CMD_AC_RESET; 275152851Sariff value |= ATI_REG_CMD_AC_SYNC; 276152851Sariff atiixp_wr(sc, ATI_REG_CMD, value); 277152851Sariff 278152851Sariff /* need to read CMD again and wait again (clocking in issue?) */ 279152851Sariff value = atiixp_rd(sc, ATI_REG_CMD); 280152851Sariff DELAY(20); 281152851Sariff 282152851Sariff /* assert aclink reset again */ 283152851Sariff value = atiixp_rd(sc, ATI_REG_CMD); 284152851Sariff value |= ATI_REG_CMD_AC_RESET; 285152851Sariff atiixp_wr(sc, ATI_REG_CMD, value); 286152851Sariff 287152851Sariff /* check if its active now */ 288152851Sariff value = atiixp_rd(sc, ATI_REG_CMD); 289152851Sariff }; 290152851Sariff 291152851Sariff if (timeout == 0) 292152851Sariff device_printf(sc->dev, "giving up aclink reset\n"); 293153708Sariff#if 0 294152851Sariff if (timeout != 10) 295152851Sariff device_printf(sc->dev, "aclink hardware reset successful\n"); 296153708Sariff#endif 297152851Sariff 298152851Sariff /* assert reset and sync for safety */ 299152851Sariff value = atiixp_rd(sc, ATI_REG_CMD); 300152851Sariff value |= ATI_REG_CMD_AC_SYNC | ATI_REG_CMD_AC_RESET; 301152851Sariff atiixp_wr(sc, ATI_REG_CMD, value); 302152851Sariff} 303152851Sariff 304152851Sariffstatic void 305152851Sariffatiixp_flush_dma(struct atiixp_info *sc, struct atiixp_chinfo *ch) 306152851Sariff{ 307152851Sariff atiixp_wr(sc, ATI_REG_FIFO_FLUSH, ch->flush_bit); 308152851Sariff} 309152851Sariff 310152851Sariffstatic void 311152851Sariffatiixp_enable_dma(struct atiixp_info *sc, struct atiixp_chinfo *ch) 312152851Sariff{ 313152851Sariff uint32_t value; 314152851Sariff 315152851Sariff value = atiixp_rd(sc, ATI_REG_CMD); 316152851Sariff if (!(value & ch->enable_bit)) { 317152851Sariff value |= ch->enable_bit; 318152851Sariff atiixp_wr(sc, ATI_REG_CMD, value); 319152851Sariff } 320152851Sariff} 321152851Sariff 322152851Sariffstatic void 323152851Sariffatiixp_disable_dma(struct atiixp_info *sc, struct atiixp_chinfo *ch) 324152851Sariff{ 325152851Sariff uint32_t value; 326152851Sariff 327152851Sariff value = atiixp_rd(sc, ATI_REG_CMD); 328152851Sariff if (value & ch->enable_bit) { 329152851Sariff value &= ~ch->enable_bit; 330152851Sariff atiixp_wr(sc, ATI_REG_CMD, value); 331152851Sariff } 332152851Sariff} 333152851Sariff 334152851Sariff/* 335152851Sariff * AC97 interface 336152851Sariff */ 337152851Sariffstatic int 338152851Sariffatiixp_waitready_codec(struct atiixp_info *sc) 339152851Sariff{ 340152851Sariff int timeout = 500; 341152851Sariff 342152851Sariff do { 343152851Sariff if ((atiixp_rd(sc, ATI_REG_PHYS_OUT_ADDR) & 344152851Sariff ATI_REG_PHYS_OUT_ADDR_EN) == 0) 345152851Sariff return 0; 346152851Sariff DELAY(1); 347152851Sariff } while (timeout--); 348152851Sariff 349152851Sariff return -1; 350152851Sariff} 351152851Sariff 352152851Sariffstatic int 353152851Sariffatiixp_rdcd(kobj_t obj, void *devinfo, int reg) 354152851Sariff{ 355152851Sariff struct atiixp_info *sc = devinfo; 356152851Sariff uint32_t data; 357152851Sariff int timeout; 358152851Sariff 359152851Sariff if (atiixp_waitready_codec(sc)) 360152851Sariff return -1; 361152851Sariff 362152851Sariff data = (reg << ATI_REG_PHYS_OUT_ADDR_SHIFT) | 363152851Sariff ATI_REG_PHYS_OUT_ADDR_EN | 364152851Sariff ATI_REG_PHYS_OUT_RW | sc->codec_idx; 365152851Sariff 366152851Sariff atiixp_wr(sc, ATI_REG_PHYS_OUT_ADDR, data); 367152851Sariff 368152851Sariff if (atiixp_waitready_codec(sc)) 369152851Sariff return -1; 370152851Sariff 371152851Sariff timeout = 500; 372152851Sariff do { 373152851Sariff data = atiixp_rd(sc, ATI_REG_PHYS_IN_ADDR); 374152851Sariff if (data & ATI_REG_PHYS_IN_READ_FLAG) 375152851Sariff return data >> ATI_REG_PHYS_IN_DATA_SHIFT; 376152851Sariff DELAY(1); 377152851Sariff } while (timeout--); 378152851Sariff 379152851Sariff if (reg < 0x7c) 380152851Sariff device_printf(sc->dev, "codec read timeout! (reg 0x%x)\n", reg); 381152851Sariff 382152851Sariff return -1; 383152851Sariff} 384152851Sariff 385152851Sariffstatic int 386152851Sariffatiixp_wrcd(kobj_t obj, void *devinfo, int reg, uint32_t data) 387152851Sariff{ 388152851Sariff struct atiixp_info *sc = devinfo; 389152851Sariff 390152851Sariff if (atiixp_waitready_codec(sc)) 391152851Sariff return -1; 392152851Sariff 393152851Sariff data = (data << ATI_REG_PHYS_OUT_DATA_SHIFT) | 394152851Sariff (((uint32_t)reg) << ATI_REG_PHYS_OUT_ADDR_SHIFT) | 395152851Sariff ATI_REG_PHYS_OUT_ADDR_EN | sc->codec_idx; 396152851Sariff 397152851Sariff atiixp_wr(sc, ATI_REG_PHYS_OUT_ADDR, data); 398152851Sariff 399152851Sariff return 0; 400152851Sariff} 401152851Sariff 402152851Sariffstatic kobj_method_t atiixp_ac97_methods[] = { 403152851Sariff KOBJMETHOD(ac97_read, atiixp_rdcd), 404152851Sariff KOBJMETHOD(ac97_write, atiixp_wrcd), 405152851Sariff { 0, 0 } 406152851Sariff}; 407152851SariffAC97_DECLARE(atiixp_ac97); 408152851Sariff 409152851Sariff/* 410152851Sariff * Playback / Record channel interface 411152851Sariff */ 412152851Sariffstatic void * 413152851Sariffatiixp_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, 414152851Sariff struct pcm_channel *c, int dir) 415152851Sariff{ 416152851Sariff struct atiixp_info *sc = devinfo; 417152851Sariff struct atiixp_chinfo *ch; 418152851Sariff int num; 419152851Sariff 420152851Sariff atiixp_lock(sc); 421152851Sariff 422152851Sariff if (dir == PCMDIR_PLAY) { 423152851Sariff ch = &sc->pch; 424152851Sariff ch->linkptr_bit = ATI_REG_OUT_DMA_LINKPTR; 425152851Sariff ch->enable_bit = ATI_REG_CMD_OUT_DMA_EN | ATI_REG_CMD_SEND_EN; 426152851Sariff ch->flush_bit = ATI_REG_FIFO_OUT_FLUSH; 427152851Sariff ch->dma_dt_cur_bit = ATI_REG_OUT_DMA_DT_CUR; 428152851Sariff /* Native 32bit playback working properly */ 429152851Sariff ch->caps_32bit = 1; 430152851Sariff } else { 431152851Sariff ch = &sc->rch; 432152851Sariff ch->linkptr_bit = ATI_REG_IN_DMA_LINKPTR; 433152851Sariff ch->enable_bit = ATI_REG_CMD_IN_DMA_EN | ATI_REG_CMD_RECEIVE_EN; 434152851Sariff ch->flush_bit = ATI_REG_FIFO_IN_FLUSH; 435152851Sariff ch->dma_dt_cur_bit = ATI_REG_IN_DMA_DT_CUR; 436152851Sariff /* XXX Native 32bit recording appear to be broken */ 437154595Sariff ch->caps_32bit = 1; 438152851Sariff } 439152851Sariff 440152851Sariff ch->buffer = b; 441152851Sariff ch->parent = sc; 442152851Sariff ch->channel = c; 443152851Sariff ch->dir = dir; 444152851Sariff ch->dma_segs = sc->dma_segs; 445152851Sariff 446152851Sariff atiixp_unlock(sc); 447152851Sariff 448152851Sariff if (sndbuf_alloc(ch->buffer, sc->parent_dmat, sc->bufsz) == -1) 449152851Sariff return NULL; 450152851Sariff 451152851Sariff atiixp_lock(sc); 452152851Sariff num = sc->registered_channels++; 453152851Sariff ch->sgd_table = &sc->sgd_table[num * ch->dma_segs]; 454152851Sariff ch->sgd_addr = sc->sgd_addr + 455152851Sariff (num * ch->dma_segs * sizeof(struct atiixp_dma_op)); 456152851Sariff atiixp_disable_dma(sc, ch); 457152851Sariff atiixp_unlock(sc); 458152851Sariff 459152851Sariff return ch; 460152851Sariff} 461152851Sariff 462152851Sariffstatic int 463152851Sariffatiixp_chan_setformat(kobj_t obj, void *data, uint32_t format) 464152851Sariff{ 465152851Sariff struct atiixp_chinfo *ch = data; 466152851Sariff struct atiixp_info *sc = ch->parent; 467152851Sariff uint32_t value; 468152851Sariff 469152851Sariff atiixp_lock(sc); 470152851Sariff if (ch->dir == PCMDIR_REC) { 471152851Sariff value = atiixp_rd(sc, ATI_REG_CMD); 472152851Sariff value &= ~ATI_REG_CMD_INTERLEAVE_IN; 473155800Sariff if ((format & AFMT_32BIT) == 0) 474152851Sariff value |= ATI_REG_CMD_INTERLEAVE_IN; 475152851Sariff atiixp_wr(sc, ATI_REG_CMD, value); 476152851Sariff } else { 477152851Sariff value = atiixp_rd(sc, ATI_REG_OUT_DMA_SLOT); 478152851Sariff value &= ~ATI_REG_OUT_DMA_SLOT_MASK; 479152851Sariff /* We do not have support for more than 2 channels, _yet_. */ 480152851Sariff value |= ATI_REG_OUT_DMA_SLOT_BIT(3) | 481152851Sariff ATI_REG_OUT_DMA_SLOT_BIT(4); 482152851Sariff value |= 0x04 << ATI_REG_OUT_DMA_THRESHOLD_SHIFT; 483152851Sariff atiixp_wr(sc, ATI_REG_OUT_DMA_SLOT, value); 484152851Sariff value = atiixp_rd(sc, ATI_REG_CMD); 485152851Sariff value &= ~ATI_REG_CMD_INTERLEAVE_OUT; 486155800Sariff if ((format & AFMT_32BIT) == 0) 487152851Sariff value |= ATI_REG_CMD_INTERLEAVE_OUT; 488152851Sariff atiixp_wr(sc, ATI_REG_CMD, value); 489152851Sariff value = atiixp_rd(sc, ATI_REG_6CH_REORDER); 490152851Sariff value &= ~ATI_REG_6CH_REORDER_EN; 491152851Sariff atiixp_wr(sc, ATI_REG_6CH_REORDER, value); 492152851Sariff } 493153708Sariff ch->fmt = format; 494152851Sariff atiixp_unlock(sc); 495152851Sariff 496152851Sariff return 0; 497152851Sariff} 498152851Sariff 499152851Sariffstatic int 500152851Sariffatiixp_chan_setspeed(kobj_t obj, void *data, uint32_t spd) 501152851Sariff{ 502152851Sariff /* XXX We're supposed to do VRA/DRA processing right here */ 503152851Sariff return ATI_IXP_BASE_RATE; 504152851Sariff} 505152851Sariff 506152851Sariffstatic int 507152851Sariffatiixp_chan_setblocksize(kobj_t obj, void *data, uint32_t blksz) 508152851Sariff{ 509152851Sariff struct atiixp_chinfo *ch = data; 510152851Sariff struct atiixp_info *sc = ch->parent; 511152851Sariff 512152851Sariff if (blksz > (sc->bufsz / ch->dma_segs)) 513152851Sariff blksz = sc->bufsz / ch->dma_segs; 514152851Sariff 515152851Sariff sndbuf_resize(ch->buffer, ch->dma_segs, blksz); 516152851Sariff 517152851Sariff return sndbuf_getblksz(ch->buffer); 518152851Sariff} 519152851Sariff 520152851Sariffstatic void 521152851Sariffatiixp_buildsgdt(struct atiixp_chinfo *ch) 522152851Sariff{ 523152851Sariff uint32_t addr, blksz; 524152851Sariff int i; 525152851Sariff 526152851Sariff addr = sndbuf_getbufaddr(ch->buffer); 527152851Sariff blksz = sndbuf_getblksz(ch->buffer); 528152851Sariff 529152851Sariff for (i = 0; i < ch->dma_segs; i++) { 530152851Sariff ch->sgd_table[i].addr = htole32(addr + (i * blksz)); 531152851Sariff ch->sgd_table[i].status = htole16(0); 532152851Sariff ch->sgd_table[i].size = htole16(blksz >> 2); 533152851Sariff ch->sgd_table[i].next = htole32((uint32_t)ch->sgd_addr + 534152851Sariff (((i + 1) % ch->dma_segs) * 535152851Sariff sizeof(struct atiixp_dma_op))); 536152851Sariff } 537152851Sariff} 538152851Sariff 539152851Sariffstatic int 540152851Sariffatiixp_chan_trigger(kobj_t obj, void *data, int go) 541152851Sariff{ 542152851Sariff struct atiixp_chinfo *ch = data; 543152851Sariff struct atiixp_info *sc = ch->parent; 544152851Sariff uint32_t value; 545152851Sariff 546152851Sariff atiixp_lock(sc); 547152851Sariff 548152851Sariff switch (go) { 549152851Sariff case PCMTRIG_START: 550152851Sariff atiixp_flush_dma(sc, ch); 551152851Sariff atiixp_buildsgdt(ch); 552152851Sariff atiixp_wr(sc, ch->linkptr_bit, 0); 553152851Sariff atiixp_enable_dma(sc, ch); 554152851Sariff atiixp_wr(sc, ch->linkptr_bit, 555152851Sariff (uint32_t)ch->sgd_addr | ATI_REG_LINKPTR_EN); 556152851Sariff break; 557152851Sariff case PCMTRIG_STOP: 558152851Sariff case PCMTRIG_ABORT: 559152851Sariff atiixp_disable_dma(sc, ch); 560152851Sariff atiixp_flush_dma(sc, ch); 561152851Sariff break; 562152851Sariff default: 563152851Sariff atiixp_unlock(sc); 564152851Sariff return 0; 565152851Sariff break; 566152851Sariff } 567152851Sariff 568152851Sariff /* Update bus busy status */ 569152851Sariff value = atiixp_rd(sc, ATI_REG_IER); 570152851Sariff if (atiixp_rd(sc, ATI_REG_CMD) & ( 571152851Sariff ATI_REG_CMD_SEND_EN | ATI_REG_CMD_RECEIVE_EN | 572152851Sariff ATI_REG_CMD_SPDF_OUT_EN)) 573152851Sariff value |= ATI_REG_IER_SET_BUS_BUSY; 574152851Sariff else 575152851Sariff value &= ~ATI_REG_IER_SET_BUS_BUSY; 576152851Sariff atiixp_wr(sc, ATI_REG_IER, value); 577152851Sariff 578152851Sariff atiixp_unlock(sc); 579152851Sariff 580152851Sariff return 0; 581152851Sariff} 582152851Sariff 583152851Sariffstatic int 584152851Sariffatiixp_chan_getptr(kobj_t obj, void *data) 585152851Sariff{ 586152851Sariff struct atiixp_chinfo *ch = data; 587152851Sariff struct atiixp_info *sc = ch->parent; 588155800Sariff uint32_t addr, align, retry, sz; 589155800Sariff volatile uint32_t ptr; 590152851Sariff 591155800Sariff addr = sndbuf_getbufaddr(ch->buffer); 592155800Sariff align = (ch->fmt & AFMT_32BIT) ? 7 : 3; 593155800Sariff retry = 100; 594155800Sariff sz = sndbuf_getblksz(ch->buffer) * ch->dma_segs; 595155800Sariff 596152851Sariff atiixp_lock(sc); 597155800Sariff do { 598155800Sariff ptr = atiixp_rd(sc, ch->dma_dt_cur_bit); 599155800Sariff if (ptr < addr) 600155800Sariff continue; 601155800Sariff ptr -= addr; 602155800Sariff if (ptr < sz && !(ptr & align)) 603155800Sariff break; 604155800Sariff } while (--retry); 605152851Sariff atiixp_unlock(sc); 606152851Sariff 607155800Sariff#if 0 608155800Sariff if (retry != 100) { 609155800Sariff device_printf(sc->dev, 610155800Sariff "%saligned hwptr: dir=PCMDIR_%s ptr=%u fmt=0x%08x retry=%d\n", 611155800Sariff (ptr & align) ? "un" : "", 612155800Sariff (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC", ptr, 613155800Sariff ch->fmt, 100 - retry); 614155800Sariff } 615155800Sariff#endif 616155800Sariff 617155800Sariff return (retry > 0) ? ptr & ~align : 0; 618152851Sariff} 619152851Sariff 620152851Sariffstatic struct pcmchan_caps * 621152851Sariffatiixp_chan_getcaps(kobj_t obj, void *data) 622152851Sariff{ 623152851Sariff struct atiixp_chinfo *ch = data; 624152851Sariff 625152851Sariff if (ch->caps_32bit) 626152851Sariff return &atiixp_caps_32bit; 627152851Sariff return &atiixp_caps; 628152851Sariff} 629152851Sariff 630152851Sariffstatic kobj_method_t atiixp_chan_methods[] = { 631152851Sariff KOBJMETHOD(channel_init, atiixp_chan_init), 632152851Sariff KOBJMETHOD(channel_setformat, atiixp_chan_setformat), 633152851Sariff KOBJMETHOD(channel_setspeed, atiixp_chan_setspeed), 634152851Sariff KOBJMETHOD(channel_setblocksize, atiixp_chan_setblocksize), 635152851Sariff KOBJMETHOD(channel_trigger, atiixp_chan_trigger), 636152851Sariff KOBJMETHOD(channel_getptr, atiixp_chan_getptr), 637152851Sariff KOBJMETHOD(channel_getcaps, atiixp_chan_getcaps), 638152851Sariff { 0, 0 } 639152851Sariff}; 640152851SariffCHANNEL_DECLARE(atiixp_chan); 641152851Sariff 642152851Sariff/* 643152851Sariff * PCI driver interface 644152851Sariff */ 645152851Sariffstatic void 646152851Sariffatiixp_intr(void *p) 647152851Sariff{ 648152851Sariff struct atiixp_info *sc = p; 649152851Sariff uint32_t status, enable, detected_codecs; 650152851Sariff 651152851Sariff atiixp_lock(sc); 652152851Sariff status = atiixp_rd(sc, ATI_REG_ISR); 653152851Sariff 654152851Sariff if (status == 0) { 655152851Sariff atiixp_unlock(sc); 656152851Sariff return; 657152851Sariff } 658152851Sariff 659153708Sariff if ((status & ATI_REG_ISR_IN_STATUS) && sc->rch.channel) { 660152851Sariff atiixp_unlock(sc); 661152851Sariff chn_intr(sc->rch.channel); 662152851Sariff atiixp_lock(sc); 663152851Sariff } 664153708Sariff if ((status & ATI_REG_ISR_OUT_STATUS) && sc->pch.channel) { 665152851Sariff atiixp_unlock(sc); 666152851Sariff chn_intr(sc->pch.channel); 667152851Sariff atiixp_lock(sc); 668152851Sariff } 669152851Sariff 670152851Sariff#if 0 671152851Sariff if (status & ATI_REG_ISR_IN_XRUN) { 672152851Sariff device_printf(sc->dev, 673152851Sariff "Recieve IN XRUN interrupt\n"); 674152851Sariff } 675152851Sariff if (status & ATI_REG_ISR_OUT_XRUN) { 676152851Sariff device_printf(sc->dev, 677152851Sariff "Recieve OUT XRUN interrupt\n"); 678152851Sariff } 679152851Sariff#endif 680152851Sariff 681152851Sariff if (status & CODEC_CHECK_BITS) { 682152851Sariff /* mark missing codecs as not ready */ 683152851Sariff detected_codecs = status & CODEC_CHECK_BITS; 684152851Sariff sc->codec_not_ready_bits |= detected_codecs; 685152851Sariff 686152851Sariff /* disable detected interupt sources */ 687152851Sariff enable = atiixp_rd(sc, ATI_REG_IER); 688152851Sariff enable &= ~detected_codecs; 689152851Sariff atiixp_wr(sc, ATI_REG_IER, enable); 690152851Sariff } 691152851Sariff 692152851Sariff /* acknowledge */ 693152851Sariff atiixp_wr(sc, ATI_REG_ISR, status); 694152851Sariff atiixp_unlock(sc); 695152851Sariff} 696152851Sariff 697152851Sariffstatic void 698152851Sariffatiixp_dma_cb(void *p, bus_dma_segment_t *bds, int a, int b) 699152851Sariff{ 700152851Sariff struct atiixp_info *sc = (struct atiixp_info *)p; 701152851Sariff sc->sgd_addr = bds->ds_addr; 702152851Sariff} 703152851Sariff 704152851Sariffstatic void 705152851Sariffatiixp_chip_pre_init(struct atiixp_info *sc) 706152851Sariff{ 707152851Sariff uint32_t value; 708152851Sariff 709152851Sariff atiixp_lock(sc); 710152851Sariff 711152851Sariff /* disable interrupts */ 712152851Sariff atiixp_disable_interrupts(sc); 713152851Sariff 714152851Sariff /* clear all DMA enables (preserving rest of settings) */ 715152851Sariff value = atiixp_rd(sc, ATI_REG_CMD); 716152851Sariff value &= ~(ATI_REG_CMD_IN_DMA_EN | ATI_REG_CMD_OUT_DMA_EN | 717152851Sariff ATI_REG_CMD_SPDF_OUT_EN ); 718152851Sariff atiixp_wr(sc, ATI_REG_CMD, value); 719152851Sariff 720152851Sariff /* reset aclink */ 721152851Sariff atiixp_reset_aclink(sc); 722152851Sariff 723152851Sariff sc->codec_not_ready_bits = 0; 724152851Sariff 725152851Sariff /* enable all codecs to interrupt as well as the new frame interrupt */ 726152851Sariff atiixp_wr(sc, ATI_REG_IER, CODEC_CHECK_BITS); 727152851Sariff 728152851Sariff atiixp_unlock(sc); 729152851Sariff} 730152851Sariff 731152851Sariffstatic void 732152851Sariffatiixp_chip_post_init(void *arg) 733152851Sariff{ 734152851Sariff struct atiixp_info *sc = (struct atiixp_info *)arg; 735155800Sariff uint32_t subdev; 736152851Sariff int i, timeout, found; 737152851Sariff char status[SND_STATUSLEN]; 738152851Sariff 739152851Sariff atiixp_lock(sc); 740152851Sariff 741152851Sariff if (sc->delayed_attach.ich_func) { 742152851Sariff config_intrhook_disestablish(&sc->delayed_attach); 743152851Sariff sc->delayed_attach.ich_func = NULL; 744152851Sariff } 745152851Sariff 746152851Sariff /* wait for the interrupts to happen */ 747152851Sariff timeout = 100; /* 100.000 usec -> 0.1 sec */ 748152851Sariff 749152851Sariff while (--timeout) { 750152851Sariff atiixp_unlock(sc); 751152851Sariff DELAY(1000); 752152851Sariff atiixp_lock(sc); 753152851Sariff if (sc->codec_not_ready_bits) 754152851Sariff break; 755152851Sariff } 756152851Sariff 757152851Sariff atiixp_disable_interrupts(sc); 758152851Sariff 759152851Sariff if (timeout == 0) { 760152851Sariff device_printf(sc->dev, 761152851Sariff "WARNING: timeout during codec detection; " 762152851Sariff "codecs might be present but haven't interrupted\n"); 763152851Sariff atiixp_unlock(sc); 764152851Sariff return; 765152851Sariff } 766152851Sariff 767152851Sariff found = 0; 768152851Sariff 769152851Sariff /* 770152851Sariff * ATI IXP can have upto 3 codecs, but single codec should be 771152851Sariff * suffice for now. 772152851Sariff */ 773152851Sariff if (!(sc->codec_not_ready_bits & 774152851Sariff ATI_REG_ISR_CODEC0_NOT_READY)) { 775152851Sariff /* codec 0 present */ 776152851Sariff sc->codec_found++; 777152851Sariff sc->codec_idx = 0; 778152851Sariff found++; 779152851Sariff } 780152851Sariff 781152851Sariff if (!(sc->codec_not_ready_bits & 782152851Sariff ATI_REG_ISR_CODEC1_NOT_READY)) { 783152851Sariff /* codec 1 present */ 784152851Sariff sc->codec_found++; 785152851Sariff } 786152851Sariff 787152851Sariff if (!(sc->codec_not_ready_bits & 788152851Sariff ATI_REG_ISR_CODEC2_NOT_READY)) { 789152851Sariff /* codec 2 present */ 790152851Sariff sc->codec_found++; 791152851Sariff } 792152851Sariff 793152851Sariff atiixp_unlock(sc); 794152851Sariff 795152851Sariff if (found == 0) 796152851Sariff return; 797152851Sariff 798152851Sariff /* create/init mixer */ 799152851Sariff sc->codec = AC97_CREATE(sc->dev, sc, atiixp_ac97); 800152851Sariff if (sc->codec == NULL) 801152851Sariff goto postinitbad; 802152851Sariff 803155800Sariff subdev = (pci_get_subdevice(sc->dev) << 16) | pci_get_subvendor(sc->dev); 804155800Sariff switch (subdev) { 805155800Sariff case 0x2043161f: /* Maxselect x710s - http://maxselect.ru/ */ 806155800Sariff ac97_setflags(sc->codec, ac97_getflags(sc->codec) | AC97_F_EAPD_INV); 807155800Sariff break; 808155800Sariff default: 809155800Sariff break; 810155800Sariff } 811155800Sariff 812152851Sariff mixer_init(sc->dev, ac97_getmixerclass(), sc->codec); 813152851Sariff 814152851Sariff if (pcm_register(sc->dev, sc, ATI_IXP_NPCHAN, ATI_IXP_NRCHAN)) 815152851Sariff goto postinitbad; 816152851Sariff 817152851Sariff for (i = 0; i < ATI_IXP_NPCHAN; i++) 818152851Sariff pcm_addchan(sc->dev, PCMDIR_PLAY, &atiixp_chan_class, sc); 819152851Sariff for (i = 0; i < ATI_IXP_NRCHAN; i++) 820152851Sariff pcm_addchan(sc->dev, PCMDIR_REC, &atiixp_chan_class, sc); 821152851Sariff 822152851Sariff snprintf(status, SND_STATUSLEN, "at memory 0x%lx irq %ld %s", 823152851Sariff rman_get_start(sc->reg), rman_get_start(sc->irq), 824152851Sariff PCM_KLDSTRING(snd_atiixp)); 825152851Sariff 826152851Sariff pcm_setstatus(sc->dev, status); 827152851Sariff 828152851Sariff atiixp_lock(sc); 829152851Sariff atiixp_enable_interrupts(sc); 830152851Sariff atiixp_unlock(sc); 831152851Sariff 832152851Sariff return; 833152851Sariff 834152851Sariffpostinitbad: 835152851Sariff if (sc->codec) 836152851Sariff ac97_destroy(sc->codec); 837152851Sariff if (sc->ih) 838152851Sariff bus_teardown_intr(sc->dev, sc->irq, sc->ih); 839152851Sariff if (sc->reg) 840152851Sariff bus_release_resource(sc->dev, sc->regtype, sc->regid, sc->reg); 841152851Sariff if (sc->irq) 842152851Sariff bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irqid, sc->irq); 843152851Sariff if (sc->parent_dmat) 844152851Sariff bus_dma_tag_destroy(sc->parent_dmat); 845152851Sariff if (sc->sgd_dmamap) 846152851Sariff bus_dmamap_unload(sc->sgd_dmat, sc->sgd_dmamap); 847152851Sariff if (sc->sgd_dmat) 848152851Sariff bus_dma_tag_destroy(sc->sgd_dmat); 849152851Sariff if (sc->lock) 850152851Sariff snd_mtxfree(sc->lock); 851152851Sariff free(sc, M_DEVBUF); 852152851Sariff} 853152851Sariff 854152851Sariffstatic int 855152851Sariffatiixp_pci_probe(device_t dev) 856152851Sariff{ 857152851Sariff int i; 858152851Sariff uint16_t devid, vendor; 859152851Sariff 860152851Sariff vendor = pci_get_vendor(dev); 861152851Sariff devid = pci_get_device(dev); 862152851Sariff for (i = 0; i < sizeof(atiixp_hw)/sizeof(atiixp_hw[0]); i++) { 863152851Sariff if (vendor == atiixp_hw[i].vendor && 864152851Sariff devid == atiixp_hw[i].devid) { 865152851Sariff device_set_desc(dev, atiixp_hw[i].desc); 866152851Sariff return BUS_PROBE_DEFAULT; 867152851Sariff } 868152851Sariff } 869152851Sariff 870152851Sariff return ENXIO; 871152851Sariff} 872152851Sariff 873152851Sariffstatic int 874152851Sariffatiixp_pci_attach(device_t dev) 875152851Sariff{ 876152851Sariff struct atiixp_info *sc; 877152851Sariff int i; 878152851Sariff 879152851Sariff if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) { 880152851Sariff device_printf(dev, "cannot allocate softc\n"); 881152851Sariff return ENXIO; 882152851Sariff } 883152851Sariff 884152851Sariff sc->lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc"); 885152851Sariff sc->dev = dev; 886152851Sariff /* 887152851Sariff * Default DMA segments per playback / recording channel 888152851Sariff */ 889152851Sariff sc->dma_segs = ATI_IXP_DMA_CHSEGS; 890152851Sariff 891152851Sariff pci_set_powerstate(dev, PCI_POWERSTATE_D0); 892152851Sariff pci_enable_busmaster(dev); 893152851Sariff 894152851Sariff sc->regid = PCIR_BAR(0); 895152851Sariff sc->regtype = SYS_RES_MEMORY; 896152851Sariff sc->reg = bus_alloc_resource_any(dev, sc->regtype, &sc->regid, 897152851Sariff RF_ACTIVE); 898152851Sariff 899152851Sariff if (!sc->reg) { 900152851Sariff device_printf(dev, "unable to allocate register space\n"); 901152851Sariff goto bad; 902152851Sariff } 903152851Sariff 904152851Sariff sc->st = rman_get_bustag(sc->reg); 905152851Sariff sc->sh = rman_get_bushandle(sc->reg); 906152851Sariff 907152851Sariff sc->bufsz = pcm_getbuffersize(dev, 4096, ATI_IXP_DEFAULT_BUFSZ, 65536); 908152851Sariff 909152851Sariff sc->irqid = 0; 910152851Sariff sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid, 911152851Sariff RF_ACTIVE | RF_SHAREABLE); 912152851Sariff if (!sc->irq || 913152851Sariff snd_setup_intr(dev, sc->irq, INTR_MPSAFE, 914152851Sariff atiixp_intr, sc, &sc->ih)) { 915152851Sariff device_printf(dev, "unable to map interrupt\n"); 916152851Sariff goto bad; 917152851Sariff } 918152851Sariff 919152851Sariff /* 920152851Sariff * Let the user choose the best DMA segments. 921152851Sariff */ 922152851Sariff if (resource_int_value(device_get_name(dev), 923152851Sariff device_get_unit(dev), "dma_segs", 924152851Sariff &i) == 0) { 925152851Sariff if (i < ATI_IXP_DMA_CHSEGS_MIN) 926152851Sariff i = ATI_IXP_DMA_CHSEGS_MIN; 927152851Sariff if (i > ATI_IXP_DMA_CHSEGS_MAX) 928152851Sariff i = ATI_IXP_DMA_CHSEGS_MAX; 929155800Sariff sc->dma_segs = i; 930152851Sariff } 931152851Sariff 932152851Sariff /* 933155800Sariff * round the value to the nearest ^2 934155800Sariff */ 935155800Sariff i = 0; 936155800Sariff while (sc->dma_segs >> i) 937155800Sariff i++; 938155800Sariff sc->dma_segs = 1 << (i - 1); 939155800Sariff if (sc->dma_segs < ATI_IXP_DMA_CHSEGS_MIN) 940155800Sariff sc->dma_segs = ATI_IXP_DMA_CHSEGS_MIN; 941155800Sariff else if (sc->dma_segs > ATI_IXP_DMA_CHSEGS_MAX) 942155800Sariff sc->dma_segs = ATI_IXP_DMA_CHSEGS_MAX; 943155800Sariff 944155800Sariff /* 945152851Sariff * DMA tag for scatter-gather buffers and link pointers 946152851Sariff */ 947155800Sariff if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/sc->bufsz, /*boundary*/0, 948152851Sariff /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 949152851Sariff /*highaddr*/BUS_SPACE_MAXADDR, 950152851Sariff /*filter*/NULL, /*filterarg*/NULL, 951152851Sariff /*maxsize*/sc->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff, 952152851Sariff /*flags*/0, /*lockfunc*/NULL, 953152851Sariff /*lockarg*/NULL, &sc->parent_dmat) != 0) { 954152851Sariff device_printf(dev, "unable to create dma tag\n"); 955152851Sariff goto bad; 956152851Sariff } 957152851Sariff 958152851Sariff if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, 959152851Sariff /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 960152851Sariff /*highaddr*/BUS_SPACE_MAXADDR, 961152851Sariff /*filter*/NULL, /*filterarg*/NULL, 962152851Sariff /*maxsize*/sc->dma_segs * ATI_IXP_NCHANS * 963152851Sariff sizeof(struct atiixp_dma_op), 964152851Sariff /*nsegments*/1, /*maxsegz*/0x3ffff, 965152851Sariff /*flags*/0, /*lockfunc*/NULL, 966152851Sariff /*lockarg*/NULL, &sc->sgd_dmat) != 0) { 967152851Sariff device_printf(dev, "unable to create dma tag\n"); 968152851Sariff goto bad; 969152851Sariff } 970152851Sariff 971152851Sariff if (bus_dmamem_alloc(sc->sgd_dmat, (void **)&sc->sgd_table, 972152851Sariff BUS_DMA_NOWAIT, &sc->sgd_dmamap) == -1) 973152851Sariff goto bad; 974152851Sariff 975152851Sariff if (bus_dmamap_load(sc->sgd_dmat, sc->sgd_dmamap, sc->sgd_table, 976152851Sariff sc->dma_segs * ATI_IXP_NCHANS * 977152851Sariff sizeof(struct atiixp_dma_op), 978152851Sariff atiixp_dma_cb, sc, 0)) 979152851Sariff goto bad; 980152851Sariff 981152851Sariff 982152851Sariff atiixp_chip_pre_init(sc); 983152851Sariff 984152851Sariff sc->delayed_attach.ich_func = atiixp_chip_post_init; 985152851Sariff sc->delayed_attach.ich_arg = sc; 986152851Sariff if (cold == 0 || 987152851Sariff config_intrhook_establish(&sc->delayed_attach) != 0) { 988152851Sariff sc->delayed_attach.ich_func = NULL; 989152851Sariff atiixp_chip_post_init(sc); 990152851Sariff } 991152851Sariff 992152851Sariff return 0; 993152851Sariff 994152851Sariffbad: 995152851Sariff if (sc->codec) 996152851Sariff ac97_destroy(sc->codec); 997152851Sariff if (sc->ih) 998152851Sariff bus_teardown_intr(dev, sc->irq, sc->ih); 999152851Sariff if (sc->reg) 1000152851Sariff bus_release_resource(dev, sc->regtype, sc->regid, sc->reg); 1001152851Sariff if (sc->irq) 1002152851Sariff bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 1003152851Sariff if (sc->parent_dmat) 1004152851Sariff bus_dma_tag_destroy(sc->parent_dmat); 1005152851Sariff if (sc->sgd_dmamap) 1006152851Sariff bus_dmamap_unload(sc->sgd_dmat, sc->sgd_dmamap); 1007152851Sariff if (sc->sgd_dmat) 1008152851Sariff bus_dma_tag_destroy(sc->sgd_dmat); 1009152851Sariff if (sc->lock) 1010152851Sariff snd_mtxfree(sc->lock); 1011152851Sariff free(sc, M_DEVBUF); 1012152851Sariff 1013152851Sariff return ENXIO; 1014152851Sariff} 1015152851Sariff 1016152851Sariffstatic int 1017152851Sariffatiixp_pci_detach(device_t dev) 1018152851Sariff{ 1019152851Sariff int r; 1020152851Sariff struct atiixp_info *sc; 1021152851Sariff 1022152851Sariff r = pcm_unregister(dev); 1023152851Sariff if (r) 1024152851Sariff return r; 1025152851Sariff 1026152851Sariff sc = pcm_getdevinfo(dev); 1027152851Sariff 1028152851Sariff atiixp_disable_interrupts(sc); 1029152851Sariff 1030152851Sariff bus_teardown_intr(dev, sc->irq, sc->ih); 1031152851Sariff bus_release_resource(dev, sc->regtype, sc->regid, sc->reg); 1032152851Sariff bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 1033152851Sariff bus_dma_tag_destroy(sc->parent_dmat); 1034152851Sariff bus_dmamap_unload(sc->sgd_dmat, sc->sgd_dmamap); 1035152851Sariff bus_dma_tag_destroy(sc->sgd_dmat); 1036152851Sariff snd_mtxfree(sc->lock); 1037152851Sariff free(sc, M_DEVBUF); 1038152851Sariff 1039152851Sariff return 0; 1040152851Sariff} 1041152851Sariff 1042153708Sariffstatic int 1043153708Sariffatiixp_pci_suspend(device_t dev) 1044153708Sariff{ 1045153708Sariff struct atiixp_info *sc = pcm_getdevinfo(dev); 1046153708Sariff uint32_t value; 1047153708Sariff 1048153708Sariff /* quickly disable interrupts and save channels active state */ 1049153708Sariff atiixp_lock(sc); 1050153708Sariff atiixp_disable_interrupts(sc); 1051153708Sariff value = atiixp_rd(sc, ATI_REG_CMD); 1052153708Sariff sc->pch.active = (value & ATI_REG_CMD_SEND_EN) ? 1 : 0; 1053153708Sariff sc->rch.active = (value & ATI_REG_CMD_RECEIVE_EN) ? 1 : 0; 1054153708Sariff atiixp_unlock(sc); 1055153708Sariff 1056153708Sariff /* stop everything */ 1057153708Sariff if (sc->pch.channel && sc->pch.active) 1058153708Sariff atiixp_chan_trigger(NULL, &sc->pch, PCMTRIG_STOP); 1059153708Sariff if (sc->rch.channel && sc->rch.active) 1060153708Sariff atiixp_chan_trigger(NULL, &sc->rch, PCMTRIG_STOP); 1061153708Sariff 1062153708Sariff /* power down aclink and pci bus */ 1063153708Sariff atiixp_lock(sc); 1064153708Sariff value = atiixp_rd(sc, ATI_REG_CMD); 1065153708Sariff value |= ATI_REG_CMD_POWERDOWN | ATI_REG_CMD_AC_RESET; 1066153708Sariff atiixp_wr(sc, ATI_REG_CMD, ATI_REG_CMD_POWERDOWN); 1067153708Sariff pci_set_powerstate(dev, PCI_POWERSTATE_D3); 1068153708Sariff atiixp_unlock(sc); 1069153708Sariff 1070153708Sariff return 0; 1071153708Sariff} 1072153708Sariff 1073153708Sariffstatic int 1074153708Sariffatiixp_pci_resume(device_t dev) 1075153708Sariff{ 1076153708Sariff struct atiixp_info *sc = pcm_getdevinfo(dev); 1077153708Sariff 1078153708Sariff atiixp_lock(sc); 1079153708Sariff /* power up pci bus */ 1080153708Sariff pci_set_powerstate(dev, PCI_POWERSTATE_D0); 1081153708Sariff pci_enable_io(dev, SYS_RES_MEMORY); 1082153708Sariff pci_enable_busmaster(dev); 1083153708Sariff /* reset / power up aclink */ 1084153708Sariff atiixp_reset_aclink(sc); 1085153708Sariff atiixp_unlock(sc); 1086153708Sariff 1087153708Sariff if (mixer_reinit(dev) == -1) { 1088153708Sariff device_printf(dev, "unable to reinitialize the mixer\n"); 1089153708Sariff return ENXIO; 1090153708Sariff } 1091153708Sariff 1092153708Sariff /* 1093153708Sariff * Resume channel activities. Reset channel format regardless 1094153708Sariff * of its previous state. 1095153708Sariff */ 1096153708Sariff if (sc->pch.channel) { 1097153708Sariff if (sc->pch.fmt) 1098153708Sariff atiixp_chan_setformat(NULL, &sc->pch, sc->pch.fmt); 1099153708Sariff if (sc->pch.active) 1100153708Sariff atiixp_chan_trigger(NULL, &sc->pch, PCMTRIG_START); 1101153708Sariff } 1102153708Sariff if (sc->rch.channel) { 1103153708Sariff if (sc->rch.fmt) 1104153708Sariff atiixp_chan_setformat(NULL, &sc->rch, sc->rch.fmt); 1105153708Sariff if (sc->rch.active) 1106153708Sariff atiixp_chan_trigger(NULL, &sc->rch, PCMTRIG_START); 1107153708Sariff } 1108153708Sariff 1109153708Sariff /* enable interrupts */ 1110153708Sariff atiixp_lock(sc); 1111153708Sariff atiixp_enable_interrupts(sc); 1112153708Sariff atiixp_unlock(sc); 1113153708Sariff 1114153708Sariff return 0; 1115153708Sariff} 1116153708Sariff 1117152851Sariffstatic device_method_t atiixp_methods[] = { 1118152851Sariff DEVMETHOD(device_probe, atiixp_pci_probe), 1119152851Sariff DEVMETHOD(device_attach, atiixp_pci_attach), 1120152851Sariff DEVMETHOD(device_detach, atiixp_pci_detach), 1121153708Sariff DEVMETHOD(device_suspend, atiixp_pci_suspend), 1122153708Sariff DEVMETHOD(device_resume, atiixp_pci_resume), 1123152851Sariff { 0, 0 } 1124152851Sariff}; 1125152851Sariff 1126152851Sariffstatic driver_t atiixp_driver = { 1127152851Sariff "pcm", 1128152851Sariff atiixp_methods, 1129152851Sariff PCM_SOFTC_SIZE, 1130152851Sariff}; 1131152851Sariff 1132152851SariffDRIVER_MODULE(snd_atiixp, pci, atiixp_driver, pcm_devclass, 0, 0); 1133152851SariffMODULE_DEPEND(snd_atiixp, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 1134152851SariffMODULE_VERSION(snd_atiixp, 1); 1135