xref: /netbsd-src/sys/arch/hpcmips/tx/tx39icu.c (revision 27578b9aac214cc7796ead81dcc5427e79d5f2a0)
1 /*	$NetBSD: tx39icu.c,v 1.13 2001/09/18 17:37:28 uch Exp $ */
2 
3 /*-
4  * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by UCHIYAMA Yasushi.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #include "opt_tx39_debug.h"
40 #include "opt_use_poll.h"
41 #include "opt_tx39icudebug.h"
42 #include "opt_tx39_watchdogtimer.h"
43 
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/device.h>
47 #include <sys/malloc.h>
48 #include <sys/queue.h>
49 
50 #include <mips/cpuregs.h>
51 #include <machine/bus.h>
52 
53 #include <hpcmips/tx/tx39var.h>
54 #include <hpcmips/tx/tx39icureg.h>
55 #include <hpcmips/tx/tx39clockvar.h>
56 
57 #include <machine/cpu.h>
58 #include <dev/dec/clockvar.h>
59 
60 #undef TX39ICUDEBUG_PRINT_PENDING_INTERRUPT /* For explorer. good luck! */
61 
62 #ifdef TX39ICUDEBUG
63 #define	DPRINTF(arg) printf arg
64 #else
65 #define	DPRINTF(arg)
66 #endif
67 u_int32_t tx39intrvec;
68 
69 /* IRQHIGH lines list */
70 static const struct irqhigh_list {
71 	int qh_pri; /* IRQHIGH priority */
72 	int qh_set; /* Register set */
73 	int qh_bit; /* bit offset in the register set */
74 } irqhigh_list[] = {
75 	{15,	5,	25},	/* POSPWROKINT */
76 	{15,	5,	24},	/* NEGPWROKINT */
77 	{14,	5,	30},	/* ALARMINT*/
78 	{13,	5,	29},	/* PERINT */
79 #ifdef TX391X
80 	{12,	2,	3},	/* MBUSPOSINT */
81 	{12,	2,	2},	/* MBUSNEGINT */
82 	{11,	2,	31},	/* UARTARXINT */
83 	{10,	2,	21},	/* UARTBRXINT */
84 	{9,	3,	19},	/* MFIOPOSINT19 */
85 	{9,	3,	18},	/* MFIOPOSINT18 */
86 	{9,	3,	17},	/* MFIOPOSINT17 */
87 	{9,	3,	16},	/* MFIOPOSINT16 */
88 	{8,	3,	1},	/* MFIOPOSINT1 */
89 	{8,	3,	0},	/* MFIOPOSINT0 */
90 	{8,	5,	13},	/* IOPOSINT6 */
91 	{8,	5,	12},	/* IOPOSINT5 */
92 	{7,	4,	19},	/* MFIONEGINT19 */
93 	{7,	4,	18},	/* MFIONEGINT18 */
94 	{7,	4,	17},	/* MFIONEGINT17 */
95 	{7,	4,	16},	/* MFIONEGINT16 */
96 	{6,	4,	1},	/* MFIONEGINT1 */
97 	{6,	4,	0},	/* MFIONEGINT0 */
98 	{6,	5,	6},	/* IONEGINT6 */
99 	{6,	5,	5},	/* IONEGINT5 */
100 	{5,	2,	5},	/* MBUSDMAFULLINT */
101 #endif /* TX391X */
102 #ifdef TX392X
103 	{12,	2,	31},	/* UARTARXINT */
104 	{12,	2,	21},	/* UARTBRXINT */
105 	{11,	3,	19},	/* MFIOPOSINT19 */
106 	{11,	3,	18},	/* MFIOPOSINT18 */
107 	{11,	3,	17},	/* MFIOPOSINT17 */
108 	{11,	3,	16},	/* MFIOPOSINT16 */
109 	{10,	3,	1},	/* MFIOPOSINT1 */
110 	{10,	3,	0},	/* MFIOPOSINT0 */
111 	{10,	5,	13},	/* IOPOSINT6 */
112 	{10,	5,	12},	/* IOPOSINT5 */
113 	{9,	4,	19},	/* MFIONEGINT19 */
114 	{9,	4,	18},	/* MFIONEGINT18 */
115 	{9,	4,	17},	/* MFIONEGINT17 */
116 	{9,	4,	16},	/* MFIONEGINT16 */
117 	{8,	4,	1},	/* MFIONEGINT1 */
118 	{8,	4,	0},	/* MFIONEGINT0 */
119 	{8,	5,	6},	/* IONEGINT6 */
120 	{8,	5,	5},	/* IONEGINT5 */
121 	{5,	7,	19},	/* IRRXCINT */
122 	{5,	7,	17},	/* IRRXEINT */
123 #endif /* TX392X */
124 	{4,	1,	18},	/* SNDDMACNTINT */
125 	{3,	1,	17},	/* TELDMACNTINT */
126 	{2,	1,	27},	/* CHIDMACNTINT */
127 	{1,	5,	7},	/* IOPOSINT0 */
128 	{1,	5,	0}	/* IONEGINT0 */
129 };
130 
131 struct txintr_high_entry {
132 	int	he_set;
133 	txreg_t	he_mask;
134 	int	(*he_fun)(void *);
135 	void	*he_arg;
136 	TAILQ_ENTRY(txintr_high_entry) he_link;
137 };
138 
139 #ifdef USE_POLL
140 struct txpoll_entry{
141 	int	p_cnt; /* dispatch interval */
142 	int	p_desc;
143 	int	(*p_fun)(void *);
144 	void	*p_arg;
145 	TAILQ_ENTRY(txpoll_entry) p_link;
146 };
147 int	tx39_poll_intr(void *);
148 #endif /* USE_POLL */
149 
150 struct tx39icu_softc {
151 	struct	device sc_dev;
152 	tx_chipset_tag_t sc_tc;
153 	/* IRQLOW */
154 	txreg_t	sc_le_mask[TX39_INTRSET_MAX + 1];
155 	int	(*sc_le_fun[TX39_INTRSET_MAX + 1][32])(void *);
156 	void	*sc_le_arg[TX39_INTRSET_MAX + 1][32];
157 	/* IRQHIGH */
158 	TAILQ_HEAD(, txintr_high_entry) sc_he_head[TX39_IRQHIGH_MAX];
159 	/* Register */
160 	txreg_t sc_regs[TX39_INTRSET_MAX + 1];
161 #ifdef USE_POLL
162 	unsigned sc_pollcnt;
163 	int	sc_polling;
164 	void	*sc_poll_ih;
165 	TAILQ_HEAD(, txpoll_entry) sc_p_head;
166 #endif /* USE_POLL */
167 };
168 
169 int	tx39icu_match(struct device *, struct cfdata *, void *);
170 void	tx39icu_attach(struct device *, struct device *, void *);
171 int	tx39icu_intr(u_int32_t, u_int32_t, u_int32_t, u_int32_t);
172 
173 void	tx39_intr_dump(struct tx39icu_softc *);
174 void	tx39_intr_decode(int, int *, int *);
175 void	tx39_irqhigh_disestablish(tx_chipset_tag_t, int, int, int);
176 void	tx39_irqhigh_establish(tx_chipset_tag_t, int, int, int,
177 	    int (*)(void *), void *);
178 void	tx39_irqhigh_intr(u_int32_t, u_int32_t, u_int32_t, u_int32_t);
179 int	tx39_irqhigh(int, int);
180 
181 struct cfattach tx39icu_ca = {
182 sizeof(struct tx39icu_softc), tx39icu_match, tx39icu_attach
183 };
184 
185 int
186 tx39icu_match(struct device *parent, struct cfdata *cf, void *aux)
187 {
188 return (ATTACH_FIRST);
189 }
190 
191 void
192 tx39icu_attach(struct device *parent, struct device *self, void *aux)
193 {
194 	struct txsim_attach_args *ta = aux;
195 	struct tx39icu_softc *sc = (void *)self;
196 	tx_chipset_tag_t tc = ta->ta_tc;
197 	txreg_t reg, *regs;
198 	int i;
199 
200 	printf("\n");
201 	sc->sc_tc = ta->ta_tc;
202 
203 	regs = sc->sc_regs;
204 	regs[0] = tx_conf_read(tc, TX39_INTRSTATUS6_REG);
205 	regs[1] = tx_conf_read(tc, TX39_INTRSTATUS1_REG);
206 	regs[2] = tx_conf_read(tc, TX39_INTRSTATUS2_REG);
207 	regs[3] = tx_conf_read(tc, TX39_INTRSTATUS3_REG);
208 	regs[4] = tx_conf_read(tc, TX39_INTRSTATUS4_REG);
209 	regs[5] = tx_conf_read(tc, TX39_INTRSTATUS5_REG);
210 #ifdef TX392X
211 	regs[7] = tx_conf_read(tc, TX39_INTRSTATUS7_REG);
212 	regs[8] = tx_conf_read(tc, TX39_INTRSTATUS8_REG);
213 #endif
214 #ifdef TX39ICUDEBUG
215 	printf("\t[Windows CE setting]\n");
216 	tx39_intr_dump(sc);
217 #endif /* TX39ICUDEBUG */
218 
219 #ifdef WINCE_DEFAULT_SETTING
220 #warning WINCE_DEFAULT_SETTING
221 #else /* WINCE_DEFAULT_SETTING */
222 	/* Disable IRQLOW */
223 	tx_conf_write(tc, TX39_INTRENABLE1_REG, 0);
224 	tx_conf_write(tc, TX39_INTRENABLE2_REG, 0);
225 	tx_conf_write(tc, TX39_INTRENABLE3_REG, 0);
226 	tx_conf_write(tc, TX39_INTRENABLE4_REG, 0);
227 	tx_conf_write(tc, TX39_INTRENABLE5_REG, 0);
228 #ifdef TX392X
229 	tx_conf_write(tc, TX39_INTRENABLE7_REG, 0);
230 	tx_conf_write(tc, TX39_INTRENABLE8_REG, 0);
231 #endif /* TX392X */
232 
233 	/* Disable IRQHIGH */
234 	reg = tx_conf_read(tc, TX39_INTRENABLE6_REG);
235 	reg &= ~TX39_INTRENABLE6_PRIORITYMASK_MASK;
236 	tx_conf_write(tc, TX39_INTRENABLE6_REG, reg);
237 #endif /* WINCE_DEFAULT_SETTING */
238 
239 	/* Clear all pending interrupts */
240 	tx_conf_write(tc, TX39_INTRCLEAR1_REG,
241 	    tx_conf_read(tc, TX39_INTRSTATUS1_REG));
242 	tx_conf_write(tc, TX39_INTRCLEAR2_REG,
243 	    tx_conf_read(tc, TX39_INTRSTATUS2_REG));
244 	tx_conf_write(tc, TX39_INTRCLEAR3_REG,
245 	    tx_conf_read(tc, TX39_INTRSTATUS3_REG));
246 	tx_conf_write(tc, TX39_INTRCLEAR4_REG,
247 	    tx_conf_read(tc, TX39_INTRSTATUS4_REG));
248 	tx_conf_write(tc, TX39_INTRCLEAR5_REG,
249 	    tx_conf_read(tc, TX39_INTRSTATUS5_REG));
250 #ifdef TX392X
251 	tx_conf_write(tc, TX39_INTRCLEAR7_REG,
252 	    tx_conf_read(tc, TX39_INTRSTATUS7_REG));
253 	tx_conf_write(tc, TX39_INTRCLEAR8_REG,
254 	    tx_conf_read(tc, TX39_INTRSTATUS8_REG));
255 #endif /* TX392X */
256 
257 	/* Enable global interrupts */
258 	reg = tx_conf_read(tc, TX39_INTRENABLE6_REG);
259 	reg |= TX39_INTRENABLE6_GLOBALEN;
260 	tx_conf_write(tc, TX39_INTRENABLE6_REG, reg);
261 
262 	/* Initialize IRQHIGH interrupt handler holder*/
263 	for (i = 0; i < TX39_IRQHIGH_MAX; i++) {
264 		TAILQ_INIT(&sc->sc_he_head[i]);
265 	}
266 #ifdef USE_POLL
267 	/* Initialize polling handler holder */
268 	TAILQ_INIT(&sc->sc_p_head);
269 #endif /* USE_POLL */
270 
271 	/* Register interrupt module myself */
272 	tx_conf_register_intr(tc, self);
273 }
274 
275 int
276 tx39icu_intr(u_int32_t status, u_int32_t cause, u_int32_t pc,
277     u_int32_t ipending)
278 {
279 	struct tx39icu_softc *sc;
280 	tx_chipset_tag_t tc;
281 	txreg_t reg, pend, *regs;
282 	int i, j;
283 
284 	tc = tx_conf_get_tag();
285 	sc = tc->tc_intrt;
286 	/*
287 	 * Read regsiter ASAP
288 	 */
289 	regs = sc->sc_regs;
290 	regs[0] = tx_conf_read(tc, TX39_INTRSTATUS6_REG);
291 	regs[1] = tx_conf_read(tc, TX39_INTRSTATUS1_REG);
292 	regs[2] = tx_conf_read(tc, TX39_INTRSTATUS2_REG);
293 	regs[3] = tx_conf_read(tc, TX39_INTRSTATUS3_REG);
294 	regs[4] = tx_conf_read(tc, TX39_INTRSTATUS4_REG);
295 	regs[5] = tx_conf_read(tc, TX39_INTRSTATUS5_REG);
296 #ifdef TX392X
297 	regs[7] = tx_conf_read(tc, TX39_INTRSTATUS7_REG);
298 	regs[8] = tx_conf_read(tc, TX39_INTRSTATUS8_REG);
299 #endif
300 
301 #ifdef TX39ICUDEBUG
302 	if (!(ipending & MIPS_INT_MASK_4) && !(ipending & MIPS_INT_MASK_2)) {
303 		bitdisp(ipending);
304 		panic("bogus HwInt");
305 	}
306 #ifdef TX39_DEBUG
307 	if (tx39debugflag) {
308 		tx39_intr_dump(sc);
309 	}
310 #endif
311 #endif /* TX39ICUDEBUG */
312 
313 	/* IRQHIGH */
314 	if (ipending & MIPS_INT_MASK_4) {
315 		tx39_irqhigh_intr(ipending, pc, status, cause);
316 
317 		return (0);
318 	}
319 
320 	/* IRQLOW */
321 	if (ipending & MIPS_INT_MASK_2) {
322 		for (i = 1; i <= TX39_INTRSET_MAX; i++) {
323 			int ofs;
324 #ifdef TX392X
325 			if (i == 6)
326 				continue;
327 #endif /* TX392X */
328 			ofs = TX39_INTRSTATUS_REG(i);
329 			pend = sc->sc_regs[i];
330 			reg = sc->sc_le_mask[i] & pend;
331 			/* Clear interrupts */
332 			tx_conf_write(tc, ofs, reg);
333 			/* Dispatch handler */
334 			for (j = 0 ; j < 32; j++) {
335 				if ((reg & (1 << j)) &&
336 				    sc->sc_le_fun[i][j]) {
337 #ifdef TX39_DEBUG
338 					tx39intrvec = (i << 16) | j;
339 					if (tx39debugflag) {
340 						DPRINTF(("IRQLOW %d:%d\n",
341 						    i, j));
342 					}
343 #endif /* TX39_DEBUG */
344 					(*sc->sc_le_fun[i][j])
345 					    (sc->sc_le_arg[i][j]);
346 
347 				}
348 			}
349 #ifdef TX39ICUDEBUG_PRINT_PENDING_INTERRUPT
350 			pend &= ~reg;
351 			if (pend) {
352 				printf("%d pending:", i);
353 				__bitdisp(pend, 0, 31, 0, 1);
354 			}
355 #endif
356 
357 		}
358 	}
359 #ifdef TX39_WATCHDOGTIMER
360 	{
361 		extern int	tx39biu_intr(void *);
362 		/* Bus error (If watch dog timer is enabled)*/
363 		if (ipending & MIPS_INT_MASK_1) {
364 			tx39biu_intr(0); /* Clear bus error */
365 		}
366 	}
367 #endif
368 #if 0
369 	/* reset priority mask */
370 	reg = tx_conf_read(tc, TX39_INTRENABLE6_REG);
371 	reg = TX39_INTRENABLE6_PRIORITYMASK_SET(reg, 0xffff);
372 	tx_conf_write(tc, TX39_INTRENABLE6_REG, reg);
373 #endif
374 	return (MIPS_SR_INT_IE | (status & ~cause & MIPS_HARD_INT_MASK));
375 }
376 
377 int
378 tx39_irqhigh(int set, int bit)
379 {
380 	int i, n;
381 
382 	n = sizeof irqhigh_list / sizeof (struct irqhigh_list);
383 	for (i = 0; i < n; i++) {
384 		if (irqhigh_list[i].qh_set == set &&
385 		    irqhigh_list[i].qh_bit == bit)
386 			return (irqhigh_list[i].qh_pri);
387 	}
388 
389 	return (0);
390 }
391 
392 void
393 tx39_irqhigh_intr(u_int32_t ipending, u_int32_t pc, u_int32_t status,
394     u_int32_t cause)
395 {
396 	struct txintr_high_entry *he;
397 	struct tx39icu_softc *sc;
398 	struct clockframe cf;
399 	tx_chipset_tag_t tc;
400 	int i, pri, ofs, set;
401 	txreg_t he_mask;
402 
403 	tc = tx_conf_get_tag();
404 	sc = tc->tc_intrt;
405 	pri = TX39_INTRSTATUS6_INTVECT(sc->sc_regs[0]);
406 
407 	if (pri == TX39_INTRPRI13_TIMER_PERIODIC) {
408 		tx_conf_write(tc, TX39_INTRCLEAR5_REG,
409 		    TX39_INTRSTATUS5_PERINT);
410 		cf.pc = pc;
411 		cf.sr = status;
412 		hardclock(&cf);
413 		intrcnt[HARDCLOCK]++;
414 
415 		return;
416 	}
417 
418 	/* Handle all pending IRQHIGH interrupts */
419 	for (i = pri; i > 0; i--) {
420 		TAILQ_FOREACH(he, &sc->sc_he_head[i], he_link) {
421 			set = he->he_set;
422 			he_mask = he->he_mask;
423 			if (he_mask & (sc->sc_regs[set])) {
424 				ofs = TX39_INTRSTATUS_REG(set);
425 				/* Clear interrupt */
426 				tx_conf_write(tc, ofs, he_mask);
427 #ifdef TX39_DEBUG
428 				tx39intrvec = (set << 16) |
429 				    (ffs(he_mask) - 1);
430 				if (tx39debugflag) {
431 					DPRINTF(("IRQHIGH: %d:%d\n",
432 					    set, ffs(he_mask) - 1));
433 				}
434 #endif /* TX39_DEBUG */
435 				/* Dispatch handler */
436 				(*he->he_fun)(he->he_arg);
437 			}
438 		}
439 	}
440 }
441 
442 void
443 tx39_intr_decode(int intr, int *set, int *bit)
444 {
445 	if (!intr || intr >= (TX39_INTRSET_MAX + 1) * 32
446 #ifdef TX392X
447 	    || intr == 6
448 #endif /* TX392X */
449 	    ) {
450 		panic("tx39icu_decode: bogus intrrupt line. %d", intr);
451 	}
452 	*set = intr / 32;
453 	*bit = intr % 32;
454 }
455 
456 void
457 tx39_irqhigh_establish(tx_chipset_tag_t tc, int set, int bit, int pri,
458     int (*ih_fun)(void *), void *ih_arg)
459 {
460 	struct tx39icu_softc *sc;
461 	struct txintr_high_entry *he;
462 	txreg_t reg;
463 
464 	sc = tc->tc_intrt;
465 	/*
466 	 *	Add new entry to `pri' priority
467 	 */
468 	if (!(he = malloc(sizeof(struct txintr_high_entry),
469 	    M_DEVBUF, M_NOWAIT))) {
470 		panic ("tx39_irqhigh_establish: no memory.");
471 	}
472 	memset(he, 0, sizeof(struct txintr_high_entry));
473 	he->he_set = set;
474 	he->he_mask= (1 << bit);
475 	he->he_fun = ih_fun;
476 	he->he_arg = ih_arg;
477 	TAILQ_INSERT_TAIL(&sc->sc_he_head[pri], he, he_link);
478 	/*
479 	 *	Enable interrupt on this priority.
480 	 */
481 	reg = tx_conf_read(tc, TX39_INTRENABLE6_REG);
482 	reg = TX39_INTRENABLE6_PRIORITYMASK_SET(reg, (1 << pri));
483 	tx_conf_write(tc, TX39_INTRENABLE6_REG, reg);
484 }
485 
486 void
487 tx39_irqhigh_disestablish(tx_chipset_tag_t tc, int set, int bit, int pri)
488 {
489 	struct tx39icu_softc *sc;
490 	struct txintr_high_entry *he;
491 	txreg_t reg;
492 
493 	sc = tc->tc_intrt;
494 	TAILQ_FOREACH(he, &sc->sc_he_head[pri], he_link) {
495 		if (he->he_set == set && he->he_mask == (1 << bit)) {
496 			TAILQ_REMOVE(&sc->sc_he_head[pri], he, he_link);
497 			free(he, M_DEVBUF);
498 			break;
499 		}
500 	}
501 
502 	if (TAILQ_EMPTY(&sc->sc_he_head[pri])) {
503 		reg = tx_conf_read(tc, TX39_INTRENABLE6_REG);
504 		reg &= ~(1 << pri);
505 		tx_conf_write(tc, TX39_INTRENABLE6_REG, reg);
506 	}
507 }
508 
509 
510 void *
511 tx_intr_establish(tx_chipset_tag_t tc, int line, int mode, int level,
512     int (*ih_fun)(void *), void *ih_arg)
513 {
514 	struct tx39icu_softc *sc;
515 	txreg_t reg;
516 	int bit, set, highpri, ofs;
517 
518 	sc = tc->tc_intrt;
519 
520 	tx39_intr_decode(line, &set, &bit);
521 
522 	sc->sc_le_fun[set][bit] = ih_fun;
523 	sc->sc_le_arg[set][bit] = ih_arg;
524 	DPRINTF(("tx_intr_establish: %d:%d", set, bit));
525 
526 	if ((highpri = tx39_irqhigh(set, bit))) {
527 		tx39_irqhigh_establish(tc, set, bit, highpri,
528 		    ih_fun, ih_arg);
529 		DPRINTF(("(high)\n"));
530 	} else {
531 		/* Set mask for acknowledge. */
532 		sc->sc_le_mask[set] |= (1 << bit);
533 		/* Enable interrupt */
534 		ofs = TX39_INTRENABLE_REG(set);
535 		reg = tx_conf_read(tc, ofs);
536 		reg |= (1 << bit);
537 		tx_conf_write(tc, ofs, reg);
538 		DPRINTF(("(low)\n"));
539 	}
540 
541 	return ((void *)line);
542 }
543 
544 void
545 tx_intr_disestablish(tx_chipset_tag_t tc, void *arg)
546 {
547 	struct tx39icu_softc *sc;
548 	int set, bit, highpri, ofs;
549 	txreg_t reg;
550 
551 	sc = tc->tc_intrt;
552 
553 	tx39_intr_decode((int)arg, &set, &bit);
554 	DPRINTF(("tx_intr_disestablish: %d:%d", set, bit));
555 
556 	if ((highpri = tx39_irqhigh(set, bit))) {
557 		tx39_irqhigh_disestablish(tc, set, bit, highpri);
558 		DPRINTF(("(high)\n"));
559 	} else {
560 		sc->sc_le_fun[set][bit] = 0;
561 		sc->sc_le_arg[set][bit] = 0;
562 		sc->sc_le_mask[set] &= ~(1 << bit);
563 		ofs = TX39_INTRENABLE_REG(set);
564 		reg = tx_conf_read(tc, ofs);
565 		reg &= ~(1 << bit);
566 		tx_conf_write(tc, ofs, reg);
567 		DPRINTF(("(low)\n"));
568 	}
569 }
570 
571 u_int32_t
572 tx_intr_status(tx_chipset_tag_t tc, int r)
573 {
574 	struct tx39icu_softc *sc = tc->tc_intrt;
575 
576 	if (r < 0 || r >= TX39_INTRSET_MAX + 1)
577 		panic("tx_intr_status: invalid index %d", r);
578 
579 	return (u_int32_t)(sc->sc_regs[r]);
580 }
581 
582 #ifdef USE_POLL
583 void *
584 tx39_poll_establish(tx_chipset_tag_t tc, int interval, int level,
585     int (*ih_fun)(void *), void *ih_arg)
586 {
587 	struct tx39icu_softc *sc;
588 	struct txpoll_entry *p;
589 	int s;
590 	void *ret;
591 
592 	s = splhigh();
593 	sc = tc->tc_intrt;
594 
595 	if (!(p = malloc(sizeof(struct txpoll_entry),
596 	    M_DEVBUF, M_NOWAIT))) {
597 		panic ("tx39_poll_establish: no memory.");
598 	}
599 	memset(p, 0, sizeof(struct txpoll_entry));
600 
601 	p->p_fun = ih_fun;
602 	p->p_arg = ih_arg;
603 	p->p_cnt = interval;
604 
605 	if (!sc->sc_polling) {
606 		tx39clock_alarm_set(tc, 33); /* 33 msec */
607 
608 		if (!(sc->sc_poll_ih =
609 		    tx_intr_establish(
610 			    tc, MAKEINTR(5, TX39_INTRSTATUS5_ALARMINT),
611 			    IST_EDGE, level, tx39_poll_intr, sc)))  {
612 			printf("tx39_poll_establish: can't hook\n");
613 
614 			splx(s);
615 			return (0);
616 		}
617 	}
618 
619 	sc->sc_polling++;
620 	p->p_desc = sc->sc_polling;
621 	TAILQ_INSERT_TAIL(&sc->sc_p_head, p, p_link);
622 	ret = (void *)p->p_desc;
623 
624 	splx(s);
625 	return (ret);
626 }
627 
628 void
629 tx39_poll_disestablish(tx_chipset_tag_t tc, void *arg)
630 {
631 	struct tx39icu_softc *sc;
632 	struct txpoll_entry *p;
633 	int s, desc;
634 
635 	s = splhigh();
636 	sc = tc->tc_intrt;
637 
638 	desc = (int)arg;
639 	TAILQ_FOREACH(p, &sc->sc_p_head, p_link) {
640 		if (p->p_desc == desc) {
641 			TAILQ_REMOVE(&sc->sc_p_head, p, p_link);
642 			free(p, M_DEVBUF);
643 			break;
644 		}
645 	}
646 
647 	if (TAILQ_EMPTY(&sc->sc_p_head)) {
648 		sc->sc_polling = 0;
649 		tx_intr_disestablish(tc, sc->sc_poll_ih);
650 	}
651 
652 	splx(s);
653 	return;
654 }
655 
656 int
657 tx39_poll_intr(void *arg)
658 {
659 	struct tx39icu_softc *sc = arg;
660 	struct txpoll_entry *p;
661 
662 	tx39clock_alarm_refill(sc->sc_tc);
663 
664 	if (!sc->sc_polling) {
665 		return (0);
666 	}
667 	sc->sc_pollcnt++;
668 	TAILQ_FOREACH(p, &sc->sc_p_head, p_link) {
669 		if (sc->sc_pollcnt % p->p_cnt == 0) {
670 			if ((*p->p_fun)(p->p_arg) == POLL_END)
671 				goto disestablish;
672 		}
673 	}
674 
675 	return (0);
676 
677  disestablish:
678 	TAILQ_REMOVE(&sc->sc_p_head, p, p_link);
679 	free(p, M_DEVBUF);
680 	if (TAILQ_EMPTY(&sc->sc_p_head)) {
681 		sc->sc_polling = 0;
682 		tx_intr_disestablish(sc->sc_tc, sc->sc_poll_ih);
683 	}
684 
685 	return (0);
686 }
687 #endif /* USE_POLL */
688 
689 void
690 tx39_intr_dump(struct tx39icu_softc *sc)
691 {
692 	tx_chipset_tag_t tc = sc->sc_tc;
693 	int i, j, ofs;
694 	txreg_t reg;
695 	char msg[16];
696 
697 	for (i = 1; i <= TX39_INTRSET_MAX; i++) {
698 #ifdef TX392X
699 		if (i == 6)
700 			continue;
701 #endif /* TX392X */
702 		for (reg = j = 0; j < 32; j++) {
703 			if (tx39_irqhigh(i, j)) {
704 				reg |= (1 << j);
705 			}
706 		}
707 		sprintf(msg, "%d high", i);
708 		__bitdisp(reg, 32, 0, msg, 1);
709 		sprintf(msg, "%d status", i);
710 		__bitdisp(sc->sc_regs[i], 0, 31, msg, 1);
711 		ofs = TX39_INTRENABLE_REG(i);
712 		reg = tx_conf_read(tc, ofs);
713 		sprintf(msg, "%d enable", i);
714 		__bitdisp(reg, 0, 31, msg, 1);
715 	}
716 	reg = sc->sc_regs[0];
717 	printf("<%s><%s> vector=%2d\t\t[6 status]\n",
718 	    reg & TX39_INTRSTATUS6_IRQHIGH ? "HI" : "--",
719 	    reg & TX39_INTRSTATUS6_IRQLOW ? "LO" : "--",
720 	    TX39_INTRSTATUS6_INTVECT(reg));
721 	reg = tx_conf_read(tc, TX39_INTRENABLE6_REG);
722 	__bitdisp(reg, 0, 18, "6 enable", 1);
723 
724 }
725