1*ef2ee5d0SMichal Meloun /*- 2*ef2ee5d0SMichal Meloun * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org> 3*ef2ee5d0SMichal Meloun * All rights reserved. 4*ef2ee5d0SMichal Meloun * 5*ef2ee5d0SMichal Meloun * Redistribution and use in source and binary forms, with or without 6*ef2ee5d0SMichal Meloun * modification, are permitted provided that the following conditions 7*ef2ee5d0SMichal Meloun * are met: 8*ef2ee5d0SMichal Meloun * 1. Redistributions of source code must retain the above copyright 9*ef2ee5d0SMichal Meloun * notice, this list of conditions and the following disclaimer. 10*ef2ee5d0SMichal Meloun * 2. Redistributions in binary form must reproduce the above copyright 11*ef2ee5d0SMichal Meloun * notice, this list of conditions and the following disclaimer in the 12*ef2ee5d0SMichal Meloun * documentation and/or other materials provided with the distribution. 13*ef2ee5d0SMichal Meloun * 14*ef2ee5d0SMichal Meloun * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*ef2ee5d0SMichal Meloun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*ef2ee5d0SMichal Meloun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*ef2ee5d0SMichal Meloun * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18*ef2ee5d0SMichal Meloun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*ef2ee5d0SMichal Meloun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*ef2ee5d0SMichal Meloun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*ef2ee5d0SMichal Meloun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*ef2ee5d0SMichal Meloun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*ef2ee5d0SMichal Meloun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*ef2ee5d0SMichal Meloun * SUCH DAMAGE. 25*ef2ee5d0SMichal Meloun */ 26*ef2ee5d0SMichal Meloun 27*ef2ee5d0SMichal Meloun #include <sys/cdefs.h> 28*ef2ee5d0SMichal Meloun __FBSDID("$FreeBSD$"); 29*ef2ee5d0SMichal Meloun 30*ef2ee5d0SMichal Meloun /* 31*ef2ee5d0SMichal Meloun * Local interrupt controller driver for Tegra SoCs. 32*ef2ee5d0SMichal Meloun */ 33*ef2ee5d0SMichal Meloun #include <sys/param.h> 34*ef2ee5d0SMichal Meloun #include <sys/module.h> 35*ef2ee5d0SMichal Meloun #include <sys/systm.h> 36*ef2ee5d0SMichal Meloun #include <sys/bus.h> 37*ef2ee5d0SMichal Meloun #include <sys/conf.h> 38*ef2ee5d0SMichal Meloun #include <sys/kernel.h> 39*ef2ee5d0SMichal Meloun #include <sys/rman.h> 40*ef2ee5d0SMichal Meloun 41*ef2ee5d0SMichal Meloun #include <machine/fdt.h> 42*ef2ee5d0SMichal Meloun #include <machine/intr.h> 43*ef2ee5d0SMichal Meloun #include <machine/resource.h> 44*ef2ee5d0SMichal Meloun 45*ef2ee5d0SMichal Meloun #include <dev/ofw/ofw_bus.h> 46*ef2ee5d0SMichal Meloun #include <dev/ofw/ofw_bus_subr.h> 47*ef2ee5d0SMichal Meloun 48*ef2ee5d0SMichal Meloun #include "pic_if.h" 49*ef2ee5d0SMichal Meloun 50*ef2ee5d0SMichal Meloun #define LIC_VIRQ_CPU 0x00 51*ef2ee5d0SMichal Meloun #define LIC_VIRQ_COP 0x04 52*ef2ee5d0SMichal Meloun #define LIC_VFRQ_CPU 0x08 53*ef2ee5d0SMichal Meloun #define LIC_VFRQ_COP 0x0c 54*ef2ee5d0SMichal Meloun #define LIC_ISR 0x10 55*ef2ee5d0SMichal Meloun #define LIC_FIR 0x14 56*ef2ee5d0SMichal Meloun #define LIC_FIR_SET 0x18 57*ef2ee5d0SMichal Meloun #define LIC_FIR_CLR 0x1c 58*ef2ee5d0SMichal Meloun #define LIC_CPU_IER 0x20 59*ef2ee5d0SMichal Meloun #define LIC_CPU_IER_SET 0x24 60*ef2ee5d0SMichal Meloun #define LIC_CPU_IER_CLR 0x28 61*ef2ee5d0SMichal Meloun #define LIC_CPU_IEP_CLASS 0x2C 62*ef2ee5d0SMichal Meloun #define LIC_COP_IER 0x30 63*ef2ee5d0SMichal Meloun #define LIC_COP_IER_SET 0x34 64*ef2ee5d0SMichal Meloun #define LIC_COP_IER_CLR 0x38 65*ef2ee5d0SMichal Meloun #define LIC_COP_IEP_CLASS 0x3c 66*ef2ee5d0SMichal Meloun 67*ef2ee5d0SMichal Meloun #define WR4(_sc, _b, _r, _v) bus_write_4((_sc)->mem_res[_b], (_r), (_v)) 68*ef2ee5d0SMichal Meloun #define RD4(_sc, _b, _r) bus_read_4((_sc)->mem_res[_b], (_r)) 69*ef2ee5d0SMichal Meloun 70*ef2ee5d0SMichal Meloun static struct resource_spec lic_spec[] = { 71*ef2ee5d0SMichal Meloun { SYS_RES_MEMORY, 0, RF_ACTIVE }, 72*ef2ee5d0SMichal Meloun { SYS_RES_MEMORY, 1, RF_ACTIVE }, 73*ef2ee5d0SMichal Meloun { SYS_RES_MEMORY, 2, RF_ACTIVE }, 74*ef2ee5d0SMichal Meloun { SYS_RES_MEMORY, 3, RF_ACTIVE }, 75*ef2ee5d0SMichal Meloun { SYS_RES_MEMORY, 4, RF_ACTIVE }, 76*ef2ee5d0SMichal Meloun { -1, 0 } 77*ef2ee5d0SMichal Meloun }; 78*ef2ee5d0SMichal Meloun 79*ef2ee5d0SMichal Meloun static struct ofw_compat_data compat_data[] = { 80*ef2ee5d0SMichal Meloun {"nvidia,tegra124-ictlr", 1}, 81*ef2ee5d0SMichal Meloun {NULL, 0} 82*ef2ee5d0SMichal Meloun }; 83*ef2ee5d0SMichal Meloun 84*ef2ee5d0SMichal Meloun struct tegra_lic_sc { 85*ef2ee5d0SMichal Meloun device_t dev; 86*ef2ee5d0SMichal Meloun struct resource *mem_res[nitems(lic_spec)]; 87*ef2ee5d0SMichal Meloun device_t parent; 88*ef2ee5d0SMichal Meloun }; 89*ef2ee5d0SMichal Meloun 90*ef2ee5d0SMichal Meloun static int 91*ef2ee5d0SMichal Meloun tegra_lic_register(device_t dev, struct intr_irqsrc *isrc, boolean_t *is_percpu) 92*ef2ee5d0SMichal Meloun { 93*ef2ee5d0SMichal Meloun struct tegra_lic_sc *sc = device_get_softc(dev); 94*ef2ee5d0SMichal Meloun 95*ef2ee5d0SMichal Meloun return (PIC_REGISTER(sc->parent, isrc, is_percpu)); 96*ef2ee5d0SMichal Meloun } 97*ef2ee5d0SMichal Meloun 98*ef2ee5d0SMichal Meloun static int 99*ef2ee5d0SMichal Meloun tegra_lic_unregister(device_t dev, struct intr_irqsrc *isrc) 100*ef2ee5d0SMichal Meloun { 101*ef2ee5d0SMichal Meloun struct tegra_lic_sc *sc = device_get_softc(dev); 102*ef2ee5d0SMichal Meloun 103*ef2ee5d0SMichal Meloun return (PIC_UNREGISTER(sc->parent, isrc)); 104*ef2ee5d0SMichal Meloun } 105*ef2ee5d0SMichal Meloun 106*ef2ee5d0SMichal Meloun static void 107*ef2ee5d0SMichal Meloun tegra_lic_enable_source(device_t dev, struct intr_irqsrc *isrc) 108*ef2ee5d0SMichal Meloun { 109*ef2ee5d0SMichal Meloun struct tegra_lic_sc *sc = device_get_softc(dev); 110*ef2ee5d0SMichal Meloun 111*ef2ee5d0SMichal Meloun PIC_ENABLE_SOURCE(sc->parent, isrc); 112*ef2ee5d0SMichal Meloun } 113*ef2ee5d0SMichal Meloun 114*ef2ee5d0SMichal Meloun static void 115*ef2ee5d0SMichal Meloun tegra_lic_disable_source(device_t dev, struct intr_irqsrc *isrc) 116*ef2ee5d0SMichal Meloun { 117*ef2ee5d0SMichal Meloun struct tegra_lic_sc *sc = device_get_softc(dev); 118*ef2ee5d0SMichal Meloun 119*ef2ee5d0SMichal Meloun PIC_DISABLE_SOURCE(sc->parent, isrc); 120*ef2ee5d0SMichal Meloun } 121*ef2ee5d0SMichal Meloun 122*ef2ee5d0SMichal Meloun static void 123*ef2ee5d0SMichal Meloun tegra_lic_enable_intr(device_t dev, struct intr_irqsrc *isrc) 124*ef2ee5d0SMichal Meloun { 125*ef2ee5d0SMichal Meloun struct tegra_lic_sc *sc = device_get_softc(dev); 126*ef2ee5d0SMichal Meloun 127*ef2ee5d0SMichal Meloun PIC_ENABLE_INTR(sc->parent, isrc); 128*ef2ee5d0SMichal Meloun } 129*ef2ee5d0SMichal Meloun 130*ef2ee5d0SMichal Meloun static void 131*ef2ee5d0SMichal Meloun tegra_lic_pre_ithread(device_t dev, struct intr_irqsrc *isrc) 132*ef2ee5d0SMichal Meloun { 133*ef2ee5d0SMichal Meloun struct tegra_lic_sc *sc = device_get_softc(dev); 134*ef2ee5d0SMichal Meloun 135*ef2ee5d0SMichal Meloun PIC_PRE_ITHREAD(sc->parent, isrc); 136*ef2ee5d0SMichal Meloun } 137*ef2ee5d0SMichal Meloun 138*ef2ee5d0SMichal Meloun 139*ef2ee5d0SMichal Meloun static void 140*ef2ee5d0SMichal Meloun tegra_lic_post_ithread(device_t dev, struct intr_irqsrc *isrc) 141*ef2ee5d0SMichal Meloun { 142*ef2ee5d0SMichal Meloun struct tegra_lic_sc *sc = device_get_softc(dev); 143*ef2ee5d0SMichal Meloun 144*ef2ee5d0SMichal Meloun PIC_POST_ITHREAD(sc->parent, isrc); 145*ef2ee5d0SMichal Meloun } 146*ef2ee5d0SMichal Meloun 147*ef2ee5d0SMichal Meloun static void 148*ef2ee5d0SMichal Meloun tegra_lic_post_filter(device_t dev, struct intr_irqsrc *isrc) 149*ef2ee5d0SMichal Meloun { 150*ef2ee5d0SMichal Meloun struct tegra_lic_sc *sc = device_get_softc(dev); 151*ef2ee5d0SMichal Meloun 152*ef2ee5d0SMichal Meloun PIC_POST_FILTER(sc->parent, isrc); 153*ef2ee5d0SMichal Meloun } 154*ef2ee5d0SMichal Meloun 155*ef2ee5d0SMichal Meloun #ifdef SMP 156*ef2ee5d0SMichal Meloun static int 157*ef2ee5d0SMichal Meloun tegra_lic_bind(device_t dev, struct intr_irqsrc *isrc) 158*ef2ee5d0SMichal Meloun { 159*ef2ee5d0SMichal Meloun struct tegra_lic_sc *sc = device_get_softc(dev); 160*ef2ee5d0SMichal Meloun 161*ef2ee5d0SMichal Meloun return (PIC_BIND(sc->parent, isrc)); 162*ef2ee5d0SMichal Meloun } 163*ef2ee5d0SMichal Meloun #endif 164*ef2ee5d0SMichal Meloun 165*ef2ee5d0SMichal Meloun static int 166*ef2ee5d0SMichal Meloun tegra_lic_probe(device_t dev) 167*ef2ee5d0SMichal Meloun { 168*ef2ee5d0SMichal Meloun if (!ofw_bus_status_okay(dev)) 169*ef2ee5d0SMichal Meloun return (ENXIO); 170*ef2ee5d0SMichal Meloun 171*ef2ee5d0SMichal Meloun if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 172*ef2ee5d0SMichal Meloun return (ENXIO); 173*ef2ee5d0SMichal Meloun 174*ef2ee5d0SMichal Meloun return (BUS_PROBE_DEFAULT); 175*ef2ee5d0SMichal Meloun } 176*ef2ee5d0SMichal Meloun 177*ef2ee5d0SMichal Meloun static int 178*ef2ee5d0SMichal Meloun tegra_lic_attach(device_t dev) 179*ef2ee5d0SMichal Meloun { 180*ef2ee5d0SMichal Meloun struct tegra_lic_sc *sc; 181*ef2ee5d0SMichal Meloun phandle_t node; 182*ef2ee5d0SMichal Meloun phandle_t parent_xref; 183*ef2ee5d0SMichal Meloun int i, rv; 184*ef2ee5d0SMichal Meloun 185*ef2ee5d0SMichal Meloun sc = device_get_softc(dev); 186*ef2ee5d0SMichal Meloun sc->dev = dev; 187*ef2ee5d0SMichal Meloun node = ofw_bus_get_node(dev); 188*ef2ee5d0SMichal Meloun 189*ef2ee5d0SMichal Meloun rv = OF_getencprop(node, "interrupt-parent", &parent_xref, 190*ef2ee5d0SMichal Meloun sizeof(parent_xref)); 191*ef2ee5d0SMichal Meloun if (rv <= 0) { 192*ef2ee5d0SMichal Meloun device_printf(dev, "Cannot read parent node property\n"); 193*ef2ee5d0SMichal Meloun goto fail; 194*ef2ee5d0SMichal Meloun } 195*ef2ee5d0SMichal Meloun sc->parent = OF_device_from_xref(parent_xref); 196*ef2ee5d0SMichal Meloun if (sc->parent == NULL) { 197*ef2ee5d0SMichal Meloun device_printf(dev, "Cannott find parent controller\n"); 198*ef2ee5d0SMichal Meloun goto fail; 199*ef2ee5d0SMichal Meloun } 200*ef2ee5d0SMichal Meloun 201*ef2ee5d0SMichal Meloun if (bus_alloc_resources(dev, lic_spec, sc->mem_res)) { 202*ef2ee5d0SMichal Meloun device_printf(dev, "Cannott allocate resources\n"); 203*ef2ee5d0SMichal Meloun goto fail; 204*ef2ee5d0SMichal Meloun } 205*ef2ee5d0SMichal Meloun 206*ef2ee5d0SMichal Meloun /* Disable all interrupts, route all to irq */ 207*ef2ee5d0SMichal Meloun for (i = 0; i < nitems(lic_spec); i++) { 208*ef2ee5d0SMichal Meloun if (sc->mem_res[i] == NULL) 209*ef2ee5d0SMichal Meloun continue; 210*ef2ee5d0SMichal Meloun WR4(sc, i, LIC_CPU_IER_CLR, 0xFFFFFFFF); 211*ef2ee5d0SMichal Meloun WR4(sc, i, LIC_CPU_IEP_CLASS, 0); 212*ef2ee5d0SMichal Meloun } 213*ef2ee5d0SMichal Meloun 214*ef2ee5d0SMichal Meloun 215*ef2ee5d0SMichal Meloun if (intr_pic_register(dev, OF_xref_from_node(node)) != 0) { 216*ef2ee5d0SMichal Meloun device_printf(dev, "Cannot register PIC\n"); 217*ef2ee5d0SMichal Meloun goto fail; 218*ef2ee5d0SMichal Meloun } 219*ef2ee5d0SMichal Meloun return (0); 220*ef2ee5d0SMichal Meloun 221*ef2ee5d0SMichal Meloun fail: 222*ef2ee5d0SMichal Meloun bus_release_resources(dev, lic_spec, sc->mem_res); 223*ef2ee5d0SMichal Meloun return (ENXIO); 224*ef2ee5d0SMichal Meloun } 225*ef2ee5d0SMichal Meloun 226*ef2ee5d0SMichal Meloun static int 227*ef2ee5d0SMichal Meloun tegra_lic_detach(device_t dev) 228*ef2ee5d0SMichal Meloun { 229*ef2ee5d0SMichal Meloun struct tegra_lic_sc *sc; 230*ef2ee5d0SMichal Meloun int i; 231*ef2ee5d0SMichal Meloun 232*ef2ee5d0SMichal Meloun sc = device_get_softc(dev); 233*ef2ee5d0SMichal Meloun for (i = 0; i < nitems(lic_spec); i++) { 234*ef2ee5d0SMichal Meloun if (sc->mem_res[i] == NULL) 235*ef2ee5d0SMichal Meloun continue; 236*ef2ee5d0SMichal Meloun bus_release_resource(dev, SYS_RES_MEMORY, i, 237*ef2ee5d0SMichal Meloun sc->mem_res[i]); 238*ef2ee5d0SMichal Meloun } 239*ef2ee5d0SMichal Meloun return (0); 240*ef2ee5d0SMichal Meloun } 241*ef2ee5d0SMichal Meloun 242*ef2ee5d0SMichal Meloun static device_method_t tegra_lic_methods[] = { 243*ef2ee5d0SMichal Meloun DEVMETHOD(device_probe, tegra_lic_probe), 244*ef2ee5d0SMichal Meloun DEVMETHOD(device_attach, tegra_lic_attach), 245*ef2ee5d0SMichal Meloun DEVMETHOD(device_detach, tegra_lic_detach), 246*ef2ee5d0SMichal Meloun 247*ef2ee5d0SMichal Meloun /* Interrupt controller interface */ 248*ef2ee5d0SMichal Meloun DEVMETHOD(pic_register, tegra_lic_register), 249*ef2ee5d0SMichal Meloun DEVMETHOD(pic_unregister, tegra_lic_unregister), 250*ef2ee5d0SMichal Meloun DEVMETHOD(pic_enable_source, tegra_lic_enable_source), 251*ef2ee5d0SMichal Meloun DEVMETHOD(pic_disable_source, tegra_lic_disable_source), 252*ef2ee5d0SMichal Meloun DEVMETHOD(pic_enable_intr, tegra_lic_enable_intr), 253*ef2ee5d0SMichal Meloun DEVMETHOD(pic_pre_ithread, tegra_lic_pre_ithread), 254*ef2ee5d0SMichal Meloun DEVMETHOD(pic_post_ithread, tegra_lic_post_ithread), 255*ef2ee5d0SMichal Meloun DEVMETHOD(pic_post_filter, tegra_lic_post_filter), 256*ef2ee5d0SMichal Meloun #ifdef SMP 257*ef2ee5d0SMichal Meloun DEVMETHOD(pic_bind, tegra_lic_bind), 258*ef2ee5d0SMichal Meloun #endif 259*ef2ee5d0SMichal Meloun DEVMETHOD_END 260*ef2ee5d0SMichal Meloun }; 261*ef2ee5d0SMichal Meloun devclass_t tegra_lic_devclass; 262*ef2ee5d0SMichal Meloun DEFINE_CLASS_0(tegra_lic, tegra_lic_driver, tegra_lic_methods, 263*ef2ee5d0SMichal Meloun sizeof(struct tegra_lic_sc)); 264*ef2ee5d0SMichal Meloun EARLY_DRIVER_MODULE(tegra_lic, simplebus, tegra_lic_driver, tegra_lic_devclass, 265*ef2ee5d0SMichal Meloun NULL, NULL, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE + 1); 266