1 /* $NetBSD: vr4181giu.c,v 1.4 2012/10/27 17:17:55 chs 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.4 2012/10/27 17:17:55 chs 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 bus_space_tag_t sc_iot; 62 bus_space_handle_t sc_ioh; 63 vrip_chipset_tag_t sc_vc; 64 void *sc_ih; 65 u_int32_t sc_intr_mode[MAX_GIU4181INTR]; 66 TAILQ_HEAD(, vr4181giu_intr_entry) 67 sc_intr_head[MAX_GIU4181INTR]; 68 struct hpcio_chip sc_iochip; 69 struct hpcio_attach_args sc_haa; 70 }; 71 72 static int vr4181giu_match(device_t, cfdata_t, void *); 73 static void vr4181giu_attach(device_t, device_t, void *); 74 75 static void vr4181giu_callback(device_t); 76 static int vr4181giu_print(void *, const char *); 77 static int vr4181giu_port_read(hpcio_chip_t, int); 78 static void vr4181giu_port_write(hpcio_chip_t, int, int); 79 static void vr4181giu_update(hpcio_chip_t); 80 static void vr4181giu_dump(hpcio_chip_t); 81 static hpcio_chip_t vr4181giu_getchip(void *, int); 82 static void *vr4181giu_intr_establish(hpcio_chip_t, int, int, 83 int (*)(void *),void *); 84 static void vr4181giu_intr_disestablish(hpcio_chip_t, void *); 85 static void vr4181giu_intr_clear(hpcio_chip_t, void *); 86 static void vr4181giu_register_iochip(hpcio_chip_t, hpcio_chip_t); 87 static int vr4181giu_intr(void *); 88 89 static 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 100 CFATTACH_DECL_NEW(vr4181giu, sizeof(struct vr4181giu_softc), 101 vr4181giu_match, vr4181giu_attach, NULL, NULL); 102 103 static int 104 vr4181giu_match(device_t parent, cfdata_t match, void *aux) 105 { 106 return (2); /* 1st attach group of vrip */ 107 } 108 109 static void 110 vr4181giu_attach(device_t parent, device_t self, void *aux) 111 { 112 struct vr4181giu_softc *sc = device_private(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", device_xname(self)); 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 = device_xname(self); 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 166 static void 167 vr4181giu_callback(device_t 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 175 static int 176 vr4181giu_print(void *aux, const char *pnp) 177 { 178 if (pnp) 179 return (QUIET); 180 return (UNCONF); 181 } 182 183 static int 184 vr4181giu_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 204 static void 205 vr4181giu_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 */ 236 static void 237 vr4181giu_update(hpcio_chip_t hc) 238 { 239 } 240 241 static void 242 vr4181giu_dump(hpcio_chip_t hc) 243 { 244 } 245 246 static hpcio_chip_t 247 vr4181giu_getchip(void* scx, int chipid) 248 { 249 struct vr4181giu_softc *sc = scx; 250 251 return (&sc->sc_iochip); 252 } 253 254 static void * 255 vr4181giu_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 382 static void 383 vr4181giu_intr_disestablish(hpcio_chip_t hc, void *arg) 384 { 385 } 386 387 static void 388 vr4181giu_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 397 static void 398 vr4181giu_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 */ 408 static int 409 vr4181giu_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