vr4181giu.c revision 1.1
1/* $NetBSD: vr4181giu.c,v 1.1 2003/05/01 07:02:05 igy 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/param.h> 38#include <sys/device.h> 39#include <sys/malloc.h> 40#include <sys/queue.h> 41#include <sys/systm.h> 42 43#include <machine/bus.h> 44 45#include <hpcmips/vr/vripif.h> 46#include <hpcmips/vr/vr4181giureg.h> 47 48#define MAX_GIU4181INTR 16 49 50struct vr4181giu_intr_entry { 51 int ih_port; 52 int (*ih_fun)(void *); 53 void *ih_arg; 54 TAILQ_ENTRY(vr4181giu_intr_entry) ih_link; 55}; 56 57struct vr4181giu_softc { 58 struct device sc_dev; 59 bus_space_tag_t sc_iot; 60 bus_space_handle_t sc_ioh; 61 vrip_chipset_tag_t sc_vc; 62 void *sc_ih; 63 u_int32_t sc_intr_mode[MAX_GIU4181INTR]; 64 TAILQ_HEAD(, vr4181giu_intr_entry) 65 sc_intr_head[MAX_GIU4181INTR]; 66 struct hpcio_chip sc_iochip; 67 struct hpcio_attach_args sc_haa; 68}; 69 70static int vr4181giu_match(struct device *, struct cfdata *, void *); 71static void vr4181giu_attach(struct device *, struct device *, void *); 72 73static void vr4181giu_callback(struct device *self); 74static int vr4181giu_print(void *aux, const char *pnp); 75static int vr4181giu_port_read(hpcio_chip_t hc, int port); 76static void vr4181giu_port_write(hpcio_chip_t hc, int port, int onoff); 77static void vr4181giu_update(hpcio_chip_t hc); 78static void vr4181giu_dump(hpcio_chip_t hc); 79static hpcio_chip_t vr4181giu_getchip(void* scx, int chipid); 80static void *vr4181giu_intr_establish(hpcio_chip_t, int, int, 81 int (*)(void *),void *); 82static void vr4181giu_intr_disestablish(hpcio_chip_t hc, void *arg); 83static void vr4181giu_intr_clear(hpcio_chip_t hc, void *arg); 84static void vr4181giu_register_iochip(hpcio_chip_t hc, hpcio_chip_t iochip); 85static int vr4181giu_intr(void *arg); 86 87 88 89static struct hpcio_chip vr4181giu_iochip = { 90 .hc_portread = vr4181giu_port_read, 91 .hc_portwrite = vr4181giu_port_write, 92 .hc_intr_establish = vr4181giu_intr_establish, 93 .hc_intr_disestablish = vr4181giu_intr_disestablish, 94 .hc_intr_clear = vr4181giu_intr_clear, 95 .hc_register_iochip = vr4181giu_register_iochip, 96 .hc_update = vr4181giu_update, 97 .hc_dump = vr4181giu_dump, 98}; 99 100CFATTACH_DECL(vr4181giu, sizeof(struct vr4181giu_softc), 101 vr4181giu_match, vr4181giu_attach, NULL, NULL); 102 103static int 104vr4181giu_match(struct device *parent, struct cfdata *match, void *aux) 105{ 106 return (2); /* 1st attach group of vrip */ 107} 108 109static void 110vr4181giu_attach(struct device *parent, struct device *self, void *aux) 111{ 112 struct vr4181giu_softc *sc = (struct vr4181giu_softc*) self; 113 struct vrip_attach_args *va = aux; 114 int i; 115 116 sc->sc_iot = va->va_iot; 117 sc->sc_vc = va->va_vc; 118 119 if (bus_space_map(sc->sc_iot, va->va_addr, va->va_size, 120 0 /* no cache */, &sc->sc_ioh)) { 121 printf(": can't map i/o space\n"); 122 return; 123 } 124 125 for (i = 0; i < MAX_GIU4181INTR; i++) 126 TAILQ_INIT(&sc->sc_intr_head[i]); 127 128 if (!(sc->sc_ih 129 = vrip_intr_establish(va->va_vc, va->va_unit, 0, 130 IPL_BIO, vr4181giu_intr, sc))) { 131 printf("%s: can't establish interrupt\n", sc->sc_dev.dv_xname); 132 return; 133 } 134 135 /* 136 * fill hpcio_chip structure 137 */ 138 sc->sc_iochip = vr4181giu_iochip; /* structure copy */ 139 sc->sc_iochip.hc_chipid = VRIP_IOCHIP_VR4181GIU; 140 sc->sc_iochip.hc_name = sc->sc_dev.dv_xname; 141 sc->sc_iochip.hc_sc = sc; 142 /* Register functions to upper interface */ 143 vrip_register_gpio(va->va_vc, &sc->sc_iochip); 144 145 printf("\n"); 146 147 /* 148 * hpcio I/F 149 */ 150 sc->sc_haa.haa_busname = HPCIO_BUSNAME; 151 sc->sc_haa.haa_sc = sc; 152 sc->sc_haa.haa_getchip = vr4181giu_getchip; 153 sc->sc_haa.haa_iot = sc->sc_iot; 154 while (config_found(self, &sc->sc_haa, vr4181giu_print)) ; 155 156 /* 157 * GIU-ISA bridge 158 */ 159#if 1 /* XXX Sometimes mounting root device failed. Why? XXX*/ 160 config_defer(self, vr4181giu_callback); 161#else 162 vr4181giu_callback(self); 163#endif 164} 165 166static void 167vr4181giu_callback(struct device *self) 168{ 169 struct vr4181giu_softc *sc = (void *) self; 170 171 sc->sc_haa.haa_busname = "vrisab"; 172 config_found(self, &sc->sc_haa, vr4181giu_print); 173} 174 175static int 176vr4181giu_print(void *aux, const char *pnp) 177{ 178 if (pnp) 179 return (QUIET); 180 return (UNCONF); 181} 182 183static int 184vr4181giu_port_read(hpcio_chip_t hc, int port) 185{ 186 struct vr4181giu_softc *sc = hc->hc_sc; 187 u_int16_t r; 188 189 if (port < 0 || 32 <= port) 190 panic("vr4181giu_port_read: invalid gpio port"); 191 192 if (port < 16) { 193 r = bus_space_read_2(sc->sc_iot, sc->sc_ioh, 194 VR4181GIU_PIOD_L_REG_W) 195 & 1 << port; 196 } else { 197 r = bus_space_read_2(sc->sc_iot, sc->sc_ioh, 198 VR4181GIU_PIOD_H_REG_W) 199 & 1 << (port - 16); 200 } 201 return r ? 1 : 0; 202} 203 204static void 205vr4181giu_port_write(hpcio_chip_t hc, int port, int onoff) 206{ 207 struct vr4181giu_softc *sc = hc->hc_sc; 208 u_int16_t r; 209 210 if (port < 16) { 211 r = bus_space_read_2(sc->sc_iot, sc->sc_ioh, 212 VR4181GIU_PIOD_L_REG_W); 213 if (onoff) { 214 r |= 1 << port; 215 } else { 216 r &= ~(1 << port); 217 } 218 bus_space_write_2(sc->sc_iot, sc->sc_ioh, 219 VR4181GIU_PIOD_L_REG_W, r); 220 } else { 221 r = bus_space_read_2(sc->sc_iot, sc->sc_ioh, 222 VR4181GIU_PIOD_H_REG_W); 223 if (onoff) { 224 r |= 1 << (port - 16); 225 } else { 226 r &= ~(1 << (port - 16)); 227 } 228 bus_space_write_2(sc->sc_iot, sc->sc_ioh, 229 VR4181GIU_PIOD_H_REG_W, r); 230 } 231} 232 233/* 234 * XXXXXXXXXXXXXXXXXXXXXXXX 235 */ 236static void 237vr4181giu_update(hpcio_chip_t hc) 238{ 239} 240 241static void 242vr4181giu_dump(hpcio_chip_t hc) 243{ 244} 245 246static hpcio_chip_t 247vr4181giu_getchip(void* scx, int chipid) 248{ 249 struct vr4181giu_softc *sc = scx; 250 251 return (&sc->sc_iochip); 252} 253 254static void * 255vr4181giu_intr_establish( 256 hpcio_chip_t hc, 257 int port, /* GPIO pin # */ 258 int mode, /* GIU trigger setting */ 259 int (*ih_fun)(void *), 260 void *ih_arg) 261{ 262 struct vr4181giu_softc *sc = hc->hc_sc; 263 struct vr4181giu_intr_entry *ih; 264 int s; 265 u_int32_t mask; 266 u_int32_t raw_intr_type; 267 int regmod; 268 int reghl; 269 int bitoff; 270 u_int16_t r; 271 272 /* 273 * trigger mode translation 274 * 275 * VR4181 only support for four type of interrupt trigger 276 * listed below: 277 * 278 * 1. high level 279 * 2. low level 280 * 3. rising edge 281 * 4. falling edge 282 * 283 * argument mode is a bitmap as following: 284 * 285 * 001 detection trigger (1:edge/0:level ) 286 * 010 signal hold/through (1:hold/0:through) 287 * 100 detection level (1:high/0:low ) 288 * 289 * possible mode value is 000B to 111B. 290 * 291 * 000 HPCIO_INTR_LEVEL_LOW_THROUGH 292 * 001 HPCIO_INTR_EDGE_THROUGH 293 * 010 HPCIO_INTR_LEVEL_LOW_HOLD 294 * 011 HPCIO_INTR_EDGE_HOLD 295 * 100 HPCIO_INTR_LEVEL_HIGH_THROUGH 296 * 101 falling edge and through? 297 * 110 HPCIO_INTR_LEVEL_HIGH_HOLD 298 * 111 falling edge and hold? 299 */ 300 301 static u_int32_t intr_mode_trans[8] = { 302 VR4181GIU_INTTYP_LOW_LEVEL, /* 000 */ 303 VR4181GIU_INTTYP_RISING_EDGE, /* 001 */ 304 VR4181GIU_INTTYP_LOW_LEVEL, /* 010 */ 305 VR4181GIU_INTTYP_RISING_EDGE, /* 011 */ 306 VR4181GIU_INTTYP_HIGH_LEVEL, /* 100 */ 307 VR4181GIU_INTTYP_FALLING_EDGE, /* 101 */ 308 VR4181GIU_INTTYP_HIGH_LEVEL, /* 110 */ 309 VR4181GIU_INTTYP_FALLING_EDGE, /* 111 */ 310 }; 311 312 raw_intr_type = intr_mode_trans[mode]; 313 if (raw_intr_type == VR4181GIU_INTTYP_INVALID) 314 panic("vr4181giu_intr_establish: invalid interrupt mode."); 315 316 if (port < 0 || MAX_GIU4181INTR <= port) 317 panic("vr4181giu_intr_establish: invalid interrupt line."); 318 if (!TAILQ_EMPTY(&sc->sc_intr_head[port]) 319 && raw_intr_type != sc->sc_intr_mode[port]) 320 panic("vr4181giu_intr_establish: " 321 "cannot use one line with two modes at a time."); 322 else 323 sc->sc_intr_mode[port] = raw_intr_type; 324 mask = (1 << port); 325 326 s = splhigh(); 327 328 if ((ih = malloc(sizeof *ih, M_DEVBUF, M_NOWAIT)) == NULL) 329 panic("vr4181giu_intr_establish: memory exhausted."); 330 331 ih->ih_port = port; 332 ih->ih_fun = ih_fun; 333 ih->ih_arg = ih_arg; 334 TAILQ_INSERT_TAIL(&sc->sc_intr_head[port], ih, ih_link); 335 336 /* 337 * setup GIU registers 338 */ 339 340 /* disable interrupt at first */ 341 r = bus_space_read_2(sc->sc_iot, sc->sc_ioh, VR4181GIU_INTEN_REG_W); 342 r &= ~mask; 343 bus_space_write_2(sc->sc_iot, sc->sc_ioh, VR4181GIU_INTEN_REG_W, r); 344 345 /* mode */ 346 regmod = port >> 3; 347 bitoff = (port & 0x7) << 1; 348 r = bus_space_read_2(sc->sc_iot, sc->sc_ioh, 349 VR4181GIU_MODE0_REG_W + regmod); 350 r &= ~(0x3 << bitoff); 351 r |= (VR4181GIU_MODE_IN | VR4181GIU_MODE_GPIO) << bitoff; 352 bus_space_write_2(sc->sc_iot, sc->sc_ioh, 353 VR4181GIU_MODE0_REG_W + regmod, r); 354 /* interrupt type */ 355 reghl = port < 8 ? 2 : 0; /* high byte: 0x0, lowbyte: 0x2 */ 356 r = bus_space_read_2(sc->sc_iot, sc->sc_ioh, 357 VR4181GIU_INTTYP_REG + reghl); 358 r &= ~(0x3 << bitoff); 359 r |= raw_intr_type << bitoff; 360 bus_space_write_2(sc->sc_iot, sc->sc_ioh, 361 VR4181GIU_INTTYP_REG + reghl, r); 362 363 /* clear status */ 364 bus_space_write_2(sc->sc_iot, sc->sc_ioh, 365 VR4181GIU_INTSTAT_REG_W, mask); 366 367 /* unmask */ 368 r = bus_space_read_2(sc->sc_iot, sc->sc_ioh, VR4181GIU_INTMASK_REG_W); 369 r &= ~mask; 370 bus_space_write_2(sc->sc_iot, sc->sc_ioh, VR4181GIU_INTMASK_REG_W, r); 371 372 /* enable */ 373 r = bus_space_read_2(sc->sc_iot, sc->sc_ioh, VR4181GIU_INTEN_REG_W); 374 r |= mask; 375 bus_space_write_2(sc->sc_iot, sc->sc_ioh, VR4181GIU_INTEN_REG_W, r); 376 377 splx(s); 378 379 return ih; 380} 381 382static void 383vr4181giu_intr_disestablish(hpcio_chip_t hc, void *arg) 384{ 385} 386 387static void 388vr4181giu_intr_clear(hpcio_chip_t hc, void *arg) 389{ 390 struct vr4181giu_softc *sc = hc->hc_sc; 391 struct vr4181giu_intr_entry *ih = arg; 392 393 bus_space_write_2(sc->sc_iot, sc->sc_ioh, 394 VR4181GIU_INTSTAT_REG_W, 1 << ih->ih_port); 395} 396 397static void 398vr4181giu_register_iochip(hpcio_chip_t hc, hpcio_chip_t iochip) 399{ 400 struct vr4181giu_softc *sc = hc->hc_sc; 401 402 vrip_register_gpio(sc->sc_vc, iochip); 403} 404 405/* 406 * interrupt handler 407 */ 408static int 409vr4181giu_intr(void *arg) 410{ 411 struct vr4181giu_softc *sc = arg; 412 int i; 413 u_int16_t r; 414 415 r = bus_space_read_2(sc->sc_iot, sc->sc_ioh, VR4181GIU_INTSTAT_REG_W); 416 bus_space_write_2(sc->sc_iot, sc->sc_ioh, VR4181GIU_INTSTAT_REG_W, r); 417 418 for (i = 0; i < MAX_GIU4181INTR; i++) { 419 if (r & (1 << i)) { 420 struct vr4181giu_intr_entry *ih; 421 TAILQ_FOREACH(ih, &sc->sc_intr_head[i], ih_link) { 422 ih->ih_fun(ih->ih_arg); 423 } 424 } 425 } 426 427 return 0; 428} 429