1248557Sray/*- 2250357Sray * Copyright (c) 2012, 2013 The FreeBSD Foundation 3248557Sray * All rights reserved. 4248557Sray * 5248557Sray * This software was developed by Oleksandr Rybalko under sponsorship 6248557Sray * from the FreeBSD Foundation. 7248557Sray * 8248557Sray * Redistribution and use in source and binary forms, with or without 9248557Sray * modification, are permitted provided that the following conditions 10248557Sray * are met: 11248557Sray * 1. Redistributions of source code must retain the above copyright 12248557Sray * notice, this list of conditions and the following disclaimer. 13248557Sray * 2. Redistributions in binary form must reproduce the above copyright 14248557Sray * notice, this list of conditions and the following disclaimer in the 15248557Sray * documentation and/or other materials provided with the distribution. 16248557Sray * 17248557Sray * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18248557Sray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19248557Sray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20248557Sray * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21248557Sray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22248557Sray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23248557Sray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24248557Sray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25248557Sray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26248557Sray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27248557Sray * SUCH DAMAGE. 28248557Sray */ 29248557Sray 30248557Sray#include <sys/cdefs.h> 31248557Sray__FBSDID("$FreeBSD: stable/11/sys/arm/freescale/imx/tzic.c 323403 2017-09-10 23:41:23Z ian $"); 32248557Sray 33248557Sray#include <sys/param.h> 34248557Sray#include <sys/systm.h> 35248557Sray#include <sys/bus.h> 36248557Sray#include <sys/kernel.h> 37248557Sray#include <sys/module.h> 38248557Sray#include <sys/rman.h> 39248557Sray#include <sys/proc.h> 40248557Sray#include <sys/lock.h> 41248557Sray#include <sys/mutex.h> 42323403Sian 43248557Sray#include <machine/bus.h> 44248557Sray#include <machine/intr.h> 45248557Sray 46248557Sray#include <dev/fdt/fdt_common.h> 47248557Sray#include <dev/ofw/openfirm.h> 48248557Sray#include <dev/ofw/ofw_bus.h> 49248557Sray#include <dev/ofw/ofw_bus_subr.h> 50248557Sray 51248557Sray#include <arm/freescale/imx/imx51_tzicreg.h> 52248557Sray 53323403Sian#include "pic_if.h" 54323403Sian 55323403Sian#define TZIC_NIRQS 128 56323403Sian 57323403Sianstruct tzic_irqsrc { 58323403Sian struct intr_irqsrc isrc; 59323403Sian u_int irq; 60248557Sray}; 61248557Sray 62323403Sianstruct tzic_softc { 63323403Sian device_t dev; 64323403Sian struct resource *tzicregs; 65323403Sian struct tzic_irqsrc isrcs[TZIC_NIRQS]; 66248557Sray}; 67248557Sray 68323403Sianstatic struct tzic_softc *tzic_sc; 69248557Sray 70323403Sianstatic inline uint32_t 71323403Siantzic_read_4(struct tzic_softc *sc, int reg) 72323403Sian{ 73248557Sray 74323403Sian return (bus_read_4(sc->tzicregs, reg)); 75323403Sian} 76248557Sray 77323403Sianstatic inline void 78323403Siantzic_write_4(struct tzic_softc *sc, int reg, uint32_t val) 79323403Sian{ 80323403Sian 81323403Sian bus_write_4(sc->tzicregs, reg, val); 82323403Sian} 83323403Sian 84323403Sianstatic inline void 85323403Siantzic_irq_eoi(struct tzic_softc *sc) 86323403Sian{ 87323403Sian 88323403Sian tzic_write_4(sc, TZIC_PRIOMASK, 0xff); 89323403Sian} 90323403Sian 91323403Sianstatic inline void 92323403Siantzic_irq_mask(struct tzic_softc *sc, u_int irq) 93323403Sian{ 94323403Sian 95323403Sian tzic_write_4(sc, TZIC_ENCLEAR(irq >> 5), (1u << (irq & 0x1f))); 96323403Sian} 97323403Sian 98323403Sianstatic inline void 99323403Siantzic_irq_unmask(struct tzic_softc *sc, u_int irq) 100323403Sian{ 101323403Sian 102323403Sian tzic_write_4(sc, TZIC_ENSET(irq >> 5), (1u << (irq & 0x1f))); 103323403Sian} 104323403Sian 105248557Sraystatic int 106323403Siantzic_intr(void *arg) 107323403Sian{ 108323403Sian struct tzic_softc *sc = arg; 109323403Sian int b, i, irq; 110323403Sian uint32_t pending; 111323403Sian 112323403Sian /* Get active interrupt */ 113323403Sian for (i = 0; i < TZIC_NIRQS / 32; ++i) { 114323403Sian pending = tzic_read_4(sc, TZIC_PND(i)); 115323403Sian if ((b = 31 - __builtin_clz(pending)) < 0) 116323403Sian continue; 117323403Sian irq = i * 32 + b; 118323403Sian tzic_write_4(sc, TZIC_PRIOMASK, 0); 119323403Sian if (intr_isrc_dispatch(&sc->isrcs[irq].isrc, 120323403Sian curthread->td_intr_frame) != 0) { 121323403Sian tzic_irq_mask(sc, irq); 122323403Sian tzic_irq_eoi(sc); 123323403Sian arm_irq_memory_barrier(irq); 124323403Sian if (bootverbose) { 125323403Sian device_printf(sc->dev, 126323403Sian "Stray irq %u disabled\n", irq); 127323403Sian } 128323403Sian } 129323403Sian return (FILTER_HANDLED); 130323403Sian } 131323403Sian 132323403Sian if (bootverbose) 133323403Sian device_printf(sc->dev, "Spurious interrupt detected\n"); 134323403Sian 135323403Sian return (FILTER_HANDLED); 136323403Sian} 137323403Sian 138323403Sianstatic void 139323403Siantzic_enable_intr(device_t dev, struct intr_irqsrc *isrc) 140323403Sian{ 141323403Sian u_int irq = ((struct tzic_irqsrc *)isrc)->irq; 142323403Sian struct tzic_softc *sc = device_get_softc(dev); 143323403Sian 144323403Sian arm_irq_memory_barrier(irq); 145323403Sian tzic_irq_unmask(sc, irq); 146323403Sian} 147323403Sian 148323403Sianstatic void 149323403Siantzic_disable_intr(device_t dev, struct intr_irqsrc *isrc) 150323403Sian{ 151323403Sian u_int irq = ((struct tzic_irqsrc *)isrc)->irq; 152323403Sian struct tzic_softc *sc = device_get_softc(dev); 153323403Sian 154323403Sian tzic_irq_mask(sc, irq); 155323403Sian} 156323403Sian 157323403Sianstatic int 158323403Siantzic_map_intr(device_t dev, struct intr_map_data *data, 159323403Sian struct intr_irqsrc **isrcp) 160323403Sian{ 161323403Sian struct intr_map_data_fdt *daf; 162323403Sian struct tzic_softc *sc; 163323403Sian 164323403Sian if (data->type != INTR_MAP_DATA_FDT) 165323403Sian return (ENOTSUP); 166323403Sian 167323403Sian daf = (struct intr_map_data_fdt *)data; 168323403Sian if (daf->ncells != 1 || daf->cells[0] >= TZIC_NIRQS) 169323403Sian return (EINVAL); 170323403Sian 171323403Sian sc = device_get_softc(dev); 172323403Sian *isrcp = &sc->isrcs[daf->cells[0]].isrc; 173323403Sian 174323403Sian return (0); 175323403Sian} 176323403Sian 177323403Sianstatic void 178323403Siantzic_pre_ithread(device_t dev, struct intr_irqsrc *isrc) 179323403Sian{ 180323403Sian struct tzic_softc *sc = device_get_softc(dev); 181323403Sian 182323403Sian tzic_irq_mask(sc, ((struct tzic_irqsrc *)isrc)->irq); 183323403Sian tzic_irq_eoi(sc); 184323403Sian} 185323403Sian 186323403Sianstatic void 187323403Siantzic_post_ithread(device_t dev, struct intr_irqsrc *isrc) 188323403Sian{ 189323403Sian 190323403Sian tzic_enable_intr(dev, isrc); 191323403Sian} 192323403Sian 193323403Sianstatic void 194323403Siantzic_post_filter(device_t dev, struct intr_irqsrc *isrc) 195323403Sian{ 196323403Sian 197323403Sian tzic_irq_eoi(device_get_softc(dev)); 198323403Sian} 199323403Sian 200323403Sianstatic int 201323403Siantzic_pic_attach(struct tzic_softc *sc) 202323403Sian{ 203323403Sian struct intr_pic *pic; 204323403Sian const char *name; 205323403Sian intptr_t xref; 206323403Sian int error; 207323403Sian u_int irq; 208323403Sian 209323403Sian name = device_get_nameunit(sc->dev); 210323403Sian for (irq = 0; irq < TZIC_NIRQS; irq++) { 211323403Sian sc->isrcs[irq].irq = irq; 212323403Sian error = intr_isrc_register(&sc->isrcs[irq].isrc, 213323403Sian sc->dev, 0, "%s,%u", name, irq); 214323403Sian if (error != 0) 215323403Sian return (error); 216323403Sian } 217323403Sian 218323403Sian xref = OF_xref_from_node(ofw_bus_get_node(sc->dev)); 219323403Sian pic = intr_pic_register(sc->dev, xref); 220323403Sian if (pic == NULL) 221323403Sian return (ENXIO); 222323403Sian 223323403Sian return (intr_pic_claim_root(sc->dev, xref, tzic_intr, sc, 0)); 224323403Sian} 225323403Sian 226323403Sianstatic int 227248557Sraytzic_probe(device_t dev) 228248557Sray{ 229261410Sian 230261410Sian if (!ofw_bus_status_okay(dev)) 231261410Sian return (ENXIO); 232261410Sian 233248557Sray if (ofw_bus_is_compatible(dev, "fsl,tzic")) { 234248557Sray device_set_desc(dev, "TrustZone Interrupt Controller"); 235248557Sray return (BUS_PROBE_DEFAULT); 236248557Sray } 237248557Sray return (ENXIO); 238248557Sray} 239248557Sray 240248557Sraystatic int 241248557Sraytzic_attach(device_t dev) 242248557Sray{ 243323403Sian struct tzic_softc *sc = device_get_softc(dev); 244323403Sian int i; 245248557Sray 246248557Sray if (tzic_sc) 247248557Sray return (ENXIO); 248323403Sian tzic_sc = sc; 249323403Sian sc->dev = dev; 250248557Sray 251323403Sian i = 0; 252323403Sian sc->tzicregs = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &i, 253323403Sian RF_ACTIVE); 254323403Sian if (sc->tzicregs == NULL) { 255248557Sray device_printf(dev, "could not allocate resources\n"); 256248557Sray return (ENXIO); 257248557Sray } 258248557Sray 259248557Sray /* route all interrupts to IRQ. secure interrupts are for FIQ */ 260248557Sray for (i = 0; i < 4; i++) 261323403Sian tzic_write_4(sc, TZIC_INTSEC(i), 0xffffffff); 262248557Sray 263248557Sray /* disable all interrupts */ 264248557Sray for (i = 0; i < 4; i++) 265323403Sian tzic_write_4(sc, TZIC_ENCLEAR(i), 0xffffffff); 266248557Sray 267323403Sian /* Set all interrupts to priority 0 (max). */ 268323403Sian for (i = 0; i < 128 / 4; ++i) 269323403Sian tzic_write_4(sc, TZIC_PRIORITY(i), 0); 270323403Sian 271323403Sian /* 272323403Sian * Set priority mask to lowest (unmasked) prio, set synchronizer to 273323403Sian * low-latency mode (as opposed to low-power), enable the controller. 274323403Sian */ 275323403Sian tzic_write_4(sc, TZIC_PRIOMASK, 0xff); 276323403Sian tzic_write_4(sc, TZIC_SYNCCTRL, 0); 277323403Sian tzic_write_4(sc, TZIC_INTCNTL, INTCNTL_NSEN_MASK|INTCNTL_NSEN|INTCNTL_EN); 278323403Sian 279323403Sian /* Register as a root pic. */ 280323403Sian if (tzic_pic_attach(sc) != 0) { 281323403Sian device_printf(dev, "could not attach PIC\n"); 282323403Sian return (ENXIO); 283323403Sian } 284323403Sian 285248557Sray return (0); 286248557Sray} 287248557Sray 288248557Sraystatic device_method_t tzic_methods[] = { 289248557Sray DEVMETHOD(device_probe, tzic_probe), 290248557Sray DEVMETHOD(device_attach, tzic_attach), 291323403Sian 292323403Sian DEVMETHOD(pic_disable_intr, tzic_disable_intr), 293323403Sian DEVMETHOD(pic_enable_intr, tzic_enable_intr), 294323403Sian DEVMETHOD(pic_map_intr, tzic_map_intr), 295323403Sian DEVMETHOD(pic_post_filter, tzic_post_filter), 296323403Sian DEVMETHOD(pic_post_ithread, tzic_post_ithread), 297323403Sian DEVMETHOD(pic_pre_ithread, tzic_pre_ithread), 298323403Sian 299323403Sian DEVMETHOD_END 300248557Sray}; 301248557Sray 302248557Sraystatic driver_t tzic_driver = { 303248557Sray "tzic", 304248557Sray tzic_methods, 305248557Sray sizeof(struct tzic_softc), 306248557Sray}; 307248557Sray 308248557Sraystatic devclass_t tzic_devclass; 309248557Sray 310261513SnwhitehornEARLY_DRIVER_MODULE(tzic, ofwbus, tzic_driver, tzic_devclass, 0, 0, 311248557Sray BUS_PASS_INTERRUPT); 312