1 /* $OpenBSD: ioasic.c,v 1.15 2008/08/09 16:42:29 miod Exp $ */ 2 /* $NetBSD: ioasic.c,v 1.34 2000/07/18 06:10:06 thorpej Exp $ */ 3 4 /*- 5 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 10 * NASA Ames Research Center. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University. 36 * All rights reserved. 37 * 38 * Author: Keith Bostic, Chris G. Demetriou 39 * 40 * Permission to use, copy, modify and distribute this software and 41 * its documentation is hereby granted, provided that both the copyright 42 * notice and this permission notice appear in all copies of the 43 * software, derivative works or modified versions, and any portions 44 * thereof, and that both notices appear in supporting documentation. 45 * 46 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 47 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 48 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 49 * 50 * Carnegie Mellon requests users of this software to return to 51 * 52 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 53 * School of Computer Science 54 * Carnegie Mellon University 55 * Pittsburgh PA 15213-3890 56 * 57 * any improvements or extensions that they make and grant Carnegie the 58 * rights to redistribute these changes. 59 */ 60 61 #include <sys/param.h> 62 #include <sys/kernel.h> 63 #include <sys/systm.h> 64 #include <sys/device.h> 65 #include <sys/malloc.h> 66 67 #include <machine/autoconf.h> 68 #include <machine/bus.h> 69 #include <machine/pte.h> 70 #include <machine/rpb.h> 71 72 #include <dev/tc/tcvar.h> 73 #include <dev/tc/ioasicreg.h> 74 #include <dev/tc/ioasicvar.h> 75 76 /* Definition of the driver for autoconfig. */ 77 int ioasicmatch(struct device *, void *, void *); 78 void ioasicattach(struct device *, struct device *, void *); 79 80 struct cfattach ioasic_ca = { 81 sizeof(struct ioasic_softc), ioasicmatch, ioasicattach, 82 }; 83 84 struct cfdriver ioasic_cd = { 85 NULL, "ioasic", DV_DULL, 86 }; 87 88 int ioasic_intr(void *); 89 int ioasic_intrnull(void *); 90 91 #define C(x) ((void *)(x)) 92 93 #define IOASIC_DEV_LANCE 0 94 #define IOASIC_DEV_SCC0 1 95 #define IOASIC_DEV_SCC1 2 96 #define IOASIC_DEV_ISDN 3 97 98 #define IOASIC_DEV_BOGUS -1 99 100 #define IOASIC_NCOOKIES 4 101 102 struct ioasic_dev ioasic_devs[] = { 103 { "PMAD-BA ", IOASIC_SLOT_3_START, C(IOASIC_DEV_LANCE), 104 IOASIC_INTR_LANCE, }, 105 { "z8530 ", IOASIC_SLOT_4_START, C(IOASIC_DEV_SCC0), 106 IOASIC_INTR_SCC_0, }, 107 { "z8530 ", IOASIC_SLOT_6_START, C(IOASIC_DEV_SCC1), 108 IOASIC_INTR_SCC_1, }, 109 { "TOY_RTC ", IOASIC_SLOT_8_START, C(IOASIC_DEV_BOGUS), 110 0, }, 111 { "AMD79c30", IOASIC_SLOT_9_START, C(IOASIC_DEV_ISDN), 112 IOASIC_INTR_ISDN_TXLOAD | IOASIC_INTR_ISDN_RXLOAD, }, 113 }; 114 int ioasic_ndevs = sizeof(ioasic_devs) / sizeof(ioasic_devs[0]); 115 116 struct ioasicintr { 117 int (*iai_func)(void *); 118 void *iai_arg; 119 struct evcount iai_count; 120 } ioasicintrs[IOASIC_NCOOKIES]; 121 122 tc_addr_t ioasic_base; /* XXX XXX XXX */ 123 124 /* There can be only one. */ 125 int ioasicfound; 126 127 int 128 ioasicmatch(parent, cfdata, aux) 129 struct device *parent; 130 void *cfdata, *aux; 131 { 132 struct tc_attach_args *ta = aux; 133 134 /* Make sure that we're looking for this type of device. */ 135 if (strncmp("FLAMG-IO", ta->ta_modname, TC_ROM_LLEN)) 136 return (0); 137 138 /* Check that it can actually exist. */ 139 if ((cputype != ST_DEC_3000_500) && (cputype != ST_DEC_3000_300)) 140 panic("ioasicmatch: how did we get here?"); 141 142 if (ioasicfound) 143 return (0); 144 145 return (1); 146 } 147 148 void 149 ioasicattach(parent, self, aux) 150 struct device *parent, *self; 151 void *aux; 152 { 153 struct ioasic_softc *sc = (struct ioasic_softc *)self; 154 struct tc_attach_args *ta = aux; 155 #ifdef DEC_3000_300 156 u_long ssr; 157 #endif 158 u_long i, imsk; 159 160 ioasicfound = 1; 161 162 sc->sc_bst = ta->ta_memt; 163 if (bus_space_map(ta->ta_memt, ta->ta_addr, 164 0x400000, 0, &sc->sc_bsh)) { 165 printf("%s: unable to map device\n", sc->sc_dv.dv_xname); 166 return; 167 } 168 sc->sc_dmat = ta->ta_dmat; 169 170 ioasic_base = sc->sc_base = ta->ta_addr; /* XXX XXX XXX */ 171 172 #ifdef DEC_3000_300 173 if (cputype == ST_DEC_3000_300) { 174 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 175 ssr |= IOASIC_CSR_FASTMODE; 176 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 177 printf(": slow mode\n"); 178 } else 179 #endif 180 printf(": fast mode\n"); 181 182 /* 183 * Turn off all device interrupt bits. 184 * (This does _not_ include 3000/300 TC option slot bits. 185 */ 186 imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK); 187 for (i = 0; i < ioasic_ndevs; i++) 188 imsk &= ~ioasic_devs[i].iad_intrbits; 189 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk); 190 191 /* 192 * Set up interrupt handlers. 193 */ 194 for (i = 0; i < IOASIC_NCOOKIES; i++) { 195 ioasicintrs[i].iai_func = ioasic_intrnull; 196 ioasicintrs[i].iai_arg = (void *)i; 197 } 198 tc_intr_establish(parent, ta->ta_cookie, IPL_NONE, ioasic_intr, sc, 199 NULL); 200 201 /* 202 * Try to configure each device. 203 */ 204 ioasic_attach_devs(sc, ioasic_devs, ioasic_ndevs); 205 } 206 207 void 208 ioasic_intr_establish(ioa, cookie, level, func, arg, name) 209 struct device *ioa; 210 void *cookie, *arg; 211 int level; 212 int (*func)(void *); 213 const char *name; 214 { 215 struct ioasic_softc *sc = (void *)ioasic_cd.cd_devs[0]; 216 u_long dev, i, imsk; 217 218 dev = (u_long)cookie; 219 #ifdef DIAGNOSTIC 220 /* XXX check cookie. */ 221 #endif 222 223 if (ioasicintrs[dev].iai_func != ioasic_intrnull) 224 panic("ioasic_intr_establish: cookie %lu twice", dev); 225 226 ioasicintrs[dev].iai_func = func; 227 ioasicintrs[dev].iai_arg = arg; 228 evcount_attach(&ioasicintrs[dev].iai_count, name, NULL, &evcount_intr); 229 230 /* Enable interrupts for the device. */ 231 for (i = 0; i < ioasic_ndevs; i++) 232 if (ioasic_devs[i].iad_cookie == cookie) 233 break; 234 if (i == ioasic_ndevs) 235 panic("ioasic_intr_establish: invalid cookie."); 236 237 imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK); 238 imsk |= ioasic_devs[i].iad_intrbits; 239 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk); 240 } 241 242 void 243 ioasic_intr_disestablish(ioa, cookie) 244 struct device *ioa; 245 void *cookie; 246 { 247 struct ioasic_softc *sc = (void *)ioasic_cd.cd_devs[0]; 248 u_long dev, i, imsk; 249 250 dev = (u_long)cookie; 251 #ifdef DIAGNOSTIC 252 /* XXX check cookie. */ 253 #endif 254 255 if (ioasicintrs[dev].iai_func == ioasic_intrnull) 256 panic("ioasic_intr_disestablish: cookie %lu missing intr", dev); 257 258 /* Enable interrupts for the device. */ 259 for (i = 0; i < ioasic_ndevs; i++) 260 if (ioasic_devs[i].iad_cookie == cookie) 261 break; 262 if (i == ioasic_ndevs) 263 panic("ioasic_intr_disestablish: invalid cookie."); 264 265 imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK); 266 imsk &= ~ioasic_devs[i].iad_intrbits; 267 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk); 268 269 ioasicintrs[dev].iai_func = ioasic_intrnull; 270 ioasicintrs[dev].iai_arg = (void *)dev; 271 evcount_detach(&ioasicintrs[dev].iai_count); 272 } 273 274 int 275 ioasic_intrnull(val) 276 void *val; 277 { 278 279 panic("ioasic_intrnull: uncaught IOASIC intr for cookie %ld", 280 (u_long)val); 281 } 282 283 /* 284 * ASIC interrupt handler. 285 */ 286 int 287 ioasic_intr(val) 288 void *val; 289 { 290 register struct ioasic_softc *sc = val; 291 register int ifound; 292 int gifound; 293 u_int32_t sir, osir; 294 295 gifound = 0; 296 do { 297 ifound = 0; 298 tc_syncbus(); 299 300 osir = sir = 301 bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_INTR); 302 303 /* XXX DUPLICATION OF INTERRUPT BIT INFORMATION... */ 304 #define CHECKINTR(slot, bits, clear) \ 305 if (sir & (bits)) { \ 306 ifound = 1; \ 307 ioasicintrs[slot].iai_count.ec_count++; \ 308 (*ioasicintrs[slot].iai_func) \ 309 (ioasicintrs[slot].iai_arg); \ 310 if (clear) \ 311 sir &= ~(bits); \ 312 } 313 CHECKINTR(IOASIC_DEV_SCC0, IOASIC_INTR_SCC_0, 0); 314 CHECKINTR(IOASIC_DEV_SCC1, IOASIC_INTR_SCC_1, 0); 315 CHECKINTR(IOASIC_DEV_LANCE, IOASIC_INTR_LANCE, 0); 316 CHECKINTR(IOASIC_DEV_ISDN, IOASIC_INTR_ISDN_TXLOAD | 317 IOASIC_INTR_ISDN_RXLOAD | IOASIC_INTR_ISDN_OVRUN, 1); 318 319 if (sir != osir) 320 bus_space_write_4(sc->sc_bst, sc->sc_bsh, 321 IOASIC_INTR, sir); 322 323 gifound |= ifound; 324 } while (ifound); 325 326 return (gifound); 327 } 328