1 /* $NetBSD: vr4181giu.c,v 1.1.2.3 2004/09/21 13:16:13 skrll Exp $ */
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
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
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
{
55 int (*ih_fun
)(void *);
57 TAILQ_ENTRY(vr4181giu_intr_entry
) ih_link
;
60 struct vr4181giu_softc
{
62 bus_space_tag_t sc_iot
;
63 bus_space_handle_t sc_ioh
;
64 vrip_chipset_tag_t sc_vc
;
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
);
107 vr4181giu_match(struct device
*parent
, struct cfdata
*match
, void *aux
)
109 return (2); /* 1st attach group of vrip */
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
;
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");
128 for (i
= 0; i
< MAX_GIU4181INTR
; i
++)
129 TAILQ_INIT(&sc
->sc_intr_head
[i
]);
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
);
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
);
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
)) ;
162 #if 1 /* XXX Sometimes mounting root device failed. Why? XXX*/
163 config_defer(self
, vr4181giu_callback
);
165 vr4181giu_callback(self
);
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
);
179 vr4181giu_print(void *aux
, const char *pnp
)
187 vr4181giu_port_read(hpcio_chip_t hc
, int port
)
189 struct vr4181giu_softc
*sc
= hc
->hc_sc
;
192 if (port
< 0 || 32 <= port
)
193 panic("vr4181giu_port_read: invalid gpio port");
196 r
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
,
197 VR4181GIU_PIOD_L_REG_W
)
200 r
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
,
201 VR4181GIU_PIOD_H_REG_W
)
208 vr4181giu_port_write(hpcio_chip_t hc
, int port
, int onoff
)
210 struct vr4181giu_softc
*sc
= hc
->hc_sc
;
214 r
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
,
215 VR4181GIU_PIOD_L_REG_W
);
221 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
,
222 VR4181GIU_PIOD_L_REG_W
, r
);
224 r
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
,
225 VR4181GIU_PIOD_H_REG_W
);
227 r
|= 1 << (port
- 16);
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
240 vr4181giu_update(hpcio_chip_t hc
)
245 vr4181giu_dump(hpcio_chip_t hc
)
250 vr4181giu_getchip(void* scx
, int chipid
)
252 struct vr4181giu_softc
*sc
= scx
;
254 return (&sc
->sc_iochip
);
258 vr4181giu_intr_establish(
260 int port
, /* GPIO pin # */
261 int mode
, /* GIU trigger setting */
262 int (*ih_fun
)(void *),
265 struct vr4181giu_softc
*sc
= hc
->hc_sc
;
266 struct vr4181giu_intr_entry
*ih
;
269 u_int32_t raw_intr_type
;
276 * trigger mode translation
278 * VR4181 only support for four type of interrupt trigger
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.");
326 sc
->sc_intr_mode
[port
] = raw_intr_type
;
331 if ((ih
= malloc(sizeof *ih
, M_DEVBUF
, M_NOWAIT
)) == NULL
)
332 panic("vr4181giu_intr_establish: memory exhausted.");
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
);
346 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, VR4181GIU_INTEN_REG_W
, r
);
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
);
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
);
367 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
,
368 VR4181GIU_INTSTAT_REG_W
, mask
);
371 r
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, VR4181GIU_INTMASK_REG_W
);
373 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, VR4181GIU_INTMASK_REG_W
, r
);
376 r
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, VR4181GIU_INTEN_REG_W
);
378 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, VR4181GIU_INTEN_REG_W
, r
);
386 vr4181giu_intr_disestablish(hpcio_chip_t hc
, void *arg
)
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
);
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
);
412 vr4181giu_intr(void *arg
)
414 struct vr4181giu_softc
*sc
= arg
;
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
++) {
423 struct vr4181giu_intr_entry
*ih
;
424 TAILQ_FOREACH(ih
, &sc
->sc_intr_head
[i
], ih_link
) {
425 ih
->ih_fun(ih
->ih_arg
);