1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2012-2017 Oleksandr Tymoshenko <[email protected]> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/bus.h> 35 #include <sys/kernel.h> 36 #include <sys/ktr.h> 37 #include <sys/lock.h> 38 #include <sys/module.h> 39 #include <sys/mutex.h> 40 #include <sys/proc.h> 41 #include <sys/rman.h> 42 #include <machine/bus.h> 43 #include <machine/intr.h> 44 45 #include <dev/ofw/openfirm.h> 46 #include <dev/ofw/ofw_bus.h> 47 #include <dev/ofw/ofw_bus_subr.h> 48 49 #include "pic_if.h" 50 51 #ifdef DEBUG 52 #define dprintf(fmt, args...) printf(fmt, ##args) 53 #else 54 #define dprintf(fmt, args...) 55 #endif 56 57 #define SIC_STATUS 0x00 58 #define SIC_RAWSTAT 0x04 59 #define SIC_ENABLE 0x08 60 #define SIC_ENSET 0x08 61 #define SIC_ENCLR 0x0C 62 #define SIC_SOFTINTSET 0x10 63 #define SIC_SOFTINTCLR 0x14 64 #define SIC_PICENABLE 0x20 65 #define SIC_PICENSET 0x20 66 #define SIC_PICENCLR 0x24 67 68 #define SIC_NIRQS 32 69 70 struct versatile_sic_irqsrc { 71 struct intr_irqsrc isrc; 72 u_int irq; 73 }; 74 75 struct versatile_sic_softc { 76 device_t dev; 77 struct mtx mtx; 78 struct resource * mem_res; 79 struct resource * irq_res; 80 void *intrh; 81 struct versatile_sic_irqsrc isrcs[SIC_NIRQS]; 82 }; 83 84 #define SIC_LOCK(_sc) mtx_lock_spin(&(_sc)->mtx) 85 #define SIC_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->mtx) 86 87 #define SIC_READ_4(sc, reg) \ 88 bus_read_4(sc->mem_res, (reg)) 89 #define SIC_WRITE_4(sc, reg, val) \ 90 bus_write_4(sc->mem_res, (reg), (val)) 91 92 /* 93 * Driver stuff 94 */ 95 static int versatile_sic_probe(device_t); 96 static int versatile_sic_attach(device_t); 97 static int versatile_sic_detach(device_t); 98 99 static void 100 versatile_sic_disable_intr(device_t dev, struct intr_irqsrc *isrc) 101 { 102 struct versatile_sic_softc *sc; 103 struct versatile_sic_irqsrc *src; 104 105 sc = device_get_softc(dev); 106 src = (struct versatile_sic_irqsrc *)isrc; 107 108 SIC_LOCK(sc); 109 SIC_WRITE_4(sc, SIC_ENCLR, (1 << src->irq)); 110 SIC_UNLOCK(sc); 111 } 112 113 static void 114 versatile_sic_enable_intr(device_t dev, struct intr_irqsrc *isrc) 115 { 116 struct versatile_sic_softc *sc; 117 struct versatile_sic_irqsrc *src; 118 119 sc = device_get_softc(dev); 120 src = (struct versatile_sic_irqsrc *)isrc; 121 122 SIC_LOCK(sc); 123 SIC_WRITE_4(sc, SIC_ENSET, (1 << src->irq)); 124 SIC_UNLOCK(sc); 125 } 126 127 static int 128 versatile_sic_map_intr(device_t dev, struct intr_map_data *data, 129 struct intr_irqsrc **isrcp) 130 { 131 struct intr_map_data_fdt *daf; 132 struct versatile_sic_softc *sc; 133 134 if (data->type != INTR_MAP_DATA_FDT) 135 return (ENOTSUP); 136 137 daf = (struct intr_map_data_fdt *)data; 138 if (daf->ncells != 1 || daf->cells[0] >= SIC_NIRQS) 139 return (EINVAL); 140 141 sc = device_get_softc(dev); 142 *isrcp = &sc->isrcs[daf->cells[0]].isrc; 143 return (0); 144 } 145 146 static void 147 versatile_sic_pre_ithread(device_t dev, struct intr_irqsrc *isrc) 148 { 149 versatile_sic_disable_intr(dev, isrc); 150 } 151 152 static void 153 versatile_sic_post_ithread(device_t dev, struct intr_irqsrc *isrc) 154 { 155 struct versatile_sic_irqsrc *src; 156 157 src = (struct versatile_sic_irqsrc *)isrc; 158 arm_irq_memory_barrier(src->irq); 159 versatile_sic_enable_intr(dev, isrc); 160 } 161 162 static void 163 versatile_sic_post_filter(device_t dev, struct intr_irqsrc *isrc) 164 { 165 struct versatile_sic_irqsrc *src; 166 167 src = (struct versatile_sic_irqsrc *)isrc; 168 arm_irq_memory_barrier(src->irq); 169 } 170 171 static int 172 versatile_sic_setup_intr(device_t dev, struct intr_irqsrc *isrc, 173 struct resource *res, struct intr_map_data *data) 174 { 175 176 return (0); 177 } 178 179 static int 180 versatile_sic_filter(void *arg) 181 { 182 struct versatile_sic_softc *sc; 183 struct intr_irqsrc *isrc; 184 uint32_t i, interrupts; 185 186 sc = arg; 187 SIC_LOCK(sc); 188 interrupts = SIC_READ_4(sc, SIC_STATUS); 189 SIC_UNLOCK(sc); 190 for (i = 0; interrupts != 0; i++, interrupts >>= 1) { 191 if ((interrupts & 0x1) == 0) 192 continue; 193 isrc = &sc->isrcs[i].isrc; 194 if (intr_isrc_dispatch(isrc, curthread->td_intr_frame) != 0) { 195 versatile_sic_disable_intr(sc->dev, isrc); 196 versatile_sic_post_filter(sc->dev, isrc); 197 device_printf(sc->dev, "Stray irq %u disabled\n", i); 198 } 199 } 200 201 return (FILTER_HANDLED); 202 } 203 204 static int 205 versatile_sic_probe(device_t dev) 206 { 207 208 if (!ofw_bus_status_okay(dev)) 209 return (ENXIO); 210 211 if (!ofw_bus_is_compatible(dev, "arm,versatile-sic")) 212 return (ENXIO); 213 device_set_desc(dev, "ARM Versatile SIC"); 214 return (BUS_PROBE_DEFAULT); 215 } 216 217 static int 218 versatile_sic_attach(device_t dev) 219 { 220 struct versatile_sic_softc *sc = device_get_softc(dev); 221 int rid, error; 222 uint32_t irq; 223 const char *name; 224 struct versatile_sic_irqsrc *isrcs; 225 226 sc->dev = dev; 227 mtx_init(&sc->mtx, device_get_nameunit(dev), "sic", 228 MTX_SPIN); 229 230 /* Request memory resources */ 231 rid = 0; 232 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 233 RF_ACTIVE); 234 if (sc->mem_res == NULL) { 235 device_printf(dev, "Error: could not allocate memory resources\n"); 236 return (ENXIO); 237 } 238 239 /* Request memory resources */ 240 rid = 0; 241 sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 242 RF_ACTIVE); 243 if (sc->irq_res == NULL) { 244 device_printf(dev, "could not allocate IRQ resources\n"); 245 versatile_sic_detach(dev); 246 return (ENXIO); 247 } 248 249 if ((bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC, 250 versatile_sic_filter, NULL, sc, &sc->intrh))) { 251 device_printf(dev, 252 "unable to register interrupt handler\n"); 253 versatile_sic_detach(dev); 254 return (ENXIO); 255 } 256 257 /* Disable all interrupts on SIC */ 258 SIC_WRITE_4(sc, SIC_ENCLR, 0xffffffff); 259 260 /* PIC attachment */ 261 isrcs = sc->isrcs; 262 name = device_get_nameunit(sc->dev); 263 for (irq = 0; irq < SIC_NIRQS; irq++) { 264 isrcs[irq].irq = irq; 265 error = intr_isrc_register(&isrcs[irq].isrc, sc->dev, 266 0, "%s,%u", name, irq); 267 if (error != 0) 268 return (error); 269 } 270 271 intr_pic_register(dev, OF_xref_from_node(ofw_bus_get_node(dev))); 272 273 return (0); 274 } 275 276 static int 277 versatile_sic_detach(device_t dev) 278 { 279 struct versatile_sic_softc *sc; 280 281 sc = device_get_softc(dev); 282 283 if (sc->intrh) 284 bus_teardown_intr(dev, sc->irq_res, sc->intrh); 285 286 if (sc->mem_res == NULL) 287 bus_release_resource(dev, SYS_RES_MEMORY, 288 rman_get_rid(sc->mem_res), sc->mem_res); 289 290 if (sc->irq_res == NULL) 291 bus_release_resource(dev, SYS_RES_IRQ, 292 rman_get_rid(sc->irq_res), sc->irq_res); 293 294 mtx_destroy(&sc->mtx); 295 296 return (0); 297 298 } 299 300 static device_method_t versatile_sic_methods[] = { 301 DEVMETHOD(device_probe, versatile_sic_probe), 302 DEVMETHOD(device_attach, versatile_sic_attach), 303 DEVMETHOD(device_detach, versatile_sic_detach), 304 305 DEVMETHOD(pic_disable_intr, versatile_sic_disable_intr), 306 DEVMETHOD(pic_enable_intr, versatile_sic_enable_intr), 307 DEVMETHOD(pic_map_intr, versatile_sic_map_intr), 308 DEVMETHOD(pic_post_filter, versatile_sic_post_filter), 309 DEVMETHOD(pic_post_ithread, versatile_sic_post_ithread), 310 DEVMETHOD(pic_pre_ithread, versatile_sic_pre_ithread), 311 DEVMETHOD(pic_setup_intr, versatile_sic_setup_intr), 312 313 DEVMETHOD_END 314 }; 315 316 static driver_t versatile_sic_driver = { 317 "sic", 318 versatile_sic_methods, 319 sizeof(struct versatile_sic_softc), 320 }; 321 322 static devclass_t versatile_sic_devclass; 323 324 DRIVER_MODULE(sic, simplebus, versatile_sic_driver, versatile_sic_devclass, 0, 0); 325