1191450Smarcel/*- 2191450Smarcel * Copyright (c) 2009 Marcel Moolenaar 3191450Smarcel * 4191450Smarcel * Redistribution and use in source and binary forms, with or without 5191450Smarcel * modification, are permitted provided that the following conditions 6191450Smarcel * are met: 7191450Smarcel * 1. Redistributions of source code must retain the above copyright 8191450Smarcel * notice, this list of conditions and the following disclaimer. 9191450Smarcel * 2. Redistributions in binary form must reproduce the above copyright 10191450Smarcel * notice, this list of conditions and the following disclaimer in the 11191450Smarcel * documentation and/or other materials provided with the distribution. 12191450Smarcel * 13191450Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14191450Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15191450Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16191450Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17191450Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 18191450Smarcel * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19191450Smarcel * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 20191450Smarcel * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21191450Smarcel * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22191450Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23191450Smarcel * SUCH DAMAGE. 24191450Smarcel */ 25191450Smarcel 26191450Smarcel#include <sys/cdefs.h> 27191450Smarcel__FBSDID("$FreeBSD$"); 28191450Smarcel 29191450Smarcel#include <sys/param.h> 30191450Smarcel#include <sys/systm.h> 31224552Smarcel#include <sys/bus.h> 32224552Smarcel#include <sys/cpuset.h> 33191450Smarcel#include <sys/kernel.h> 34191450Smarcel#include <sys/module.h> 35191450Smarcel#include <sys/rman.h> 36191450Smarcel 37191450Smarcel#include <machine/bus.h> 38191450Smarcel#include <machine/intr_machdep.h> 39191450Smarcel#include <machine/pio.h> 40191450Smarcel 41209908Sraj#include <powerpc/mpc85xx/mpc85xx.h> 42191450Smarcel 43191450Smarcel#include <dev/ic/i8259.h> 44191450Smarcel 45191450Smarcel#include <isa/isareg.h> 46191450Smarcel#include <isa/isavar.h> 47191450Smarcel 48191450Smarcel#include "pic_if.h" 49191450Smarcel 50191450Smarcel#define ATPIC_MASTER 0 51191450Smarcel#define ATPIC_SLAVE 1 52191450Smarcel 53191450Smarcelstruct atpic_softc { 54191450Smarcel device_t sc_dev; 55191450Smarcel 56191450Smarcel /* I/O port resources for master & slave. */ 57191450Smarcel struct resource *sc_res[2]; 58191450Smarcel int sc_rid[2]; 59191450Smarcel 60191450Smarcel /* Our "routing" interrupt */ 61191450Smarcel struct resource *sc_ires; 62191450Smarcel void *sc_icookie; 63191450Smarcel int sc_irid; 64191450Smarcel 65191450Smarcel int sc_vector[16]; 66191450Smarcel uint8_t sc_mask[2]; 67191450Smarcel}; 68191450Smarcel 69191450Smarcelstatic int atpic_isa_attach(device_t); 70191450Smarcelstatic void atpic_isa_identify(driver_t *, device_t); 71191450Smarcelstatic int atpic_isa_probe(device_t); 72191450Smarcel 73191450Smarcelstatic void atpic_config(device_t, u_int, enum intr_trigger, 74191450Smarcel enum intr_polarity); 75191450Smarcelstatic void atpic_dispatch(device_t, struct trapframe *); 76191450Smarcelstatic void atpic_enable(device_t, u_int, u_int); 77191450Smarcelstatic void atpic_eoi(device_t, u_int); 78191450Smarcelstatic void atpic_ipi(device_t, u_int); 79191450Smarcelstatic void atpic_mask(device_t, u_int); 80191450Smarcelstatic void atpic_unmask(device_t, u_int); 81191450Smarcel 82191450Smarcelstatic device_method_t atpic_isa_methods[] = { 83191450Smarcel /* Device interface */ 84191450Smarcel DEVMETHOD(device_identify, atpic_isa_identify), 85191450Smarcel DEVMETHOD(device_probe, atpic_isa_probe), 86191450Smarcel DEVMETHOD(device_attach, atpic_isa_attach), 87191450Smarcel 88191450Smarcel /* PIC interface */ 89191450Smarcel DEVMETHOD(pic_config, atpic_config), 90191450Smarcel DEVMETHOD(pic_dispatch, atpic_dispatch), 91191450Smarcel DEVMETHOD(pic_enable, atpic_enable), 92191450Smarcel DEVMETHOD(pic_eoi, atpic_eoi), 93191450Smarcel DEVMETHOD(pic_ipi, atpic_ipi), 94191450Smarcel DEVMETHOD(pic_mask, atpic_mask), 95191450Smarcel DEVMETHOD(pic_unmask, atpic_unmask), 96191450Smarcel 97191450Smarcel { 0, 0 }, 98191450Smarcel}; 99191450Smarcel 100191450Smarcelstatic driver_t atpic_isa_driver = { 101191450Smarcel "atpic", 102191450Smarcel atpic_isa_methods, 103191450Smarcel sizeof(struct atpic_softc) 104191450Smarcel}; 105191450Smarcel 106191450Smarcelstatic devclass_t atpic_devclass; 107191450Smarcel 108191450SmarcelDRIVER_MODULE(atpic, isa, atpic_isa_driver, atpic_devclass, 0, 0); 109191450Smarcel 110191450Smarcelstatic struct isa_pnp_id atpic_ids[] = { 111191450Smarcel { 0x0000d041 /* PNP0000 */, "AT interrupt controller" }, 112191450Smarcel { 0 } 113191450Smarcel}; 114191450Smarcel 115191450Smarcelstatic __inline uint8_t 116191450Smarcelatpic_read(struct atpic_softc *sc, int icu, int ofs) 117191450Smarcel{ 118191450Smarcel uint8_t val; 119191450Smarcel 120191450Smarcel val = bus_read_1(sc->sc_res[icu], ofs); 121191450Smarcel return (val); 122191450Smarcel} 123191450Smarcel 124191450Smarcelstatic __inline void 125191450Smarcelatpic_write(struct atpic_softc *sc, int icu, int ofs, uint8_t val) 126191450Smarcel{ 127191450Smarcel 128191450Smarcel bus_write_1(sc->sc_res[icu], ofs, val); 129191450Smarcel bus_barrier(sc->sc_res[icu], ofs, 2 - ofs, 130191450Smarcel BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE); 131191450Smarcel} 132191450Smarcel 133191450Smarcelstatic void 134191450Smarcelatpic_intr(void *arg) 135191450Smarcel{ 136191450Smarcel 137209493Smarcel atpic_dispatch(arg, NULL); 138191450Smarcel} 139191450Smarcel 140191450Smarcelstatic void 141191450Smarcelatpic_isa_identify(driver_t *drv, device_t parent) 142191450Smarcel{ 143191450Smarcel device_t child; 144191450Smarcel 145191450Smarcel child = BUS_ADD_CHILD(parent, ISA_ORDER_SENSITIVE, drv->name, -1); 146191450Smarcel device_set_driver(child, drv); 147191450Smarcel isa_set_logicalid(child, atpic_ids[0].ip_id); 148191450Smarcel isa_set_vendorid(child, atpic_ids[0].ip_id); 149191450Smarcel 150191450Smarcel bus_set_resource(child, SYS_RES_IOPORT, ATPIC_MASTER, IO_ICU1, 2); 151191450Smarcel bus_set_resource(child, SYS_RES_IOPORT, ATPIC_SLAVE, IO_ICU2, 2); 152191450Smarcel 153191450Smarcel /* ISA interrupts are routed through external interrupt 0. */ 154218075Smarcel bus_set_resource(child, SYS_RES_IRQ, 0, 16, 1); 155191450Smarcel} 156191450Smarcel 157191450Smarcelstatic int 158191450Smarcelatpic_isa_probe(device_t dev) 159191450Smarcel{ 160191450Smarcel int res; 161191450Smarcel 162191450Smarcel res = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids); 163191450Smarcel if (res > 0) 164191450Smarcel return (res); 165191450Smarcel 166191450Smarcel device_set_desc(dev, "PC/AT compatible PIC"); 167191450Smarcel return (res); 168191450Smarcel} 169191450Smarcel 170191450Smarcelstatic void 171191450Smarcelatpic_init(struct atpic_softc *sc, int icu) 172191450Smarcel{ 173191450Smarcel 174191450Smarcel sc->sc_mask[icu] = 0xff - ((icu == ATPIC_MASTER) ? 4 : 0); 175191450Smarcel 176191450Smarcel atpic_write(sc, icu, 0, ICW1_RESET | ICW1_IC4); 177191450Smarcel atpic_write(sc, icu, 1, (icu == ATPIC_SLAVE) ? 8 : 0); 178191450Smarcel atpic_write(sc, icu, 1, (icu == ATPIC_SLAVE) ? 2 : 4); 179191450Smarcel atpic_write(sc, icu, 1, ICW4_8086); 180191450Smarcel atpic_write(sc, icu, 1, sc->sc_mask[icu]); 181191450Smarcel atpic_write(sc, icu, 0, OCW3_SEL | OCW3_RR); 182191450Smarcel} 183191450Smarcel 184191450Smarcelstatic int 185191450Smarcelatpic_isa_attach(device_t dev) 186191450Smarcel{ 187191450Smarcel struct atpic_softc *sc; 188191450Smarcel int error; 189191450Smarcel 190191450Smarcel sc = device_get_softc(dev); 191191450Smarcel sc->sc_dev = dev; 192191450Smarcel 193191450Smarcel error = ENXIO; 194191450Smarcel 195191450Smarcel sc->sc_rid[ATPIC_MASTER] = 0; 196191450Smarcel sc->sc_res[ATPIC_MASTER] = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 197191450Smarcel &sc->sc_rid[ATPIC_MASTER], RF_ACTIVE); 198191450Smarcel if (sc->sc_res[ATPIC_MASTER] == NULL) 199191450Smarcel goto fail; 200191450Smarcel 201191450Smarcel sc->sc_rid[ATPIC_SLAVE] = 1; 202191450Smarcel sc->sc_res[ATPIC_SLAVE] = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 203191450Smarcel &sc->sc_rid[ATPIC_SLAVE], RF_ACTIVE); 204191450Smarcel if (sc->sc_res[ATPIC_SLAVE] == NULL) 205191450Smarcel goto fail; 206191450Smarcel 207191450Smarcel sc->sc_irid = 0; 208191450Smarcel sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irid, 209191450Smarcel RF_ACTIVE); 210191450Smarcel if (sc->sc_ires == NULL) 211191450Smarcel goto fail; 212191450Smarcel 213193144Smarcel error = bus_setup_intr(dev, sc->sc_ires, INTR_TYPE_MISC | INTR_MPSAFE, 214209493Smarcel NULL, atpic_intr, dev, &sc->sc_icookie); 215191450Smarcel if (error) 216191450Smarcel goto fail; 217191450Smarcel 218191450Smarcel atpic_init(sc, ATPIC_SLAVE); 219191450Smarcel atpic_init(sc, ATPIC_MASTER); 220191450Smarcel 221218075Smarcel powerpc_register_pic(dev, 0, 16, 0, TRUE); 222191450Smarcel return (0); 223191450Smarcel 224191450Smarcel fail: 225191450Smarcel if (sc->sc_ires != NULL) 226191450Smarcel bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, 227191450Smarcel sc->sc_ires); 228191450Smarcel if (sc->sc_res[ATPIC_SLAVE] != NULL) 229191450Smarcel bus_release_resource(dev, SYS_RES_IOPORT, 230191450Smarcel sc->sc_rid[ATPIC_SLAVE], sc->sc_res[ATPIC_SLAVE]); 231191450Smarcel if (sc->sc_res[ATPIC_MASTER] != NULL) 232191450Smarcel bus_release_resource(dev, SYS_RES_IOPORT, 233191450Smarcel sc->sc_rid[ATPIC_MASTER], sc->sc_res[ATPIC_MASTER]); 234191450Smarcel return (error); 235191450Smarcel} 236191450Smarcel 237191450Smarcel 238191450Smarcel/* 239191450Smarcel * PIC interface. 240191450Smarcel */ 241191450Smarcel 242191450Smarcelstatic void 243191450Smarcelatpic_config(device_t dev, u_int irq, enum intr_trigger trig, 244191450Smarcel enum intr_polarity pol) 245191450Smarcel{ 246191450Smarcel} 247191450Smarcel 248191450Smarcelstatic void 249191450Smarcelatpic_dispatch(device_t dev, struct trapframe *tf) 250191450Smarcel{ 251191450Smarcel struct atpic_softc *sc; 252191450Smarcel uint8_t irq; 253191450Smarcel 254191450Smarcel sc = device_get_softc(dev); 255191450Smarcel atpic_write(sc, ATPIC_MASTER, 0, OCW3_SEL | OCW3_P); 256191450Smarcel irq = atpic_read(sc, ATPIC_MASTER, 0); 257191450Smarcel atpic_write(sc, ATPIC_MASTER, 0, OCW3_SEL | OCW3_RR); 258191450Smarcel if ((irq & 0x80) == 0) 259191450Smarcel return; 260191450Smarcel 261191450Smarcel if (irq == 0x82) { 262191450Smarcel atpic_write(sc, ATPIC_SLAVE, 0, OCW3_SEL | OCW3_P); 263191450Smarcel irq = atpic_read(sc, ATPIC_SLAVE, 0) + 8; 264191450Smarcel atpic_write(sc, ATPIC_SLAVE, 0, OCW3_SEL | OCW3_RR); 265191450Smarcel if ((irq & 0x80) == 0) 266191450Smarcel return; 267191450Smarcel } 268191450Smarcel 269191450Smarcel powerpc_dispatch_intr(sc->sc_vector[irq & 0x0f], tf); 270191450Smarcel} 271191450Smarcel 272191450Smarcelstatic void 273191450Smarcelatpic_enable(device_t dev, u_int irq, u_int vector) 274191450Smarcel{ 275191450Smarcel struct atpic_softc *sc; 276191450Smarcel 277191450Smarcel sc = device_get_softc(dev); 278191450Smarcel sc->sc_vector[irq] = vector; 279191450Smarcel atpic_unmask(dev, irq); 280191450Smarcel} 281191450Smarcel 282191450Smarcelstatic void 283191450Smarcelatpic_eoi(device_t dev, u_int irq) 284191450Smarcel{ 285191450Smarcel struct atpic_softc *sc; 286191450Smarcel 287191450Smarcel sc = device_get_softc(dev); 288191450Smarcel if (irq > 7) 289191450Smarcel atpic_write(sc, ATPIC_SLAVE, 0, OCW2_EOI); 290191450Smarcel atpic_write(sc, ATPIC_MASTER, 0, OCW2_EOI); 291191450Smarcel} 292191450Smarcel 293191450Smarcelstatic void 294191450Smarcelatpic_ipi(device_t dev, u_int cpu) 295191450Smarcel{ 296191450Smarcel /* No SMP support. */ 297191450Smarcel} 298191450Smarcel 299191450Smarcelstatic void 300191450Smarcelatpic_mask(device_t dev, u_int irq) 301191450Smarcel{ 302191450Smarcel struct atpic_softc *sc; 303191450Smarcel 304191450Smarcel sc = device_get_softc(dev); 305191450Smarcel if (irq > 7) { 306191450Smarcel sc->sc_mask[ATPIC_SLAVE] |= 1 << (irq - 8); 307191450Smarcel atpic_write(sc, ATPIC_SLAVE, 1, sc->sc_mask[ATPIC_SLAVE]); 308191450Smarcel } else { 309191450Smarcel sc->sc_mask[ATPIC_MASTER] |= 1 << irq; 310191450Smarcel atpic_write(sc, ATPIC_MASTER, 1, sc->sc_mask[ATPIC_MASTER]); 311191450Smarcel } 312191450Smarcel} 313191450Smarcel 314191450Smarcelstatic void 315191450Smarcelatpic_unmask(device_t dev, u_int irq) 316191450Smarcel{ 317191450Smarcel struct atpic_softc *sc; 318191450Smarcel 319191450Smarcel sc = device_get_softc(dev); 320191450Smarcel if (irq > 7) { 321191450Smarcel sc->sc_mask[ATPIC_SLAVE] &= ~(1 << (irq - 8)); 322191450Smarcel atpic_write(sc, ATPIC_SLAVE, 1, sc->sc_mask[ATPIC_SLAVE]); 323191450Smarcel } else { 324191450Smarcel sc->sc_mask[ATPIC_MASTER] &= ~(1 << irq); 325191450Smarcel atpic_write(sc, ATPIC_MASTER, 1, sc->sc_mask[ATPIC_MASTER]); 326191450Smarcel } 327191450Smarcel} 328