Annotation of sys/dev/pci/auixp.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: auixp.c,v 1.10 2007/05/26 00:36:03 krw Exp $ */
2: /* $NetBSD: auixp.c,v 1.9 2005/06/27 21:13:09 thorpej Exp $ */
3:
4: /*
5: * Copyright (c) 2004, 2005 Reinoud Zandijk <reinoud@netbsd.org>
6: * All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. The name of the author may not be used to endorse or promote products
14: * derived from this software without specific prior written permission.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed by the NetBSD
18: * Foundation, Inc. and its contributors.
19: * 4. Neither the name of The NetBSD Foundation nor the names of its
20: * contributors may be used to endorse or promote products derived
21: * from this software without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28: * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30: * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: */
35: /*
36: * Audio driver for ATI IXP-{150,200,...} audio driver hardware.
37: *
38: * Recording and playback has been tested OK on various sample rates and
39: * encodings.
40: *
41: * Known problems and issues :
42: * - SPDIF is untested and needs some work still (LED stays off)
43: * - 32 bit audio playback failed last time i tried but that might an AC'97
44: * codec support problem.
45: * - 32 bit recording works but can't try out playing: see above.
46: * - no suspend/resume support yet.
47: * - multiple codecs are `supported' but not tested; the implemetation needs
48: * some cleaning up.
49: */
50:
51: /*#define DEBUG_AUIXP*/
52:
53: #include <sys/types.h>
54: #include <sys/errno.h>
55: #include <sys/param.h>
56: #include <sys/systm.h>
57: #include <sys/malloc.h>
58: #include <sys/device.h>
59: #include <sys/conf.h>
60: #include <sys/exec.h>
61: #include <sys/selinfo.h>
62: #include <sys/audioio.h>
63: #include <sys/queue.h>
64:
65: #include <machine/bus.h>
66: #include <machine/intr.h>
67:
68: #include <dev/pci/pcidevs.h>
69: #include <dev/pci/pcivar.h>
70:
71: #include <dev/audio_if.h>
72: #include <dev/mulaw.h>
73: #include <dev/auconv.h>
74: #include <dev/ic/ac97.h>
75:
76: #include <dev/pci/auixpreg.h>
77: #include <dev/pci/auixpvar.h>
78:
79: /* codec detection constant indicating the interrupt flags */
80: #define ALL_CODECS_NOT_READY \
81: (ATI_REG_ISR_CODEC0_NOT_READY | ATI_REG_ISR_CODEC1_NOT_READY |\
82: ATI_REG_ISR_CODEC2_NOT_READY)
83: #define CODEC_CHECK_BITS (ALL_CODECS_NOT_READY|ATI_REG_ISR_NEW_FRAME)
84:
85: /* why isn't this base address register not in the headerfile? */
86: #define PCI_CBIO 0x10
87:
88: /* macro's used */
89: #define KERNADDR(p) ((void *)((p)->addr))
90: #define DMAADDR(p) ((p)->map->dm_segs[0].ds_addr)
91:
92: const struct pci_matchid auixp_pci_devices[] = {
93: { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_IXP_AUDIO_200 },
94: { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_IXP_AUDIO_300 },
95: { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_IXP_AUDIO_400 },
96: };
97:
98: struct cfdriver auixp_cd = {
99: NULL, "auixp", DV_DULL
100: };
101:
102: int auixp_match( struct device *, void *, void *);
103: void auixp_attach(struct device *, struct device *, void *);
104: int auixp_detach(struct device *, int);
105:
106: struct cfattach auixp_ca = {
107: sizeof(struct auixp_softc), auixp_match, auixp_attach
108: };
109:
110: int auixp_open(void *v, int flags);
111: void auixp_close(void *v);
112: int auixp_query_encoding(void *, struct audio_encoding *);
113: int auixp_set_params(void *, int, int, struct audio_params *,
114: struct audio_params *);
115: int auixp_commit_settings(void *);
116: int auixp_round_blocksize(void *, int);
117: int auixp_trigger_output(void *, void *, void *, int,
118: void (*)(void *), void *, struct audio_params *);
119: int auixp_trigger_input(void *, void *, void *, int,
120: void (*)(void *), void *, struct audio_params *);
121: int auixp_halt_output(void *);
122: int auixp_halt_input(void *);
123: int auixp_set_port(void *, mixer_ctrl_t *);
124: int auixp_get_port(void *, mixer_ctrl_t *);
125: int auixp_query_devinfo(void *, mixer_devinfo_t *);
126: void * auixp_malloc(void *, int, size_t, int, int);
127: void auixp_free(void *, void *, int);
128: int auixp_getdev(void *, struct audio_device *);
129: size_t auixp_round_buffersize(void *, int, size_t);
130: int auixp_get_props(void *);
131: int auixp_intr(void *);
132: int auixp_allocmem(struct auixp_softc *, size_t, size_t,
133: struct auixp_dma *);
134: int auixp_freemem(struct auixp_softc *, struct auixp_dma *);
135: paddr_t auixp_mappage(void *, void *, off_t, int);
136:
137:
138: /* power management (do we support that already?) */
139: int auixp_power(struct auixp_softc *, int);
140: #if 0
141: void auixp_powerhook(int, void *);
142: int auixp_suspend(struct auixp_softc *);
143: int auixp_resume(struct auixp_softc *);
144: #endif
145:
146:
147: /* Supporting subroutines */
148: int auixp_init(struct auixp_softc *);
149: void auixp_autodetect_codecs(struct auixp_softc *);
150: void auixp_post_config(void *);
151:
152: void auixp_reset_aclink(struct auixp_softc *);
153: int auixp_attach_codec(void *, struct ac97_codec_if *);
154: int auixp_read_codec(void *, u_int8_t, u_int16_t *);
155: int auixp_write_codec(void *, u_int8_t, u_int16_t);
156: int auixp_wait_for_codecs(struct auixp_softc *, const char *);
157: void auixp_reset_codec(void *);
158: enum ac97_host_flags auixp_flags_codec(void *);
159:
160: void auixp_enable_dma(struct auixp_softc *, struct auixp_dma *);
161: void auixp_disable_dma(struct auixp_softc *, struct auixp_dma *);
162: void auixp_enable_interrupts(struct auixp_softc *);
163: void auixp_disable_interrupts(struct auixp_softc *);
164:
165: void auixp_link_daisychain(struct auixp_softc *,
166: struct auixp_dma *, struct auixp_dma *, int, int);
167: int auixp_allocate_dma_chain(struct auixp_softc *, struct auixp_dma **);
168: void auixp_program_dma_chain(struct auixp_softc *, struct auixp_dma *);
169: void auixp_dma_update(struct auixp_softc *, struct auixp_dma *);
170: void auixp_update_busbusy(struct auixp_softc *);
171:
172: #ifdef DEBUG_AUIXP
173: #define DPRINTF(x) printf x;
174: #else
175: #define DPRINTF(x)
176: #endif
177:
178: struct audio_hw_if auixp_hw_if = {
179: auixp_open,
180: auixp_close,
181: NULL, /* drain */
182: auixp_query_encoding,
183: auixp_set_params,
184: auixp_round_blocksize,
185: auixp_commit_settings,
186: NULL, /* init_output */
187: NULL, /* init_input */
188: NULL, /* start_output */
189: NULL, /* start_input */
190: auixp_halt_output,
191: auixp_halt_input,
192: NULL, /* speaker_ctl */
193: auixp_getdev,
194: NULL, /* getfd */
195: auixp_set_port,
196: auixp_get_port,
197: auixp_query_devinfo,
198: auixp_malloc,
199: auixp_free,
200: auixp_round_buffersize,
201: auixp_mappage,
202: auixp_get_props,
203: auixp_trigger_output,
204: auixp_trigger_input
205: };
206:
207: int
208: auixp_open(void *v, int flags)
209: {
210:
211: return 0;
212: }
213:
214: void
215: auixp_close(void *v)
216: {
217: }
218:
219: int
220: auixp_query_encoding(void *hdl, struct audio_encoding *aep)
221: {
222: switch (aep->index) {
223: case 0:
224: strlcpy(aep->name, AudioEulinear, sizeof aep->name);
225: aep->encoding = AUDIO_ENCODING_ULINEAR;
226: aep->precision = 8;
227: aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
228: return (0);
229: case 1:
230: strlcpy(aep->name, AudioEmulaw, sizeof aep->name);
231: aep->encoding = AUDIO_ENCODING_ULAW;
232: aep->precision = 8;
233: aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
234: return (0);
235: case 2:
236: strlcpy(aep->name, AudioEalaw, sizeof aep->name);
237: aep->encoding = AUDIO_ENCODING_ALAW;
238: aep->precision = 8;
239: aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
240: return (0);
241: case 3:
242: strlcpy(aep->name, AudioEslinear, sizeof aep->name);
243: aep->encoding = AUDIO_ENCODING_SLINEAR;
244: aep->precision = 8;
245: aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
246: return (0);
247: case 4:
248: strlcpy(aep->name, AudioEslinear_le, sizeof aep->name);
249: aep->encoding = AUDIO_ENCODING_SLINEAR_LE;
250: aep->precision = 16;
251: aep->flags = 0;
252: return (0);
253: case 5:
254: strlcpy(aep->name, AudioEulinear_le, sizeof aep->name);
255: aep->encoding = AUDIO_ENCODING_ULINEAR_LE;
256: aep->precision = 16;
257: aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
258: return (0);
259: case 6:
260: strlcpy(aep->name, AudioEslinear_be, sizeof aep->name);
261: aep->encoding = AUDIO_ENCODING_SLINEAR_BE;
262: aep->precision = 16;
263: aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
264: return (0);
265: case 7:
266: strlcpy(aep->name, AudioEulinear_be, sizeof aep->name);
267: aep->encoding = AUDIO_ENCODING_ULINEAR_BE;
268: aep->precision = 16;
269: aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
270: return (0);
271: default:
272: return (EINVAL);
273: }
274: }
275:
276:
277: /* commit setting and program ATI IXP chip */
278: int
279: auixp_commit_settings(void *hdl)
280: {
281: struct auixp_codec *co;
282: struct auixp_softc *sc;
283: bus_space_tag_t iot;
284: bus_space_handle_t ioh;
285: struct audio_params *params;
286: u_int32_t value;
287:
288: /* XXX would it be better to stop interrupts first? XXX */
289: co = (struct auixp_codec *) hdl;
290: sc = co->sc;
291: iot = sc->sc_iot;
292: ioh = sc->sc_ioh;
293:
294: /* process input settings */
295: params = &sc->sc_play_params;
296:
297: /* set input interleaving (precision) */
298: value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
299: value &= ~ATI_REG_CMD_INTERLEAVE_IN;
300: if (params->precision <= 16)
301: value |= ATI_REG_CMD_INTERLEAVE_IN;
302: bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
303:
304: /* process output settings */
305: params = &sc->sc_play_params;
306:
307: value = bus_space_read_4(iot, ioh, ATI_REG_OUT_DMA_SLOT);
308: value &= ~ATI_REG_OUT_DMA_SLOT_MASK;
309:
310: /* TODO SPDIF case for 8 channels */
311: switch (params->channels) {
312: case 6:
313: value |= ATI_REG_OUT_DMA_SLOT_BIT(7) |
314: ATI_REG_OUT_DMA_SLOT_BIT(8);
315: /* FALLTHROUGH */
316: case 4:
317: value |= ATI_REG_OUT_DMA_SLOT_BIT(6) |
318: ATI_REG_OUT_DMA_SLOT_BIT(9);
319: /* FALLTHROUGH */
320: default:
321: value |= ATI_REG_OUT_DMA_SLOT_BIT(3) |
322: ATI_REG_OUT_DMA_SLOT_BIT(4);
323: break;
324: }
325: /* set output threshold */
326: value |= 0x04 << ATI_REG_OUT_DMA_THRESHOLD_SHIFT;
327: bus_space_write_4(iot, ioh, ATI_REG_OUT_DMA_SLOT, value);
328:
329: /* set output interleaving (precision) */
330: value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
331: value &= ~ATI_REG_CMD_INTERLEAVE_OUT;
332: if (params->precision <= 16)
333: value |= ATI_REG_CMD_INTERLEAVE_OUT;
334: bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
335:
336: /* enable 6 channel reordering */
337: value = bus_space_read_4(iot, ioh, ATI_REG_6CH_REORDER);
338: value &= ~ATI_REG_6CH_REORDER_EN;
339: if (params->channels == 6)
340: value |= ATI_REG_6CH_REORDER_EN;
341: bus_space_write_4(iot, ioh, ATI_REG_6CH_REORDER, value);
342:
343: if (sc->has_spdif) {
344: /* set SPDIF (if present) */
345: value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
346: value &= ~ATI_REG_CMD_SPDF_CONFIG_MASK;
347: value |= ATI_REG_CMD_SPDF_CONFIG_34; /* NetBSD AC'97 default */
348:
349: /* XXX this is probably not necessary unless splitted XXX */
350: value &= ~ATI_REG_CMD_INTERLEAVE_SPDF;
351: if (params->precision <= 16)
352: value |= ATI_REG_CMD_INTERLEAVE_SPDF;
353: bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
354: }
355:
356: return 0;
357: }
358:
359:
360: /* set audio properties in desired setting */
361: int
362: auixp_set_params(void *hdl, int setmode, int usemode,
363: struct audio_params *play, struct audio_params *rec)
364: {
365: struct auixp_codec *co;
366: struct auixp_softc *sc;
367: int error;
368:
369: co = (struct auixp_codec *) hdl;
370: sc = co->sc;
371: if (setmode & AUMODE_PLAY) {
372: play->factor = 1;
373: play->sw_code = NULL;
374: switch(play->encoding) {
375: case AUDIO_ENCODING_ULAW:
376: switch (play->channels) {
377: case 1:
378: play->factor = 4;
379: play->sw_code = mulaw_to_slinear16_mts;
380: break;
381: case 2:
382: play->factor = 2;
383: play->sw_code = mulaw_to_slinear16;
384: break;
385: default:
386: return (EINVAL);
387: }
388: break;
389: case AUDIO_ENCODING_SLINEAR_LE:
390: switch (play->precision) {
391: case 8:
392: switch (play->channels) {
393: case 1:
394: play->factor = 4;
395: play->sw_code = linear8_to_linear16_mts;
396: break;
397: case 2:
398: play->factor = 2;
399: play->sw_code = linear8_to_linear16;
400: break;
401: default:
402: return (EINVAL);
403: }
404: break;
405: case 16:
406: switch (play->channels) {
407: case 1:
408: play->factor = 2;
409: play->sw_code = noswap_bytes_mts;
410: break;
411: case 2:
412: break;
413: default:
414: return (EINVAL);
415: }
416: break;
417: default:
418: return (EINVAL);
419: }
420: break;
421: case AUDIO_ENCODING_ULINEAR_LE:
422: switch (play->precision) {
423: case 8:
424: switch (play->channels) {
425: case 1:
426: play->factor = 4;
427: play->sw_code = ulinear8_to_linear16_mts;
428: break;
429: case 2:
430: play->factor = 2;
431: play->sw_code = ulinear8_to_linear16;
432: break;
433: default:
434: return (EINVAL);
435: }
436: break;
437: case 16:
438: switch (play->channels) {
439: case 1:
440: play->factor = 2;
441: play->sw_code = change_sign16_mts;
442: break;
443: case 2:
444: play->sw_code = change_sign16;
445: break;
446: default:
447: return (EINVAL);
448: }
449: break;
450: default:
451: return (EINVAL);
452: }
453: break;
454: case AUDIO_ENCODING_ALAW:
455: switch (play->channels) {
456: case 1:
457: play->factor = 4;
458: play->sw_code = alaw_to_slinear16_mts;
459: break;
460: case 2:
461: play->factor = 2;
462: play->sw_code = alaw_to_slinear16;
463: break;
464: default:
465: return (EINVAL);
466: }
467: break;
468: case AUDIO_ENCODING_SLINEAR_BE:
469: switch (play->precision) {
470: case 8:
471: switch (play->channels) {
472: case 1:
473: play->factor = 4;
474: play->sw_code = linear8_to_linear16_mts;
475: break;
476: case 2:
477: play->factor = 2;
478: play->sw_code = linear8_to_linear16;
479: break;
480: default:
481: return (EINVAL);
482: }
483: break;
484: case 16:
485: switch (play->channels) {
486: case 1:
487: play->factor = 2;
488: play->sw_code = swap_bytes_mts;
489: break;
490: case 2:
491: play->sw_code = swap_bytes;
492: break;
493: default:
494: return (EINVAL);
495: }
496: break;
497: default:
498: return (EINVAL);
499: }
500: break;
501: case AUDIO_ENCODING_ULINEAR_BE:
502: switch (play->precision) {
503: case 8:
504: switch (play->channels) {
505: case 1:
506: play->factor = 4;
507: play->sw_code = ulinear8_to_linear16_mts;
508: break;
509: case 2:
510: play->factor = 2;
511: play->sw_code = ulinear8_to_linear16;
512: break;
513: default:
514: return (EINVAL);
515: }
516: break;
517: case 16:
518: switch (play->channels) {
519: case 1:
520: play->factor = 2;
521: play->sw_code = change_sign16_swap_bytes_mts;
522: break;
523: case 2:
524: play->sw_code = change_sign16_swap_bytes;
525: break;
526: default:
527: return (EINVAL);
528: }
529: break;
530: default:
531: return (EINVAL);
532: }
533: break;
534: default:
535: return (EINVAL);
536: }
537:
538: error = ac97_set_rate(co->codec_if, play, AUMODE_PLAY);
539: if (error)
540: return (error);
541: }
542:
543: if (setmode & AUMODE_RECORD) {
544: rec->factor = 1;
545: rec->sw_code = 0;
546: switch(rec->encoding) {
547: case AUDIO_ENCODING_ULAW:
548: rec->sw_code = ulinear8_to_mulaw;
549: break;
550: case AUDIO_ENCODING_SLINEAR_LE:
551: if (rec->precision == 8)
552: rec->sw_code = change_sign8;
553: break;
554: case AUDIO_ENCODING_ULINEAR_LE:
555: if (rec->precision == 16)
556: rec->sw_code = change_sign16;
557: break;
558: case AUDIO_ENCODING_ALAW:
559: rec->sw_code = ulinear8_to_alaw;
560: break;
561: case AUDIO_ENCODING_SLINEAR_BE:
562: if (rec->precision == 16)
563: rec->sw_code = swap_bytes;
564: else
565: rec->sw_code = change_sign8;
566: break;
567: case AUDIO_ENCODING_ULINEAR_BE:
568: if (rec->precision == 16)
569: rec->sw_code = swap_bytes_change_sign16;
570: break;
571: default:
572: return (EINVAL);
573: }
574:
575: error = ac97_set_rate(co->codec_if, rec, AUMODE_RECORD);
576: if (error)
577: return (error);
578: }
579:
580: return (0);
581: }
582:
583:
584: /* called to translate a requested blocksize to a hw-possible one */
585: int
586: auixp_round_blocksize(void *v, int blk)
587: {
588:
589: blk = (blk + 0x1f) & ~0x1f;
590: /* Be conservative; align to 32 bytes and maximise it to 64 kb */
591: if (blk > 0x10000)
592: blk = 0x10000;
593:
594: return blk;
595: }
596:
597:
598: /*
599: * allocate dma capable memory and record its information for later retrieval
600: * when we program the dma chain itself. The trigger routines passes on the
601: * kernel virtual address we return here as a reference to the mapping.
602: */
603: void *
604: auixp_malloc(void *hdl, int direction, size_t size, int pool, int flags)
605: {
606: struct auixp_codec *co;
607: struct auixp_softc *sc;
608: struct auixp_dma *dma;
609: int error;
610:
611: co = (struct auixp_codec *) hdl;
612: sc = co->sc;
613: /* get us a auixp_dma structure */
614: dma = malloc(sizeof(*dma), pool, flags);
615: if (!dma)
616: return NULL;
617:
618: /* get us a dma buffer itself */
619: error = auixp_allocmem(sc, size, 16, dma);
620: if (error) {
621: free(dma, pool);
622: printf("%s: auixp_malloc: not enough memory\n",
623: sc->sc_dev.dv_xname);
624: return NULL;
625: }
626: SLIST_INSERT_HEAD(&sc->sc_dma_list, dma, dma_chain);
627:
628: DPRINTF(("auixp_malloc: returning kern %p, hw 0x%08x for %d bytes "
629: "in %d segs\n", KERNADDR(dma), (u_int32_t) DMAADDR(dma), dma->size,
630: dma->nsegs)
631: );
632:
633: return KERNADDR(dma);
634: }
635:
636: /*
637: * free and release dma capable memory we allocated before and remove its
638: * recording
639: */
640: void
641: auixp_free(void *hdl, void *addr, int pool)
642: {
643: struct auixp_codec *co;
644: struct auixp_softc *sc;
645: struct auixp_dma *dma;
646:
647: co = (struct auixp_codec *) hdl;
648: sc = co->sc;
649: SLIST_FOREACH(dma, &sc->sc_dma_list, dma_chain) {
650: if (KERNADDR(dma) == addr) {
651: SLIST_REMOVE(&sc->sc_dma_list, dma, auixp_dma,
652: dma_chain);
653: auixp_freemem(sc, dma);
654: free(dma, pool);
655: return;
656: }
657: }
658: }
659:
660: int
661: auixp_getdev(void *v, struct audio_device *adp)
662: {
663: struct auixp_softc *sc = v;
664: *adp = sc->sc_audev;
665: return 0;
666: }
667:
668: /* pass request to AC'97 codec code */
669: int
670: auixp_set_port(void *hdl, mixer_ctrl_t *mc)
671: {
672: struct auixp_codec *co;
673:
674: co = (struct auixp_codec *) hdl;
675: return co->codec_if->vtbl->mixer_set_port(co->codec_if, mc);
676: }
677:
678:
679: /* pass request to AC'97 codec code */
680: int
681: auixp_get_port(void *hdl, mixer_ctrl_t *mc)
682: {
683: struct auixp_codec *co;
684:
685: co = (struct auixp_codec *) hdl;
686: return co->codec_if->vtbl->mixer_get_port(co->codec_if, mc);
687: }
688:
689: /* pass request to AC'97 codec code */
690: int
691: auixp_query_devinfo(void *hdl, mixer_devinfo_t *di)
692: {
693: struct auixp_codec *co;
694:
695: co = (struct auixp_codec *) hdl;
696: return co->codec_if->vtbl->query_devinfo(co->codec_if, di);
697: }
698:
699:
700: size_t
701: auixp_round_buffersize(void *hdl, int direction, size_t bufsize)
702: {
703:
704: /* XXX force maximum? i.e. 256 kb? */
705: return bufsize;
706: }
707:
708:
709: int
710: auixp_get_props(void *hdl)
711: {
712:
713: return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX;
714: }
715:
716:
717: /*
718: * A dma descriptor has dma->nsegs segments defined in dma->segs set up when
719: * we claimed the memory.
720: *
721: * Due to our demand for one contiguous DMA area, we only have one segment. A
722: * c_dma structure is about 3 kb for the 256 entries we maximally program
723: * -arbitrary limit AFAIK- so all is most likely to be in one segment/page
724: * anyway.
725: *
726: * XXX ought to implement fragmented dma area XXX
727: *
728: * Note that _v variables depict kernel virtual addresses, _p variables depict
729: * physical addresses.
730: */
731: void
732: auixp_link_daisychain(struct auixp_softc *sc,
733: struct auixp_dma *c_dma, struct auixp_dma *s_dma,
734: int blksize, int blocks)
735: {
736: atiixp_dma_desc_t *caddr_v, *next_caddr_v;
737: u_int32_t caddr_p, next_caddr_p, saddr_p;
738: int i;
739:
740: /* just make sure we are not changing when its running */
741: auixp_disable_dma(sc, c_dma);
742:
743: /* setup dma chain start addresses */
744: caddr_v = KERNADDR(c_dma);
745: caddr_p = DMAADDR(c_dma);
746: saddr_p = DMAADDR(s_dma);
747:
748: /* program the requested number of blocks */
749: for (i = 0; i < blocks; i++) {
750: /* clear the block just in case */
751: bzero(caddr_v, sizeof(atiixp_dma_desc_t));
752:
753: /* round robin the chain dma addresses for its successor */
754: next_caddr_v = caddr_v + 1;
755: next_caddr_p = caddr_p + sizeof(atiixp_dma_desc_t);
756:
757: if (i == blocks-1) {
758: next_caddr_v = KERNADDR(c_dma);
759: next_caddr_p = DMAADDR(c_dma);
760: }
761:
762: /* fill in the hardware dma chain descriptor in little-endian */
763: caddr_v->addr = htole32(saddr_p);
764: caddr_v->status = htole16(0);
765: caddr_v->size = htole16((blksize >> 2)); /* in dwords (!!!) */
766: caddr_v->next = htole32(next_caddr_p);
767:
768: /* advance slot */
769: saddr_p += blksize; /* XXX assuming contiguous XXX */
770: caddr_v = next_caddr_v;
771: caddr_p = next_caddr_p;
772: }
773: }
774:
775:
776: int
777: auixp_allocate_dma_chain(struct auixp_softc *sc, struct auixp_dma **dmap)
778: {
779: struct auixp_dma *dma;
780: int error;
781:
782: /* allocate keeper of dma area */
783: *dmap = NULL;
784: dma = malloc(sizeof(*dma), M_DEVBUF, M_NOWAIT);
785: if (!dma)
786: return ENOMEM;
787: bzero(dma, sizeof(*dma));
788:
789: /* allocate for daisychain of IXP hardware-dma descriptors */
790: error = auixp_allocmem(sc, DMA_DESC_CHAIN * sizeof(atiixp_dma_desc_t),
791: 16, dma);
792: if (error) {
793: printf("%s: can't malloc dma descriptor chain\n",
794: sc->sc_dev.dv_xname);
795: free(dma, M_DEVBUF);
796: return ENOMEM;
797: }
798:
799: /* return info and initialise structure */
800: dma->intr = NULL;
801: dma->intrarg = NULL;
802:
803: *dmap = dma;
804: return 0;
805: }
806:
807:
808: /* program dma chain in its link address descriptor */
809: void
810: auixp_program_dma_chain(struct auixp_softc *sc, struct auixp_dma *dma)
811: {
812: bus_space_tag_t iot;
813: bus_space_handle_t ioh;
814: u_int32_t value;
815:
816: iot = sc->sc_iot;
817: ioh = sc->sc_ioh;
818: /* get hardware start address of DMA chain and set valid-flag in it */
819: /* XXX always at start? XXX */
820: value = DMAADDR(dma);
821: value = value | ATI_REG_LINKPTR_EN;
822:
823: /* reset linkpointer */
824: bus_space_write_4(iot, ioh, dma->linkptr, 0);
825:
826: /* reset this DMA engine */
827: auixp_disable_dma(sc, dma);
828: auixp_enable_dma(sc, dma);
829:
830: /* program new DMA linkpointer */
831: bus_space_write_4(iot, ioh, dma->linkptr, value);
832: }
833:
834:
835: /* called from interrupt code to signal end of one dma-slot */
836: void
837: auixp_dma_update(struct auixp_softc *sc, struct auixp_dma *dma)
838: {
839:
840: /* be very paranoid */
841: if (!dma)
842: panic("auixp: update: dma = NULL");
843: if (!dma->intr)
844: panic("auixp: update: dma->intr = NULL");
845:
846: /* request more input from upper layer */
847: (*dma->intr)(dma->intrarg);
848: }
849:
850:
851: /*
852: * The magic `busbusy' bit that needs to be set when dma is active; allowing
853: * busmastering?
854: */
855: void
856: auixp_update_busbusy(struct auixp_softc *sc)
857: {
858: bus_space_tag_t iot;
859: bus_space_handle_t ioh;
860: u_int32_t value;
861: int running;
862:
863: iot = sc->sc_iot;
864: ioh = sc->sc_ioh;
865: /* set bus-busy flag when either recording or playing is performed */
866: value = bus_space_read_4(iot, ioh, ATI_REG_IER);
867: value &= ~ATI_REG_IER_SET_BUS_BUSY;
868:
869: running = ((sc->sc_output_dma->running) || (sc->sc_input_dma->running));
870: if (running)
871: value |= ATI_REG_IER_SET_BUS_BUSY;
872:
873: bus_space_write_4(iot, ioh, ATI_REG_IER, value);
874:
875: }
876:
877:
878: /*
879: * Called from upper audio layer to request playing audio, only called once;
880: * audio is refilled by calling the intr() function when space is available
881: * again.
882: */
883: /* XXX almost literally a copy of trigger-input; could be factorised XXX */
884: int
885: auixp_trigger_output(void *hdl, void *start, void *end, int blksize,
886: void (*intr)(void *), void *intrarg, struct audio_params *param)
887: {
888: struct auixp_codec *co;
889: struct auixp_softc *sc;
890: struct auixp_dma *chain_dma;
891: struct auixp_dma *sound_dma;
892: u_int32_t blocks;
893:
894: co = (struct auixp_codec *) hdl;
895: sc = co->sc;
896: chain_dma = sc->sc_output_dma;
897: /* add functions to call back */
898: chain_dma->intr = intr;
899: chain_dma->intrarg = intrarg;
900:
901: /*
902: * Program output DMA chain with blocks from [start...end] with
903: * blksize fragments.
904: *
905: * NOTE, we can assume its in one block since we asked for it to be in
906: * one contiguous blob; XXX change this? XXX
907: */
908: blocks = (size_t) (((caddr_t) end) - ((caddr_t) start)) / blksize;
909:
910: /* lookup `start' address in our list of DMA area's */
911: SLIST_FOREACH(sound_dma, &sc->sc_dma_list, dma_chain) {
912: if (KERNADDR(sound_dma) == start)
913: break;
914: }
915:
916: /* not ours ? then bail out */
917: if (!sound_dma) {
918: printf("%s: auixp_trigger_output: bad sound addr %p\n",
919: sc->sc_dev.dv_xname, start);
920: return EINVAL;
921: }
922:
923: /* link round-robin daisychain and program hardware */
924: auixp_link_daisychain(sc, chain_dma, sound_dma, blksize, blocks);
925: auixp_program_dma_chain(sc, chain_dma);
926:
927: /* mark we are now able to run now */
928: chain_dma->running = 1;
929:
930: /* update bus-flags; XXX programs more flags XXX */
931: auixp_update_busbusy(sc);
932:
933: /* callbacks happen in interrupt routine */
934: return 0;
935: }
936:
937:
938: /* halt output of audio, just disable its dma and update bus state */
939: int
940: auixp_halt_output(void *hdl)
941: {
942: struct auixp_codec *co;
943: struct auixp_softc *sc;
944: struct auixp_dma *dma;
945:
946: co = (struct auixp_codec *) hdl;
947: sc = co->sc;
948: dma = sc->sc_output_dma;
949: auixp_disable_dma(sc, dma);
950:
951: dma->running = 0;
952: auixp_update_busbusy(sc);
953:
954: return 0;
955: }
956:
957:
958: /* XXX almost literally a copy of trigger-output; could be factorised XXX */
959: int
960: auixp_trigger_input(void *hdl, void *start, void *end, int blksize,
961: void (*intr)(void *), void *intrarg, struct audio_params *param)
962: {
963: struct auixp_codec *co;
964: struct auixp_softc *sc;
965: struct auixp_dma *chain_dma;
966: struct auixp_dma *sound_dma;
967: u_int32_t blocks;
968:
969: co = (struct auixp_codec *) hdl;
970: sc = co->sc;
971: chain_dma = sc->sc_input_dma;
972: /* add functions to call back */
973: chain_dma->intr = intr;
974: chain_dma->intrarg = intrarg;
975:
976: /*
977: * Program output DMA chain with blocks from [start...end] with
978: * blksize fragments.
979: *
980: * NOTE, we can assume its in one block since we asked for it to be in
981: * one contiguous blob; XXX change this? XXX
982: */
983: blocks = (size_t) (((caddr_t) end) - ((caddr_t) start)) / blksize;
984:
985: /* lookup `start' address in our list of DMA area's */
986: SLIST_FOREACH(sound_dma, &sc->sc_dma_list, dma_chain) {
987: if (KERNADDR(sound_dma) == start)
988: break;
989: }
990:
991: /* not ours ? then bail out */
992: if (!sound_dma) {
993: printf("%s: auixp_trigger_input: bad sound addr %p\n",
994: sc->sc_dev.dv_xname, start);
995: return EINVAL;
996: }
997:
998: /* link round-robin daisychain and program hardware */
999: auixp_link_daisychain(sc, chain_dma, sound_dma, blksize, blocks);
1000: auixp_program_dma_chain(sc, chain_dma);
1001:
1002: /* mark we are now able to run now */
1003: chain_dma->running = 1;
1004:
1005: /* update bus-flags; XXX programs more flags XXX */
1006: auixp_update_busbusy(sc);
1007:
1008: /* callbacks happen in interrupt routine */
1009: return 0;
1010: }
1011:
1012:
1013: /* halt sampling audio, just disable its dma and update bus state */
1014: int
1015: auixp_halt_input(void *hdl)
1016: {
1017: struct auixp_codec *co;
1018: struct auixp_softc *sc;
1019: struct auixp_dma *dma;
1020:
1021: co = (struct auixp_codec *) hdl;
1022: sc = co->sc;
1023: dma = sc->sc_input_dma;
1024: auixp_disable_dma(sc, dma);
1025:
1026: dma->running = 0;
1027: auixp_update_busbusy(sc);
1028:
1029: return 0;
1030: }
1031:
1032:
1033: /*
1034: * IXP audio interrupt handler
1035: *
1036: * note that we return the number of bits handled; the return value is not
1037: * documented but I saw it implemented in other drivers. Probably returning a
1038: * value > 0 means "I've dealt with it"
1039: *
1040: */
1041: int
1042: auixp_intr(void *softc)
1043: {
1044: struct auixp_softc *sc;
1045: bus_space_tag_t iot;
1046: bus_space_handle_t ioh;
1047: u_int32_t status, enable, detected_codecs;
1048: int ret;
1049:
1050: sc = softc;
1051: iot = sc->sc_iot;
1052: ioh = sc->sc_ioh;
1053: ret = 0;
1054: /* get status from the interrupt status register */
1055: status = bus_space_read_4(iot, ioh, ATI_REG_ISR);
1056:
1057: if (status == 0)
1058: return 0;
1059:
1060: DPRINTF(("%s: (status = %x)\n", sc->sc_dev.dv_xname, status));
1061:
1062: /* check DMA UPDATE flags for input & output */
1063: if (status & ATI_REG_ISR_IN_STATUS) {
1064: ret++; DPRINTF(("IN_STATUS\n"));
1065: auixp_dma_update(sc, sc->sc_input_dma);
1066: }
1067: if (status & ATI_REG_ISR_OUT_STATUS) {
1068: ret++; DPRINTF(("OUT_STATUS\n"));
1069: auixp_dma_update(sc, sc->sc_output_dma);
1070: }
1071:
1072: /* XXX XRUN flags not used/needed yet; should i implement it? XXX */
1073: /* acknowledge the interrupts nevertheless */
1074: if (status & ATI_REG_ISR_IN_XRUN) {
1075: ret++; DPRINTF(("IN_XRUN\n"));
1076: /* auixp_dma_xrun(sc, sc->sc_input_dma); */
1077: }
1078: if (status & ATI_REG_ISR_OUT_XRUN) {
1079: ret++; DPRINTF(("OUT_XRUN\n"));
1080: /* auixp_dma_xrun(sc, sc->sc_output_dma); */
1081: }
1082:
1083: /* check if we are looking for codec detection */
1084: if (status & CODEC_CHECK_BITS) {
1085: ret++;
1086: /* mark missing codecs as not ready */
1087: detected_codecs = status & CODEC_CHECK_BITS;
1088: sc->sc_codec_not_ready_bits |= detected_codecs;
1089:
1090: /* disable detected interrupt sources */
1091: enable = bus_space_read_4(iot, ioh, ATI_REG_IER);
1092: enable &= ~detected_codecs;
1093: bus_space_write_4(iot, ioh, ATI_REG_IER, enable);
1094: }
1095:
1096: /* acknowledge interrupt sources */
1097: bus_space_write_4(iot, ioh, ATI_REG_ISR, status);
1098:
1099: return ret;
1100: }
1101:
1102:
1103: /* allocate memory for dma purposes; on failure of any of the steps, roll back */
1104: int
1105: auixp_allocmem(struct auixp_softc *sc, size_t size,
1106: size_t align, struct auixp_dma *dma)
1107: {
1108: int error;
1109:
1110: /* remember size */
1111: dma->size = size;
1112:
1113: /* allocate DMA safe memory but in just one segment for now :( */
1114: error = bus_dmamem_alloc(sc->sc_dmat, dma->size, align, 0,
1115: dma->segs, sizeof(dma->segs) / sizeof(dma->segs[0]), &dma->nsegs,
1116: BUS_DMA_NOWAIT);
1117: if (error)
1118: return error;
1119:
1120: /*
1121: * map allocated memory into kernel virtual address space and keep it
1122: * coherent with the CPU.
1123: */
1124: error = bus_dmamem_map(sc->sc_dmat, dma->segs, dma->nsegs, dma->size,
1125: &dma->addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
1126: if (error)
1127: goto free;
1128:
1129: /* allocate associated dma handle and initialize it. */
1130: error = bus_dmamap_create(sc->sc_dmat, dma->size, 1, dma->size, 0,
1131: BUS_DMA_NOWAIT, &dma->map);
1132: if (error)
1133: goto unmap;
1134:
1135: /*
1136: * load the dma handle with mappings for a dma transfer; all pages
1137: * need to be wired.
1138: */
1139: error = bus_dmamap_load(sc->sc_dmat, dma->map, dma->addr, dma->size, NULL,
1140: BUS_DMA_NOWAIT);
1141: if (error)
1142: goto destroy;
1143:
1144: return 0;
1145:
1146: destroy:
1147: bus_dmamap_destroy(sc->sc_dmat, dma->map);
1148: unmap:
1149: bus_dmamem_unmap(sc->sc_dmat, dma->addr, dma->size);
1150: free:
1151: bus_dmamem_free(sc->sc_dmat, dma->segs, dma->nsegs);
1152:
1153: return error;
1154: }
1155:
1156:
1157: /* undo dma mapping and release memory allocated */
1158: int
1159: auixp_freemem(struct auixp_softc *sc, struct auixp_dma *p)
1160: {
1161:
1162: bus_dmamap_unload(sc->sc_dmat, p->map);
1163: bus_dmamap_destroy(sc->sc_dmat, p->map);
1164: bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size);
1165: bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs);
1166:
1167: return 0;
1168: }
1169:
1170:
1171: /* memory map dma memory */
1172: paddr_t
1173: auixp_mappage(void *hdl, void *mem, off_t off, int prot)
1174: {
1175: struct auixp_codec *co;
1176: struct auixp_softc *sc;
1177: struct auixp_dma *p;
1178:
1179: co = (struct auixp_codec *) hdl;
1180: sc = co->sc;
1181: /* for sanity */
1182: if (off < 0)
1183: return -1;
1184:
1185: /* look up allocated DMA area */
1186: SLIST_FOREACH(p, &sc->sc_dma_list, dma_chain) {
1187: if (KERNADDR(p) == mem)
1188: break;
1189: }
1190:
1191: /* have we found it ? */
1192: if (!p)
1193: return -1;
1194:
1195: /* return mmap'd region */
1196: return bus_dmamem_mmap(sc->sc_dmat, p->segs, p->nsegs,
1197: off, prot, BUS_DMA_WAITOK);
1198: }
1199:
1200: int
1201: auixp_match(struct device *dev, void *match, void *aux)
1202: {
1203: return (pci_matchbyid((struct pci_attach_args *)aux, auixp_pci_devices,
1204: sizeof(auixp_pci_devices)/sizeof(auixp_pci_devices[0])));
1205: }
1206:
1207: void
1208: auixp_attach(struct device *parent, struct device *self, void *aux)
1209: {
1210: struct auixp_softc *sc;
1211: struct pci_attach_args *pa;
1212: pcitag_t tag;
1213: pci_chipset_tag_t pc;
1214: pci_intr_handle_t ih;
1215: const char *intrstr;
1216: int len;
1217:
1218: sc = (struct auixp_softc *)self;
1219: pa = (struct pci_attach_args *)aux;
1220: tag = pa->pa_tag;
1221: pc = pa->pa_pc;
1222:
1223: /* map memory; its not sized -> what is the size? max PCI slot size? */
1224: if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_MEM, 0,
1225: &sc->sc_iot, &sc->sc_ioh, &sc->sc_iob, &sc->sc_ios, 0)) {
1226: printf(": can't map memory space\n");
1227: return;
1228: }
1229:
1230: /* Initialize softc */
1231: sc->sc_tag = tag;
1232: sc->sc_pct = pc;
1233: sc->sc_dmat = pa->pa_dmat;
1234: SLIST_INIT(&sc->sc_dma_list);
1235:
1236: /* get us the auixp_dma structures */
1237: auixp_allocate_dma_chain(sc, &sc->sc_output_dma);
1238: auixp_allocate_dma_chain(sc, &sc->sc_input_dma);
1239:
1240: /* when that fails we are dead in the water */
1241: if (!sc->sc_output_dma || !sc->sc_input_dma)
1242: return;
1243:
1244: /* fill in the missing details about the dma channels. */
1245:
1246: /* for output */
1247: sc->sc_output_dma->linkptr = ATI_REG_OUT_DMA_LINKPTR;
1248: sc->sc_output_dma->dma_enable_bit = ATI_REG_CMD_OUT_DMA_EN |
1249: ATI_REG_CMD_SEND_EN;
1250: /* have spdif? then this too! XXX not seeing LED yet! XXX */
1251: if (sc->has_spdif)
1252: sc->sc_output_dma->dma_enable_bit |= ATI_REG_CMD_SPDF_OUT_EN;
1253:
1254: /* and for input */
1255: sc->sc_input_dma->linkptr = ATI_REG_IN_DMA_LINKPTR;
1256: sc->sc_input_dma->dma_enable_bit = ATI_REG_CMD_IN_DMA_EN |
1257: ATI_REG_CMD_RECEIVE_EN;
1258:
1259: #if 0
1260: /* could preliminary program DMA chain */
1261: auixp_program_dma_chain(sc, sc->sc_output_dma);
1262: auixp_program_dma_chain(sc, sc->sc_input_dma);
1263: #endif
1264:
1265: if (pci_intr_map(pa, &ih)) {
1266: printf(": can't map interrupt\n");
1267: return;
1268: }
1269: intrstr = pci_intr_string(pc, ih);
1270: sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, auixp_intr, sc,
1271: sc->sc_dev.dv_xname);
1272: if (sc->sc_ih == NULL) {
1273: printf(": can't establish interrupt");
1274: if (intrstr != NULL)
1275: printf(" at %s", intrstr);
1276: printf("\n");
1277: return;
1278: }
1279: printf(": %s\n", intrstr);
1280:
1281: strlcpy(sc->sc_audev.name, "ATI IXP AC97", sizeof sc->sc_audev.name);
1282: snprintf(sc->sc_audev.version, sizeof sc->sc_audev.version, "0x%02x",
1283: PCI_REVISION(pa->pa_class));
1284: strlcpy(sc->sc_audev.config, sc->sc_dev.dv_xname,
1285: sizeof sc->sc_audev.config);
1286:
1287: /* power up chip */
1288: auixp_power(sc, PCI_PMCSR_STATE_D0);
1289:
1290: /* init chip */
1291: if (auixp_init(sc) == -1) {
1292: printf("%s: auixp_attach: unable to initialize the card\n",
1293: sc->sc_dev.dv_xname);
1294: return;
1295: }
1296:
1297: /* XXX set up power hooks; not implemented yet XXX */
1298:
1299: len = 1; /* shut up gcc */
1300: #ifdef notyet
1301: /* create suspend save area */
1302: len = sizeof(u_int16_t) * (ESA_REV_B_CODE_MEMORY_LENGTH
1303: + ESA_REV_B_DATA_MEMORY_LENGTH + 1);
1304: sc->savemem = (u_int16_t *)malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO);
1305: if (sc->savemem == NULL) {
1306: printf("%s: unable to allocate suspend buffer\n",
1307: sc->sc_dev.dv_xname);
1308: return;
1309: }
1310:
1311: sc->powerhook = powerhook_establish(auixp_powerhook, sc);
1312: if (sc->powerhook == NULL)
1313: printf("%s: WARNING: unable to establish powerhook\n",
1314: sc->sc_dev.dv_xname);
1315:
1316: #endif
1317:
1318: /*
1319: * delay further configuration of codecs and audio after interrupts
1320: * are enabled.
1321: */
1322: mountroothook_establish(auixp_post_config, self);
1323: }
1324:
1325: /* called from autoconfigure system when interrupts are enabled */
1326: void
1327: auixp_post_config(void *self)
1328: {
1329: struct auixp_softc *sc;
1330: struct auixp_codec *codec;
1331: int codec_nr;
1332:
1333: sc = (struct auixp_softc *)self;
1334: /* detect the AC97 codecs */
1335: auixp_autodetect_codecs(sc);
1336:
1337: #if notyet
1338: /* copy formats and invalidate entries not suitable for codec0 */
1339: sc->has_4ch = AC97_IS_4CH(codec->codec_if);
1340: sc->has_6ch = AC97_IS_6CH(codec->codec_if);
1341: sc->is_fixed = AC97_IS_FIXED_RATE(codec->codec_if);
1342: sc->has_spdif = AC97_HAS_SPDIF(codec->codec_if);
1343: #endif
1344:
1345: /* attach audio devices for all detected codecs */
1346: for (codec_nr = 0; codec_nr < ATI_IXP_CODECS; codec_nr++) {
1347: codec = &sc->sc_codec[codec_nr];
1348: if (codec->present)
1349: audio_attach_mi(&auixp_hw_if, codec, &sc->sc_dev);
1350: }
1351:
1352: /* done! now enable all interrupts we can service */
1353: auixp_enable_interrupts(sc);
1354: }
1355:
1356: void
1357: auixp_enable_interrupts(struct auixp_softc *sc)
1358: {
1359: bus_space_tag_t iot;
1360: bus_space_handle_t ioh;
1361: u_int32_t value;
1362:
1363: iot = sc->sc_iot;
1364: ioh = sc->sc_ioh;
1365: /* clear all pending */
1366: bus_space_write_4(iot, ioh, ATI_REG_ISR, 0xffffffff);
1367:
1368: /* enable all relevant interrupt sources we can handle */
1369: value = bus_space_read_4(iot, ioh, ATI_REG_IER);
1370:
1371: value |= ATI_REG_IER_IO_STATUS_EN;
1372: #ifdef notyet
1373: value |= ATI_REG_IER_IN_XRUN_EN;
1374: value |= ATI_REG_IER_OUT_XRUN_EN;
1375:
1376: value |= ATI_REG_IER_SPDIF_XRUN_EN;
1377: value |= ATI_REG_IER_SPDF_STATUS_EN;
1378: #endif
1379:
1380: bus_space_write_4(iot, ioh, ATI_REG_IER, value);
1381: }
1382:
1383: void
1384: auixp_disable_interrupts(struct auixp_softc *sc)
1385: {
1386: bus_space_tag_t iot;
1387: bus_space_handle_t ioh;
1388:
1389: iot = sc->sc_iot;
1390: ioh = sc->sc_ioh;
1391: /* disable all interrupt sources */
1392: bus_space_write_4(iot, ioh, ATI_REG_IER, 0);
1393:
1394: /* clear all pending */
1395: bus_space_write_4(iot, ioh, ATI_REG_ISR, 0xffffffff);
1396: }
1397:
1398: /* dismantle what we've set up by undoing setup */
1399: int
1400: auixp_detach(struct device *self, int flags)
1401: {
1402: struct auixp_softc *sc;
1403:
1404: sc = (struct auixp_softc *)self;
1405: /* XXX shouldn't we just reset the chip? XXX */
1406: /*
1407: * should we explicitly disable interrupt generation and acknowledge
1408: * what's left on? better be safe than sorry.
1409: */
1410: auixp_disable_interrupts(sc);
1411:
1412: /* tear down .... */
1413: config_detach(&sc->sc_dev, flags); /* XXX OK? XXX */
1414:
1415: if (sc->sc_ih != NULL)
1416: pci_intr_disestablish(sc->sc_pct, sc->sc_ih);
1417: if (sc->sc_ios)
1418: bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
1419:
1420: if (sc->savemem)
1421: free(sc->savemem, M_DEVBUF);
1422:
1423: return 0;
1424: }
1425:
1426:
1427: /*
1428: * codec handling
1429: *
1430: * IXP audio support can have upto 3 codecs! are they chained ? or
1431: * alternative outlets with the same audio feed i.e. with different mixer
1432: * settings? XXX does NetBSD support more than one audio codec? XXX
1433: */
1434:
1435:
1436: int
1437: auixp_attach_codec(void *aux, struct ac97_codec_if *codec_if)
1438: {
1439: struct auixp_codec *ixp_codec;
1440:
1441: ixp_codec = aux;
1442: ixp_codec->codec_if = codec_if;
1443: ixp_codec->present = 1;
1444:
1445: return 0;
1446: }
1447:
1448: int
1449: auixp_read_codec(void *aux, u_int8_t reg, u_int16_t *result)
1450: {
1451: struct auixp_codec *co;
1452: struct auixp_softc *sc;
1453: bus_space_tag_t iot;
1454: bus_space_handle_t ioh;
1455: u_int32_t data;
1456: int timeout;
1457:
1458: co = aux;
1459: sc = co->sc;
1460: iot = sc->sc_iot;
1461: ioh = sc->sc_ioh;
1462: if (auixp_wait_for_codecs(sc, "read_codec"))
1463: return 0xffff;
1464:
1465: /* build up command for reading codec register */
1466: data = (reg << ATI_REG_PHYS_OUT_ADDR_SHIFT) |
1467: ATI_REG_PHYS_OUT_ADDR_EN |
1468: ATI_REG_PHYS_OUT_RW |
1469: co->codec_nr;
1470:
1471: bus_space_write_4(iot, ioh, ATI_REG_PHYS_OUT_ADDR, data);
1472:
1473: if (auixp_wait_for_codecs(sc, "read_codec"))
1474: return 0xffff;
1475:
1476: /* wait until codec info is clocked in */
1477: timeout = 500; /* 500*2 usec -> 0.001 sec */
1478: do {
1479: data = bus_space_read_4(iot, ioh, ATI_REG_PHYS_IN_ADDR);
1480: if (data & ATI_REG_PHYS_IN_READ_FLAG) {
1481: DPRINTF(("read ac'97 codec reg 0x%x = 0x%08x\n",
1482: reg, data >> ATI_REG_PHYS_IN_DATA_SHIFT));
1483: *result = data >> ATI_REG_PHYS_IN_DATA_SHIFT;
1484: return 0;
1485: }
1486: DELAY(2);
1487: timeout--;
1488: } while (timeout > 0);
1489:
1490: if (reg < 0x7c)
1491: printf("%s: codec read timeout! (reg %x)\n",
1492: sc->sc_dev.dv_xname, reg);
1493:
1494: return 0xffff;
1495: }
1496:
1497: int
1498: auixp_write_codec(void *aux, u_int8_t reg, u_int16_t data)
1499: {
1500: struct auixp_codec *co;
1501: struct auixp_softc *sc;
1502: bus_space_tag_t iot;
1503: bus_space_handle_t ioh;
1504: u_int32_t value;
1505:
1506: DPRINTF(("write ac'97 codec reg 0x%x = 0x%08x\n", reg, data));
1507: co = aux;
1508: sc = co->sc;
1509: iot = sc->sc_iot;
1510: ioh = sc->sc_ioh;
1511: if (auixp_wait_for_codecs(sc, "write_codec"))
1512: return -1;
1513:
1514: /* build up command for writing codec register */
1515: value = (((u_int32_t) data) << ATI_REG_PHYS_OUT_DATA_SHIFT) |
1516: (((u_int32_t) reg) << ATI_REG_PHYS_OUT_ADDR_SHIFT) |
1517: ATI_REG_PHYS_OUT_ADDR_EN |
1518: co->codec_nr;
1519:
1520: bus_space_write_4(iot, ioh, ATI_REG_PHYS_OUT_ADDR, value);
1521:
1522: return 0;
1523: }
1524:
1525: void
1526: auixp_reset_codec(void *aux)
1527: {
1528:
1529: /* nothing to be done? */
1530: }
1531:
1532: enum ac97_host_flags
1533: auixp_flags_codec(void *aux)
1534: {
1535: struct auixp_codec *ixp_codec;
1536:
1537: ixp_codec = aux;
1538: return ixp_codec->codec_flags;
1539: }
1540:
1541: int
1542: auixp_wait_for_codecs(struct auixp_softc *sc, const char *func)
1543: {
1544: bus_space_tag_t iot;
1545: bus_space_handle_t ioh;
1546: u_int32_t value;
1547: int timeout;
1548:
1549: iot = sc->sc_iot;
1550: ioh = sc->sc_ioh;
1551: /* wait until all codec transfers are done */
1552: timeout = 500; /* 500*2 usec -> 0.001 sec */
1553: do {
1554: value = bus_space_read_4(iot, ioh, ATI_REG_PHYS_OUT_ADDR);
1555: if ((value & ATI_REG_PHYS_OUT_ADDR_EN) == 0)
1556: return 0;
1557:
1558: DELAY(2);
1559: timeout--;
1560: } while (timeout > 0);
1561:
1562: printf("%s: %s: timed out\n", func, sc->sc_dev.dv_xname);
1563: return -1;
1564: }
1565:
1566: void
1567: auixp_autodetect_codecs(struct auixp_softc *sc)
1568: {
1569: bus_space_tag_t iot;
1570: bus_space_handle_t ioh;
1571: pcireg_t subdev;
1572: struct auixp_codec *codec;
1573: int timeout, codec_nr;
1574:
1575: iot = sc->sc_iot;
1576: ioh = sc->sc_ioh;
1577: subdev = pci_conf_read(sc->sc_pct, sc->sc_tag, PCI_SUBSYS_ID_REG);
1578:
1579: /* ATI IXP can have upto 3 codecs; mark all codecs as not existing */
1580: sc->sc_codec_not_ready_bits = 0;
1581: sc->sc_num_codecs = 0;
1582:
1583: /* enable all codecs to interrupt as well as the new frame interrupt */
1584: bus_space_write_4(iot, ioh, ATI_REG_IER, CODEC_CHECK_BITS);
1585:
1586: /* wait for the interrupts to happen */
1587: timeout = 100; /* 100.000 usec -> 0.1 sec */
1588:
1589: while (timeout > 0) {
1590: DELAY(1000);
1591: if (sc->sc_codec_not_ready_bits)
1592: break;
1593: timeout--;
1594: }
1595:
1596: if (timeout == 0)
1597: printf("%s: WARNING: timeout during codec detection; "
1598: "codecs might be present but haven't interrupted\n",
1599: sc->sc_dev.dv_xname);
1600:
1601: /* disable all interrupts for now */
1602: auixp_disable_interrupts(sc);
1603:
1604: /* Attach AC97 host interfaces */
1605: for (codec_nr = 0; codec_nr < ATI_IXP_CODECS; codec_nr++) {
1606: codec = &sc->sc_codec[codec_nr];
1607: bzero(codec, sizeof(struct auixp_codec));
1608:
1609: codec->sc = sc;
1610: codec->codec_nr = codec_nr;
1611: codec->present = 0;
1612:
1613: codec->host_if.arg = codec;
1614: codec->host_if.attach = auixp_attach_codec;
1615: codec->host_if.read = auixp_read_codec;
1616: codec->host_if.write = auixp_write_codec;
1617: codec->host_if.reset = auixp_reset_codec;
1618: codec->host_if.flags = auixp_flags_codec;
1619: switch (subdev) {
1620: case 0x1311462: /* MSI S270 */
1621: codec->codec_flags = AC97_HOST_DONT_ENABLE_SPDIF;
1622: break;
1623: }
1624: }
1625:
1626: if (!(sc->sc_codec_not_ready_bits & ATI_REG_ISR_CODEC0_NOT_READY)) {
1627: /* codec 0 present */
1628: DPRINTF(("auixp : YAY! codec 0 present!\n"));
1629: if (ac97_attach(&sc->sc_codec[0].host_if) == 0)
1630: sc->sc_num_codecs++;
1631: }
1632:
1633: #ifdef notyet
1634: if (!(sc->sc_codec_not_ready_bits & ATI_REG_ISR_CODEC1_NOT_READY)) {
1635: /* codec 1 present */
1636: DPRINTF(("auixp : YAY! codec 1 present!\n"));
1637: if (ac97_attach(&sc->sc_codec[1].host_if, &sc->sc_dev) == 0)
1638: sc->sc_num_codecs++;
1639: }
1640:
1641: if (!(sc->sc_codec_not_ready_bits & ATI_REG_ISR_CODEC2_NOT_READY)) {
1642: /* codec 2 present */
1643: DPRINTF(("auixp : YAY! codec 2 present!\n"));
1644: if (ac97_attach(&sc->sc_codec[2].host_if, &sc->sc_dev) == 0)
1645: sc->sc_num_codecs++;
1646: }
1647: #endif
1648:
1649: if (sc->sc_num_codecs == 0) {
1650: printf("%s: no codecs detected or initialised\n",
1651: sc->sc_dev.dv_xname);
1652: return;
1653: }
1654: }
1655:
1656: void
1657: auixp_disable_dma(struct auixp_softc *sc, struct auixp_dma *dma)
1658: {
1659: bus_space_tag_t iot;
1660: bus_space_handle_t ioh;
1661: u_int32_t value;
1662:
1663: iot = sc->sc_iot;
1664: ioh = sc->sc_ioh;
1665: /* lets not stress the DMA engine more than necessary */
1666: value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
1667: if (value & dma->dma_enable_bit) {
1668: value &= ~dma->dma_enable_bit;
1669: bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
1670: }
1671: }
1672:
1673: void
1674: auixp_enable_dma(struct auixp_softc *sc, struct auixp_dma *dma)
1675: {
1676: bus_space_tag_t iot;
1677: bus_space_handle_t ioh;
1678: u_int32_t value;
1679:
1680: iot = sc->sc_iot;
1681: ioh = sc->sc_ioh;
1682: /* lets not stress the DMA engine more than necesssary */
1683: value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
1684: if (!(value & dma->dma_enable_bit)) {
1685: value |= dma->dma_enable_bit;
1686: bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
1687: }
1688: }
1689:
1690: void
1691: auixp_reset_aclink(struct auixp_softc *sc)
1692: {
1693: bus_space_tag_t iot;
1694: bus_space_handle_t ioh;
1695: u_int32_t value, timeout;
1696:
1697: iot = sc->sc_iot;
1698: ioh = sc->sc_ioh;
1699:
1700: /* if power is down, power it up */
1701: value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
1702: if (value & ATI_REG_CMD_POWERDOWN) {
1703: printf("%s: powering up\n", sc->sc_dev.dv_xname);
1704:
1705: /* explicitly enable power */
1706: value &= ~ATI_REG_CMD_POWERDOWN;
1707: bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
1708:
1709: /* have to wait at least 10 usec for it to initialise */
1710: DELAY(20);
1711: };
1712:
1713: printf("%s: soft resetting aclink\n", sc->sc_dev.dv_xname);
1714:
1715: /* perform a soft reset */
1716: value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
1717: value |= ATI_REG_CMD_AC_SOFT_RESET;
1718: bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
1719:
1720: /* need to read the CMD reg and wait aprox. 10 usec to init */
1721: value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
1722: DELAY(20);
1723:
1724: /* clear soft reset flag again */
1725: value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
1726: value &= ~ATI_REG_CMD_AC_SOFT_RESET;
1727: bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
1728:
1729: /* check if the ac-link is working; reset device otherwise */
1730: timeout = 10;
1731: value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
1732: while (!(value & ATI_REG_CMD_ACLINK_ACTIVE)) {
1733: printf("%s: not up; resetting aclink hardware\n",
1734: sc->sc_dev.dv_xname);
1735:
1736: /* dip aclink reset but keep the acsync */
1737: value &= ~ATI_REG_CMD_AC_RESET;
1738: value |= ATI_REG_CMD_AC_SYNC;
1739: bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
1740:
1741: /* need to read CMD again and wait again (clocking in issue?) */
1742: value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
1743: DELAY(20);
1744:
1745: /* assert aclink reset again */
1746: value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
1747: value |= ATI_REG_CMD_AC_RESET;
1748: bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
1749:
1750: /* check if its active now */
1751: value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
1752:
1753: timeout--;
1754: if (timeout == 0) break;
1755: };
1756:
1757: if (timeout == 0) {
1758: printf("%s: giving up aclink reset\n", sc->sc_dev.dv_xname);
1759: };
1760: if (timeout != 10) {
1761: printf("%s: aclink hardware reset successful\n",
1762: sc->sc_dev.dv_xname);
1763: };
1764:
1765: /* assert reset and sync for safety */
1766: value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
1767: value |= ATI_REG_CMD_AC_SYNC | ATI_REG_CMD_AC_RESET;
1768: bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
1769: }
1770:
1771: /* chip hard init */
1772: int
1773: auixp_init(struct auixp_softc *sc)
1774: {
1775: bus_space_tag_t iot;
1776: bus_space_handle_t ioh;
1777: u_int32_t value;
1778:
1779: iot = sc->sc_iot;
1780: ioh = sc->sc_ioh;
1781: /* disable all interrupts and clear all sources */
1782: auixp_disable_interrupts(sc);
1783:
1784: /* clear all DMA enables (preserving rest of settings) */
1785: value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
1786: value &= ~( ATI_REG_CMD_IN_DMA_EN |
1787: ATI_REG_CMD_OUT_DMA_EN |
1788: ATI_REG_CMD_SPDF_OUT_EN );
1789: bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
1790:
1791: /* Reset AC-link */
1792: auixp_reset_aclink(sc);
1793:
1794: /*
1795: * codecs get auto-detected later
1796: *
1797: * note: we are NOT enabling interrupts yet, no codecs have been
1798: * detected yet nor is anything else set up
1799: */
1800:
1801: return 0;
1802: }
1803:
1804: /*
1805: * TODO power saving and suspend / resume support
1806: */
1807: int
1808: auixp_power(struct auixp_softc *sc, int state)
1809: {
1810: pcitag_t tag;
1811: pci_chipset_tag_t pc;
1812: pcireg_t data;
1813: int pmcapreg;
1814:
1815: tag = sc->sc_tag;
1816: pc = sc->sc_pct;
1817: if (pci_get_capability(pc, tag, PCI_CAP_PWRMGMT, &pmcapreg, 0)) {
1818: data = pci_conf_read(pc, tag, pmcapreg + PCI_PMCSR);
1819: if ((data & PCI_PMCSR_STATE_MASK) != state)
1820: pci_conf_write(pc, tag, pmcapreg + PCI_PMCSR, state);
1821: }
1822:
1823: return 0;
1824: }
1825:
1826: #if 0
1827: void
1828: auixp_powerhook(int why, void *hdl)
1829: {
1830: struct auixp_softc *sc;
1831:
1832: sc = (struct auixp_softc *)hdl;
1833: switch (why) {
1834: case PWR_SUSPEND:
1835: case PWR_STANDBY:
1836: auixp_suspend(sc);
1837: break;
1838: case PWR_RESUME:
1839: auixp_resume(sc);
1840: /* XXX fix me XXX */
1841: (sc->codec_if->vtbl->restore_ports)(sc->codec_if);
1842: break;
1843: }
1844: }
1845:
1846: int
1847: auixp_suspend(struct auixp_softc *sc)
1848: {
1849:
1850: /* XXX no power functions yet XXX */
1851: return 0;
1852: }
1853:
1854: int
1855: auixp_resume(struct auixp_softc *sc)
1856: {
1857:
1858: /* XXX no power functions yet XXX */
1859: return 0;
1860: }
1861: #endif /* 0 */
CVSweb