144d027bbSEmmanuel Vadot /*- 244d027bbSEmmanuel Vadot * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 344d027bbSEmmanuel Vadot * 444d027bbSEmmanuel Vadot * Copyright (c) 2018 Rubicon Communications, LLC (Netgate) 544d027bbSEmmanuel Vadot * 644d027bbSEmmanuel Vadot * Redistribution and use in source and binary forms, with or without 744d027bbSEmmanuel Vadot * modification, are permitted provided that the following conditions 844d027bbSEmmanuel Vadot * are met: 944d027bbSEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright 1044d027bbSEmmanuel Vadot * notice, this list of conditions and the following disclaimer. 1144d027bbSEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright 1244d027bbSEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the 1344d027bbSEmmanuel Vadot * documentation and/or other materials provided with the distribution. 1444d027bbSEmmanuel Vadot * 1544d027bbSEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1644d027bbSEmmanuel Vadot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1744d027bbSEmmanuel Vadot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1844d027bbSEmmanuel Vadot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1944d027bbSEmmanuel Vadot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2044d027bbSEmmanuel Vadot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2144d027bbSEmmanuel Vadot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2244d027bbSEmmanuel Vadot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2344d027bbSEmmanuel Vadot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2444d027bbSEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2544d027bbSEmmanuel Vadot * SUCH DAMAGE. 2644d027bbSEmmanuel Vadot * 2744d027bbSEmmanuel Vadot * $FreeBSD$ 2844d027bbSEmmanuel Vadot */ 2944d027bbSEmmanuel Vadot 3044d027bbSEmmanuel Vadot #include <sys/cdefs.h> 3144d027bbSEmmanuel Vadot __FBSDID("$FreeBSD$"); 3244d027bbSEmmanuel Vadot 3344d027bbSEmmanuel Vadot #include <sys/param.h> 3444d027bbSEmmanuel Vadot #include <sys/systm.h> 3544d027bbSEmmanuel Vadot #include <sys/bus.h> 3644d027bbSEmmanuel Vadot 3744d027bbSEmmanuel Vadot #include <sys/kernel.h> 3844d027bbSEmmanuel Vadot #include <sys/module.h> 3944d027bbSEmmanuel Vadot #include <sys/rman.h> 4044d027bbSEmmanuel Vadot #include <sys/lock.h> 4144d027bbSEmmanuel Vadot #include <sys/mutex.h> 4244d027bbSEmmanuel Vadot 4344d027bbSEmmanuel Vadot #include <machine/bus.h> 4444d027bbSEmmanuel Vadot #include <machine/resource.h> 4544d027bbSEmmanuel Vadot #include <machine/intr.h> 4644d027bbSEmmanuel Vadot 4744d027bbSEmmanuel Vadot #include <dev/fdt/simplebus.h> 4844d027bbSEmmanuel Vadot 4944d027bbSEmmanuel Vadot #include <dev/ofw/ofw_bus.h> 5044d027bbSEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h> 5144d027bbSEmmanuel Vadot 528a7a4683SEmmanuel Vadot #include <dt-bindings/interrupt-controller/irq.h> 53986bbba9SKornel Duleba 5444d027bbSEmmanuel Vadot #include "pic_if.h" 55986bbba9SKornel Duleba #include "msi_if.h" 56986bbba9SKornel Duleba 57986bbba9SKornel Duleba #define ICU_TYPE_NSR 1 58986bbba9SKornel Duleba #define ICU_TYPE_SEI 2 5944d027bbSEmmanuel Vadot 6044d027bbSEmmanuel Vadot #define ICU_GRP_NSR 0x0 6144d027bbSEmmanuel Vadot #define ICU_GRP_SR 0x1 6244d027bbSEmmanuel Vadot #define ICU_GRP_SEI 0x4 6344d027bbSEmmanuel Vadot #define ICU_GRP_REI 0x5 6444d027bbSEmmanuel Vadot 6544d027bbSEmmanuel Vadot #define ICU_SETSPI_NSR_AL 0x10 6644d027bbSEmmanuel Vadot #define ICU_SETSPI_NSR_AH 0x14 6744d027bbSEmmanuel Vadot #define ICU_CLRSPI_NSR_AL 0x18 6844d027bbSEmmanuel Vadot #define ICU_CLRSPI_NSR_AH 0x1c 69986bbba9SKornel Duleba #define ICU_SETSPI_SEI_AL 0x50 70986bbba9SKornel Duleba #define ICU_SETSPI_SEI_AH 0x54 7144d027bbSEmmanuel Vadot #define ICU_INT_CFG(x) (0x100 + (x) * 4) 7244d027bbSEmmanuel Vadot #define ICU_INT_ENABLE (1 << 24) 7344d027bbSEmmanuel Vadot #define ICU_INT_EDGE (1 << 28) 7444d027bbSEmmanuel Vadot #define ICU_INT_GROUP_SHIFT 29 7544d027bbSEmmanuel Vadot #define ICU_INT_MASK 0x3ff 7644d027bbSEmmanuel Vadot 77986bbba9SKornel Duleba #define ICU_INT_SATA0 109 78986bbba9SKornel Duleba #define ICU_INT_SATA1 107 79986bbba9SKornel Duleba 8044d027bbSEmmanuel Vadot #define MV_CP110_ICU_MAX_NIRQS 207 8144d027bbSEmmanuel Vadot 82986bbba9SKornel Duleba #define MV_CP110_ICU_CLRSPI_OFFSET 0x8 83986bbba9SKornel Duleba 8444d027bbSEmmanuel Vadot struct mv_cp110_icu_softc { 8544d027bbSEmmanuel Vadot device_t dev; 8644d027bbSEmmanuel Vadot device_t parent; 8744d027bbSEmmanuel Vadot struct resource *res; 884b84206bSMichal Meloun struct intr_map_data_fdt *parent_map_data; 89986bbba9SKornel Duleba bool initialized; 90986bbba9SKornel Duleba int type; 9144d027bbSEmmanuel Vadot }; 9244d027bbSEmmanuel Vadot 9344d027bbSEmmanuel Vadot static struct resource_spec mv_cp110_icu_res_spec[] = { 9444d027bbSEmmanuel Vadot { SYS_RES_MEMORY, 0, RF_ACTIVE | RF_SHAREABLE }, 9544d027bbSEmmanuel Vadot { -1, 0 } 9644d027bbSEmmanuel Vadot }; 9744d027bbSEmmanuel Vadot 9844d027bbSEmmanuel Vadot static struct ofw_compat_data compat_data[] = { 99986bbba9SKornel Duleba {"marvell,cp110-icu-nsr", ICU_TYPE_NSR}, 100986bbba9SKornel Duleba {"marvell,cp110-icu-sei", ICU_TYPE_SEI}, 10144d027bbSEmmanuel Vadot {NULL, 0} 10244d027bbSEmmanuel Vadot }; 10344d027bbSEmmanuel Vadot 10444d027bbSEmmanuel Vadot #define RD4(sc, reg) bus_read_4((sc)->res, (reg)) 10544d027bbSEmmanuel Vadot #define WR4(sc, reg, val) bus_write_4((sc)->res, (reg), (val)) 10644d027bbSEmmanuel Vadot 10744d027bbSEmmanuel Vadot static int 10844d027bbSEmmanuel Vadot mv_cp110_icu_probe(device_t dev) 10944d027bbSEmmanuel Vadot { 11044d027bbSEmmanuel Vadot 11144d027bbSEmmanuel Vadot if (!ofw_bus_status_okay(dev)) 11244d027bbSEmmanuel Vadot return (ENXIO); 11344d027bbSEmmanuel Vadot 11444d027bbSEmmanuel Vadot if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 11544d027bbSEmmanuel Vadot return (ENXIO); 11644d027bbSEmmanuel Vadot 11744d027bbSEmmanuel Vadot device_set_desc(dev, "Marvell Interrupt Consolidation Unit"); 11844d027bbSEmmanuel Vadot return (BUS_PROBE_DEFAULT); 11944d027bbSEmmanuel Vadot } 12044d027bbSEmmanuel Vadot 12144d027bbSEmmanuel Vadot static int 12244d027bbSEmmanuel Vadot mv_cp110_icu_attach(device_t dev) 12344d027bbSEmmanuel Vadot { 12444d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc; 12544d027bbSEmmanuel Vadot phandle_t node, msi_parent; 126986bbba9SKornel Duleba uint32_t reg, icu_grp; 127986bbba9SKornel Duleba int i; 12844d027bbSEmmanuel Vadot 12944d027bbSEmmanuel Vadot sc = device_get_softc(dev); 13044d027bbSEmmanuel Vadot sc->dev = dev; 13144d027bbSEmmanuel Vadot node = ofw_bus_get_node(dev); 132986bbba9SKornel Duleba sc->type = (int)ofw_bus_search_compatible(dev, compat_data)->ocd_data; 133986bbba9SKornel Duleba sc->initialized = false; 13444d027bbSEmmanuel Vadot 13544d027bbSEmmanuel Vadot if (OF_getencprop(node, "msi-parent", &msi_parent, 13644d027bbSEmmanuel Vadot sizeof(phandle_t)) <= 0) { 13744d027bbSEmmanuel Vadot device_printf(dev, "cannot find msi-parent property\n"); 13844d027bbSEmmanuel Vadot return (ENXIO); 13944d027bbSEmmanuel Vadot } 14044d027bbSEmmanuel Vadot 14144d027bbSEmmanuel Vadot if ((sc->parent = OF_device_from_xref(msi_parent)) == NULL) { 14244d027bbSEmmanuel Vadot device_printf(dev, "cannot find msi-parent device\n"); 14344d027bbSEmmanuel Vadot return (ENXIO); 14444d027bbSEmmanuel Vadot } 14544d027bbSEmmanuel Vadot if (bus_alloc_resources(dev, mv_cp110_icu_res_spec, &sc->res) != 0) { 14644d027bbSEmmanuel Vadot device_printf(dev, "cannot allocate resources for device\n"); 14744d027bbSEmmanuel Vadot return (ENXIO); 14844d027bbSEmmanuel Vadot } 14944d027bbSEmmanuel Vadot 15044d027bbSEmmanuel Vadot if (intr_pic_register(dev, OF_xref_from_node(node)) == NULL) { 15144d027bbSEmmanuel Vadot device_printf(dev, "Cannot register ICU\n"); 15244d027bbSEmmanuel Vadot goto fail; 15344d027bbSEmmanuel Vadot } 1544b84206bSMichal Meloun 155986bbba9SKornel Duleba /* Allocate GICP/SEI compatible mapping entry (2 cells) */ 1564b84206bSMichal Meloun sc->parent_map_data = (struct intr_map_data_fdt *)intr_alloc_map_data( 1574b84206bSMichal Meloun INTR_MAP_DATA_FDT, sizeof(struct intr_map_data_fdt) + 1584b84206bSMichal Meloun + 3 * sizeof(phandle_t), M_WAITOK | M_ZERO); 159986bbba9SKornel Duleba 160986bbba9SKornel Duleba /* Clear any previous mapping done by firmware. */ 161986bbba9SKornel Duleba for (i = 0; i < MV_CP110_ICU_MAX_NIRQS; i++) { 162986bbba9SKornel Duleba reg = RD4(sc, ICU_INT_CFG(i)); 163986bbba9SKornel Duleba icu_grp = reg >> ICU_INT_GROUP_SHIFT; 164986bbba9SKornel Duleba 165986bbba9SKornel Duleba if (icu_grp == ICU_GRP_NSR || icu_grp == ICU_GRP_SEI) 166986bbba9SKornel Duleba WR4(sc, ICU_INT_CFG(i), 0); 167986bbba9SKornel Duleba } 168986bbba9SKornel Duleba 16944d027bbSEmmanuel Vadot return (0); 17044d027bbSEmmanuel Vadot 17144d027bbSEmmanuel Vadot fail: 17244d027bbSEmmanuel Vadot bus_release_resources(dev, mv_cp110_icu_res_spec, &sc->res); 17344d027bbSEmmanuel Vadot return (ENXIO); 17444d027bbSEmmanuel Vadot } 17544d027bbSEmmanuel Vadot 1764b84206bSMichal Meloun static struct intr_map_data * 1774b84206bSMichal Meloun mv_cp110_icu_convert_map_data(struct mv_cp110_icu_softc *sc, struct intr_map_data *data) 1784b84206bSMichal Meloun { 1794b84206bSMichal Meloun struct intr_map_data_fdt *daf; 1804b84206bSMichal Meloun uint32_t reg, irq_no, irq_type; 1814b84206bSMichal Meloun 1824b84206bSMichal Meloun daf = (struct intr_map_data_fdt *)data; 1834b84206bSMichal Meloun if (daf->ncells != 2) 1844b84206bSMichal Meloun return (NULL); 185986bbba9SKornel Duleba 1864b84206bSMichal Meloun irq_no = daf->cells[0]; 1874b84206bSMichal Meloun if (irq_no >= MV_CP110_ICU_MAX_NIRQS) 1884b84206bSMichal Meloun return (NULL); 189986bbba9SKornel Duleba 190986bbba9SKornel Duleba irq_type = daf->cells[1]; 1914b84206bSMichal Meloun if (irq_type != IRQ_TYPE_LEVEL_HIGH && 1924b84206bSMichal Meloun irq_type != IRQ_TYPE_EDGE_RISING) 1934b84206bSMichal Meloun return (NULL); 1944b84206bSMichal Meloun 195986bbba9SKornel Duleba /* ICU -> GICP/SEI mapping is set in mv_cp110_icu_map_intr. */ 1964b84206bSMichal Meloun reg = RD4(sc, ICU_INT_CFG(irq_no)); 1974b84206bSMichal Meloun 1984b84206bSMichal Meloun /* Construct GICP compatible mapping. */ 1994b84206bSMichal Meloun sc->parent_map_data->ncells = 2; 2004b84206bSMichal Meloun sc->parent_map_data->cells[0] = reg & ICU_INT_MASK; 2014b84206bSMichal Meloun sc->parent_map_data->cells[1] = irq_type; 2024b84206bSMichal Meloun 2034b84206bSMichal Meloun return ((struct intr_map_data *)sc->parent_map_data); 2044b84206bSMichal Meloun } 2054b84206bSMichal Meloun 20644d027bbSEmmanuel Vadot static int 20744d027bbSEmmanuel Vadot mv_cp110_icu_detach(device_t dev) 20844d027bbSEmmanuel Vadot { 20944d027bbSEmmanuel Vadot 21044d027bbSEmmanuel Vadot return (EBUSY); 21144d027bbSEmmanuel Vadot } 21244d027bbSEmmanuel Vadot 21344d027bbSEmmanuel Vadot static int 21444d027bbSEmmanuel Vadot mv_cp110_icu_activate_intr(device_t dev, struct intr_irqsrc *isrc, 21544d027bbSEmmanuel Vadot struct resource *res, struct intr_map_data *data) 21644d027bbSEmmanuel Vadot { 21744d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc; 21844d027bbSEmmanuel Vadot 21944d027bbSEmmanuel Vadot sc = device_get_softc(dev); 2204b84206bSMichal Meloun data = mv_cp110_icu_convert_map_data(sc, data); 2214b84206bSMichal Meloun if (data == NULL) 2224b84206bSMichal Meloun return (EINVAL); 22344d027bbSEmmanuel Vadot return (PIC_ACTIVATE_INTR(sc->parent, isrc, res, data)); 22444d027bbSEmmanuel Vadot } 22544d027bbSEmmanuel Vadot 22644d027bbSEmmanuel Vadot static void 22744d027bbSEmmanuel Vadot mv_cp110_icu_enable_intr(device_t dev, struct intr_irqsrc *isrc) 22844d027bbSEmmanuel Vadot { 22944d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc; 23044d027bbSEmmanuel Vadot sc = device_get_softc(dev); 23144d027bbSEmmanuel Vadot 23244d027bbSEmmanuel Vadot PIC_ENABLE_INTR(sc->parent, isrc); 23344d027bbSEmmanuel Vadot } 23444d027bbSEmmanuel Vadot 23544d027bbSEmmanuel Vadot static void 23644d027bbSEmmanuel Vadot mv_cp110_icu_disable_intr(device_t dev, struct intr_irqsrc *isrc) 23744d027bbSEmmanuel Vadot { 23844d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc; 23944d027bbSEmmanuel Vadot 24044d027bbSEmmanuel Vadot sc = device_get_softc(dev); 24144d027bbSEmmanuel Vadot 24244d027bbSEmmanuel Vadot PIC_DISABLE_INTR(sc->parent, isrc); 24344d027bbSEmmanuel Vadot } 24444d027bbSEmmanuel Vadot 245986bbba9SKornel Duleba static void 246986bbba9SKornel Duleba mv_cp110_icu_init(struct mv_cp110_icu_softc *sc, uint64_t addr) 247986bbba9SKornel Duleba { 248986bbba9SKornel Duleba 249986bbba9SKornel Duleba if (sc->initialized) 250986bbba9SKornel Duleba return; 251986bbba9SKornel Duleba 252986bbba9SKornel Duleba switch (sc->type) { 253986bbba9SKornel Duleba case ICU_TYPE_NSR: 254986bbba9SKornel Duleba WR4(sc, ICU_SETSPI_NSR_AL, addr & UINT32_MAX); 255986bbba9SKornel Duleba WR4(sc, ICU_SETSPI_NSR_AH, (addr >> 32) & UINT32_MAX); 256986bbba9SKornel Duleba addr += MV_CP110_ICU_CLRSPI_OFFSET; 257986bbba9SKornel Duleba WR4(sc, ICU_CLRSPI_NSR_AL, addr & UINT32_MAX); 258986bbba9SKornel Duleba WR4(sc, ICU_CLRSPI_NSR_AH, (addr >> 32) & UINT32_MAX); 259986bbba9SKornel Duleba break; 260986bbba9SKornel Duleba case ICU_TYPE_SEI: 261986bbba9SKornel Duleba WR4(sc, ICU_SETSPI_SEI_AL, addr & UINT32_MAX); 262986bbba9SKornel Duleba WR4(sc, ICU_SETSPI_SEI_AH, (addr >> 32) & UINT32_MAX); 263986bbba9SKornel Duleba break; 264986bbba9SKornel Duleba default: 265986bbba9SKornel Duleba panic("Unkown ICU type."); 266986bbba9SKornel Duleba } 267986bbba9SKornel Duleba 268986bbba9SKornel Duleba sc->initialized = true; 269986bbba9SKornel Duleba } 270986bbba9SKornel Duleba 27144d027bbSEmmanuel Vadot static int 27244d027bbSEmmanuel Vadot mv_cp110_icu_map_intr(device_t dev, struct intr_map_data *data, 27344d027bbSEmmanuel Vadot struct intr_irqsrc **isrcp) 27444d027bbSEmmanuel Vadot { 27544d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc; 27644d027bbSEmmanuel Vadot struct intr_map_data_fdt *daf; 277986bbba9SKornel Duleba uint32_t vector, irq_no, irq_type; 278986bbba9SKornel Duleba uint64_t addr; 2794b84206bSMichal Meloun int ret; 28044d027bbSEmmanuel Vadot 28144d027bbSEmmanuel Vadot sc = device_get_softc(dev); 28244d027bbSEmmanuel Vadot 28344d027bbSEmmanuel Vadot if (data->type != INTR_MAP_DATA_FDT) 28444d027bbSEmmanuel Vadot return (ENOTSUP); 28544d027bbSEmmanuel Vadot 2864b84206bSMichal Meloun /* Parse original */ 28744d027bbSEmmanuel Vadot daf = (struct intr_map_data_fdt *)data; 2884b84206bSMichal Meloun if (daf->ncells != 2) 2894b84206bSMichal Meloun return (EINVAL); 290986bbba9SKornel Duleba 2914b84206bSMichal Meloun irq_no = daf->cells[0]; 292986bbba9SKornel Duleba if (irq_no >= MV_CP110_ICU_MAX_NIRQS) 29344d027bbSEmmanuel Vadot return (EINVAL); 29444d027bbSEmmanuel Vadot 295986bbba9SKornel Duleba irq_type = daf->cells[1]; 296986bbba9SKornel Duleba if (irq_type != IRQ_TYPE_LEVEL_HIGH && 297986bbba9SKornel Duleba irq_type != IRQ_TYPE_EDGE_RISING) 298986bbba9SKornel Duleba return (EINVAL); 29944d027bbSEmmanuel Vadot 300986bbba9SKornel Duleba /* 301986bbba9SKornel Duleba * Allocate MSI vector. 302986bbba9SKornel Duleba * We don't use intr_alloc_msi wrapper, since it registers a new irq 303986bbba9SKornel Duleba * in the kernel. In our case irq was already added by the ofw code. 304986bbba9SKornel Duleba */ 305986bbba9SKornel Duleba ret = MSI_ALLOC_MSI(sc->parent, dev, 1, 1, NULL, isrcp); 306986bbba9SKornel Duleba if (ret != 0) 307986bbba9SKornel Duleba return (ret); 308986bbba9SKornel Duleba 309986bbba9SKornel Duleba ret = MSI_MAP_MSI(sc->parent, dev, *isrcp, &addr, &vector); 310986bbba9SKornel Duleba if (ret != 0) 311986bbba9SKornel Duleba goto fail; 312986bbba9SKornel Duleba 313986bbba9SKornel Duleba mv_cp110_icu_init(sc, addr); 314986bbba9SKornel Duleba vector |= ICU_INT_ENABLE; 315986bbba9SKornel Duleba 316986bbba9SKornel Duleba if (sc->type == ICU_TYPE_NSR) 317986bbba9SKornel Duleba vector |= ICU_GRP_NSR << ICU_INT_GROUP_SHIFT; 318986bbba9SKornel Duleba else 319986bbba9SKornel Duleba vector |= ICU_GRP_SEI << ICU_INT_GROUP_SHIFT; 320986bbba9SKornel Duleba 321986bbba9SKornel Duleba if (irq_type & IRQ_TYPE_EDGE_BOTH) 322986bbba9SKornel Duleba vector |= ICU_INT_EDGE; 323986bbba9SKornel Duleba 324986bbba9SKornel Duleba WR4(sc, ICU_INT_CFG(irq_no), vector); 325986bbba9SKornel Duleba 326986bbba9SKornel Duleba /* 327986bbba9SKornel Duleba * SATA controller has two ports, each gets its own interrupt. 328986bbba9SKornel Duleba * The problem is that only one irq is described in dts. 329986bbba9SKornel Duleba * Also ahci_generic driver supports only one irq per controller. 330986bbba9SKornel Duleba * As a workaround map both interrupts when one of them is allocated. 331986bbba9SKornel Duleba * This allows us to use both SATA ports. 332986bbba9SKornel Duleba */ 333986bbba9SKornel Duleba if (irq_no == ICU_INT_SATA0) 334986bbba9SKornel Duleba WR4(sc, ICU_INT_CFG(ICU_INT_SATA1), vector); 335986bbba9SKornel Duleba if (irq_no == ICU_INT_SATA1) 336986bbba9SKornel Duleba WR4(sc, ICU_INT_CFG(ICU_INT_SATA0), vector); 337986bbba9SKornel Duleba 3384b84206bSMichal Meloun (*isrcp)->isrc_dev = sc->dev; 3394b84206bSMichal Meloun return (ret); 340986bbba9SKornel Duleba 341986bbba9SKornel Duleba fail: 342986bbba9SKornel Duleba if (*isrcp != NULL) 343986bbba9SKornel Duleba MSI_RELEASE_MSI(sc->parent, dev, 1, isrcp); 344986bbba9SKornel Duleba 345986bbba9SKornel Duleba return (ret); 34644d027bbSEmmanuel Vadot } 34744d027bbSEmmanuel Vadot 34844d027bbSEmmanuel Vadot static int 34944d027bbSEmmanuel Vadot mv_cp110_icu_deactivate_intr(device_t dev, struct intr_irqsrc *isrc, 35044d027bbSEmmanuel Vadot struct resource *res, struct intr_map_data *data) 35144d027bbSEmmanuel Vadot { 35244d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc; 353986bbba9SKornel Duleba struct intr_map_data_fdt *daf; 354986bbba9SKornel Duleba int irq_no, ret; 355986bbba9SKornel Duleba 356986bbba9SKornel Duleba if (data->type != INTR_MAP_DATA_FDT) 357986bbba9SKornel Duleba return (ENOTSUP); 35844d027bbSEmmanuel Vadot 35944d027bbSEmmanuel Vadot sc = device_get_softc(dev); 360986bbba9SKornel Duleba daf = (struct intr_map_data_fdt *)data; 361986bbba9SKornel Duleba if (daf->ncells != 2) 362986bbba9SKornel Duleba return (EINVAL); 363986bbba9SKornel Duleba 364986bbba9SKornel Duleba irq_no = daf->cells[0]; 3654b84206bSMichal Meloun data = mv_cp110_icu_convert_map_data(sc, data); 3664b84206bSMichal Meloun if (data == NULL) 3674b84206bSMichal Meloun return (EINVAL); 36844d027bbSEmmanuel Vadot 369986bbba9SKornel Duleba /* Clear the mapping. */ 370986bbba9SKornel Duleba WR4(sc, ICU_INT_CFG(irq_no), 0); 371986bbba9SKornel Duleba 372986bbba9SKornel Duleba ret = PIC_DEACTIVATE_INTR(sc->parent, isrc, res, data); 373986bbba9SKornel Duleba if (ret != 0) 374986bbba9SKornel Duleba return (ret); 375986bbba9SKornel Duleba 376986bbba9SKornel Duleba return (MSI_RELEASE_MSI(sc->parent, dev, 1, &isrc)); 37744d027bbSEmmanuel Vadot } 37844d027bbSEmmanuel Vadot 37944d027bbSEmmanuel Vadot static int 38044d027bbSEmmanuel Vadot mv_cp110_icu_setup_intr(device_t dev, struct intr_irqsrc *isrc, 38144d027bbSEmmanuel Vadot struct resource *res, struct intr_map_data *data) 38244d027bbSEmmanuel Vadot { 38344d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc; 38444d027bbSEmmanuel Vadot 38544d027bbSEmmanuel Vadot sc = device_get_softc(dev); 3864b84206bSMichal Meloun data = mv_cp110_icu_convert_map_data(sc, data); 3874b84206bSMichal Meloun if (data == NULL) 3884b84206bSMichal Meloun return (EINVAL); 38944d027bbSEmmanuel Vadot 39044d027bbSEmmanuel Vadot return (PIC_SETUP_INTR(sc->parent, isrc, res, data)); 39144d027bbSEmmanuel Vadot } 39244d027bbSEmmanuel Vadot 39344d027bbSEmmanuel Vadot static int 39444d027bbSEmmanuel Vadot mv_cp110_icu_teardown_intr(device_t dev, struct intr_irqsrc *isrc, 39544d027bbSEmmanuel Vadot struct resource *res, struct intr_map_data *data) 39644d027bbSEmmanuel Vadot { 39744d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc; 39844d027bbSEmmanuel Vadot 39944d027bbSEmmanuel Vadot sc = device_get_softc(dev); 4004b84206bSMichal Meloun data = mv_cp110_icu_convert_map_data(sc, data); 4014b84206bSMichal Meloun if (data == NULL) 4024b84206bSMichal Meloun return (EINVAL); 40344d027bbSEmmanuel Vadot 40444d027bbSEmmanuel Vadot return (PIC_TEARDOWN_INTR(sc->parent, isrc, res, data)); 40544d027bbSEmmanuel Vadot } 40644d027bbSEmmanuel Vadot 40744d027bbSEmmanuel Vadot static void 40844d027bbSEmmanuel Vadot mv_cp110_icu_pre_ithread(device_t dev, struct intr_irqsrc *isrc) 40944d027bbSEmmanuel Vadot { 41044d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc; 41144d027bbSEmmanuel Vadot 41244d027bbSEmmanuel Vadot sc = device_get_softc(dev); 41344d027bbSEmmanuel Vadot 41444d027bbSEmmanuel Vadot PIC_PRE_ITHREAD(sc->parent, isrc); 41544d027bbSEmmanuel Vadot } 41644d027bbSEmmanuel Vadot 41744d027bbSEmmanuel Vadot static void 41844d027bbSEmmanuel Vadot mv_cp110_icu_post_ithread(device_t dev, struct intr_irqsrc *isrc) 41944d027bbSEmmanuel Vadot { 42044d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc; 42144d027bbSEmmanuel Vadot 42244d027bbSEmmanuel Vadot sc = device_get_softc(dev); 42344d027bbSEmmanuel Vadot 42444d027bbSEmmanuel Vadot PIC_POST_ITHREAD(sc->parent, isrc); 42544d027bbSEmmanuel Vadot } 42644d027bbSEmmanuel Vadot 42744d027bbSEmmanuel Vadot static void 42844d027bbSEmmanuel Vadot mv_cp110_icu_post_filter(device_t dev, struct intr_irqsrc *isrc) 42944d027bbSEmmanuel Vadot { 43044d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc; 43144d027bbSEmmanuel Vadot 43244d027bbSEmmanuel Vadot sc = device_get_softc(dev); 43344d027bbSEmmanuel Vadot 43444d027bbSEmmanuel Vadot PIC_POST_FILTER(sc->parent, isrc); 43544d027bbSEmmanuel Vadot } 43644d027bbSEmmanuel Vadot 43744d027bbSEmmanuel Vadot static device_method_t mv_cp110_icu_methods[] = { 43844d027bbSEmmanuel Vadot /* Device interface */ 43944d027bbSEmmanuel Vadot DEVMETHOD(device_probe, mv_cp110_icu_probe), 44044d027bbSEmmanuel Vadot DEVMETHOD(device_attach, mv_cp110_icu_attach), 44144d027bbSEmmanuel Vadot DEVMETHOD(device_detach, mv_cp110_icu_detach), 44244d027bbSEmmanuel Vadot 44344d027bbSEmmanuel Vadot /* Interrupt controller interface */ 44444d027bbSEmmanuel Vadot DEVMETHOD(pic_activate_intr, mv_cp110_icu_activate_intr), 44544d027bbSEmmanuel Vadot DEVMETHOD(pic_disable_intr, mv_cp110_icu_disable_intr), 44644d027bbSEmmanuel Vadot DEVMETHOD(pic_enable_intr, mv_cp110_icu_enable_intr), 44744d027bbSEmmanuel Vadot DEVMETHOD(pic_map_intr, mv_cp110_icu_map_intr), 44844d027bbSEmmanuel Vadot DEVMETHOD(pic_deactivate_intr, mv_cp110_icu_deactivate_intr), 44944d027bbSEmmanuel Vadot DEVMETHOD(pic_setup_intr, mv_cp110_icu_setup_intr), 45044d027bbSEmmanuel Vadot DEVMETHOD(pic_teardown_intr, mv_cp110_icu_teardown_intr), 45144d027bbSEmmanuel Vadot DEVMETHOD(pic_post_filter, mv_cp110_icu_post_filter), 45244d027bbSEmmanuel Vadot DEVMETHOD(pic_post_ithread, mv_cp110_icu_post_ithread), 45344d027bbSEmmanuel Vadot DEVMETHOD(pic_pre_ithread, mv_cp110_icu_pre_ithread), 45444d027bbSEmmanuel Vadot 45544d027bbSEmmanuel Vadot DEVMETHOD_END 45644d027bbSEmmanuel Vadot }; 45744d027bbSEmmanuel Vadot 45844d027bbSEmmanuel Vadot static driver_t mv_cp110_icu_driver = { 45944d027bbSEmmanuel Vadot "mv_cp110_icu", 46044d027bbSEmmanuel Vadot mv_cp110_icu_methods, 46144d027bbSEmmanuel Vadot sizeof(struct mv_cp110_icu_softc), 46244d027bbSEmmanuel Vadot }; 46344d027bbSEmmanuel Vadot 464*a3b866cbSJohn Baldwin EARLY_DRIVER_MODULE(mv_cp110_icu, mv_cp110_icu_bus, mv_cp110_icu_driver, 0, 0, 465*a3b866cbSJohn Baldwin BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST); 466