xref: /freebsd/sys/arm/mv/mpic.c (revision 244af1d4db0f7b9f2dc3068228ca3ef5278b9ad4)
116694521SOleksandr Tymoshenko /*-
2af3dc4a7SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3af3dc4a7SPedro F. Giffuni  *
416694521SOleksandr Tymoshenko  * Copyright (c) 2006 Benno Rice.
516694521SOleksandr Tymoshenko  * Copyright (C) 2007-2011 MARVELL INTERNATIONAL LTD.
6aa0ea9d0SGrzegorz Bernacki  * Copyright (c) 2012 Semihalf.
716694521SOleksandr Tymoshenko  * All rights reserved.
816694521SOleksandr Tymoshenko  *
916694521SOleksandr Tymoshenko  * Developed by Semihalf.
1016694521SOleksandr Tymoshenko  *
1116694521SOleksandr Tymoshenko  * Redistribution and use in source and binary forms, with or without
1216694521SOleksandr Tymoshenko  * modification, are permitted provided that the following conditions
1316694521SOleksandr Tymoshenko  * are met:
1416694521SOleksandr Tymoshenko  * 1. Redistributions of source code must retain the above copyright
1516694521SOleksandr Tymoshenko  *    notice, this list of conditions and the following disclaimer.
1616694521SOleksandr Tymoshenko  * 2. Redistributions in binary form must reproduce the above copyright
1716694521SOleksandr Tymoshenko  *    notice, this list of conditions and the following disclaimer in the
1816694521SOleksandr Tymoshenko  *    documentation and/or other materials provided with the distribution.
1916694521SOleksandr Tymoshenko  *
2016694521SOleksandr Tymoshenko  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2116694521SOleksandr Tymoshenko  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2216694521SOleksandr Tymoshenko  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2316694521SOleksandr Tymoshenko  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2416694521SOleksandr Tymoshenko  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2516694521SOleksandr Tymoshenko  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2616694521SOleksandr Tymoshenko  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2716694521SOleksandr Tymoshenko  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2816694521SOleksandr Tymoshenko  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2916694521SOleksandr Tymoshenko  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3016694521SOleksandr Tymoshenko  *
3116694521SOleksandr Tymoshenko  * from: FreeBSD: //depot/projects/arm/src/sys/arm/xscale/pxa2x0/pxa2x0_icu.c, rev 1
3216694521SOleksandr Tymoshenko  * from: FreeBSD: src/sys/arm/mv/ic.c,v 1.5 2011/02/08 01:49:30
3316694521SOleksandr Tymoshenko  */
3416694521SOleksandr Tymoshenko 
3516694521SOleksandr Tymoshenko #include <sys/cdefs.h>
3616694521SOleksandr Tymoshenko __FBSDID("$FreeBSD$");
3716694521SOleksandr Tymoshenko 
38ca8e2078SWojciech Macek #include "opt_platform.h"
39ca8e2078SWojciech Macek 
4016694521SOleksandr Tymoshenko #include <sys/param.h>
4116694521SOleksandr Tymoshenko #include <sys/systm.h>
4216694521SOleksandr Tymoshenko #include <sys/bus.h>
4316694521SOleksandr Tymoshenko #include <sys/kernel.h>
4416694521SOleksandr Tymoshenko #include <sys/cpuset.h>
4516694521SOleksandr Tymoshenko #include <sys/ktr.h>
46ca8e2078SWojciech Macek #include <sys/kdb.h>
4716694521SOleksandr Tymoshenko #include <sys/module.h>
48ca8e2078SWojciech Macek #include <sys/lock.h>
49ca8e2078SWojciech Macek #include <sys/mutex.h>
5016694521SOleksandr Tymoshenko #include <sys/rman.h>
51ca8e2078SWojciech Macek #include <sys/proc.h>
5208d94c6eSZbigniew Bodek #include <sys/smp.h>
5316694521SOleksandr Tymoshenko 
5416694521SOleksandr Tymoshenko #include <machine/bus.h>
5516694521SOleksandr Tymoshenko #include <machine/intr.h>
5616694521SOleksandr Tymoshenko #include <machine/smp.h>
5716694521SOleksandr Tymoshenko 
58aa0ea9d0SGrzegorz Bernacki #include <arm/mv/mvvar.h>
59ca8e2078SWojciech Macek #include <arm/mv/mvreg.h>
60aa0ea9d0SGrzegorz Bernacki 
6116694521SOleksandr Tymoshenko #include <dev/ofw/ofw_bus.h>
6216694521SOleksandr Tymoshenko #include <dev/ofw/ofw_bus_subr.h>
63aa0ea9d0SGrzegorz Bernacki #include <dev/fdt/fdt_common.h>
6416694521SOleksandr Tymoshenko 
6559c3cb81SAndrew Turner #ifdef INTRNG
66ca8e2078SWojciech Macek #include "pic_if.h"
67ca8e2078SWojciech Macek #endif
68ca8e2078SWojciech Macek 
69aa0ea9d0SGrzegorz Bernacki #ifdef DEBUG
70aa0ea9d0SGrzegorz Bernacki #define debugf(fmt, args...) do { printf("%s(): ", __func__);	\
71aa0ea9d0SGrzegorz Bernacki     printf(fmt,##args); } while (0)
72aa0ea9d0SGrzegorz Bernacki #else
73aa0ea9d0SGrzegorz Bernacki #define debugf(fmt, args...)
74aa0ea9d0SGrzegorz Bernacki #endif
75aa0ea9d0SGrzegorz Bernacki 
7608d94c6eSZbigniew Bodek #define	MPIC_INT_LOCAL			3
77aa0ea9d0SGrzegorz Bernacki #define	MPIC_INT_ERR			4
78aa0ea9d0SGrzegorz Bernacki #define	MPIC_INT_MSI			96
7916694521SOleksandr Tymoshenko 
807e53dd74SWojciech Macek #define	MPIC_IRQ_MASK		0x3ff
8116694521SOleksandr Tymoshenko 
8216694521SOleksandr Tymoshenko #define	MPIC_CTRL		0x0
8316694521SOleksandr Tymoshenko #define	MPIC_SOFT_INT		0x4
84aa0ea9d0SGrzegorz Bernacki #define	MPIC_SOFT_INT_DRBL1	(1 << 5)
8516694521SOleksandr Tymoshenko #define	MPIC_ERR_CAUSE		0x20
8616694521SOleksandr Tymoshenko #define	MPIC_ISE		0x30
8716694521SOleksandr Tymoshenko #define	MPIC_ICE		0x34
88ca8e2078SWojciech Macek #define	MPIC_INT_CTL(irq)	(0x100 + (irq)*4)
8916694521SOleksandr Tymoshenko 
90ca8e2078SWojciech Macek #define	MPIC_INT_IRQ_FIQ_MASK(cpuid)	(0x101 << (cpuid))
91ca8e2078SWojciech Macek #define	MPIC_CTRL_NIRQS(ctrl)	(((ctrl) >> 2) & 0x3ff)
9216694521SOleksandr Tymoshenko 
93ca8e2078SWojciech Macek #define	MPIC_IN_DRBL		0x08
94ca8e2078SWojciech Macek #define	MPIC_IN_DRBL_MASK	0x0c
95ca8e2078SWojciech Macek #define	MPIC_PPI_CAUSE		0x10
96ca8e2078SWojciech Macek #define	MPIC_CTP		0x40
97ca8e2078SWojciech Macek #define	MPIC_IIACK		0x44
98ca8e2078SWojciech Macek #define	MPIC_ISM		0x48
99ca8e2078SWojciech Macek #define	MPIC_ICM		0x4c
10008d94c6eSZbigniew Bodek #define	MPIC_ERR_MASK		0x50
10108d94c6eSZbigniew Bodek #define	MPIC_LOCAL_MASK		0x54
10208d94c6eSZbigniew Bodek #define	MPIC_CPU(n)		(n) * 0x100
103ca8e2078SWojciech Macek 
104ca8e2078SWojciech Macek #define	MPIC_PPI	32
10516694521SOleksandr Tymoshenko 
106bff6be3eSSvatopluk Kraus struct mv_mpic_irqsrc {
107bff6be3eSSvatopluk Kraus 	struct intr_irqsrc	mmi_isrc;
108bff6be3eSSvatopluk Kraus 	u_int			mmi_irq;
109bff6be3eSSvatopluk Kraus };
110bff6be3eSSvatopluk Kraus 
11116694521SOleksandr Tymoshenko struct mv_mpic_softc {
112aa0ea9d0SGrzegorz Bernacki 	device_t		sc_dev;
113ca8e2078SWojciech Macek 	struct resource	*	mpic_res[4];
11416694521SOleksandr Tymoshenko 	bus_space_tag_t		mpic_bst;
11516694521SOleksandr Tymoshenko 	bus_space_handle_t	mpic_bsh;
11616694521SOleksandr Tymoshenko 	bus_space_tag_t		cpu_bst;
11716694521SOleksandr Tymoshenko 	bus_space_handle_t	cpu_bsh;
118aa0ea9d0SGrzegorz Bernacki 	bus_space_tag_t		drbl_bst;
119aa0ea9d0SGrzegorz Bernacki 	bus_space_handle_t	drbl_bsh;
120ca8e2078SWojciech Macek 	struct mtx		mtx;
121bff6be3eSSvatopluk Kraus 	struct mv_mpic_irqsrc *	mpic_isrcs;
122ca8e2078SWojciech Macek 	int			nirqs;
123ca8e2078SWojciech Macek 	void *			intr_hand;
12416694521SOleksandr Tymoshenko };
12516694521SOleksandr Tymoshenko 
12616694521SOleksandr Tymoshenko static struct resource_spec mv_mpic_spec[] = {
12716694521SOleksandr Tymoshenko 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
12816694521SOleksandr Tymoshenko 	{ SYS_RES_MEMORY,	1,	RF_ACTIVE },
129ca8e2078SWojciech Macek 	{ SYS_RES_MEMORY,	2,	RF_ACTIVE | RF_OPTIONAL },
130ca8e2078SWojciech Macek 	{ SYS_RES_IRQ,		0,	RF_ACTIVE | RF_OPTIONAL },
13116694521SOleksandr Tymoshenko 	{ -1, 0 }
13216694521SOleksandr Tymoshenko };
13316694521SOleksandr Tymoshenko 
134ca8e2078SWojciech Macek static struct ofw_compat_data compat_data[] = {
135ca8e2078SWojciech Macek 	{"mrvl,mpic",		true},
136ca8e2078SWojciech Macek 	{"marvell,mpic",	true},
137ca8e2078SWojciech Macek 	{NULL,			false}
138ca8e2078SWojciech Macek };
139ca8e2078SWojciech Macek 
14016694521SOleksandr Tymoshenko static struct mv_mpic_softc *mv_mpic_sc = NULL;
14116694521SOleksandr Tymoshenko 
14216694521SOleksandr Tymoshenko void mpic_send_ipi(int cpus, u_int ipi);
14316694521SOleksandr Tymoshenko 
14416694521SOleksandr Tymoshenko static int	mv_mpic_probe(device_t);
14516694521SOleksandr Tymoshenko static int	mv_mpic_attach(device_t);
14616694521SOleksandr Tymoshenko uint32_t	mv_mpic_get_cause(void);
14716694521SOleksandr Tymoshenko uint32_t	mv_mpic_get_cause_err(void);
148aa0ea9d0SGrzegorz Bernacki uint32_t	mv_mpic_get_msi(void);
149ca8e2078SWojciech Macek static void	mpic_unmask_irq(uintptr_t nb);
150ca8e2078SWojciech Macek static void	mpic_mask_irq(uintptr_t nb);
151ca8e2078SWojciech Macek static void	mpic_mask_irq_err(uintptr_t nb);
152ca8e2078SWojciech Macek static void	mpic_unmask_irq_err(uintptr_t nb);
153c7a65ae3SWojciech Macek static boolean_t mpic_irq_is_percpu(uintptr_t);
154ca8e2078SWojciech Macek static int	mpic_intr(void *arg);
1550044ecdeSLuiz Otavio O Souza static void	mpic_unmask_msi(void);
156*244af1d4SMarcin Wojtas void mpic_init_secondary(device_t);
157*244af1d4SMarcin Wojtas void mpic_ipi_send(device_t, struct intr_irqsrc*, cpuset_t, u_int);
158*244af1d4SMarcin Wojtas int mpic_ipi_read(int);
159*244af1d4SMarcin Wojtas void mpic_ipi_clear(int);
160ca8e2078SWojciech Macek 
161ca8e2078SWojciech Macek #define	MPIC_WRITE(softc, reg, val) \
162ca8e2078SWojciech Macek     bus_space_write_4((softc)->mpic_bst, (softc)->mpic_bsh, (reg), (val))
163ca8e2078SWojciech Macek #define	MPIC_READ(softc, reg) \
164ca8e2078SWojciech Macek     bus_space_read_4((softc)->mpic_bst, (softc)->mpic_bsh, (reg))
16516694521SOleksandr Tymoshenko 
16616694521SOleksandr Tymoshenko #define MPIC_CPU_WRITE(softc, reg, val) \
16716694521SOleksandr Tymoshenko     bus_space_write_4((softc)->cpu_bst, (softc)->cpu_bsh, (reg), (val))
16816694521SOleksandr Tymoshenko #define MPIC_CPU_READ(softc, reg) \
16916694521SOleksandr Tymoshenko     bus_space_read_4((softc)->cpu_bst, (softc)->cpu_bsh, (reg))
17016694521SOleksandr Tymoshenko 
171aa0ea9d0SGrzegorz Bernacki #define MPIC_DRBL_WRITE(softc, reg, val) \
172aa0ea9d0SGrzegorz Bernacki     bus_space_write_4((softc)->drbl_bst, (softc)->drbl_bsh, (reg), (val))
173aa0ea9d0SGrzegorz Bernacki #define MPIC_DRBL_READ(softc, reg) \
174aa0ea9d0SGrzegorz Bernacki     bus_space_read_4((softc)->drbl_bst, (softc)->drbl_bsh, (reg))
175aa0ea9d0SGrzegorz Bernacki 
17616694521SOleksandr Tymoshenko static int
17716694521SOleksandr Tymoshenko mv_mpic_probe(device_t dev)
17816694521SOleksandr Tymoshenko {
17916694521SOleksandr Tymoshenko 
180add35ed5SIan Lepore 	if (!ofw_bus_status_okay(dev))
181add35ed5SIan Lepore 		return (ENXIO);
182add35ed5SIan Lepore 
183ca8e2078SWojciech Macek 	if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
18416694521SOleksandr Tymoshenko 		return (ENXIO);
18516694521SOleksandr Tymoshenko 
18616694521SOleksandr Tymoshenko 	device_set_desc(dev, "Marvell Integrated Interrupt Controller");
18716694521SOleksandr Tymoshenko 	return (0);
18816694521SOleksandr Tymoshenko }
18916694521SOleksandr Tymoshenko 
190bff6be3eSSvatopluk Kraus static int
191bff6be3eSSvatopluk Kraus mv_mpic_register_isrcs(struct mv_mpic_softc *sc)
192bff6be3eSSvatopluk Kraus {
193bff6be3eSSvatopluk Kraus 	int error;
194bff6be3eSSvatopluk Kraus 	uint32_t irq;
195bff6be3eSSvatopluk Kraus 	struct intr_irqsrc *isrc;
196bff6be3eSSvatopluk Kraus 	const char *name;
197bff6be3eSSvatopluk Kraus 
198bff6be3eSSvatopluk Kraus 	sc->mpic_isrcs = malloc(sc->nirqs * sizeof (*sc->mpic_isrcs), M_DEVBUF,
199bff6be3eSSvatopluk Kraus 	    M_WAITOK | M_ZERO);
200bff6be3eSSvatopluk Kraus 
201bff6be3eSSvatopluk Kraus 	name = device_get_nameunit(sc->sc_dev);
202bff6be3eSSvatopluk Kraus 	for (irq = 0; irq < sc->nirqs; irq++) {
203bff6be3eSSvatopluk Kraus 		sc->mpic_isrcs[irq].mmi_irq = irq;
204bff6be3eSSvatopluk Kraus 
205bff6be3eSSvatopluk Kraus 		isrc = &sc->mpic_isrcs[irq].mmi_isrc;
206bff6be3eSSvatopluk Kraus 		if (irq < MPIC_PPI) {
207bff6be3eSSvatopluk Kraus 			error = intr_isrc_register(isrc, sc->sc_dev,
208bff6be3eSSvatopluk Kraus 			    INTR_ISRCF_PPI, "%s", name);
209bff6be3eSSvatopluk Kraus 		} else {
210bff6be3eSSvatopluk Kraus 			error = intr_isrc_register(isrc, sc->sc_dev, 0, "%s",
211bff6be3eSSvatopluk Kraus 			    name);
212bff6be3eSSvatopluk Kraus 		}
213bff6be3eSSvatopluk Kraus 		if (error != 0) {
214bff6be3eSSvatopluk Kraus 			/* XXX call intr_isrc_deregister() */
215bff6be3eSSvatopluk Kraus 			device_printf(sc->sc_dev, "%s failed", __func__);
216bff6be3eSSvatopluk Kraus 			return (error);
217bff6be3eSSvatopluk Kraus 		}
218bff6be3eSSvatopluk Kraus 	}
219bff6be3eSSvatopluk Kraus 	return (0);
220bff6be3eSSvatopluk Kraus }
221bff6be3eSSvatopluk Kraus 
22216694521SOleksandr Tymoshenko static int
22316694521SOleksandr Tymoshenko mv_mpic_attach(device_t dev)
22416694521SOleksandr Tymoshenko {
22516694521SOleksandr Tymoshenko 	struct mv_mpic_softc *sc;
22616694521SOleksandr Tymoshenko 	int error;
227ca8e2078SWojciech Macek 	uint32_t val;
22808d94c6eSZbigniew Bodek 	int cpu;
22916694521SOleksandr Tymoshenko 
23016694521SOleksandr Tymoshenko 	sc = (struct mv_mpic_softc *)device_get_softc(dev);
23116694521SOleksandr Tymoshenko 
23216694521SOleksandr Tymoshenko 	if (mv_mpic_sc != NULL)
23316694521SOleksandr Tymoshenko 		return (ENXIO);
23416694521SOleksandr Tymoshenko 	mv_mpic_sc = sc;
23516694521SOleksandr Tymoshenko 
236aa0ea9d0SGrzegorz Bernacki 	sc->sc_dev = dev;
237aa0ea9d0SGrzegorz Bernacki 
238ca8e2078SWojciech Macek 	mtx_init(&sc->mtx, "MPIC lock", NULL, MTX_SPIN);
239ca8e2078SWojciech Macek 
24016694521SOleksandr Tymoshenko 	error = bus_alloc_resources(dev, mv_mpic_spec, sc->mpic_res);
24116694521SOleksandr Tymoshenko 	if (error) {
24216694521SOleksandr Tymoshenko 		device_printf(dev, "could not allocate resources\n");
24316694521SOleksandr Tymoshenko 		return (ENXIO);
24416694521SOleksandr Tymoshenko 	}
245ca8e2078SWojciech Macek 	if (sc->mpic_res[3] == NULL)
246ca8e2078SWojciech Macek 		device_printf(dev, "No interrupt to use.\n");
247ca8e2078SWojciech Macek 	else
248ca8e2078SWojciech Macek 		bus_setup_intr(dev, sc->mpic_res[3], INTR_TYPE_CLK,
249ca8e2078SWojciech Macek 		    mpic_intr, NULL, sc, &sc->intr_hand);
25016694521SOleksandr Tymoshenko 
25116694521SOleksandr Tymoshenko 	sc->mpic_bst = rman_get_bustag(sc->mpic_res[0]);
25216694521SOleksandr Tymoshenko 	sc->mpic_bsh = rman_get_bushandle(sc->mpic_res[0]);
25316694521SOleksandr Tymoshenko 
25416694521SOleksandr Tymoshenko 	sc->cpu_bst = rman_get_bustag(sc->mpic_res[1]);
25516694521SOleksandr Tymoshenko 	sc->cpu_bsh = rman_get_bushandle(sc->mpic_res[1]);
25616694521SOleksandr Tymoshenko 
257ca8e2078SWojciech Macek 	if (sc->mpic_res[2] != NULL) {
258ca8e2078SWojciech Macek 		/* This is required only if MSIs are used. */
259aa0ea9d0SGrzegorz Bernacki 		sc->drbl_bst = rman_get_bustag(sc->mpic_res[2]);
260aa0ea9d0SGrzegorz Bernacki 		sc->drbl_bsh = rman_get_bushandle(sc->mpic_res[2]);
261ca8e2078SWojciech Macek 	}
262aa0ea9d0SGrzegorz Bernacki 
2630044ecdeSLuiz Otavio O Souza 	MPIC_WRITE(mv_mpic_sc, MPIC_CTRL, 1);
26416694521SOleksandr Tymoshenko 	MPIC_CPU_WRITE(mv_mpic_sc, MPIC_CTP, 0);
26516694521SOleksandr Tymoshenko 
266ca8e2078SWojciech Macek 	val = MPIC_READ(mv_mpic_sc, MPIC_CTRL);
267ca8e2078SWojciech Macek 	sc->nirqs = MPIC_CTRL_NIRQS(val);
268ca8e2078SWojciech Macek 
269bff6be3eSSvatopluk Kraus 	if (mv_mpic_register_isrcs(sc) != 0) {
270bff6be3eSSvatopluk Kraus 		device_printf(dev, "could not register PIC ISRCs\n");
271bff6be3eSSvatopluk Kraus 		bus_release_resources(dev, mv_mpic_spec, sc->mpic_res);
272bff6be3eSSvatopluk Kraus 		return (ENXIO);
273bff6be3eSSvatopluk Kraus 	}
274b488f7aaSZbigniew Bodek 
275b488f7aaSZbigniew Bodek 	OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev);
276b488f7aaSZbigniew Bodek 
2779346e913SAndrew Turner 	if (intr_pic_register(dev, OF_xref_from_device(dev)) == NULL) {
278ca8e2078SWojciech Macek 		device_printf(dev, "could not register PIC\n");
279ca8e2078SWojciech Macek 		bus_release_resources(dev, mv_mpic_spec, sc->mpic_res);
280ca8e2078SWojciech Macek 		return (ENXIO);
281ca8e2078SWojciech Macek 	}
282ca8e2078SWojciech Macek 
283ca8e2078SWojciech Macek 	mpic_unmask_msi();
284aa0ea9d0SGrzegorz Bernacki 
28508d94c6eSZbigniew Bodek 	/* Unmask CPU performance counters overflow irq */
28608d94c6eSZbigniew Bodek 	for (cpu = 0; cpu < mp_ncpus; cpu++)
28708d94c6eSZbigniew Bodek 		MPIC_CPU_WRITE(mv_mpic_sc, MPIC_CPU(cpu) + MPIC_LOCAL_MASK,
28808d94c6eSZbigniew Bodek 		    (1 << cpu) | MPIC_CPU_READ(mv_mpic_sc,
28908d94c6eSZbigniew Bodek 		    MPIC_CPU(cpu) + MPIC_LOCAL_MASK));
29008d94c6eSZbigniew Bodek 
29116694521SOleksandr Tymoshenko 	return (0);
29216694521SOleksandr Tymoshenko }
29316694521SOleksandr Tymoshenko 
294ca8e2078SWojciech Macek static int
295ca8e2078SWojciech Macek mpic_intr(void *arg)
296ca8e2078SWojciech Macek {
297ca8e2078SWojciech Macek 	struct mv_mpic_softc *sc;
298ca8e2078SWojciech Macek 	uint32_t cause, irqsrc;
299ca8e2078SWojciech Macek 	unsigned int irq;
300ca8e2078SWojciech Macek 	u_int cpuid;
301ca8e2078SWojciech Macek 
302ca8e2078SWojciech Macek 	sc = arg;
303ca8e2078SWojciech Macek 	cpuid = PCPU_GET(cpuid);
304ca8e2078SWojciech Macek 	irq = 0;
305ca8e2078SWojciech Macek 
306ca8e2078SWojciech Macek 	for (cause = MPIC_CPU_READ(sc, MPIC_PPI_CAUSE); cause > 0;
307ca8e2078SWojciech Macek 	    cause >>= 1, irq++) {
308ca8e2078SWojciech Macek 		if (cause & 1) {
309ca8e2078SWojciech Macek 			irqsrc = MPIC_READ(sc, MPIC_INT_CTL(irq));
310ca8e2078SWojciech Macek 			if ((irqsrc & MPIC_INT_IRQ_FIQ_MASK(cpuid)) == 0)
311ca8e2078SWojciech Macek 				continue;
312bff6be3eSSvatopluk Kraus 			if (intr_isrc_dispatch(&sc->mpic_isrcs[irq].mmi_isrc,
313bff6be3eSSvatopluk Kraus 			    curthread->td_intr_frame) != 0) {
314ca8e2078SWojciech Macek 				mpic_mask_irq(irq);
315bff6be3eSSvatopluk Kraus 				device_printf(sc->sc_dev, "Stray irq %u "
316bff6be3eSSvatopluk Kraus 				    "disabled\n", irq);
317ca8e2078SWojciech Macek 			}
318ca8e2078SWojciech Macek 		}
319ca8e2078SWojciech Macek 	}
320ca8e2078SWojciech Macek 
321ca8e2078SWojciech Macek 	return (FILTER_HANDLED);
322ca8e2078SWojciech Macek }
323ca8e2078SWojciech Macek 
324ca8e2078SWojciech Macek static void
325bff6be3eSSvatopluk Kraus mpic_disable_intr(device_t dev, struct intr_irqsrc *isrc)
326ca8e2078SWojciech Macek {
327ca8e2078SWojciech Macek 	u_int irq;
328ca8e2078SWojciech Macek 
329bff6be3eSSvatopluk Kraus 	irq = ((struct mv_mpic_irqsrc *)isrc)->mmi_irq;
330ca8e2078SWojciech Macek 	mpic_mask_irq(irq);
331ca8e2078SWojciech Macek }
332ca8e2078SWojciech Macek 
333ca8e2078SWojciech Macek static void
334bff6be3eSSvatopluk Kraus mpic_enable_intr(device_t dev, struct intr_irqsrc *isrc)
335ca8e2078SWojciech Macek {
336ca8e2078SWojciech Macek 	u_int irq;
337ca8e2078SWojciech Macek 
338bff6be3eSSvatopluk Kraus 	irq = ((struct mv_mpic_irqsrc *)isrc)->mmi_irq;
339ca8e2078SWojciech Macek 	mpic_unmask_irq(irq);
340ca8e2078SWojciech Macek }
341bff6be3eSSvatopluk Kraus 
342bff6be3eSSvatopluk Kraus static int
343bff6be3eSSvatopluk Kraus mpic_map_intr(device_t dev, struct intr_map_data *data,
344bff6be3eSSvatopluk Kraus     struct intr_irqsrc **isrcp)
345bff6be3eSSvatopluk Kraus {
346cd642c88SSvatopluk Kraus 	struct intr_map_data_fdt *daf;
347bff6be3eSSvatopluk Kraus 	struct mv_mpic_softc *sc;
348bff6be3eSSvatopluk Kraus 
349cd642c88SSvatopluk Kraus 	if (data->type != INTR_MAP_DATA_FDT)
350cd642c88SSvatopluk Kraus 		return (ENOTSUP);
351bff6be3eSSvatopluk Kraus 
352cd642c88SSvatopluk Kraus 	sc = device_get_softc(dev);
353cd642c88SSvatopluk Kraus 	daf = (struct intr_map_data_fdt *)data;
354cd642c88SSvatopluk Kraus 
355cd642c88SSvatopluk Kraus 	if (daf->ncells !=1 || daf->cells[0] >= sc->nirqs)
356bff6be3eSSvatopluk Kraus 		return (EINVAL);
357bff6be3eSSvatopluk Kraus 
358cd642c88SSvatopluk Kraus 	*isrcp = &sc->mpic_isrcs[daf->cells[0]].mmi_isrc;
359bff6be3eSSvatopluk Kraus 	return (0);
360bff6be3eSSvatopluk Kraus }
361bff6be3eSSvatopluk Kraus 
362ca8e2078SWojciech Macek static void
363ca8e2078SWojciech Macek mpic_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
364ca8e2078SWojciech Macek {
365ca8e2078SWojciech Macek 
366bff6be3eSSvatopluk Kraus 	mpic_disable_intr(dev, isrc);
367ca8e2078SWojciech Macek }
368ca8e2078SWojciech Macek 
369ca8e2078SWojciech Macek static void
370ca8e2078SWojciech Macek mpic_post_ithread(device_t dev, struct intr_irqsrc *isrc)
371ca8e2078SWojciech Macek {
372ca8e2078SWojciech Macek 
373bff6be3eSSvatopluk Kraus 	mpic_enable_intr(dev, isrc);
374ca8e2078SWojciech Macek }
375babd7717SSvatopluk Kraus 
376babd7717SSvatopluk Kraus static void
377babd7717SSvatopluk Kraus mpic_post_filter(device_t dev, struct intr_irqsrc *isrc)
378babd7717SSvatopluk Kraus {
379babd7717SSvatopluk Kraus }
380ca8e2078SWojciech Macek 
38116694521SOleksandr Tymoshenko static device_method_t mv_mpic_methods[] = {
38216694521SOleksandr Tymoshenko 	DEVMETHOD(device_probe,		mv_mpic_probe),
38316694521SOleksandr Tymoshenko 	DEVMETHOD(device_attach,	mv_mpic_attach),
384ca8e2078SWojciech Macek 
385bff6be3eSSvatopluk Kraus 	DEVMETHOD(pic_disable_intr,	mpic_disable_intr),
386bff6be3eSSvatopluk Kraus 	DEVMETHOD(pic_enable_intr,	mpic_enable_intr),
387bff6be3eSSvatopluk Kraus 	DEVMETHOD(pic_map_intr,		mpic_map_intr),
388babd7717SSvatopluk Kraus 	DEVMETHOD(pic_post_filter,	mpic_post_filter),
389ca8e2078SWojciech Macek 	DEVMETHOD(pic_post_ithread,	mpic_post_ithread),
390ca8e2078SWojciech Macek 	DEVMETHOD(pic_pre_ithread,	mpic_pre_ithread),
391*244af1d4SMarcin Wojtas 	DEVMETHOD(pic_init_secondary,	mpic_init_secondary),
392*244af1d4SMarcin Wojtas 	DEVMETHOD(pic_ipi_send,		mpic_ipi_send),
39316694521SOleksandr Tymoshenko 	{ 0, 0 }
39416694521SOleksandr Tymoshenko };
39516694521SOleksandr Tymoshenko 
39616694521SOleksandr Tymoshenko static driver_t mv_mpic_driver = {
39716694521SOleksandr Tymoshenko 	"mpic",
39816694521SOleksandr Tymoshenko 	mv_mpic_methods,
39916694521SOleksandr Tymoshenko 	sizeof(struct mv_mpic_softc),
40016694521SOleksandr Tymoshenko };
40116694521SOleksandr Tymoshenko 
40216694521SOleksandr Tymoshenko static devclass_t mv_mpic_devclass;
40316694521SOleksandr Tymoshenko 
404ca8e2078SWojciech Macek EARLY_DRIVER_MODULE(mpic, simplebus, mv_mpic_driver, mv_mpic_devclass, 0, 0,
405da081cb5SZbigniew Bodek     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
40616694521SOleksandr Tymoshenko 
407ca8e2078SWojciech Macek static void
408ca8e2078SWojciech Macek mpic_unmask_msi(void)
409ca8e2078SWojciech Macek {
410ca8e2078SWojciech Macek 
411ca8e2078SWojciech Macek 	mpic_unmask_irq(MPIC_INT_MSI);
412ca8e2078SWojciech Macek }
413ca8e2078SWojciech Macek 
414ca8e2078SWojciech Macek static void
415ca8e2078SWojciech Macek mpic_unmask_irq_err(uintptr_t nb)
416ca8e2078SWojciech Macek {
41716694521SOleksandr Tymoshenko 	uint32_t mask;
41816694521SOleksandr Tymoshenko 	uint8_t bit_off;
41916694521SOleksandr Tymoshenko 
4200044ecdeSLuiz Otavio O Souza 	MPIC_WRITE(mv_mpic_sc, MPIC_ISE, MPIC_INT_ERR);
421aa0ea9d0SGrzegorz Bernacki 	MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ICM, MPIC_INT_ERR);
42216694521SOleksandr Tymoshenko 
423aa0ea9d0SGrzegorz Bernacki 	bit_off = nb - ERR_IRQ;
42416694521SOleksandr Tymoshenko 	mask = MPIC_CPU_READ(mv_mpic_sc, MPIC_ERR_MASK);
42516694521SOleksandr Tymoshenko 	mask |= (1 << bit_off);
42616694521SOleksandr Tymoshenko 	MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ERR_MASK, mask);
42716694521SOleksandr Tymoshenko }
42816694521SOleksandr Tymoshenko 
429aa0ea9d0SGrzegorz Bernacki static void
430ca8e2078SWojciech Macek mpic_mask_irq_err(uintptr_t nb)
431ca8e2078SWojciech Macek {
432ca8e2078SWojciech Macek 	uint32_t mask;
433ca8e2078SWojciech Macek 	uint8_t bit_off;
434ca8e2078SWojciech Macek 
435ca8e2078SWojciech Macek 	bit_off = nb - ERR_IRQ;
436ca8e2078SWojciech Macek 	mask = MPIC_CPU_READ(mv_mpic_sc, MPIC_ERR_MASK);
437ca8e2078SWojciech Macek 	mask &= ~(1 << bit_off);
438ca8e2078SWojciech Macek 	MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ERR_MASK, mask);
439ca8e2078SWojciech Macek }
440ca8e2078SWojciech Macek 
441c7a65ae3SWojciech Macek static boolean_t
442c7a65ae3SWojciech Macek mpic_irq_is_percpu(uintptr_t nb)
443c7a65ae3SWojciech Macek {
444c7a65ae3SWojciech Macek 	if (nb < MPIC_PPI)
445c7a65ae3SWojciech Macek 		return TRUE;
446c7a65ae3SWojciech Macek 
447c7a65ae3SWojciech Macek 	return FALSE;
448c7a65ae3SWojciech Macek }
449c7a65ae3SWojciech Macek 
450ca8e2078SWojciech Macek static void
451ca8e2078SWojciech Macek mpic_unmask_irq(uintptr_t nb)
452aa0ea9d0SGrzegorz Bernacki {
453aa0ea9d0SGrzegorz Bernacki 
45408d94c6eSZbigniew Bodek #ifdef SMP
45508d94c6eSZbigniew Bodek 	int cpu;
45608d94c6eSZbigniew Bodek 
45708d94c6eSZbigniew Bodek 	if (nb == MPIC_INT_LOCAL) {
45808d94c6eSZbigniew Bodek 		for (cpu = 0; cpu < mp_ncpus; cpu++)
45908d94c6eSZbigniew Bodek 			MPIC_CPU_WRITE(mv_mpic_sc,
46008d94c6eSZbigniew Bodek 			    MPIC_CPU(cpu) + MPIC_ICM, nb);
46108d94c6eSZbigniew Bodek 		return;
46208d94c6eSZbigniew Bodek 	}
46308d94c6eSZbigniew Bodek #endif
464c7a65ae3SWojciech Macek 	if (mpic_irq_is_percpu(nb))
465ca8e2078SWojciech Macek 		MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ICM, nb);
466c7a65ae3SWojciech Macek 	else if (nb < ERR_IRQ)
467c7a65ae3SWojciech Macek 		MPIC_WRITE(mv_mpic_sc, MPIC_ISE, nb);
468c7a65ae3SWojciech Macek 	else if (nb < MSI_IRQ)
469ca8e2078SWojciech Macek 		mpic_unmask_irq_err(nb);
470ca8e2078SWojciech Macek 
471ca8e2078SWojciech Macek 	if (nb == 0)
472ca8e2078SWojciech Macek 		MPIC_CPU_WRITE(mv_mpic_sc, MPIC_IN_DRBL_MASK, 0xffffffff);
473ca8e2078SWojciech Macek }
474ca8e2078SWojciech Macek 
475ca8e2078SWojciech Macek static void
476ca8e2078SWojciech Macek mpic_mask_irq(uintptr_t nb)
477ca8e2078SWojciech Macek {
478ca8e2078SWojciech Macek 
47908d94c6eSZbigniew Bodek #ifdef SMP
48008d94c6eSZbigniew Bodek 	int cpu;
48108d94c6eSZbigniew Bodek 
48208d94c6eSZbigniew Bodek 	if (nb == MPIC_INT_LOCAL) {
48308d94c6eSZbigniew Bodek 		for (cpu = 0; cpu < mp_ncpus; cpu++)
48408d94c6eSZbigniew Bodek 			MPIC_CPU_WRITE(mv_mpic_sc,
48508d94c6eSZbigniew Bodek 			    MPIC_CPU(cpu) + MPIC_ISM, nb);
48608d94c6eSZbigniew Bodek 		return;
48708d94c6eSZbigniew Bodek 	}
48808d94c6eSZbigniew Bodek #endif
489c7a65ae3SWojciech Macek 	if (mpic_irq_is_percpu(nb))
490ca8e2078SWojciech Macek 		MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ISM, nb);
491c7a65ae3SWojciech Macek 	else if (nb < ERR_IRQ)
492c7a65ae3SWojciech Macek 		MPIC_WRITE(mv_mpic_sc, MPIC_ICE, nb);
493c7a65ae3SWojciech Macek 	else if (nb < MSI_IRQ)
494ca8e2078SWojciech Macek 		mpic_mask_irq_err(nb);
495aa0ea9d0SGrzegorz Bernacki }
496aa0ea9d0SGrzegorz Bernacki 
49716694521SOleksandr Tymoshenko uint32_t
49816694521SOleksandr Tymoshenko mv_mpic_get_cause(void)
49916694521SOleksandr Tymoshenko {
50016694521SOleksandr Tymoshenko 
50116694521SOleksandr Tymoshenko 	return (MPIC_CPU_READ(mv_mpic_sc, MPIC_IIACK));
50216694521SOleksandr Tymoshenko }
50316694521SOleksandr Tymoshenko 
50416694521SOleksandr Tymoshenko uint32_t
50516694521SOleksandr Tymoshenko mv_mpic_get_cause_err(void)
50616694521SOleksandr Tymoshenko {
50716694521SOleksandr Tymoshenko 	uint32_t err_cause;
50816694521SOleksandr Tymoshenko 	uint8_t bit_off;
50916694521SOleksandr Tymoshenko 
5100044ecdeSLuiz Otavio O Souza 	err_cause = MPIC_READ(mv_mpic_sc, MPIC_ERR_CAUSE);
51116694521SOleksandr Tymoshenko 
51216694521SOleksandr Tymoshenko 	if (err_cause)
51316694521SOleksandr Tymoshenko 		bit_off = ffs(err_cause) - 1;
51416694521SOleksandr Tymoshenko 	else
51516694521SOleksandr Tymoshenko 		return (-1);
516aa0ea9d0SGrzegorz Bernacki 
517aa0ea9d0SGrzegorz Bernacki 	debugf("%s: irq:%x cause:%x\n", __func__, bit_off, err_cause);
518aa0ea9d0SGrzegorz Bernacki 	return (ERR_IRQ + bit_off);
519aa0ea9d0SGrzegorz Bernacki }
520aa0ea9d0SGrzegorz Bernacki 
521aa0ea9d0SGrzegorz Bernacki uint32_t
522aa0ea9d0SGrzegorz Bernacki mv_mpic_get_msi(void)
523aa0ea9d0SGrzegorz Bernacki {
524aa0ea9d0SGrzegorz Bernacki 	uint32_t cause;
525aa0ea9d0SGrzegorz Bernacki 	uint8_t bit_off;
526aa0ea9d0SGrzegorz Bernacki 
527ca8e2078SWojciech Macek 	KASSERT(mv_mpic_sc->drbl_bst != NULL, ("No doorbell in mv_mpic_get_msi"));
528aa0ea9d0SGrzegorz Bernacki 	cause = MPIC_DRBL_READ(mv_mpic_sc, 0);
529aa0ea9d0SGrzegorz Bernacki 
530aa0ea9d0SGrzegorz Bernacki 	if (cause)
531aa0ea9d0SGrzegorz Bernacki 		bit_off = ffs(cause) - 1;
532aa0ea9d0SGrzegorz Bernacki 	else
533aa0ea9d0SGrzegorz Bernacki 		return (-1);
534aa0ea9d0SGrzegorz Bernacki 
535aa0ea9d0SGrzegorz Bernacki 	debugf("%s: irq:%x cause:%x\n", __func__, bit_off, cause);
536aa0ea9d0SGrzegorz Bernacki 
537aa0ea9d0SGrzegorz Bernacki 	cause &= ~(1 << bit_off);
538aa0ea9d0SGrzegorz Bernacki 	MPIC_DRBL_WRITE(mv_mpic_sc, 0, cause);
539aa0ea9d0SGrzegorz Bernacki 
540aa0ea9d0SGrzegorz Bernacki 	return (MSI_IRQ + bit_off);
541aa0ea9d0SGrzegorz Bernacki }
542aa0ea9d0SGrzegorz Bernacki 
543aa0ea9d0SGrzegorz Bernacki int
544aa0ea9d0SGrzegorz Bernacki mv_msi_data(int irq, uint64_t *addr, uint32_t *data)
545aa0ea9d0SGrzegorz Bernacki {
546aa0ea9d0SGrzegorz Bernacki 	u_long phys, base, size;
547aa0ea9d0SGrzegorz Bernacki 	phandle_t node;
548aa0ea9d0SGrzegorz Bernacki 	int error;
549aa0ea9d0SGrzegorz Bernacki 
550aa0ea9d0SGrzegorz Bernacki 	node = ofw_bus_get_node(mv_mpic_sc->sc_dev);
551aa0ea9d0SGrzegorz Bernacki 
552255eff3bSPedro F. Giffuni 	/* Get physical address of register space */
553aa0ea9d0SGrzegorz Bernacki 	error = fdt_get_range(OF_parent(node), 0, &phys, &size);
554aa0ea9d0SGrzegorz Bernacki 	if (error) {
555aa0ea9d0SGrzegorz Bernacki 		printf("%s: Cannot get register physical address, err:%d",
556aa0ea9d0SGrzegorz Bernacki 		    __func__, error);
557aa0ea9d0SGrzegorz Bernacki 		return (error);
558aa0ea9d0SGrzegorz Bernacki 	}
559aa0ea9d0SGrzegorz Bernacki 
560aa0ea9d0SGrzegorz Bernacki 	/* Get offset of MPIC register space */
561aa0ea9d0SGrzegorz Bernacki 	error = fdt_regsize(node, &base, &size);
562aa0ea9d0SGrzegorz Bernacki 	if (error) {
563aa0ea9d0SGrzegorz Bernacki 		printf("%s: Cannot get MPIC register offset, err:%d",
564aa0ea9d0SGrzegorz Bernacki 		    __func__, error);
565aa0ea9d0SGrzegorz Bernacki 		return (error);
566aa0ea9d0SGrzegorz Bernacki 	}
567aa0ea9d0SGrzegorz Bernacki 
568aa0ea9d0SGrzegorz Bernacki 	*addr = phys + base + MPIC_SOFT_INT;
569aa0ea9d0SGrzegorz Bernacki 	*data = MPIC_SOFT_INT_DRBL1 | irq;
570aa0ea9d0SGrzegorz Bernacki 
571aa0ea9d0SGrzegorz Bernacki 	return (0);
57216694521SOleksandr Tymoshenko }
57316694521SOleksandr Tymoshenko 
57416694521SOleksandr Tymoshenko void
575*244af1d4SMarcin Wojtas mpic_init_secondary(device_t dev)
5767133fe0fSAndrew Turner {
5777133fe0fSAndrew Turner }
5787133fe0fSAndrew Turner 
5797133fe0fSAndrew Turner void
580*244af1d4SMarcin Wojtas mpic_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus, u_int ipi)
58116694521SOleksandr Tymoshenko {
58216694521SOleksandr Tymoshenko 	uint32_t val, i;
58316694521SOleksandr Tymoshenko 
58416694521SOleksandr Tymoshenko 	val = 0x00000000;
58516694521SOleksandr Tymoshenko 	for (i = 0; i < MAXCPU; i++)
58616694521SOleksandr Tymoshenko 		if (CPU_ISSET(i, &cpus))
58716694521SOleksandr Tymoshenko 			val |= (1 << (8 + i));
58816694521SOleksandr Tymoshenko 	val |= ipi;
5890044ecdeSLuiz Otavio O Souza 	MPIC_WRITE(mv_mpic_sc, MPIC_SOFT_INT, val);
59016694521SOleksandr Tymoshenko }
59116694521SOleksandr Tymoshenko 
59216694521SOleksandr Tymoshenko int
593*244af1d4SMarcin Wojtas mpic_ipi_read(int i __unused)
59416694521SOleksandr Tymoshenko {
59516694521SOleksandr Tymoshenko 	uint32_t val;
59617fb49c1SAndrew Turner 	int ipi;
59716694521SOleksandr Tymoshenko 
598aa0ea9d0SGrzegorz Bernacki 	val = MPIC_CPU_READ(mv_mpic_sc, MPIC_IN_DRBL);
59917fb49c1SAndrew Turner 	if (val) {
60017fb49c1SAndrew Turner 		ipi = ffs(val) - 1;
60117fb49c1SAndrew Turner 		MPIC_CPU_WRITE(mv_mpic_sc, MPIC_IN_DRBL, ~(1 << ipi));
60217fb49c1SAndrew Turner 		return (ipi);
60317fb49c1SAndrew Turner 	}
60416694521SOleksandr Tymoshenko 
60516694521SOleksandr Tymoshenko 	return (0x3ff);
60616694521SOleksandr Tymoshenko }
60716694521SOleksandr Tymoshenko 
60816694521SOleksandr Tymoshenko void
609*244af1d4SMarcin Wojtas mpic_ipi_clear(int ipi)
61016694521SOleksandr Tymoshenko {
61116694521SOleksandr Tymoshenko }
612