vr4181giu.c revision 1.3
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 53struct 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 60struct 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 73static int vr4181giu_match(struct device *, struct cfdata *, void *); 74static void vr4181giu_attach(struct device *, struct device *, void *); 75 76static void vr4181giu_callback(struct device *self); 77static int vr4181giu_print(void *aux, const char *pnp); 78static int vr4181giu_port_read(hpcio_chip_t hc, int port); 79static void vr4181giu_port_write(hpcio_chip_t hc, int port, int onoff); 80static void vr4181giu_update(hpcio_chip_t hc); 81static void vr4181giu_dump(hpcio_chip_t hc); 82static hpcio_chip_t vr4181giu_getchip(void* scx, int chipid); 83static void *vr4181giu_intr_establish(hpcio_chip_t, int, int, 84 int (*)(void *),void *); 85static void vr4181giu_intr_disestablish(hpcio_chip_t hc, void *arg); 86static void vr4181giu_intr_clear(hpcio_chip_t hc, void *arg); 87static void vr4181giu_register_iochip(hpcio_chip_t hc, hpcio_chip_t iochip); 88static int vr4181giu_intr(void *arg); 89 90 91 92static 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 103CFATTACH_DECL(vr4181giu, sizeof(struct vr4181giu_softc), 104 vr4181giu_match, vr4181giu_attach, NULL, NULL); 105 106static int 107vr4181giu_match(struct device *parent, struct cfdata *match, void *aux) 108{ 109 return (2); /* 1st attach group of vrip */ 110} 111 112static void 113vr4181giu_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 169static void 170vr4181giu_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 178static int 179vr4181giu_print(void *aux, const char *pnp) 180{ 181 if (pnp) 182 return (QUIET); 183 return (UNCONF); 184} 185 186static int 187vr4181giu_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 207static void 208vr4181giu_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 */ 239static void 240vr4181giu_update(hpcio_chip_t hc) 241{ 242} 243 244static void 245vr4181giu_dump(hpcio_chip_t hc) 246{ 247} 248 249static hpcio_chip_t 250vr4181giu_getchip(void* scx, int chipid) 251{ 252 struct vr4181giu_softc *sc = scx; 253 254 return (&sc->sc_iochip); 255} 256 257static void * 258vr4181giu_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 385static void 386vr4181giu_intr_disestablish(hpcio_chip_t hc, void *arg) 387{ 388} 389 390static void 391vr4181giu_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 400static void 401vr4181giu_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 */ 411static int 412vr4181giu_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