1*44d027bbSEmmanuel Vadot /*- 2*44d027bbSEmmanuel Vadot * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*44d027bbSEmmanuel Vadot * 4*44d027bbSEmmanuel Vadot * Copyright (c) 2018 Rubicon Communications, LLC (Netgate) 5*44d027bbSEmmanuel Vadot * 6*44d027bbSEmmanuel Vadot * Redistribution and use in source and binary forms, with or without 7*44d027bbSEmmanuel Vadot * modification, are permitted provided that the following conditions 8*44d027bbSEmmanuel Vadot * are met: 9*44d027bbSEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright 10*44d027bbSEmmanuel Vadot * notice, this list of conditions and the following disclaimer. 11*44d027bbSEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright 12*44d027bbSEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the 13*44d027bbSEmmanuel Vadot * documentation and/or other materials provided with the distribution. 14*44d027bbSEmmanuel Vadot * 15*44d027bbSEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16*44d027bbSEmmanuel Vadot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*44d027bbSEmmanuel Vadot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*44d027bbSEmmanuel Vadot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19*44d027bbSEmmanuel Vadot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*44d027bbSEmmanuel Vadot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*44d027bbSEmmanuel Vadot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*44d027bbSEmmanuel Vadot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*44d027bbSEmmanuel Vadot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*44d027bbSEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*44d027bbSEmmanuel Vadot * SUCH DAMAGE. 26*44d027bbSEmmanuel Vadot * 27*44d027bbSEmmanuel Vadot * $FreeBSD$ 28*44d027bbSEmmanuel Vadot */ 29*44d027bbSEmmanuel Vadot 30*44d027bbSEmmanuel Vadot #include <sys/cdefs.h> 31*44d027bbSEmmanuel Vadot __FBSDID("$FreeBSD$"); 32*44d027bbSEmmanuel Vadot 33*44d027bbSEmmanuel Vadot #include <sys/param.h> 34*44d027bbSEmmanuel Vadot #include <sys/systm.h> 35*44d027bbSEmmanuel Vadot #include <sys/bus.h> 36*44d027bbSEmmanuel Vadot 37*44d027bbSEmmanuel Vadot #include <sys/kernel.h> 38*44d027bbSEmmanuel Vadot #include <sys/module.h> 39*44d027bbSEmmanuel Vadot #include <sys/rman.h> 40*44d027bbSEmmanuel Vadot #include <sys/lock.h> 41*44d027bbSEmmanuel Vadot #include <sys/mutex.h> 42*44d027bbSEmmanuel Vadot 43*44d027bbSEmmanuel Vadot #include <machine/bus.h> 44*44d027bbSEmmanuel Vadot #include <machine/resource.h> 45*44d027bbSEmmanuel Vadot #include <machine/intr.h> 46*44d027bbSEmmanuel Vadot 47*44d027bbSEmmanuel Vadot #include <dev/fdt/simplebus.h> 48*44d027bbSEmmanuel Vadot 49*44d027bbSEmmanuel Vadot #include <dev/ofw/ofw_bus.h> 50*44d027bbSEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h> 51*44d027bbSEmmanuel Vadot 52*44d027bbSEmmanuel Vadot #include "pic_if.h" 53*44d027bbSEmmanuel Vadot 54*44d027bbSEmmanuel Vadot #define ICU_GRP_NSR 0x0 55*44d027bbSEmmanuel Vadot #define ICU_GRP_SR 0x1 56*44d027bbSEmmanuel Vadot #define ICU_GRP_SEI 0x4 57*44d027bbSEmmanuel Vadot #define ICU_GRP_REI 0x5 58*44d027bbSEmmanuel Vadot 59*44d027bbSEmmanuel Vadot #define ICU_SETSPI_NSR_AL 0x10 60*44d027bbSEmmanuel Vadot #define ICU_SETSPI_NSR_AH 0x14 61*44d027bbSEmmanuel Vadot #define ICU_CLRSPI_NSR_AL 0x18 62*44d027bbSEmmanuel Vadot #define ICU_CLRSPI_NSR_AH 0x1c 63*44d027bbSEmmanuel Vadot #define ICU_INT_CFG(x) (0x100 + (x) * 4) 64*44d027bbSEmmanuel Vadot #define ICU_INT_ENABLE (1 << 24) 65*44d027bbSEmmanuel Vadot #define ICU_INT_EDGE (1 << 28) 66*44d027bbSEmmanuel Vadot #define ICU_INT_GROUP_SHIFT 29 67*44d027bbSEmmanuel Vadot #define ICU_INT_MASK 0x3ff 68*44d027bbSEmmanuel Vadot 69*44d027bbSEmmanuel Vadot #define MV_CP110_ICU_MAX_NIRQS 207 70*44d027bbSEmmanuel Vadot 71*44d027bbSEmmanuel Vadot struct mv_cp110_icu_softc { 72*44d027bbSEmmanuel Vadot device_t dev; 73*44d027bbSEmmanuel Vadot device_t parent; 74*44d027bbSEmmanuel Vadot struct resource *res; 75*44d027bbSEmmanuel Vadot }; 76*44d027bbSEmmanuel Vadot 77*44d027bbSEmmanuel Vadot static struct resource_spec mv_cp110_icu_res_spec[] = { 78*44d027bbSEmmanuel Vadot { SYS_RES_MEMORY, 0, RF_ACTIVE | RF_SHAREABLE }, 79*44d027bbSEmmanuel Vadot { -1, 0 } 80*44d027bbSEmmanuel Vadot }; 81*44d027bbSEmmanuel Vadot 82*44d027bbSEmmanuel Vadot static struct ofw_compat_data compat_data[] = { 83*44d027bbSEmmanuel Vadot {"marvell,cp110-icu", 1}, 84*44d027bbSEmmanuel Vadot {NULL, 0} 85*44d027bbSEmmanuel Vadot }; 86*44d027bbSEmmanuel Vadot 87*44d027bbSEmmanuel Vadot #define RD4(sc, reg) bus_read_4((sc)->res, (reg)) 88*44d027bbSEmmanuel Vadot #define WR4(sc, reg, val) bus_write_4((sc)->res, (reg), (val)) 89*44d027bbSEmmanuel Vadot 90*44d027bbSEmmanuel Vadot static int 91*44d027bbSEmmanuel Vadot mv_cp110_icu_probe(device_t dev) 92*44d027bbSEmmanuel Vadot { 93*44d027bbSEmmanuel Vadot 94*44d027bbSEmmanuel Vadot if (!ofw_bus_status_okay(dev)) 95*44d027bbSEmmanuel Vadot return (ENXIO); 96*44d027bbSEmmanuel Vadot 97*44d027bbSEmmanuel Vadot if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 98*44d027bbSEmmanuel Vadot return (ENXIO); 99*44d027bbSEmmanuel Vadot 100*44d027bbSEmmanuel Vadot device_set_desc(dev, "Marvell Interrupt Consolidation Unit"); 101*44d027bbSEmmanuel Vadot return (BUS_PROBE_DEFAULT); 102*44d027bbSEmmanuel Vadot } 103*44d027bbSEmmanuel Vadot 104*44d027bbSEmmanuel Vadot static int 105*44d027bbSEmmanuel Vadot mv_cp110_icu_attach(device_t dev) 106*44d027bbSEmmanuel Vadot { 107*44d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc; 108*44d027bbSEmmanuel Vadot phandle_t node, msi_parent; 109*44d027bbSEmmanuel Vadot 110*44d027bbSEmmanuel Vadot sc = device_get_softc(dev); 111*44d027bbSEmmanuel Vadot sc->dev = dev; 112*44d027bbSEmmanuel Vadot node = ofw_bus_get_node(dev); 113*44d027bbSEmmanuel Vadot 114*44d027bbSEmmanuel Vadot if (OF_getencprop(node, "msi-parent", &msi_parent, 115*44d027bbSEmmanuel Vadot sizeof(phandle_t)) <= 0) { 116*44d027bbSEmmanuel Vadot device_printf(dev, "cannot find msi-parent property\n"); 117*44d027bbSEmmanuel Vadot return (ENXIO); 118*44d027bbSEmmanuel Vadot } 119*44d027bbSEmmanuel Vadot 120*44d027bbSEmmanuel Vadot if ((sc->parent = OF_device_from_xref(msi_parent)) == NULL) { 121*44d027bbSEmmanuel Vadot device_printf(dev, "cannot find msi-parent device\n"); 122*44d027bbSEmmanuel Vadot return (ENXIO); 123*44d027bbSEmmanuel Vadot } 124*44d027bbSEmmanuel Vadot if (bus_alloc_resources(dev, mv_cp110_icu_res_spec, &sc->res) != 0) { 125*44d027bbSEmmanuel Vadot device_printf(dev, "cannot allocate resources for device\n"); 126*44d027bbSEmmanuel Vadot return (ENXIO); 127*44d027bbSEmmanuel Vadot } 128*44d027bbSEmmanuel Vadot 129*44d027bbSEmmanuel Vadot if (intr_pic_register(dev, OF_xref_from_node(node)) == NULL) { 130*44d027bbSEmmanuel Vadot device_printf(dev, "Cannot register ICU\n"); 131*44d027bbSEmmanuel Vadot goto fail; 132*44d027bbSEmmanuel Vadot } 133*44d027bbSEmmanuel Vadot return (0); 134*44d027bbSEmmanuel Vadot 135*44d027bbSEmmanuel Vadot fail: 136*44d027bbSEmmanuel Vadot bus_release_resources(dev, mv_cp110_icu_res_spec, &sc->res); 137*44d027bbSEmmanuel Vadot return (ENXIO); 138*44d027bbSEmmanuel Vadot } 139*44d027bbSEmmanuel Vadot 140*44d027bbSEmmanuel Vadot static int 141*44d027bbSEmmanuel Vadot mv_cp110_icu_detach(device_t dev) 142*44d027bbSEmmanuel Vadot { 143*44d027bbSEmmanuel Vadot 144*44d027bbSEmmanuel Vadot return (EBUSY); 145*44d027bbSEmmanuel Vadot } 146*44d027bbSEmmanuel Vadot 147*44d027bbSEmmanuel Vadot static int 148*44d027bbSEmmanuel Vadot mv_cp110_icu_activate_intr(device_t dev, struct intr_irqsrc *isrc, 149*44d027bbSEmmanuel Vadot struct resource *res, struct intr_map_data *data) 150*44d027bbSEmmanuel Vadot { 151*44d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc; 152*44d027bbSEmmanuel Vadot 153*44d027bbSEmmanuel Vadot sc = device_get_softc(dev); 154*44d027bbSEmmanuel Vadot 155*44d027bbSEmmanuel Vadot return (PIC_ACTIVATE_INTR(sc->parent, isrc, res, data)); 156*44d027bbSEmmanuel Vadot } 157*44d027bbSEmmanuel Vadot 158*44d027bbSEmmanuel Vadot static void 159*44d027bbSEmmanuel Vadot mv_cp110_icu_enable_intr(device_t dev, struct intr_irqsrc *isrc) 160*44d027bbSEmmanuel Vadot { 161*44d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc; 162*44d027bbSEmmanuel Vadot 163*44d027bbSEmmanuel Vadot sc = device_get_softc(dev); 164*44d027bbSEmmanuel Vadot 165*44d027bbSEmmanuel Vadot PIC_ENABLE_INTR(sc->parent, isrc); 166*44d027bbSEmmanuel Vadot } 167*44d027bbSEmmanuel Vadot 168*44d027bbSEmmanuel Vadot static void 169*44d027bbSEmmanuel Vadot mv_cp110_icu_disable_intr(device_t dev, struct intr_irqsrc *isrc) 170*44d027bbSEmmanuel Vadot { 171*44d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc; 172*44d027bbSEmmanuel Vadot 173*44d027bbSEmmanuel Vadot sc = device_get_softc(dev); 174*44d027bbSEmmanuel Vadot 175*44d027bbSEmmanuel Vadot PIC_DISABLE_INTR(sc->parent, isrc); 176*44d027bbSEmmanuel Vadot } 177*44d027bbSEmmanuel Vadot 178*44d027bbSEmmanuel Vadot static int 179*44d027bbSEmmanuel Vadot mv_cp110_icu_map_intr(device_t dev, struct intr_map_data *data, 180*44d027bbSEmmanuel Vadot struct intr_irqsrc **isrcp) 181*44d027bbSEmmanuel Vadot { 182*44d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc; 183*44d027bbSEmmanuel Vadot struct intr_map_data_fdt *daf; 184*44d027bbSEmmanuel Vadot uint32_t reg; 185*44d027bbSEmmanuel Vadot 186*44d027bbSEmmanuel Vadot sc = device_get_softc(dev); 187*44d027bbSEmmanuel Vadot 188*44d027bbSEmmanuel Vadot if (data->type != INTR_MAP_DATA_FDT) 189*44d027bbSEmmanuel Vadot return (ENOTSUP); 190*44d027bbSEmmanuel Vadot 191*44d027bbSEmmanuel Vadot daf = (struct intr_map_data_fdt *)data; 192*44d027bbSEmmanuel Vadot if (daf->ncells != 3 || daf->cells[0] >= MV_CP110_ICU_MAX_NIRQS) 193*44d027bbSEmmanuel Vadot return (EINVAL); 194*44d027bbSEmmanuel Vadot 195*44d027bbSEmmanuel Vadot reg = RD4(sc, ICU_INT_CFG(daf->cells[1])); 196*44d027bbSEmmanuel Vadot 197*44d027bbSEmmanuel Vadot if ((reg & ICU_INT_ENABLE) == 0) { 198*44d027bbSEmmanuel Vadot reg |= ICU_INT_ENABLE; 199*44d027bbSEmmanuel Vadot WR4(sc, ICU_INT_CFG(daf->cells[1], reg)); 200*44d027bbSEmmanuel Vadot } 201*44d027bbSEmmanuel Vadot 202*44d027bbSEmmanuel Vadot daf->cells[1] = reg & ICU_INT_MASK; 203*44d027bbSEmmanuel Vadot return (PIC_MAP_INTR(sc->parent, data, isrcp)); 204*44d027bbSEmmanuel Vadot } 205*44d027bbSEmmanuel Vadot 206*44d027bbSEmmanuel Vadot static int 207*44d027bbSEmmanuel Vadot mv_cp110_icu_deactivate_intr(device_t dev, struct intr_irqsrc *isrc, 208*44d027bbSEmmanuel Vadot struct resource *res, struct intr_map_data *data) 209*44d027bbSEmmanuel Vadot { 210*44d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc; 211*44d027bbSEmmanuel Vadot 212*44d027bbSEmmanuel Vadot sc = device_get_softc(dev); 213*44d027bbSEmmanuel Vadot 214*44d027bbSEmmanuel Vadot return (PIC_DEACTIVATE_INTR(sc->parent, isrc, res, data)); 215*44d027bbSEmmanuel Vadot } 216*44d027bbSEmmanuel Vadot 217*44d027bbSEmmanuel Vadot static int 218*44d027bbSEmmanuel Vadot mv_cp110_icu_setup_intr(device_t dev, struct intr_irqsrc *isrc, 219*44d027bbSEmmanuel Vadot struct resource *res, struct intr_map_data *data) 220*44d027bbSEmmanuel Vadot { 221*44d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc; 222*44d027bbSEmmanuel Vadot 223*44d027bbSEmmanuel Vadot sc = device_get_softc(dev); 224*44d027bbSEmmanuel Vadot 225*44d027bbSEmmanuel Vadot return (PIC_SETUP_INTR(sc->parent, isrc, res, data)); 226*44d027bbSEmmanuel Vadot } 227*44d027bbSEmmanuel Vadot 228*44d027bbSEmmanuel Vadot static int 229*44d027bbSEmmanuel Vadot mv_cp110_icu_teardown_intr(device_t dev, struct intr_irqsrc *isrc, 230*44d027bbSEmmanuel Vadot struct resource *res, struct intr_map_data *data) 231*44d027bbSEmmanuel Vadot { 232*44d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc; 233*44d027bbSEmmanuel Vadot 234*44d027bbSEmmanuel Vadot sc = device_get_softc(dev); 235*44d027bbSEmmanuel Vadot 236*44d027bbSEmmanuel Vadot return (PIC_TEARDOWN_INTR(sc->parent, isrc, res, data)); 237*44d027bbSEmmanuel Vadot } 238*44d027bbSEmmanuel Vadot 239*44d027bbSEmmanuel Vadot static void 240*44d027bbSEmmanuel Vadot mv_cp110_icu_pre_ithread(device_t dev, struct intr_irqsrc *isrc) 241*44d027bbSEmmanuel Vadot { 242*44d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc; 243*44d027bbSEmmanuel Vadot 244*44d027bbSEmmanuel Vadot sc = device_get_softc(dev); 245*44d027bbSEmmanuel Vadot 246*44d027bbSEmmanuel Vadot PIC_PRE_ITHREAD(sc->parent, isrc); 247*44d027bbSEmmanuel Vadot } 248*44d027bbSEmmanuel Vadot 249*44d027bbSEmmanuel Vadot static void 250*44d027bbSEmmanuel Vadot mv_cp110_icu_post_ithread(device_t dev, struct intr_irqsrc *isrc) 251*44d027bbSEmmanuel Vadot { 252*44d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc; 253*44d027bbSEmmanuel Vadot 254*44d027bbSEmmanuel Vadot sc = device_get_softc(dev); 255*44d027bbSEmmanuel Vadot 256*44d027bbSEmmanuel Vadot PIC_POST_ITHREAD(sc->parent, isrc); 257*44d027bbSEmmanuel Vadot } 258*44d027bbSEmmanuel Vadot 259*44d027bbSEmmanuel Vadot static void 260*44d027bbSEmmanuel Vadot mv_cp110_icu_post_filter(device_t dev, struct intr_irqsrc *isrc) 261*44d027bbSEmmanuel Vadot { 262*44d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc; 263*44d027bbSEmmanuel Vadot 264*44d027bbSEmmanuel Vadot sc = device_get_softc(dev); 265*44d027bbSEmmanuel Vadot 266*44d027bbSEmmanuel Vadot PIC_POST_FILTER(sc->parent, isrc); 267*44d027bbSEmmanuel Vadot } 268*44d027bbSEmmanuel Vadot 269*44d027bbSEmmanuel Vadot static device_method_t mv_cp110_icu_methods[] = { 270*44d027bbSEmmanuel Vadot /* Device interface */ 271*44d027bbSEmmanuel Vadot DEVMETHOD(device_probe, mv_cp110_icu_probe), 272*44d027bbSEmmanuel Vadot DEVMETHOD(device_attach, mv_cp110_icu_attach), 273*44d027bbSEmmanuel Vadot DEVMETHOD(device_detach, mv_cp110_icu_detach), 274*44d027bbSEmmanuel Vadot 275*44d027bbSEmmanuel Vadot /* Interrupt controller interface */ 276*44d027bbSEmmanuel Vadot DEVMETHOD(pic_activate_intr, mv_cp110_icu_activate_intr), 277*44d027bbSEmmanuel Vadot DEVMETHOD(pic_disable_intr, mv_cp110_icu_disable_intr), 278*44d027bbSEmmanuel Vadot DEVMETHOD(pic_enable_intr, mv_cp110_icu_enable_intr), 279*44d027bbSEmmanuel Vadot DEVMETHOD(pic_map_intr, mv_cp110_icu_map_intr), 280*44d027bbSEmmanuel Vadot DEVMETHOD(pic_deactivate_intr, mv_cp110_icu_deactivate_intr), 281*44d027bbSEmmanuel Vadot DEVMETHOD(pic_setup_intr, mv_cp110_icu_setup_intr), 282*44d027bbSEmmanuel Vadot DEVMETHOD(pic_teardown_intr, mv_cp110_icu_teardown_intr), 283*44d027bbSEmmanuel Vadot DEVMETHOD(pic_post_filter, mv_cp110_icu_post_filter), 284*44d027bbSEmmanuel Vadot DEVMETHOD(pic_post_ithread, mv_cp110_icu_post_ithread), 285*44d027bbSEmmanuel Vadot DEVMETHOD(pic_pre_ithread, mv_cp110_icu_pre_ithread), 286*44d027bbSEmmanuel Vadot 287*44d027bbSEmmanuel Vadot DEVMETHOD_END 288*44d027bbSEmmanuel Vadot }; 289*44d027bbSEmmanuel Vadot 290*44d027bbSEmmanuel Vadot static devclass_t mv_cp110_icu_devclass; 291*44d027bbSEmmanuel Vadot 292*44d027bbSEmmanuel Vadot static driver_t mv_cp110_icu_driver = { 293*44d027bbSEmmanuel Vadot "mv_cp110_icu", 294*44d027bbSEmmanuel Vadot mv_cp110_icu_methods, 295*44d027bbSEmmanuel Vadot sizeof(struct mv_cp110_icu_softc), 296*44d027bbSEmmanuel Vadot }; 297*44d027bbSEmmanuel Vadot 298*44d027bbSEmmanuel Vadot EARLY_DRIVER_MODULE(mv_cp110_icu, simplebus, mv_cp110_icu_driver, 299*44d027bbSEmmanuel Vadot mv_cp110_icu_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST); 300