Line data Source code
1 : /* $OpenBSD: auixp.c,v 1.40 2018/09/03 05:37:32 miko 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/param.h>
54 : #include <sys/errno.h>
55 : #include <sys/systm.h>
56 : #include <sys/malloc.h>
57 : #include <sys/device.h>
58 : #include <sys/conf.h>
59 : #include <sys/exec.h>
60 : #include <sys/selinfo.h>
61 : #include <sys/audioio.h>
62 : #include <sys/queue.h>
63 :
64 : #include <machine/bus.h>
65 :
66 : #include <dev/pci/pcidevs.h>
67 : #include <dev/pci/pcivar.h>
68 :
69 : #include <dev/audio_if.h>
70 : #include <dev/ic/ac97.h>
71 :
72 : #include <dev/pci/auixpreg.h>
73 : #include <dev/pci/auixpvar.h>
74 :
75 : /* codec detection constant indicating the interrupt flags */
76 : #define ALL_CODECS_NOT_READY \
77 : (ATI_REG_ISR_CODEC0_NOT_READY | ATI_REG_ISR_CODEC1_NOT_READY |\
78 : ATI_REG_ISR_CODEC2_NOT_READY)
79 : #define CODEC_CHECK_BITS (ALL_CODECS_NOT_READY|ATI_REG_ISR_NEW_FRAME)
80 :
81 : /* why isn't this base address register not in the headerfile? */
82 : #define PCI_CBIO 0x10
83 :
84 : /* macro's used */
85 : #define KERNADDR(p) ((void *)((p)->addr))
86 : #define DMAADDR(p) ((p)->map->dm_segs[0].ds_addr)
87 :
88 : const struct pci_matchid auixp_pci_devices[] = {
89 : { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB200_AUDIO },
90 : { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB300_AUDIO },
91 : { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB400_AUDIO },
92 : { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB600_AUDIO }
93 : };
94 :
95 : struct cfdriver auixp_cd = {
96 : NULL, "auixp", DV_DULL
97 : };
98 :
99 : int auixp_match( struct device *, void *, void *);
100 : void auixp_attach(struct device *, struct device *, void *);
101 : int auixp_detach(struct device *, int);
102 :
103 : int auixp_activate(struct device *, int);
104 :
105 : struct cfattach auixp_ca = {
106 : sizeof(struct auixp_softc), auixp_match, auixp_attach,
107 : NULL, auixp_activate
108 : };
109 :
110 : int auixp_open(void *v, int flags);
111 : void auixp_close(void *v);
112 : int auixp_set_params(void *, int, int, struct audio_params *,
113 : struct audio_params *);
114 : int auixp_commit_settings(void *);
115 : int auixp_round_blocksize(void *, int);
116 : int auixp_trigger_output(void *, void *, void *, int,
117 : void (*)(void *), void *, struct audio_params *);
118 : int auixp_trigger_input(void *, void *, void *, int,
119 : void (*)(void *), void *, struct audio_params *);
120 : int auixp_halt_output(void *);
121 : int auixp_halt_input(void *);
122 : int auixp_set_port(void *, mixer_ctrl_t *);
123 : int auixp_get_port(void *, mixer_ctrl_t *);
124 : int auixp_query_devinfo(void *, mixer_devinfo_t *);
125 : void * auixp_malloc(void *, int, size_t, int, int);
126 : void auixp_free(void *, void *, int);
127 : int auixp_get_props(void *);
128 : int auixp_intr(void *);
129 : int auixp_allocmem(struct auixp_softc *, size_t, size_t,
130 : struct auixp_dma *);
131 : int auixp_freemem(struct auixp_softc *, struct auixp_dma *);
132 :
133 : /* Supporting subroutines */
134 : int auixp_init(struct auixp_softc *);
135 : void auixp_autodetect_codecs(struct auixp_softc *);
136 : void auixp_post_config(struct device *);
137 :
138 : void auixp_reset_aclink(struct auixp_softc *);
139 : int auixp_attach_codec(void *, struct ac97_codec_if *);
140 : int auixp_read_codec(void *, u_int8_t, u_int16_t *);
141 : int auixp_write_codec(void *, u_int8_t, u_int16_t);
142 : int auixp_wait_for_codecs(struct auixp_softc *, const char *);
143 : void auixp_reset_codec(void *);
144 : enum ac97_host_flags auixp_flags_codec(void *);
145 :
146 : void auixp_enable_dma(struct auixp_softc *, struct auixp_dma *);
147 : void auixp_disable_dma(struct auixp_softc *, struct auixp_dma *);
148 : void auixp_enable_interrupts(struct auixp_softc *);
149 : void auixp_disable_interrupts(struct auixp_softc *);
150 :
151 : void auixp_link_daisychain(struct auixp_softc *,
152 : struct auixp_dma *, struct auixp_dma *, int, int);
153 : int auixp_allocate_dma_chain(struct auixp_softc *, struct auixp_dma **);
154 : void auixp_program_dma_chain(struct auixp_softc *, struct auixp_dma *);
155 : void auixp_dma_update(struct auixp_softc *, struct auixp_dma *);
156 : void auixp_update_busbusy(struct auixp_softc *);
157 :
158 : #ifdef DEBUG_AUIXP
159 : #define DPRINTF(x) printf x;
160 : #else
161 : #define DPRINTF(x)
162 : #endif
163 :
164 : struct audio_hw_if auixp_hw_if = {
165 : auixp_open,
166 : auixp_close,
167 : auixp_set_params,
168 : auixp_round_blocksize,
169 : auixp_commit_settings,
170 : NULL, /* init_output */
171 : NULL, /* init_input */
172 : NULL, /* start_output */
173 : NULL, /* start_input */
174 : auixp_halt_output,
175 : auixp_halt_input,
176 : NULL, /* speaker_ctl */
177 : NULL, /* getfd */
178 : auixp_set_port,
179 : auixp_get_port,
180 : auixp_query_devinfo,
181 : auixp_malloc,
182 : auixp_free,
183 : NULL, /* round_buffersize */
184 : auixp_get_props,
185 : auixp_trigger_output,
186 : auixp_trigger_input
187 : };
188 :
189 : int
190 0 : auixp_open(void *v, int flags)
191 : {
192 :
193 0 : return 0;
194 : }
195 :
196 : void
197 0 : auixp_close(void *v)
198 : {
199 0 : }
200 :
201 : /* commit setting and program ATI IXP chip */
202 : int
203 0 : auixp_commit_settings(void *hdl)
204 : {
205 : struct auixp_codec *co;
206 : struct auixp_softc *sc;
207 : bus_space_tag_t iot;
208 : bus_space_handle_t ioh;
209 : struct audio_params *params;
210 : u_int32_t value;
211 :
212 : /* XXX would it be better to stop interrupts first? XXX */
213 0 : co = (struct auixp_codec *) hdl;
214 0 : sc = co->sc;
215 0 : iot = sc->sc_iot;
216 0 : ioh = sc->sc_ioh;
217 :
218 : /* process input settings */
219 0 : params = &sc->sc_play_params;
220 :
221 : /* set input interleaving (precision) */
222 0 : value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
223 0 : value &= ~ATI_REG_CMD_INTERLEAVE_IN;
224 0 : if (params->precision <= 16)
225 0 : value |= ATI_REG_CMD_INTERLEAVE_IN;
226 0 : bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
227 :
228 : /* process output settings */
229 : params = &sc->sc_play_params;
230 :
231 0 : value = bus_space_read_4(iot, ioh, ATI_REG_OUT_DMA_SLOT);
232 0 : value &= ~ATI_REG_OUT_DMA_SLOT_MASK;
233 :
234 : /* TODO SPDIF case for 8 channels */
235 0 : switch (params->channels) {
236 : case 6:
237 0 : value |= ATI_REG_OUT_DMA_SLOT_BIT(7) |
238 : ATI_REG_OUT_DMA_SLOT_BIT(8);
239 : /* FALLTHROUGH */
240 : case 4:
241 0 : value |= ATI_REG_OUT_DMA_SLOT_BIT(6) |
242 : ATI_REG_OUT_DMA_SLOT_BIT(9);
243 : /* FALLTHROUGH */
244 : default:
245 0 : value |= ATI_REG_OUT_DMA_SLOT_BIT(3) |
246 : ATI_REG_OUT_DMA_SLOT_BIT(4);
247 : break;
248 : }
249 : /* set output threshold */
250 0 : value |= 0x04 << ATI_REG_OUT_DMA_THRESHOLD_SHIFT;
251 0 : bus_space_write_4(iot, ioh, ATI_REG_OUT_DMA_SLOT, value);
252 :
253 : /* set output interleaving (precision) */
254 0 : value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
255 0 : value &= ~ATI_REG_CMD_INTERLEAVE_OUT;
256 0 : if (params->precision <= 16)
257 0 : value |= ATI_REG_CMD_INTERLEAVE_OUT;
258 0 : bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
259 :
260 : /* enable 6 channel reordering */
261 0 : value = bus_space_read_4(iot, ioh, ATI_REG_6CH_REORDER);
262 0 : value &= ~ATI_REG_6CH_REORDER_EN;
263 0 : if (params->channels == 6)
264 0 : value |= ATI_REG_6CH_REORDER_EN;
265 0 : bus_space_write_4(iot, ioh, ATI_REG_6CH_REORDER, value);
266 :
267 0 : if (sc->has_spdif) {
268 : /* set SPDIF (if present) */
269 0 : value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
270 0 : value &= ~ATI_REG_CMD_SPDF_CONFIG_MASK;
271 0 : value |= ATI_REG_CMD_SPDF_CONFIG_34; /* NetBSD AC'97 default */
272 :
273 : /* XXX this is probably not necessary unless splitted XXX */
274 0 : value &= ~ATI_REG_CMD_INTERLEAVE_SPDF;
275 0 : if (params->precision <= 16)
276 0 : value |= ATI_REG_CMD_INTERLEAVE_SPDF;
277 0 : bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
278 0 : }
279 :
280 0 : return 0;
281 : }
282 :
283 :
284 : /* set audio properties in desired setting */
285 : int
286 0 : auixp_set_params(void *hdl, int setmode, int usemode,
287 : struct audio_params *play, struct audio_params *rec)
288 : {
289 : struct auixp_codec *co;
290 : int error;
291 : u_int temprate;
292 :
293 0 : co = (struct auixp_codec *) hdl;
294 0 : if (setmode & AUMODE_PLAY) {
295 0 : play->channels = 2;
296 0 : play->precision = 16;
297 0 : switch(play->encoding) {
298 : case AUDIO_ENCODING_SLINEAR_LE:
299 : break;
300 : default:
301 0 : return (EINVAL);
302 : }
303 0 : play->bps = AUDIO_BPS(play->precision);
304 0 : play->msb = 1;
305 :
306 0 : temprate = play->sample_rate;
307 0 : error = ac97_set_rate(co->codec_if,
308 : AC97_REG_PCM_LFE_DAC_RATE, &play->sample_rate);
309 0 : if (error)
310 0 : return (error);
311 :
312 0 : play->sample_rate = temprate;
313 0 : error = ac97_set_rate(co->codec_if,
314 : AC97_REG_PCM_SURR_DAC_RATE, &play->sample_rate);
315 0 : if (error)
316 0 : return (error);
317 :
318 0 : play->sample_rate = temprate;
319 0 : error = ac97_set_rate(co->codec_if,
320 : AC97_REG_PCM_FRONT_DAC_RATE, &play->sample_rate);
321 0 : if (error)
322 0 : return (error);
323 :
324 : }
325 :
326 0 : if (setmode & AUMODE_RECORD) {
327 0 : rec->channels = 2;
328 0 : rec->precision = 16;
329 0 : switch(rec->encoding) {
330 : case AUDIO_ENCODING_SLINEAR_LE:
331 : break;
332 : default:
333 0 : return (EINVAL);
334 : }
335 0 : rec->bps = AUDIO_BPS(rec->precision);
336 0 : rec->msb = 1;
337 :
338 0 : error = ac97_set_rate(co->codec_if, AC97_REG_PCM_LR_ADC_RATE,
339 0 : &rec->sample_rate);
340 0 : if (error)
341 0 : return (error);
342 : }
343 :
344 0 : return (0);
345 0 : }
346 :
347 :
348 : /* called to translate a requested blocksize to a hw-possible one */
349 : int
350 0 : auixp_round_blocksize(void *v, int blk)
351 : {
352 :
353 0 : blk = (blk + 0x1f) & ~0x1f;
354 : /* Be conservative; align to 32 bytes and maximise it to 64 kb */
355 0 : if (blk > 0x10000)
356 : blk = 0x10000;
357 :
358 0 : return blk;
359 : }
360 :
361 :
362 : /*
363 : * allocate dma capable memory and record its information for later retrieval
364 : * when we program the dma chain itself. The trigger routines passes on the
365 : * kernel virtual address we return here as a reference to the mapping.
366 : */
367 : void *
368 0 : auixp_malloc(void *hdl, int direction, size_t size, int pool, int flags)
369 : {
370 : struct auixp_codec *co;
371 : struct auixp_softc *sc;
372 : struct auixp_dma *dma;
373 : int error;
374 :
375 0 : co = (struct auixp_codec *) hdl;
376 0 : sc = co->sc;
377 : /* get us a auixp_dma structure */
378 0 : dma = malloc(sizeof(*dma), pool, flags);
379 0 : if (!dma)
380 0 : return NULL;
381 :
382 : /* get us a dma buffer itself */
383 0 : error = auixp_allocmem(sc, size, 16, dma);
384 0 : if (error) {
385 0 : free(dma, pool, 0);
386 0 : printf("%s: auixp_malloc: not enough memory\n",
387 0 : sc->sc_dev.dv_xname);
388 0 : return NULL;
389 : }
390 0 : SLIST_INSERT_HEAD(&sc->sc_dma_list, dma, dma_chain);
391 :
392 : DPRINTF(("auixp_malloc: returning kern %p, hw 0x%08x for %d bytes "
393 : "in %d segs\n", KERNADDR(dma), (u_int32_t) DMAADDR(dma), dma->size,
394 : dma->nsegs)
395 : );
396 :
397 0 : return KERNADDR(dma);
398 0 : }
399 :
400 : /*
401 : * free and release dma capable memory we allocated before and remove its
402 : * recording
403 : */
404 : void
405 0 : auixp_free(void *hdl, void *addr, int pool)
406 : {
407 : struct auixp_codec *co;
408 : struct auixp_softc *sc;
409 : struct auixp_dma *dma;
410 :
411 0 : co = (struct auixp_codec *) hdl;
412 0 : sc = co->sc;
413 0 : SLIST_FOREACH(dma, &sc->sc_dma_list, dma_chain) {
414 0 : if (KERNADDR(dma) == addr) {
415 0 : SLIST_REMOVE(&sc->sc_dma_list, dma, auixp_dma,
416 : dma_chain);
417 0 : auixp_freemem(sc, dma);
418 0 : free(dma, pool, 0);
419 0 : return;
420 : }
421 : }
422 0 : }
423 :
424 : /* pass request to AC'97 codec code */
425 : int
426 0 : auixp_set_port(void *hdl, mixer_ctrl_t *mc)
427 : {
428 : struct auixp_codec *co;
429 :
430 0 : co = (struct auixp_codec *) hdl;
431 0 : return co->codec_if->vtbl->mixer_set_port(co->codec_if, mc);
432 : }
433 :
434 :
435 : /* pass request to AC'97 codec code */
436 : int
437 0 : auixp_get_port(void *hdl, mixer_ctrl_t *mc)
438 : {
439 : struct auixp_codec *co;
440 :
441 0 : co = (struct auixp_codec *) hdl;
442 0 : return co->codec_if->vtbl->mixer_get_port(co->codec_if, mc);
443 : }
444 :
445 : /* pass request to AC'97 codec code */
446 : int
447 0 : auixp_query_devinfo(void *hdl, mixer_devinfo_t *di)
448 : {
449 : struct auixp_codec *co;
450 :
451 0 : co = (struct auixp_codec *) hdl;
452 0 : return co->codec_if->vtbl->query_devinfo(co->codec_if, di);
453 : }
454 :
455 : int
456 0 : auixp_get_props(void *hdl)
457 : {
458 :
459 0 : return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX;
460 : }
461 :
462 :
463 : /*
464 : * A dma descriptor has dma->nsegs segments defined in dma->segs set up when
465 : * we claimed the memory.
466 : *
467 : * Due to our demand for one contiguous DMA area, we only have one segment. A
468 : * c_dma structure is about 3 kb for the 256 entries we maximally program
469 : * -arbitrary limit AFAIK- so all is most likely to be in one segment/page
470 : * anyway.
471 : *
472 : * XXX ought to implement fragmented dma area XXX
473 : *
474 : * Note that _v variables depict kernel virtual addresses, _p variables depict
475 : * physical addresses.
476 : */
477 : void
478 0 : auixp_link_daisychain(struct auixp_softc *sc,
479 : struct auixp_dma *c_dma, struct auixp_dma *s_dma,
480 : int blksize, int blocks)
481 : {
482 : atiixp_dma_desc_t *caddr_v, *next_caddr_v;
483 : u_int32_t caddr_p, next_caddr_p, saddr_p;
484 : int i;
485 :
486 : /* just make sure we are not changing when its running */
487 0 : auixp_disable_dma(sc, c_dma);
488 :
489 : /* setup dma chain start addresses */
490 0 : caddr_v = KERNADDR(c_dma);
491 0 : caddr_p = DMAADDR(c_dma);
492 0 : saddr_p = DMAADDR(s_dma);
493 :
494 : /* program the requested number of blocks */
495 0 : for (i = 0; i < blocks; i++) {
496 : /* clear the block just in case */
497 0 : bzero(caddr_v, sizeof(atiixp_dma_desc_t));
498 :
499 : /* round robin the chain dma addresses for its successor */
500 0 : next_caddr_v = caddr_v + 1;
501 0 : next_caddr_p = caddr_p + sizeof(atiixp_dma_desc_t);
502 :
503 0 : if (i == blocks-1) {
504 0 : next_caddr_v = KERNADDR(c_dma);
505 0 : next_caddr_p = DMAADDR(c_dma);
506 0 : }
507 :
508 : /* fill in the hardware dma chain descriptor in little-endian */
509 0 : caddr_v->addr = htole32(saddr_p);
510 0 : caddr_v->status = htole16(0);
511 0 : caddr_v->size = htole16((blksize >> 2)); /* in dwords (!!!) */
512 0 : caddr_v->next = htole32(next_caddr_p);
513 :
514 : /* advance slot */
515 0 : saddr_p += blksize; /* XXX assuming contiguous XXX */
516 : caddr_v = next_caddr_v;
517 : caddr_p = next_caddr_p;
518 : }
519 0 : }
520 :
521 :
522 : int
523 0 : auixp_allocate_dma_chain(struct auixp_softc *sc, struct auixp_dma **dmap)
524 : {
525 : struct auixp_dma *dma;
526 : int error;
527 :
528 : /* allocate keeper of dma area */
529 0 : *dmap = NULL;
530 0 : dma = malloc(sizeof(*dma), M_DEVBUF, M_NOWAIT | M_ZERO);
531 0 : if (!dma)
532 0 : return ENOMEM;
533 :
534 : /* allocate for daisychain of IXP hardware-dma descriptors */
535 0 : error = auixp_allocmem(sc, DMA_DESC_CHAIN * sizeof(atiixp_dma_desc_t),
536 : 16, dma);
537 0 : if (error) {
538 0 : printf("%s: can't malloc dma descriptor chain\n",
539 0 : sc->sc_dev.dv_xname);
540 0 : free(dma, M_DEVBUF, 0);
541 0 : return ENOMEM;
542 : }
543 :
544 : /* return info and initialise structure */
545 0 : dma->intr = NULL;
546 0 : dma->intrarg = NULL;
547 :
548 0 : *dmap = dma;
549 0 : return 0;
550 0 : }
551 :
552 :
553 : /* program dma chain in its link address descriptor */
554 : void
555 0 : auixp_program_dma_chain(struct auixp_softc *sc, struct auixp_dma *dma)
556 : {
557 : bus_space_tag_t iot;
558 : bus_space_handle_t ioh;
559 : u_int32_t value;
560 :
561 0 : iot = sc->sc_iot;
562 0 : ioh = sc->sc_ioh;
563 : /* get hardware start address of DMA chain and set valid-flag in it */
564 : /* XXX always at start? XXX */
565 0 : value = DMAADDR(dma);
566 0 : value = value | ATI_REG_LINKPTR_EN;
567 :
568 : /* reset linkpointer */
569 0 : bus_space_write_4(iot, ioh, dma->linkptr, 0);
570 :
571 : /* reset this DMA engine */
572 0 : auixp_disable_dma(sc, dma);
573 0 : auixp_enable_dma(sc, dma);
574 :
575 : /* program new DMA linkpointer */
576 0 : bus_space_write_4(iot, ioh, dma->linkptr, value);
577 0 : }
578 :
579 :
580 : /* called from interrupt code to signal end of one dma-slot */
581 : void
582 0 : auixp_dma_update(struct auixp_softc *sc, struct auixp_dma *dma)
583 : {
584 :
585 : /* be very paranoid */
586 0 : if (!dma)
587 0 : panic("auixp: update: dma = NULL");
588 0 : if (!dma->intr)
589 0 : panic("auixp: update: dma->intr = NULL");
590 :
591 : /* request more input from upper layer */
592 0 : (*dma->intr)(dma->intrarg);
593 0 : }
594 :
595 :
596 : /*
597 : * The magic `busbusy' bit that needs to be set when dma is active; allowing
598 : * busmastering?
599 : */
600 : void
601 0 : auixp_update_busbusy(struct auixp_softc *sc)
602 : {
603 : bus_space_tag_t iot;
604 : bus_space_handle_t ioh;
605 : u_int32_t value;
606 : int running;
607 :
608 0 : iot = sc->sc_iot;
609 0 : ioh = sc->sc_ioh;
610 : /* set bus-busy flag when either recording or playing is performed */
611 0 : value = bus_space_read_4(iot, ioh, ATI_REG_IER);
612 0 : value &= ~ATI_REG_IER_SET_BUS_BUSY;
613 :
614 0 : running = ((sc->sc_output_dma->running) || (sc->sc_input_dma->running));
615 0 : if (running)
616 0 : value |= ATI_REG_IER_SET_BUS_BUSY;
617 :
618 0 : bus_space_write_4(iot, ioh, ATI_REG_IER, value);
619 :
620 0 : }
621 :
622 :
623 : /*
624 : * Called from upper audio layer to request playing audio, only called once;
625 : * audio is refilled by calling the intr() function when space is available
626 : * again.
627 : */
628 : /* XXX almost literally a copy of trigger-input; could be factorised XXX */
629 : int
630 0 : auixp_trigger_output(void *hdl, void *start, void *end, int blksize,
631 : void (*intr)(void *), void *intrarg, struct audio_params *param)
632 : {
633 : struct auixp_codec *co;
634 : struct auixp_softc *sc;
635 : struct auixp_dma *chain_dma;
636 : struct auixp_dma *sound_dma;
637 : u_int32_t blocks;
638 :
639 0 : co = (struct auixp_codec *) hdl;
640 0 : sc = co->sc;
641 0 : chain_dma = sc->sc_output_dma;
642 : /* add functions to call back */
643 0 : chain_dma->intr = intr;
644 0 : chain_dma->intrarg = intrarg;
645 :
646 : /*
647 : * Program output DMA chain with blocks from [start...end] with
648 : * blksize fragments.
649 : *
650 : * NOTE, we can assume its in one block since we asked for it to be in
651 : * one contiguous blob; XXX change this? XXX
652 : */
653 0 : blocks = (size_t) (((caddr_t) end) - ((caddr_t) start)) / blksize;
654 :
655 : /* lookup `start' address in our list of DMA area's */
656 0 : SLIST_FOREACH(sound_dma, &sc->sc_dma_list, dma_chain) {
657 0 : if (KERNADDR(sound_dma) == start)
658 : break;
659 : }
660 :
661 : /* not ours ? then bail out */
662 0 : if (!sound_dma) {
663 0 : printf("%s: auixp_trigger_output: bad sound addr %p\n",
664 0 : sc->sc_dev.dv_xname, start);
665 0 : return EINVAL;
666 : }
667 :
668 : /* link round-robin daisychain and program hardware */
669 0 : auixp_link_daisychain(sc, chain_dma, sound_dma, blksize, blocks);
670 0 : auixp_program_dma_chain(sc, chain_dma);
671 :
672 : /* mark we are now able to run now */
673 0 : mtx_enter(&audio_lock);
674 0 : chain_dma->running = 1;
675 :
676 : /* update bus-flags; XXX programs more flags XXX */
677 0 : auixp_update_busbusy(sc);
678 0 : mtx_leave(&audio_lock);
679 :
680 : /* callbacks happen in interrupt routine */
681 0 : return 0;
682 0 : }
683 :
684 :
685 : /* halt output of audio, just disable its dma and update bus state */
686 : int
687 0 : auixp_halt_output(void *hdl)
688 : {
689 : struct auixp_codec *co;
690 : struct auixp_softc *sc;
691 : struct auixp_dma *dma;
692 :
693 0 : mtx_enter(&audio_lock);
694 0 : co = (struct auixp_codec *) hdl;
695 0 : sc = co->sc;
696 0 : dma = sc->sc_output_dma;
697 0 : auixp_disable_dma(sc, dma);
698 :
699 0 : dma->running = 0;
700 0 : auixp_update_busbusy(sc);
701 0 : mtx_leave(&audio_lock);
702 0 : return 0;
703 : }
704 :
705 :
706 : /* XXX almost literally a copy of trigger-output; could be factorised XXX */
707 : int
708 0 : auixp_trigger_input(void *hdl, void *start, void *end, int blksize,
709 : void (*intr)(void *), void *intrarg, struct audio_params *param)
710 : {
711 : struct auixp_codec *co;
712 : struct auixp_softc *sc;
713 : struct auixp_dma *chain_dma;
714 : struct auixp_dma *sound_dma;
715 : u_int32_t blocks;
716 :
717 0 : co = (struct auixp_codec *) hdl;
718 0 : sc = co->sc;
719 0 : chain_dma = sc->sc_input_dma;
720 : /* add functions to call back */
721 0 : chain_dma->intr = intr;
722 0 : chain_dma->intrarg = intrarg;
723 :
724 : /*
725 : * Program output DMA chain with blocks from [start...end] with
726 : * blksize fragments.
727 : *
728 : * NOTE, we can assume its in one block since we asked for it to be in
729 : * one contiguous blob; XXX change this? XXX
730 : */
731 0 : blocks = (size_t) (((caddr_t) end) - ((caddr_t) start)) / blksize;
732 :
733 : /* lookup `start' address in our list of DMA area's */
734 0 : SLIST_FOREACH(sound_dma, &sc->sc_dma_list, dma_chain) {
735 0 : if (KERNADDR(sound_dma) == start)
736 : break;
737 : }
738 :
739 : /* not ours ? then bail out */
740 0 : if (!sound_dma) {
741 0 : printf("%s: auixp_trigger_input: bad sound addr %p\n",
742 0 : sc->sc_dev.dv_xname, start);
743 0 : return EINVAL;
744 : }
745 :
746 : /* link round-robin daisychain and program hardware */
747 0 : auixp_link_daisychain(sc, chain_dma, sound_dma, blksize, blocks);
748 0 : auixp_program_dma_chain(sc, chain_dma);
749 :
750 : /* mark we are now able to run now */
751 0 : mtx_enter(&audio_lock);
752 0 : chain_dma->running = 1;
753 :
754 : /* update bus-flags; XXX programs more flags XXX */
755 0 : auixp_update_busbusy(sc);
756 0 : mtx_leave(&audio_lock);
757 :
758 : /* callbacks happen in interrupt routine */
759 0 : return 0;
760 0 : }
761 :
762 :
763 : /* halt sampling audio, just disable its dma and update bus state */
764 : int
765 0 : auixp_halt_input(void *hdl)
766 : {
767 : struct auixp_codec *co;
768 : struct auixp_softc *sc;
769 : struct auixp_dma *dma;
770 :
771 0 : mtx_enter(&audio_lock);
772 0 : co = (struct auixp_codec *) hdl;
773 0 : sc = co->sc;
774 0 : dma = sc->sc_input_dma;
775 0 : auixp_disable_dma(sc, dma);
776 :
777 0 : dma->running = 0;
778 0 : auixp_update_busbusy(sc);
779 :
780 0 : mtx_leave(&audio_lock);
781 0 : return 0;
782 : }
783 :
784 :
785 : /*
786 : * IXP audio interrupt handler
787 : *
788 : * note that we return the number of bits handled; the return value is not
789 : * documented but I saw it implemented in other drivers. Probably returning a
790 : * value > 0 means "I've dealt with it"
791 : *
792 : */
793 : int
794 0 : auixp_intr(void *softc)
795 : {
796 : struct auixp_softc *sc;
797 : bus_space_tag_t iot;
798 : bus_space_handle_t ioh;
799 : u_int32_t status, enable, detected_codecs;
800 : int ret;
801 :
802 0 : mtx_enter(&audio_lock);
803 0 : sc = softc;
804 0 : iot = sc->sc_iot;
805 0 : ioh = sc->sc_ioh;
806 : ret = 0;
807 : /* get status from the interrupt status register */
808 0 : status = bus_space_read_4(iot, ioh, ATI_REG_ISR);
809 :
810 0 : if (status == 0) {
811 0 : mtx_leave(&audio_lock);
812 0 : return 0;
813 : }
814 :
815 : DPRINTF(("%s: (status = %x)\n", sc->sc_dev.dv_xname, status));
816 :
817 : /* check DMA UPDATE flags for input & output */
818 0 : if (status & ATI_REG_ISR_IN_STATUS) {
819 : ret++; DPRINTF(("IN_STATUS\n"));
820 0 : auixp_dma_update(sc, sc->sc_input_dma);
821 0 : }
822 0 : if (status & ATI_REG_ISR_OUT_STATUS) {
823 0 : ret++; DPRINTF(("OUT_STATUS\n"));
824 0 : auixp_dma_update(sc, sc->sc_output_dma);
825 0 : }
826 :
827 : /* XXX XRUN flags not used/needed yet; should i implement it? XXX */
828 : /* acknowledge the interrupts nevertheless */
829 0 : if (status & ATI_REG_ISR_IN_XRUN) {
830 0 : ret++; DPRINTF(("IN_XRUN\n"));
831 : /* auixp_dma_xrun(sc, sc->sc_input_dma); */
832 0 : }
833 0 : if (status & ATI_REG_ISR_OUT_XRUN) {
834 0 : ret++; DPRINTF(("OUT_XRUN\n"));
835 : /* auixp_dma_xrun(sc, sc->sc_output_dma); */
836 0 : }
837 :
838 : /* check if we are looking for codec detection */
839 0 : if (status & CODEC_CHECK_BITS) {
840 0 : ret++;
841 : /* mark missing codecs as not ready */
842 : detected_codecs = status & CODEC_CHECK_BITS;
843 0 : sc->sc_codec_not_ready_bits |= detected_codecs;
844 :
845 : /* disable detected interrupt sources */
846 0 : enable = bus_space_read_4(iot, ioh, ATI_REG_IER);
847 0 : enable &= ~detected_codecs;
848 0 : bus_space_write_4(iot, ioh, ATI_REG_IER, enable);
849 0 : }
850 :
851 : /* acknowledge interrupt sources */
852 0 : bus_space_write_4(iot, ioh, ATI_REG_ISR, status);
853 0 : mtx_leave(&audio_lock);
854 0 : return ret;
855 0 : }
856 :
857 :
858 : /* allocate memory for dma purposes; on failure of any of the steps, roll back */
859 : int
860 0 : auixp_allocmem(struct auixp_softc *sc, size_t size,
861 : size_t align, struct auixp_dma *dma)
862 : {
863 : int error;
864 :
865 : /* remember size */
866 0 : dma->size = size;
867 :
868 : /* allocate DMA safe memory but in just one segment for now :( */
869 0 : error = bus_dmamem_alloc(sc->sc_dmat, dma->size, align, 0,
870 : dma->segs, sizeof(dma->segs) / sizeof(dma->segs[0]), &dma->nsegs,
871 : BUS_DMA_NOWAIT);
872 0 : if (error)
873 0 : return error;
874 :
875 : /*
876 : * map allocated memory into kernel virtual address space and keep it
877 : * coherent with the CPU.
878 : */
879 0 : error = bus_dmamem_map(sc->sc_dmat, dma->segs, dma->nsegs, dma->size,
880 : &dma->addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
881 0 : if (error)
882 : goto free;
883 :
884 : /* allocate associated dma handle and initialize it. */
885 0 : error = bus_dmamap_create(sc->sc_dmat, dma->size, 1, dma->size, 0,
886 : BUS_DMA_NOWAIT, &dma->map);
887 0 : if (error)
888 : goto unmap;
889 :
890 : /*
891 : * load the dma handle with mappings for a dma transfer; all pages
892 : * need to be wired.
893 : */
894 0 : error = bus_dmamap_load(sc->sc_dmat, dma->map, dma->addr, dma->size, NULL,
895 : BUS_DMA_NOWAIT);
896 0 : if (error)
897 : goto destroy;
898 :
899 0 : return 0;
900 :
901 : destroy:
902 0 : bus_dmamap_destroy(sc->sc_dmat, dma->map);
903 : unmap:
904 0 : bus_dmamem_unmap(sc->sc_dmat, dma->addr, dma->size);
905 : free:
906 0 : bus_dmamem_free(sc->sc_dmat, dma->segs, dma->nsegs);
907 :
908 0 : return error;
909 0 : }
910 :
911 :
912 : /* undo dma mapping and release memory allocated */
913 : int
914 0 : auixp_freemem(struct auixp_softc *sc, struct auixp_dma *p)
915 : {
916 :
917 0 : bus_dmamap_unload(sc->sc_dmat, p->map);
918 0 : bus_dmamap_destroy(sc->sc_dmat, p->map);
919 0 : bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size);
920 0 : bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs);
921 :
922 0 : return 0;
923 : }
924 :
925 : int
926 0 : auixp_match(struct device *dev, void *match, void *aux)
927 : {
928 0 : return (pci_matchbyid((struct pci_attach_args *)aux, auixp_pci_devices,
929 : sizeof(auixp_pci_devices)/sizeof(auixp_pci_devices[0])));
930 : }
931 :
932 : int
933 0 : auixp_activate(struct device *self, int act)
934 : {
935 0 : struct auixp_softc *sc = (struct auixp_softc *)self;
936 : int rv = 0;
937 :
938 0 : switch (act) {
939 : case DVACT_SUSPEND:
940 0 : auixp_disable_interrupts(sc);
941 0 : break;
942 : case DVACT_RESUME:
943 0 : auixp_init(sc);
944 0 : ac97_resume(&sc->sc_codec.host_if, sc->sc_codec.codec_if);
945 0 : rv = config_activate_children(self, act);
946 0 : break;
947 : default:
948 0 : rv = config_activate_children(self, act);
949 0 : break;
950 : }
951 0 : return (rv);
952 : }
953 :
954 : void
955 0 : auixp_attach(struct device *parent, struct device *self, void *aux)
956 : {
957 : struct auixp_softc *sc;
958 : struct pci_attach_args *pa;
959 : pcitag_t tag;
960 : pci_chipset_tag_t pc;
961 0 : pci_intr_handle_t ih;
962 : const char *intrstr;
963 :
964 0 : sc = (struct auixp_softc *)self;
965 0 : pa = (struct pci_attach_args *)aux;
966 0 : tag = pa->pa_tag;
967 0 : pc = pa->pa_pc;
968 :
969 : /* map memory; its not sized -> what is the size? max PCI slot size? */
970 0 : if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_MEM, 0,
971 0 : &sc->sc_iot, &sc->sc_ioh, &sc->sc_iob, &sc->sc_ios, 0)) {
972 0 : printf(": can't map mem space\n");
973 0 : return;
974 : }
975 :
976 : /* Initialize softc */
977 0 : sc->sc_tag = tag;
978 0 : sc->sc_pct = pc;
979 0 : sc->sc_dmat = pa->pa_dmat;
980 0 : SLIST_INIT(&sc->sc_dma_list);
981 :
982 : /* get us the auixp_dma structures */
983 0 : auixp_allocate_dma_chain(sc, &sc->sc_output_dma);
984 0 : auixp_allocate_dma_chain(sc, &sc->sc_input_dma);
985 :
986 : /* when that fails we are dead in the water */
987 0 : if (!sc->sc_output_dma || !sc->sc_input_dma)
988 0 : return;
989 :
990 : #if 0
991 : /* could preliminary program DMA chain */
992 : auixp_program_dma_chain(sc, sc->sc_output_dma);
993 : auixp_program_dma_chain(sc, sc->sc_input_dma);
994 : #endif
995 :
996 0 : if (pci_intr_map(pa, &ih)) {
997 0 : printf(": can't map interrupt\n");
998 0 : return;
999 : }
1000 0 : intrstr = pci_intr_string(pc, ih);
1001 0 : sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO | IPL_MPSAFE,
1002 0 : auixp_intr, sc, sc->sc_dev.dv_xname);
1003 0 : if (sc->sc_ih == NULL) {
1004 0 : printf(": can't establish interrupt");
1005 0 : if (intrstr != NULL)
1006 0 : printf(" at %s", intrstr);
1007 0 : printf("\n");
1008 0 : return;
1009 : }
1010 0 : printf(": %s\n", intrstr);
1011 :
1012 : /* power up chip */
1013 0 : pci_set_powerstate(pc, tag, PCI_PMCSR_STATE_D0);
1014 :
1015 : /* init chip */
1016 0 : if (auixp_init(sc) == -1) {
1017 0 : printf("%s: auixp_attach: unable to initialize the card\n",
1018 : sc->sc_dev.dv_xname);
1019 0 : return;
1020 : }
1021 :
1022 : /*
1023 : * delay further configuration of codecs and audio after interrupts
1024 : * are enabled.
1025 : */
1026 0 : config_mountroot(self, auixp_post_config);
1027 0 : }
1028 :
1029 : /* called from autoconfigure system when interrupts are enabled */
1030 : void
1031 0 : auixp_post_config(struct device *self)
1032 : {
1033 0 : struct auixp_softc *sc = (struct auixp_softc *)self;
1034 :
1035 : /* detect the AC97 codecs */
1036 0 : auixp_autodetect_codecs(sc);
1037 :
1038 : /* Bail if no codecs attached. */
1039 0 : if (!sc->sc_codec.present) {
1040 0 : printf("%s: no codecs detected or initialised\n",
1041 0 : sc->sc_dev.dv_xname);
1042 0 : return;
1043 : }
1044 :
1045 0 : audio_attach_mi(&auixp_hw_if, &sc->sc_codec, &sc->sc_dev);
1046 :
1047 : #if notyet
1048 : /* copy formats and invalidate entries not suitable for codec0 */
1049 : sc->has_4ch = AC97_IS_4CH(sc->sc_codec.codec_if);
1050 : sc->has_6ch = AC97_IS_6CH(sc->sc_codec.codec_if);
1051 : sc->is_fixed = AC97_IS_FIXED_RATE(sc->sc_codec.codec_if);
1052 : sc->has_spdif = AC97_HAS_SPDIF(sc->sc_codec.codec_if);
1053 : #endif
1054 :
1055 0 : if (sc->has_spdif)
1056 0 : sc->has_spdif = 0;
1057 :
1058 : /* fill in the missing details about the dma channels. */
1059 : /* for output */
1060 0 : sc->sc_output_dma->linkptr = ATI_REG_OUT_DMA_LINKPTR;
1061 0 : sc->sc_output_dma->dma_enable_bit = ATI_REG_CMD_OUT_DMA_EN |
1062 : ATI_REG_CMD_SEND_EN;
1063 : /* have spdif? then this too! XXX not seeing LED yet! XXX */
1064 0 : if (sc->has_spdif)
1065 0 : sc->sc_output_dma->dma_enable_bit |= ATI_REG_CMD_SPDF_OUT_EN;
1066 :
1067 : /* and for input */
1068 0 : sc->sc_input_dma->linkptr = ATI_REG_IN_DMA_LINKPTR;
1069 0 : sc->sc_input_dma->dma_enable_bit = ATI_REG_CMD_IN_DMA_EN |
1070 : ATI_REG_CMD_RECEIVE_EN;
1071 :
1072 : /* done! now enable all interrupts we can service */
1073 0 : auixp_enable_interrupts(sc);
1074 0 : }
1075 :
1076 : void
1077 0 : auixp_enable_interrupts(struct auixp_softc *sc)
1078 : {
1079 : bus_space_tag_t iot;
1080 : bus_space_handle_t ioh;
1081 : u_int32_t value;
1082 :
1083 0 : iot = sc->sc_iot;
1084 0 : ioh = sc->sc_ioh;
1085 : /* clear all pending */
1086 0 : bus_space_write_4(iot, ioh, ATI_REG_ISR, 0xffffffff);
1087 :
1088 : /* enable all relevant interrupt sources we can handle */
1089 0 : value = bus_space_read_4(iot, ioh, ATI_REG_IER);
1090 :
1091 0 : value |= ATI_REG_IER_IO_STATUS_EN;
1092 : #ifdef notyet
1093 : value |= ATI_REG_IER_IN_XRUN_EN;
1094 : value |= ATI_REG_IER_OUT_XRUN_EN;
1095 :
1096 : value |= ATI_REG_IER_SPDIF_XRUN_EN;
1097 : value |= ATI_REG_IER_SPDF_STATUS_EN;
1098 : #endif
1099 :
1100 0 : bus_space_write_4(iot, ioh, ATI_REG_IER, value);
1101 0 : }
1102 :
1103 : void
1104 0 : auixp_disable_interrupts(struct auixp_softc *sc)
1105 : {
1106 : bus_space_tag_t iot;
1107 : bus_space_handle_t ioh;
1108 :
1109 0 : iot = sc->sc_iot;
1110 0 : ioh = sc->sc_ioh;
1111 : /* disable all interrupt sources */
1112 0 : bus_space_write_4(iot, ioh, ATI_REG_IER, 0);
1113 :
1114 : /* clear all pending */
1115 0 : bus_space_write_4(iot, ioh, ATI_REG_ISR, 0xffffffff);
1116 0 : }
1117 :
1118 : /* dismantle what we've set up by undoing setup */
1119 : int
1120 0 : auixp_detach(struct device *self, int flags)
1121 : {
1122 : struct auixp_softc *sc;
1123 :
1124 0 : sc = (struct auixp_softc *)self;
1125 : /* XXX shouldn't we just reset the chip? XXX */
1126 : /*
1127 : * should we explicitly disable interrupt generation and acknowledge
1128 : * what's left on? better be safe than sorry.
1129 : */
1130 0 : auixp_disable_interrupts(sc);
1131 :
1132 : /* tear down .... */
1133 0 : config_detach(&sc->sc_dev, flags); /* XXX OK? XXX */
1134 :
1135 0 : if (sc->sc_ih != NULL)
1136 0 : pci_intr_disestablish(sc->sc_pct, sc->sc_ih);
1137 0 : if (sc->sc_ios)
1138 0 : bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
1139 0 : return 0;
1140 : }
1141 :
1142 :
1143 : /*
1144 : * codec handling
1145 : *
1146 : * IXP audio support can have upto 3 codecs! are they chained ? or
1147 : * alternative outlets with the same audio feed i.e. with different mixer
1148 : * settings? XXX does NetBSD support more than one audio codec? XXX
1149 : */
1150 :
1151 :
1152 : int
1153 0 : auixp_attach_codec(void *aux, struct ac97_codec_if *codec_if)
1154 : {
1155 : struct auixp_codec *ixp_codec;
1156 :
1157 0 : ixp_codec = aux;
1158 0 : ixp_codec->codec_if = codec_if;
1159 :
1160 0 : return 0;
1161 : }
1162 :
1163 : int
1164 0 : auixp_read_codec(void *aux, u_int8_t reg, u_int16_t *result)
1165 : {
1166 : struct auixp_codec *co;
1167 : struct auixp_softc *sc;
1168 : bus_space_tag_t iot;
1169 : bus_space_handle_t ioh;
1170 : u_int32_t data;
1171 : int timeout;
1172 :
1173 0 : co = aux;
1174 0 : sc = co->sc;
1175 0 : iot = sc->sc_iot;
1176 0 : ioh = sc->sc_ioh;
1177 0 : if (auixp_wait_for_codecs(sc, "read_codec"))
1178 0 : return 0xffff;
1179 :
1180 : /* build up command for reading codec register */
1181 0 : data = (reg << ATI_REG_PHYS_OUT_ADDR_SHIFT) |
1182 0 : ATI_REG_PHYS_OUT_ADDR_EN |
1183 0 : ATI_REG_PHYS_OUT_RW |
1184 0 : co->codec_nr;
1185 :
1186 0 : bus_space_write_4(iot, ioh, ATI_REG_PHYS_OUT_ADDR, data);
1187 :
1188 0 : if (auixp_wait_for_codecs(sc, "read_codec"))
1189 0 : return 0xffff;
1190 :
1191 : /* wait until codec info is clocked in */
1192 : timeout = 500; /* 500*2 usec -> 0.001 sec */
1193 0 : do {
1194 0 : data = bus_space_read_4(iot, ioh, ATI_REG_PHYS_IN_ADDR);
1195 0 : if (data & ATI_REG_PHYS_IN_READ_FLAG) {
1196 : DPRINTF(("read ac'97 codec reg 0x%x = 0x%08x\n",
1197 : reg, data >> ATI_REG_PHYS_IN_DATA_SHIFT));
1198 0 : *result = data >> ATI_REG_PHYS_IN_DATA_SHIFT;
1199 0 : return 0;
1200 : }
1201 0 : DELAY(2);
1202 0 : timeout--;
1203 0 : } while (timeout > 0);
1204 :
1205 0 : if (reg < 0x7c)
1206 0 : printf("%s: codec read timeout! (reg %x)\n",
1207 0 : sc->sc_dev.dv_xname, reg);
1208 :
1209 0 : return 0xffff;
1210 0 : }
1211 :
1212 : int
1213 0 : auixp_write_codec(void *aux, u_int8_t reg, u_int16_t data)
1214 : {
1215 : struct auixp_codec *co;
1216 : struct auixp_softc *sc;
1217 : bus_space_tag_t iot;
1218 : bus_space_handle_t ioh;
1219 : u_int32_t value;
1220 :
1221 : DPRINTF(("write ac'97 codec reg 0x%x = 0x%08x\n", reg, data));
1222 0 : co = aux;
1223 0 : sc = co->sc;
1224 0 : iot = sc->sc_iot;
1225 0 : ioh = sc->sc_ioh;
1226 0 : if (auixp_wait_for_codecs(sc, "write_codec"))
1227 0 : return -1;
1228 :
1229 : /* build up command for writing codec register */
1230 0 : value = (((u_int32_t) data) << ATI_REG_PHYS_OUT_DATA_SHIFT) |
1231 0 : (((u_int32_t) reg) << ATI_REG_PHYS_OUT_ADDR_SHIFT) |
1232 0 : ATI_REG_PHYS_OUT_ADDR_EN |
1233 0 : co->codec_nr;
1234 :
1235 0 : bus_space_write_4(iot, ioh, ATI_REG_PHYS_OUT_ADDR, value);
1236 :
1237 0 : return 0;
1238 0 : }
1239 :
1240 : void
1241 0 : auixp_reset_codec(void *aux)
1242 : {
1243 :
1244 : /* nothing to be done? */
1245 0 : }
1246 :
1247 : enum ac97_host_flags
1248 0 : auixp_flags_codec(void *aux)
1249 : {
1250 : struct auixp_codec *ixp_codec;
1251 :
1252 0 : ixp_codec = aux;
1253 0 : return ixp_codec->codec_flags;
1254 : }
1255 :
1256 : int
1257 0 : auixp_wait_for_codecs(struct auixp_softc *sc, const char *func)
1258 : {
1259 : bus_space_tag_t iot;
1260 : bus_space_handle_t ioh;
1261 : u_int32_t value;
1262 : int timeout;
1263 :
1264 0 : iot = sc->sc_iot;
1265 0 : ioh = sc->sc_ioh;
1266 : /* wait until all codec transfers are done */
1267 : timeout = 500; /* 500*2 usec -> 0.001 sec */
1268 0 : do {
1269 0 : value = bus_space_read_4(iot, ioh, ATI_REG_PHYS_OUT_ADDR);
1270 0 : if ((value & ATI_REG_PHYS_OUT_ADDR_EN) == 0)
1271 0 : return 0;
1272 :
1273 0 : DELAY(2);
1274 0 : timeout--;
1275 0 : } while (timeout > 0);
1276 :
1277 0 : printf("%s: %s: timed out\n", func, sc->sc_dev.dv_xname);
1278 0 : return -1;
1279 0 : }
1280 :
1281 : void
1282 0 : auixp_autodetect_codecs(struct auixp_softc *sc)
1283 : {
1284 : bus_space_tag_t iot;
1285 : bus_space_handle_t ioh;
1286 : pcireg_t subdev;
1287 : struct auixp_codec *codec;
1288 : int timeout;
1289 :
1290 0 : iot = sc->sc_iot;
1291 0 : ioh = sc->sc_ioh;
1292 0 : subdev = pci_conf_read(sc->sc_pct, sc->sc_tag, PCI_SUBSYS_ID_REG);
1293 :
1294 : /* ATI IXP can have upto 3 codecs; mark all codecs as not existing */
1295 0 : sc->sc_codec_not_ready_bits = 0;
1296 :
1297 : /* enable all codecs to interrupt as well as the new frame interrupt */
1298 0 : bus_space_write_4(iot, ioh, ATI_REG_IER, CODEC_CHECK_BITS);
1299 :
1300 : /* wait for the interrupts to happen */
1301 : timeout = 100; /* 100.000 usec -> 0.1 sec */
1302 :
1303 0 : while (timeout > 0) {
1304 0 : DELAY(1000);
1305 0 : if (sc->sc_codec_not_ready_bits)
1306 : break;
1307 0 : timeout--;
1308 : }
1309 :
1310 0 : if (timeout == 0)
1311 0 : printf("%s: WARNING: timeout during codec detection; "
1312 : "codecs might be present but haven't interrupted\n",
1313 0 : sc->sc_dev.dv_xname);
1314 :
1315 : /* disable all interrupts for now */
1316 0 : auixp_disable_interrupts(sc);
1317 :
1318 : /* Attach AC97 host interfaces */
1319 0 : codec = &sc->sc_codec;
1320 0 : bzero(codec, sizeof(struct auixp_codec));
1321 :
1322 0 : codec->sc = sc;
1323 :
1324 0 : codec->host_if.arg = codec;
1325 0 : codec->host_if.attach = auixp_attach_codec;
1326 0 : codec->host_if.read = auixp_read_codec;
1327 0 : codec->host_if.write = auixp_write_codec;
1328 0 : codec->host_if.reset = auixp_reset_codec;
1329 0 : codec->host_if.flags = auixp_flags_codec;
1330 0 : switch (subdev) {
1331 : case 0x1311462: /* MSI S270 */
1332 : case 0x1611462: /* LG K1 Express */
1333 : case 0x3511462: /* MSI L725 */
1334 : case 0x4711462: /* MSI L720 */
1335 : case 0x0611462: /* MSI S250 */
1336 0 : codec->codec_flags = AC97_HOST_ALC650_PIN47_IS_EAPD;
1337 0 : break;
1338 : }
1339 :
1340 0 : if (!(sc->sc_codec_not_ready_bits & ATI_REG_ISR_CODEC0_NOT_READY)) {
1341 : /* codec 0 present */
1342 : DPRINTF(("auixp : YAY! codec 0 present!\n"));
1343 0 : if (ac97_attach(&sc->sc_codec.host_if) == 0) {
1344 0 : sc->sc_codec.codec_nr = 0;
1345 0 : sc->sc_codec.present = 1;
1346 0 : return;
1347 : }
1348 : }
1349 :
1350 0 : if (!(sc->sc_codec_not_ready_bits & ATI_REG_ISR_CODEC1_NOT_READY)) {
1351 : /* codec 1 present */
1352 : DPRINTF(("auixp : YAY! codec 1 present!\n"));
1353 0 : if (ac97_attach(&sc->sc_codec.host_if) == 0) {
1354 0 : sc->sc_codec.codec_nr = 1;
1355 0 : sc->sc_codec.present = 1;
1356 0 : return;
1357 : }
1358 : }
1359 :
1360 0 : if (!(sc->sc_codec_not_ready_bits & ATI_REG_ISR_CODEC2_NOT_READY)) {
1361 : /* codec 2 present */
1362 : DPRINTF(("auixp : YAY! codec 2 present!\n"));
1363 0 : if (ac97_attach(&sc->sc_codec.host_if) == 0) {
1364 0 : sc->sc_codec.codec_nr = 2;
1365 0 : sc->sc_codec.present = 1;
1366 0 : return;
1367 : }
1368 : }
1369 0 : }
1370 :
1371 : void
1372 0 : auixp_disable_dma(struct auixp_softc *sc, struct auixp_dma *dma)
1373 : {
1374 : bus_space_tag_t iot;
1375 : bus_space_handle_t ioh;
1376 : u_int32_t value;
1377 :
1378 0 : iot = sc->sc_iot;
1379 0 : ioh = sc->sc_ioh;
1380 : /* lets not stress the DMA engine more than necessary */
1381 0 : value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
1382 0 : if (value & dma->dma_enable_bit) {
1383 0 : value &= ~dma->dma_enable_bit;
1384 0 : bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
1385 0 : }
1386 0 : }
1387 :
1388 : void
1389 0 : auixp_enable_dma(struct auixp_softc *sc, struct auixp_dma *dma)
1390 : {
1391 : bus_space_tag_t iot;
1392 : bus_space_handle_t ioh;
1393 : u_int32_t value;
1394 :
1395 0 : iot = sc->sc_iot;
1396 0 : ioh = sc->sc_ioh;
1397 : /* lets not stress the DMA engine more than necesssary */
1398 0 : value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
1399 0 : if (!(value & dma->dma_enable_bit)) {
1400 0 : value |= dma->dma_enable_bit;
1401 0 : bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
1402 0 : }
1403 0 : }
1404 :
1405 : void
1406 0 : auixp_reset_aclink(struct auixp_softc *sc)
1407 : {
1408 : bus_space_tag_t iot;
1409 : bus_space_handle_t ioh;
1410 : u_int32_t value, timeout;
1411 :
1412 0 : iot = sc->sc_iot;
1413 0 : ioh = sc->sc_ioh;
1414 :
1415 : /* if power is down, power it up */
1416 0 : value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
1417 0 : if (value & ATI_REG_CMD_POWERDOWN) {
1418 0 : printf("%s: powering up\n", sc->sc_dev.dv_xname);
1419 :
1420 : /* explicitly enable power */
1421 0 : value &= ~ATI_REG_CMD_POWERDOWN;
1422 0 : bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
1423 :
1424 : /* have to wait at least 10 usec for it to initialise */
1425 0 : DELAY(20);
1426 0 : };
1427 :
1428 0 : printf("%s: soft resetting aclink\n", sc->sc_dev.dv_xname);
1429 :
1430 : /* perform a soft reset */
1431 0 : value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
1432 0 : value |= ATI_REG_CMD_AC_SOFT_RESET;
1433 0 : bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
1434 :
1435 : /* need to read the CMD reg and wait aprox. 10 usec to init */
1436 0 : value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
1437 0 : DELAY(20);
1438 :
1439 : /* clear soft reset flag again */
1440 0 : value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
1441 0 : value &= ~ATI_REG_CMD_AC_SOFT_RESET;
1442 0 : bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
1443 :
1444 : /* check if the ac-link is working; reset device otherwise */
1445 : timeout = 10;
1446 0 : value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
1447 0 : while (!(value & ATI_REG_CMD_ACLINK_ACTIVE)) {
1448 0 : printf("%s: not up; resetting aclink hardware\n",
1449 : sc->sc_dev.dv_xname);
1450 :
1451 : /* dip aclink reset but keep the acsync */
1452 0 : value &= ~ATI_REG_CMD_AC_RESET;
1453 0 : value |= ATI_REG_CMD_AC_SYNC;
1454 0 : bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
1455 :
1456 : /* need to read CMD again and wait again (clocking in issue?) */
1457 0 : value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
1458 0 : DELAY(20);
1459 :
1460 : /* assert aclink reset again */
1461 0 : value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
1462 0 : value |= ATI_REG_CMD_AC_RESET;
1463 0 : bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
1464 :
1465 : /* check if its active now */
1466 0 : value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
1467 :
1468 0 : timeout--;
1469 0 : if (timeout == 0) break;
1470 : };
1471 :
1472 0 : if (timeout == 0) {
1473 0 : printf("%s: giving up aclink reset\n", sc->sc_dev.dv_xname);
1474 0 : };
1475 0 : if (timeout != 10) {
1476 0 : printf("%s: aclink hardware reset successful\n",
1477 : sc->sc_dev.dv_xname);
1478 0 : };
1479 :
1480 : /* assert reset and sync for safety */
1481 0 : value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
1482 0 : value |= ATI_REG_CMD_AC_SYNC | ATI_REG_CMD_AC_RESET;
1483 0 : bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
1484 0 : }
1485 :
1486 : /* chip hard init */
1487 : int
1488 0 : auixp_init(struct auixp_softc *sc)
1489 : {
1490 : bus_space_tag_t iot;
1491 : bus_space_handle_t ioh;
1492 : u_int32_t value;
1493 :
1494 0 : iot = sc->sc_iot;
1495 0 : ioh = sc->sc_ioh;
1496 : /* disable all interrupts and clear all sources */
1497 0 : auixp_disable_interrupts(sc);
1498 :
1499 : /* clear all DMA enables (preserving rest of settings) */
1500 0 : value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
1501 0 : value &= ~( ATI_REG_CMD_IN_DMA_EN |
1502 : ATI_REG_CMD_OUT_DMA_EN |
1503 : ATI_REG_CMD_SPDF_OUT_EN );
1504 0 : bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
1505 :
1506 : /* Reset AC-link */
1507 0 : auixp_reset_aclink(sc);
1508 :
1509 : /*
1510 : * codecs get auto-detected later
1511 : *
1512 : * note: we are NOT enabling interrupts yet, no codecs have been
1513 : * detected yet nor is anything else set up
1514 : */
1515 :
1516 0 : return 0;
1517 : }
|