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