openpic.c revision 209299
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: head/sys/powerpc/powerpc/openpic.c 209299 2010-06-18 14:16:24Z nwhitehorn $ 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> 33171805Smarcel#include <sys/rman.h> 3499654Sbenno 3599654Sbenno#include <machine/bus.h> 3699654Sbenno#include <machine/intr.h> 3799654Sbenno#include <machine/intr_machdep.h> 3899654Sbenno#include <machine/md_var.h> 3999654Sbenno#include <machine/pio.h> 4099654Sbenno#include <machine/resource.h> 4199654Sbenno 4299654Sbenno#include <vm/vm.h> 4399654Sbenno#include <vm/pmap.h> 4499654Sbenno 4599654Sbenno#include <machine/openpicreg.h> 4699654Sbenno#include <machine/openpicvar.h> 4799654Sbenno 4899654Sbenno#include "pic_if.h" 4999654Sbenno 50171805Smarceldevclass_t openpic_devclass; 51171805Smarcel 5299654Sbenno/* 5399654Sbenno * Local routines 5499654Sbenno */ 55209298Snwhitehornstatic int openpic_intr(void *arg); 5699654Sbenno 57171805Smarcelstatic __inline uint32_t 58171805Smarcelopenpic_read(struct openpic_softc *sc, u_int reg) 59171805Smarcel{ 60171805Smarcel return (bus_space_read_4(sc->sc_bt, sc->sc_bh, reg)); 61171805Smarcel} 6299654Sbenno 63171805Smarcelstatic __inline void 64171805Smarcelopenpic_write(struct openpic_softc *sc, u_int reg, uint32_t val) 6599654Sbenno{ 66171805Smarcel bus_space_write_4(sc->sc_bt, sc->sc_bh, reg, val); 67171805Smarcel} 68124469Sgrehan 69171805Smarcelstatic __inline void 70176208Smarcelopenpic_set_priority(struct openpic_softc *sc, int pri) 71171805Smarcel{ 72176208Smarcel u_int tpr; 73171805Smarcel uint32_t x; 7499654Sbenno 75176208Smarcel tpr = OPENPIC_PCPU_TPR(PCPU_GET(cpuid)); 76176208Smarcel x = openpic_read(sc, tpr); 77176208Smarcel x &= ~OPENPIC_TPR_MASK; 78171805Smarcel x |= pri; 79176208Smarcel openpic_write(sc, tpr, x); 80124469Sgrehan} 8199654Sbenno 82124469Sgrehanint 83124469Sgrehanopenpic_attach(device_t dev) 84124469Sgrehan{ 85124469Sgrehan struct openpic_softc *sc; 86178628Smarcel u_int cpu, ipi, irq; 87124469Sgrehan u_int32_t x; 88103603Sgrehan 89124469Sgrehan sc = device_get_softc(dev); 90171805Smarcel sc->sc_dev = dev; 91103603Sgrehan 92171805Smarcel sc->sc_rid = 0; 93171805Smarcel sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid, 94171805Smarcel RF_ACTIVE); 95124469Sgrehan 96171805Smarcel if (sc->sc_memr == NULL) { 97171805Smarcel device_printf(dev, "Could not alloc mem resource!\n"); 98171805Smarcel return (ENXIO); 99171805Smarcel } 100171805Smarcel 101171805Smarcel sc->sc_bt = rman_get_bustag(sc->sc_memr); 102171805Smarcel sc->sc_bh = rman_get_bushandle(sc->sc_memr); 103171805Smarcel 104208149Snwhitehorn /* Reset the PIC */ 105208149Snwhitehorn x = openpic_read(sc, OPENPIC_CONFIG); 106208149Snwhitehorn x |= OPENPIC_CONFIG_RESET; 107208149Snwhitehorn openpic_write(sc, OPENPIC_CONFIG, x); 108208149Snwhitehorn 109208149Snwhitehorn while (openpic_read(sc, OPENPIC_CONFIG) & OPENPIC_CONFIG_RESET) { 110208149Snwhitehorn powerpc_sync(); 111208149Snwhitehorn DELAY(100); 112208149Snwhitehorn } 113208149Snwhitehorn 114209298Snwhitehorn /* Check if this is a cascaded PIC */ 115209298Snwhitehorn sc->sc_irq = 0; 116209298Snwhitehorn sc->sc_intr = NULL; 117209298Snwhitehorn if (resource_list_find(BUS_GET_RESOURCE_LIST(device_get_parent(dev), 118209298Snwhitehorn dev), SYS_RES_IRQ, 0) != NULL) { 119209298Snwhitehorn sc->sc_intr = bus_alloc_resource_any(dev, SYS_RES_IRQ, 120209298Snwhitehorn &sc->sc_irq, RF_ACTIVE); 121209298Snwhitehorn 122209298Snwhitehorn /* XXX Cascaded PICs pass NULL trapframes! */ 123209298Snwhitehorn bus_setup_intr(dev, sc->sc_intr, INTR_TYPE_MISC | INTR_MPSAFE, 124209298Snwhitehorn openpic_intr, NULL, dev, &sc->sc_icookie); 125209298Snwhitehorn } 126209298Snwhitehorn 127209298Snwhitehorn /* Reset the PIC */ 128209298Snwhitehorn x = openpic_read(sc, OPENPIC_CONFIG); 129209298Snwhitehorn x |= OPENPIC_CONFIG_RESET; 130209298Snwhitehorn openpic_write(sc, OPENPIC_CONFIG, x); 131209298Snwhitehorn 132209298Snwhitehorn while (openpic_read(sc, OPENPIC_CONFIG) & OPENPIC_CONFIG_RESET) { 133209298Snwhitehorn powerpc_sync(); 134209298Snwhitehorn DELAY(100); 135209298Snwhitehorn } 136209298Snwhitehorn 137124469Sgrehan x = openpic_read(sc, OPENPIC_FEATURE); 138124469Sgrehan switch (x & OPENPIC_FEATURE_VERSION_MASK) { 13999654Sbenno case 1: 14099654Sbenno sc->sc_version = "1.0"; 14199654Sbenno break; 14299654Sbenno case 2: 14399654Sbenno sc->sc_version = "1.2"; 14499654Sbenno break; 14599654Sbenno case 3: 14699654Sbenno sc->sc_version = "1.3"; 14799654Sbenno break; 14899654Sbenno default: 14999654Sbenno sc->sc_version = "unknown"; 15099654Sbenno break; 15199654Sbenno } 15299654Sbenno 153124469Sgrehan sc->sc_ncpu = ((x & OPENPIC_FEATURE_LAST_CPU_MASK) >> 154110167Sbenno OPENPIC_FEATURE_LAST_CPU_SHIFT) + 1; 155124469Sgrehan sc->sc_nirq = ((x & OPENPIC_FEATURE_LAST_IRQ_MASK) >> 156110167Sbenno OPENPIC_FEATURE_LAST_IRQ_SHIFT) + 1; 15799654Sbenno 158111156Sgrehan /* 159193909Sgrehan * PSIM seems to report 1 too many IRQs and CPUs 160111156Sgrehan */ 161193909Sgrehan if (sc->sc_psim) { 162111156Sgrehan sc->sc_nirq--; 163193909Sgrehan sc->sc_ncpu--; 164193909Sgrehan } 165111156Sgrehan 166124469Sgrehan if (bootverbose) 167124469Sgrehan device_printf(dev, 168124469Sgrehan "Version %s, supports %d CPUs and %d irqs\n", 169124469Sgrehan sc->sc_version, sc->sc_ncpu, sc->sc_nirq); 17099654Sbenno 171178628Smarcel for (cpu = 0; cpu < sc->sc_ncpu; cpu++) 172178628Smarcel openpic_write(sc, OPENPIC_PCPU_TPR(cpu), 15); 173178628Smarcel 174176208Smarcel /* Reset and disable all interrupts. */ 175176208Smarcel for (irq = 0; irq < sc->sc_nirq; irq++) { 176176208Smarcel x = irq; /* irq == vector. */ 177176208Smarcel x |= OPENPIC_IMASK; 178209299Snwhitehorn x |= OPENPIC_POLARITY_NEGATIVE; 179176208Smarcel x |= OPENPIC_SENSE_LEVEL; 180176208Smarcel x |= 8 << OPENPIC_PRIORITY_SHIFT; 181176208Smarcel openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x); 182176208Smarcel } 18399654Sbenno 184176208Smarcel /* Reset and disable all IPIs. */ 185176208Smarcel for (ipi = 0; ipi < 4; ipi++) { 186176208Smarcel x = sc->sc_nirq + ipi; 187176208Smarcel x |= OPENPIC_IMASK; 188176208Smarcel x |= 15 << OPENPIC_PRIORITY_SHIFT; 189176208Smarcel openpic_write(sc, OPENPIC_IPI_VECTOR(ipi), x); 190176208Smarcel } 19199654Sbenno 19299654Sbenno /* we don't need 8259 passthrough mode */ 19399654Sbenno x = openpic_read(sc, OPENPIC_CONFIG); 19499654Sbenno x |= OPENPIC_CONFIG_8259_PASSTHRU_DISABLE; 19599654Sbenno openpic_write(sc, OPENPIC_CONFIG, x); 19699654Sbenno 19799654Sbenno /* send all interrupts to cpu 0 */ 19899654Sbenno for (irq = 0; irq < sc->sc_nirq; irq++) 19999654Sbenno openpic_write(sc, OPENPIC_IDEST(irq), 1 << 0); 20099654Sbenno 20199654Sbenno /* clear all pending interrupts */ 202103603Sgrehan for (irq = 0; irq < sc->sc_nirq; irq++) { 203176208Smarcel (void)openpic_read(sc, OPENPIC_PCPU_IACK(PCPU_GET(cpuid))); 204176208Smarcel openpic_write(sc, OPENPIC_PCPU_EOI(PCPU_GET(cpuid)), 0); 20599654Sbenno } 20699654Sbenno 207183028Smarcel for (cpu = 0; cpu < sc->sc_ncpu; cpu++) 208183028Smarcel openpic_write(sc, OPENPIC_PCPU_TPR(cpu), 0); 209183028Smarcel 210176208Smarcel powerpc_register_pic(dev, sc->sc_nirq); 21199654Sbenno 212209298Snwhitehorn /* If this is not a cascaded PIC, it must be the root PIC */ 213209298Snwhitehorn if (sc->sc_intr == NULL) 214209298Snwhitehorn root_pic = dev; 215209298Snwhitehorn 21699654Sbenno return (0); 21799654Sbenno} 21899654Sbenno 21999654Sbenno/* 220171805Smarcel * PIC I/F methods 22199654Sbenno */ 22299654Sbenno 223171805Smarcelvoid 224176918Smarcelopenpic_config(device_t dev, u_int irq, enum intr_trigger trig, 225176918Smarcel enum intr_polarity pol) 226176918Smarcel{ 227176918Smarcel struct openpic_softc *sc; 228176918Smarcel uint32_t x; 229176918Smarcel 230176918Smarcel sc = device_get_softc(dev); 231176918Smarcel x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq)); 232176918Smarcel if (pol == INTR_POLARITY_LOW) 233176918Smarcel x &= ~OPENPIC_POLARITY_POSITIVE; 234176918Smarcel else 235176918Smarcel x |= OPENPIC_POLARITY_POSITIVE; 236176918Smarcel if (trig == INTR_TRIGGER_EDGE) 237176918Smarcel x &= ~OPENPIC_SENSE_LEVEL; 238176918Smarcel else 239176918Smarcel x |= OPENPIC_SENSE_LEVEL; 240176918Smarcel openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x); 241176918Smarcel} 242176918Smarcel 243209298Snwhitehornstatic int 244209298Snwhitehornopenpic_intr(void *arg) 245209298Snwhitehorn{ 246209298Snwhitehorn device_t dev = (device_t)(arg); 247209298Snwhitehorn 248209298Snwhitehorn /* XXX Cascaded PICs do not pass non-NULL trapframes! */ 249209298Snwhitehorn openpic_dispatch(dev, NULL); 250209298Snwhitehorn 251209298Snwhitehorn return (FILTER_HANDLED); 252209298Snwhitehorn} 253209298Snwhitehorn 254176918Smarcelvoid 255171805Smarcelopenpic_dispatch(device_t dev, struct trapframe *tf) 25699654Sbenno{ 257171805Smarcel struct openpic_softc *sc; 258183028Smarcel u_int cpuid, vector; 25999654Sbenno 260192532Sraj CTR1(KTR_INTR, "%s: got interrupt", __func__); 261192532Sraj 262183028Smarcel cpuid = PCPU_GET(cpuid); 263183028Smarcel sc = device_get_softc(dev); 264178628Smarcel 265171805Smarcel while (1) { 266183028Smarcel vector = openpic_read(sc, OPENPIC_PCPU_IACK(cpuid)); 267171805Smarcel vector &= OPENPIC_VECTOR_MASK; 268171805Smarcel if (vector == 255) 269171805Smarcel break; 270171805Smarcel powerpc_dispatch_intr(vector, tf); 271124469Sgrehan } 27299654Sbenno} 27399654Sbenno 274171805Smarcelvoid 275171805Smarcelopenpic_enable(device_t dev, u_int irq, u_int vector) 27699654Sbenno{ 277171805Smarcel struct openpic_softc *sc; 278171805Smarcel uint32_t x; 27999654Sbenno 28099654Sbenno sc = device_get_softc(dev); 281176208Smarcel if (irq < sc->sc_nirq) { 282176208Smarcel x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq)); 283176208Smarcel x &= ~(OPENPIC_IMASK | OPENPIC_VECTOR_MASK); 284176208Smarcel x |= vector; 285176208Smarcel openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x); 286176208Smarcel } else { 287176208Smarcel x = openpic_read(sc, OPENPIC_IPI_VECTOR(0)); 288176208Smarcel x &= ~(OPENPIC_IMASK | OPENPIC_VECTOR_MASK); 289176208Smarcel x |= vector; 290176208Smarcel openpic_write(sc, OPENPIC_IPI_VECTOR(0), x); 291176208Smarcel } 29299654Sbenno} 29399654Sbenno 294171805Smarcelvoid 295171805Smarcelopenpic_eoi(device_t dev, u_int irq __unused) 29699654Sbenno{ 297171805Smarcel struct openpic_softc *sc; 29899654Sbenno 299171805Smarcel sc = device_get_softc(dev); 300176208Smarcel openpic_write(sc, OPENPIC_PCPU_EOI(PCPU_GET(cpuid)), 0); 30199654Sbenno} 30299654Sbenno 303171805Smarcelvoid 304176208Smarcelopenpic_ipi(device_t dev, u_int cpu) 305176208Smarcel{ 306176208Smarcel struct openpic_softc *sc; 307176208Smarcel 308176208Smarcel sc = device_get_softc(dev); 309176208Smarcel openpic_write(sc, OPENPIC_PCPU_IPI_DISPATCH(PCPU_GET(cpuid), 0), 310176208Smarcel 1u << cpu); 311176208Smarcel} 312176208Smarcel 313176208Smarcelvoid 314171805Smarcelopenpic_mask(device_t dev, u_int irq) 31599654Sbenno{ 316171805Smarcel struct openpic_softc *sc; 317171805Smarcel uint32_t x; 31899654Sbenno 319171805Smarcel sc = device_get_softc(dev); 320176208Smarcel if (irq < sc->sc_nirq) { 321176208Smarcel x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq)); 322176208Smarcel x |= OPENPIC_IMASK; 323176208Smarcel openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x); 324176208Smarcel } else { 325176208Smarcel x = openpic_read(sc, OPENPIC_IPI_VECTOR(0)); 326176208Smarcel x |= OPENPIC_IMASK; 327176208Smarcel openpic_write(sc, OPENPIC_IPI_VECTOR(0), x); 328176208Smarcel } 329176208Smarcel openpic_write(sc, OPENPIC_PCPU_EOI(PCPU_GET(cpuid)), 0); 33099654Sbenno} 33199654Sbenno 332171805Smarcelvoid 333171805Smarcelopenpic_unmask(device_t dev, u_int irq) 33499654Sbenno{ 335171805Smarcel struct openpic_softc *sc; 336171805Smarcel uint32_t x; 33799654Sbenno 338171805Smarcel sc = device_get_softc(dev); 339176208Smarcel if (irq < sc->sc_nirq) { 340176208Smarcel x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq)); 341176208Smarcel x &= ~OPENPIC_IMASK; 342176208Smarcel openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x); 343176208Smarcel } else { 344176208Smarcel x = openpic_read(sc, OPENPIC_IPI_VECTOR(0)); 345176208Smarcel x &= ~OPENPIC_IMASK; 346176208Smarcel openpic_write(sc, OPENPIC_IPI_VECTOR(0), x); 347176208Smarcel } 34899654Sbenno} 349