1 /* $OpenBSD: ioasic.c,v 1.18 2017/10/11 08:14:28 mpi 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 #include <sys/timeout.h> 67 68 #include <machine/autoconf.h> 69 #include <machine/bus.h> 70 #include <machine/pte.h> 71 #include <machine/rpb.h> 72 73 #include <dev/tc/tcvar.h> 74 #include <dev/tc/ioasicreg.h> 75 #include <dev/tc/ioasicvar.h> 76 #ifdef DEC_3000_300 77 #include <alpha/tc/tc_3000_300.h> 78 #endif 79 80 /* Definition of the driver for autoconfig. */ 81 int ioasicmatch(struct device *, void *, void *); 82 void ioasicattach(struct device *, struct device *, void *); 83 84 struct cfattach ioasic_ca = { 85 sizeof(struct ioasic_softc), ioasicmatch, ioasicattach, 86 }; 87 88 struct cfdriver ioasic_cd = { 89 NULL, "ioasic", DV_DULL, 90 }; 91 92 int ioasic_intr(void *); 93 int ioasic_intrnull(void *); 94 void ioasic_led_blink(void *); 95 96 #define C(x) ((void *)(u_long)(x)) 97 #define KV(x) (ALPHA_PHYS_TO_K0SEG(x)) 98 99 #define IOASIC_DEV_LANCE 0 100 #define IOASIC_DEV_SCC0 1 101 #define IOASIC_DEV_SCC1 2 102 #define IOASIC_DEV_ISDN 3 103 104 #define IOASIC_DEV_BOGUS -1 105 106 #define IOASIC_NCOOKIES 4 107 108 struct ioasic_dev ioasic_devs[] = { 109 { "PMAD-BA ", IOASIC_SLOT_3_START, C(IOASIC_DEV_LANCE), 110 IOASIC_INTR_LANCE, }, 111 { "z8530 ", IOASIC_SLOT_4_START, C(IOASIC_DEV_SCC0), 112 IOASIC_INTR_SCC_0, }, 113 { "z8530 ", IOASIC_SLOT_6_START, C(IOASIC_DEV_SCC1), 114 IOASIC_INTR_SCC_1, }, 115 { "TOY_RTC ", IOASIC_SLOT_8_START, C(IOASIC_DEV_BOGUS), 116 0, }, 117 { "AMD79c30", IOASIC_SLOT_9_START, C(IOASIC_DEV_ISDN), 118 IOASIC_INTR_ISDN_TXLOAD | IOASIC_INTR_ISDN_RXLOAD, }, 119 }; 120 int ioasic_ndevs = sizeof(ioasic_devs) / sizeof(ioasic_devs[0]); 121 122 struct ioasicintr { 123 int (*iai_func)(void *); 124 void *iai_arg; 125 struct evcount iai_count; 126 } ioasicintrs[IOASIC_NCOOKIES]; 127 128 tc_addr_t ioasic_base; /* XXX XXX XXX */ 129 130 /* There can be only one. */ 131 int ioasicfound; 132 133 int 134 ioasicmatch(parent, cfdata, aux) 135 struct device *parent; 136 void *cfdata, *aux; 137 { 138 struct tc_attach_args *ta = aux; 139 140 /* Make sure that we're looking for this type of device. */ 141 if (strncmp("FLAMG-IO", ta->ta_modname, TC_ROM_LLEN)) 142 return (0); 143 144 /* Check that it can actually exist. */ 145 if ((cputype != ST_DEC_3000_500) && (cputype != ST_DEC_3000_300)) 146 panic("ioasicmatch: how did we get here?"); 147 148 if (ioasicfound) 149 return (0); 150 151 return (1); 152 } 153 154 void 155 ioasicattach(parent, self, aux) 156 struct device *parent, *self; 157 void *aux; 158 { 159 struct ioasic_softc *sc = (struct ioasic_softc *)self; 160 struct tc_attach_args *ta = aux; 161 #ifdef DEC_3000_300 162 u_long ssr; 163 #endif 164 u_long i, imsk; 165 166 ioasicfound = 1; 167 168 sc->sc_bst = ta->ta_memt; 169 if (bus_space_map(ta->ta_memt, ta->ta_addr, 170 0x400000, 0, &sc->sc_bsh)) { 171 printf("%s: unable to map device\n", sc->sc_dv.dv_xname); 172 return; 173 } 174 sc->sc_dmat = ta->ta_dmat; 175 176 ioasic_base = sc->sc_base = ta->ta_addr; /* XXX XXX XXX */ 177 178 #ifdef DEC_3000_300 179 if (cputype == ST_DEC_3000_300) { 180 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 181 ssr |= IOASIC_CSR_FASTMODE; 182 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 183 printf(": slow mode\n"); 184 } else 185 #endif 186 printf(": fast mode\n"); 187 188 /* 189 * Turn off all device interrupt bits. 190 * (This does _not_ include 3000/300 TC option slot bits). 191 */ 192 imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK); 193 for (i = 0; i < ioasic_ndevs; i++) 194 imsk &= ~ioasic_devs[i].iad_intrbits; 195 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk); 196 197 /* 198 * Set up interrupt handlers. 199 */ 200 for (i = 0; i < IOASIC_NCOOKIES; i++) { 201 ioasicintrs[i].iai_func = ioasic_intrnull; 202 ioasicintrs[i].iai_arg = (void *)i; 203 } 204 tc_intr_establish(parent, ta->ta_cookie, IPL_NONE, ioasic_intr, sc, 205 NULL); 206 207 /* 208 * Try to configure each device. 209 */ 210 ioasic_attach_devs(sc, ioasic_devs, ioasic_ndevs); 211 212 ioasic_led_blink(NULL); 213 } 214 215 void 216 ioasic_intr_establish(ioa, cookie, level, func, arg, name) 217 struct device *ioa; 218 void *cookie, *arg; 219 int level; 220 int (*func)(void *); 221 const char *name; 222 { 223 struct ioasic_softc *sc = (void *)ioasic_cd.cd_devs[0]; 224 u_long dev, i, imsk; 225 226 dev = (u_long)cookie; 227 #ifdef DIAGNOSTIC 228 /* XXX check cookie. */ 229 #endif 230 231 if (ioasicintrs[dev].iai_func != ioasic_intrnull) 232 panic("ioasic_intr_establish: cookie %lu twice", dev); 233 234 ioasicintrs[dev].iai_func = func; 235 ioasicintrs[dev].iai_arg = arg; 236 evcount_attach(&ioasicintrs[dev].iai_count, name, NULL); 237 238 /* Enable interrupts for the device. */ 239 for (i = 0; i < ioasic_ndevs; i++) 240 if (ioasic_devs[i].iad_cookie == cookie) 241 break; 242 if (i == ioasic_ndevs) 243 panic("ioasic_intr_establish: invalid cookie."); 244 245 imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK); 246 imsk |= ioasic_devs[i].iad_intrbits; 247 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk); 248 } 249 250 void 251 ioasic_intr_disestablish(ioa, cookie) 252 struct device *ioa; 253 void *cookie; 254 { 255 struct ioasic_softc *sc = (void *)ioasic_cd.cd_devs[0]; 256 u_long dev, i, imsk; 257 258 dev = (u_long)cookie; 259 #ifdef DIAGNOSTIC 260 /* XXX check cookie. */ 261 #endif 262 263 if (ioasicintrs[dev].iai_func == ioasic_intrnull) 264 panic("ioasic_intr_disestablish: cookie %lu missing intr", dev); 265 266 /* Enable interrupts for the device. */ 267 for (i = 0; i < ioasic_ndevs; i++) 268 if (ioasic_devs[i].iad_cookie == cookie) 269 break; 270 if (i == ioasic_ndevs) 271 panic("ioasic_intr_disestablish: invalid cookie."); 272 273 imsk = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK); 274 imsk &= ~ioasic_devs[i].iad_intrbits; 275 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_IMSK, imsk); 276 277 ioasicintrs[dev].iai_func = ioasic_intrnull; 278 ioasicintrs[dev].iai_arg = (void *)dev; 279 evcount_detach(&ioasicintrs[dev].iai_count); 280 } 281 282 int 283 ioasic_intrnull(val) 284 void *val; 285 { 286 287 panic("ioasic_intrnull: uncaught IOASIC intr for cookie %ld", 288 (u_long)val); 289 } 290 291 /* 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, osir; 302 303 gifound = 0; 304 do { 305 ifound = 0; 306 tc_syncbus(); 307 308 osir = sir = 309 bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_INTR); 310 311 /* XXX DUPLICATION OF INTERRUPT BIT INFORMATION... */ 312 #define CHECKINTR(slot, bits, clear) \ 313 if (sir & (bits)) { \ 314 ifound = 1; \ 315 ioasicintrs[slot].iai_count.ec_count++; \ 316 (*ioasicintrs[slot].iai_func) \ 317 (ioasicintrs[slot].iai_arg); \ 318 if (clear) \ 319 sir &= ~(bits); \ 320 } 321 CHECKINTR(IOASIC_DEV_SCC0, IOASIC_INTR_SCC_0, 0); 322 CHECKINTR(IOASIC_DEV_SCC1, IOASIC_INTR_SCC_1, 0); 323 CHECKINTR(IOASIC_DEV_LANCE, IOASIC_INTR_LANCE, 0); 324 CHECKINTR(IOASIC_DEV_ISDN, IOASIC_INTR_ISDN_TXLOAD | 325 IOASIC_INTR_ISDN_RXLOAD | IOASIC_INTR_ISDN_OVRUN, 1); 326 327 if (sir != osir) 328 bus_space_write_4(sc->sc_bst, sc->sc_bsh, 329 IOASIC_INTR, sir); 330 331 gifound |= ifound; 332 } while (ifound); 333 334 return (gifound); 335 } 336 337 /* 338 * Blink leds 339 */ 340 341 struct { 342 int patpos; 343 struct timeout tmo; 344 } led_blink_state; 345 346 static const uint8_t led_pattern8[] = { 347 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 348 0x40, 0x20, 0x10, 0x08, 0x04, 0x02 349 }; 350 351 void 352 ioasic_led_blink(void *unused) 353 { 354 extern int alpha_led_blink; /* machdep.c */ 355 vaddr_t rw_csr; 356 u_int32_t pattern; 357 int display_loadavg; 358 359 if (alpha_led_blink == 0) { 360 pattern = 0; /* all clear */ 361 led_blink_state.patpos = 0; 362 } else { 363 #ifdef DEC_3000_300 364 if (cputype == ST_DEC_3000_300) 365 display_loadavg = 0; 366 else 367 #endif 368 switch (hwrpb->rpb_variation & SV_ST_MASK) { 369 case SV_ST_FLAMINGO: 370 case SV_ST_HOTPINK: 371 case SV_ST_FLAMINGOPLUS: 372 case SV_ST_ULTRA: 373 case SV_ST_FLAMINGO45: 374 /* 500/800/900, 2 7-segment display, display loadavg */ 375 display_loadavg = 1; 376 break; 377 case SV_ST_SANDPIPER: 378 case SV_ST_SANDPLUS: 379 case SV_ST_SANDPIPER45: 380 default: 381 /* 400/600/700, 8 leds, display moving pattern */ 382 display_loadavg = 0; 383 break; 384 } 385 386 if (display_loadavg) 387 pattern = averunnable.ldavg[0] >> FSHIFT; 388 else { 389 pattern = led_pattern8[led_blink_state.patpos]; 390 led_blink_state.patpos = 391 (led_blink_state.patpos + 1) % sizeof(led_pattern8); 392 } 393 } 394 395 /* 396 * The low 8 bits, controlling the leds, are read-only in the 397 * CSR register, but read-write in its image at CSR + 4. 398 * 399 * On model 300, however, the internal 8 leds are at a different 400 * address, but the (better visible) power supply led is actually 401 * bit 5 in CSR (active low). 402 */ 403 #ifdef DEC_3000_300 404 if (cputype == ST_DEC_3000_300) { 405 rw_csr = KV(0x1a0000000 + IOASIC_CSR + 4); 406 407 *(volatile uint32_t *)TC_3000_300_LED = 408 (*(volatile uint32_t *)TC_3000_300_LED & ~(0xff << 16)) | 409 (pattern << 16); 410 /* 411 * Blink the power supply led 8x slower. This relies 412 * on led_pattern8[] being a < 16 element array. 413 */ 414 *(volatile uint32_t *)rw_csr = 415 (*(volatile uint32_t *)rw_csr & ~(1 << 5)) ^ 416 ((led_blink_state.patpos >> 3) << 5); 417 } else 418 #endif 419 { 420 rw_csr = KV(0x1e0000000 + IOASIC_CSR + 4); 421 422 *(volatile uint32_t *)rw_csr = 423 (*(volatile uint32_t *)rw_csr & ~0xff) | pattern; 424 } 425 426 if (alpha_led_blink != 0) { 427 timeout_set(&led_blink_state.tmo, ioasic_led_blink, NULL); 428 timeout_add(&led_blink_state.tmo, 429 (((averunnable.ldavg[0] + FSCALE) * hz) >> (FSHIFT + 3))); 430 } 431 } 432