1/*- 2 * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@bluezbox.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 28#include <sys/cdefs.h> 29__FBSDID("$FreeBSD$"); 30 31#include <sys/param.h> 32#include <sys/systm.h> 33#include <sys/bus.h> 34#include <sys/kernel.h> 35#include <sys/ktr.h> 36#include <sys/module.h> 37#include <sys/rman.h> 38#include <machine/bus.h> 39#include <machine/intr.h> 40 41#include <dev/fdt/fdt_common.h> 42#include <dev/ofw/openfirm.h> 43#include <dev/ofw/ofw_bus.h> 44#include <dev/ofw/ofw_bus_subr.h> 45 46#ifdef DEBUG 47#define dprintf(fmt, args...) printf(fmt, ##args) 48#else 49#define dprintf(fmt, args...) 50#endif 51 52#define VICIRQSTATUS 0x000 53#define VICFIQSTATUS 0x004 54#define VICRAWINTR 0x008 55#define VICINTSELECT 0x00C 56#define VICINTENABLE 0x010 57#define VICINTENCLEAR 0x014 58#define VICSOFTINT 0x018 59#define VICSOFTINTCLEAR 0x01C 60#define VICPROTECTION 0x020 61#define VICPERIPHID 0xFE0 62#define VICPRIMECELLID 0xFF0 63 64#define VIC_NIRQS 32 65 66struct pl190_intc_softc { 67 device_t sc_dev; 68 struct resource * intc_res; 69}; 70 71static struct pl190_intc_softc *pl190_intc_sc = NULL; 72 73#define intc_vic_read_4(reg) \ 74 bus_read_4(pl190_intc_sc->intc_res, (reg)) 75#define intc_vic_write_4(reg, val) \ 76 bus_write_4(pl190_intc_sc->intc_res, (reg), (val)) 77 78static int 79pl190_intc_probe(device_t dev) 80{ 81 82 if (!ofw_bus_status_okay(dev)) 83 return (ENXIO); 84 85 if (!ofw_bus_is_compatible(dev, "arm,versatile-vic")) 86 return (ENXIO); 87 device_set_desc(dev, "ARM PL190 VIC"); 88 return (BUS_PROBE_DEFAULT); 89} 90 91static int 92pl190_intc_attach(device_t dev) 93{ 94 struct pl190_intc_softc *sc = device_get_softc(dev); 95 uint32_t id; 96 int i, rid; 97 98 sc->sc_dev = dev; 99 100 if (pl190_intc_sc) 101 return (ENXIO); 102 103 /* Request memory resources */ 104 rid = 0; 105 sc->intc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 106 RF_ACTIVE); 107 if (sc->intc_res == NULL) { 108 device_printf(dev, "Error: could not allocate memory resources\n"); 109 return (ENXIO); 110 } 111 112 pl190_intc_sc = sc; 113 /* 114 * All interrupts should use IRQ line 115 */ 116 intc_vic_write_4(VICINTSELECT, 0x00000000); 117 /* Disable all interrupts */ 118 intc_vic_write_4(VICINTENCLEAR, 0xffffffff); 119 /* Enable INT31, SIC IRQ */ 120 intc_vic_write_4(VICINTENABLE, (1U << 31)); 121 122 id = 0; 123 for (i = 3; i >= 0; i--) { 124 id = (id << 8) | 125 (intc_vic_read_4(VICPERIPHID + i*4) & 0xff); 126 } 127 128 device_printf(dev, "Peripheral ID: %08x\n", id); 129 130 id = 0; 131 for (i = 3; i >= 0; i--) { 132 id = (id << 8) | 133 (intc_vic_read_4(VICPRIMECELLID + i*4) & 0xff); 134 } 135 136 device_printf(dev, "PrimeCell ID: %08x\n", id); 137 138 return (0); 139} 140 141static device_method_t pl190_intc_methods[] = { 142 DEVMETHOD(device_probe, pl190_intc_probe), 143 DEVMETHOD(device_attach, pl190_intc_attach), 144 { 0, 0 } 145}; 146 147static driver_t pl190_intc_driver = { 148 "intc", 149 pl190_intc_methods, 150 sizeof(struct pl190_intc_softc), 151}; 152 153static devclass_t pl190_intc_devclass; 154 155EARLY_DRIVER_MODULE(intc, simplebus, pl190_intc_driver, pl190_intc_devclass, 156 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); 157 158int 159arm_get_next_irq(int last_irq) 160{ 161 uint32_t pending; 162 int32_t irq = last_irq + 1; 163 164 /* Sanity check */ 165 if (irq < 0) 166 irq = 0; 167 168 pending = intc_vic_read_4(VICIRQSTATUS); 169 while (irq < VIC_NIRQS) { 170 if (pending & (1 << irq)) 171 return (irq); 172 irq++; 173 } 174 175 return (-1); 176} 177 178void 179arm_mask_irq(uintptr_t nb) 180{ 181 182 dprintf("%s: %d\n", __func__, nb); 183 intc_vic_write_4(VICINTENCLEAR, (1 << nb)); 184} 185 186void 187arm_unmask_irq(uintptr_t nb) 188{ 189 190 dprintf("%s: %d\n", __func__, nb); 191 intc_vic_write_4(VICINTENABLE, (1 << nb)); 192} 193