1 /*- 2 * Copyright (C) 2002 Benno Rice. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * 25 * $FreeBSD$ 26 */ 27 28 #include <sys/param.h> 29 #include <sys/systm.h> 30 #include <sys/bus.h> 31 #include <sys/conf.h> 32 #include <sys/kernel.h> 33 #include <sys/rman.h> 34 35 #include <machine/bus.h> 36 #include <machine/intr.h> 37 #include <machine/intr_machdep.h> 38 #include <machine/md_var.h> 39 #include <machine/pio.h> 40 #include <machine/resource.h> 41 42 #include <vm/vm.h> 43 #include <vm/pmap.h> 44 45 #include <machine/openpicreg.h> 46 #include <machine/openpicvar.h> 47 48 #include "pic_if.h" 49 50 devclass_t openpic_devclass; 51 52 /* 53 * Local routines 54 */ 55 56 static __inline uint32_t 57 openpic_read(struct openpic_softc *sc, u_int reg) 58 { 59 return (bus_space_read_4(sc->sc_bt, sc->sc_bh, reg)); 60 } 61 62 static __inline void 63 openpic_write(struct openpic_softc *sc, u_int reg, uint32_t val) 64 { 65 bus_space_write_4(sc->sc_bt, sc->sc_bh, reg, val); 66 } 67 68 static __inline void 69 openpic_set_priority(struct openpic_softc *sc, int pri) 70 { 71 u_int tpr; 72 uint32_t x; 73 74 tpr = OPENPIC_PCPU_TPR(PCPU_GET(cpuid)); 75 x = openpic_read(sc, tpr); 76 x &= ~OPENPIC_TPR_MASK; 77 x |= pri; 78 openpic_write(sc, tpr, x); 79 } 80 81 int 82 openpic_attach(device_t dev) 83 { 84 struct openpic_softc *sc; 85 u_int cpu, ipi, irq; 86 u_int32_t x; 87 88 sc = device_get_softc(dev); 89 sc->sc_dev = dev; 90 91 sc->sc_rid = 0; 92 sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid, 93 RF_ACTIVE); 94 95 if (sc->sc_memr == NULL) { 96 device_printf(dev, "Could not alloc mem resource!\n"); 97 return (ENXIO); 98 } 99 100 sc->sc_bt = rman_get_bustag(sc->sc_memr); 101 sc->sc_bh = rman_get_bushandle(sc->sc_memr); 102 103 /* Reset the PIC */ 104 x = openpic_read(sc, OPENPIC_CONFIG); 105 x |= OPENPIC_CONFIG_RESET; 106 openpic_write(sc, OPENPIC_CONFIG, x); 107 108 while (openpic_read(sc, OPENPIC_CONFIG) & OPENPIC_CONFIG_RESET) { 109 powerpc_sync(); 110 DELAY(100); 111 } 112 113 x = openpic_read(sc, OPENPIC_FEATURE); 114 switch (x & OPENPIC_FEATURE_VERSION_MASK) { 115 case 1: 116 sc->sc_version = "1.0"; 117 break; 118 case 2: 119 sc->sc_version = "1.2"; 120 break; 121 case 3: 122 sc->sc_version = "1.3"; 123 break; 124 default: 125 sc->sc_version = "unknown"; 126 break; 127 } 128 129 sc->sc_ncpu = ((x & OPENPIC_FEATURE_LAST_CPU_MASK) >> 130 OPENPIC_FEATURE_LAST_CPU_SHIFT) + 1; 131 sc->sc_nirq = ((x & OPENPIC_FEATURE_LAST_IRQ_MASK) >> 132 OPENPIC_FEATURE_LAST_IRQ_SHIFT) + 1; 133 134 /* 135 * PSIM seems to report 1 too many IRQs and CPUs 136 */ 137 if (sc->sc_psim) { 138 sc->sc_nirq--; 139 sc->sc_ncpu--; 140 } 141 142 if (bootverbose) 143 device_printf(dev, 144 "Version %s, supports %d CPUs and %d irqs\n", 145 sc->sc_version, sc->sc_ncpu, sc->sc_nirq); 146 147 for (cpu = 0; cpu < sc->sc_ncpu; cpu++) 148 openpic_write(sc, OPENPIC_PCPU_TPR(cpu), 15); 149 150 /* Reset and disable all interrupts. */ 151 for (irq = 0; irq < sc->sc_nirq; irq++) { 152 x = irq; /* irq == vector. */ 153 x |= OPENPIC_IMASK; 154 x |= OPENPIC_POLARITY_POSITIVE; 155 x |= OPENPIC_SENSE_LEVEL; 156 x |= 8 << OPENPIC_PRIORITY_SHIFT; 157 openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x); 158 } 159 160 /* Reset and disable all IPIs. */ 161 for (ipi = 0; ipi < 4; ipi++) { 162 x = sc->sc_nirq + ipi; 163 x |= OPENPIC_IMASK; 164 x |= 15 << OPENPIC_PRIORITY_SHIFT; 165 openpic_write(sc, OPENPIC_IPI_VECTOR(ipi), x); 166 } 167 168 /* we don't need 8259 passthrough mode */ 169 x = openpic_read(sc, OPENPIC_CONFIG); 170 x |= OPENPIC_CONFIG_8259_PASSTHRU_DISABLE; 171 openpic_write(sc, OPENPIC_CONFIG, x); 172 173 /* send all interrupts to cpu 0 */ 174 for (irq = 0; irq < sc->sc_nirq; irq++) 175 openpic_write(sc, OPENPIC_IDEST(irq), 1 << 0); 176 177 /* clear all pending interrupts */ 178 for (irq = 0; irq < sc->sc_nirq; irq++) { 179 (void)openpic_read(sc, OPENPIC_PCPU_IACK(PCPU_GET(cpuid))); 180 openpic_write(sc, OPENPIC_PCPU_EOI(PCPU_GET(cpuid)), 0); 181 } 182 183 for (cpu = 0; cpu < sc->sc_ncpu; cpu++) 184 openpic_write(sc, OPENPIC_PCPU_TPR(cpu), 0); 185 186 powerpc_register_pic(dev, sc->sc_nirq); 187 188 return (0); 189 } 190 191 /* 192 * PIC I/F methods 193 */ 194 195 void 196 openpic_config(device_t dev, u_int irq, enum intr_trigger trig, 197 enum intr_polarity pol) 198 { 199 struct openpic_softc *sc; 200 uint32_t x; 201 202 sc = device_get_softc(dev); 203 x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq)); 204 if (pol == INTR_POLARITY_LOW) 205 x &= ~OPENPIC_POLARITY_POSITIVE; 206 else 207 x |= OPENPIC_POLARITY_POSITIVE; 208 if (trig == INTR_TRIGGER_EDGE) 209 x &= ~OPENPIC_SENSE_LEVEL; 210 else 211 x |= OPENPIC_SENSE_LEVEL; 212 openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x); 213 } 214 215 void 216 openpic_dispatch(device_t dev, struct trapframe *tf) 217 { 218 struct openpic_softc *sc; 219 u_int cpuid, vector; 220 221 CTR1(KTR_INTR, "%s: got interrupt", __func__); 222 223 cpuid = PCPU_GET(cpuid); 224 sc = device_get_softc(dev); 225 226 while (1) { 227 vector = openpic_read(sc, OPENPIC_PCPU_IACK(cpuid)); 228 vector &= OPENPIC_VECTOR_MASK; 229 if (vector == 255) 230 break; 231 powerpc_dispatch_intr(vector, tf); 232 } 233 } 234 235 void 236 openpic_enable(device_t dev, u_int irq, u_int vector) 237 { 238 struct openpic_softc *sc; 239 uint32_t x; 240 241 sc = device_get_softc(dev); 242 if (irq < sc->sc_nirq) { 243 x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq)); 244 x &= ~(OPENPIC_IMASK | OPENPIC_VECTOR_MASK); 245 x |= vector; 246 openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x); 247 } else { 248 x = openpic_read(sc, OPENPIC_IPI_VECTOR(0)); 249 x &= ~(OPENPIC_IMASK | OPENPIC_VECTOR_MASK); 250 x |= vector; 251 openpic_write(sc, OPENPIC_IPI_VECTOR(0), x); 252 } 253 } 254 255 void 256 openpic_eoi(device_t dev, u_int irq __unused) 257 { 258 struct openpic_softc *sc; 259 260 sc = device_get_softc(dev); 261 openpic_write(sc, OPENPIC_PCPU_EOI(PCPU_GET(cpuid)), 0); 262 } 263 264 void 265 openpic_ipi(device_t dev, u_int cpu) 266 { 267 struct openpic_softc *sc; 268 269 sc = device_get_softc(dev); 270 openpic_write(sc, OPENPIC_PCPU_IPI_DISPATCH(PCPU_GET(cpuid), 0), 271 1u << cpu); 272 } 273 274 void 275 openpic_mask(device_t dev, u_int irq) 276 { 277 struct openpic_softc *sc; 278 uint32_t x; 279 280 sc = device_get_softc(dev); 281 if (irq < sc->sc_nirq) { 282 x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq)); 283 x |= OPENPIC_IMASK; 284 openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x); 285 } else { 286 x = openpic_read(sc, OPENPIC_IPI_VECTOR(0)); 287 x |= OPENPIC_IMASK; 288 openpic_write(sc, OPENPIC_IPI_VECTOR(0), x); 289 } 290 openpic_write(sc, OPENPIC_PCPU_EOI(PCPU_GET(cpuid)), 0); 291 } 292 293 void 294 openpic_unmask(device_t dev, u_int irq) 295 { 296 struct openpic_softc *sc; 297 uint32_t x; 298 299 sc = device_get_softc(dev); 300 if (irq < sc->sc_nirq) { 301 x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq)); 302 x &= ~OPENPIC_IMASK; 303 openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x); 304 } else { 305 x = openpic_read(sc, OPENPIC_IPI_VECTOR(0)); 306 x &= ~OPENPIC_IMASK; 307 openpic_write(sc, OPENPIC_IPI_VECTOR(0), x); 308 } 309 } 310