No empty .Rs/.Re
[netbsd-mini2440.git] / sys / arch / hpcmips / vr / vr4181giu.c
blobe81e195d1eb556409783d1da1ca5deb9711c28b4
1 /* $NetBSD: vr4181giu.c,v 1.1.2.3 2004/09/21 13:16:13 skrll Exp $ */
3 /*-
4 * Copyright (c) 1999-2001
5 * Shin Takemura and PocketBSD Project. All rights reserved.
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. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
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 PocketBSD project
18 * and its contributors.
19 * 4. Neither the name of the project nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, 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.
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: vr4181giu.c,v 1.1.2.3 2004/09/21 13:16:13 skrll Exp $");
40 #include <sys/param.h>
41 #include <sys/device.h>
42 #include <sys/malloc.h>
43 #include <sys/queue.h>
44 #include <sys/systm.h>
46 #include <machine/bus.h>
48 #include <hpcmips/vr/vripif.h>
49 #include <hpcmips/vr/vr4181giureg.h>
51 #define MAX_GIU4181INTR 16
53 struct vr4181giu_intr_entry {
54 int ih_port;
55 int (*ih_fun)(void *);
56 void *ih_arg;
57 TAILQ_ENTRY(vr4181giu_intr_entry) ih_link;
60 struct vr4181giu_softc {
61 struct device sc_dev;
62 bus_space_tag_t sc_iot;
63 bus_space_handle_t sc_ioh;
64 vrip_chipset_tag_t sc_vc;
65 void *sc_ih;
66 u_int32_t sc_intr_mode[MAX_GIU4181INTR];
67 TAILQ_HEAD(, vr4181giu_intr_entry)
68 sc_intr_head[MAX_GIU4181INTR];
69 struct hpcio_chip sc_iochip;
70 struct hpcio_attach_args sc_haa;
73 static int vr4181giu_match(struct device *, struct cfdata *, void *);
74 static void vr4181giu_attach(struct device *, struct device *, void *);
76 static void vr4181giu_callback(struct device *self);
77 static int vr4181giu_print(void *aux, const char *pnp);
78 static int vr4181giu_port_read(hpcio_chip_t hc, int port);
79 static void vr4181giu_port_write(hpcio_chip_t hc, int port, int onoff);
80 static void vr4181giu_update(hpcio_chip_t hc);
81 static void vr4181giu_dump(hpcio_chip_t hc);
82 static hpcio_chip_t vr4181giu_getchip(void* scx, int chipid);
83 static void *vr4181giu_intr_establish(hpcio_chip_t, int, int,
84 int (*)(void *),void *);
85 static void vr4181giu_intr_disestablish(hpcio_chip_t hc, void *arg);
86 static void vr4181giu_intr_clear(hpcio_chip_t hc, void *arg);
87 static void vr4181giu_register_iochip(hpcio_chip_t hc, hpcio_chip_t iochip);
88 static int vr4181giu_intr(void *arg);
92 static struct hpcio_chip vr4181giu_iochip = {
93 .hc_portread = vr4181giu_port_read,
94 .hc_portwrite = vr4181giu_port_write,
95 .hc_intr_establish = vr4181giu_intr_establish,
96 .hc_intr_disestablish = vr4181giu_intr_disestablish,
97 .hc_intr_clear = vr4181giu_intr_clear,
98 .hc_register_iochip = vr4181giu_register_iochip,
99 .hc_update = vr4181giu_update,
100 .hc_dump = vr4181giu_dump,
103 CFATTACH_DECL(vr4181giu, sizeof(struct vr4181giu_softc),
104 vr4181giu_match, vr4181giu_attach, NULL, NULL);
106 static int
107 vr4181giu_match(struct device *parent, struct cfdata *match, void *aux)
109 return (2); /* 1st attach group of vrip */
112 static void
113 vr4181giu_attach(struct device *parent, struct device *self, void *aux)
115 struct vr4181giu_softc *sc = (struct vr4181giu_softc*) self;
116 struct vrip_attach_args *va = aux;
117 int i;
119 sc->sc_iot = va->va_iot;
120 sc->sc_vc = va->va_vc;
122 if (bus_space_map(sc->sc_iot, va->va_addr, va->va_size,
123 0 /* no cache */, &sc->sc_ioh)) {
124 printf(": can't map i/o space\n");
125 return;
128 for (i = 0; i < MAX_GIU4181INTR; i++)
129 TAILQ_INIT(&sc->sc_intr_head[i]);
131 if (!(sc->sc_ih
132 = vrip_intr_establish(va->va_vc, va->va_unit, 0,
133 IPL_BIO, vr4181giu_intr, sc))) {
134 printf("%s: can't establish interrupt\n", sc->sc_dev.dv_xname);
135 return;
139 * fill hpcio_chip structure
141 sc->sc_iochip = vr4181giu_iochip; /* structure copy */
142 sc->sc_iochip.hc_chipid = VRIP_IOCHIP_VR4181GIU;
143 sc->sc_iochip.hc_name = sc->sc_dev.dv_xname;
144 sc->sc_iochip.hc_sc = sc;
145 /* Register functions to upper interface */
146 vrip_register_gpio(va->va_vc, &sc->sc_iochip);
148 printf("\n");
151 * hpcio I/F
153 sc->sc_haa.haa_busname = HPCIO_BUSNAME;
154 sc->sc_haa.haa_sc = sc;
155 sc->sc_haa.haa_getchip = vr4181giu_getchip;
156 sc->sc_haa.haa_iot = sc->sc_iot;
157 while (config_found(self, &sc->sc_haa, vr4181giu_print)) ;
160 * GIU-ISA bridge
162 #if 1 /* XXX Sometimes mounting root device failed. Why? XXX*/
163 config_defer(self, vr4181giu_callback);
164 #else
165 vr4181giu_callback(self);
166 #endif
169 static void
170 vr4181giu_callback(struct device *self)
172 struct vr4181giu_softc *sc = (void *) self;
174 sc->sc_haa.haa_busname = "vrisab";
175 config_found(self, &sc->sc_haa, vr4181giu_print);
178 static int
179 vr4181giu_print(void *aux, const char *pnp)
181 if (pnp)
182 return (QUIET);
183 return (UNCONF);
186 static int
187 vr4181giu_port_read(hpcio_chip_t hc, int port)
189 struct vr4181giu_softc *sc = hc->hc_sc;
190 u_int16_t r;
192 if (port < 0 || 32 <= port)
193 panic("vr4181giu_port_read: invalid gpio port");
195 if (port < 16) {
196 r = bus_space_read_2(sc->sc_iot, sc->sc_ioh,
197 VR4181GIU_PIOD_L_REG_W)
198 & 1 << port;
199 } else {
200 r = bus_space_read_2(sc->sc_iot, sc->sc_ioh,
201 VR4181GIU_PIOD_H_REG_W)
202 & 1 << (port - 16);
204 return r ? 1 : 0;
207 static void
208 vr4181giu_port_write(hpcio_chip_t hc, int port, int onoff)
210 struct vr4181giu_softc *sc = hc->hc_sc;
211 u_int16_t r;
213 if (port < 16) {
214 r = bus_space_read_2(sc->sc_iot, sc->sc_ioh,
215 VR4181GIU_PIOD_L_REG_W);
216 if (onoff) {
217 r |= 1 << port;
218 } else {
219 r &= ~(1 << port);
221 bus_space_write_2(sc->sc_iot, sc->sc_ioh,
222 VR4181GIU_PIOD_L_REG_W, r);
223 } else {
224 r = bus_space_read_2(sc->sc_iot, sc->sc_ioh,
225 VR4181GIU_PIOD_H_REG_W);
226 if (onoff) {
227 r |= 1 << (port - 16);
228 } else {
229 r &= ~(1 << (port - 16));
231 bus_space_write_2(sc->sc_iot, sc->sc_ioh,
232 VR4181GIU_PIOD_H_REG_W, r);
237 * XXXXXXXXXXXXXXXXXXXXXXXX
239 static void
240 vr4181giu_update(hpcio_chip_t hc)
244 static void
245 vr4181giu_dump(hpcio_chip_t hc)
249 static hpcio_chip_t
250 vr4181giu_getchip(void* scx, int chipid)
252 struct vr4181giu_softc *sc = scx;
254 return (&sc->sc_iochip);
257 static void *
258 vr4181giu_intr_establish(
259 hpcio_chip_t hc,
260 int port, /* GPIO pin # */
261 int mode, /* GIU trigger setting */
262 int (*ih_fun)(void *),
263 void *ih_arg)
265 struct vr4181giu_softc *sc = hc->hc_sc;
266 struct vr4181giu_intr_entry *ih;
267 int s;
268 u_int32_t mask;
269 u_int32_t raw_intr_type;
270 int regmod;
271 int reghl;
272 int bitoff;
273 u_int16_t r;
276 * trigger mode translation
278 * VR4181 only support for four type of interrupt trigger
279 * listed below:
281 * 1. high level
282 * 2. low level
283 * 3. rising edge
284 * 4. falling edge
286 * argument mode is a bitmap as following:
288 * 001 detection trigger (1:edge/0:level )
289 * 010 signal hold/through (1:hold/0:through)
290 * 100 detection level (1:high/0:low )
292 * possible mode value is 000B to 111B.
294 * 000 HPCIO_INTR_LEVEL_LOW_THROUGH
295 * 001 HPCIO_INTR_EDGE_THROUGH
296 * 010 HPCIO_INTR_LEVEL_LOW_HOLD
297 * 011 HPCIO_INTR_EDGE_HOLD
298 * 100 HPCIO_INTR_LEVEL_HIGH_THROUGH
299 * 101 falling edge and through?
300 * 110 HPCIO_INTR_LEVEL_HIGH_HOLD
301 * 111 falling edge and hold?
304 static u_int32_t intr_mode_trans[8] = {
305 VR4181GIU_INTTYP_LOW_LEVEL, /* 000 */
306 VR4181GIU_INTTYP_RISING_EDGE, /* 001 */
307 VR4181GIU_INTTYP_LOW_LEVEL, /* 010 */
308 VR4181GIU_INTTYP_RISING_EDGE, /* 011 */
309 VR4181GIU_INTTYP_HIGH_LEVEL, /* 100 */
310 VR4181GIU_INTTYP_FALLING_EDGE, /* 101 */
311 VR4181GIU_INTTYP_HIGH_LEVEL, /* 110 */
312 VR4181GIU_INTTYP_FALLING_EDGE, /* 111 */
315 raw_intr_type = intr_mode_trans[mode];
316 if (raw_intr_type == VR4181GIU_INTTYP_INVALID)
317 panic("vr4181giu_intr_establish: invalid interrupt mode.");
319 if (port < 0 || MAX_GIU4181INTR <= port)
320 panic("vr4181giu_intr_establish: invalid interrupt line.");
321 if (!TAILQ_EMPTY(&sc->sc_intr_head[port])
322 && raw_intr_type != sc->sc_intr_mode[port])
323 panic("vr4181giu_intr_establish: "
324 "cannot use one line with two modes at a time.");
325 else
326 sc->sc_intr_mode[port] = raw_intr_type;
327 mask = (1 << port);
329 s = splhigh();
331 if ((ih = malloc(sizeof *ih, M_DEVBUF, M_NOWAIT)) == NULL)
332 panic("vr4181giu_intr_establish: memory exhausted.");
334 ih->ih_port = port;
335 ih->ih_fun = ih_fun;
336 ih->ih_arg = ih_arg;
337 TAILQ_INSERT_TAIL(&sc->sc_intr_head[port], ih, ih_link);
340 * setup GIU registers
343 /* disable interrupt at first */
344 r = bus_space_read_2(sc->sc_iot, sc->sc_ioh, VR4181GIU_INTEN_REG_W);
345 r &= ~mask;
346 bus_space_write_2(sc->sc_iot, sc->sc_ioh, VR4181GIU_INTEN_REG_W, r);
348 /* mode */
349 regmod = port >> 3;
350 bitoff = (port & 0x7) << 1;
351 r = bus_space_read_2(sc->sc_iot, sc->sc_ioh,
352 VR4181GIU_MODE0_REG_W + regmod);
353 r &= ~(0x3 << bitoff);
354 r |= (VR4181GIU_MODE_IN | VR4181GIU_MODE_GPIO) << bitoff;
355 bus_space_write_2(sc->sc_iot, sc->sc_ioh,
356 VR4181GIU_MODE0_REG_W + regmod, r);
357 /* interrupt type */
358 reghl = port < 8 ? 2 : 0; /* high byte: 0x0, lowbyte: 0x2 */
359 r = bus_space_read_2(sc->sc_iot, sc->sc_ioh,
360 VR4181GIU_INTTYP_REG + reghl);
361 r &= ~(0x3 << bitoff);
362 r |= raw_intr_type << bitoff;
363 bus_space_write_2(sc->sc_iot, sc->sc_ioh,
364 VR4181GIU_INTTYP_REG + reghl, r);
366 /* clear status */
367 bus_space_write_2(sc->sc_iot, sc->sc_ioh,
368 VR4181GIU_INTSTAT_REG_W, mask);
370 /* unmask */
371 r = bus_space_read_2(sc->sc_iot, sc->sc_ioh, VR4181GIU_INTMASK_REG_W);
372 r &= ~mask;
373 bus_space_write_2(sc->sc_iot, sc->sc_ioh, VR4181GIU_INTMASK_REG_W, r);
375 /* enable */
376 r = bus_space_read_2(sc->sc_iot, sc->sc_ioh, VR4181GIU_INTEN_REG_W);
377 r |= mask;
378 bus_space_write_2(sc->sc_iot, sc->sc_ioh, VR4181GIU_INTEN_REG_W, r);
380 splx(s);
382 return ih;
385 static void
386 vr4181giu_intr_disestablish(hpcio_chip_t hc, void *arg)
390 static void
391 vr4181giu_intr_clear(hpcio_chip_t hc, void *arg)
393 struct vr4181giu_softc *sc = hc->hc_sc;
394 struct vr4181giu_intr_entry *ih = arg;
396 bus_space_write_2(sc->sc_iot, sc->sc_ioh,
397 VR4181GIU_INTSTAT_REG_W, 1 << ih->ih_port);
400 static void
401 vr4181giu_register_iochip(hpcio_chip_t hc, hpcio_chip_t iochip)
403 struct vr4181giu_softc *sc = hc->hc_sc;
405 vrip_register_gpio(sc->sc_vc, iochip);
409 * interrupt handler
411 static int
412 vr4181giu_intr(void *arg)
414 struct vr4181giu_softc *sc = arg;
415 int i;
416 u_int16_t r;
418 r = bus_space_read_2(sc->sc_iot, sc->sc_ioh, VR4181GIU_INTSTAT_REG_W);
419 bus_space_write_2(sc->sc_iot, sc->sc_ioh, VR4181GIU_INTSTAT_REG_W, r);
421 for (i = 0; i < MAX_GIU4181INTR; i++) {
422 if (r & (1 << i)) {
423 struct vr4181giu_intr_entry *ih;
424 TAILQ_FOREACH(ih, &sc->sc_intr_head[i], ih_link) {
425 ih->ih_fun(ih->ih_arg);
430 return 0;