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