maestro.c revision 82180
1/*-
2 * Copyright (c) 2000 Taku YAMAMOTO <taku@cent.saitama-u.ac.jp>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 *	$Id: maestro.c,v 1.12 2000/09/06 03:32:34 taku Exp $
27 */
28
29/*
30 * Credits:
31 *
32 * Part of this code (especially in many magic numbers) was heavily inspired
33 * by the Linux driver originally written by
34 * Alan Cox <alan.cox@linux.org>, modified heavily by
35 * Zach Brown <zab@zabbo.net>.
36 *
37 * busdma()-ize and buffer size reduction were suggested by
38 * Cameron Grant <gandalf@vilnya.demon.co.uk>.
39 * Also he showed me the way to use busdma() suite.
40 *
41 * Internal speaker problems on NEC VersaPro's and Dell Inspiron 7500
42 * were looked at by
43 * Munehiro Matsuda <haro@tk.kubota.co.jp>,
44 * who brought patches based on the Linux driver with some simplification.
45 */
46
47#include <dev/sound/pcm/sound.h>
48#include <dev/sound/pcm/ac97.h>
49#include <pci/pcireg.h>
50#include <pci/pcivar.h>
51
52#include <dev/sound/pci/maestro_reg.h>
53
54SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/maestro.c 82180 2001-08-23 11:30:52Z cg $");
55
56#define inline __inline
57
58/*
59 * PCI IDs of supported chips:
60 *
61 * MAESTRO-1	0x01001285
62 * MAESTRO-2	0x1968125d
63 * MAESTRO-2E	0x1978125d
64 */
65
66#define MAESTRO_1_PCI_ID	0x01001285
67#define MAESTRO_2_PCI_ID	0x1968125d
68#define MAESTRO_2E_PCI_ID	0x1978125d
69
70#define NEC_SUBID1	0x80581033	/* Taken from Linux driver */
71#define NEC_SUBID2	0x803c1033	/* NEC VersaProNX VA26D    */
72
73#ifndef AGG_MAXPLAYCH
74# define AGG_MAXPLAYCH	4
75#endif
76
77#define AGG_BUFSIZ	0x4000 /* 0x1000, but gets underflows */
78
79
80/* -----------------------------
81 * Data structures.
82 */
83struct agg_chinfo {
84	struct agg_info		*parent;
85	struct pcm_channel	*channel;
86	struct snd_dbuf		*buffer;
87	bus_addr_t		offset;
88	u_int32_t		blocksize;
89	u_int32_t		speed;
90	int			dir;
91	u_int			num;
92	u_int16_t		aputype;
93	u_int16_t		wcreg_tpl;
94};
95
96struct agg_info {
97	device_t		dev;
98	struct resource		*reg;
99	int			regid;
100
101	bus_space_tag_t		st;
102	bus_space_handle_t	sh;
103	bus_dma_tag_t		parent_dmat;
104
105	struct resource		*irq;
106	int			irqid;
107	void			*ih;
108
109	u_int8_t		*stat;
110	bus_addr_t		baseaddr;
111
112	struct ac97_info	*codec;
113	void			*lock;
114
115	u_int			playchns, active;
116	struct agg_chinfo	pch[AGG_MAXPLAYCH];
117	struct agg_chinfo	rch;
118};
119
120static inline void	 ringbus_setdest(struct agg_info*, int, int);
121
122static inline u_int16_t	 wp_rdreg(struct agg_info*, u_int16_t);
123static inline void	 wp_wrreg(struct agg_info*, u_int16_t, u_int16_t);
124static inline u_int16_t	 wp_rdapu(struct agg_info*, int, u_int16_t);
125static inline void	 wp_wrapu(struct agg_info*, int, u_int16_t, u_int16_t);
126static inline void	 wp_settimer(struct agg_info*, u_int);
127static inline void	 wp_starttimer(struct agg_info*);
128static inline void	 wp_stoptimer(struct agg_info*);
129
130static inline u_int16_t	 wc_rdreg(struct agg_info*, u_int16_t);
131static inline void	 wc_wrreg(struct agg_info*, u_int16_t, u_int16_t);
132static inline u_int16_t	 wc_rdchctl(struct agg_info*, int);
133static inline void	 wc_wrchctl(struct agg_info*, int, u_int16_t);
134
135static inline void	 agg_power(struct agg_info*, int);
136
137static void		 agg_init(struct agg_info*);
138
139static void		 aggch_start_dac(struct agg_chinfo*);
140static void		 aggch_stop_dac(struct agg_chinfo*);
141
142static inline void	 suppress_jitter(struct agg_chinfo*);
143
144static inline u_int	 calc_timer_freq(struct agg_chinfo*);
145static void		 set_timer(struct agg_info*);
146
147static void		 agg_intr(void *);
148static int		 agg_probe(device_t);
149static int		 agg_attach(device_t);
150static int		 agg_detach(device_t);
151static int		 agg_suspend(device_t);
152static int		 agg_resume(device_t);
153static int		 agg_shutdown(device_t);
154
155static void	*dma_malloc(struct agg_info*, u_int32_t, bus_addr_t*);
156static void	 dma_free(struct agg_info*, void *);
157
158/* -----------------------------
159 * Subsystems.
160 */
161
162/* Codec/Ringbus */
163
164/* -------------------------------------------------------------------- */
165
166static u_int32_t
167agg_ac97_init(kobj_t obj, void *sc)
168{
169	struct agg_info *ess = sc;
170
171	return (bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT) & CODEC_STAT_MASK)? 0 : 1;
172}
173
174static int
175agg_rdcodec(kobj_t obj, void *sc, int regno)
176{
177	struct agg_info *ess = sc;
178	unsigned t;
179
180	/* We have to wait for a SAFE time to write addr/data */
181	for (t = 0; t < 20; t++) {
182		if ((bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT)
183		    & CODEC_STAT_MASK) != CODEC_STAT_PROGLESS)
184			break;
185		DELAY(2);	/* 20.8us / 13 */
186	}
187	if (t == 20)
188		device_printf(ess->dev, "agg_rdcodec() PROGLESS timed out.\n");
189
190	bus_space_write_1(ess->st, ess->sh, PORT_CODEC_CMD,
191	    CODEC_CMD_READ | regno);
192	DELAY(21);	/* AC97 cycle = 20.8usec */
193
194	/* Wait for data retrieve */
195	for (t = 0; t < 20; t++) {
196		if ((bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT)
197		    & CODEC_STAT_MASK) == CODEC_STAT_RW_DONE)
198			break;
199		DELAY(2);	/* 20.8us / 13 */
200	}
201	if (t == 20)
202		/* Timed out, but perform dummy read. */
203		device_printf(ess->dev, "agg_rdcodec() RW_DONE timed out.\n");
204
205	return bus_space_read_2(ess->st, ess->sh, PORT_CODEC_REG);
206}
207
208static int
209agg_wrcodec(kobj_t obj, void *sc, int regno, u_int32_t data)
210{
211	unsigned t;
212	struct agg_info *ess = sc;
213
214	/* We have to wait for a SAFE time to write addr/data */
215	for (t = 0; t < 20; t++) {
216		if ((bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT)
217		    & CODEC_STAT_MASK) != CODEC_STAT_PROGLESS)
218			break;
219		DELAY(2);	/* 20.8us / 13 */
220	}
221	if (t == 20) {
222		/* Timed out. Abort writing. */
223		device_printf(ess->dev, "agg_wrcodec() PROGLESS timed out.\n");
224		return -1;
225	}
226
227	bus_space_write_2(ess->st, ess->sh, PORT_CODEC_REG, data);
228	bus_space_write_1(ess->st, ess->sh, PORT_CODEC_CMD,
229	    CODEC_CMD_WRITE | regno);
230
231	return 0;
232}
233
234static kobj_method_t agg_ac97_methods[] = {
235    	KOBJMETHOD(ac97_init,		agg_ac97_init),
236    	KOBJMETHOD(ac97_read,		agg_rdcodec),
237    	KOBJMETHOD(ac97_write,		agg_wrcodec),
238	{ 0, 0 }
239};
240AC97_DECLARE(agg_ac97);
241
242/* -------------------------------------------------------------------- */
243
244static inline void
245ringbus_setdest(struct agg_info *ess, int src, int dest)
246{
247	u_int32_t	data;
248
249	data = bus_space_read_4(ess->st, ess->sh, PORT_RINGBUS_CTRL);
250	data &= ~(0xfU << src);
251	data |= (0xfU & dest) << src;
252	bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, data);
253}
254
255/* Wave Processor */
256
257static inline u_int16_t
258wp_rdreg(struct agg_info *ess, u_int16_t reg)
259{
260	bus_space_write_2(ess->st, ess->sh, PORT_DSP_INDEX, reg);
261	return bus_space_read_2(ess->st, ess->sh, PORT_DSP_DATA);
262}
263
264static inline void
265wp_wrreg(struct agg_info *ess, u_int16_t reg, u_int16_t data)
266{
267	bus_space_write_2(ess->st, ess->sh, PORT_DSP_INDEX, reg);
268	bus_space_write_2(ess->st, ess->sh, PORT_DSP_DATA, data);
269}
270
271static inline void
272apu_setindex(struct agg_info *ess, u_int16_t reg)
273{
274	int t;
275
276	wp_wrreg(ess, WPREG_CRAM_PTR, reg);
277	/* Sometimes WP fails to set apu register index. */
278	for (t = 0; t < 1000; t++) {
279		if (bus_space_read_2(ess->st, ess->sh, PORT_DSP_DATA) == reg)
280			break;
281		bus_space_write_2(ess->st, ess->sh, PORT_DSP_DATA, reg);
282	}
283	if (t == 1000)
284		device_printf(ess->dev, "apu_setindex() timed out.\n");
285}
286
287static inline u_int16_t
288wp_rdapu(struct agg_info *ess, int ch, u_int16_t reg)
289{
290	u_int16_t ret;
291
292	apu_setindex(ess, ((unsigned)ch << 4) + reg);
293	ret = wp_rdreg(ess, WPREG_DATA_PORT);
294	return ret;
295}
296
297static inline void
298wp_wrapu(struct agg_info *ess, int ch, u_int16_t reg, u_int16_t data)
299{
300	int t;
301
302	apu_setindex(ess, ((unsigned)ch << 4) + reg);
303	wp_wrreg(ess, WPREG_DATA_PORT, data);
304	for (t = 0; t < 1000; t++) {
305		if (bus_space_read_2(ess->st, ess->sh, PORT_DSP_DATA) == data)
306			break;
307		bus_space_write_2(ess->st, ess->sh, PORT_DSP_DATA, data);
308	}
309	if (t == 1000)
310		device_printf(ess->dev, "wp_wrapu() timed out.\n");
311}
312
313static inline void
314wp_settimer(struct agg_info *ess, u_int freq)
315{
316	u_int clock = 48000 << 2;
317	u_int prescale = 0, divide = (freq != 0) ? (clock / freq) : ~0;
318
319	RANGE(divide, 4, 32 << 8);
320
321	for (; divide > 32 << 1; divide >>= 1)
322		prescale++;
323	divide = (divide + 1) >> 1;
324
325	for (; prescale < 7 && divide > 2 && !(divide & 1); divide >>= 1)
326		prescale++;
327
328	wp_wrreg(ess, WPREG_TIMER_ENABLE, 0);
329	wp_wrreg(ess, WPREG_TIMER_FREQ,
330	    (prescale << WP_TIMER_FREQ_PRESCALE_SHIFT) | (divide - 1));
331	wp_wrreg(ess, WPREG_TIMER_ENABLE, 1);
332}
333
334static inline void
335wp_starttimer(struct agg_info *ess)
336{
337	wp_wrreg(ess, WPREG_TIMER_START, 1);
338}
339
340static inline void
341wp_stoptimer(struct agg_info *ess)
342{
343	wp_wrreg(ess, WPREG_TIMER_START, 0);
344	bus_space_write_2(ess->st, ess->sh, PORT_INT_STAT, 1);
345}
346
347/* WaveCache */
348
349static inline u_int16_t
350wc_rdreg(struct agg_info *ess, u_int16_t reg)
351{
352	bus_space_write_2(ess->st, ess->sh, PORT_WAVCACHE_INDEX, reg);
353	return bus_space_read_2(ess->st, ess->sh, PORT_WAVCACHE_DATA);
354}
355
356static inline void
357wc_wrreg(struct agg_info *ess, u_int16_t reg, u_int16_t data)
358{
359	bus_space_write_2(ess->st, ess->sh, PORT_WAVCACHE_INDEX, reg);
360	bus_space_write_2(ess->st, ess->sh, PORT_WAVCACHE_DATA, data);
361}
362
363static inline u_int16_t
364wc_rdchctl(struct agg_info *ess, int ch)
365{
366	return wc_rdreg(ess, ch << 3);
367}
368
369static inline void
370wc_wrchctl(struct agg_info *ess, int ch, u_int16_t data)
371{
372	wc_wrreg(ess, ch << 3, data);
373}
374
375/* Power management */
376
377static inline void
378agg_power(struct agg_info *ess, int status)
379{
380	u_int8_t data;
381
382	data = pci_read_config(ess->dev, CONF_PM_PTR, 1);
383	if (pci_read_config(ess->dev, data, 1) == PPMI_CID)
384		pci_write_config(ess->dev, data + PM_CTRL, status, 1);
385}
386
387
388/* -----------------------------
389 * Controller.
390 */
391
392static inline void
393agg_initcodec(struct agg_info* ess)
394{
395	u_int16_t data;
396
397	if (bus_space_read_4(ess->st, ess->sh, PORT_RINGBUS_CTRL)
398	    & RINGBUS_CTRL_ACLINK_ENABLED) {
399		bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 0);
400		DELAY(104);	/* 20.8us * (4 + 1) */
401	}
402	/* XXX - 2nd codec should be looked at. */
403	bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL,
404	    RINGBUS_CTRL_AC97_SWRESET);
405	DELAY(2);
406	bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL,
407	    RINGBUS_CTRL_ACLINK_ENABLED);
408	DELAY(21);
409
410	agg_rdcodec(NULL, ess, 0);
411	if (bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT)
412	    & CODEC_STAT_MASK) {
413		bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 0);
414		DELAY(21);
415
416		/* Try cold reset. */
417		device_printf(ess->dev, "will perform cold reset.\n");
418		data = bus_space_read_2(ess->st, ess->sh, PORT_GPIO_DIR);
419		if (pci_read_config(ess->dev, 0x58, 2) & 1)
420			data |= 0x10;
421		data |= 0x009 &
422		    ~bus_space_read_2(ess->st, ess->sh, PORT_GPIO_DATA);
423		bus_space_write_2(ess->st, ess->sh, PORT_GPIO_MASK, 0xff6);
424		bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DIR,
425		    data | 0x009);
426		bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 0x000);
427		DELAY(2);
428		bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 0x001);
429		DELAY(1);
430		bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 0x009);
431		DELAY(500000);
432		bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DIR, data);
433		DELAY(84);	/* 20.8us * 4 */
434		bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL,
435		    RINGBUS_CTRL_ACLINK_ENABLED);
436		DELAY(21);
437	}
438}
439
440static void
441agg_init(struct agg_info* ess)
442{
443	u_int32_t data;
444
445	/* Setup PCI config registers. */
446
447	/* Disable all legacy emulations. */
448	data = pci_read_config(ess->dev, CONF_LEGACY, 2);
449	data |= LEGACY_DISABLED;
450	pci_write_config(ess->dev, CONF_LEGACY, data, 2);
451
452	/* Disconnect from CHI. (Makes Dell inspiron 7500 work?)
453	 * Enable posted write.
454	 * Prefer PCI timing rather than that of ISA.
455	 * Don't swap L/R. */
456	data = pci_read_config(ess->dev, CONF_MAESTRO, 4);
457	data |= MAESTRO_CHIBUS | MAESTRO_POSTEDWRITE | MAESTRO_DMA_PCITIMING;
458	data &= ~MAESTRO_SWAP_LR;
459	pci_write_config(ess->dev, CONF_MAESTRO, data, 4);
460
461	/* Reset direct sound. */
462	bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL,
463	    HOSTINT_CTRL_DSOUND_RESET);
464	DELAY(10000);	/* XXX - too long? */
465	bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 0);
466	DELAY(10000);
467
468	/* Enable direct sound interruption and hardware volume control. */
469	bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL,
470	    HOSTINT_CTRL_DSOUND_INT_ENABLED | HOSTINT_CTRL_HWVOL_ENABLED);
471
472	/* Setup Wave Processor. */
473
474	/* Enable WaveCache, set DMA base address. */
475	wp_wrreg(ess, WPREG_WAVE_ROMRAM,
476	    WP_WAVE_VIRTUAL_ENABLED | WP_WAVE_DRAM_ENABLED);
477	bus_space_write_2(ess->st, ess->sh, PORT_WAVCACHE_CTRL,
478	    WAVCACHE_ENABLED | WAVCACHE_WTSIZE_4MB);
479
480	for (data = WAVCACHE_PCMBAR; data < WAVCACHE_PCMBAR + 4; data++)
481		wc_wrreg(ess, data, ess->baseaddr >> WAVCACHE_BASEADDR_SHIFT);
482
483	/* Setup Codec/Ringbus. */
484	agg_initcodec(ess);
485	bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL,
486	    RINGBUS_CTRL_RINGBUS_ENABLED | RINGBUS_CTRL_ACLINK_ENABLED);
487
488	wp_wrreg(ess, WPREG_BASE, 0x8500);	/* Parallel I/O */
489	ringbus_setdest(ess, RINGBUS_SRC_ADC,
490	    RINGBUS_DEST_STEREO | RINGBUS_DEST_DSOUND_IN);
491	ringbus_setdest(ess, RINGBUS_SRC_DSOUND,
492	    RINGBUS_DEST_STEREO | RINGBUS_DEST_DAC);
493
494	/* Setup ASSP. Needed for Dell Inspiron 7500? */
495	bus_space_write_1(ess->st, ess->sh, PORT_ASSP_CTRL_B, 0x00);
496	bus_space_write_1(ess->st, ess->sh, PORT_ASSP_CTRL_A, 0x03);
497	bus_space_write_1(ess->st, ess->sh, PORT_ASSP_CTRL_C, 0x00);
498
499	/*
500	 * Setup GPIO.
501	 * There seems to be speciality with NEC systems.
502	 */
503	switch (pci_get_subvendor(ess->dev)
504	    | (pci_get_subdevice(ess->dev) << 16)) {
505	case NEC_SUBID1:
506	case NEC_SUBID2:
507		/* Matthew Braithwaite <matt@braithwaite.net> reported that
508		 * NEC Versa LX doesn't need GPIO operation. */
509		bus_space_write_2(ess->st, ess->sh, PORT_GPIO_MASK, 0x9ff);
510		bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DIR,
511		    bus_space_read_2(ess->st, ess->sh, PORT_GPIO_DIR) | 0x600);
512		bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 0x200);
513		break;
514	}
515}
516
517/* Channel controller. */
518
519static void
520aggch_start_dac(struct agg_chinfo *ch)
521{
522	u_int wpwa = APU_USE_SYSMEM | (ch->offset >> 9);
523	u_int size = AGG_BUFSIZ >> 1;
524	u_int speed = ch->speed;
525	u_int offset = ch->offset >> 1;
526	u_int cp = 0;
527	u_int16_t apuch = ch->num << 1;
528	u_int dv;
529	int pan = 0;
530
531	switch (ch->aputype) {
532	case APUTYPE_16BITSTEREO:
533		wpwa >>= 1;
534		size >>= 1;
535		offset >>= 1;
536		cp >>= 1;
537		/* FALLTHROUGH */
538	case APUTYPE_8BITSTEREO:
539		pan = 8;
540		apuch++;
541		break;
542	case APUTYPE_8BITLINEAR:
543		speed >>= 1;
544		break;
545	}
546
547	dv = (((speed % 48000) << 16) + 24000) / 48000
548	    + ((speed / 48000) << 16);
549
550	do {
551		wp_wrapu(ch->parent, apuch, APUREG_WAVESPACE, wpwa & 0xff00);
552		wp_wrapu(ch->parent, apuch, APUREG_CURPTR, offset + cp);
553		wp_wrapu(ch->parent, apuch, APUREG_ENDPTR, offset + size);
554		wp_wrapu(ch->parent, apuch, APUREG_LOOPLEN, size);
555		wp_wrapu(ch->parent, apuch, APUREG_AMPLITUDE, 0xe800);
556		wp_wrapu(ch->parent, apuch, APUREG_POSITION, 0x8f00
557		    | (RADIUS_CENTERCIRCLE << APU_RADIUS_SHIFT)
558		    | ((PAN_FRONT + pan) << APU_PAN_SHIFT));
559		wp_wrapu(ch->parent, apuch, APUREG_FREQ_LOBYTE, APU_plus6dB
560		    | ((dv & 0xff) << APU_FREQ_LOBYTE_SHIFT));
561		wp_wrapu(ch->parent, apuch, APUREG_FREQ_HIWORD, dv >> 8);
562
563		if (ch->aputype == APUTYPE_16BITSTEREO)
564			wpwa |= APU_STEREO >> 1;
565		pan = -pan;
566	} while (pan < 0 && apuch--);
567
568	wc_wrchctl(ch->parent, apuch, ch->wcreg_tpl);
569	wc_wrchctl(ch->parent, apuch + 1, ch->wcreg_tpl);
570
571	wp_wrapu(ch->parent, apuch, APUREG_APUTYPE,
572	    (ch->aputype << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf);
573	if (ch->wcreg_tpl & WAVCACHE_CHCTL_STEREO)
574		wp_wrapu(ch->parent, apuch + 1, APUREG_APUTYPE,
575		    (ch->aputype << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf);
576}
577
578static void
579aggch_stop_dac(struct agg_chinfo *ch)
580{
581	wp_wrapu(ch->parent, (ch->num << 1), APUREG_APUTYPE,
582	    APUTYPE_INACTIVE << APU_APUTYPE_SHIFT);
583	wp_wrapu(ch->parent, (ch->num << 1) + 1, APUREG_APUTYPE,
584	    APUTYPE_INACTIVE << APU_APUTYPE_SHIFT);
585}
586
587/*
588 * Stereo jitter suppressor.
589 * Sometimes playback pointers differ in stereo-paired channels.
590 * Calling this routine within intr fixes the problem.
591 */
592static inline void
593suppress_jitter(struct agg_chinfo *ch)
594{
595	if (ch->wcreg_tpl & WAVCACHE_CHCTL_STEREO) {
596		int cp, diff, halfsize = AGG_BUFSIZ >> 2;
597
598		if (ch->aputype == APUTYPE_16BITSTEREO)
599			halfsize >>= 1;
600		cp = wp_rdapu(ch->parent, (ch->num << 1), APUREG_CURPTR);
601		diff = wp_rdapu(ch->parent, (ch->num << 1) + 1, APUREG_CURPTR);
602		diff -= cp;
603		if (diff >> 1 && diff > -halfsize && diff < halfsize)
604			bus_space_write_2(ch->parent->st, ch->parent->sh,
605			    PORT_DSP_DATA, cp);
606	}
607}
608
609static inline u_int
610calc_timer_freq(struct agg_chinfo *ch)
611{
612	u_int	ss = 2;
613
614	if (ch->aputype == APUTYPE_16BITSTEREO)
615		ss <<= 1;
616	if (ch->aputype == APUTYPE_8BITLINEAR)
617		ss >>= 1;
618
619	return (ch->speed * ss) / ch->blocksize;
620}
621
622static void
623set_timer(struct agg_info *ess)
624{
625	int i;
626	u_int	freq = 0;
627
628	for (i = 0; i < ess->playchns; i++)
629		if ((ess->active & (1 << i)) &&
630		    (freq < calc_timer_freq(ess->pch + i)))
631			freq = calc_timer_freq(ess->pch + i);
632
633	wp_settimer(ess, freq);
634}
635
636
637/* -----------------------------
638 * Newpcm glue.
639 */
640
641static void *
642aggch_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
643{
644	struct agg_info *ess = devinfo;
645	struct agg_chinfo *ch;
646	bus_addr_t physaddr;
647	void *p;
648
649	ch = (dir == PCMDIR_PLAY)? ess->pch + ess->playchns : &ess->rch;
650
651	ch->parent = ess;
652	ch->channel = c;
653	ch->buffer = b;
654	ch->num = ess->playchns;
655	ch->dir = dir;
656
657	p = dma_malloc(ess, AGG_BUFSIZ, &physaddr);
658	if (p == NULL)
659		return NULL;
660	sndbuf_setup(b, p, AGG_BUFSIZ);
661
662	ch->offset = physaddr - ess->baseaddr;
663	if (physaddr < ess->baseaddr || ch->offset > WPWA_MAXADDR) {
664		device_printf(ess->dev,
665		    "offset %#x exceeds limit. ", ch->offset);
666		dma_free(ess, sndbuf_getbuf(b));
667		return NULL;
668	}
669
670	ch->wcreg_tpl = (physaddr - 16) & WAVCACHE_CHCTL_ADDRTAG_MASK;
671
672	if (dir == PCMDIR_PLAY) {
673		ess->playchns++;
674		if (bootverbose)
675			device_printf(ess->dev, "pch[%d].offset = %#x\n", ch->num, ch->offset);
676	} else if (bootverbose)
677		device_printf(ess->dev, "rch.offset = %#x\n", ch->offset);
678
679	return ch;
680}
681
682static int
683aggch_free(kobj_t obj, void *data)
684{
685	struct agg_chinfo *ch = data;
686	struct agg_info *ess = ch->parent;
687
688	/* free up buffer - called after channel stopped */
689	dma_free(ess, sndbuf_getbuf(ch->buffer));
690
691	/* return 0 if ok */
692	return 0;
693}
694
695static int
696aggch_setplayformat(kobj_t obj, void *data, u_int32_t format)
697{
698	struct agg_chinfo *ch = data;
699	u_int16_t wcreg_tpl;
700	u_int16_t aputype = APUTYPE_16BITLINEAR;
701
702	wcreg_tpl = ch->wcreg_tpl & WAVCACHE_CHCTL_ADDRTAG_MASK;
703
704	if (format & AFMT_STEREO) {
705		wcreg_tpl |= WAVCACHE_CHCTL_STEREO;
706		aputype += 1;
707	}
708	if (format & AFMT_U8 || format & AFMT_S8) {
709		aputype += 2;
710		if (format & AFMT_U8)
711			wcreg_tpl |= WAVCACHE_CHCTL_U8;
712	}
713	if (format & AFMT_BIGENDIAN || format & AFMT_U16_LE) {
714		format &= ~AFMT_BIGENDIAN & ~AFMT_U16_LE;
715		format |= AFMT_S16_LE;
716	}
717	ch->wcreg_tpl = wcreg_tpl;
718	ch->aputype = aputype;
719	return format;
720}
721
722static int
723aggch_setspeed(kobj_t obj, void *data, u_int32_t speed)
724{
725	struct agg_chinfo *ch = data;
726
727	ch->speed = speed;
728	return ch->speed;
729}
730
731static int
732aggch_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
733{
734	return ((struct agg_chinfo*)data)->blocksize = blocksize;
735}
736
737static int
738aggch_trigger(kobj_t obj, void *data, int go)
739{
740	struct agg_chinfo *ch = data;
741
742	switch (go) {
743	case PCMTRIG_EMLDMAWR:
744		return 0;
745	case PCMTRIG_START:
746		ch->parent->active |= (1 << ch->num);
747		if (ch->dir == PCMDIR_PLAY)
748			aggch_start_dac(ch);
749#if 0	/* XXX - RECORDING */
750		else
751			aggch_start_adc(ch);
752#endif
753		break;
754	case PCMTRIG_ABORT:
755	case PCMTRIG_STOP:
756		ch->parent->active &= ~(1 << ch->num);
757		if (ch->dir == PCMDIR_PLAY)
758			aggch_stop_dac(ch);
759#if 0	/* XXX - RECORDING */
760		else
761			aggch_stop_adc(ch);
762#endif
763		break;
764	}
765
766	if (ch->parent->active) {
767		set_timer(ch->parent);
768		wp_starttimer(ch->parent);
769	} else
770		wp_stoptimer(ch->parent);
771
772	return 0;
773}
774
775static int
776aggch_getplayptr(kobj_t obj, void *data)
777{
778	struct agg_chinfo *ch = data;
779	u_int cp;
780
781	cp = wp_rdapu(ch->parent, (ch->num << 1), APUREG_CURPTR);
782	if (ch->aputype == APUTYPE_16BITSTEREO)
783		cp = (0xffff << 2) & ((cp << 2) - ch->offset);
784	else
785		cp = (0xffff << 1) & ((cp << 1) - ch->offset);
786
787	return cp;
788}
789
790static struct pcmchan_caps *
791aggch_getcaps(kobj_t obj, void *data)
792{
793	static u_int32_t playfmt[] = {
794		AFMT_U8,
795		AFMT_STEREO | AFMT_U8,
796		AFMT_S8,
797		AFMT_STEREO | AFMT_S8,
798		AFMT_S16_LE,
799		AFMT_STEREO | AFMT_S16_LE,
800		0
801	};
802	static struct pcmchan_caps playcaps = {2000, 96000, playfmt, 0};
803
804	static u_int32_t recfmt[] = {
805		AFMT_S8,
806		AFMT_STEREO | AFMT_S8,
807		AFMT_S16_LE,
808		AFMT_STEREO | AFMT_S16_LE,
809		0
810	};
811	static struct pcmchan_caps reccaps = {4000, 48000, recfmt, 0};
812
813	return (((struct agg_chinfo*)data)->dir == PCMDIR_PLAY)?
814	    &playcaps : &reccaps;
815}
816
817static kobj_method_t aggch_methods[] = {
818    	KOBJMETHOD(channel_init,		aggch_init),
819    	KOBJMETHOD(channel_free,		aggch_free),
820    	KOBJMETHOD(channel_setformat,		aggch_setplayformat),
821    	KOBJMETHOD(channel_setspeed,		aggch_setspeed),
822    	KOBJMETHOD(channel_setblocksize,	aggch_setblocksize),
823    	KOBJMETHOD(channel_trigger,		aggch_trigger),
824    	KOBJMETHOD(channel_getptr,		aggch_getplayptr),
825    	KOBJMETHOD(channel_getcaps,		aggch_getcaps),
826	{ 0, 0 }
827};
828CHANNEL_DECLARE(aggch);
829
830/* -----------------------------
831 * Bus space.
832 */
833
834static void
835agg_intr(void *sc)
836{
837	struct agg_info* ess = sc;
838	u_int16_t status;
839	int i;
840
841	status = bus_space_read_1(ess->st, ess->sh, PORT_HOSTINT_STAT);
842	if (!status)
843		return;
844
845	/* Acknowledge all. */
846	bus_space_write_2(ess->st, ess->sh, PORT_INT_STAT, 1);
847	bus_space_write_1(ess->st, ess->sh, PORT_HOSTINT_STAT, 0xff);
848
849	if (status & HOSTINT_STAT_HWVOL) {
850		u_int event;
851
852		event = bus_space_read_1(ess->st, ess->sh, PORT_HWVOL_MASTER);
853		switch (event) {
854		case HWVOL_MUTE:
855			mixer_hwvol_mute(ess->dev);
856			break;
857		case HWVOL_UP:
858			mixer_hwvol_step(ess->dev, 1, 1);
859			break;
860		case HWVOL_DOWN:
861			mixer_hwvol_step(ess->dev, -1, -1);
862			break;
863		case HWVOL_NOP:
864			break;
865		default:
866			device_printf(ess->dev, "%s: unknown HWVOL event 0x%x\n",
867			    device_get_nameunit(ess->dev), event);
868		}
869		bus_space_write_1(ess->st, ess->sh, PORT_HWVOL_MASTER,
870		    HWVOL_NOP);
871	}
872
873	for (i = 0; i < ess->playchns; i++)
874		if (ess->active & (1 << i)) {
875			suppress_jitter(ess->pch + i);
876			chn_intr(ess->pch[i].channel);
877		}
878#if 0	/* XXX - RECORDING */
879	if (ess->active & (1 << i))
880		chn_intr(ess->rch.channel);
881#endif
882}
883
884static void
885setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
886{
887	bus_addr_t *phys = arg;
888
889	*phys = error? 0 : segs->ds_addr;
890
891	if (bootverbose) {
892		printf("setmap (%lx, %lx), nseg=%d, error=%d\n",
893		    (unsigned long)segs->ds_addr, (unsigned long)segs->ds_len,
894		    nseg, error);
895	}
896}
897
898static void *
899dma_malloc(struct agg_info *sc, u_int32_t sz, bus_addr_t *phys)
900{
901	void *buf;
902	bus_dmamap_t map;
903
904	if (bus_dmamem_alloc(sc->parent_dmat, &buf, BUS_DMA_NOWAIT, &map))
905		return NULL;
906	if (bus_dmamap_load(sc->parent_dmat, map, buf, sz, setmap, phys, 0)
907	    || !*phys) {
908		bus_dmamem_free(sc->parent_dmat, buf, map);
909		return NULL;
910	}
911	return buf;
912}
913
914static void
915dma_free(struct agg_info *sc, void *buf)
916{
917	bus_dmamem_free(sc->parent_dmat, buf, NULL);
918}
919
920static int
921agg_probe(device_t dev)
922{
923	char *s = NULL;
924
925	switch (pci_get_devid(dev)) {
926	case MAESTRO_1_PCI_ID:
927		s = "ESS Technology Maestro-1";
928		break;
929
930	case MAESTRO_2_PCI_ID:
931		s = "ESS Technology Maestro-2";
932		break;
933
934	case MAESTRO_2E_PCI_ID:
935		s = "ESS Technology Maestro-2E";
936		break;
937	}
938
939	if (s != NULL && pci_get_class(dev) == PCIC_MULTIMEDIA) {
940		device_set_desc(dev, s);
941		return 0;
942	}
943	return ENXIO;
944}
945
946static int
947agg_attach(device_t dev)
948{
949	struct agg_info	*ess = NULL;
950	u_int32_t	data;
951	int	mapped = 0;
952	int	regid = PCIR_MAPS;
953	struct resource	*reg = NULL;
954	struct ac97_info	*codec = NULL;
955	int	irqid = 0;
956	struct resource	*irq = NULL;
957	void	*ih = NULL;
958	char	status[SND_STATUSLEN];
959
960	if ((ess = malloc(sizeof *ess, M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) {
961		device_printf(dev, "cannot allocate softc\n");
962		return ENXIO;
963	}
964	ess->dev = dev;
965
966	if (bus_dma_tag_create(/*parent*/NULL,
967	    /*alignment*/1 << WAVCACHE_BASEADDR_SHIFT,
968	    /*boundary*/WPWA_MAXADDR + 1,
969	    /*lowaddr*/MAESTRO_MAXADDR, /*highaddr*/BUS_SPACE_MAXADDR,
970	    /*filter*/NULL, /*filterarg*/NULL,
971	    /*maxsize*/AGG_BUFSIZ * 2, /*nsegments*/1, /*maxsegz*/0x3ffff,
972	    /*flags*/0, &ess->parent_dmat) != 0) {
973		device_printf(dev, "unable to create dma tag\n");
974		goto bad;
975	}
976
977	ess->stat = dma_malloc(ess, AGG_BUFSIZ, &ess->baseaddr);
978	if (ess->stat == NULL) {
979		device_printf(dev, "cannot allocate status buffer\n");
980		goto bad;
981	}
982	if (bootverbose)
983		device_printf(dev, "Maestro DMA base: %#x\n", ess->baseaddr);
984
985	agg_power(ess, PPMI_D0);
986	DELAY(100000);
987
988	data = pci_read_config(dev, PCIR_COMMAND, 2);
989	data |= (PCIM_CMD_PORTEN|PCIM_CMD_BUSMASTEREN);
990	pci_write_config(dev, PCIR_COMMAND, data, 2);
991	data = pci_read_config(dev, PCIR_COMMAND, 2);
992
993	if (data & PCIM_CMD_PORTEN) {
994		reg = bus_alloc_resource(dev, SYS_RES_IOPORT, &regid,
995		    0, BUS_SPACE_UNRESTRICTED, 256, RF_ACTIVE);
996		if (reg != NULL) {
997			ess->reg = reg;
998			ess->regid = regid;
999			ess->st = rman_get_bustag(reg);
1000			ess->sh = rman_get_bushandle(reg);
1001			mapped++;
1002		}
1003	}
1004	if (mapped == 0) {
1005		device_printf(dev, "unable to map register space\n");
1006		goto bad;
1007	}
1008
1009	agg_init(ess);
1010	if (agg_rdcodec(NULL, ess, 0) == 0x80) {
1011		device_printf(dev, "PT101 codec detected!\n");
1012		goto bad;
1013	}
1014	codec = AC97_CREATE(dev, ess, agg_ac97);
1015	if (codec == NULL)
1016		goto bad;
1017	if (mixer_init(dev, ac97_getmixerclass(), codec) == -1)
1018		goto bad;
1019	ess->codec = codec;
1020
1021	irq = bus_alloc_resource(dev, SYS_RES_IRQ, &irqid,
1022	    0, BUS_SPACE_UNRESTRICTED, 1, RF_ACTIVE | RF_SHAREABLE);
1023	if (irq == NULL || snd_setup_intr(dev, irq, 0, agg_intr, ess, &ih)) {
1024		device_printf(dev, "unable to map interrupt\n");
1025		goto bad;
1026	}
1027	ess->irq = irq;
1028	ess->irqid = irqid;
1029	ess->ih = ih;
1030
1031	snprintf(status, SND_STATUSLEN, "at I/O port 0x%lx irq %ld",
1032	    rman_get_start(reg), rman_get_start(irq));
1033
1034	if (pcm_register(dev, ess, AGG_MAXPLAYCH, 1))
1035		goto bad;
1036
1037	mixer_hwvol_init(dev);
1038	for (data = 0; data < AGG_MAXPLAYCH; data++)
1039		pcm_addchan(dev, PCMDIR_PLAY, &aggch_class, ess);
1040#if 0	/* XXX - RECORDING */
1041	pcm_addchan(dev, PCMDIR_REC, &aggrch_class, ess);
1042#endif
1043	pcm_setstatus(dev, status);
1044
1045	return 0;
1046
1047 bad:
1048	if (codec != NULL)
1049		ac97_destroy(codec);
1050	if (ih != NULL)
1051		bus_teardown_intr(dev, irq, ih);
1052	if (irq != NULL)
1053		bus_release_resource(dev, SYS_RES_IRQ, irqid, irq);
1054	if (reg != NULL)
1055		bus_release_resource(dev, SYS_RES_IOPORT, regid, reg);
1056	if (ess != NULL) {
1057		agg_power(ess, PPMI_D3);
1058		if (ess->stat != NULL)
1059			dma_free(ess, ess->stat);
1060		if (ess->parent_dmat != NULL)
1061			bus_dma_tag_destroy(ess->parent_dmat);
1062		free(ess, M_DEVBUF);
1063	}
1064
1065	return ENXIO;
1066}
1067
1068static int
1069agg_detach(device_t dev)
1070{
1071	struct agg_info	*ess = pcm_getdevinfo(dev);
1072	int r;
1073
1074	r = pcm_unregister(dev);
1075	if (r)
1076		return r;
1077
1078	ess = pcm_getdevinfo(dev);
1079	dma_free(ess, ess->stat);
1080
1081	/* Power down everything except clock and vref. */
1082	agg_wrcodec(NULL, ess, AC97_REG_POWER, 0xd700);
1083	DELAY(20);
1084	bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 0);
1085	agg_power(ess, PPMI_D3);
1086
1087	bus_teardown_intr(dev, ess->irq, ess->ih);
1088	bus_release_resource(dev, SYS_RES_IRQ, ess->irqid, ess->irq);
1089	bus_release_resource(dev, SYS_RES_IOPORT, ess->regid, ess->reg);
1090	bus_dma_tag_destroy(ess->parent_dmat);
1091	free(ess, M_DEVBUF);
1092	return 0;
1093}
1094
1095static int
1096agg_suspend(device_t dev)
1097{
1098	struct agg_info *ess = pcm_getdevinfo(dev);
1099	int i, x;
1100
1101	x = spltty();
1102	wp_stoptimer(ess);
1103	bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 0);
1104
1105	for (i = 0; i < ess->playchns; i++)
1106		aggch_stop_dac(ess->pch + i);
1107
1108#if 0	/* XXX - RECORDING */
1109	aggch_stop_adc(&ess->rch);
1110#endif
1111	splx(x);
1112	/* Power down everything except clock. */
1113	agg_wrcodec(NULL, ess, AC97_REG_POWER, 0xdf00);
1114	DELAY(20);
1115	bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 0);
1116	DELAY(1);
1117	agg_power(ess, PPMI_D3);
1118
1119	return 0;
1120}
1121
1122static int
1123agg_resume(device_t dev)
1124{
1125	int i, x;
1126	struct agg_info *ess = pcm_getdevinfo(dev);
1127
1128	agg_power(ess, PPMI_D0);
1129	DELAY(100000);
1130	agg_init(ess);
1131	if (mixer_reinit(dev)) {
1132		device_printf(dev, "unable to reinitialize the mixer\n");
1133		return ENXIO;
1134	}
1135
1136	x = spltty();
1137	for (i = 0; i < ess->playchns; i++)
1138		if (ess->active & (1 << i))
1139			aggch_start_dac(ess->pch + i);
1140#if 0	/* XXX - RECORDING */
1141	if (ess->active & (1 << i))
1142		aggch_start_adc(&ess->rch);
1143#endif
1144	if (ess->active) {
1145		set_timer(ess);
1146		wp_starttimer(ess);
1147	}
1148	splx(x);
1149	return 0;
1150}
1151
1152static int
1153agg_shutdown(device_t dev)
1154{
1155	struct agg_info *ess = pcm_getdevinfo(dev);
1156	int i;
1157
1158	wp_stoptimer(ess);
1159	bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 0);
1160
1161	for (i = 0; i < ess->playchns; i++)
1162		aggch_stop_dac(ess->pch + i);
1163
1164#if 0	/* XXX - RECORDING */
1165	aggch_stop_adc(&ess->rch);
1166#endif
1167	return 0;
1168}
1169
1170
1171static device_method_t agg_methods[] = {
1172    DEVMETHOD(device_probe,	agg_probe),
1173    DEVMETHOD(device_attach,	agg_attach),
1174    DEVMETHOD(device_detach,	agg_detach),
1175    DEVMETHOD(device_suspend,	agg_suspend),
1176    DEVMETHOD(device_resume,	agg_resume),
1177    DEVMETHOD(device_shutdown,	agg_shutdown),
1178
1179    { 0, 0 }
1180};
1181
1182static driver_t agg_driver = {
1183    "pcm",
1184    agg_methods,
1185    PCM_SOFTC_SIZE,
1186};
1187
1188DRIVER_MODULE(snd_maestro, pci, agg_driver, pcm_devclass, 0, 0);
1189MODULE_DEPEND(snd_maestro, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER);
1190MODULE_VERSION(snd_maestro, 1);
1191