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