1239478Sadrian/*- 2239478Sadrian * Copyright (C) 2012 Margarida Gouveia 3239478Sadrian * All rights reserved. 4239478Sadrian * 5239478Sadrian * Redistribution and use in source and binary forms, with or without 6239478Sadrian * modification, are permitted provided that the following conditions 7239478Sadrian * are met: 8239478Sadrian * 1. Redistributions of source code must retain the above copyright 9239478Sadrian * notice, this list of conditions and the following disclaimer. 10239478Sadrian * 2. Redistributions in binary form must reproduce the above copyright 11239478Sadrian * notice, this list of conditions and the following disclaimer in the 12239478Sadrian * documentation and/or other materials provided with the distribution. 13239478Sadrian * 14239478Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15239478Sadrian * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16239478Sadrian * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17239478Sadrian * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18239478Sadrian * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 19239478Sadrian * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20239478Sadrian * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 21239478Sadrian * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22239478Sadrian * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23239478Sadrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24239478Sadrian * SUCH DAMAGE. 25239478Sadrian */ 26239478Sadrian#include <sys/cdefs.h> 27239478Sadrian__FBSDID("$FreeBSD: releng/10.3/sys/powerpc/wii/wii_pic.c 249826 2013-04-24 01:36:35Z rpaulo $"); 28239478Sadrian 29239478Sadrian#include <sys/param.h> 30239478Sadrian#include <sys/systm.h> 31239478Sadrian#include <sys/module.h> 32239478Sadrian#include <sys/bus.h> 33239478Sadrian#include <sys/conf.h> 34239478Sadrian#include <sys/kernel.h> 35239478Sadrian#include <sys/malloc.h> 36239478Sadrian#include <sys/rman.h> 37249826Srpaulo#include <sys/reboot.h> 38239478Sadrian 39239478Sadrian#include <machine/bus.h> 40239478Sadrian#include <machine/platform.h> 41239478Sadrian#include <machine/intr_machdep.h> 42239478Sadrian#include <machine/resource.h> 43239478Sadrian 44239478Sadrian#include <powerpc/wii/wii_picreg.h> 45239478Sadrian 46239478Sadrian#include "pic_if.h" 47239478Sadrian 48239478Sadrianstatic int wiipic_probe(device_t); 49239478Sadrianstatic int wiipic_attach(device_t); 50239478Sadrianstatic void wiipic_dispatch(device_t, struct trapframe *); 51239478Sadrianstatic void wiipic_enable(device_t, unsigned int, unsigned int); 52239478Sadrianstatic void wiipic_eoi(device_t, unsigned int); 53239478Sadrianstatic void wiipic_mask(device_t, unsigned int); 54239478Sadrianstatic void wiipic_unmask(device_t, unsigned int); 55249826Srpaulostatic void wiipic_intr(void *); 56239478Sadrian 57239478Sadrianstruct wiipic_softc { 58239478Sadrian device_t sc_dev; 59239478Sadrian struct resource *sc_rres; 60239478Sadrian bus_space_tag_t sc_bt; 61239478Sadrian bus_space_handle_t sc_bh; 62239478Sadrian int sc_rrid; 63249826Srpaulo int sc_irqid; 64249826Srpaulo struct resource *sc_irq; 65249826Srpaulo void *sc_irqctx; 66239478Sadrian int sc_vector[WIIPIC_NIRQ]; 67239478Sadrian}; 68239478Sadrian 69239478Sadrianstatic device_method_t wiipic_methods[] = { 70239478Sadrian /* Device interface */ 71239478Sadrian DEVMETHOD(device_probe, wiipic_probe), 72239478Sadrian DEVMETHOD(device_attach, wiipic_attach), 73239478Sadrian 74239478Sadrian /* PIC interface */ 75239478Sadrian DEVMETHOD(pic_dispatch, wiipic_dispatch), 76239478Sadrian DEVMETHOD(pic_enable, wiipic_enable), 77239478Sadrian DEVMETHOD(pic_eoi, wiipic_eoi), 78239478Sadrian DEVMETHOD(pic_mask, wiipic_mask), 79239478Sadrian DEVMETHOD(pic_unmask, wiipic_unmask), 80239478Sadrian 81246655Srpaulo DEVMETHOD_END 82239478Sadrian}; 83239478Sadrian 84239478Sadrianstatic driver_t wiipic_driver = { 85239478Sadrian "wiipic", 86239478Sadrian wiipic_methods, 87239478Sadrian sizeof(struct wiipic_softc) 88239478Sadrian}; 89239478Sadrian 90239478Sadrianstatic devclass_t wiipic_devclass; 91239478Sadrian 92239478SadrianDRIVER_MODULE(wiipic, wiibus, wiipic_driver, wiipic_devclass, 0, 0); 93239478Sadrian 94239478Sadrianstatic __inline uint32_t 95239478Sadrianwiipic_imr_read(struct wiipic_softc *sc) 96239478Sadrian{ 97239478Sadrian 98239478Sadrian return (bus_space_read_4(sc->sc_bt, sc->sc_bh, WIIPIC_IMR)); 99239478Sadrian} 100239478Sadrian 101239478Sadrianstatic __inline void 102239478Sadrianwiipic_imr_write(struct wiipic_softc *sc, uint32_t imr) 103239478Sadrian{ 104239478Sadrian 105239478Sadrian bus_space_write_4(sc->sc_bt, sc->sc_bh, WIIPIC_IMR, imr); 106239478Sadrian} 107239478Sadrian 108239478Sadrianstatic __inline uint32_t 109239478Sadrianwiipic_icr_read(struct wiipic_softc *sc) 110239478Sadrian{ 111239478Sadrian 112239478Sadrian return (bus_space_read_4(sc->sc_bt, sc->sc_bh, WIIPIC_ICR)); 113239478Sadrian} 114239478Sadrian 115239478Sadrianstatic __inline void 116239478Sadrianwiipic_icr_write(struct wiipic_softc *sc, uint32_t icr) 117239478Sadrian{ 118239478Sadrian 119239478Sadrian bus_space_write_4(sc->sc_bt, sc->sc_bh, WIIPIC_ICR, icr); 120239478Sadrian} 121239478Sadrian 122239478Sadrianstatic int 123239478Sadrianwiipic_probe(device_t dev) 124239478Sadrian{ 125239478Sadrian device_set_desc(dev, "Nintendo Wii PIC"); 126239478Sadrian 127239478Sadrian return (BUS_PROBE_NOWILDCARD); 128239478Sadrian} 129239478Sadrian 130239478Sadrianstatic int 131239478Sadrianwiipic_attach(device_t dev) 132239478Sadrian{ 133239478Sadrian struct wiipic_softc *sc; 134239478Sadrian 135239478Sadrian sc = device_get_softc(dev); 136239478Sadrian sc->sc_dev = dev; 137239478Sadrian 138239478Sadrian sc->sc_rrid = 0; 139239478Sadrian sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 140239478Sadrian &sc->sc_rrid, RF_ACTIVE); 141239478Sadrian if (sc->sc_rres == NULL) { 142239478Sadrian device_printf(dev, "could not alloc mem resource\n"); 143239478Sadrian return (ENXIO); 144239478Sadrian } 145239478Sadrian sc->sc_bt = rman_get_bustag(sc->sc_rres); 146239478Sadrian sc->sc_bh = rman_get_bushandle(sc->sc_rres); 147239478Sadrian 148239478Sadrian /* Turn off all interrupts */ 149239478Sadrian wiipic_imr_write(sc, 0x00000000); 150239478Sadrian wiipic_icr_write(sc, 0xffffffff); 151239478Sadrian 152239478Sadrian powerpc_register_pic(dev, 0, WIIPIC_NIRQ, 0, FALSE); 153239478Sadrian 154249826Srpaulo /* 155249826Srpaulo * Setup the interrupt handler. 156249826Srpaulo */ 157249826Srpaulo sc->sc_irqid = 0; 158249826Srpaulo sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqid, 159249826Srpaulo RF_ACTIVE); 160249826Srpaulo if (sc->sc_irq == NULL) { 161249826Srpaulo device_printf(dev, "could not alloc IRQ resource\n"); 162249826Srpaulo return (ENXIO); 163249826Srpaulo } 164249826Srpaulo bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC | INTR_MPSAFE, 165249826Srpaulo NULL, wiipic_intr, sc, &sc->sc_irqctx); 166249826Srpaulo 167239478Sadrian return (0); 168239478Sadrian} 169239478Sadrian 170239478Sadrianstatic void 171239478Sadrianwiipic_dispatch(device_t dev, struct trapframe *tf) 172239478Sadrian{ 173239478Sadrian struct wiipic_softc *sc; 174239478Sadrian uint32_t irq; 175239478Sadrian 176239478Sadrian sc = device_get_softc(dev); 177249718Srpaulo irq = wiipic_icr_read(sc) & wiipic_imr_read(sc); 178249718Srpaulo if (irq == 0) 179249718Srpaulo return; 180249718Srpaulo irq = ffs(irq) - 1; 181239478Sadrian KASSERT(irq < WIIPIC_NIRQ, ("bogus irq %d", irq)); 182239478Sadrian powerpc_dispatch_intr(sc->sc_vector[irq], tf); 183239478Sadrian} 184239478Sadrian 185239478Sadrianstatic void 186239478Sadrianwiipic_enable(device_t dev, unsigned int irq, unsigned int vector) 187239478Sadrian{ 188239478Sadrian struct wiipic_softc *sc; 189239478Sadrian 190239478Sadrian KASSERT(irq < WIIPIC_NIRQ, ("bogus irq %d", irq)); 191239478Sadrian sc = device_get_softc(dev); 192239478Sadrian sc->sc_vector[irq] = vector; 193239478Sadrian wiipic_unmask(dev, irq); 194239478Sadrian} 195239478Sadrian 196239478Sadrianstatic void 197239478Sadrianwiipic_eoi(device_t dev, unsigned int irq) 198239478Sadrian{ 199239478Sadrian struct wiipic_softc *sc; 200239478Sadrian uint32_t icr; 201239478Sadrian 202239478Sadrian sc = device_get_softc(dev); 203239478Sadrian icr = wiipic_icr_read(sc); 204239478Sadrian icr |= (1 << irq); 205239478Sadrian wiipic_icr_write(sc, icr); 206239478Sadrian} 207239478Sadrian 208239478Sadrianstatic void 209239478Sadrianwiipic_mask(device_t dev, unsigned int irq) 210239478Sadrian{ 211239478Sadrian struct wiipic_softc *sc; 212239478Sadrian uint32_t imr; 213239478Sadrian 214239478Sadrian sc = device_get_softc(dev); 215239478Sadrian imr = wiipic_imr_read(sc); 216239478Sadrian imr &= ~(1 << irq); 217239478Sadrian wiipic_imr_write(sc, imr); 218239478Sadrian} 219239478Sadrian 220239478Sadrianstatic void 221239478Sadrianwiipic_unmask(device_t dev, unsigned int irq) 222239478Sadrian{ 223239478Sadrian struct wiipic_softc *sc; 224239478Sadrian uint32_t imr; 225239478Sadrian 226239478Sadrian sc = device_get_softc(dev); 227239478Sadrian imr = wiipic_imr_read(sc); 228239478Sadrian imr |= (1 << irq); 229239478Sadrian wiipic_imr_write(sc, imr); 230239478Sadrian} 231249826Srpaulo 232249826Srpaulo/* 233249826Srpaulo * Reset button interrupt. 234249826Srpaulo */ 235249826Srpaulostatic void 236249826Srpaulowiipic_intr(void *xsc) 237249826Srpaulo{ 238249826Srpaulo struct wiipic_softc *sc; 239249826Srpaulo 240249826Srpaulo sc = (struct wiipic_softc *)xsc; 241249826Srpaulo if (wiipic_icr_read(sc) & WIIPIC_RBS) 242249826Srpaulo shutdown_nice(RB_AUTOBOOT); 243249826Srpaulo} 244249826Srpaulo 245