xref: /netbsd-src/sys/arch/hpcmips/vr/vr4181giu.c (revision a5847cc334d9a7029f6352b847e9e8d71a0f9e0c)
1 /* $NetBSD: vr4181giu.c,v 1.3 2005/12/11 12:17:34 christos Exp $ */
2 
3 /*-
4  * Copyright (c) 1999-2001
5  *         Shin Takemura and PocketBSD Project. 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. 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.
22  *
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.
34  *
35  */
36 
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: vr4181giu.c,v 1.3 2005/12/11 12:17:34 christos Exp $");
39 
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>
45 
46 #include <machine/bus.h>
47 
48 #include <hpcmips/vr/vripif.h>
49 #include <hpcmips/vr/vr4181giureg.h>
50 
51 #define MAX_GIU4181INTR	16
52 
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;
58 };
59 
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;
71 };
72 
73 static int vr4181giu_match(struct device *, struct cfdata *, void *);
74 static void vr4181giu_attach(struct device *, struct device *, void *);
75 
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);
89 
90 
91 
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,
101 };
102 
103 CFATTACH_DECL(vr4181giu, sizeof(struct vr4181giu_softc),
104 	      vr4181giu_match, vr4181giu_attach, NULL, NULL);
105 
106 static int
107 vr4181giu_match(struct device *parent, struct cfdata *match, void *aux)
108 {
109 	return (2); /* 1st attach group of vrip */
110 }
111 
112 static void
113 vr4181giu_attach(struct device *parent, struct device *self, void *aux)
114 {
115 	struct vr4181giu_softc	*sc = (struct vr4181giu_softc*) self;
116 	struct vrip_attach_args	*va = aux;
117 	int			i;
118 
119 	sc->sc_iot = va->va_iot;
120 	sc->sc_vc = va->va_vc;
121 
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;
126 	}
127 
128 	for (i = 0; i < MAX_GIU4181INTR; i++)
129 		TAILQ_INIT(&sc->sc_intr_head[i]);
130 
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;
136 	}
137 
138 	/*
139 	 * fill hpcio_chip structure
140 	 */
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);
147 
148 	printf("\n");
149 
150 	/*
151 	 *  hpcio I/F
152 	 */
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)) ;
158 
159 	/*
160 	 * GIU-ISA bridge
161 	 */
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
167 }
168 
169 static void
170 vr4181giu_callback(struct device *self)
171 {
172 	struct vr4181giu_softc		*sc = (void *) self;
173 
174 	sc->sc_haa.haa_busname = "vrisab";
175 	config_found(self, &sc->sc_haa, vr4181giu_print);
176 }
177 
178 static int
179 vr4181giu_print(void *aux, const char *pnp)
180 {
181 	if (pnp)
182 		return (QUIET);
183 	return (UNCONF);
184 }
185 
186 static int
187 vr4181giu_port_read(hpcio_chip_t hc, int port)
188 {
189 	struct vr4181giu_softc	*sc = hc->hc_sc;
190 	u_int16_t		r;
191 
192 	if (port < 0 || 32 <= port)
193 		panic("vr4181giu_port_read: invalid gpio port");
194 
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);
203 	}
204 	return r ? 1 : 0;
205 }
206 
207 static void
208 vr4181giu_port_write(hpcio_chip_t hc, int port, int onoff)
209 {
210 	struct vr4181giu_softc	*sc = hc->hc_sc;
211 	u_int16_t		r;
212 
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);
220 		}
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));
230 		}
231 		bus_space_write_2(sc->sc_iot, sc->sc_ioh,
232 				  VR4181GIU_PIOD_H_REG_W, r);
233 	}
234 }
235 
236 /*
237  * XXXXXXXXXXXXXXXXXXXXXXXX
238  */
239 static void
240 vr4181giu_update(hpcio_chip_t hc)
241 {
242 }
243 
244 static void
245 vr4181giu_dump(hpcio_chip_t hc)
246 {
247 }
248 
249 static hpcio_chip_t
250 vr4181giu_getchip(void* scx, int chipid)
251 {
252 	struct vr4181giu_softc	*sc = scx;
253 
254 	return (&sc->sc_iochip);
255 }
256 
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)
264 {
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;
274 
275 	/*
276 	 * trigger mode translation
277 	 *
278 	 * VR4181 only support for four type of interrupt trigger
279 	 * listed below:
280 	 *
281 	 * 1. high level
282 	 * 2. low level
283 	 * 3. rising edge
284 	 * 4. falling edge
285 	 *
286 	 * argument mode is a bitmap as following:
287 	 *
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    )
291 	 *
292 	 * possible mode value is 000B to 111B.
293 	 *
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?
302 	 */
303 
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 */
313 	};
314 
315 	raw_intr_type = intr_mode_trans[mode];
316 	if (raw_intr_type == VR4181GIU_INTTYP_INVALID)
317 		panic("vr4181giu_intr_establish: invalid interrupt mode.");
318 
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);
328 
329 	s = splhigh();
330 
331 	if ((ih = malloc(sizeof *ih, M_DEVBUF, M_NOWAIT)) == NULL)
332 		panic("vr4181giu_intr_establish: memory exhausted.");
333 
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);
338 
339 	/*
340 	 * setup GIU registers
341 	 */
342 
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);
347 
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);
365 
366 	/* clear status */
367 	bus_space_write_2(sc->sc_iot, sc->sc_ioh,
368 			  VR4181GIU_INTSTAT_REG_W, mask);
369 
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);
374 
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);
379 
380 	splx(s);
381 
382 	return ih;
383 }
384 
385 static void
386 vr4181giu_intr_disestablish(hpcio_chip_t hc, void *arg)
387 {
388 }
389 
390 static void
391 vr4181giu_intr_clear(hpcio_chip_t hc, void *arg)
392 {
393 	struct vr4181giu_softc		*sc = hc->hc_sc;
394 	struct vr4181giu_intr_entry	*ih = arg;
395 
396 	bus_space_write_2(sc->sc_iot, sc->sc_ioh,
397 			  VR4181GIU_INTSTAT_REG_W, 1 << ih->ih_port);
398 }
399 
400 static void
401 vr4181giu_register_iochip(hpcio_chip_t hc, hpcio_chip_t iochip)
402 {
403 	struct vr4181giu_softc	*sc = hc->hc_sc;
404 
405 	vrip_register_gpio(sc->sc_vc, iochip);
406 }
407 
408 /*
409  * interrupt handler
410  */
411 static int
412 vr4181giu_intr(void *arg)
413 {
414 	struct vr4181giu_softc	*sc = arg;
415 	int			i;
416 	u_int16_t		r;
417 
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);
420 
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);
426 			}
427 		}
428 	}
429 
430 	return 0;
431 }
432