1/*- 2 * Copyright (c) 2010 Jakub Wojciech Klama <jceel@FreeBSD.org> 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: head/sys/arm/lpc/lpc_intc.c 261410 2014-02-02 19:17:28Z ian $");
|
29__FBSDID("$FreeBSD: head/sys/arm/lpc/lpc_intc.c 276023 2014-12-21 16:59:41Z andrew $"); |
30 31#include <sys/param.h> 32#include <sys/systm.h> 33#include <sys/bus.h> 34#include <sys/kernel.h> 35#include <sys/module.h> 36#include <sys/malloc.h> 37#include <sys/rman.h> 38#include <sys/timetc.h> 39#include <machine/bus.h> 40#include <machine/intr.h> 41 42#include <dev/fdt/fdt_common.h> 43#include <dev/ofw/openfirm.h> 44 45#include <dev/ofw/ofw_bus.h> 46#include <dev/ofw/ofw_bus_subr.h> 47 48#include <arm/lpc/lpcreg.h> 49 50struct lpc_intc_softc { 51 struct resource * li_res; 52 bus_space_tag_t li_bst; 53 bus_space_handle_t li_bsh; 54}; 55 56static int lpc_intc_probe(device_t); 57static int lpc_intc_attach(device_t); 58static void lpc_intc_eoi(void *); 59 60static struct lpc_intc_softc *intc_softc = NULL; 61
|
62#define intc_read_4(reg) \
63 bus_space_read_4(intc_softc->li_bst, intc_softc->li_bsh, reg)
64#define intc_write_4(reg, val) \
65 bus_space_write_4(intc_softc->li_bst, intc_softc->li_bsh, reg, val)
|
62#define intc_read_4(_sc, _reg) \ 63 bus_space_read_4((_sc)->li_bst, (_sc)->li_bsh, (_reg)) 64#define intc_write_4(_sc, _reg, _val) \ 65 bus_space_write_4((_sc)->li_bst, (_sc)->li_bsh, (_reg), (_val)) |
66 67static int 68lpc_intc_probe(device_t dev) 69{ 70 71 if (!ofw_bus_status_okay(dev)) 72 return (ENXIO); 73 74 if (!ofw_bus_is_compatible(dev, "lpc,pic")) 75 return (ENXIO); 76 77 device_set_desc(dev, "LPC32x0 Interrupt Controller"); 78 return (BUS_PROBE_DEFAULT); 79} 80 81static int 82lpc_intc_attach(device_t dev) 83{ 84 struct lpc_intc_softc *sc = device_get_softc(dev); 85 int rid = 0; 86 87 if (intc_softc) 88 return (ENXIO); 89 90 sc->li_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 91 RF_ACTIVE); 92 if (!sc->li_res) { 93 device_printf(dev, "could not alloc resources\n"); 94 return (ENXIO); 95 } 96 97 sc->li_bst = rman_get_bustag(sc->li_res); 98 sc->li_bsh = rman_get_bushandle(sc->li_res); 99 intc_softc = sc; 100 arm_post_filter = lpc_intc_eoi; 101 102 /* Clear interrupt status registers and disable all interrupts */
|
103 intc_write_4(LPC_INTC_MIC_ER, 0);
104 intc_write_4(LPC_INTC_SIC1_ER, 0);
105 intc_write_4(LPC_INTC_SIC2_ER, 0);
106 intc_write_4(LPC_INTC_MIC_RSR, ~0);
107 intc_write_4(LPC_INTC_SIC1_RSR, ~0);
108 intc_write_4(LPC_INTC_SIC2_RSR, ~0);
|
103 intc_write_4(sc, LPC_INTC_MIC_ER, 0); 104 intc_write_4(sc, LPC_INTC_SIC1_ER, 0); 105 intc_write_4(sc, LPC_INTC_SIC2_ER, 0); 106 intc_write_4(sc, LPC_INTC_MIC_RSR, ~0); 107 intc_write_4(sc, LPC_INTC_SIC1_RSR, ~0); 108 intc_write_4(sc, LPC_INTC_SIC2_RSR, ~0); |
109 return (0); 110} 111 112static device_method_t lpc_intc_methods[] = { 113 DEVMETHOD(device_probe, lpc_intc_probe), 114 DEVMETHOD(device_attach, lpc_intc_attach), 115 { 0, 0 } 116}; 117 118static driver_t lpc_intc_driver = { 119 "pic", 120 lpc_intc_methods, 121 sizeof(struct lpc_intc_softc), 122}; 123 124static devclass_t lpc_intc_devclass; 125 126DRIVER_MODULE(pic, simplebus, lpc_intc_driver, lpc_intc_devclass, 0, 0); 127 128int 129arm_get_next_irq(int last) 130{
|
131 struct lpc_intc_softc *sc = intc_softc; |
132 uint32_t value; 133 int i; 134 135 /* IRQs 0-31 are mapped to LPC_INTC_MIC_SR */
|
135 value = intc_read_4(LPC_INTC_MIC_SR);
|
136 value = intc_read_4(sc, LPC_INTC_MIC_SR); |
137 for (i = 0; i < 32; i++) { 138 if (value & (1 << i)) 139 return (i); 140 } 141 142 /* IRQs 32-63 are mapped to LPC_INTC_SIC1_SR */
|
142 value = intc_read_4(LPC_INTC_SIC1_SR);
|
143 value = intc_read_4(sc, LPC_INTC_SIC1_SR); |
144 for (i = 0; i < 32; i++) { 145 if (value & (1 << i)) 146 return (i + 32); 147 } 148 149 /* IRQs 64-95 are mapped to LPC_INTC_SIC2_SR */
|
149 value = intc_read_4(LPC_INTC_SIC2_SR);
|
150 value = intc_read_4(sc, LPC_INTC_SIC2_SR); |
151 for (i = 0; i < 32; i++) { 152 if (value & (1 << i)) 153 return (i + 64); 154 } 155 156 return (-1); 157} 158 159void 160arm_mask_irq(uintptr_t nb) 161{
|
162 struct lpc_intc_softc *sc = intc_softc; |
163 int reg; 164 uint32_t value; 165 166 /* Make sure that interrupt isn't active already */ 167 lpc_intc_eoi((void *)nb); 168 169 if (nb > 63) { 170 nb -= 64; 171 reg = LPC_INTC_SIC2_ER; 172 } else if (nb > 31) { 173 nb -= 32; 174 reg = LPC_INTC_SIC1_ER; 175 } else 176 reg = LPC_INTC_MIC_ER; 177 178 /* Clear bit in ER register */
|
177 value = intc_read_4(reg);
|
179 value = intc_read_4(sc, reg); |
180 value &= ~(1 << nb);
|
179 intc_write_4(reg, value);
|
181 intc_write_4(sc, reg, value); |
182} 183 184void 185arm_unmask_irq(uintptr_t nb) 186{
|
187 struct lpc_intc_softc *sc = intc_softc; |
188 int reg; 189 uint32_t value; 190 191 if (nb > 63) { 192 nb -= 64; 193 reg = LPC_INTC_SIC2_ER; 194 } else if (nb > 31) { 195 nb -= 32; 196 reg = LPC_INTC_SIC1_ER; 197 } else 198 reg = LPC_INTC_MIC_ER; 199 200 /* Set bit in ER register */
|
198 value = intc_read_4(reg);
|
201 value = intc_read_4(sc, reg); |
202 value |= (1 << nb);
|
200 intc_write_4(reg, value);
|
203 intc_write_4(sc, reg, value); |
204} 205 206static void 207lpc_intc_eoi(void *data) 208{
|
209 struct lpc_intc_softc *sc = intc_softc; |
210 int reg; 211 int nb = (int)data; 212 uint32_t value; 213 214 if (nb > 63) { 215 nb -= 64; 216 reg = LPC_INTC_SIC2_RSR; 217 } else if (nb > 31) { 218 nb -= 32; 219 reg = LPC_INTC_SIC1_RSR; 220 } else 221 reg = LPC_INTC_MIC_RSR; 222 223 /* Set bit in RSR register */
|
220 value = intc_read_4(reg);
|
224 value = intc_read_4(sc, reg); |
225 value |= (1 << nb);
|
222 intc_write_4(reg, value);
|
226 intc_write_4(sc, reg, value); |
227 228} 229 230struct fdt_fixup_entry fdt_fixup_table[] = { 231 { NULL, NULL } 232}; 233 234static int 235fdt_pic_decode_ic(phandle_t node, pcell_t *intr, int *interrupt, int *trig, 236 int *pol) 237{ 238 if (!fdt_is_compatible(node, "lpc,pic")) 239 return (ENXIO); 240 241 *interrupt = fdt32_to_cpu(intr[0]); 242 *trig = INTR_TRIGGER_CONFORM; 243 *pol = INTR_POLARITY_CONFORM; 244 return (0); 245} 246 247fdt_pic_decode_t fdt_pic_table[] = { 248 &fdt_pic_decode_ic, 249 NULL 250};
|