pl190.c revision 261455
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: stable/10/sys/arm/arm/pl190.c 261455 2014-02-04 03:36:42Z eadler $"); 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 if (!ofw_bus_is_compatible(dev, "arm,versatile-vic")) 82 return (ENXIO); 83 device_set_desc(dev, "ARM PL190 VIC"); 84 return (BUS_PROBE_DEFAULT); 85} 86 87static int 88pl190_intc_attach(device_t dev) 89{ 90 struct pl190_intc_softc *sc = device_get_softc(dev); 91 uint32_t id; 92 int i, rid; 93 94 sc->sc_dev = dev; 95 96 if (pl190_intc_sc) 97 return (ENXIO); 98 99 /* Request memory resources */ 100 rid = 0; 101 sc->intc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 102 RF_ACTIVE); 103 if (sc->intc_res == NULL) { 104 device_printf(dev, "Error: could not allocate memory resources\n"); 105 return (ENXIO); 106 } 107 108 pl190_intc_sc = sc; 109 /* 110 * All interrupts should use IRQ line 111 */ 112 intc_vic_write_4(VICINTSELECT, 0x00000000); 113 /* Disable all interrupts */ 114 intc_vic_write_4(VICINTENCLEAR, 0xffffffff); 115 /* Enable INT31, SIC IRQ */ 116 intc_vic_write_4(VICINTENABLE, (1U << 31)); 117 118 id = 0; 119 for (i = 3; i >= 0; i--) { 120 id = (id << 8) | 121 (intc_vic_read_4(VICPERIPHID + i*4) & 0xff); 122 } 123 124 device_printf(dev, "Peripheral ID: %08x\n", id); 125 126 id = 0; 127 for (i = 3; i >= 0; i--) { 128 id = (id << 8) | 129 (intc_vic_read_4(VICPRIMECELLID + i*4) & 0xff); 130 } 131 132 device_printf(dev, "PrimeCell ID: %08x\n", id); 133 134 return (0); 135} 136 137static device_method_t pl190_intc_methods[] = { 138 DEVMETHOD(device_probe, pl190_intc_probe), 139 DEVMETHOD(device_attach, pl190_intc_attach), 140 { 0, 0 } 141}; 142 143static driver_t pl190_intc_driver = { 144 "intc", 145 pl190_intc_methods, 146 sizeof(struct pl190_intc_softc), 147}; 148 149static devclass_t pl190_intc_devclass; 150 151DRIVER_MODULE(intc, simplebus, pl190_intc_driver, pl190_intc_devclass, 0, 0); 152 153int 154arm_get_next_irq(int last_irq) 155{ 156 uint32_t pending; 157 int32_t irq = last_irq + 1; 158 159 /* Sanity check */ 160 if (irq < 0) 161 irq = 0; 162 163 pending = intc_vic_read_4(VICIRQSTATUS); 164 while (irq < VIC_NIRQS) { 165 if (pending & (1 << irq)) 166 return (irq); 167 irq++; 168 } 169 170 return (-1); 171} 172 173void 174arm_mask_irq(uintptr_t nb) 175{ 176 177 dprintf("%s: %d\n", __func__, nb); 178 intc_vic_write_4(VICINTENCLEAR, (1 << nb)); 179} 180 181void 182arm_unmask_irq(uintptr_t nb) 183{ 184 185 dprintf("%s: %d\n", __func__, nb); 186 intc_vic_write_4(VICINTENABLE, (1 << nb)); 187} 188