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