1139825Simp/*- 299654Sbenno * Copyright (C) 2002 Benno Rice. 399654Sbenno * All rights reserved. 499654Sbenno * 599654Sbenno * Redistribution and use in source and binary forms, with or without 699654Sbenno * modification, are permitted provided that the following conditions 799654Sbenno * are met: 899654Sbenno * 1. Redistributions of source code must retain the above copyright 999654Sbenno * notice, this list of conditions and the following disclaimer. 1099654Sbenno * 2. Redistributions in binary form must reproduce the above copyright 1199654Sbenno * notice, this list of conditions and the following disclaimer in the 1299654Sbenno * documentation and/or other materials provided with the distribution. 1399654Sbenno * 1499654Sbenno * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 1599654Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1699654Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1799654Sbenno * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1899654Sbenno * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 1999654Sbenno * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 2099654Sbenno * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 2199654Sbenno * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 2299654Sbenno * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 2399654Sbenno * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2499654Sbenno * 2599654Sbenno * $FreeBSD$ 2699654Sbenno */ 2799654Sbenno 2899654Sbenno#include <sys/param.h> 2999654Sbenno#include <sys/systm.h> 3099654Sbenno#include <sys/bus.h> 3199654Sbenno#include <sys/conf.h> 3299654Sbenno#include <sys/kernel.h> 33209486Snwhitehorn#include <sys/proc.h> 34171805Smarcel#include <sys/rman.h> 35209486Snwhitehorn#include <sys/sched.h> 3699654Sbenno 3799654Sbenno#include <machine/bus.h> 3899654Sbenno#include <machine/intr_machdep.h> 3999654Sbenno#include <machine/md_var.h> 4099654Sbenno#include <machine/pio.h> 4199654Sbenno#include <machine/resource.h> 4299654Sbenno 4399654Sbenno#include <vm/vm.h> 4499654Sbenno#include <vm/pmap.h> 4599654Sbenno 4699654Sbenno#include <machine/openpicreg.h> 4799654Sbenno#include <machine/openpicvar.h> 4899654Sbenno 4999654Sbenno#include "pic_if.h" 5099654Sbenno 51171805Smarceldevclass_t openpic_devclass; 52171805Smarcel 5399654Sbenno/* 5499654Sbenno * Local routines 5599654Sbenno */ 56209298Snwhitehornstatic int openpic_intr(void *arg); 5799654Sbenno 58171805Smarcelstatic __inline uint32_t 59171805Smarcelopenpic_read(struct openpic_softc *sc, u_int reg) 60171805Smarcel{ 61171805Smarcel return (bus_space_read_4(sc->sc_bt, sc->sc_bh, reg)); 62171805Smarcel} 6399654Sbenno 64171805Smarcelstatic __inline void 65171805Smarcelopenpic_write(struct openpic_softc *sc, u_int reg, uint32_t val) 6699654Sbenno{ 67171805Smarcel bus_space_write_4(sc->sc_bt, sc->sc_bh, reg, val); 68171805Smarcel} 69124469Sgrehan 70171805Smarcelstatic __inline void 71176208Smarcelopenpic_set_priority(struct openpic_softc *sc, int pri) 72171805Smarcel{ 73176208Smarcel u_int tpr; 74171805Smarcel uint32_t x; 7599654Sbenno 76209486Snwhitehorn sched_pin(); 77209725Snwhitehorn tpr = OPENPIC_PCPU_TPR((sc->sc_dev == root_pic) ? PCPU_GET(cpuid) : 0); 78176208Smarcel x = openpic_read(sc, tpr); 79176208Smarcel x &= ~OPENPIC_TPR_MASK; 80171805Smarcel x |= pri; 81176208Smarcel openpic_write(sc, tpr, x); 82209486Snwhitehorn sched_unpin(); 83124469Sgrehan} 8499654Sbenno 85124469Sgrehanint 86218075Smarcelopenpic_common_attach(device_t dev, uint32_t node) 87124469Sgrehan{ 88124469Sgrehan struct openpic_softc *sc; 89178628Smarcel u_int cpu, ipi, irq; 90124469Sgrehan u_int32_t x; 91103603Sgrehan 92124469Sgrehan sc = device_get_softc(dev); 93171805Smarcel sc->sc_dev = dev; 94103603Sgrehan 95171805Smarcel sc->sc_rid = 0; 96171805Smarcel sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid, 97171805Smarcel RF_ACTIVE); 98124469Sgrehan 99171805Smarcel if (sc->sc_memr == NULL) { 100171805Smarcel device_printf(dev, "Could not alloc mem resource!\n"); 101171805Smarcel return (ENXIO); 102171805Smarcel } 103171805Smarcel 104171805Smarcel sc->sc_bt = rman_get_bustag(sc->sc_memr); 105171805Smarcel sc->sc_bh = rman_get_bushandle(sc->sc_memr); 106171805Smarcel 107208149Snwhitehorn /* Reset the PIC */ 108208149Snwhitehorn x = openpic_read(sc, OPENPIC_CONFIG); 109208149Snwhitehorn x |= OPENPIC_CONFIG_RESET; 110208149Snwhitehorn openpic_write(sc, OPENPIC_CONFIG, x); 111208149Snwhitehorn 112208149Snwhitehorn while (openpic_read(sc, OPENPIC_CONFIG) & OPENPIC_CONFIG_RESET) { 113208149Snwhitehorn powerpc_sync(); 114208149Snwhitehorn DELAY(100); 115208149Snwhitehorn } 116208149Snwhitehorn 117209298Snwhitehorn /* Check if this is a cascaded PIC */ 118209298Snwhitehorn sc->sc_irq = 0; 119209298Snwhitehorn sc->sc_intr = NULL; 120209485Smarcel do { 121209485Smarcel struct resource_list *rl; 122209485Smarcel 123209485Smarcel rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev); 124209485Smarcel if (rl == NULL) 125209485Smarcel break; 126209485Smarcel if (resource_list_find(rl, SYS_RES_IRQ, 0) == NULL) 127209485Smarcel break; 128209485Smarcel 129209298Snwhitehorn sc->sc_intr = bus_alloc_resource_any(dev, SYS_RES_IRQ, 130209298Snwhitehorn &sc->sc_irq, RF_ACTIVE); 131209298Snwhitehorn 132209298Snwhitehorn /* XXX Cascaded PICs pass NULL trapframes! */ 133209298Snwhitehorn bus_setup_intr(dev, sc->sc_intr, INTR_TYPE_MISC | INTR_MPSAFE, 134209298Snwhitehorn openpic_intr, NULL, dev, &sc->sc_icookie); 135209485Smarcel } while (0); 136209298Snwhitehorn 137209298Snwhitehorn /* Reset the PIC */ 138209298Snwhitehorn x = openpic_read(sc, OPENPIC_CONFIG); 139209298Snwhitehorn x |= OPENPIC_CONFIG_RESET; 140209298Snwhitehorn openpic_write(sc, OPENPIC_CONFIG, x); 141209298Snwhitehorn 142209298Snwhitehorn while (openpic_read(sc, OPENPIC_CONFIG) & OPENPIC_CONFIG_RESET) { 143209298Snwhitehorn powerpc_sync(); 144209298Snwhitehorn DELAY(100); 145209298Snwhitehorn } 146209298Snwhitehorn 147124469Sgrehan x = openpic_read(sc, OPENPIC_FEATURE); 148124469Sgrehan switch (x & OPENPIC_FEATURE_VERSION_MASK) { 14999654Sbenno case 1: 15099654Sbenno sc->sc_version = "1.0"; 15199654Sbenno break; 15299654Sbenno case 2: 15399654Sbenno sc->sc_version = "1.2"; 15499654Sbenno break; 15599654Sbenno case 3: 15699654Sbenno sc->sc_version = "1.3"; 15799654Sbenno break; 15899654Sbenno default: 15999654Sbenno sc->sc_version = "unknown"; 16099654Sbenno break; 16199654Sbenno } 16299654Sbenno 163124469Sgrehan sc->sc_ncpu = ((x & OPENPIC_FEATURE_LAST_CPU_MASK) >> 164110167Sbenno OPENPIC_FEATURE_LAST_CPU_SHIFT) + 1; 165124469Sgrehan sc->sc_nirq = ((x & OPENPIC_FEATURE_LAST_IRQ_MASK) >> 166110167Sbenno OPENPIC_FEATURE_LAST_IRQ_SHIFT) + 1; 16799654Sbenno 168111156Sgrehan /* 169193909Sgrehan * PSIM seems to report 1 too many IRQs and CPUs 170111156Sgrehan */ 171193909Sgrehan if (sc->sc_psim) { 172111156Sgrehan sc->sc_nirq--; 173193909Sgrehan sc->sc_ncpu--; 174193909Sgrehan } 175111156Sgrehan 176124469Sgrehan if (bootverbose) 177124469Sgrehan device_printf(dev, 178124469Sgrehan "Version %s, supports %d CPUs and %d irqs\n", 179124469Sgrehan sc->sc_version, sc->sc_ncpu, sc->sc_nirq); 18099654Sbenno 181178628Smarcel for (cpu = 0; cpu < sc->sc_ncpu; cpu++) 182178628Smarcel openpic_write(sc, OPENPIC_PCPU_TPR(cpu), 15); 183178628Smarcel 184176208Smarcel /* Reset and disable all interrupts. */ 185176208Smarcel for (irq = 0; irq < sc->sc_nirq; irq++) { 186176208Smarcel x = irq; /* irq == vector. */ 187176208Smarcel x |= OPENPIC_IMASK; 188209299Snwhitehorn x |= OPENPIC_POLARITY_NEGATIVE; 189176208Smarcel x |= OPENPIC_SENSE_LEVEL; 190176208Smarcel x |= 8 << OPENPIC_PRIORITY_SHIFT; 191176208Smarcel openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x); 192176208Smarcel } 19399654Sbenno 194176208Smarcel /* Reset and disable all IPIs. */ 195176208Smarcel for (ipi = 0; ipi < 4; ipi++) { 196176208Smarcel x = sc->sc_nirq + ipi; 197176208Smarcel x |= OPENPIC_IMASK; 198176208Smarcel x |= 15 << OPENPIC_PRIORITY_SHIFT; 199176208Smarcel openpic_write(sc, OPENPIC_IPI_VECTOR(ipi), x); 200176208Smarcel } 20199654Sbenno 20299654Sbenno /* we don't need 8259 passthrough mode */ 20399654Sbenno x = openpic_read(sc, OPENPIC_CONFIG); 20499654Sbenno x |= OPENPIC_CONFIG_8259_PASSTHRU_DISABLE; 20599654Sbenno openpic_write(sc, OPENPIC_CONFIG, x); 20699654Sbenno 20799654Sbenno /* send all interrupts to cpu 0 */ 20899654Sbenno for (irq = 0; irq < sc->sc_nirq; irq++) 20999654Sbenno openpic_write(sc, OPENPIC_IDEST(irq), 1 << 0); 21099654Sbenno 211209725Snwhitehorn /* clear all pending interrupts from cpu 0 */ 212103603Sgrehan for (irq = 0; irq < sc->sc_nirq; irq++) { 213209725Snwhitehorn (void)openpic_read(sc, OPENPIC_PCPU_IACK(0)); 214209725Snwhitehorn openpic_write(sc, OPENPIC_PCPU_EOI(0), 0); 21599654Sbenno } 21699654Sbenno 217183028Smarcel for (cpu = 0; cpu < sc->sc_ncpu; cpu++) 218183028Smarcel openpic_write(sc, OPENPIC_PCPU_TPR(cpu), 0); 219183028Smarcel 220218075Smarcel powerpc_register_pic(dev, node, sc->sc_nirq, 4, FALSE); 22199654Sbenno 222209298Snwhitehorn /* If this is not a cascaded PIC, it must be the root PIC */ 223209298Snwhitehorn if (sc->sc_intr == NULL) 224209298Snwhitehorn root_pic = dev; 225209298Snwhitehorn 22699654Sbenno return (0); 22799654Sbenno} 22899654Sbenno 22999654Sbenno/* 230171805Smarcel * PIC I/F methods 23199654Sbenno */ 23299654Sbenno 233171805Smarcelvoid 234222813Sattilioopenpic_bind(device_t dev, u_int irq, cpuset_t cpumask) 235209486Snwhitehorn{ 236209486Snwhitehorn struct openpic_softc *sc; 237209486Snwhitehorn 238209486Snwhitehorn /* If we aren't directly connected to the CPU, this won't work */ 239209486Snwhitehorn if (dev != root_pic) 240209486Snwhitehorn return; 241209486Snwhitehorn 242209486Snwhitehorn sc = device_get_softc(dev); 243222813Sattilio 244222813Sattilio /* 245222813Sattilio * XXX: openpic_write() is very special and just needs a 32 bits mask. 246222813Sattilio * For the moment, just play dirty and get the first half word. 247222813Sattilio */ 248222813Sattilio openpic_write(sc, OPENPIC_IDEST(irq), cpumask.__bits[0] & 0xffffffff); 249209486Snwhitehorn} 250209486Snwhitehorn 251209486Snwhitehornvoid 252176918Smarcelopenpic_config(device_t dev, u_int irq, enum intr_trigger trig, 253176918Smarcel enum intr_polarity pol) 254176918Smarcel{ 255176918Smarcel struct openpic_softc *sc; 256176918Smarcel uint32_t x; 257176918Smarcel 258176918Smarcel sc = device_get_softc(dev); 259176918Smarcel x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq)); 260176918Smarcel if (pol == INTR_POLARITY_LOW) 261176918Smarcel x &= ~OPENPIC_POLARITY_POSITIVE; 262176918Smarcel else 263176918Smarcel x |= OPENPIC_POLARITY_POSITIVE; 264176918Smarcel if (trig == INTR_TRIGGER_EDGE) 265176918Smarcel x &= ~OPENPIC_SENSE_LEVEL; 266176918Smarcel else 267176918Smarcel x |= OPENPIC_SENSE_LEVEL; 268176918Smarcel openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x); 269176918Smarcel} 270176918Smarcel 271209298Snwhitehornstatic int 272209298Snwhitehornopenpic_intr(void *arg) 273209298Snwhitehorn{ 274209298Snwhitehorn device_t dev = (device_t)(arg); 275209298Snwhitehorn 276209298Snwhitehorn /* XXX Cascaded PICs do not pass non-NULL trapframes! */ 277209298Snwhitehorn openpic_dispatch(dev, NULL); 278209298Snwhitehorn 279209298Snwhitehorn return (FILTER_HANDLED); 280209298Snwhitehorn} 281209298Snwhitehorn 282176918Smarcelvoid 283171805Smarcelopenpic_dispatch(device_t dev, struct trapframe *tf) 28499654Sbenno{ 285171805Smarcel struct openpic_softc *sc; 286183028Smarcel u_int cpuid, vector; 28799654Sbenno 288192532Sraj CTR1(KTR_INTR, "%s: got interrupt", __func__); 289192532Sraj 290209725Snwhitehorn cpuid = (dev == root_pic) ? PCPU_GET(cpuid) : 0; 291209725Snwhitehorn 292183028Smarcel sc = device_get_softc(dev); 293171805Smarcel while (1) { 294183028Smarcel vector = openpic_read(sc, OPENPIC_PCPU_IACK(cpuid)); 295171805Smarcel vector &= OPENPIC_VECTOR_MASK; 296171805Smarcel if (vector == 255) 297171805Smarcel break; 298171805Smarcel powerpc_dispatch_intr(vector, tf); 299124469Sgrehan } 30099654Sbenno} 30199654Sbenno 302171805Smarcelvoid 303171805Smarcelopenpic_enable(device_t dev, u_int irq, u_int vector) 30499654Sbenno{ 305171805Smarcel struct openpic_softc *sc; 306171805Smarcel uint32_t x; 30799654Sbenno 30899654Sbenno sc = device_get_softc(dev); 309176208Smarcel if (irq < sc->sc_nirq) { 310176208Smarcel x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq)); 311176208Smarcel x &= ~(OPENPIC_IMASK | OPENPIC_VECTOR_MASK); 312176208Smarcel x |= vector; 313176208Smarcel openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x); 314176208Smarcel } else { 315176208Smarcel x = openpic_read(sc, OPENPIC_IPI_VECTOR(0)); 316176208Smarcel x &= ~(OPENPIC_IMASK | OPENPIC_VECTOR_MASK); 317176208Smarcel x |= vector; 318176208Smarcel openpic_write(sc, OPENPIC_IPI_VECTOR(0), x); 319176208Smarcel } 32099654Sbenno} 32199654Sbenno 322171805Smarcelvoid 323171805Smarcelopenpic_eoi(device_t dev, u_int irq __unused) 32499654Sbenno{ 325171805Smarcel struct openpic_softc *sc; 326209725Snwhitehorn u_int cpuid; 32799654Sbenno 328209725Snwhitehorn cpuid = (dev == root_pic) ? PCPU_GET(cpuid) : 0; 329209725Snwhitehorn 330171805Smarcel sc = device_get_softc(dev); 331209725Snwhitehorn openpic_write(sc, OPENPIC_PCPU_EOI(cpuid), 0); 33299654Sbenno} 33399654Sbenno 334171805Smarcelvoid 335176208Smarcelopenpic_ipi(device_t dev, u_int cpu) 336176208Smarcel{ 337176208Smarcel struct openpic_softc *sc; 338176208Smarcel 339209726Snwhitehorn KASSERT(dev == root_pic, ("Cannot send IPIs from non-root OpenPIC")); 340209726Snwhitehorn 341176208Smarcel sc = device_get_softc(dev); 342209486Snwhitehorn sched_pin(); 343209726Snwhitehorn openpic_write(sc, OPENPIC_PCPU_IPI_DISPATCH(PCPU_GET(cpuid), 0), 344176208Smarcel 1u << cpu); 345209486Snwhitehorn sched_unpin(); 346176208Smarcel} 347176208Smarcel 348176208Smarcelvoid 349171805Smarcelopenpic_mask(device_t dev, u_int irq) 35099654Sbenno{ 351171805Smarcel struct openpic_softc *sc; 352171805Smarcel uint32_t x; 35399654Sbenno 354171805Smarcel sc = device_get_softc(dev); 355176208Smarcel if (irq < sc->sc_nirq) { 356176208Smarcel x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq)); 357176208Smarcel x |= OPENPIC_IMASK; 358176208Smarcel openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x); 359176208Smarcel } else { 360176208Smarcel x = openpic_read(sc, OPENPIC_IPI_VECTOR(0)); 361176208Smarcel x |= OPENPIC_IMASK; 362176208Smarcel openpic_write(sc, OPENPIC_IPI_VECTOR(0), x); 363176208Smarcel } 36499654Sbenno} 36599654Sbenno 366171805Smarcelvoid 367171805Smarcelopenpic_unmask(device_t dev, u_int irq) 36899654Sbenno{ 369171805Smarcel struct openpic_softc *sc; 370171805Smarcel uint32_t x; 37199654Sbenno 372171805Smarcel sc = device_get_softc(dev); 373176208Smarcel if (irq < sc->sc_nirq) { 374176208Smarcel x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq)); 375176208Smarcel x &= ~OPENPIC_IMASK; 376176208Smarcel openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x); 377176208Smarcel } else { 378176208Smarcel x = openpic_read(sc, OPENPIC_IPI_VECTOR(0)); 379176208Smarcel x &= ~OPENPIC_IMASK; 380176208Smarcel openpic_write(sc, OPENPIC_IPI_VECTOR(0), x); 381176208Smarcel } 38299654Sbenno} 383