1244195Sgonzo/*- 2244195Sgonzo * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@bluezbox.com> 3244195Sgonzo * All rights reserved. 4244195Sgonzo * 5244195Sgonzo * Redistribution and use in source and binary forms, with or without 6244195Sgonzo * modification, are permitted provided that the following conditions 7244195Sgonzo * are met: 8244195Sgonzo * 1. Redistributions of source code must retain the above copyright 9244195Sgonzo * notice, this list of conditions and the following disclaimer. 10244195Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 11244195Sgonzo * notice, this list of conditions and the following disclaimer in the 12244195Sgonzo * documentation and/or other materials provided with the distribution. 13244195Sgonzo * 14244195Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15244195Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16244195Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17244195Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18244195Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19244195Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20244195Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21244195Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22244195Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23244195Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24244195Sgonzo * SUCH DAMAGE. 25244195Sgonzo */ 26244195Sgonzo 27244195Sgonzo 28244195Sgonzo#include <sys/cdefs.h> 29244195Sgonzo__FBSDID("$FreeBSD$"); 30244195Sgonzo 31244195Sgonzo#include <sys/param.h> 32244195Sgonzo#include <sys/systm.h> 33244195Sgonzo#include <sys/bus.h> 34244195Sgonzo#include <sys/kernel.h> 35244195Sgonzo#include <sys/ktr.h> 36244195Sgonzo#include <sys/module.h> 37244195Sgonzo#include <sys/rman.h> 38244195Sgonzo#include <machine/bus.h> 39244195Sgonzo#include <machine/intr.h> 40244195Sgonzo 41244195Sgonzo#include <dev/fdt/fdt_common.h> 42244195Sgonzo#include <dev/ofw/openfirm.h> 43244195Sgonzo#include <dev/ofw/ofw_bus.h> 44244195Sgonzo#include <dev/ofw/ofw_bus_subr.h> 45244195Sgonzo 46244195Sgonzo#ifdef DEBUG 47244195Sgonzo#define dprintf(fmt, args...) printf(fmt, ##args) 48244195Sgonzo#else 49244195Sgonzo#define dprintf(fmt, args...) 50244195Sgonzo#endif 51244195Sgonzo 52244195Sgonzo#define VICIRQSTATUS 0x000 53244195Sgonzo#define VICFIQSTATUS 0x004 54244195Sgonzo#define VICRAWINTR 0x008 55244195Sgonzo#define VICINTSELECT 0x00C 56244195Sgonzo#define VICINTENABLE 0x010 57244195Sgonzo#define VICINTENCLEAR 0x014 58244195Sgonzo#define VICSOFTINT 0x018 59244195Sgonzo#define VICSOFTINTCLEAR 0x01C 60244195Sgonzo#define VICPROTECTION 0x020 61244195Sgonzo#define VICPERIPHID 0xFE0 62244195Sgonzo#define VICPRIMECELLID 0xFF0 63244195Sgonzo 64244195Sgonzo#define VIC_NIRQS 32 65244195Sgonzo 66244195Sgonzostruct pl190_intc_softc { 67244195Sgonzo device_t sc_dev; 68244195Sgonzo struct resource * intc_res; 69244195Sgonzo}; 70244195Sgonzo 71244195Sgonzostatic struct pl190_intc_softc *pl190_intc_sc = NULL; 72244195Sgonzo 73244195Sgonzo#define intc_vic_read_4(reg) \ 74244195Sgonzo bus_read_4(pl190_intc_sc->intc_res, (reg)) 75244195Sgonzo#define intc_vic_write_4(reg, val) \ 76244195Sgonzo bus_write_4(pl190_intc_sc->intc_res, (reg), (val)) 77244195Sgonzo 78244195Sgonzostatic int 79244195Sgonzopl190_intc_probe(device_t dev) 80244195Sgonzo{ 81266152Sian 82266152Sian if (!ofw_bus_status_okay(dev)) 83266152Sian return (ENXIO); 84266152Sian 85244195Sgonzo if (!ofw_bus_is_compatible(dev, "arm,versatile-vic")) 86244195Sgonzo return (ENXIO); 87244195Sgonzo device_set_desc(dev, "ARM PL190 VIC"); 88244195Sgonzo return (BUS_PROBE_DEFAULT); 89244195Sgonzo} 90244195Sgonzo 91244195Sgonzostatic int 92244195Sgonzopl190_intc_attach(device_t dev) 93244195Sgonzo{ 94244195Sgonzo struct pl190_intc_softc *sc = device_get_softc(dev); 95244195Sgonzo uint32_t id; 96244195Sgonzo int i, rid; 97244195Sgonzo 98244195Sgonzo sc->sc_dev = dev; 99244195Sgonzo 100244195Sgonzo if (pl190_intc_sc) 101244195Sgonzo return (ENXIO); 102244195Sgonzo 103244195Sgonzo /* Request memory resources */ 104244195Sgonzo rid = 0; 105244195Sgonzo sc->intc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 106244195Sgonzo RF_ACTIVE); 107244195Sgonzo if (sc->intc_res == NULL) { 108244195Sgonzo device_printf(dev, "Error: could not allocate memory resources\n"); 109244195Sgonzo return (ENXIO); 110244195Sgonzo } 111244195Sgonzo 112244195Sgonzo pl190_intc_sc = sc; 113244195Sgonzo /* 114244195Sgonzo * All interrupts should use IRQ line 115244195Sgonzo */ 116244195Sgonzo intc_vic_write_4(VICINTSELECT, 0x00000000); 117244195Sgonzo /* Disable all interrupts */ 118244195Sgonzo intc_vic_write_4(VICINTENCLEAR, 0xffffffff); 119244195Sgonzo /* Enable INT31, SIC IRQ */ 120261455Seadler intc_vic_write_4(VICINTENABLE, (1U << 31)); 121244195Sgonzo 122244195Sgonzo id = 0; 123244195Sgonzo for (i = 3; i >= 0; i--) { 124244195Sgonzo id = (id << 8) | 125244195Sgonzo (intc_vic_read_4(VICPERIPHID + i*4) & 0xff); 126244195Sgonzo } 127244195Sgonzo 128244195Sgonzo device_printf(dev, "Peripheral ID: %08x\n", id); 129244195Sgonzo 130244195Sgonzo id = 0; 131244195Sgonzo for (i = 3; i >= 0; i--) { 132244195Sgonzo id = (id << 8) | 133244195Sgonzo (intc_vic_read_4(VICPRIMECELLID + i*4) & 0xff); 134244195Sgonzo } 135244195Sgonzo 136244195Sgonzo device_printf(dev, "PrimeCell ID: %08x\n", id); 137244195Sgonzo 138244195Sgonzo return (0); 139244195Sgonzo} 140244195Sgonzo 141244195Sgonzostatic device_method_t pl190_intc_methods[] = { 142244195Sgonzo DEVMETHOD(device_probe, pl190_intc_probe), 143244195Sgonzo DEVMETHOD(device_attach, pl190_intc_attach), 144244195Sgonzo { 0, 0 } 145244195Sgonzo}; 146244195Sgonzo 147244195Sgonzostatic driver_t pl190_intc_driver = { 148244195Sgonzo "intc", 149244195Sgonzo pl190_intc_methods, 150244195Sgonzo sizeof(struct pl190_intc_softc), 151244195Sgonzo}; 152244195Sgonzo 153244195Sgonzostatic devclass_t pl190_intc_devclass; 154244195Sgonzo 155270075SianEARLY_DRIVER_MODULE(intc, simplebus, pl190_intc_driver, pl190_intc_devclass, 156270075Sian 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); 157244195Sgonzo 158244195Sgonzoint 159244195Sgonzoarm_get_next_irq(int last_irq) 160244195Sgonzo{ 161244195Sgonzo uint32_t pending; 162244195Sgonzo int32_t irq = last_irq + 1; 163244195Sgonzo 164244195Sgonzo /* Sanity check */ 165244195Sgonzo if (irq < 0) 166244195Sgonzo irq = 0; 167244195Sgonzo 168244195Sgonzo pending = intc_vic_read_4(VICIRQSTATUS); 169244195Sgonzo while (irq < VIC_NIRQS) { 170244195Sgonzo if (pending & (1 << irq)) 171244195Sgonzo return (irq); 172244195Sgonzo irq++; 173244195Sgonzo } 174244195Sgonzo 175244195Sgonzo return (-1); 176244195Sgonzo} 177244195Sgonzo 178244195Sgonzovoid 179244195Sgonzoarm_mask_irq(uintptr_t nb) 180244195Sgonzo{ 181244195Sgonzo 182244195Sgonzo dprintf("%s: %d\n", __func__, nb); 183244195Sgonzo intc_vic_write_4(VICINTENCLEAR, (1 << nb)); 184244195Sgonzo} 185244195Sgonzo 186244195Sgonzovoid 187244195Sgonzoarm_unmask_irq(uintptr_t nb) 188244195Sgonzo{ 189244195Sgonzo 190244195Sgonzo dprintf("%s: %d\n", __func__, nb); 191244195Sgonzo intc_vic_write_4(VICINTENABLE, (1 << nb)); 192244195Sgonzo} 193