1/*- 2 * Copyright (c) 2016 Stanislav Galabov 3 * Copyright (c) 2015 Alexander Kabaev 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions, and the following disclaimer, 11 * without modification, immediately at the beginning of the file. 12 * 2. The name of the author may not be used to endorse or promote products 13 * derived from this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 19 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 */ 28 29#include "opt_platform.h" 30 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD$"); 33 34#include <sys/param.h> 35#include <sys/systm.h> 36#include <sys/bus.h> 37#include <sys/kernel.h> 38#include <sys/ktr.h> 39#include <sys/module.h> 40#include <sys/malloc.h> 41#include <sys/rman.h> 42#include <sys/pcpu.h> 43#include <sys/proc.h> 44#include <sys/cpuset.h> 45#include <sys/lock.h> 46#include <sys/mutex.h> 47#include <sys/smp.h> 48#include <sys/sched.h> 49#include <machine/bus.h> 50#include <machine/intr.h> 51#include <machine/smp.h> 52 53#include <dev/fdt/fdt_common.h> 54#include <dev/ofw/openfirm.h> 55#include <dev/ofw/ofw_bus.h> 56#include <dev/ofw/ofw_bus_subr.h> 57 58#include "pic_if.h" 59 60#define MTK_NIRQS 64 /* We'll only use 64 for now */ 61 62#define MTK_INTPOL 0x0100 63#define MTK_INTTRIG 0x0180 64#define MTK_INTDIS 0x0300 65#define MTK_INTENA 0x0380 66#define MTK_INTMASK 0x0400 67#define MTK_INTSTAT 0x0480 68#define MTK_MAPPIN(_i) (0x0500 + (4 * (_i))) 69#define MTK_MAPVPE(_i, _v) (0x2000 + (32 * (_i)) + (((_v) / 32) * 4)) 70 71#define MTK_INTPOL_POS 1 72#define MTK_INTPOL_NEG 0 73#define MTK_INTTRIG_EDGE 1 74#define MTK_INTTRIG_LEVEL 0 75#define MTK_PIN_BITS(_i) ((1 << 31) | (_i)) 76#define MTK_VPE_BITS(_v) (1 << ((_v) % 32)) 77 78static int mtk_gic_intr(void *); 79 80struct mtk_gic_irqsrc { 81 struct intr_irqsrc isrc; 82 u_int irq; 83}; 84 85struct mtk_gic_softc { 86 device_t gic_dev; 87 void * gic_intrhand; 88 struct resource * gic_res[2]; 89 struct mtk_gic_irqsrc gic_irqs[MTK_NIRQS]; 90 struct mtx mutex; 91 uint32_t nirqs; 92}; 93 94#define GIC_INTR_ISRC(sc, irq) (&(sc)->gic_irqs[(irq)].isrc) 95 96static struct resource_spec mtk_gic_spec[] = { 97 { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Registers */ 98 { -1, 0 } 99}; 100 101static struct ofw_compat_data compat_data[] = { 102 { "mti,gic", 1 }, 103 { NULL, 0 } 104}; 105 106#define READ4(_sc, _reg) bus_read_4((_sc)->gic_res[0], (_reg)) 107#define WRITE4(_sc, _reg, _val) bus_write_4((_sc)->gic_res[0], (_reg), (_val)) 108 109static int 110mtk_gic_probe(device_t dev) 111{ 112 113 if (!ofw_bus_status_okay(dev)) 114 return (ENXIO); 115 116 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 117 return (ENXIO); 118 119 device_set_desc(dev, "MTK Interrupt Controller (GIC)"); 120 return (BUS_PROBE_DEFAULT); 121} 122 123static inline void 124gic_irq_unmask(struct mtk_gic_softc *sc, u_int irq) 125{ 126 127 WRITE4(sc, MTK_INTENA, (1u << (irq))); 128} 129 130static inline void 131gic_irq_mask(struct mtk_gic_softc *sc, u_int irq) 132{ 133 134 WRITE4(sc, MTK_INTDIS, (1u << (irq))); 135} 136 137static inline intptr_t 138gic_xref(device_t dev) 139{ 140 141 return (OF_xref_from_node(ofw_bus_get_node(dev))); 142} 143 144static int 145mtk_gic_register_isrcs(struct mtk_gic_softc *sc) 146{ 147 int error; 148 uint32_t irq; 149 struct intr_irqsrc *isrc; 150 const char *name; 151 152 name = device_get_nameunit(sc->gic_dev); 153 for (irq = 0; irq < sc->nirqs; irq++) { 154 sc->gic_irqs[irq].irq = irq; 155 isrc = GIC_INTR_ISRC(sc, irq); 156 error = intr_isrc_register(isrc, sc->gic_dev, 0, "%s", name); 157 if (error != 0) { 158 /* XXX call intr_isrc_deregister */ 159 device_printf(sc->gic_dev, "%s failed", __func__); 160 return (error); 161 } 162 } 163 164 return (0); 165} 166 167static int 168mtk_gic_attach(device_t dev) 169{ 170 struct mtk_gic_softc *sc; 171 intptr_t xref = gic_xref(dev); 172 int i; 173 174 sc = device_get_softc(dev); 175 176 if (bus_alloc_resources(dev, mtk_gic_spec, sc->gic_res)) { 177 device_printf(dev, "could not allocate resources\n"); 178 return (ENXIO); 179 } 180 181 sc->gic_dev = dev; 182 183 /* Initialize mutex */ 184 mtx_init(&sc->mutex, "PIC lock", "", MTX_SPIN); 185 186 /* Set the number of interrupts */ 187 sc->nirqs = nitems(sc->gic_irqs); 188 189 /* Mask all interrupts */ 190 WRITE4(sc, MTK_INTDIS, 0xFFFFFFFF); 191 192 /* All interrupts are of type level */ 193 WRITE4(sc, MTK_INTTRIG, 0x00000000); 194 195 /* All interrupts are of positive polarity */ 196 WRITE4(sc, MTK_INTPOL, 0xFFFFFFFF); 197 198 /* 199 * Route all interrupts to pin 0 on VPE 0; 200 */ 201 for (i = 0; i < 32; i++) { 202 WRITE4(sc, MTK_MAPPIN(i), MTK_PIN_BITS(0)); 203 WRITE4(sc, MTK_MAPVPE(i, 0), MTK_VPE_BITS(0)); 204 } 205 206 /* Register the interrupts */ 207 if (mtk_gic_register_isrcs(sc) != 0) { 208 device_printf(dev, "could not register GIC ISRCs\n"); 209 goto cleanup; 210 } 211 212 /* 213 * Now, when everything is initialized, it's right time to 214 * register interrupt controller to interrupt framefork. 215 */ 216 if (intr_pic_register(dev, xref) == NULL) { 217 device_printf(dev, "could not register PIC\n"); 218 goto cleanup; 219 } 220 221 cpu_establish_hardintr("gic", mtk_gic_intr, NULL, sc, 0, INTR_TYPE_CLK, 222 NULL); 223 224 return (0); 225 226cleanup: 227 bus_release_resources(dev, mtk_gic_spec, sc->gic_res); 228 return(ENXIO); 229} 230 231static int 232mtk_gic_intr(void *arg) 233{ 234 struct mtk_gic_softc *sc = arg; 235 struct thread *td; 236 uint32_t i, intr; 237 238 td = curthread; 239 /* Workaround: do not inflate intr nesting level */ 240 td->td_intr_nesting_level--; 241 242 intr = READ4(sc, MTK_INTSTAT) & READ4(sc, MTK_INTMASK); 243 while ((i = fls(intr)) != 0) { 244 i--; 245 intr &= ~(1u << i); 246 247 if (intr_isrc_dispatch(GIC_INTR_ISRC(sc, i), 248 curthread->td_intr_frame) != 0) { 249 device_printf(sc->gic_dev, 250 "Stray interrupt %u detected\n", i); 251 gic_irq_mask(sc, i); 252 continue; 253 } 254 } 255 256 KASSERT(i == 0, ("all interrupts handled")); 257 258 td->td_intr_nesting_level++; 259 260 return (FILTER_HANDLED); 261} 262 263static int 264mtk_gic_map_intr(device_t dev, struct intr_map_data *data, 265 struct intr_irqsrc **isrcp) 266{ 267#ifdef FDT 268 struct intr_map_data_fdt *daf; 269 struct mtk_gic_softc *sc; 270 271 if (data->type != INTR_MAP_DATA_FDT) 272 return (ENOTSUP); 273 274 sc = device_get_softc(dev); 275 daf = (struct intr_map_data_fdt *)data; 276 277 if (daf->ncells != 3 || daf->cells[1] >= sc->nirqs) 278 return (EINVAL); 279 280 *isrcp = GIC_INTR_ISRC(sc, daf->cells[1]); 281 return (0); 282#else 283 return (ENOTSUP); 284#endif 285} 286 287static void 288mtk_gic_enable_intr(device_t dev, struct intr_irqsrc *isrc) 289{ 290 u_int irq; 291 292 irq = ((struct mtk_gic_irqsrc *)isrc)->irq; 293 gic_irq_unmask(device_get_softc(dev), irq); 294} 295 296static void 297mtk_gic_disable_intr(device_t dev, struct intr_irqsrc *isrc) 298{ 299 u_int irq; 300 301 irq = ((struct mtk_gic_irqsrc *)isrc)->irq; 302 gic_irq_mask(device_get_softc(dev), irq); 303} 304 305static void 306mtk_gic_pre_ithread(device_t dev, struct intr_irqsrc *isrc) 307{ 308 309 mtk_gic_disable_intr(dev, isrc); 310} 311 312static void 313mtk_gic_post_ithread(device_t dev, struct intr_irqsrc *isrc) 314{ 315 316 mtk_gic_enable_intr(dev, isrc); 317} 318 319static void 320mtk_gic_post_filter(device_t dev, struct intr_irqsrc *isrc) 321{ 322} 323 324#ifdef SMP 325static int 326mtk_gic_bind(device_t dev, struct intr_irqsrc *isrc) 327{ 328 return (EOPNOTSUPP); 329} 330 331static void 332mtk_gic_init_secondary(device_t dev) 333{ 334} 335 336static void 337mtk_gic_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus) 338{ 339} 340#endif 341 342static device_method_t mtk_gic_methods[] = { 343 /* Device interface */ 344 DEVMETHOD(device_probe, mtk_gic_probe), 345 DEVMETHOD(device_attach, mtk_gic_attach), 346 /* Interrupt controller interface */ 347 DEVMETHOD(pic_disable_intr, mtk_gic_disable_intr), 348 DEVMETHOD(pic_enable_intr, mtk_gic_enable_intr), 349 DEVMETHOD(pic_map_intr, mtk_gic_map_intr), 350 DEVMETHOD(pic_post_filter, mtk_gic_post_filter), 351 DEVMETHOD(pic_post_ithread, mtk_gic_post_ithread), 352 DEVMETHOD(pic_pre_ithread, mtk_gic_pre_ithread), 353#ifdef SMP 354 DEVMETHOD(pic_bind, mtk_gic_bind), 355 DEVMETHOD(pic_init_secondary, mtk_gic_init_secondary), 356 DEVMETHOD(pic_ipi_send, mtk_gic_ipi_send), 357#endif 358 { 0, 0 } 359}; 360 361static driver_t mtk_gic_driver = { 362 "intc", 363 mtk_gic_methods, 364 sizeof(struct mtk_gic_softc), 365}; 366 367static devclass_t mtk_gic_devclass; 368 369EARLY_DRIVER_MODULE(intc_gic, simplebus, mtk_gic_driver, mtk_gic_devclass, 0, 0, 370 BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); 371