1 /* $NetBSD: vrc4172gpio.c,v 1.19 2023/08/07 23:29:22 mrg Exp $ */
2 /*-
3 * Copyright (c) 2001 TAKEMRUA Shin. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 */
30
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: vrc4172gpio.c,v 1.19 2023/08/07 23:29:22 mrg Exp $");
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/device.h>
37 #include <sys/kmem.h>
38 #include <sys/queue.h>
39 #include <sys/reboot.h>
40 #include <machine/bus.h>
41 #include <machine/platid.h>
42 #include <machine/platid_mask.h>
43
44 #include <dev/hpc/hpciovar.h>
45
46 #include <hpcmips/vr/vripif.h>
47 #include <hpcmips/vr/vripvar.h>
48 #include <hpcmips/vr/vrc4172gpioreg.h>
49
50 #include "locators.h"
51
52 #define VRC2GPIODEBUG
53 #ifdef VRC2GPIODEBUG
54 #define DBG_IO (1<<0)
55 #define DBG_INTR (1<<1)
56 #define DBG_INFO (1<<2)
57 #ifndef VRC2GPIODEBUG_CONF
58 #define VRC2GPIODEBUG_CONF 0
59 #endif /* VRC2GPIODEBUG_CONF */
60 int vrc4172gpio_debug = VRC2GPIODEBUG_CONF;
61 #define DBG(flag) (vrc4172gpio_debug & (flag))
62 #define DPRINTF(flag, arg...) do { \
63 if (DBG(flag)) \
64 printf(arg); \
65 } while (0)
66 #else
67 #define DBG(flag) (0)
68 #define DPRINTF(flag, arg...) do {} while(0)
69 #endif
70 #define VPRINTF(arg...) do { \
71 if (bootverbose) \
72 printf(##arg); \
73 } while (0)
74
75 #define CHECK_PORT(x) (0 <= (x) && (x) < VRC2_EXGP_NPORTS)
76
77 struct vrc4172gpio_intr_entry {
78 int ih_port;
79 int (*ih_fun)(void*);
80 void *ih_arg;
81 TAILQ_ENTRY(vrc4172gpio_intr_entry) ih_link;
82 };
83
84 struct vrc4172gpio_softc {
85 bus_space_tag_t sc_iot;
86 bus_space_handle_t sc_ioh;
87 struct hpcio_attach_args sc_args;
88 struct hpcio_chip *sc_hc;
89
90 void *sc_intr_handle;
91 u_int32_t sc_intr_mask;
92 u_int32_t sc_data;
93 u_int32_t sc_intr_mode[VRC2_EXGP_NPORTS];
94 TAILQ_HEAD(, vrc4172gpio_intr_entry) sc_intr_head[VRC2_EXGP_NPORTS];
95 struct hpcio_chip sc_iochip;
96 struct hpcio_attach_args sc_haa;
97 };
98
99 int vrc4172gpio_match(device_t, cfdata_t, void *);
100 void vrc4172gpio_attach(device_t, device_t, void *);
101 void vrc4172gpio_callback(device_t);
102 int vrc4172gpio_intr(void *);
103 int vrc4172gpio_print(void *, const char *);
104
105 int vrc4172gpio_port_read(hpcio_chip_t, int);
106 void vrc4172gpio_port_write(hpcio_chip_t, int, int);
107 void *vrc4172gpio_intr_establish(hpcio_chip_t, int, int, int (*)(void *), void *);
108 void vrc4172gpio_intr_disestablish(hpcio_chip_t, void *);
109 void vrc4172gpio_intr_clear(hpcio_chip_t, void *);
110 void vrc4172gpio_register_iochip(hpcio_chip_t, hpcio_chip_t);
111 void vrc4172gpio_update(hpcio_chip_t);
112 void vrc4172gpio_dump(hpcio_chip_t);
113 void vrc4172gpio_intr_dump(struct vrc4172gpio_softc *, int);
114 hpcio_chip_t vrc4172gpio_getchip(void *, int);
115 static void vrc4172gpio_diffport(struct vrc4172gpio_softc *);
116
117 static u_int16_t read_2(struct vrc4172gpio_softc *, bus_addr_t);
118 static void write_2(struct vrc4172gpio_softc *, bus_addr_t, u_int16_t);
119 static u_int32_t read_4(struct vrc4172gpio_softc *, bus_addr_t);
120 static void write_4(struct vrc4172gpio_softc *, bus_addr_t, u_int32_t);
121 static void dumpbits(u_int32_t*, int, int, int, const char *);
122
123 static struct hpcio_chip vrc4172gpio_iochip = {
124 .hc_portread = vrc4172gpio_port_read,
125 .hc_portwrite = vrc4172gpio_port_write,
126 .hc_intr_establish = vrc4172gpio_intr_establish,
127 .hc_intr_disestablish = vrc4172gpio_intr_disestablish,
128 .hc_intr_clear = vrc4172gpio_intr_clear,
129 .hc_register_iochip = vrc4172gpio_register_iochip,
130 .hc_update = vrc4172gpio_update,
131 .hc_dump = vrc4172gpio_dump,
132 };
133
134 static int intlv_regs[] = {
135 VRC2_EXGPINTLV0L,
136 VRC2_EXGPINTLV0H,
137 VRC2_EXGPINTLV1L
138 };
139
140 CFATTACH_DECL_NEW(vrc4172gpio, sizeof(struct vrc4172gpio_softc),
141 vrc4172gpio_match, vrc4172gpio_attach, NULL, NULL);
142
143 /*
144 * register access method
145 */
146 static inline u_int16_t
read_2(struct vrc4172gpio_softc * sc,bus_addr_t off)147 read_2(struct vrc4172gpio_softc *sc, bus_addr_t off)
148 {
149 return bus_space_read_2(sc->sc_iot, sc->sc_ioh, off);
150 }
151
152 static inline void
write_2(struct vrc4172gpio_softc * sc,bus_addr_t off,u_int16_t data)153 write_2(struct vrc4172gpio_softc *sc, bus_addr_t off, u_int16_t data)
154 {
155 bus_space_write_2(sc->sc_iot, sc->sc_ioh, off, data);
156 }
157
158 static u_int32_t
read_4(struct vrc4172gpio_softc * sc,bus_addr_t off)159 read_4(struct vrc4172gpio_softc *sc, bus_addr_t off)
160 {
161 u_int16_t reg0, reg1;
162
163 reg0 = read_2(sc, off);
164 reg1 = read_2(sc, off + VRC2_EXGP_OFFSET);
165
166 return (reg0|(reg1<<16));
167 }
168
169 static void
write_4(struct vrc4172gpio_softc * sc,bus_addr_t off,u_int32_t data)170 write_4(struct vrc4172gpio_softc *sc, bus_addr_t off, u_int32_t data)
171 {
172 write_2(sc, off, data & 0xffff);
173 write_2(sc, off + VRC2_EXGP_OFFSET, (data>>16)&0xffff);
174 }
175
176 int
vrc4172gpio_match(device_t parent,cfdata_t cf,void * aux)177 vrc4172gpio_match(device_t parent, cfdata_t cf, void *aux)
178 {
179 struct hpcio_attach_args *haa = aux;
180 platid_mask_t mask;
181
182 if (strcmp(haa->haa_busname, HPCIO_BUSNAME))
183 return (0);
184 if (cf->cf_loc[HPCIOIFCF_PLATFORM] == 0)
185 return (0);
186 mask = PLATID_DEREF(cf->cf_loc[HPCIOIFCF_PLATFORM]);
187
188 return platid_match(&platid, &mask);
189 }
190
191 void
vrc4172gpio_attach(device_t parent,device_t self,void * aux)192 vrc4172gpio_attach(device_t parent, device_t self, void *aux)
193 {
194 struct hpcio_attach_args *args = aux;
195 struct vrc4172gpio_softc *sc = device_private(self);
196 int i, *loc, port, mode;
197 u_int32_t regs[6], t0, t1, t2;
198
199 printf("\n");
200 loc = device_cfdata(self)->cf_loc;
201
202 /*
203 * map bus space
204 */
205 sc->sc_iot = args->haa_iot;
206 sc->sc_hc = (*args->haa_getchip)(args->haa_sc, loc[HPCIOIFCF_IOCHIP]);
207 sc->sc_args = *args; /* structure copy */
208 bus_space_map(sc->sc_iot, loc[HPCIOIFCF_ADDR], loc[HPCIOIFCF_SIZE],
209 0 /* no cache */, &sc->sc_ioh);
210 if (sc->sc_ioh == 0) {
211 printf("%s: can't map bus space\n", device_xname(self));
212 return;
213 }
214
215 /*
216 * dump Windows CE register setting
217 */
218 regs[0] = read_4(sc, VRC2_EXGPDATA);
219 regs[1] = read_4(sc, VRC2_EXGPDIR);
220 regs[2] = read_4(sc, VRC2_EXGPINTEN);
221 regs[3] = read_4(sc, VRC2_EXGPINTTYP);
222 t0 = read_2(sc, VRC2_EXGPINTLV0L);
223 t1 = read_2(sc, VRC2_EXGPINTLV0H);
224 t2 = read_2(sc, VRC2_EXGPINTLV1L);
225 regs[4] = ((t2&0xff00)<<8) | (t1&0xff00) | ((t0&0xff00)>>8);
226 regs[5] = ((t2&0xff)<<16) | ((t1&0xff)<<8) | (t0&0xff);
227
228 if (bootverbose || DBG(DBG_INFO)) {
229 /*
230 * o: output
231 * i: input (no interrupt)
232 * H: level sense interrupt (active high)
233 * L: level sense interrupt (active low)
234 * B: both edge trigger interrupt
235 * P: positive edge trigger interrupt
236 * N: negative edge trigger interrupt
237 */
238 printf(" port#:321098765432109876543210\n");
239 printf(" EXGPDATA :");
240 dumpbits(®s[0], 1, 23, 0, "10\n");
241 printf("WIN setting:");
242 dumpbits(®s[1], 5, 23, 0,
243 "oooo" /* dir=1 en=1 typ=1 */
244 "oooo" /* dir=1 en=1 typ=0 */
245 "oooo" /* dir=1 en=0 typ=1 */
246 "oooo" /* dir=1 en=0 typ=0 */
247 "BBPN" /* dir=0 en=1 typ=1 */
248 "HLHL" /* dir=0 en=1 typ=0 */
249 "iiii" /* dir=0 en=0 typ=1 */
250 "iiii" /* dir=0 en=0 typ=0 */
251 );
252 printf("\n");
253 }
254 #ifdef VRC2GPIODEBUG
255 if (DBG(DBG_INFO)) {
256 printf(" EXGPDIR :");
257 dumpbits(®s[1], 1, 23, 0, "oi\n");
258
259 printf(" EXGPINTEN :");
260 dumpbits(®s[2], 1, 23, 0, "I-\n");
261
262 printf(" EXGPINTTYP:");
263 dumpbits(®s[3], 1, 23, 0, "EL\n");
264
265 printf(" EXPIB :");
266 dumpbits(®s[4], 1, 23, 0, "10\n");
267
268 printf(" EXPIL :");
269 dumpbits(®s[5], 1, 23, 0, "10\n");
270
271 printf(" EXGPINTLV :%04x %04x %04x\n", t2, t1, t0);
272 }
273 #endif /* VRC2GPIODEBUG */
274
275 /*
276 * initialize register and internal data
277 */
278 sc->sc_intr_mask = 0;
279 write_2(sc, VRC2_EXGPINTEN, sc->sc_intr_mask);
280 for (i = 0; i < VRC2_EXGP_NPORTS; i++)
281 TAILQ_INIT(&sc->sc_intr_head[i]);
282 sc->sc_data = read_4(sc, VRC2_EXGPDATA);
283 if (bootverbose || DBG(DBG_INFO)) {
284 u_int32_t data;
285
286 sc->sc_intr_mask = (~read_4(sc, VRC2_EXGPDIR) & 0xffffff);
287 write_4(sc, VRC2_EXGPINTTYP, 0); /* level sence interrupt */
288 data = ~read_4(sc, VRC2_EXGPDATA);
289 write_2(sc, VRC2_EXGPINTLV0L, (data >> 0) & 0xff);
290 write_2(sc, VRC2_EXGPINTLV0H, (data >> 8) & 0xff);
291 write_2(sc, VRC2_EXGPINTLV1L, (data >> 16) & 0xff);
292 }
293
294 /*
295 * install interrupt handler
296 */
297 port = loc[HPCIOIFCF_PORT];
298 mode = HPCIO_INTR_LEVEL | HPCIO_INTR_HIGH;
299 sc->sc_intr_handle =
300 hpcio_intr_establish(sc->sc_hc, port, mode, vrc4172gpio_intr, sc);
301 if (sc->sc_intr_handle == NULL) {
302 printf("%s: can't establish interrupt\n", device_xname(self));
303 return;
304 }
305
306 /*
307 * fill hpcio_chip structure
308 */
309 sc->sc_iochip = vrc4172gpio_iochip; /* structure copy */
310 sc->sc_iochip.hc_chipid = VRIP_IOCHIP_VRC4172GPIO;
311 sc->sc_iochip.hc_name = device_xname(self);
312 sc->sc_iochip.hc_sc = sc;
313 /* Register functions to upper interface */
314 hpcio_register_iochip(sc->sc_hc, &sc->sc_iochip);
315
316 /*
317 * hpcio I/F
318 */
319 sc->sc_haa.haa_busname = HPCIO_BUSNAME;
320 sc->sc_haa.haa_sc = sc;
321 sc->sc_haa.haa_getchip = vrc4172gpio_getchip;
322 sc->sc_haa.haa_iot = sc->sc_iot;
323 while (config_found(self, &sc->sc_haa, vrc4172gpio_print, CFARGS_NONE)) ;
324 /*
325 * GIU-ISA bridge
326 */
327 #if 1 /* XXX Sometimes mounting root device failed. Why? XXX*/
328 config_defer(self, vrc4172gpio_callback);
329 #else
330 vrc4172gpio_callback(self);
331 #endif
332 }
333
334 void
vrc4172gpio_callback(device_t self)335 vrc4172gpio_callback(device_t self)
336 {
337 struct vrc4172gpio_softc *sc = device_private(self);
338
339 sc->sc_haa.haa_busname = "vrisab";
340 config_found(self, &sc->sc_haa, vrc4172gpio_print, CFARGS_NONE);
341 }
342
343 int
vrc4172gpio_print(void * aux,const char * pnp)344 vrc4172gpio_print(void *aux, const char *pnp)
345 {
346 if (pnp)
347 return (QUIET);
348 return (UNCONF);
349 }
350
351 /*
352 * PORT
353 */
354 int
vrc4172gpio_port_read(hpcio_chip_t hc,int port)355 vrc4172gpio_port_read(hpcio_chip_t hc, int port)
356 {
357 struct vrc4172gpio_softc *sc = hc->hc_sc;
358 int on;
359
360 if (!CHECK_PORT(port))
361 panic("%s: illegal gpio port", __func__);
362
363 on = (read_4(sc, VRC2_EXGPDATA) & (1 << port));
364
365 return (on ? 1 : 0);
366 }
367
368 void
vrc4172gpio_port_write(hpcio_chip_t hc,int port,int onoff)369 vrc4172gpio_port_write(hpcio_chip_t hc, int port, int onoff)
370 {
371 struct vrc4172gpio_softc *sc = hc->hc_sc;
372 u_int32_t data;
373
374 if (!CHECK_PORT(port))
375 panic("%s: illegal gpio port", __func__);
376 data = read_4(sc, VRC2_EXGPDATA);
377 if (onoff)
378 data |= (1<<port);
379 else
380 data &= ~(1<<port);
381 write_4(sc, VRC2_EXGPDATA, data);
382 }
383
384 void
vrc4172gpio_update(hpcio_chip_t hc)385 vrc4172gpio_update(hpcio_chip_t hc)
386 {
387 }
388
389 void
vrc4172gpio_intr_dump(struct vrc4172gpio_softc * sc,int port)390 vrc4172gpio_intr_dump(struct vrc4172gpio_softc *sc, int port)
391 {
392 u_int32_t mask, mask2;
393 int intlv_reg;
394
395 mask = (1 << port);
396 mask2 = (1 << (port % 8));
397 intlv_reg = intlv_regs[port/8];
398
399 if (read_4(sc, VRC2_EXGPDIR) & mask) {
400 printf(" output");
401 return;
402 }
403 printf(" input");
404
405 if (read_4(sc, VRC2_EXGPINTTYP) & mask) {
406 if (read_4(sc, intlv_reg) & (mask2 << 8)) {
407 printf(", both edge");
408 } else {
409 if (read_4(sc, intlv_reg) & mask2)
410 printf(", positive edge");
411 else
412 printf(", negative edge");
413 }
414 } else {
415 if (read_4(sc, intlv_reg) & mask2)
416 printf(", high level");
417 else
418 printf(", low level");
419 }
420 }
421
422 static void
vrc4172gpio_diffport(struct vrc4172gpio_softc * sc)423 vrc4172gpio_diffport(struct vrc4172gpio_softc *sc)
424 {
425 u_int32_t data;
426 data = read_4(sc, VRC2_EXGPDATA);
427 if (sc->sc_data != data) {
428 printf(" port# 321098765432109876543210\n");
429 printf("vrc4172data:");
430 dumpbits(&data, 1, 23, 0, "10\n");
431 /* bits which changed */
432 data = (data & ~sc->sc_data)|(~data & sc->sc_data);
433 printf(" ");
434 dumpbits(&data, 1, 23, 0, "^ \n");
435 sc->sc_data = data;
436 }
437 }
438
439 static void
dumpbits(u_int32_t * data,int ndata,int start,int end,const char * sym)440 dumpbits(u_int32_t *data, int ndata, int start, int end, const char *sym)
441 {
442 int i, j;
443
444 if (start <= end)
445 panic("%s(%d): %s", __FILE__, __LINE__, __func__);
446
447 for (i = start; end <= i; i--) {
448 int d = 0;
449 for (j = 0; j < ndata; j++)
450 d = (d << 1) | ((data[j] & (1 << i)) ? 1 : 0);
451 printf("%c", sym[(1 << ndata) - d - 1]);
452
453 }
454 if (sym[1<<ndata])
455 printf("%c", sym[1<<ndata]);
456 }
457
458 void
vrc4172gpio_dump(hpcio_chip_t hc)459 vrc4172gpio_dump(hpcio_chip_t hc)
460 {
461 }
462
463 hpcio_chip_t
vrc4172gpio_getchip(void * scx,int chipid)464 vrc4172gpio_getchip(void* scx, int chipid)
465 {
466 struct vrc4172gpio_softc *sc = scx;
467
468 return (&sc->sc_iochip);
469 }
470
471 /*
472 * Interrupt staff
473 */
474 void *
vrc4172gpio_intr_establish(hpcio_chip_t hc,int port,int mode,int (* ih_fun)(void *),void * ih_arg)475 vrc4172gpio_intr_establish(
476 hpcio_chip_t hc,
477 int port, /* GPIO pin # */
478 int mode, /* GIU trigger setting */
479 int (*ih_fun)(void*),
480 void *ih_arg)
481 {
482 struct vrc4172gpio_softc *sc = hc->hc_sc;
483 int s;
484 u_int32_t reg, mask, mask2;
485 struct vrc4172gpio_intr_entry *ih;
486 int intlv_reg;
487
488 s = splhigh();
489
490 if (!CHECK_PORT(port))
491 panic ("%s: bogus interrupt line", __func__);
492 if (sc->sc_intr_mode[port] && mode != sc->sc_intr_mode[port])
493 panic ("%s: bogus interrupt type", __func__);
494 else
495 sc->sc_intr_mode[port] = mode;
496
497 mask = (1 << port);
498 mask2 = (1 << (port % 8));
499 intlv_reg = intlv_regs[port/8];
500
501 ih = kmem_alloc(sizeof(*ih), KM_SLEEP);
502 ih->ih_port = port;
503 ih->ih_fun = ih_fun;
504 ih->ih_arg = ih_arg;
505 TAILQ_INSERT_TAIL(&sc->sc_intr_head[port], ih, ih_link);
506
507 #ifdef VRC2GPIODEBUG
508 if (DBG(DBG_INFO)) {
509 printf("port %2d:", port);
510 vrc4172gpio_intr_dump(sc, port);
511 printf("->");
512 }
513 #endif
514
515 /*
516 * Setup registers
517 */
518 /* I/O direction */
519 reg = read_4(sc, VRC2_EXGPDIR);
520 reg &= ~mask;
521 write_4(sc, VRC2_EXGPDIR, reg);
522
523 /* interrupt triger (level/edge) */
524 reg = read_4(sc, VRC2_EXGPINTTYP);
525 if (mode & HPCIO_INTR_EDGE)
526 reg |= mask; /* edge */
527 else
528 reg &= ~mask; /* level */
529 write_4(sc, VRC2_EXGPINTTYP, reg);
530
531 /* interrupt trigger option */
532 reg = read_4(sc, intlv_reg);
533 if (mode & HPCIO_INTR_EDGE) {
534 switch (mode & (HPCIO_INTR_POSEDGE | HPCIO_INTR_NEGEDGE)) {
535 case HPCIO_INTR_POSEDGE:
536 reg &= ~(mask2 << 8);
537 reg |= mask2;
538 break;
539 case HPCIO_INTR_NEGEDGE:
540 reg &= ~(mask2 << 8);
541 reg &= ~mask2;
542 break;
543 case HPCIO_INTR_POSEDGE | HPCIO_INTR_NEGEDGE:
544 default:
545 reg |= (mask2 << 8);
546 break;
547 }
548 } else {
549 if (mode & HPCIO_INTR_HIGH)
550 reg |= mask2; /* high */
551 else
552 reg &= ~mask2; /* low */
553 }
554 write_4(sc, intlv_reg, reg);
555
556 #ifdef VRC2GPIODEBUG
557 if (DBG(DBG_INFO)) {
558 vrc4172gpio_intr_dump(sc, port);
559 printf("\n");
560 }
561 #endif
562
563 /* XXX, Vrc4172 doesn't have register to set hold or through */
564
565 /*
566 * clear interrupt status and enable interrupt
567 */
568 vrc4172gpio_intr_clear(&sc->sc_iochip, ih);
569 sc->sc_intr_mask |= mask;
570 write_4(sc, VRC2_EXGPINTEN, sc->sc_intr_mask);
571
572 splx(s);
573
574 DPRINTF(DBG_INFO, "\n");
575
576 return (ih);
577 }
578
579 void
vrc4172gpio_intr_disestablish(hpcio_chip_t hc,void * arg)580 vrc4172gpio_intr_disestablish(hpcio_chip_t hc, void *arg)
581 {
582 struct vrc4172gpio_intr_entry *ihe = arg;
583 struct vrc4172gpio_softc *sc = hc->hc_sc;
584 int port = ihe->ih_port;
585 struct vrc4172gpio_intr_entry *ih;
586 int s;
587
588 s = splhigh();
589 TAILQ_FOREACH(ih, &sc->sc_intr_head[port], ih_link) {
590 if (ih == ihe) {
591 TAILQ_REMOVE(&sc->sc_intr_head[port], ih, ih_link);
592 kmem_free(ih, sizeof(*ih));
593 if (TAILQ_EMPTY(&sc->sc_intr_head[port])) {
594 /* disable interrupt */
595 sc->sc_intr_mask &= ~(1<<port);
596 write_4(sc, VRC2_EXGPINTEN,
597 sc->sc_intr_mask);
598 }
599 splx(s);
600 return;
601 }
602 }
603 panic("%s: no such a handle.", __func__);
604 /* NOTREACHED */
605 }
606
607 /* Clear interrupt */
608 void
vrc4172gpio_intr_clear(hpcio_chip_t hc,void * arg)609 vrc4172gpio_intr_clear(hpcio_chip_t hc, void *arg)
610 {
611 struct vrc4172gpio_softc *sc = hc->hc_sc;
612 struct vrc4172gpio_intr_entry *ihe = arg;
613
614 write_4(sc, VRC2_EXGPINTST, 1 << ihe->ih_port);
615 write_4(sc, VRC2_EXGPINTST, 0);
616 }
617
618 void
vrc4172gpio_register_iochip(hpcio_chip_t hc,hpcio_chip_t iochip)619 vrc4172gpio_register_iochip(hpcio_chip_t hc, hpcio_chip_t iochip)
620 {
621 struct vrc4172gpio_softc *sc = hc->hc_sc;
622
623 hpcio_register_iochip(sc->sc_hc, iochip);
624 }
625
626 /* interrupt handler */
627 int
vrc4172gpio_intr(void * arg)628 vrc4172gpio_intr(void *arg)
629 {
630 struct vrc4172gpio_softc *sc = arg;
631 int i;
632 u_int32_t reg;
633
634 /* dispatch handler */
635 reg = read_4(sc, VRC2_EXGPINTST);
636 DPRINTF(DBG_INTR, "%s: EXGPINTST=%06x\n", __func__, reg);
637 for (i = 0; i < VRC2_EXGP_NPORTS; i++) {
638 if (reg & (1 << i)) {
639 register struct vrc4172gpio_intr_entry *ih;
640
641 /*
642 * call interrupt handler
643 */
644 TAILQ_FOREACH(ih, &sc->sc_intr_head[i], ih_link) {
645 ih->ih_fun(ih->ih_arg);
646 }
647
648 /*
649 * disable interrupt if no handler is installed
650 */
651 if (TAILQ_EMPTY(&sc->sc_intr_head[i])) {
652 sc->sc_intr_mask &= ~(1 << i);
653 write_2(sc, VRC2_EXGPINTEN, sc->sc_intr_mask);
654
655 /* dump EXGPDATA bits which changed */
656 if (bootverbose || DBG(DBG_INFO))
657 vrc4172gpio_diffport(sc);
658 }
659 }
660 }
661
662 return (0);
663 }
664