1 /* $OpenBSD: ioasic.c,v 1.7 1999/01/11 05:11:04 millert Exp $ */ 2 /* $NetBSD: ioasic.c,v 1.10 1996/12/05 01:39:41 cgd Exp $ */ 3 4 /* 5 * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University. 6 * All rights reserved. 7 * 8 * Author: Keith Bostic, Chris G. Demetriou 9 * 10 * Permission to use, copy, modify and distribute this software and 11 * its documentation is hereby granted, provided that both the copyright 12 * notice and this permission notice appear in all copies of the 13 * software, derivative works or modified versions, and any portions 14 * thereof, and that both notices appear in supporting documentation. 15 * 16 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 17 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 18 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 19 * 20 * Carnegie Mellon requests users of this software to return to 21 * 22 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 23 * School of Computer Science 24 * Carnegie Mellon University 25 * Pittsburgh PA 15213-3890 26 * 27 * any improvements or extensions that they make and grant Carnegie the 28 * rights to redistribute these changes. 29 */ 30 31 #include <sys/param.h> 32 #include <sys/kernel.h> 33 #include <sys/systm.h> 34 #include <sys/device.h> 35 36 #include <machine/autoconf.h> 37 #include <machine/pte.h> 38 #include <machine/rpb.h> 39 #ifndef EVCNT_COUNTERS 40 #include <machine/intrcnt.h> 41 #endif 42 43 #include <dev/tc/tcvar.h> 44 #include <alpha/tc/ioasicreg.h> 45 #include <dev/tc/ioasicvar.h> 46 47 struct ioasic_softc { 48 struct device sc_dv; 49 50 tc_addr_t sc_base; 51 void *sc_cookie; 52 }; 53 54 /* Definition of the driver for autoconfig. */ 55 #ifdef __BROKEN_INDIRECT_CONFIG 56 int ioasicmatch __P((struct device *, void *, void *)); 57 #else 58 int ioasicmatch __P((struct device *, struct cfdata *, void *)); 59 #endif 60 void ioasicattach __P((struct device *, struct device *, void *)); 61 int ioasicprint(void *, const char *); 62 63 struct cfattach ioasic_ca = { 64 sizeof(struct ioasic_softc), ioasicmatch, ioasicattach, 65 }; 66 67 struct cfdriver ioasic_cd = { 68 NULL, "ioasic", DV_DULL, 69 }; 70 71 int ioasic_intr __P((void *)); 72 int ioasic_intrnull __P((void *)); 73 74 #define C(x) ((void *)(x)) 75 76 #define IOASIC_DEV_LANCE 0 77 #define IOASIC_DEV_SCC0 1 78 #define IOASIC_DEV_SCC1 2 79 #define IOASIC_DEV_ISDN 3 80 81 #define IOASIC_DEV_BOGUS -1 82 83 #define IOASIC_NCOOKIES 4 84 85 struct ioasic_dev { 86 char *iad_modname; 87 tc_offset_t iad_offset; 88 void *iad_cookie; 89 u_int32_t iad_intrbits; 90 } ioasic_devs[] = { 91 /* XXX lance name */ 92 { "lance", 0x000c0000, C(IOASIC_DEV_LANCE), IOASIC_INTR_LANCE, }, 93 { "z8530 ", 0x00100000, C(IOASIC_DEV_SCC0), IOASIC_INTR_SCC_0, }, 94 { "z8530 ", 0x00180000, C(IOASIC_DEV_SCC1), IOASIC_INTR_SCC_1, }, 95 { "TOY_RTC ", 0x00200000, C(IOASIC_DEV_BOGUS), 0, }, 96 { "AMD79c30", 0x00240000, C(IOASIC_DEV_ISDN), IOASIC_INTR_ISDN, }, 97 }; 98 int ioasic_ndevs = sizeof(ioasic_devs) / sizeof(ioasic_devs[0]); 99 100 struct ioasicintr { 101 int (*iai_func) __P((void *)); 102 void *iai_arg; 103 } ioasicintrs[IOASIC_NCOOKIES]; 104 105 tc_addr_t ioasic_base; /* XXX XXX XXX */ 106 107 /* There can be only one. */ 108 int ioasicfound; 109 110 extern int cputype; 111 112 int 113 ioasicmatch(parent, cfdata, aux) 114 struct device *parent; 115 #ifdef __BROKEN_INDIRECT_CONFIG 116 void *cfdata; 117 #else 118 struct cfdata *cfdata; 119 #endif 120 void *aux; 121 { 122 struct tc_attach_args *ta = aux; 123 124 /* Make sure that we're looking for this type of device. */ 125 if (strncmp("FLAMG-IO", ta->ta_modname, TC_ROM_LLEN)) 126 return (0); 127 128 /* Check that it can actually exist. */ 129 if ((cputype != ST_DEC_3000_500) && (cputype != ST_DEC_3000_300)) 130 panic("ioasicmatch: how did we get here?"); 131 132 if (ioasicfound) 133 return (0); 134 135 return (1); 136 } 137 138 void 139 ioasicattach(parent, self, aux) 140 struct device *parent, *self; 141 void *aux; 142 { 143 struct ioasic_softc *sc = (struct ioasic_softc *)self; 144 struct tc_attach_args *ta = aux; 145 struct ioasicdev_attach_args ioasicdev; 146 u_long i; 147 148 ioasicfound = 1; 149 150 sc->sc_base = ta->ta_addr; 151 ioasic_base = sc->sc_base; /* XXX XXX XXX */ 152 sc->sc_cookie = ta->ta_cookie; 153 154 #ifdef DEC_3000_300 155 if (cputype == ST_DEC_3000_300) { 156 *(volatile u_int *)IOASIC_REG_CSR(sc->sc_base) |= 157 IOASIC_CSR_FASTMODE; 158 tc_mb(); 159 printf(": slow mode\n"); 160 } else 161 #endif 162 printf(": fast mode\n"); 163 164 /* 165 * Turn off all device interrupt bits. 166 * (This does _not_ include 3000/300 TC option slot bits. 167 */ 168 for (i = 0; i < ioasic_ndevs; i++) 169 *(volatile u_int32_t *)IOASIC_REG_IMSK(ioasic_base) &= 170 ~ioasic_devs[i].iad_intrbits; 171 tc_mb(); 172 173 /* 174 * Set up interrupt handlers. 175 */ 176 for (i = 0; i < IOASIC_NCOOKIES; i++) { 177 ioasicintrs[i].iai_func = ioasic_intrnull; 178 ioasicintrs[i].iai_arg = (void *)i; 179 } 180 tc_intr_establish(parent, sc->sc_cookie, TC_IPL_NONE, ioasic_intr, sc); 181 182 /* 183 * Try to configure each device. 184 */ 185 for (i = 0; i < ioasic_ndevs; i++) { 186 strncpy(ioasicdev.iada_modname, ioasic_devs[i].iad_modname, 187 TC_ROM_LLEN); 188 ioasicdev.iada_modname[TC_ROM_LLEN] = '\0'; 189 ioasicdev.iada_offset = ioasic_devs[i].iad_offset; 190 ioasicdev.iada_addr = sc->sc_base + ioasic_devs[i].iad_offset; 191 ioasicdev.iada_cookie = ioasic_devs[i].iad_cookie; 192 193 /* Tell the autoconfig machinery we've found the hardware. */ 194 config_found(self, &ioasicdev, ioasicprint); 195 } 196 } 197 198 int 199 ioasicprint(aux, pnp) 200 void *aux; 201 const char *pnp; 202 { 203 struct ioasicdev_attach_args *d = aux; 204 205 if (pnp) 206 printf("%s at %s", d->iada_modname, pnp); 207 printf(" offset 0x%lx", (long)d->iada_offset); 208 return (UNCONF); 209 } 210 211 int 212 ioasic_submatch(match, d) 213 struct cfdata *match; 214 struct ioasicdev_attach_args *d; 215 { 216 217 return ((match->ioasiccf_offset == d->iada_offset) || 218 (match->ioasiccf_offset == IOASIC_OFFSET_UNKNOWN)); 219 } 220 221 void 222 ioasic_intr_establish(ioa, cookie, level, func, arg) 223 struct device *ioa; 224 void *cookie, *arg; 225 tc_intrlevel_t level; 226 int (*func) __P((void *)); 227 { 228 u_long dev, i; 229 230 dev = (u_long)cookie; 231 #ifdef DIAGNOSTIC 232 /* XXX check cookie. */ 233 #endif 234 235 if (ioasicintrs[dev].iai_func != ioasic_intrnull) 236 panic("ioasic_intr_establish: cookie %d twice", dev); 237 238 ioasicintrs[dev].iai_func = func; 239 ioasicintrs[dev].iai_arg = arg; 240 241 /* Enable interrupts for the device. */ 242 for (i = 0; i < ioasic_ndevs; i++) 243 if (ioasic_devs[i].iad_cookie == cookie) 244 break; 245 if (i == ioasic_ndevs) 246 panic("ioasic_intr_establish: invalid cookie."); 247 *(volatile u_int32_t *)IOASIC_REG_IMSK(ioasic_base) |= 248 ioasic_devs[i].iad_intrbits; 249 tc_mb(); 250 } 251 252 void 253 ioasic_intr_disestablish(ioa, cookie) 254 struct device *ioa; 255 void *cookie; 256 { 257 u_long dev, i; 258 259 dev = (u_long)cookie; 260 #ifdef DIAGNOSTIC 261 /* XXX check cookie. */ 262 #endif 263 264 if (ioasicintrs[dev].iai_func == ioasic_intrnull) 265 panic("ioasic_intr_disestablish: cookie %d missing intr", dev); 266 267 /* Enable interrupts for the device. */ 268 for (i = 0; i < ioasic_ndevs; i++) 269 if (ioasic_devs[i].iad_cookie == cookie) 270 break; 271 if (i == ioasic_ndevs) 272 panic("ioasic_intr_disestablish: invalid cookie."); 273 *(volatile u_int32_t *)IOASIC_REG_IMSK(ioasic_base) &= 274 ~ioasic_devs[i].iad_intrbits; 275 tc_mb(); 276 277 ioasicintrs[dev].iai_func = ioasic_intrnull; 278 ioasicintrs[dev].iai_arg = (void *)dev; 279 } 280 281 int 282 ioasic_intrnull(val) 283 void *val; 284 { 285 286 panic("ioasic_intrnull: uncaught IOASIC intr for cookie %ld", 287 (u_long)val); 288 } 289 290 /* 291 * asic_intr -- 292 * ASIC interrupt handler. 293 */ 294 int 295 ioasic_intr(val) 296 void *val; 297 { 298 register struct ioasic_softc *sc = val; 299 register int ifound; 300 int gifound; 301 u_int32_t sir; 302 volatile u_int32_t *sirp; 303 304 sirp = (volatile u_int32_t *)IOASIC_REG_INTR(sc->sc_base); 305 306 gifound = 0; 307 do { 308 ifound = 0; 309 tc_syncbus(); 310 311 sir = *sirp; 312 313 #ifdef EVCNT_COUNTERS 314 /* No interrupt counting via evcnt counters */ 315 XXX BREAK HERE XXX 316 #else /* !EVCNT_COUNTERS */ 317 #define INCRINTRCNT(slot) intrcnt[INTRCNT_IOASIC + slot]++ 318 #endif /* EVCNT_COUNTERS */ 319 320 /* XXX DUPLICATION OF INTERRUPT BIT INFORMATION... */ 321 #define CHECKINTR(slot, bits) \ 322 if (sir & bits) { \ 323 ifound = 1; \ 324 INCRINTRCNT(slot); \ 325 (*ioasicintrs[slot].iai_func) \ 326 (ioasicintrs[slot].iai_arg); \ 327 } 328 CHECKINTR(IOASIC_DEV_SCC0, IOASIC_INTR_SCC_0); 329 CHECKINTR(IOASIC_DEV_SCC1, IOASIC_INTR_SCC_1); 330 CHECKINTR(IOASIC_DEV_LANCE, IOASIC_INTR_LANCE); 331 CHECKINTR(IOASIC_DEV_ISDN, IOASIC_INTR_ISDN); 332 333 gifound |= ifound; 334 } while (ifound); 335 336 return (gifound); 337 } 338 339 /* XXX */ 340 char * 341 ioasic_lance_ether_address() 342 { 343 344 return (u_char *)IOASIC_SYS_ETHER_ADDRESS(ioasic_base); 345 } 346 347 void 348 ioasic_lance_dma_setup(v) 349 void *v; 350 { 351 volatile u_int32_t *ldp; 352 tc_addr_t tca; 353 354 tca = (tc_addr_t)v; 355 356 ldp = (volatile u_int *)IOASIC_REG_LANCE_DMAPTR(ioasic_base); 357 *ldp = ((tca << 3) & ~(tc_addr_t)0x1f) | ((tca >> 29) & 0x1f); 358 tc_wmb(); 359 360 *(volatile u_int32_t *)IOASIC_REG_CSR(ioasic_base) |= 361 IOASIC_CSR_DMAEN_LANCE; 362 tc_mb(); 363 } 364