1d5688b6aSAriff Abdullah /*- 2d5688b6aSAriff Abdullah * Copyright (c) 2005 Ariff Abdullah <ariff@FreeBSD.org> 3d5688b6aSAriff Abdullah * All rights reserved. 4d5688b6aSAriff Abdullah * 5d5688b6aSAriff Abdullah * Redistribution and use in source and binary forms, with or without 6d5688b6aSAriff Abdullah * modification, are permitted provided that the following conditions 7d5688b6aSAriff Abdullah * are met: 8d5688b6aSAriff Abdullah * 1. Redistributions of source code must retain the above copyright 9d5688b6aSAriff Abdullah * notice, this list of conditions and the following disclaimer. 10d5688b6aSAriff Abdullah * 2. Redistributions in binary form must reproduce the above copyright 11d5688b6aSAriff Abdullah * notice, this list of conditions and the following disclaimer in the 12d5688b6aSAriff Abdullah * documentation and/or other materials provided with the distribution. 13d5688b6aSAriff Abdullah * 14d5688b6aSAriff Abdullah * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15d5688b6aSAriff Abdullah * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16d5688b6aSAriff Abdullah * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17d5688b6aSAriff Abdullah * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18d5688b6aSAriff Abdullah * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19d5688b6aSAriff Abdullah * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20d5688b6aSAriff Abdullah * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21d5688b6aSAriff Abdullah * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT 22d5688b6aSAriff Abdullah * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23d5688b6aSAriff Abdullah * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF 24d5688b6aSAriff Abdullah * SUCH DAMAGE. 25d5688b6aSAriff Abdullah */ 26d5688b6aSAriff Abdullah 27d5688b6aSAriff Abdullah /* 28d5688b6aSAriff Abdullah * FreeBSD pcm driver for ATI IXP 150/200/250/300 AC97 controllers 29d5688b6aSAriff Abdullah * 30d5688b6aSAriff Abdullah * Features 31d5688b6aSAriff Abdullah * * 16bit playback / recording 32d5688b6aSAriff Abdullah * * 32bit native playback - yay! 3305051995SAriff Abdullah * * 32bit native recording (seems broken on few hardwares) 34d5688b6aSAriff Abdullah * 35d5688b6aSAriff Abdullah * Issues / TODO: 36d5688b6aSAriff Abdullah * * SPDIF 37d5688b6aSAriff Abdullah * * Support for more than 2 channels. 38d5688b6aSAriff Abdullah * * VRA ? VRM ? DRA ? 3905051995SAriff Abdullah * * 32bit native recording seems broken on few hardwares, most 4005051995SAriff Abdullah * probably because of incomplete VRA/DRA cleanup. 41d5688b6aSAriff Abdullah * 42d5688b6aSAriff Abdullah * 43d5688b6aSAriff Abdullah * Thanks goes to: 44d5688b6aSAriff Abdullah * 45d5688b6aSAriff Abdullah * Shaharil @ SCAN Associates whom relentlessly providing me the 46d5688b6aSAriff Abdullah * mind blowing Acer Ferrari 4002 WLMi with this ATI IXP hardware. 47d5688b6aSAriff Abdullah * 48d5688b6aSAriff Abdullah * Reinoud Zandijk <reinoud@NetBSD.org> (auixp), which this driver is 49d5688b6aSAriff Abdullah * largely based upon although large part of it has been reworked. His 50d5688b6aSAriff Abdullah * driver is the primary reference and pretty much well documented. 51d5688b6aSAriff Abdullah * 52d5688b6aSAriff Abdullah * Takashi Iwai (ALSA snd-atiixp), for register definitions and some 53d5688b6aSAriff Abdullah * random ninja hackery. 54d5688b6aSAriff Abdullah */ 55d5688b6aSAriff Abdullah 5690da2b28SAriff Abdullah #ifdef HAVE_KERNEL_OPTION_HEADERS 5790da2b28SAriff Abdullah #include "opt_snd.h" 5890da2b28SAriff Abdullah #endif 5990da2b28SAriff Abdullah 60d5688b6aSAriff Abdullah #include <dev/sound/pcm/sound.h> 61d5688b6aSAriff Abdullah #include <dev/sound/pcm/ac97.h> 62d5688b6aSAriff Abdullah 63d5688b6aSAriff Abdullah #include <dev/pci/pcireg.h> 64d5688b6aSAriff Abdullah #include <dev/pci/pcivar.h> 65d5688b6aSAriff Abdullah #include <sys/sysctl.h> 66d5688b6aSAriff Abdullah #include <sys/endian.h> 67d5688b6aSAriff Abdullah 68d5688b6aSAriff Abdullah #include <dev/sound/pci/atiixp.h> 69d5688b6aSAriff Abdullah 70d5688b6aSAriff Abdullah SND_DECLARE_FILE("$FreeBSD$"); 71d5688b6aSAriff Abdullah 729f52a325SAriff Abdullah #define ATI_IXP_DMA_RETRY_MAX 100 739f52a325SAriff Abdullah 749f52a325SAriff Abdullah #define ATI_IXP_BUFSZ_MIN 4096 759f52a325SAriff Abdullah #define ATI_IXP_BUFSZ_MAX 65536 769f52a325SAriff Abdullah #define ATI_IXP_BUFSZ_DEFAULT 16384 779f52a325SAriff Abdullah 781042342aSAriff Abdullah #define ATI_IXP_BLK_MIN 32 791042342aSAriff Abdullah #define ATI_IXP_BLK_ALIGN (~(ATI_IXP_BLK_MIN - 1)) 801042342aSAriff Abdullah 818a7c4d36SAriff Abdullah #define ATI_IXP_CHN_RUNNING 0x00000001 828a7c4d36SAriff Abdullah #define ATI_IXP_CHN_SUSPEND 0x00000002 838a7c4d36SAriff Abdullah 84d5688b6aSAriff Abdullah struct atiixp_dma_op { 8505051995SAriff Abdullah volatile uint32_t addr; 8605051995SAriff Abdullah volatile uint16_t status; 8705051995SAriff Abdullah volatile uint16_t size; 8805051995SAriff Abdullah volatile uint32_t next; 89d5688b6aSAriff Abdullah }; 90d5688b6aSAriff Abdullah 91d5688b6aSAriff Abdullah struct atiixp_info; 92d5688b6aSAriff Abdullah 93d5688b6aSAriff Abdullah struct atiixp_chinfo { 94d5688b6aSAriff Abdullah struct snd_dbuf *buffer; 95d5688b6aSAriff Abdullah struct pcm_channel *channel; 96d5688b6aSAriff Abdullah struct atiixp_info *parent; 97d5688b6aSAriff Abdullah struct atiixp_dma_op *sgd_table; 98d5688b6aSAriff Abdullah bus_addr_t sgd_addr; 99a580b31aSAriff Abdullah uint32_t enable_bit, flush_bit, linkptr_bit, dt_cur_bit; 100a580b31aSAriff Abdullah uint32_t blksz, blkcnt; 101a580b31aSAriff Abdullah uint32_t ptr, prevptr; 10288a50509SAriff Abdullah uint32_t fmt; 1038a7c4d36SAriff Abdullah uint32_t flags; 1048a7c4d36SAriff Abdullah int caps_32bit, dir; 105d5688b6aSAriff Abdullah }; 106d5688b6aSAriff Abdullah 107d5688b6aSAriff Abdullah struct atiixp_info { 108d5688b6aSAriff Abdullah device_t dev; 109d5688b6aSAriff Abdullah 110d5688b6aSAriff Abdullah bus_space_tag_t st; 111d5688b6aSAriff Abdullah bus_space_handle_t sh; 112d5688b6aSAriff Abdullah bus_dma_tag_t parent_dmat; 113d5688b6aSAriff Abdullah bus_dma_tag_t sgd_dmat; 114d5688b6aSAriff Abdullah bus_dmamap_t sgd_dmamap; 115d5688b6aSAriff Abdullah bus_addr_t sgd_addr; 116d5688b6aSAriff Abdullah 117d5688b6aSAriff Abdullah struct resource *reg, *irq; 118d5688b6aSAriff Abdullah int regtype, regid, irqid; 119d5688b6aSAriff Abdullah void *ih; 120d5688b6aSAriff Abdullah struct ac97_info *codec; 121d5688b6aSAriff Abdullah 122d5688b6aSAriff Abdullah struct atiixp_chinfo pch; 123d5688b6aSAriff Abdullah struct atiixp_chinfo rch; 124d5688b6aSAriff Abdullah struct atiixp_dma_op *sgd_table; 125d5688b6aSAriff Abdullah struct intr_config_hook delayed_attach; 126d5688b6aSAriff Abdullah 127d5688b6aSAriff Abdullah uint32_t bufsz; 128d5688b6aSAriff Abdullah uint32_t codec_not_ready_bits, codec_idx, codec_found; 129a580b31aSAriff Abdullah uint32_t blkcnt; 130d5688b6aSAriff Abdullah int registered_channels; 131d5688b6aSAriff Abdullah 132d5688b6aSAriff Abdullah struct mtx *lock; 133a580b31aSAriff Abdullah struct callout poll_timer; 134a580b31aSAriff Abdullah int poll_ticks, polling; 135d5688b6aSAriff Abdullah }; 136d5688b6aSAriff Abdullah 137d5688b6aSAriff Abdullah #define atiixp_rd(_sc, _reg) \ 138d5688b6aSAriff Abdullah bus_space_read_4((_sc)->st, (_sc)->sh, _reg) 139d5688b6aSAriff Abdullah #define atiixp_wr(_sc, _reg, _val) \ 140d5688b6aSAriff Abdullah bus_space_write_4((_sc)->st, (_sc)->sh, _reg, _val) 141d5688b6aSAriff Abdullah 142d5688b6aSAriff Abdullah #define atiixp_lock(_sc) snd_mtxlock((_sc)->lock) 143d5688b6aSAriff Abdullah #define atiixp_unlock(_sc) snd_mtxunlock((_sc)->lock) 144d5688b6aSAriff Abdullah #define atiixp_assert(_sc) snd_mtxassert((_sc)->lock) 145d5688b6aSAriff Abdullah 146d5688b6aSAriff Abdullah static uint32_t atiixp_fmt_32bit[] = { 14790da2b28SAriff Abdullah SND_FORMAT(AFMT_S16_LE, 2, 0), 14890da2b28SAriff Abdullah SND_FORMAT(AFMT_S32_LE, 2, 0), 149d5688b6aSAriff Abdullah 0 150d5688b6aSAriff Abdullah }; 151d5688b6aSAriff Abdullah 152d5688b6aSAriff Abdullah static uint32_t atiixp_fmt[] = { 15390da2b28SAriff Abdullah SND_FORMAT(AFMT_S16_LE, 2, 0), 154d5688b6aSAriff Abdullah 0 155d5688b6aSAriff Abdullah }; 156d5688b6aSAriff Abdullah 157d5688b6aSAriff Abdullah static struct pcmchan_caps atiixp_caps_32bit = { 158d5688b6aSAriff Abdullah ATI_IXP_BASE_RATE, 159d5688b6aSAriff Abdullah ATI_IXP_BASE_RATE, 160d5688b6aSAriff Abdullah atiixp_fmt_32bit, 0 161d5688b6aSAriff Abdullah }; 162d5688b6aSAriff Abdullah 163d5688b6aSAriff Abdullah static struct pcmchan_caps atiixp_caps = { 164d5688b6aSAriff Abdullah ATI_IXP_BASE_RATE, 165d5688b6aSAriff Abdullah ATI_IXP_BASE_RATE, 166d5688b6aSAriff Abdullah atiixp_fmt, 0 167d5688b6aSAriff Abdullah }; 168d5688b6aSAriff Abdullah 169d5688b6aSAriff Abdullah static const struct { 170d5688b6aSAriff Abdullah uint16_t vendor; 171d5688b6aSAriff Abdullah uint16_t devid; 172d5688b6aSAriff Abdullah char *desc; 173d5688b6aSAriff Abdullah } atiixp_hw[] = { 174d5688b6aSAriff Abdullah { ATI_VENDOR_ID, ATI_IXP_200_ID, "ATI IXP 200" }, 175d5688b6aSAriff Abdullah { ATI_VENDOR_ID, ATI_IXP_300_ID, "ATI IXP 300" }, 176d5688b6aSAriff Abdullah { ATI_VENDOR_ID, ATI_IXP_400_ID, "ATI IXP 400" }, 177ee2b7497SAriff Abdullah { ATI_VENDOR_ID, ATI_IXP_SB600_ID, "ATI IXP SB600" }, 178d5688b6aSAriff Abdullah }; 179d5688b6aSAriff Abdullah 180d5688b6aSAriff Abdullah static void atiixp_enable_interrupts(struct atiixp_info *); 181d5688b6aSAriff Abdullah static void atiixp_disable_interrupts(struct atiixp_info *); 182d5688b6aSAriff Abdullah static void atiixp_reset_aclink(struct atiixp_info *); 1839f52a325SAriff Abdullah static void atiixp_flush_dma(struct atiixp_chinfo *); 1849f52a325SAriff Abdullah static void atiixp_enable_dma(struct atiixp_chinfo *); 1859f52a325SAriff Abdullah static void atiixp_disable_dma(struct atiixp_chinfo *); 186d5688b6aSAriff Abdullah 187d5688b6aSAriff Abdullah static int atiixp_waitready_codec(struct atiixp_info *); 188d5688b6aSAriff Abdullah static int atiixp_rdcd(kobj_t, void *, int); 189d5688b6aSAriff Abdullah static int atiixp_wrcd(kobj_t, void *, int, uint32_t); 190d5688b6aSAriff Abdullah 191d5688b6aSAriff Abdullah static void *atiixp_chan_init(kobj_t, void *, struct snd_dbuf *, 192d5688b6aSAriff Abdullah struct pcm_channel *, int); 193d5688b6aSAriff Abdullah static int atiixp_chan_setformat(kobj_t, void *, uint32_t); 19490da2b28SAriff Abdullah static uint32_t atiixp_chan_setspeed(kobj_t, void *, uint32_t); 1951042342aSAriff Abdullah static int atiixp_chan_setfragments(kobj_t, void *, uint32_t, uint32_t); 19690da2b28SAriff Abdullah static uint32_t atiixp_chan_setblocksize(kobj_t, void *, uint32_t); 197d5688b6aSAriff Abdullah static void atiixp_buildsgdt(struct atiixp_chinfo *); 198d5688b6aSAriff Abdullah static int atiixp_chan_trigger(kobj_t, void *, int); 1999f52a325SAriff Abdullah static __inline uint32_t atiixp_dmapos(struct atiixp_chinfo *); 20090da2b28SAriff Abdullah static uint32_t atiixp_chan_getptr(kobj_t, void *); 201d5688b6aSAriff Abdullah static struct pcmchan_caps *atiixp_chan_getcaps(kobj_t, void *); 202d5688b6aSAriff Abdullah 203d5688b6aSAriff Abdullah static void atiixp_intr(void *); 204d5688b6aSAriff Abdullah static void atiixp_dma_cb(void *, bus_dma_segment_t *, int, int); 205d5688b6aSAriff Abdullah static void atiixp_chip_pre_init(struct atiixp_info *); 206d5688b6aSAriff Abdullah static void atiixp_chip_post_init(void *); 207f2a1d71aSAriff Abdullah static void atiixp_release_resource(struct atiixp_info *); 208d5688b6aSAriff Abdullah static int atiixp_pci_probe(device_t); 209d5688b6aSAriff Abdullah static int atiixp_pci_attach(device_t); 210d5688b6aSAriff Abdullah static int atiixp_pci_detach(device_t); 21188a50509SAriff Abdullah static int atiixp_pci_suspend(device_t); 21288a50509SAriff Abdullah static int atiixp_pci_resume(device_t); 213d5688b6aSAriff Abdullah 214d5688b6aSAriff Abdullah /* 215d5688b6aSAriff Abdullah * ATI IXP helper functions 216d5688b6aSAriff Abdullah */ 217d5688b6aSAriff Abdullah static void 218d5688b6aSAriff Abdullah atiixp_enable_interrupts(struct atiixp_info *sc) 219d5688b6aSAriff Abdullah { 220d5688b6aSAriff Abdullah uint32_t value; 221d5688b6aSAriff Abdullah 222d5688b6aSAriff Abdullah /* clear all pending */ 223d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_ISR, 0xffffffff); 224d5688b6aSAriff Abdullah 225d5688b6aSAriff Abdullah /* enable all relevant interrupt sources we can handle */ 226d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_IER); 227d5688b6aSAriff Abdullah 228d5688b6aSAriff Abdullah value |= ATI_REG_IER_IO_STATUS_EN; 229d5688b6aSAriff Abdullah 230d5688b6aSAriff Abdullah /* 231d5688b6aSAriff Abdullah * Disable / ignore internal xrun/spdf interrupt flags 232d5688b6aSAriff Abdullah * since it doesn't interest us (for now). 233d5688b6aSAriff Abdullah */ 2349f52a325SAriff Abdullah #if 1 2359f52a325SAriff Abdullah value &= ~(ATI_REG_IER_IN_XRUN_EN | ATI_REG_IER_OUT_XRUN_EN | 2369f52a325SAriff Abdullah ATI_REG_IER_SPDF_XRUN_EN | ATI_REG_IER_SPDF_STATUS_EN); 2379f52a325SAriff Abdullah #else 238d5688b6aSAriff Abdullah value |= ATI_REG_IER_IN_XRUN_EN; 239d5688b6aSAriff Abdullah value |= ATI_REG_IER_OUT_XRUN_EN; 240d5688b6aSAriff Abdullah 241d5688b6aSAriff Abdullah value |= ATI_REG_IER_SPDF_XRUN_EN; 242d5688b6aSAriff Abdullah value |= ATI_REG_IER_SPDF_STATUS_EN; 243d5688b6aSAriff Abdullah #endif 244d5688b6aSAriff Abdullah 245d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_IER, value); 246d5688b6aSAriff Abdullah } 247d5688b6aSAriff Abdullah 248d5688b6aSAriff Abdullah static void 249d5688b6aSAriff Abdullah atiixp_disable_interrupts(struct atiixp_info *sc) 250d5688b6aSAriff Abdullah { 251d5688b6aSAriff Abdullah /* disable all interrupt sources */ 252d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_IER, 0); 253d5688b6aSAriff Abdullah 254d5688b6aSAriff Abdullah /* clear all pending */ 255d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_ISR, 0xffffffff); 256d5688b6aSAriff Abdullah } 257d5688b6aSAriff Abdullah 258d5688b6aSAriff Abdullah static void 259d5688b6aSAriff Abdullah atiixp_reset_aclink(struct atiixp_info *sc) 260d5688b6aSAriff Abdullah { 261d5688b6aSAriff Abdullah uint32_t value, timeout; 262d5688b6aSAriff Abdullah 263d5688b6aSAriff Abdullah /* if power is down, power it up */ 264d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_CMD); 265d5688b6aSAriff Abdullah if (value & ATI_REG_CMD_POWERDOWN) { 266d5688b6aSAriff Abdullah /* explicitly enable power */ 267d5688b6aSAriff Abdullah value &= ~ATI_REG_CMD_POWERDOWN; 268d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_CMD, value); 269d5688b6aSAriff Abdullah 270d5688b6aSAriff Abdullah /* have to wait at least 10 usec for it to initialise */ 271d5688b6aSAriff Abdullah DELAY(20); 2729f52a325SAriff Abdullah } 273d5688b6aSAriff Abdullah 274d5688b6aSAriff Abdullah /* perform a soft reset */ 275d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_CMD); 276d5688b6aSAriff Abdullah value |= ATI_REG_CMD_AC_SOFT_RESET; 277d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_CMD, value); 278d5688b6aSAriff Abdullah 279d5688b6aSAriff Abdullah /* need to read the CMD reg and wait aprox. 10 usec to init */ 280d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_CMD); 281d5688b6aSAriff Abdullah DELAY(20); 282d5688b6aSAriff Abdullah 283d5688b6aSAriff Abdullah /* clear soft reset flag again */ 284d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_CMD); 285d5688b6aSAriff Abdullah value &= ~ATI_REG_CMD_AC_SOFT_RESET; 286d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_CMD, value); 287d5688b6aSAriff Abdullah 288d5688b6aSAriff Abdullah /* check if the ac-link is working; reset device otherwise */ 289d5688b6aSAriff Abdullah timeout = 10; 290d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_CMD); 291a580b31aSAriff Abdullah while (!(value & ATI_REG_CMD_ACLINK_ACTIVE) && --timeout) { 29288a50509SAriff Abdullah #if 0 293d5688b6aSAriff Abdullah device_printf(sc->dev, "not up; resetting aclink hardware\n"); 29488a50509SAriff Abdullah #endif 295d5688b6aSAriff Abdullah 296d5688b6aSAriff Abdullah /* dip aclink reset but keep the acsync */ 297d5688b6aSAriff Abdullah value &= ~ATI_REG_CMD_AC_RESET; 298d5688b6aSAriff Abdullah value |= ATI_REG_CMD_AC_SYNC; 299d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_CMD, value); 300d5688b6aSAriff Abdullah 301d5688b6aSAriff Abdullah /* need to read CMD again and wait again (clocking in issue?) */ 302d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_CMD); 303d5688b6aSAriff Abdullah DELAY(20); 304d5688b6aSAriff Abdullah 305d5688b6aSAriff Abdullah /* assert aclink reset again */ 306d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_CMD); 307d5688b6aSAriff Abdullah value |= ATI_REG_CMD_AC_RESET; 308d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_CMD, value); 309d5688b6aSAriff Abdullah 310d5688b6aSAriff Abdullah /* check if its active now */ 311d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_CMD); 3129f52a325SAriff Abdullah } 313d5688b6aSAriff Abdullah 314d5688b6aSAriff Abdullah if (timeout == 0) 315d5688b6aSAriff Abdullah device_printf(sc->dev, "giving up aclink reset\n"); 31688a50509SAriff Abdullah #if 0 317d5688b6aSAriff Abdullah if (timeout != 10) 318d5688b6aSAriff Abdullah device_printf(sc->dev, "aclink hardware reset successful\n"); 31988a50509SAriff Abdullah #endif 320d5688b6aSAriff Abdullah 321d5688b6aSAriff Abdullah /* assert reset and sync for safety */ 322d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_CMD); 323d5688b6aSAriff Abdullah value |= ATI_REG_CMD_AC_SYNC | ATI_REG_CMD_AC_RESET; 324d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_CMD, value); 325d5688b6aSAriff Abdullah } 326d5688b6aSAriff Abdullah 327d5688b6aSAriff Abdullah static void 3289f52a325SAriff Abdullah atiixp_flush_dma(struct atiixp_chinfo *ch) 329d5688b6aSAriff Abdullah { 3309f52a325SAriff Abdullah atiixp_wr(ch->parent, ATI_REG_FIFO_FLUSH, ch->flush_bit); 331d5688b6aSAriff Abdullah } 332d5688b6aSAriff Abdullah 333d5688b6aSAriff Abdullah static void 3349f52a325SAriff Abdullah atiixp_enable_dma(struct atiixp_chinfo *ch) 335d5688b6aSAriff Abdullah { 336d5688b6aSAriff Abdullah uint32_t value; 337d5688b6aSAriff Abdullah 3389f52a325SAriff Abdullah value = atiixp_rd(ch->parent, ATI_REG_CMD); 339d5688b6aSAriff Abdullah if (!(value & ch->enable_bit)) { 340d5688b6aSAriff Abdullah value |= ch->enable_bit; 3419f52a325SAriff Abdullah atiixp_wr(ch->parent, ATI_REG_CMD, value); 342d5688b6aSAriff Abdullah } 343d5688b6aSAriff Abdullah } 344d5688b6aSAriff Abdullah 345d5688b6aSAriff Abdullah static void 3469f52a325SAriff Abdullah atiixp_disable_dma(struct atiixp_chinfo *ch) 347d5688b6aSAriff Abdullah { 348d5688b6aSAriff Abdullah uint32_t value; 349d5688b6aSAriff Abdullah 3509f52a325SAriff Abdullah value = atiixp_rd(ch->parent, ATI_REG_CMD); 351d5688b6aSAriff Abdullah if (value & ch->enable_bit) { 352d5688b6aSAriff Abdullah value &= ~ch->enable_bit; 3539f52a325SAriff Abdullah atiixp_wr(ch->parent, ATI_REG_CMD, value); 354d5688b6aSAriff Abdullah } 355d5688b6aSAriff Abdullah } 356d5688b6aSAriff Abdullah 357d5688b6aSAriff Abdullah /* 358d5688b6aSAriff Abdullah * AC97 interface 359d5688b6aSAriff Abdullah */ 360d5688b6aSAriff Abdullah static int 361d5688b6aSAriff Abdullah atiixp_waitready_codec(struct atiixp_info *sc) 362d5688b6aSAriff Abdullah { 363d5688b6aSAriff Abdullah int timeout = 500; 364d5688b6aSAriff Abdullah 365d5688b6aSAriff Abdullah do { 366d5688b6aSAriff Abdullah if ((atiixp_rd(sc, ATI_REG_PHYS_OUT_ADDR) & 367d5688b6aSAriff Abdullah ATI_REG_PHYS_OUT_ADDR_EN) == 0) 3689f52a325SAriff Abdullah return (0); 369d5688b6aSAriff Abdullah DELAY(1); 3709f52a325SAriff Abdullah } while (--timeout); 371d5688b6aSAriff Abdullah 3729f52a325SAriff Abdullah return (-1); 373d5688b6aSAriff Abdullah } 374d5688b6aSAriff Abdullah 375d5688b6aSAriff Abdullah static int 376d5688b6aSAriff Abdullah atiixp_rdcd(kobj_t obj, void *devinfo, int reg) 377d5688b6aSAriff Abdullah { 378d5688b6aSAriff Abdullah struct atiixp_info *sc = devinfo; 379d5688b6aSAriff Abdullah uint32_t data; 380d5688b6aSAriff Abdullah int timeout; 381d5688b6aSAriff Abdullah 382d5688b6aSAriff Abdullah if (atiixp_waitready_codec(sc)) 3839f52a325SAriff Abdullah return (-1); 384d5688b6aSAriff Abdullah 385d5688b6aSAriff Abdullah data = (reg << ATI_REG_PHYS_OUT_ADDR_SHIFT) | 386a580b31aSAriff Abdullah ATI_REG_PHYS_OUT_ADDR_EN | ATI_REG_PHYS_OUT_RW | sc->codec_idx; 387d5688b6aSAriff Abdullah 388d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_PHYS_OUT_ADDR, data); 389d5688b6aSAriff Abdullah 390d5688b6aSAriff Abdullah if (atiixp_waitready_codec(sc)) 3919f52a325SAriff Abdullah return (-1); 392d5688b6aSAriff Abdullah 393d5688b6aSAriff Abdullah timeout = 500; 394d5688b6aSAriff Abdullah do { 395d5688b6aSAriff Abdullah data = atiixp_rd(sc, ATI_REG_PHYS_IN_ADDR); 396d5688b6aSAriff Abdullah if (data & ATI_REG_PHYS_IN_READ_FLAG) 3979f52a325SAriff Abdullah return (data >> ATI_REG_PHYS_IN_DATA_SHIFT); 398d5688b6aSAriff Abdullah DELAY(1); 3999f52a325SAriff Abdullah } while (--timeout); 400d5688b6aSAriff Abdullah 401d5688b6aSAriff Abdullah if (reg < 0x7c) 402d5688b6aSAriff Abdullah device_printf(sc->dev, "codec read timeout! (reg 0x%x)\n", reg); 403d5688b6aSAriff Abdullah 4049f52a325SAriff Abdullah return (-1); 405d5688b6aSAriff Abdullah } 406d5688b6aSAriff Abdullah 407d5688b6aSAriff Abdullah static int 408d5688b6aSAriff Abdullah atiixp_wrcd(kobj_t obj, void *devinfo, int reg, uint32_t data) 409d5688b6aSAriff Abdullah { 410d5688b6aSAriff Abdullah struct atiixp_info *sc = devinfo; 411d5688b6aSAriff Abdullah 412d5688b6aSAriff Abdullah if (atiixp_waitready_codec(sc)) 4139f52a325SAriff Abdullah return (-1); 414d5688b6aSAriff Abdullah 415d5688b6aSAriff Abdullah data = (data << ATI_REG_PHYS_OUT_DATA_SHIFT) | 416d5688b6aSAriff Abdullah (((uint32_t)reg) << ATI_REG_PHYS_OUT_ADDR_SHIFT) | 417d5688b6aSAriff Abdullah ATI_REG_PHYS_OUT_ADDR_EN | sc->codec_idx; 418d5688b6aSAriff Abdullah 419d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_PHYS_OUT_ADDR, data); 420d5688b6aSAriff Abdullah 4219f52a325SAriff Abdullah return (0); 422d5688b6aSAriff Abdullah } 423d5688b6aSAriff Abdullah 424d5688b6aSAriff Abdullah static kobj_method_t atiixp_ac97_methods[] = { 425d5688b6aSAriff Abdullah KOBJMETHOD(ac97_read, atiixp_rdcd), 426d5688b6aSAriff Abdullah KOBJMETHOD(ac97_write, atiixp_wrcd), 42790da2b28SAriff Abdullah KOBJMETHOD_END 428d5688b6aSAriff Abdullah }; 429d5688b6aSAriff Abdullah AC97_DECLARE(atiixp_ac97); 430d5688b6aSAriff Abdullah 431d5688b6aSAriff Abdullah /* 432d5688b6aSAriff Abdullah * Playback / Record channel interface 433d5688b6aSAriff Abdullah */ 434d5688b6aSAriff Abdullah static void * 435d5688b6aSAriff Abdullah atiixp_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, 436d5688b6aSAriff Abdullah struct pcm_channel *c, int dir) 437d5688b6aSAriff Abdullah { 438d5688b6aSAriff Abdullah struct atiixp_info *sc = devinfo; 439d5688b6aSAriff Abdullah struct atiixp_chinfo *ch; 440d5688b6aSAriff Abdullah int num; 441d5688b6aSAriff Abdullah 442d5688b6aSAriff Abdullah atiixp_lock(sc); 443d5688b6aSAriff Abdullah 444d5688b6aSAriff Abdullah if (dir == PCMDIR_PLAY) { 445d5688b6aSAriff Abdullah ch = &sc->pch; 446d5688b6aSAriff Abdullah ch->linkptr_bit = ATI_REG_OUT_DMA_LINKPTR; 447d5688b6aSAriff Abdullah ch->enable_bit = ATI_REG_CMD_OUT_DMA_EN | ATI_REG_CMD_SEND_EN; 448d5688b6aSAriff Abdullah ch->flush_bit = ATI_REG_FIFO_OUT_FLUSH; 449a580b31aSAriff Abdullah ch->dt_cur_bit = ATI_REG_OUT_DMA_DT_CUR; 450d5688b6aSAriff Abdullah /* Native 32bit playback working properly */ 451d5688b6aSAriff Abdullah ch->caps_32bit = 1; 452d5688b6aSAriff Abdullah } else { 453d5688b6aSAriff Abdullah ch = &sc->rch; 454d5688b6aSAriff Abdullah ch->linkptr_bit = ATI_REG_IN_DMA_LINKPTR; 455d5688b6aSAriff Abdullah ch->enable_bit = ATI_REG_CMD_IN_DMA_EN | ATI_REG_CMD_RECEIVE_EN; 456d5688b6aSAriff Abdullah ch->flush_bit = ATI_REG_FIFO_IN_FLUSH; 457a580b31aSAriff Abdullah ch->dt_cur_bit = ATI_REG_IN_DMA_DT_CUR; 458d5688b6aSAriff Abdullah /* XXX Native 32bit recording appear to be broken */ 4598815a869SAriff Abdullah ch->caps_32bit = 1; 460d5688b6aSAriff Abdullah } 461d5688b6aSAriff Abdullah 462d5688b6aSAriff Abdullah ch->buffer = b; 463d5688b6aSAriff Abdullah ch->parent = sc; 464d5688b6aSAriff Abdullah ch->channel = c; 465d5688b6aSAriff Abdullah ch->dir = dir; 466a580b31aSAriff Abdullah ch->blkcnt = sc->blkcnt; 467a580b31aSAriff Abdullah ch->blksz = sc->bufsz / ch->blkcnt; 468d5688b6aSAriff Abdullah 469d5688b6aSAriff Abdullah atiixp_unlock(sc); 470d5688b6aSAriff Abdullah 4712e334adfSAriff Abdullah if (sndbuf_alloc(ch->buffer, sc->parent_dmat, 0, sc->bufsz) == -1) 4729f52a325SAriff Abdullah return (NULL); 473d5688b6aSAriff Abdullah 474d5688b6aSAriff Abdullah atiixp_lock(sc); 475d5688b6aSAriff Abdullah num = sc->registered_channels++; 4761042342aSAriff Abdullah ch->sgd_table = &sc->sgd_table[num * ATI_IXP_DMA_CHSEGS_MAX]; 4771042342aSAriff Abdullah ch->sgd_addr = sc->sgd_addr + (num * ATI_IXP_DMA_CHSEGS_MAX * 478a580b31aSAriff Abdullah sizeof(struct atiixp_dma_op)); 4799f52a325SAriff Abdullah atiixp_disable_dma(ch); 480d5688b6aSAriff Abdullah atiixp_unlock(sc); 481d5688b6aSAriff Abdullah 4829f52a325SAriff Abdullah return (ch); 483d5688b6aSAriff Abdullah } 484d5688b6aSAriff Abdullah 485d5688b6aSAriff Abdullah static int 486d5688b6aSAriff Abdullah atiixp_chan_setformat(kobj_t obj, void *data, uint32_t format) 487d5688b6aSAriff Abdullah { 488d5688b6aSAriff Abdullah struct atiixp_chinfo *ch = data; 489d5688b6aSAriff Abdullah struct atiixp_info *sc = ch->parent; 490d5688b6aSAriff Abdullah uint32_t value; 491d5688b6aSAriff Abdullah 492d5688b6aSAriff Abdullah atiixp_lock(sc); 493d5688b6aSAriff Abdullah if (ch->dir == PCMDIR_REC) { 494d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_CMD); 495d5688b6aSAriff Abdullah value &= ~ATI_REG_CMD_INTERLEAVE_IN; 49605051995SAriff Abdullah if ((format & AFMT_32BIT) == 0) 497d5688b6aSAriff Abdullah value |= ATI_REG_CMD_INTERLEAVE_IN; 498d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_CMD, value); 499d5688b6aSAriff Abdullah } else { 500d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_OUT_DMA_SLOT); 501d5688b6aSAriff Abdullah value &= ~ATI_REG_OUT_DMA_SLOT_MASK; 502d5688b6aSAriff Abdullah /* We do not have support for more than 2 channels, _yet_. */ 503d5688b6aSAriff Abdullah value |= ATI_REG_OUT_DMA_SLOT_BIT(3) | 504d5688b6aSAriff Abdullah ATI_REG_OUT_DMA_SLOT_BIT(4); 505d5688b6aSAriff Abdullah value |= 0x04 << ATI_REG_OUT_DMA_THRESHOLD_SHIFT; 506d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_OUT_DMA_SLOT, value); 507d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_CMD); 508d5688b6aSAriff Abdullah value &= ~ATI_REG_CMD_INTERLEAVE_OUT; 50905051995SAriff Abdullah if ((format & AFMT_32BIT) == 0) 510d5688b6aSAriff Abdullah value |= ATI_REG_CMD_INTERLEAVE_OUT; 511d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_CMD, value); 512d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_6CH_REORDER); 513d5688b6aSAriff Abdullah value &= ~ATI_REG_6CH_REORDER_EN; 514d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_6CH_REORDER, value); 515d5688b6aSAriff Abdullah } 51688a50509SAriff Abdullah ch->fmt = format; 517d5688b6aSAriff Abdullah atiixp_unlock(sc); 518d5688b6aSAriff Abdullah 5199f52a325SAriff Abdullah return (0); 520d5688b6aSAriff Abdullah } 521d5688b6aSAriff Abdullah 52290da2b28SAriff Abdullah static uint32_t 523d5688b6aSAriff Abdullah atiixp_chan_setspeed(kobj_t obj, void *data, uint32_t spd) 524d5688b6aSAriff Abdullah { 525d5688b6aSAriff Abdullah /* XXX We're supposed to do VRA/DRA processing right here */ 5269f52a325SAriff Abdullah return (ATI_IXP_BASE_RATE); 527d5688b6aSAriff Abdullah } 528d5688b6aSAriff Abdullah 529d5688b6aSAriff Abdullah static int 5301042342aSAriff Abdullah atiixp_chan_setfragments(kobj_t obj, void *data, 5311042342aSAriff Abdullah uint32_t blksz, uint32_t blkcnt) 5321042342aSAriff Abdullah { 5331042342aSAriff Abdullah struct atiixp_chinfo *ch = data; 5341042342aSAriff Abdullah struct atiixp_info *sc = ch->parent; 5351042342aSAriff Abdullah 5361042342aSAriff Abdullah blksz &= ATI_IXP_BLK_ALIGN; 5371042342aSAriff Abdullah 5381042342aSAriff Abdullah if (blksz > (sndbuf_getmaxsize(ch->buffer) / ATI_IXP_DMA_CHSEGS_MIN)) 5391042342aSAriff Abdullah blksz = sndbuf_getmaxsize(ch->buffer) / ATI_IXP_DMA_CHSEGS_MIN; 5401042342aSAriff Abdullah if (blksz < ATI_IXP_BLK_MIN) 5411042342aSAriff Abdullah blksz = ATI_IXP_BLK_MIN; 5421042342aSAriff Abdullah if (blkcnt > ATI_IXP_DMA_CHSEGS_MAX) 5431042342aSAriff Abdullah blkcnt = ATI_IXP_DMA_CHSEGS_MAX; 5441042342aSAriff Abdullah if (blkcnt < ATI_IXP_DMA_CHSEGS_MIN) 5451042342aSAriff Abdullah blkcnt = ATI_IXP_DMA_CHSEGS_MIN; 5461042342aSAriff Abdullah 5471042342aSAriff Abdullah while ((blksz * blkcnt) > sndbuf_getmaxsize(ch->buffer)) { 5481042342aSAriff Abdullah if ((blkcnt >> 1) >= ATI_IXP_DMA_CHSEGS_MIN) 5491042342aSAriff Abdullah blkcnt >>= 1; 5501042342aSAriff Abdullah else if ((blksz >> 1) >= ATI_IXP_BLK_MIN) 5511042342aSAriff Abdullah blksz >>= 1; 5521042342aSAriff Abdullah else 5531042342aSAriff Abdullah break; 5541042342aSAriff Abdullah } 5551042342aSAriff Abdullah 5561042342aSAriff Abdullah if ((sndbuf_getblksz(ch->buffer) != blksz || 5571042342aSAriff Abdullah sndbuf_getblkcnt(ch->buffer) != blkcnt) && 5581042342aSAriff Abdullah sndbuf_resize(ch->buffer, blkcnt, blksz) != 0) 5591042342aSAriff Abdullah device_printf(sc->dev, "%s: failed blksz=%u blkcnt=%u\n", 5601042342aSAriff Abdullah __func__, blksz, blkcnt); 5611042342aSAriff Abdullah 5621042342aSAriff Abdullah ch->blksz = sndbuf_getblksz(ch->buffer); 5631042342aSAriff Abdullah ch->blkcnt = sndbuf_getblkcnt(ch->buffer); 5641042342aSAriff Abdullah 56590da2b28SAriff Abdullah return (0); 5661042342aSAriff Abdullah } 5671042342aSAriff Abdullah 56890da2b28SAriff Abdullah static uint32_t 569d5688b6aSAriff Abdullah atiixp_chan_setblocksize(kobj_t obj, void *data, uint32_t blksz) 570d5688b6aSAriff Abdullah { 571d5688b6aSAriff Abdullah struct atiixp_chinfo *ch = data; 572d5688b6aSAriff Abdullah struct atiixp_info *sc = ch->parent; 573d5688b6aSAriff Abdullah 5741042342aSAriff Abdullah atiixp_chan_setfragments(obj, data, blksz, sc->blkcnt); 575a580b31aSAriff Abdullah 576a580b31aSAriff Abdullah return (ch->blksz); 577d5688b6aSAriff Abdullah } 578d5688b6aSAriff Abdullah 579d5688b6aSAriff Abdullah static void 580d5688b6aSAriff Abdullah atiixp_buildsgdt(struct atiixp_chinfo *ch) 581d5688b6aSAriff Abdullah { 582a580b31aSAriff Abdullah struct atiixp_info *sc = ch->parent; 583a580b31aSAriff Abdullah uint32_t addr, blksz, blkcnt; 584d5688b6aSAriff Abdullah int i; 585d5688b6aSAriff Abdullah 586d5688b6aSAriff Abdullah addr = sndbuf_getbufaddr(ch->buffer); 587d5688b6aSAriff Abdullah 588a580b31aSAriff Abdullah if (sc->polling != 0) { 589a580b31aSAriff Abdullah blksz = ch->blksz * ch->blkcnt; 590a580b31aSAriff Abdullah blkcnt = 1; 591a580b31aSAriff Abdullah } else { 592a580b31aSAriff Abdullah blksz = ch->blksz; 593a580b31aSAriff Abdullah blkcnt = ch->blkcnt; 594d5688b6aSAriff Abdullah } 5959f52a325SAriff Abdullah 596a580b31aSAriff Abdullah for (i = 0; i < blkcnt; i++) { 597a580b31aSAriff Abdullah ch->sgd_table[i].addr = htole32(addr + (i * blksz)); 598a580b31aSAriff Abdullah ch->sgd_table[i].status = htole16(0); 599a580b31aSAriff Abdullah ch->sgd_table[i].size = htole16(blksz >> 2); 600a580b31aSAriff Abdullah ch->sgd_table[i].next = htole32((uint32_t)ch->sgd_addr + 601a580b31aSAriff Abdullah (((i + 1) % blkcnt) * sizeof(struct atiixp_dma_op))); 602a580b31aSAriff Abdullah } 603a580b31aSAriff Abdullah } 604a580b31aSAriff Abdullah 605a580b31aSAriff Abdullah static __inline uint32_t 606a580b31aSAriff Abdullah atiixp_dmapos(struct atiixp_chinfo *ch) 607a580b31aSAriff Abdullah { 608a580b31aSAriff Abdullah struct atiixp_info *sc = ch->parent; 609a580b31aSAriff Abdullah uint32_t reg, addr, sz, retry; 610a580b31aSAriff Abdullah volatile uint32_t ptr; 611a580b31aSAriff Abdullah 612a580b31aSAriff Abdullah reg = ch->dt_cur_bit; 613a580b31aSAriff Abdullah addr = sndbuf_getbufaddr(ch->buffer); 614a580b31aSAriff Abdullah sz = ch->blkcnt * ch->blksz; 615a580b31aSAriff Abdullah retry = ATI_IXP_DMA_RETRY_MAX; 616a580b31aSAriff Abdullah 617a580b31aSAriff Abdullah do { 618a580b31aSAriff Abdullah ptr = atiixp_rd(sc, reg); 619a580b31aSAriff Abdullah if (ptr < addr) 620a580b31aSAriff Abdullah continue; 621a580b31aSAriff Abdullah ptr -= addr; 622a580b31aSAriff Abdullah if (ptr < sz) { 623a580b31aSAriff Abdullah #if 0 6249f52a325SAriff Abdullah #ifdef ATI_IXP_DEBUG 625a580b31aSAriff Abdullah if ((ptr & ~(ch->blksz - 1)) != ch->ptr) { 626a580b31aSAriff Abdullah uint32_t delta; 627a580b31aSAriff Abdullah 628a580b31aSAriff Abdullah delta = (sz + ptr - ch->prevptr) % sz; 629a580b31aSAriff Abdullah #ifndef ATI_IXP_DEBUG_VERBOSE 630a580b31aSAriff Abdullah if (delta < ch->blksz) 6319f52a325SAriff Abdullah #endif 632a580b31aSAriff Abdullah device_printf(sc->dev, 633a580b31aSAriff Abdullah "PCMDIR_%s: incoherent DMA " 634a580b31aSAriff Abdullah "prevptr=%u ptr=%u " 635a580b31aSAriff Abdullah "ptr=%u blkcnt=%u " 636a580b31aSAriff Abdullah "[delta=%u != blksz=%u] " 637a580b31aSAriff Abdullah "(%s)\n", 638a580b31aSAriff Abdullah (ch->dir == PCMDIR_PLAY) ? 639a580b31aSAriff Abdullah "PLAY" : "REC", 640a580b31aSAriff Abdullah ch->prevptr, ptr, 641a580b31aSAriff Abdullah ch->ptr, ch->blkcnt, 642a580b31aSAriff Abdullah delta, ch->blksz, 643a580b31aSAriff Abdullah (delta < ch->blksz) ? 644a580b31aSAriff Abdullah "OVERLAPPED!" : "Ok"); 645a580b31aSAriff Abdullah ch->ptr = ptr & ~(ch->blksz - 1); 646a580b31aSAriff Abdullah } 647a580b31aSAriff Abdullah ch->prevptr = ptr; 648a580b31aSAriff Abdullah #endif 649a580b31aSAriff Abdullah #endif 650a580b31aSAriff Abdullah return (ptr); 651a580b31aSAriff Abdullah } 652a580b31aSAriff Abdullah } while (--retry); 653a580b31aSAriff Abdullah 654a580b31aSAriff Abdullah device_printf(sc->dev, "PCMDIR_%s: invalid DMA pointer ptr=%u\n", 655a580b31aSAriff Abdullah (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC", ptr); 656a580b31aSAriff Abdullah 657a580b31aSAriff Abdullah return (0); 658a580b31aSAriff Abdullah } 659a580b31aSAriff Abdullah 660a580b31aSAriff Abdullah static __inline int 661a580b31aSAriff Abdullah atiixp_poll_channel(struct atiixp_chinfo *ch) 662a580b31aSAriff Abdullah { 663a580b31aSAriff Abdullah uint32_t sz, delta; 664a580b31aSAriff Abdullah volatile uint32_t ptr; 665a580b31aSAriff Abdullah 6668a7c4d36SAriff Abdullah if (!(ch->flags & ATI_IXP_CHN_RUNNING)) 667a580b31aSAriff Abdullah return (0); 668a580b31aSAriff Abdullah 669a580b31aSAriff Abdullah sz = ch->blksz * ch->blkcnt; 670a580b31aSAriff Abdullah ptr = atiixp_dmapos(ch); 671a580b31aSAriff Abdullah ch->ptr = ptr; 672a580b31aSAriff Abdullah ptr %= sz; 673a580b31aSAriff Abdullah ptr &= ~(ch->blksz - 1); 674a580b31aSAriff Abdullah delta = (sz + ptr - ch->prevptr) % sz; 675a580b31aSAriff Abdullah 676a580b31aSAriff Abdullah if (delta < ch->blksz) 677a580b31aSAriff Abdullah return (0); 678a580b31aSAriff Abdullah 679a580b31aSAriff Abdullah ch->prevptr = ptr; 680a580b31aSAriff Abdullah 681a580b31aSAriff Abdullah return (1); 682a580b31aSAriff Abdullah } 683a580b31aSAriff Abdullah 6848a7c4d36SAriff Abdullah #define atiixp_chan_active(sc) (((sc)->pch.flags | (sc)->rch.flags) & \ 6858a7c4d36SAriff Abdullah ATI_IXP_CHN_RUNNING) 686a580b31aSAriff Abdullah 687a580b31aSAriff Abdullah static void 688a580b31aSAriff Abdullah atiixp_poll_callback(void *arg) 689a580b31aSAriff Abdullah { 690a580b31aSAriff Abdullah struct atiixp_info *sc = arg; 691a580b31aSAriff Abdullah uint32_t trigger = 0; 692a580b31aSAriff Abdullah 693a580b31aSAriff Abdullah if (sc == NULL) 694a580b31aSAriff Abdullah return; 695a580b31aSAriff Abdullah 696a580b31aSAriff Abdullah atiixp_lock(sc); 697a580b31aSAriff Abdullah if (sc->polling == 0 || atiixp_chan_active(sc) == 0) { 698a580b31aSAriff Abdullah atiixp_unlock(sc); 699a580b31aSAriff Abdullah return; 700a580b31aSAriff Abdullah } 701a580b31aSAriff Abdullah 702a580b31aSAriff Abdullah trigger |= (atiixp_poll_channel(&sc->pch) != 0) ? 1 : 0; 703a580b31aSAriff Abdullah trigger |= (atiixp_poll_channel(&sc->rch) != 0) ? 2 : 0; 704a580b31aSAriff Abdullah 705a580b31aSAriff Abdullah /* XXX */ 706a580b31aSAriff Abdullah callout_reset(&sc->poll_timer, 1/*sc->poll_ticks*/, 707a580b31aSAriff Abdullah atiixp_poll_callback, sc); 708a580b31aSAriff Abdullah 709a580b31aSAriff Abdullah atiixp_unlock(sc); 710a580b31aSAriff Abdullah 711a580b31aSAriff Abdullah if (trigger & 1) 712a580b31aSAriff Abdullah chn_intr(sc->pch.channel); 713a580b31aSAriff Abdullah if (trigger & 2) 714a580b31aSAriff Abdullah chn_intr(sc->rch.channel); 715d5688b6aSAriff Abdullah } 716d5688b6aSAriff Abdullah 717d5688b6aSAriff Abdullah static int 718d5688b6aSAriff Abdullah atiixp_chan_trigger(kobj_t obj, void *data, int go) 719d5688b6aSAriff Abdullah { 720d5688b6aSAriff Abdullah struct atiixp_chinfo *ch = data; 721d5688b6aSAriff Abdullah struct atiixp_info *sc = ch->parent; 722d5688b6aSAriff Abdullah uint32_t value; 723a580b31aSAriff Abdullah int pollticks; 724d5688b6aSAriff Abdullah 725bdfbdcecSAriff Abdullah if (!PCMTRIG_COMMON(go)) 726bdfbdcecSAriff Abdullah return (0); 727bdfbdcecSAriff Abdullah 728d5688b6aSAriff Abdullah atiixp_lock(sc); 729d5688b6aSAriff Abdullah 730d5688b6aSAriff Abdullah switch (go) { 731d5688b6aSAriff Abdullah case PCMTRIG_START: 7329f52a325SAriff Abdullah atiixp_flush_dma(ch); 733d5688b6aSAriff Abdullah atiixp_buildsgdt(ch); 734d5688b6aSAriff Abdullah atiixp_wr(sc, ch->linkptr_bit, 0); 7359f52a325SAriff Abdullah atiixp_enable_dma(ch); 736d5688b6aSAriff Abdullah atiixp_wr(sc, ch->linkptr_bit, 737d5688b6aSAriff Abdullah (uint32_t)ch->sgd_addr | ATI_REG_LINKPTR_EN); 738a580b31aSAriff Abdullah if (sc->polling != 0) { 739a580b31aSAriff Abdullah ch->ptr = 0; 740a580b31aSAriff Abdullah ch->prevptr = 0; 741a580b31aSAriff Abdullah pollticks = ((uint64_t)hz * ch->blksz) / 74290da2b28SAriff Abdullah ((uint64_t)sndbuf_getalign(ch->buffer) * 743a580b31aSAriff Abdullah sndbuf_getspd(ch->buffer)); 744a580b31aSAriff Abdullah pollticks >>= 2; 745a580b31aSAriff Abdullah if (pollticks > hz) 746a580b31aSAriff Abdullah pollticks = hz; 747a580b31aSAriff Abdullah if (pollticks < 1) 748a580b31aSAriff Abdullah pollticks = 1; 749a580b31aSAriff Abdullah if (atiixp_chan_active(sc) == 0 || 750a580b31aSAriff Abdullah pollticks < sc->poll_ticks) { 751a580b31aSAriff Abdullah if (bootverbose) { 752a580b31aSAriff Abdullah if (atiixp_chan_active(sc) == 0) 753a580b31aSAriff Abdullah device_printf(sc->dev, 754a580b31aSAriff Abdullah "%s: pollticks=%d\n", 755a580b31aSAriff Abdullah __func__, pollticks); 756a580b31aSAriff Abdullah else 757a580b31aSAriff Abdullah device_printf(sc->dev, 758a580b31aSAriff Abdullah "%s: pollticks %d -> %d\n", 759a580b31aSAriff Abdullah __func__, sc->poll_ticks, 760a580b31aSAriff Abdullah pollticks); 761a580b31aSAriff Abdullah } 762a580b31aSAriff Abdullah sc->poll_ticks = pollticks; 763a580b31aSAriff Abdullah callout_reset(&sc->poll_timer, 1, 764a580b31aSAriff Abdullah atiixp_poll_callback, sc); 765a580b31aSAriff Abdullah } 766a580b31aSAriff Abdullah } 7678a7c4d36SAriff Abdullah ch->flags |= ATI_IXP_CHN_RUNNING; 768d5688b6aSAriff Abdullah break; 769d5688b6aSAriff Abdullah case PCMTRIG_STOP: 770d5688b6aSAriff Abdullah case PCMTRIG_ABORT: 7719f52a325SAriff Abdullah atiixp_disable_dma(ch); 7729f52a325SAriff Abdullah atiixp_flush_dma(ch); 7738a7c4d36SAriff Abdullah ch->flags &= ~ATI_IXP_CHN_RUNNING; 774a580b31aSAriff Abdullah if (sc->polling != 0) { 775a580b31aSAriff Abdullah if (atiixp_chan_active(sc) == 0) { 776a580b31aSAriff Abdullah callout_stop(&sc->poll_timer); 777a580b31aSAriff Abdullah sc->poll_ticks = 1; 778a580b31aSAriff Abdullah } else { 7798a7c4d36SAriff Abdullah if (sc->pch.flags & ATI_IXP_CHN_RUNNING) 780a580b31aSAriff Abdullah ch = &sc->pch; 781a580b31aSAriff Abdullah else 782a580b31aSAriff Abdullah ch = &sc->rch; 783a580b31aSAriff Abdullah pollticks = ((uint64_t)hz * ch->blksz) / 78490da2b28SAriff Abdullah ((uint64_t)sndbuf_getalign(ch->buffer) * 785a580b31aSAriff Abdullah sndbuf_getspd(ch->buffer)); 786a580b31aSAriff Abdullah pollticks >>= 2; 787a580b31aSAriff Abdullah if (pollticks > hz) 788a580b31aSAriff Abdullah pollticks = hz; 789a580b31aSAriff Abdullah if (pollticks < 1) 790a580b31aSAriff Abdullah pollticks = 1; 791a580b31aSAriff Abdullah if (pollticks > sc->poll_ticks) { 792a580b31aSAriff Abdullah if (bootverbose) 793a580b31aSAriff Abdullah device_printf(sc->dev, 794a580b31aSAriff Abdullah "%s: pollticks %d -> %d\n", 795a580b31aSAriff Abdullah __func__, sc->poll_ticks, 796a580b31aSAriff Abdullah pollticks); 797a580b31aSAriff Abdullah sc->poll_ticks = pollticks; 798a580b31aSAriff Abdullah callout_reset(&sc->poll_timer, 799a580b31aSAriff Abdullah 1, atiixp_poll_callback, 800a580b31aSAriff Abdullah sc); 801a580b31aSAriff Abdullah } 802a580b31aSAriff Abdullah } 803a580b31aSAriff Abdullah } 804d5688b6aSAriff Abdullah break; 805d5688b6aSAriff Abdullah default: 806d5688b6aSAriff Abdullah atiixp_unlock(sc); 8079f52a325SAriff Abdullah return (0); 808d5688b6aSAriff Abdullah break; 809d5688b6aSAriff Abdullah } 810d5688b6aSAriff Abdullah 811d5688b6aSAriff Abdullah /* Update bus busy status */ 812d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_IER); 813a580b31aSAriff Abdullah if (atiixp_rd(sc, ATI_REG_CMD) & (ATI_REG_CMD_SEND_EN | 814a580b31aSAriff Abdullah ATI_REG_CMD_RECEIVE_EN | ATI_REG_CMD_SPDF_OUT_EN)) 815d5688b6aSAriff Abdullah value |= ATI_REG_IER_SET_BUS_BUSY; 816d5688b6aSAriff Abdullah else 817d5688b6aSAriff Abdullah value &= ~ATI_REG_IER_SET_BUS_BUSY; 818d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_IER, value); 819d5688b6aSAriff Abdullah 820d5688b6aSAriff Abdullah atiixp_unlock(sc); 821d5688b6aSAriff Abdullah 8229f52a325SAriff Abdullah return (0); 8239f52a325SAriff Abdullah } 8249f52a325SAriff Abdullah 82590da2b28SAriff Abdullah static uint32_t 826d5688b6aSAriff Abdullah atiixp_chan_getptr(kobj_t obj, void *data) 827d5688b6aSAriff Abdullah { 828d5688b6aSAriff Abdullah struct atiixp_chinfo *ch = data; 829d5688b6aSAriff Abdullah struct atiixp_info *sc = ch->parent; 8309f52a325SAriff Abdullah uint32_t ptr; 831d5688b6aSAriff Abdullah 832d5688b6aSAriff Abdullah atiixp_lock(sc); 833a580b31aSAriff Abdullah if (sc->polling != 0) 834a580b31aSAriff Abdullah ptr = ch->ptr; 835a580b31aSAriff Abdullah else 8369f52a325SAriff Abdullah ptr = atiixp_dmapos(ch); 837d5688b6aSAriff Abdullah atiixp_unlock(sc); 838d5688b6aSAriff Abdullah 8399f52a325SAriff Abdullah return (ptr); 840d5688b6aSAriff Abdullah } 841d5688b6aSAriff Abdullah 842d5688b6aSAriff Abdullah static struct pcmchan_caps * 843d5688b6aSAriff Abdullah atiixp_chan_getcaps(kobj_t obj, void *data) 844d5688b6aSAriff Abdullah { 845d5688b6aSAriff Abdullah struct atiixp_chinfo *ch = data; 846d5688b6aSAriff Abdullah 847d5688b6aSAriff Abdullah if (ch->caps_32bit) 8489f52a325SAriff Abdullah return (&atiixp_caps_32bit); 8499f52a325SAriff Abdullah return (&atiixp_caps); 850d5688b6aSAriff Abdullah } 851d5688b6aSAriff Abdullah 852d5688b6aSAriff Abdullah static kobj_method_t atiixp_chan_methods[] = { 853d5688b6aSAriff Abdullah KOBJMETHOD(channel_init, atiixp_chan_init), 854d5688b6aSAriff Abdullah KOBJMETHOD(channel_setformat, atiixp_chan_setformat), 855d5688b6aSAriff Abdullah KOBJMETHOD(channel_setspeed, atiixp_chan_setspeed), 856d5688b6aSAriff Abdullah KOBJMETHOD(channel_setblocksize, atiixp_chan_setblocksize), 8571042342aSAriff Abdullah KOBJMETHOD(channel_setfragments, atiixp_chan_setfragments), 858d5688b6aSAriff Abdullah KOBJMETHOD(channel_trigger, atiixp_chan_trigger), 859d5688b6aSAriff Abdullah KOBJMETHOD(channel_getptr, atiixp_chan_getptr), 860d5688b6aSAriff Abdullah KOBJMETHOD(channel_getcaps, atiixp_chan_getcaps), 86190da2b28SAriff Abdullah KOBJMETHOD_END 862d5688b6aSAriff Abdullah }; 863d5688b6aSAriff Abdullah CHANNEL_DECLARE(atiixp_chan); 864d5688b6aSAriff Abdullah 865d5688b6aSAriff Abdullah /* 866d5688b6aSAriff Abdullah * PCI driver interface 867d5688b6aSAriff Abdullah */ 868d5688b6aSAriff Abdullah static void 869d5688b6aSAriff Abdullah atiixp_intr(void *p) 870d5688b6aSAriff Abdullah { 871d5688b6aSAriff Abdullah struct atiixp_info *sc = p; 872d5688b6aSAriff Abdullah uint32_t status, enable, detected_codecs; 873a580b31aSAriff Abdullah uint32_t trigger = 0; 874d5688b6aSAriff Abdullah 875d5688b6aSAriff Abdullah atiixp_lock(sc); 876a580b31aSAriff Abdullah if (sc->polling != 0) { 877a580b31aSAriff Abdullah atiixp_unlock(sc); 878a580b31aSAriff Abdullah return; 879a580b31aSAriff Abdullah } 880d5688b6aSAriff Abdullah status = atiixp_rd(sc, ATI_REG_ISR); 881d5688b6aSAriff Abdullah 882d5688b6aSAriff Abdullah if (status == 0) { 883d5688b6aSAriff Abdullah atiixp_unlock(sc); 884d5688b6aSAriff Abdullah return; 885d5688b6aSAriff Abdullah } 886d5688b6aSAriff Abdullah 8878a7c4d36SAriff Abdullah if ((status & ATI_REG_ISR_OUT_STATUS) && 8888a7c4d36SAriff Abdullah (sc->pch.flags & ATI_IXP_CHN_RUNNING)) 889a580b31aSAriff Abdullah trigger |= 1; 8908a7c4d36SAriff Abdullah if ((status & ATI_REG_ISR_IN_STATUS) && 8918a7c4d36SAriff Abdullah (sc->rch.flags & ATI_IXP_CHN_RUNNING)) 892a580b31aSAriff Abdullah trigger |= 2; 893d5688b6aSAriff Abdullah 894d5688b6aSAriff Abdullah #if 0 895d5688b6aSAriff Abdullah if (status & ATI_REG_ISR_IN_XRUN) { 896d5688b6aSAriff Abdullah device_printf(sc->dev, 897d5688b6aSAriff Abdullah "Recieve IN XRUN interrupt\n"); 898d5688b6aSAriff Abdullah } 899d5688b6aSAriff Abdullah if (status & ATI_REG_ISR_OUT_XRUN) { 900d5688b6aSAriff Abdullah device_printf(sc->dev, 901d5688b6aSAriff Abdullah "Recieve OUT XRUN interrupt\n"); 902d5688b6aSAriff Abdullah } 903d5688b6aSAriff Abdullah #endif 904d5688b6aSAriff Abdullah 905d5688b6aSAriff Abdullah if (status & CODEC_CHECK_BITS) { 906d5688b6aSAriff Abdullah /* mark missing codecs as not ready */ 907d5688b6aSAriff Abdullah detected_codecs = status & CODEC_CHECK_BITS; 908d5688b6aSAriff Abdullah sc->codec_not_ready_bits |= detected_codecs; 909d5688b6aSAriff Abdullah 910976b0106SKevin Lo /* disable detected interrupt sources */ 911d5688b6aSAriff Abdullah enable = atiixp_rd(sc, ATI_REG_IER); 912d5688b6aSAriff Abdullah enable &= ~detected_codecs; 913d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_IER, enable); 91479b783c7SAriff Abdullah wakeup(sc); 915d5688b6aSAriff Abdullah } 916d5688b6aSAriff Abdullah 917d5688b6aSAriff Abdullah /* acknowledge */ 918d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_ISR, status); 919d5688b6aSAriff Abdullah atiixp_unlock(sc); 920a580b31aSAriff Abdullah 921a580b31aSAriff Abdullah if (trigger & 1) 922a580b31aSAriff Abdullah chn_intr(sc->pch.channel); 923a580b31aSAriff Abdullah if (trigger & 2) 924a580b31aSAriff Abdullah chn_intr(sc->rch.channel); 925d5688b6aSAriff Abdullah } 926d5688b6aSAriff Abdullah 927d5688b6aSAriff Abdullah static void 928d5688b6aSAriff Abdullah atiixp_dma_cb(void *p, bus_dma_segment_t *bds, int a, int b) 929d5688b6aSAriff Abdullah { 930d5688b6aSAriff Abdullah struct atiixp_info *sc = (struct atiixp_info *)p; 931d5688b6aSAriff Abdullah sc->sgd_addr = bds->ds_addr; 932d5688b6aSAriff Abdullah } 933d5688b6aSAriff Abdullah 934d5688b6aSAriff Abdullah static void 935d5688b6aSAriff Abdullah atiixp_chip_pre_init(struct atiixp_info *sc) 936d5688b6aSAriff Abdullah { 937d5688b6aSAriff Abdullah uint32_t value; 938d5688b6aSAriff Abdullah 939d5688b6aSAriff Abdullah atiixp_lock(sc); 940d5688b6aSAriff Abdullah 941d5688b6aSAriff Abdullah /* disable interrupts */ 942d5688b6aSAriff Abdullah atiixp_disable_interrupts(sc); 943d5688b6aSAriff Abdullah 944d5688b6aSAriff Abdullah /* clear all DMA enables (preserving rest of settings) */ 945d5688b6aSAriff Abdullah value = atiixp_rd(sc, ATI_REG_CMD); 946d5688b6aSAriff Abdullah value &= ~(ATI_REG_CMD_IN_DMA_EN | ATI_REG_CMD_OUT_DMA_EN | 947d5688b6aSAriff Abdullah ATI_REG_CMD_SPDF_OUT_EN ); 948d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_CMD, value); 949d5688b6aSAriff Abdullah 950d5688b6aSAriff Abdullah /* reset aclink */ 951d5688b6aSAriff Abdullah atiixp_reset_aclink(sc); 952d5688b6aSAriff Abdullah 953d5688b6aSAriff Abdullah sc->codec_not_ready_bits = 0; 954d5688b6aSAriff Abdullah 955d5688b6aSAriff Abdullah /* enable all codecs to interrupt as well as the new frame interrupt */ 956d5688b6aSAriff Abdullah atiixp_wr(sc, ATI_REG_IER, CODEC_CHECK_BITS); 957d5688b6aSAriff Abdullah 958d5688b6aSAriff Abdullah atiixp_unlock(sc); 959d5688b6aSAriff Abdullah } 960d5688b6aSAriff Abdullah 961a580b31aSAriff Abdullah static int 962a580b31aSAriff Abdullah sysctl_atiixp_polling(SYSCTL_HANDLER_ARGS) 963a580b31aSAriff Abdullah { 964a580b31aSAriff Abdullah struct atiixp_info *sc; 965a580b31aSAriff Abdullah device_t dev; 966a580b31aSAriff Abdullah int err, val; 967a580b31aSAriff Abdullah 968a580b31aSAriff Abdullah dev = oidp->oid_arg1; 969a580b31aSAriff Abdullah sc = pcm_getdevinfo(dev); 970a580b31aSAriff Abdullah if (sc == NULL) 971a580b31aSAriff Abdullah return (EINVAL); 972a580b31aSAriff Abdullah atiixp_lock(sc); 973a580b31aSAriff Abdullah val = sc->polling; 974a580b31aSAriff Abdullah atiixp_unlock(sc); 975041b706bSDavid Malone err = sysctl_handle_int(oidp, &val, 0, req); 976a580b31aSAriff Abdullah 977a580b31aSAriff Abdullah if (err || req->newptr == NULL) 978a580b31aSAriff Abdullah return (err); 979a580b31aSAriff Abdullah if (val < 0 || val > 1) 980a580b31aSAriff Abdullah return (EINVAL); 981a580b31aSAriff Abdullah 982a580b31aSAriff Abdullah atiixp_lock(sc); 983a580b31aSAriff Abdullah if (val != sc->polling) { 984a580b31aSAriff Abdullah if (atiixp_chan_active(sc) != 0) 985a580b31aSAriff Abdullah err = EBUSY; 986a580b31aSAriff Abdullah else if (val == 0) { 987a580b31aSAriff Abdullah atiixp_enable_interrupts(sc); 988a580b31aSAriff Abdullah sc->polling = 0; 989a580b31aSAriff Abdullah DELAY(1000); 990a580b31aSAriff Abdullah } else { 991a580b31aSAriff Abdullah atiixp_disable_interrupts(sc); 992a580b31aSAriff Abdullah sc->polling = 1; 993a580b31aSAriff Abdullah DELAY(1000); 994a580b31aSAriff Abdullah } 995a580b31aSAriff Abdullah } 996a580b31aSAriff Abdullah atiixp_unlock(sc); 997a580b31aSAriff Abdullah 998a580b31aSAriff Abdullah return (err); 999a580b31aSAriff Abdullah } 1000a580b31aSAriff Abdullah 1001d5688b6aSAriff Abdullah static void 1002d5688b6aSAriff Abdullah atiixp_chip_post_init(void *arg) 1003d5688b6aSAriff Abdullah { 1004d5688b6aSAriff Abdullah struct atiixp_info *sc = (struct atiixp_info *)arg; 100505051995SAriff Abdullah uint32_t subdev; 1006a580b31aSAriff Abdullah int i, timeout, found, polling; 1007d5688b6aSAriff Abdullah char status[SND_STATUSLEN]; 1008d5688b6aSAriff Abdullah 1009d5688b6aSAriff Abdullah atiixp_lock(sc); 1010d5688b6aSAriff Abdullah 1011d5688b6aSAriff Abdullah if (sc->delayed_attach.ich_func) { 1012d5688b6aSAriff Abdullah config_intrhook_disestablish(&sc->delayed_attach); 1013d5688b6aSAriff Abdullah sc->delayed_attach.ich_func = NULL; 1014d5688b6aSAriff Abdullah } 1015d5688b6aSAriff Abdullah 1016a580b31aSAriff Abdullah polling = sc->polling; 1017a580b31aSAriff Abdullah sc->polling = 0; 1018a580b31aSAriff Abdullah 101979b783c7SAriff Abdullah timeout = 10; 102079b783c7SAriff Abdullah if (sc->codec_not_ready_bits == 0) { 1021d5688b6aSAriff Abdullah /* wait for the interrupts to happen */ 10229f52a325SAriff Abdullah do { 102379b783c7SAriff Abdullah msleep(sc, sc->lock, PWAIT, "ixpslp", max(hz / 10, 1)); 102479b783c7SAriff Abdullah if (sc->codec_not_ready_bits != 0) 1025d5688b6aSAriff Abdullah break; 10269f52a325SAriff Abdullah } while (--timeout); 102779b783c7SAriff Abdullah } 1028d5688b6aSAriff Abdullah 1029a580b31aSAriff Abdullah sc->polling = polling; 1030d5688b6aSAriff Abdullah atiixp_disable_interrupts(sc); 1031d5688b6aSAriff Abdullah 103279b783c7SAriff Abdullah if (sc->codec_not_ready_bits == 0 && timeout == 0) { 1033d5688b6aSAriff Abdullah device_printf(sc->dev, 1034d5688b6aSAriff Abdullah "WARNING: timeout during codec detection; " 1035d5688b6aSAriff Abdullah "codecs might be present but haven't interrupted\n"); 1036d5688b6aSAriff Abdullah atiixp_unlock(sc); 1037f2a1d71aSAriff Abdullah goto postinitbad; 1038d5688b6aSAriff Abdullah } 1039d5688b6aSAriff Abdullah 1040d5688b6aSAriff Abdullah found = 0; 1041d5688b6aSAriff Abdullah 1042d5688b6aSAriff Abdullah /* 1043d5688b6aSAriff Abdullah * ATI IXP can have upto 3 codecs, but single codec should be 1044d5688b6aSAriff Abdullah * suffice for now. 1045d5688b6aSAriff Abdullah */ 1046a580b31aSAriff Abdullah if (!(sc->codec_not_ready_bits & ATI_REG_ISR_CODEC0_NOT_READY)) { 1047d5688b6aSAriff Abdullah /* codec 0 present */ 1048d5688b6aSAriff Abdullah sc->codec_found++; 1049d5688b6aSAriff Abdullah sc->codec_idx = 0; 1050d5688b6aSAriff Abdullah found++; 1051d5688b6aSAriff Abdullah } 1052d5688b6aSAriff Abdullah 1053a580b31aSAriff Abdullah if (!(sc->codec_not_ready_bits & ATI_REG_ISR_CODEC1_NOT_READY)) { 1054d5688b6aSAriff Abdullah /* codec 1 present */ 1055d5688b6aSAriff Abdullah sc->codec_found++; 1056d5688b6aSAriff Abdullah } 1057d5688b6aSAriff Abdullah 1058a580b31aSAriff Abdullah if (!(sc->codec_not_ready_bits & ATI_REG_ISR_CODEC2_NOT_READY)) { 1059d5688b6aSAriff Abdullah /* codec 2 present */ 1060d5688b6aSAriff Abdullah sc->codec_found++; 1061d5688b6aSAriff Abdullah } 1062d5688b6aSAriff Abdullah 1063d5688b6aSAriff Abdullah atiixp_unlock(sc); 1064d5688b6aSAriff Abdullah 1065d5688b6aSAriff Abdullah if (found == 0) 1066f2a1d71aSAriff Abdullah goto postinitbad; 1067d5688b6aSAriff Abdullah 1068d5688b6aSAriff Abdullah /* create/init mixer */ 1069d5688b6aSAriff Abdullah sc->codec = AC97_CREATE(sc->dev, sc, atiixp_ac97); 1070d5688b6aSAriff Abdullah if (sc->codec == NULL) 1071d5688b6aSAriff Abdullah goto postinitbad; 1072d5688b6aSAriff Abdullah 1073a580b31aSAriff Abdullah subdev = (pci_get_subdevice(sc->dev) << 16) | 1074a580b31aSAriff Abdullah pci_get_subvendor(sc->dev); 107505051995SAriff Abdullah switch (subdev) { 10760585c315SAriff Abdullah case 0x11831043: /* ASUS A6R */ 107705051995SAriff Abdullah case 0x2043161f: /* Maxselect x710s - http://maxselect.ru/ */ 1078a580b31aSAriff Abdullah ac97_setflags(sc->codec, ac97_getflags(sc->codec) | 1079a580b31aSAriff Abdullah AC97_F_EAPD_INV); 108005051995SAriff Abdullah break; 108105051995SAriff Abdullah default: 108205051995SAriff Abdullah break; 108305051995SAriff Abdullah } 108405051995SAriff Abdullah 1085d5688b6aSAriff Abdullah mixer_init(sc->dev, ac97_getmixerclass(), sc->codec); 1086d5688b6aSAriff Abdullah 1087d5688b6aSAriff Abdullah if (pcm_register(sc->dev, sc, ATI_IXP_NPCHAN, ATI_IXP_NRCHAN)) 1088d5688b6aSAriff Abdullah goto postinitbad; 1089d5688b6aSAriff Abdullah 1090d5688b6aSAriff Abdullah for (i = 0; i < ATI_IXP_NPCHAN; i++) 1091d5688b6aSAriff Abdullah pcm_addchan(sc->dev, PCMDIR_PLAY, &atiixp_chan_class, sc); 1092d5688b6aSAriff Abdullah for (i = 0; i < ATI_IXP_NRCHAN; i++) 1093d5688b6aSAriff Abdullah pcm_addchan(sc->dev, PCMDIR_REC, &atiixp_chan_class, sc); 1094d5688b6aSAriff Abdullah 1095a580b31aSAriff Abdullah SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev), 1096a580b31aSAriff Abdullah SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO, 1097a580b31aSAriff Abdullah "polling", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev), 1098a580b31aSAriff Abdullah sysctl_atiixp_polling, "I", "Enable polling mode"); 1099a580b31aSAriff Abdullah 1100d5688b6aSAriff Abdullah snprintf(status, SND_STATUSLEN, "at memory 0x%lx irq %ld %s", 1101d5688b6aSAriff Abdullah rman_get_start(sc->reg), rman_get_start(sc->irq), 1102d5688b6aSAriff Abdullah PCM_KLDSTRING(snd_atiixp)); 1103d5688b6aSAriff Abdullah 1104d5688b6aSAriff Abdullah pcm_setstatus(sc->dev, status); 1105d5688b6aSAriff Abdullah 1106d5688b6aSAriff Abdullah atiixp_lock(sc); 1107a580b31aSAriff Abdullah if (sc->polling == 0) 1108d5688b6aSAriff Abdullah atiixp_enable_interrupts(sc); 1109d5688b6aSAriff Abdullah atiixp_unlock(sc); 1110d5688b6aSAriff Abdullah 1111d5688b6aSAriff Abdullah return; 1112d5688b6aSAriff Abdullah 1113d5688b6aSAriff Abdullah postinitbad: 1114f2a1d71aSAriff Abdullah atiixp_release_resource(sc); 1115f2a1d71aSAriff Abdullah } 1116f2a1d71aSAriff Abdullah 1117f2a1d71aSAriff Abdullah static void 1118f2a1d71aSAriff Abdullah atiixp_release_resource(struct atiixp_info *sc) 1119f2a1d71aSAriff Abdullah { 1120f2a1d71aSAriff Abdullah if (sc == NULL) 1121f2a1d71aSAriff Abdullah return; 11225d75db4fSAriff Abdullah if (sc->registered_channels != 0) { 11235d75db4fSAriff Abdullah atiixp_lock(sc); 11245d75db4fSAriff Abdullah sc->polling = 0; 11255d75db4fSAriff Abdullah callout_stop(&sc->poll_timer); 11265d75db4fSAriff Abdullah atiixp_unlock(sc); 11275d75db4fSAriff Abdullah callout_drain(&sc->poll_timer); 11285d75db4fSAriff Abdullah } 1129f2a1d71aSAriff Abdullah if (sc->codec) { 1130d5688b6aSAriff Abdullah ac97_destroy(sc->codec); 1131f2a1d71aSAriff Abdullah sc->codec = NULL; 1132f2a1d71aSAriff Abdullah } 1133f2a1d71aSAriff Abdullah if (sc->ih) { 1134d5688b6aSAriff Abdullah bus_teardown_intr(sc->dev, sc->irq, sc->ih); 1135703c934aSAriff Abdullah sc->ih = NULL; 1136f2a1d71aSAriff Abdullah } 1137f2a1d71aSAriff Abdullah if (sc->reg) { 1138d5688b6aSAriff Abdullah bus_release_resource(sc->dev, sc->regtype, sc->regid, sc->reg); 1139703c934aSAriff Abdullah sc->reg = NULL; 1140f2a1d71aSAriff Abdullah } 1141f2a1d71aSAriff Abdullah if (sc->irq) { 1142d5688b6aSAriff Abdullah bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irqid, sc->irq); 1143703c934aSAriff Abdullah sc->irq = NULL; 1144f2a1d71aSAriff Abdullah } 1145f2a1d71aSAriff Abdullah if (sc->parent_dmat) { 1146d5688b6aSAriff Abdullah bus_dma_tag_destroy(sc->parent_dmat); 1147703c934aSAriff Abdullah sc->parent_dmat = NULL; 1148f2a1d71aSAriff Abdullah } 1149*86843ea8SJohn Baldwin if (sc->sgd_addr) { 1150d5688b6aSAriff Abdullah bus_dmamap_unload(sc->sgd_dmat, sc->sgd_dmamap); 1151*86843ea8SJohn Baldwin sc->sgd_addr = 0; 1152*86843ea8SJohn Baldwin } 1153703c934aSAriff Abdullah if (sc->sgd_table) { 1154703c934aSAriff Abdullah bus_dmamem_free(sc->sgd_dmat, sc->sgd_table, sc->sgd_dmamap); 1155703c934aSAriff Abdullah sc->sgd_table = NULL; 1156f2a1d71aSAriff Abdullah } 1157f2a1d71aSAriff Abdullah if (sc->sgd_dmat) { 1158d5688b6aSAriff Abdullah bus_dma_tag_destroy(sc->sgd_dmat); 1159703c934aSAriff Abdullah sc->sgd_dmat = NULL; 1160f2a1d71aSAriff Abdullah } 1161f2a1d71aSAriff Abdullah if (sc->lock) { 1162d5688b6aSAriff Abdullah snd_mtxfree(sc->lock); 1163f2a1d71aSAriff Abdullah sc->lock = NULL; 1164f2a1d71aSAriff Abdullah } 11655d75db4fSAriff Abdullah free(sc, M_DEVBUF); 1166d5688b6aSAriff Abdullah } 1167d5688b6aSAriff Abdullah 1168d5688b6aSAriff Abdullah static int 1169d5688b6aSAriff Abdullah atiixp_pci_probe(device_t dev) 1170d5688b6aSAriff Abdullah { 1171d5688b6aSAriff Abdullah int i; 1172d5688b6aSAriff Abdullah uint16_t devid, vendor; 1173d5688b6aSAriff Abdullah 1174d5688b6aSAriff Abdullah vendor = pci_get_vendor(dev); 1175d5688b6aSAriff Abdullah devid = pci_get_device(dev); 1176d5688b6aSAriff Abdullah for (i = 0; i < sizeof(atiixp_hw) / sizeof(atiixp_hw[0]); i++) { 1177d5688b6aSAriff Abdullah if (vendor == atiixp_hw[i].vendor && 1178d5688b6aSAriff Abdullah devid == atiixp_hw[i].devid) { 1179d5688b6aSAriff Abdullah device_set_desc(dev, atiixp_hw[i].desc); 11809f52a325SAriff Abdullah return (BUS_PROBE_DEFAULT); 1181d5688b6aSAriff Abdullah } 1182d5688b6aSAriff Abdullah } 1183d5688b6aSAriff Abdullah 11849f52a325SAriff Abdullah return (ENXIO); 1185d5688b6aSAriff Abdullah } 1186d5688b6aSAriff Abdullah 1187d5688b6aSAriff Abdullah static int 1188d5688b6aSAriff Abdullah atiixp_pci_attach(device_t dev) 1189d5688b6aSAriff Abdullah { 1190d5688b6aSAriff Abdullah struct atiixp_info *sc; 1191d5688b6aSAriff Abdullah int i; 1192d5688b6aSAriff Abdullah 11935d75db4fSAriff Abdullah sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); 11944582b3a1SAriff Abdullah sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_atiixp softc"); 1195d5688b6aSAriff Abdullah sc->dev = dev; 1196a580b31aSAriff Abdullah 1197a580b31aSAriff Abdullah callout_init(&sc->poll_timer, CALLOUT_MPSAFE); 1198a580b31aSAriff Abdullah sc->poll_ticks = 1; 1199a580b31aSAriff Abdullah 1200a580b31aSAriff Abdullah if (resource_int_value(device_get_name(sc->dev), 1201a580b31aSAriff Abdullah device_get_unit(sc->dev), "polling", &i) == 0 && i != 0) 1202a580b31aSAriff Abdullah sc->polling = 1; 1203a580b31aSAriff Abdullah else 1204a580b31aSAriff Abdullah sc->polling = 0; 1205d5688b6aSAriff Abdullah 1206d5688b6aSAriff Abdullah pci_enable_busmaster(dev); 1207d5688b6aSAriff Abdullah 1208d5688b6aSAriff Abdullah sc->regid = PCIR_BAR(0); 1209d5688b6aSAriff Abdullah sc->regtype = SYS_RES_MEMORY; 1210a580b31aSAriff Abdullah sc->reg = bus_alloc_resource_any(dev, sc->regtype, 1211a580b31aSAriff Abdullah &sc->regid, RF_ACTIVE); 1212d5688b6aSAriff Abdullah 1213d5688b6aSAriff Abdullah if (!sc->reg) { 1214d5688b6aSAriff Abdullah device_printf(dev, "unable to allocate register space\n"); 1215d5688b6aSAriff Abdullah goto bad; 1216d5688b6aSAriff Abdullah } 1217d5688b6aSAriff Abdullah 1218d5688b6aSAriff Abdullah sc->st = rman_get_bustag(sc->reg); 1219d5688b6aSAriff Abdullah sc->sh = rman_get_bushandle(sc->reg); 1220d5688b6aSAriff Abdullah 12219f52a325SAriff Abdullah sc->bufsz = pcm_getbuffersize(dev, ATI_IXP_BUFSZ_MIN, 12229f52a325SAriff Abdullah ATI_IXP_BUFSZ_DEFAULT, ATI_IXP_BUFSZ_MAX); 1223d5688b6aSAriff Abdullah 1224d5688b6aSAriff Abdullah sc->irqid = 0; 1225d5688b6aSAriff Abdullah sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid, 1226d5688b6aSAriff Abdullah RF_ACTIVE | RF_SHAREABLE); 1227a580b31aSAriff Abdullah if (!sc->irq || snd_setup_intr(dev, sc->irq, INTR_MPSAFE, 1228d5688b6aSAriff Abdullah atiixp_intr, sc, &sc->ih)) { 1229d5688b6aSAriff Abdullah device_printf(dev, "unable to map interrupt\n"); 1230d5688b6aSAriff Abdullah goto bad; 1231d5688b6aSAriff Abdullah } 1232d5688b6aSAriff Abdullah 1233d5688b6aSAriff Abdullah /* 1234d5688b6aSAriff Abdullah * Let the user choose the best DMA segments. 1235d5688b6aSAriff Abdullah */ 1236d5688b6aSAriff Abdullah if (resource_int_value(device_get_name(dev), 1237a580b31aSAriff Abdullah device_get_unit(dev), "blocksize", &i) == 0 && i > 0) { 12381042342aSAriff Abdullah i &= ATI_IXP_BLK_ALIGN; 12391042342aSAriff Abdullah if (i < ATI_IXP_BLK_MIN) 12401042342aSAriff Abdullah i = ATI_IXP_BLK_MIN; 1241a580b31aSAriff Abdullah sc->blkcnt = sc->bufsz / i; 124205051995SAriff Abdullah i = 0; 1243a580b31aSAriff Abdullah while (sc->blkcnt >> i) 124405051995SAriff Abdullah i++; 1245a580b31aSAriff Abdullah sc->blkcnt = 1 << (i - 1); 1246a580b31aSAriff Abdullah if (sc->blkcnt < ATI_IXP_DMA_CHSEGS_MIN) 1247a580b31aSAriff Abdullah sc->blkcnt = ATI_IXP_DMA_CHSEGS_MIN; 1248a580b31aSAriff Abdullah else if (sc->blkcnt > ATI_IXP_DMA_CHSEGS_MAX) 1249a580b31aSAriff Abdullah sc->blkcnt = ATI_IXP_DMA_CHSEGS_MAX; 1250a580b31aSAriff Abdullah 1251a580b31aSAriff Abdullah } else 1252a580b31aSAriff Abdullah sc->blkcnt = ATI_IXP_DMA_CHSEGS; 125305051995SAriff Abdullah 125405051995SAriff Abdullah /* 1255d5688b6aSAriff Abdullah * DMA tag for scatter-gather buffers and link pointers 1256d5688b6aSAriff Abdullah */ 12570b989078SAlexander Leidinger if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2, 12580b989078SAlexander Leidinger /*boundary*/0, 1259d5688b6aSAriff Abdullah /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 1260d5688b6aSAriff Abdullah /*highaddr*/BUS_SPACE_MAXADDR, 1261d5688b6aSAriff Abdullah /*filter*/NULL, /*filterarg*/NULL, 1262d5688b6aSAriff Abdullah /*maxsize*/sc->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff, 1263d5688b6aSAriff Abdullah /*flags*/0, /*lockfunc*/NULL, 1264d5688b6aSAriff Abdullah /*lockarg*/NULL, &sc->parent_dmat) != 0) { 1265d5688b6aSAriff Abdullah device_printf(dev, "unable to create dma tag\n"); 1266d5688b6aSAriff Abdullah goto bad; 1267d5688b6aSAriff Abdullah } 1268d5688b6aSAriff Abdullah 12690b989078SAlexander Leidinger if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2, 12700b989078SAlexander Leidinger /*boundary*/0, 1271d5688b6aSAriff Abdullah /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 1272d5688b6aSAriff Abdullah /*highaddr*/BUS_SPACE_MAXADDR, 1273d5688b6aSAriff Abdullah /*filter*/NULL, /*filterarg*/NULL, 12741042342aSAriff Abdullah /*maxsize*/ATI_IXP_DMA_CHSEGS_MAX * ATI_IXP_NCHANS * 1275d5688b6aSAriff Abdullah sizeof(struct atiixp_dma_op), 1276d5688b6aSAriff Abdullah /*nsegments*/1, /*maxsegz*/0x3ffff, 1277d5688b6aSAriff Abdullah /*flags*/0, /*lockfunc*/NULL, 1278d5688b6aSAriff Abdullah /*lockarg*/NULL, &sc->sgd_dmat) != 0) { 1279d5688b6aSAriff Abdullah device_printf(dev, "unable to create dma tag\n"); 1280d5688b6aSAriff Abdullah goto bad; 1281d5688b6aSAriff Abdullah } 1282d5688b6aSAriff Abdullah 1283d5688b6aSAriff Abdullah if (bus_dmamem_alloc(sc->sgd_dmat, (void **)&sc->sgd_table, 1284d5688b6aSAriff Abdullah BUS_DMA_NOWAIT, &sc->sgd_dmamap) == -1) 1285d5688b6aSAriff Abdullah goto bad; 1286d5688b6aSAriff Abdullah 1287d5688b6aSAriff Abdullah if (bus_dmamap_load(sc->sgd_dmat, sc->sgd_dmamap, sc->sgd_table, 12881042342aSAriff Abdullah ATI_IXP_DMA_CHSEGS_MAX * ATI_IXP_NCHANS * 12891042342aSAriff Abdullah sizeof(struct atiixp_dma_op), atiixp_dma_cb, sc, 0)) 1290d5688b6aSAriff Abdullah goto bad; 1291d5688b6aSAriff Abdullah 1292d5688b6aSAriff Abdullah 1293d5688b6aSAriff Abdullah atiixp_chip_pre_init(sc); 1294d5688b6aSAriff Abdullah 1295d5688b6aSAriff Abdullah sc->delayed_attach.ich_func = atiixp_chip_post_init; 1296d5688b6aSAriff Abdullah sc->delayed_attach.ich_arg = sc; 1297d5688b6aSAriff Abdullah if (cold == 0 || 1298d5688b6aSAriff Abdullah config_intrhook_establish(&sc->delayed_attach) != 0) { 1299d5688b6aSAriff Abdullah sc->delayed_attach.ich_func = NULL; 1300d5688b6aSAriff Abdullah atiixp_chip_post_init(sc); 1301d5688b6aSAriff Abdullah } 1302d5688b6aSAriff Abdullah 13039f52a325SAriff Abdullah return (0); 1304d5688b6aSAriff Abdullah 1305d5688b6aSAriff Abdullah bad: 1306f2a1d71aSAriff Abdullah atiixp_release_resource(sc); 13079f52a325SAriff Abdullah return (ENXIO); 1308d5688b6aSAriff Abdullah } 1309d5688b6aSAriff Abdullah 1310d5688b6aSAriff Abdullah static int 1311d5688b6aSAriff Abdullah atiixp_pci_detach(device_t dev) 1312d5688b6aSAriff Abdullah { 1313d5688b6aSAriff Abdullah int r; 1314d5688b6aSAriff Abdullah struct atiixp_info *sc; 1315d5688b6aSAriff Abdullah 1316f2a1d71aSAriff Abdullah sc = pcm_getdevinfo(dev); 1317f2a1d71aSAriff Abdullah if (sc != NULL) { 1318f2a1d71aSAriff Abdullah if (sc->codec != NULL) { 1319d5688b6aSAriff Abdullah r = pcm_unregister(dev); 1320d5688b6aSAriff Abdullah if (r) 13219f52a325SAriff Abdullah return (r); 1322f2a1d71aSAriff Abdullah } 1323f2a1d71aSAriff Abdullah sc->codec = NULL; 13249f52a325SAriff Abdullah if (sc->st != 0 && sc->sh != 0) 1325d5688b6aSAriff Abdullah atiixp_disable_interrupts(sc); 1326f2a1d71aSAriff Abdullah atiixp_release_resource(sc); 1327f2a1d71aSAriff Abdullah } 13289f52a325SAriff Abdullah return (0); 1329d5688b6aSAriff Abdullah } 1330d5688b6aSAriff Abdullah 133188a50509SAriff Abdullah static int 133288a50509SAriff Abdullah atiixp_pci_suspend(device_t dev) 133388a50509SAriff Abdullah { 133488a50509SAriff Abdullah struct atiixp_info *sc = pcm_getdevinfo(dev); 133588a50509SAriff Abdullah uint32_t value; 133688a50509SAriff Abdullah 133788a50509SAriff Abdullah /* quickly disable interrupts and save channels active state */ 133888a50509SAriff Abdullah atiixp_lock(sc); 133988a50509SAriff Abdullah atiixp_disable_interrupts(sc); 134088a50509SAriff Abdullah atiixp_unlock(sc); 134188a50509SAriff Abdullah 134288a50509SAriff Abdullah /* stop everything */ 13438a7c4d36SAriff Abdullah if (sc->pch.flags & ATI_IXP_CHN_RUNNING) { 134488a50509SAriff Abdullah atiixp_chan_trigger(NULL, &sc->pch, PCMTRIG_STOP); 13458a7c4d36SAriff Abdullah sc->pch.flags |= ATI_IXP_CHN_SUSPEND; 13468a7c4d36SAriff Abdullah } 13478a7c4d36SAriff Abdullah if (sc->rch.flags & ATI_IXP_CHN_RUNNING) { 134888a50509SAriff Abdullah atiixp_chan_trigger(NULL, &sc->rch, PCMTRIG_STOP); 13498a7c4d36SAriff Abdullah sc->rch.flags |= ATI_IXP_CHN_SUSPEND; 13508a7c4d36SAriff Abdullah } 135188a50509SAriff Abdullah 135288a50509SAriff Abdullah /* power down aclink and pci bus */ 135388a50509SAriff Abdullah atiixp_lock(sc); 135488a50509SAriff Abdullah value = atiixp_rd(sc, ATI_REG_CMD); 135588a50509SAriff Abdullah value |= ATI_REG_CMD_POWERDOWN | ATI_REG_CMD_AC_RESET; 135688a50509SAriff Abdullah atiixp_wr(sc, ATI_REG_CMD, ATI_REG_CMD_POWERDOWN); 135788a50509SAriff Abdullah atiixp_unlock(sc); 135888a50509SAriff Abdullah 13599f52a325SAriff Abdullah return (0); 136088a50509SAriff Abdullah } 136188a50509SAriff Abdullah 136288a50509SAriff Abdullah static int 136388a50509SAriff Abdullah atiixp_pci_resume(device_t dev) 136488a50509SAriff Abdullah { 136588a50509SAriff Abdullah struct atiixp_info *sc = pcm_getdevinfo(dev); 136688a50509SAriff Abdullah 136788a50509SAriff Abdullah atiixp_lock(sc); 136888a50509SAriff Abdullah /* reset / power up aclink */ 136988a50509SAriff Abdullah atiixp_reset_aclink(sc); 137088a50509SAriff Abdullah atiixp_unlock(sc); 137188a50509SAriff Abdullah 137288a50509SAriff Abdullah if (mixer_reinit(dev) == -1) { 137388a50509SAriff Abdullah device_printf(dev, "unable to reinitialize the mixer\n"); 13749f52a325SAriff Abdullah return (ENXIO); 137588a50509SAriff Abdullah } 137688a50509SAriff Abdullah 137788a50509SAriff Abdullah /* 137888a50509SAriff Abdullah * Resume channel activities. Reset channel format regardless 137988a50509SAriff Abdullah * of its previous state. 138088a50509SAriff Abdullah */ 1381a580b31aSAriff Abdullah if (sc->pch.channel != NULL) { 1382a580b31aSAriff Abdullah if (sc->pch.fmt != 0) 138388a50509SAriff Abdullah atiixp_chan_setformat(NULL, &sc->pch, sc->pch.fmt); 13848a7c4d36SAriff Abdullah if (sc->pch.flags & ATI_IXP_CHN_SUSPEND) { 13858a7c4d36SAriff Abdullah sc->pch.flags &= ~ATI_IXP_CHN_SUSPEND; 138688a50509SAriff Abdullah atiixp_chan_trigger(NULL, &sc->pch, PCMTRIG_START); 138788a50509SAriff Abdullah } 13888a7c4d36SAriff Abdullah } 1389a580b31aSAriff Abdullah if (sc->rch.channel != NULL) { 1390a580b31aSAriff Abdullah if (sc->rch.fmt != 0) 139188a50509SAriff Abdullah atiixp_chan_setformat(NULL, &sc->rch, sc->rch.fmt); 13928a7c4d36SAriff Abdullah if (sc->rch.flags & ATI_IXP_CHN_SUSPEND) { 13938a7c4d36SAriff Abdullah sc->rch.flags &= ~ATI_IXP_CHN_SUSPEND; 139488a50509SAriff Abdullah atiixp_chan_trigger(NULL, &sc->rch, PCMTRIG_START); 139588a50509SAriff Abdullah } 13968a7c4d36SAriff Abdullah } 139788a50509SAriff Abdullah 139888a50509SAriff Abdullah /* enable interrupts */ 139988a50509SAriff Abdullah atiixp_lock(sc); 1400a580b31aSAriff Abdullah if (sc->polling == 0) 140188a50509SAriff Abdullah atiixp_enable_interrupts(sc); 140288a50509SAriff Abdullah atiixp_unlock(sc); 140388a50509SAriff Abdullah 14049f52a325SAriff Abdullah return (0); 140588a50509SAriff Abdullah } 140688a50509SAriff Abdullah 1407d5688b6aSAriff Abdullah static device_method_t atiixp_methods[] = { 1408d5688b6aSAriff Abdullah DEVMETHOD(device_probe, atiixp_pci_probe), 1409d5688b6aSAriff Abdullah DEVMETHOD(device_attach, atiixp_pci_attach), 1410d5688b6aSAriff Abdullah DEVMETHOD(device_detach, atiixp_pci_detach), 141188a50509SAriff Abdullah DEVMETHOD(device_suspend, atiixp_pci_suspend), 141288a50509SAriff Abdullah DEVMETHOD(device_resume, atiixp_pci_resume), 1413d5688b6aSAriff Abdullah { 0, 0 } 1414d5688b6aSAriff Abdullah }; 1415d5688b6aSAriff Abdullah 1416d5688b6aSAriff Abdullah static driver_t atiixp_driver = { 1417d5688b6aSAriff Abdullah "pcm", 1418d5688b6aSAriff Abdullah atiixp_methods, 1419d5688b6aSAriff Abdullah PCM_SOFTC_SIZE, 1420d5688b6aSAriff Abdullah }; 1421d5688b6aSAriff Abdullah 1422d5688b6aSAriff Abdullah DRIVER_MODULE(snd_atiixp, pci, atiixp_driver, pcm_devclass, 0, 0); 1423d5688b6aSAriff Abdullah MODULE_DEPEND(snd_atiixp, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 1424d5688b6aSAriff Abdullah MODULE_VERSION(snd_atiixp, 1); 1425