144d027bbSEmmanuel Vadot /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
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
2844d027bbSEmmanuel Vadot #include <sys/param.h>
2944d027bbSEmmanuel Vadot #include <sys/systm.h>
3044d027bbSEmmanuel Vadot #include <sys/bus.h>
3144d027bbSEmmanuel Vadot
3244d027bbSEmmanuel Vadot #include <sys/kernel.h>
3344d027bbSEmmanuel Vadot #include <sys/module.h>
3444d027bbSEmmanuel Vadot #include <sys/rman.h>
3544d027bbSEmmanuel Vadot #include <sys/lock.h>
3644d027bbSEmmanuel Vadot #include <sys/mutex.h>
3744d027bbSEmmanuel Vadot
3844d027bbSEmmanuel Vadot #include <machine/bus.h>
3944d027bbSEmmanuel Vadot #include <machine/resource.h>
4044d027bbSEmmanuel Vadot #include <machine/intr.h>
4144d027bbSEmmanuel Vadot
4244d027bbSEmmanuel Vadot #include <dev/fdt/simplebus.h>
4344d027bbSEmmanuel Vadot
4444d027bbSEmmanuel Vadot #include <dev/ofw/ofw_bus.h>
4544d027bbSEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h>
4644d027bbSEmmanuel Vadot
478a7a4683SEmmanuel Vadot #include <dt-bindings/interrupt-controller/irq.h>
48986bbba9SKornel Duleba
4944d027bbSEmmanuel Vadot #include "pic_if.h"
50986bbba9SKornel Duleba #include "msi_if.h"
51986bbba9SKornel Duleba
52986bbba9SKornel Duleba #define ICU_TYPE_NSR 1
53986bbba9SKornel Duleba #define ICU_TYPE_SEI 2
5444d027bbSEmmanuel Vadot
5544d027bbSEmmanuel Vadot #define ICU_GRP_NSR 0x0
5644d027bbSEmmanuel Vadot #define ICU_GRP_SR 0x1
5744d027bbSEmmanuel Vadot #define ICU_GRP_SEI 0x4
5844d027bbSEmmanuel Vadot #define ICU_GRP_REI 0x5
5944d027bbSEmmanuel Vadot
6044d027bbSEmmanuel Vadot #define ICU_SETSPI_NSR_AL 0x10
6144d027bbSEmmanuel Vadot #define ICU_SETSPI_NSR_AH 0x14
6244d027bbSEmmanuel Vadot #define ICU_CLRSPI_NSR_AL 0x18
6344d027bbSEmmanuel Vadot #define ICU_CLRSPI_NSR_AH 0x1c
64986bbba9SKornel Duleba #define ICU_SETSPI_SEI_AL 0x50
65986bbba9SKornel Duleba #define ICU_SETSPI_SEI_AH 0x54
6644d027bbSEmmanuel Vadot #define ICU_INT_CFG(x) (0x100 + (x) * 4)
6744d027bbSEmmanuel Vadot #define ICU_INT_ENABLE (1 << 24)
6844d027bbSEmmanuel Vadot #define ICU_INT_EDGE (1 << 28)
6944d027bbSEmmanuel Vadot #define ICU_INT_GROUP_SHIFT 29
7044d027bbSEmmanuel Vadot #define ICU_INT_MASK 0x3ff
7144d027bbSEmmanuel Vadot
72986bbba9SKornel Duleba #define ICU_INT_SATA0 109
73986bbba9SKornel Duleba #define ICU_INT_SATA1 107
74986bbba9SKornel Duleba
7544d027bbSEmmanuel Vadot #define MV_CP110_ICU_MAX_NIRQS 207
7644d027bbSEmmanuel Vadot
77986bbba9SKornel Duleba #define MV_CP110_ICU_CLRSPI_OFFSET 0x8
78986bbba9SKornel Duleba
7944d027bbSEmmanuel Vadot struct mv_cp110_icu_softc {
8044d027bbSEmmanuel Vadot device_t dev;
8144d027bbSEmmanuel Vadot device_t parent;
8244d027bbSEmmanuel Vadot struct resource *res;
834b84206bSMichal Meloun struct intr_map_data_fdt *parent_map_data;
84986bbba9SKornel Duleba bool initialized;
85986bbba9SKornel Duleba int type;
8644d027bbSEmmanuel Vadot };
8744d027bbSEmmanuel Vadot
8844d027bbSEmmanuel Vadot static struct resource_spec mv_cp110_icu_res_spec[] = {
8944d027bbSEmmanuel Vadot { SYS_RES_MEMORY, 0, RF_ACTIVE | RF_SHAREABLE },
9044d027bbSEmmanuel Vadot { -1, 0 }
9144d027bbSEmmanuel Vadot };
9244d027bbSEmmanuel Vadot
9344d027bbSEmmanuel Vadot static struct ofw_compat_data compat_data[] = {
94986bbba9SKornel Duleba {"marvell,cp110-icu-nsr", ICU_TYPE_NSR},
95986bbba9SKornel Duleba {"marvell,cp110-icu-sei", ICU_TYPE_SEI},
9644d027bbSEmmanuel Vadot {NULL, 0}
9744d027bbSEmmanuel Vadot };
9844d027bbSEmmanuel Vadot
9944d027bbSEmmanuel Vadot #define RD4(sc, reg) bus_read_4((sc)->res, (reg))
10044d027bbSEmmanuel Vadot #define WR4(sc, reg, val) bus_write_4((sc)->res, (reg), (val))
10144d027bbSEmmanuel Vadot
10244d027bbSEmmanuel Vadot static int
mv_cp110_icu_probe(device_t dev)10344d027bbSEmmanuel Vadot mv_cp110_icu_probe(device_t dev)
10444d027bbSEmmanuel Vadot {
10544d027bbSEmmanuel Vadot
10644d027bbSEmmanuel Vadot if (!ofw_bus_status_okay(dev))
10744d027bbSEmmanuel Vadot return (ENXIO);
10844d027bbSEmmanuel Vadot
10944d027bbSEmmanuel Vadot if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
11044d027bbSEmmanuel Vadot return (ENXIO);
11144d027bbSEmmanuel Vadot
11244d027bbSEmmanuel Vadot device_set_desc(dev, "Marvell Interrupt Consolidation Unit");
11344d027bbSEmmanuel Vadot return (BUS_PROBE_DEFAULT);
11444d027bbSEmmanuel Vadot }
11544d027bbSEmmanuel Vadot
11644d027bbSEmmanuel Vadot static int
mv_cp110_icu_attach(device_t dev)11744d027bbSEmmanuel Vadot mv_cp110_icu_attach(device_t dev)
11844d027bbSEmmanuel Vadot {
11944d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc;
12044d027bbSEmmanuel Vadot phandle_t node, msi_parent;
121986bbba9SKornel Duleba uint32_t reg, icu_grp;
122986bbba9SKornel Duleba int i;
12344d027bbSEmmanuel Vadot
12444d027bbSEmmanuel Vadot sc = device_get_softc(dev);
12544d027bbSEmmanuel Vadot sc->dev = dev;
12644d027bbSEmmanuel Vadot node = ofw_bus_get_node(dev);
127986bbba9SKornel Duleba sc->type = (int)ofw_bus_search_compatible(dev, compat_data)->ocd_data;
128986bbba9SKornel Duleba sc->initialized = false;
12944d027bbSEmmanuel Vadot
13044d027bbSEmmanuel Vadot if (OF_getencprop(node, "msi-parent", &msi_parent,
13144d027bbSEmmanuel Vadot sizeof(phandle_t)) <= 0) {
13244d027bbSEmmanuel Vadot device_printf(dev, "cannot find msi-parent property\n");
13344d027bbSEmmanuel Vadot return (ENXIO);
13444d027bbSEmmanuel Vadot }
13544d027bbSEmmanuel Vadot
13644d027bbSEmmanuel Vadot if ((sc->parent = OF_device_from_xref(msi_parent)) == NULL) {
13744d027bbSEmmanuel Vadot device_printf(dev, "cannot find msi-parent device\n");
13844d027bbSEmmanuel Vadot return (ENXIO);
13944d027bbSEmmanuel Vadot }
14044d027bbSEmmanuel Vadot if (bus_alloc_resources(dev, mv_cp110_icu_res_spec, &sc->res) != 0) {
14144d027bbSEmmanuel Vadot device_printf(dev, "cannot allocate resources for device\n");
14244d027bbSEmmanuel Vadot return (ENXIO);
14344d027bbSEmmanuel Vadot }
14444d027bbSEmmanuel Vadot
14544d027bbSEmmanuel Vadot if (intr_pic_register(dev, OF_xref_from_node(node)) == NULL) {
14644d027bbSEmmanuel Vadot device_printf(dev, "Cannot register ICU\n");
14744d027bbSEmmanuel Vadot goto fail;
14844d027bbSEmmanuel Vadot }
1494b84206bSMichal Meloun
150986bbba9SKornel Duleba /* Allocate GICP/SEI compatible mapping entry (2 cells) */
1514b84206bSMichal Meloun sc->parent_map_data = (struct intr_map_data_fdt *)intr_alloc_map_data(
1524b84206bSMichal Meloun INTR_MAP_DATA_FDT, sizeof(struct intr_map_data_fdt) +
1534b84206bSMichal Meloun + 3 * sizeof(phandle_t), M_WAITOK | M_ZERO);
154986bbba9SKornel Duleba
155986bbba9SKornel Duleba /* Clear any previous mapping done by firmware. */
156986bbba9SKornel Duleba for (i = 0; i < MV_CP110_ICU_MAX_NIRQS; i++) {
157986bbba9SKornel Duleba reg = RD4(sc, ICU_INT_CFG(i));
158986bbba9SKornel Duleba icu_grp = reg >> ICU_INT_GROUP_SHIFT;
159986bbba9SKornel Duleba
160986bbba9SKornel Duleba if (icu_grp == ICU_GRP_NSR || icu_grp == ICU_GRP_SEI)
161986bbba9SKornel Duleba WR4(sc, ICU_INT_CFG(i), 0);
162986bbba9SKornel Duleba }
163986bbba9SKornel Duleba
16444d027bbSEmmanuel Vadot return (0);
16544d027bbSEmmanuel Vadot
16644d027bbSEmmanuel Vadot fail:
16744d027bbSEmmanuel Vadot bus_release_resources(dev, mv_cp110_icu_res_spec, &sc->res);
16844d027bbSEmmanuel Vadot return (ENXIO);
16944d027bbSEmmanuel Vadot }
17044d027bbSEmmanuel Vadot
1714b84206bSMichal Meloun static struct intr_map_data *
mv_cp110_icu_convert_map_data(struct mv_cp110_icu_softc * sc,struct intr_map_data * data)1724b84206bSMichal Meloun mv_cp110_icu_convert_map_data(struct mv_cp110_icu_softc *sc, struct intr_map_data *data)
1734b84206bSMichal Meloun {
1744b84206bSMichal Meloun struct intr_map_data_fdt *daf;
1754b84206bSMichal Meloun uint32_t reg, irq_no, irq_type;
1764b84206bSMichal Meloun
1774b84206bSMichal Meloun daf = (struct intr_map_data_fdt *)data;
1784b84206bSMichal Meloun if (daf->ncells != 2)
1794b84206bSMichal Meloun return (NULL);
180986bbba9SKornel Duleba
1814b84206bSMichal Meloun irq_no = daf->cells[0];
1824b84206bSMichal Meloun if (irq_no >= MV_CP110_ICU_MAX_NIRQS)
1834b84206bSMichal Meloun return (NULL);
184986bbba9SKornel Duleba
185986bbba9SKornel Duleba irq_type = daf->cells[1];
1864b84206bSMichal Meloun if (irq_type != IRQ_TYPE_LEVEL_HIGH &&
1874b84206bSMichal Meloun irq_type != IRQ_TYPE_EDGE_RISING)
1884b84206bSMichal Meloun return (NULL);
1894b84206bSMichal Meloun
190986bbba9SKornel Duleba /* ICU -> GICP/SEI mapping is set in mv_cp110_icu_map_intr. */
1914b84206bSMichal Meloun reg = RD4(sc, ICU_INT_CFG(irq_no));
1924b84206bSMichal Meloun
1934b84206bSMichal Meloun /* Construct GICP compatible mapping. */
1944b84206bSMichal Meloun sc->parent_map_data->ncells = 2;
1954b84206bSMichal Meloun sc->parent_map_data->cells[0] = reg & ICU_INT_MASK;
1964b84206bSMichal Meloun sc->parent_map_data->cells[1] = irq_type;
1974b84206bSMichal Meloun
1984b84206bSMichal Meloun return ((struct intr_map_data *)sc->parent_map_data);
1994b84206bSMichal Meloun }
2004b84206bSMichal Meloun
20144d027bbSEmmanuel Vadot static int
mv_cp110_icu_detach(device_t dev)20244d027bbSEmmanuel Vadot mv_cp110_icu_detach(device_t dev)
20344d027bbSEmmanuel Vadot {
20444d027bbSEmmanuel Vadot
20544d027bbSEmmanuel Vadot return (EBUSY);
20644d027bbSEmmanuel Vadot }
20744d027bbSEmmanuel Vadot
20844d027bbSEmmanuel Vadot static int
mv_cp110_icu_activate_intr(device_t dev,struct intr_irqsrc * isrc,struct resource * res,struct intr_map_data * data)20944d027bbSEmmanuel Vadot mv_cp110_icu_activate_intr(device_t dev, struct intr_irqsrc *isrc,
21044d027bbSEmmanuel Vadot struct resource *res, struct intr_map_data *data)
21144d027bbSEmmanuel Vadot {
21244d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc;
21344d027bbSEmmanuel Vadot
21444d027bbSEmmanuel Vadot sc = device_get_softc(dev);
2154b84206bSMichal Meloun data = mv_cp110_icu_convert_map_data(sc, data);
2164b84206bSMichal Meloun if (data == NULL)
2174b84206bSMichal Meloun return (EINVAL);
21844d027bbSEmmanuel Vadot return (PIC_ACTIVATE_INTR(sc->parent, isrc, res, data));
21944d027bbSEmmanuel Vadot }
22044d027bbSEmmanuel Vadot
22144d027bbSEmmanuel Vadot static void
mv_cp110_icu_enable_intr(device_t dev,struct intr_irqsrc * isrc)22244d027bbSEmmanuel Vadot mv_cp110_icu_enable_intr(device_t dev, struct intr_irqsrc *isrc)
22344d027bbSEmmanuel Vadot {
22444d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc;
22544d027bbSEmmanuel Vadot sc = device_get_softc(dev);
22644d027bbSEmmanuel Vadot
22744d027bbSEmmanuel Vadot PIC_ENABLE_INTR(sc->parent, isrc);
22844d027bbSEmmanuel Vadot }
22944d027bbSEmmanuel Vadot
23044d027bbSEmmanuel Vadot static void
mv_cp110_icu_disable_intr(device_t dev,struct intr_irqsrc * isrc)23144d027bbSEmmanuel Vadot mv_cp110_icu_disable_intr(device_t dev, struct intr_irqsrc *isrc)
23244d027bbSEmmanuel Vadot {
23344d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc;
23444d027bbSEmmanuel Vadot
23544d027bbSEmmanuel Vadot sc = device_get_softc(dev);
23644d027bbSEmmanuel Vadot
23744d027bbSEmmanuel Vadot PIC_DISABLE_INTR(sc->parent, isrc);
23844d027bbSEmmanuel Vadot }
23944d027bbSEmmanuel Vadot
240986bbba9SKornel Duleba static void
mv_cp110_icu_init(struct mv_cp110_icu_softc * sc,uint64_t addr)241986bbba9SKornel Duleba mv_cp110_icu_init(struct mv_cp110_icu_softc *sc, uint64_t addr)
242986bbba9SKornel Duleba {
243986bbba9SKornel Duleba
244986bbba9SKornel Duleba if (sc->initialized)
245986bbba9SKornel Duleba return;
246986bbba9SKornel Duleba
247986bbba9SKornel Duleba switch (sc->type) {
248986bbba9SKornel Duleba case ICU_TYPE_NSR:
249986bbba9SKornel Duleba WR4(sc, ICU_SETSPI_NSR_AL, addr & UINT32_MAX);
250986bbba9SKornel Duleba WR4(sc, ICU_SETSPI_NSR_AH, (addr >> 32) & UINT32_MAX);
251986bbba9SKornel Duleba addr += MV_CP110_ICU_CLRSPI_OFFSET;
252986bbba9SKornel Duleba WR4(sc, ICU_CLRSPI_NSR_AL, addr & UINT32_MAX);
253986bbba9SKornel Duleba WR4(sc, ICU_CLRSPI_NSR_AH, (addr >> 32) & UINT32_MAX);
254986bbba9SKornel Duleba break;
255986bbba9SKornel Duleba case ICU_TYPE_SEI:
256986bbba9SKornel Duleba WR4(sc, ICU_SETSPI_SEI_AL, addr & UINT32_MAX);
257986bbba9SKornel Duleba WR4(sc, ICU_SETSPI_SEI_AH, (addr >> 32) & UINT32_MAX);
258986bbba9SKornel Duleba break;
259986bbba9SKornel Duleba default:
260986bbba9SKornel Duleba panic("Unkown ICU type.");
261986bbba9SKornel Duleba }
262986bbba9SKornel Duleba
263986bbba9SKornel Duleba sc->initialized = true;
264986bbba9SKornel Duleba }
265986bbba9SKornel Duleba
26644d027bbSEmmanuel Vadot static int
mv_cp110_icu_map_intr(device_t dev,struct intr_map_data * data,struct intr_irqsrc ** isrcp)26744d027bbSEmmanuel Vadot mv_cp110_icu_map_intr(device_t dev, struct intr_map_data *data,
26844d027bbSEmmanuel Vadot struct intr_irqsrc **isrcp)
26944d027bbSEmmanuel Vadot {
27044d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc;
27144d027bbSEmmanuel Vadot struct intr_map_data_fdt *daf;
272986bbba9SKornel Duleba uint32_t vector, irq_no, irq_type;
273986bbba9SKornel Duleba uint64_t addr;
2744b84206bSMichal Meloun int ret;
27544d027bbSEmmanuel Vadot
27644d027bbSEmmanuel Vadot sc = device_get_softc(dev);
27744d027bbSEmmanuel Vadot
27844d027bbSEmmanuel Vadot if (data->type != INTR_MAP_DATA_FDT)
27944d027bbSEmmanuel Vadot return (ENOTSUP);
28044d027bbSEmmanuel Vadot
2814b84206bSMichal Meloun /* Parse original */
28244d027bbSEmmanuel Vadot daf = (struct intr_map_data_fdt *)data;
2834b84206bSMichal Meloun if (daf->ncells != 2)
2844b84206bSMichal Meloun return (EINVAL);
285986bbba9SKornel Duleba
2864b84206bSMichal Meloun irq_no = daf->cells[0];
287986bbba9SKornel Duleba if (irq_no >= MV_CP110_ICU_MAX_NIRQS)
28844d027bbSEmmanuel Vadot return (EINVAL);
28944d027bbSEmmanuel Vadot
290986bbba9SKornel Duleba irq_type = daf->cells[1];
291986bbba9SKornel Duleba if (irq_type != IRQ_TYPE_LEVEL_HIGH &&
292986bbba9SKornel Duleba irq_type != IRQ_TYPE_EDGE_RISING)
293986bbba9SKornel Duleba return (EINVAL);
29444d027bbSEmmanuel Vadot
295986bbba9SKornel Duleba /*
296986bbba9SKornel Duleba * Allocate MSI vector.
297986bbba9SKornel Duleba * We don't use intr_alloc_msi wrapper, since it registers a new irq
298986bbba9SKornel Duleba * in the kernel. In our case irq was already added by the ofw code.
299986bbba9SKornel Duleba */
300986bbba9SKornel Duleba ret = MSI_ALLOC_MSI(sc->parent, dev, 1, 1, NULL, isrcp);
301986bbba9SKornel Duleba if (ret != 0)
302986bbba9SKornel Duleba return (ret);
303986bbba9SKornel Duleba
304986bbba9SKornel Duleba ret = MSI_MAP_MSI(sc->parent, dev, *isrcp, &addr, &vector);
305986bbba9SKornel Duleba if (ret != 0)
306986bbba9SKornel Duleba goto fail;
307986bbba9SKornel Duleba
308986bbba9SKornel Duleba mv_cp110_icu_init(sc, addr);
309986bbba9SKornel Duleba vector |= ICU_INT_ENABLE;
310986bbba9SKornel Duleba
311986bbba9SKornel Duleba if (sc->type == ICU_TYPE_NSR)
312986bbba9SKornel Duleba vector |= ICU_GRP_NSR << ICU_INT_GROUP_SHIFT;
313986bbba9SKornel Duleba else
314986bbba9SKornel Duleba vector |= ICU_GRP_SEI << ICU_INT_GROUP_SHIFT;
315986bbba9SKornel Duleba
316986bbba9SKornel Duleba if (irq_type & IRQ_TYPE_EDGE_BOTH)
317986bbba9SKornel Duleba vector |= ICU_INT_EDGE;
318986bbba9SKornel Duleba
319986bbba9SKornel Duleba WR4(sc, ICU_INT_CFG(irq_no), vector);
320986bbba9SKornel Duleba
321986bbba9SKornel Duleba /*
322986bbba9SKornel Duleba * SATA controller has two ports, each gets its own interrupt.
323986bbba9SKornel Duleba * The problem is that only one irq is described in dts.
324986bbba9SKornel Duleba * Also ahci_generic driver supports only one irq per controller.
325986bbba9SKornel Duleba * As a workaround map both interrupts when one of them is allocated.
326986bbba9SKornel Duleba * This allows us to use both SATA ports.
327986bbba9SKornel Duleba */
328986bbba9SKornel Duleba if (irq_no == ICU_INT_SATA0)
329986bbba9SKornel Duleba WR4(sc, ICU_INT_CFG(ICU_INT_SATA1), vector);
330986bbba9SKornel Duleba if (irq_no == ICU_INT_SATA1)
331986bbba9SKornel Duleba WR4(sc, ICU_INT_CFG(ICU_INT_SATA0), vector);
332986bbba9SKornel Duleba
3334b84206bSMichal Meloun (*isrcp)->isrc_dev = sc->dev;
3344b84206bSMichal Meloun return (ret);
335986bbba9SKornel Duleba
336986bbba9SKornel Duleba fail:
337986bbba9SKornel Duleba if (*isrcp != NULL)
338986bbba9SKornel Duleba MSI_RELEASE_MSI(sc->parent, dev, 1, isrcp);
339986bbba9SKornel Duleba
340986bbba9SKornel Duleba return (ret);
34144d027bbSEmmanuel Vadot }
34244d027bbSEmmanuel Vadot
34344d027bbSEmmanuel Vadot static int
mv_cp110_icu_deactivate_intr(device_t dev,struct intr_irqsrc * isrc,struct resource * res,struct intr_map_data * data)34444d027bbSEmmanuel Vadot mv_cp110_icu_deactivate_intr(device_t dev, struct intr_irqsrc *isrc,
34544d027bbSEmmanuel Vadot struct resource *res, struct intr_map_data *data)
34644d027bbSEmmanuel Vadot {
34744d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc;
348986bbba9SKornel Duleba struct intr_map_data_fdt *daf;
349986bbba9SKornel Duleba int irq_no, ret;
350986bbba9SKornel Duleba
351986bbba9SKornel Duleba if (data->type != INTR_MAP_DATA_FDT)
352986bbba9SKornel Duleba return (ENOTSUP);
35344d027bbSEmmanuel Vadot
35444d027bbSEmmanuel Vadot sc = device_get_softc(dev);
355986bbba9SKornel Duleba daf = (struct intr_map_data_fdt *)data;
356986bbba9SKornel Duleba if (daf->ncells != 2)
357986bbba9SKornel Duleba return (EINVAL);
358986bbba9SKornel Duleba
359986bbba9SKornel Duleba irq_no = daf->cells[0];
3604b84206bSMichal Meloun data = mv_cp110_icu_convert_map_data(sc, data);
3614b84206bSMichal Meloun if (data == NULL)
3624b84206bSMichal Meloun return (EINVAL);
36344d027bbSEmmanuel Vadot
364986bbba9SKornel Duleba /* Clear the mapping. */
365986bbba9SKornel Duleba WR4(sc, ICU_INT_CFG(irq_no), 0);
366986bbba9SKornel Duleba
367986bbba9SKornel Duleba ret = PIC_DEACTIVATE_INTR(sc->parent, isrc, res, data);
368986bbba9SKornel Duleba if (ret != 0)
369986bbba9SKornel Duleba return (ret);
370986bbba9SKornel Duleba
371986bbba9SKornel Duleba return (MSI_RELEASE_MSI(sc->parent, dev, 1, &isrc));
37244d027bbSEmmanuel Vadot }
37344d027bbSEmmanuel Vadot
37444d027bbSEmmanuel Vadot static int
mv_cp110_icu_setup_intr(device_t dev,struct intr_irqsrc * isrc,struct resource * res,struct intr_map_data * data)37544d027bbSEmmanuel Vadot mv_cp110_icu_setup_intr(device_t dev, struct intr_irqsrc *isrc,
37644d027bbSEmmanuel Vadot struct resource *res, struct intr_map_data *data)
37744d027bbSEmmanuel Vadot {
37844d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc;
37944d027bbSEmmanuel Vadot
38044d027bbSEmmanuel Vadot sc = device_get_softc(dev);
3814b84206bSMichal Meloun data = mv_cp110_icu_convert_map_data(sc, data);
3824b84206bSMichal Meloun if (data == NULL)
3834b84206bSMichal Meloun return (EINVAL);
38444d027bbSEmmanuel Vadot
38544d027bbSEmmanuel Vadot return (PIC_SETUP_INTR(sc->parent, isrc, res, data));
38644d027bbSEmmanuel Vadot }
38744d027bbSEmmanuel Vadot
38844d027bbSEmmanuel Vadot static int
mv_cp110_icu_teardown_intr(device_t dev,struct intr_irqsrc * isrc,struct resource * res,struct intr_map_data * data)38944d027bbSEmmanuel Vadot mv_cp110_icu_teardown_intr(device_t dev, struct intr_irqsrc *isrc,
39044d027bbSEmmanuel Vadot struct resource *res, struct intr_map_data *data)
39144d027bbSEmmanuel Vadot {
39244d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc;
39344d027bbSEmmanuel Vadot
39444d027bbSEmmanuel Vadot sc = device_get_softc(dev);
3954b84206bSMichal Meloun data = mv_cp110_icu_convert_map_data(sc, data);
3964b84206bSMichal Meloun if (data == NULL)
3974b84206bSMichal Meloun return (EINVAL);
39844d027bbSEmmanuel Vadot
39944d027bbSEmmanuel Vadot return (PIC_TEARDOWN_INTR(sc->parent, isrc, res, data));
40044d027bbSEmmanuel Vadot }
40144d027bbSEmmanuel Vadot
40244d027bbSEmmanuel Vadot static void
mv_cp110_icu_pre_ithread(device_t dev,struct intr_irqsrc * isrc)40344d027bbSEmmanuel Vadot mv_cp110_icu_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
40444d027bbSEmmanuel Vadot {
40544d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc;
40644d027bbSEmmanuel Vadot
40744d027bbSEmmanuel Vadot sc = device_get_softc(dev);
40844d027bbSEmmanuel Vadot
40944d027bbSEmmanuel Vadot PIC_PRE_ITHREAD(sc->parent, isrc);
41044d027bbSEmmanuel Vadot }
41144d027bbSEmmanuel Vadot
41244d027bbSEmmanuel Vadot static void
mv_cp110_icu_post_ithread(device_t dev,struct intr_irqsrc * isrc)41344d027bbSEmmanuel Vadot mv_cp110_icu_post_ithread(device_t dev, struct intr_irqsrc *isrc)
41444d027bbSEmmanuel Vadot {
41544d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc;
41644d027bbSEmmanuel Vadot
41744d027bbSEmmanuel Vadot sc = device_get_softc(dev);
41844d027bbSEmmanuel Vadot
41944d027bbSEmmanuel Vadot PIC_POST_ITHREAD(sc->parent, isrc);
42044d027bbSEmmanuel Vadot }
42144d027bbSEmmanuel Vadot
42244d027bbSEmmanuel Vadot static void
mv_cp110_icu_post_filter(device_t dev,struct intr_irqsrc * isrc)42344d027bbSEmmanuel Vadot mv_cp110_icu_post_filter(device_t dev, struct intr_irqsrc *isrc)
42444d027bbSEmmanuel Vadot {
42544d027bbSEmmanuel Vadot struct mv_cp110_icu_softc *sc;
42644d027bbSEmmanuel Vadot
42744d027bbSEmmanuel Vadot sc = device_get_softc(dev);
42844d027bbSEmmanuel Vadot
42944d027bbSEmmanuel Vadot PIC_POST_FILTER(sc->parent, isrc);
43044d027bbSEmmanuel Vadot }
43144d027bbSEmmanuel Vadot
43244d027bbSEmmanuel Vadot static device_method_t mv_cp110_icu_methods[] = {
43344d027bbSEmmanuel Vadot /* Device interface */
43444d027bbSEmmanuel Vadot DEVMETHOD(device_probe, mv_cp110_icu_probe),
43544d027bbSEmmanuel Vadot DEVMETHOD(device_attach, mv_cp110_icu_attach),
43644d027bbSEmmanuel Vadot DEVMETHOD(device_detach, mv_cp110_icu_detach),
43744d027bbSEmmanuel Vadot
43844d027bbSEmmanuel Vadot /* Interrupt controller interface */
43944d027bbSEmmanuel Vadot DEVMETHOD(pic_activate_intr, mv_cp110_icu_activate_intr),
44044d027bbSEmmanuel Vadot DEVMETHOD(pic_disable_intr, mv_cp110_icu_disable_intr),
44144d027bbSEmmanuel Vadot DEVMETHOD(pic_enable_intr, mv_cp110_icu_enable_intr),
44244d027bbSEmmanuel Vadot DEVMETHOD(pic_map_intr, mv_cp110_icu_map_intr),
44344d027bbSEmmanuel Vadot DEVMETHOD(pic_deactivate_intr, mv_cp110_icu_deactivate_intr),
44444d027bbSEmmanuel Vadot DEVMETHOD(pic_setup_intr, mv_cp110_icu_setup_intr),
44544d027bbSEmmanuel Vadot DEVMETHOD(pic_teardown_intr, mv_cp110_icu_teardown_intr),
44644d027bbSEmmanuel Vadot DEVMETHOD(pic_post_filter, mv_cp110_icu_post_filter),
44744d027bbSEmmanuel Vadot DEVMETHOD(pic_post_ithread, mv_cp110_icu_post_ithread),
44844d027bbSEmmanuel Vadot DEVMETHOD(pic_pre_ithread, mv_cp110_icu_pre_ithread),
44944d027bbSEmmanuel Vadot
45044d027bbSEmmanuel Vadot DEVMETHOD_END
45144d027bbSEmmanuel Vadot };
45244d027bbSEmmanuel Vadot
45344d027bbSEmmanuel Vadot static driver_t mv_cp110_icu_driver = {
45444d027bbSEmmanuel Vadot "mv_cp110_icu",
45544d027bbSEmmanuel Vadot mv_cp110_icu_methods,
45644d027bbSEmmanuel Vadot sizeof(struct mv_cp110_icu_softc),
45744d027bbSEmmanuel Vadot };
45844d027bbSEmmanuel Vadot
459a3b866cbSJohn Baldwin EARLY_DRIVER_MODULE(mv_cp110_icu, mv_cp110_icu_bus, mv_cp110_icu_driver, 0, 0,
460a3b866cbSJohn Baldwin BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST);
461