xref: /freebsd/sys/powerpc/powermac/hrowpic.c (revision 40cdee9dabeb39b6d0ea97d66453a95dca1e1457)
1bd687ebfSPeter Grehan /*
2bd687ebfSPeter Grehan  * Copyright 2003 by Peter Grehan. All rights reserved.
3bd687ebfSPeter Grehan  *
4bd687ebfSPeter Grehan  * Redistribution and use in source and binary forms, with or without
5bd687ebfSPeter Grehan  * modification, are permitted provided that the following conditions
6bd687ebfSPeter Grehan  * are met:
7bd687ebfSPeter Grehan  * 1. Redistributions of source code must retain the above copyright
8bd687ebfSPeter Grehan  *    notice, this list of conditions and the following disclaimer.
9bd687ebfSPeter Grehan  * 2. Redistributions in binary form must reproduce the above copyright
10bd687ebfSPeter Grehan  *    notice, this list of conditions and the following disclaimer in the
11bd687ebfSPeter Grehan  *    documentation and/or other materials provided with the distribution.
12bd687ebfSPeter Grehan  * 3. The name of the author may not be used to endorse or promote products
13bd687ebfSPeter Grehan  *    derived from this software without specific prior written permission.
14bd687ebfSPeter Grehan  *
15bd687ebfSPeter Grehan  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16bd687ebfSPeter Grehan  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17bd687ebfSPeter Grehan  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18bd687ebfSPeter Grehan  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19bd687ebfSPeter Grehan  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20bd687ebfSPeter Grehan  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21bd687ebfSPeter Grehan  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22bd687ebfSPeter Grehan  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23bd687ebfSPeter Grehan  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24bd687ebfSPeter Grehan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25bd687ebfSPeter Grehan  * SUCH DAMAGE.
26bd687ebfSPeter Grehan  *
27bd687ebfSPeter Grehan  * $FreeBSD$
28bd687ebfSPeter Grehan  */
29bd687ebfSPeter Grehan 
30bd687ebfSPeter Grehan /*
31bd687ebfSPeter Grehan  *  A driver for the PIC found in the Heathrow/Paddington MacIO chips.
32bd687ebfSPeter Grehan  * This was superseded by an OpenPIC in the Keylargo and beyond
33bd687ebfSPeter Grehan  * MacIO versions.
34bd687ebfSPeter Grehan  *
35bd687ebfSPeter Grehan  *  The device is initially located in the OpenFirmware device tree
36bd687ebfSPeter Grehan  * in the earliest stage of the nexus probe. However, no device registers
37bd687ebfSPeter Grehan  * are touched until the actual h/w is probed later on during the
38bd687ebfSPeter Grehan  * MacIO probe. At that point, any interrupt sources that were allocated
39bd687ebfSPeter Grehan  * prior to this are activated.
40bd687ebfSPeter Grehan  */
41bd687ebfSPeter Grehan 
42bd687ebfSPeter Grehan #include <sys/param.h>
43bd687ebfSPeter Grehan #include <sys/systm.h>
4440cdee9dSPeter Grehan #include <sys/module.h>
45bd687ebfSPeter Grehan #include <sys/bus.h>
46bd687ebfSPeter Grehan #include <sys/conf.h>
47bd687ebfSPeter Grehan #include <sys/kernel.h>
48bd687ebfSPeter Grehan 
49bd687ebfSPeter Grehan #include <dev/ofw/openfirm.h>
50bd687ebfSPeter Grehan 
51bd687ebfSPeter Grehan #include <machine/bus.h>
52bd687ebfSPeter Grehan #include <machine/intr.h>
53bd687ebfSPeter Grehan #include <machine/intr_machdep.h>
54bd687ebfSPeter Grehan #include <machine/md_var.h>
55bd687ebfSPeter Grehan #include <machine/nexusvar.h>
56bd687ebfSPeter Grehan #include <machine/pio.h>
57bd687ebfSPeter Grehan #include <machine/resource.h>
58bd687ebfSPeter Grehan 
59bd687ebfSPeter Grehan #include <vm/vm.h>
60bd687ebfSPeter Grehan #include <vm/pmap.h>
61bd687ebfSPeter Grehan 
62bd687ebfSPeter Grehan #include <sys/rman.h>
63bd687ebfSPeter Grehan 
64bd687ebfSPeter Grehan #include <powerpc/powermac/maciovar.h>
65bd687ebfSPeter Grehan #include <powerpc/powermac/hrowpicvar.h>
66bd687ebfSPeter Grehan 
67bd687ebfSPeter Grehan #include "pic_if.h"
68bd687ebfSPeter Grehan 
69bd687ebfSPeter Grehan /*
70bd687ebfSPeter Grehan  * Device interface.
71bd687ebfSPeter Grehan  */
7273cb337cSPeter Grehan static void		hrowpic_identify(driver_t *, device_t);
73bd687ebfSPeter Grehan static int		hrowpic_probe(device_t);
74bd687ebfSPeter Grehan static int		hrowpic_attach(device_t);
75bd687ebfSPeter Grehan 
76bd687ebfSPeter Grehan /*
77bd687ebfSPeter Grehan  * PIC interface.
78bd687ebfSPeter Grehan  */
79bd687ebfSPeter Grehan static struct resource	*hrowpic_allocate_intr(device_t, device_t, int *,
80bd687ebfSPeter Grehan                             u_long, u_int);
81bd687ebfSPeter Grehan static int		hrowpic_setup_intr(device_t, device_t,
82bd687ebfSPeter Grehan                             struct resource *, int, driver_intr_t, void *,
83bd687ebfSPeter Grehan                             void **);
84bd687ebfSPeter Grehan static int		hrowpic_teardown_intr(device_t, device_t,
85bd687ebfSPeter Grehan                             struct resource *, void *);
86bd687ebfSPeter Grehan static int		hrowpic_release_intr(device_t dev, device_t, int,
87bd687ebfSPeter Grehan                             struct resource *res);
88bd687ebfSPeter Grehan 
89bd687ebfSPeter Grehan /*
90bd687ebfSPeter Grehan  * MacIO interface
91bd687ebfSPeter Grehan  */
92bd687ebfSPeter Grehan static int	hrowpic_macio_probe(device_t);
93bd687ebfSPeter Grehan static int	hrowpic_macio_attach(device_t);
94bd687ebfSPeter Grehan 
95bd687ebfSPeter Grehan /*
96bd687ebfSPeter Grehan  * Local routines
97bd687ebfSPeter Grehan  */
98bd687ebfSPeter Grehan static void	hrowpic_intr(void);
990bfbe7b9SPeter Wemm static void	hrowpic_ext_enable_irq(uintptr_t);
1000bfbe7b9SPeter Wemm static void	hrowpic_ext_disable_irq(uintptr_t);
101bd687ebfSPeter Grehan static void	hrowpic_toggle_irq(struct hrowpic_softc *sc, int, int);
102bd687ebfSPeter Grehan 
103bd687ebfSPeter Grehan /*
104bd687ebfSPeter Grehan  * Interrupt controller softc. There should only be one.
105bd687ebfSPeter Grehan  */
106bd687ebfSPeter Grehan static struct hrowpic_softc  *hpicsoftc;
107bd687ebfSPeter Grehan 
108bd687ebfSPeter Grehan /*
109bd687ebfSPeter Grehan  * Driver methods.
110bd687ebfSPeter Grehan  */
111bd687ebfSPeter Grehan static device_method_t  hrowpic_methods[] = {
112bd687ebfSPeter Grehan 	/* Device interface */
11373cb337cSPeter Grehan 	DEVMETHOD(device_identify,	hrowpic_identify),
114bd687ebfSPeter Grehan 	DEVMETHOD(device_probe,         hrowpic_probe),
115bd687ebfSPeter Grehan 	DEVMETHOD(device_attach,        hrowpic_attach),
116bd687ebfSPeter Grehan 
117bd687ebfSPeter Grehan 	/* PIC interface */
118bd687ebfSPeter Grehan 	DEVMETHOD(pic_allocate_intr,    hrowpic_allocate_intr),
119bd687ebfSPeter Grehan 	DEVMETHOD(pic_setup_intr,       hrowpic_setup_intr),
120bd687ebfSPeter Grehan 	DEVMETHOD(pic_teardown_intr,    hrowpic_teardown_intr),
121bd687ebfSPeter Grehan 	DEVMETHOD(pic_release_intr,     hrowpic_release_intr),
122bd687ebfSPeter Grehan 
123bd687ebfSPeter Grehan 	{ 0, 0 }
124bd687ebfSPeter Grehan };
125bd687ebfSPeter Grehan 
126bd687ebfSPeter Grehan static driver_t hrowpic_driver = {
127bd687ebfSPeter Grehan 	"hrowpic",
128bd687ebfSPeter Grehan 	hrowpic_methods,
129bd687ebfSPeter Grehan 	sizeof(struct hrowpic_softc)
130bd687ebfSPeter Grehan };
131bd687ebfSPeter Grehan 
132bd687ebfSPeter Grehan static devclass_t hrowpic_devclass;
133bd687ebfSPeter Grehan 
134bd687ebfSPeter Grehan DRIVER_MODULE(hrowpic, nexus, hrowpic_driver, hrowpic_devclass, 0, 0);
135bd687ebfSPeter Grehan 
13673cb337cSPeter Grehan static void
13773cb337cSPeter Grehan hrowpic_identify(driver_t *driver, device_t parent)
13873cb337cSPeter Grehan {
13973cb337cSPeter Grehan 	phandle_t chosen, pic;
14073cb337cSPeter Grehan 	char type[40];
14173cb337cSPeter Grehan 
14273cb337cSPeter Grehan 	chosen = OF_finddevice("/chosen");
14373cb337cSPeter Grehan 	if (chosen == -1)
14473cb337cSPeter Grehan 		return;
14573cb337cSPeter Grehan 
14673cb337cSPeter Grehan 	if (OF_getprop(chosen, "interrupt-controller", &pic, 4) != 4)
14773cb337cSPeter Grehan 		return;
14873cb337cSPeter Grehan 
14973cb337cSPeter Grehan 	OF_getprop(pic, "compatible", type, sizeof(type));
15073cb337cSPeter Grehan 	if (strcmp(type, "heathrow"))
15173cb337cSPeter Grehan 		return;
15273cb337cSPeter Grehan 
15373cb337cSPeter Grehan 	BUS_ADD_CHILD(parent, 0, "hrowpic", 0);
15473cb337cSPeter Grehan }
15573cb337cSPeter Grehan 
156bd687ebfSPeter Grehan static int
157bd687ebfSPeter Grehan hrowpic_probe(device_t dev)
158bd687ebfSPeter Grehan {
15973cb337cSPeter Grehan 	char    *name;
160bd687ebfSPeter Grehan 
16173cb337cSPeter Grehan 	name = nexus_get_name(dev);
162bd687ebfSPeter Grehan 
16373cb337cSPeter Grehan 	if (strcmp(name, "hrowpic"))
164bd687ebfSPeter Grehan 		return (ENXIO);
165bd687ebfSPeter Grehan 
166bd687ebfSPeter Grehan 	device_set_desc(dev, "Heathrow interrupt controller");
167bd687ebfSPeter Grehan 	return (0);
168bd687ebfSPeter Grehan }
169bd687ebfSPeter Grehan 
170bd687ebfSPeter Grehan static int
171bd687ebfSPeter Grehan hrowpic_attach(device_t dev)
172bd687ebfSPeter Grehan {
173bd687ebfSPeter Grehan 	struct hrowpic_softc *sc;
174bd687ebfSPeter Grehan 
175bd687ebfSPeter Grehan 	sc = device_get_softc(dev);
176bd687ebfSPeter Grehan 
177bd687ebfSPeter Grehan 	sc->sc_rman.rm_type = RMAN_ARRAY;
178bd687ebfSPeter Grehan 	sc->sc_rman.rm_descr = device_get_nameunit(dev);
179bd687ebfSPeter Grehan 
180bd687ebfSPeter Grehan 	if (rman_init(&sc->sc_rman) != 0 ||
181bd687ebfSPeter Grehan 	    rman_manage_region(&sc->sc_rman, 0, HROWPIC_IRQMAX-1) != 0) {
182bd687ebfSPeter Grehan 		device_printf(dev, "could not set up resource management");
183bd687ebfSPeter Grehan 		return (ENXIO);
184bd687ebfSPeter Grehan         }
185bd687ebfSPeter Grehan 
18673cb337cSPeter Grehan 	nexus_install_intcntlr(dev);
187bd687ebfSPeter Grehan 	intr_init(hrowpic_intr, HROWPIC_IRQMAX, hrowpic_ext_enable_irq,
188bd687ebfSPeter Grehan 	    hrowpic_ext_disable_irq);
189bd687ebfSPeter Grehan 
190bd687ebfSPeter Grehan 	KASSERT(hpicsoftc == NULL, ("hrowpic: h/w already probed"));
191bd687ebfSPeter Grehan 	hpicsoftc = sc;
192bd687ebfSPeter Grehan 
193bd687ebfSPeter Grehan 	return (0);
194bd687ebfSPeter Grehan }
195bd687ebfSPeter Grehan 
196bd687ebfSPeter Grehan /*
197bd687ebfSPeter Grehan  * PIC interface
198bd687ebfSPeter Grehan  */
199bd687ebfSPeter Grehan static struct resource *
200bd687ebfSPeter Grehan hrowpic_allocate_intr(device_t picdev, device_t child, int *rid, u_long intr,
201bd687ebfSPeter Grehan     u_int flags)
202bd687ebfSPeter Grehan {
203bd687ebfSPeter Grehan 	struct  hrowpic_softc *sc;
204bd687ebfSPeter Grehan 	struct  resource *rv;
205bd687ebfSPeter Grehan 	int     needactivate;
206bd687ebfSPeter Grehan 
207bd687ebfSPeter Grehan 	sc = device_get_softc(picdev);
208bd687ebfSPeter Grehan 	needactivate = flags & RF_ACTIVE;
209bd687ebfSPeter Grehan 	flags &= ~RF_ACTIVE;
210bd687ebfSPeter Grehan 
211bd687ebfSPeter Grehan 	rv = rman_reserve_resource(&sc->sc_rman, intr, intr, 1, flags, child);
212bd687ebfSPeter Grehan 	if (rv == NULL) {
213bd687ebfSPeter Grehan 		device_printf(picdev, "interrupt reservation failed for %s\n",
214bd687ebfSPeter Grehan 		    device_get_nameunit(child));
215bd687ebfSPeter Grehan 		return (NULL);
216bd687ebfSPeter Grehan 	}
217bd687ebfSPeter Grehan 
218bd687ebfSPeter Grehan 	return (rv);
219bd687ebfSPeter Grehan }
220bd687ebfSPeter Grehan 
221bd687ebfSPeter Grehan static int
222bd687ebfSPeter Grehan hrowpic_setup_intr(device_t picdev, device_t child, struct resource *res,
223bd687ebfSPeter Grehan     int flags, driver_intr_t *intr, void *arg, void **cookiep)
224bd687ebfSPeter Grehan {
225bd687ebfSPeter Grehan 	struct  hrowpic_softc *sc;
226bd687ebfSPeter Grehan 	int error;
227bd687ebfSPeter Grehan 
228bd687ebfSPeter Grehan 	sc = device_get_softc(picdev);
229bd687ebfSPeter Grehan 
230bd687ebfSPeter Grehan 	if ((res->r_flags & RF_SHAREABLE) == 0)
231bd687ebfSPeter Grehan 		flags |= INTR_EXCL;
232bd687ebfSPeter Grehan 
233bd687ebfSPeter Grehan 	/*
234bd687ebfSPeter Grehan 	 * We depend here on rman_activate_resource() being idempotent.
235bd687ebfSPeter Grehan 	 */
236bd687ebfSPeter Grehan 	error = rman_activate_resource(res);
237bd687ebfSPeter Grehan 	if (error)
238bd687ebfSPeter Grehan 		return (error);
239bd687ebfSPeter Grehan 
240bd687ebfSPeter Grehan 	error = inthand_add(device_get_nameunit(child), res->r_start, intr,
241bd687ebfSPeter Grehan 	    arg, flags, cookiep);
242bd687ebfSPeter Grehan 
243bd687ebfSPeter Grehan 	if (!error) {
244bd687ebfSPeter Grehan 		/*
245bd687ebfSPeter Grehan 		 * Record irq request, and enable if h/w has been probed
246bd687ebfSPeter Grehan 		 */
247bd687ebfSPeter Grehan 		sc->sc_irq[res->r_start] = 1;
248bd687ebfSPeter Grehan 		if (sc->sc_memr) {
249bd687ebfSPeter Grehan 			hrowpic_toggle_irq(sc, res->r_start, 1);
250bd687ebfSPeter Grehan 		}
251bd687ebfSPeter Grehan 	}
252bd687ebfSPeter Grehan 
253bd687ebfSPeter Grehan 	return (error);
254bd687ebfSPeter Grehan }
255bd687ebfSPeter Grehan 
256bd687ebfSPeter Grehan static int
257bd687ebfSPeter Grehan hrowpic_teardown_intr(device_t picdev, device_t child, struct resource *res,
258bd687ebfSPeter Grehan     void *ih)
259bd687ebfSPeter Grehan {
260bd687ebfSPeter Grehan 	int     error;
261bd687ebfSPeter Grehan 
262bd687ebfSPeter Grehan 	error = rman_deactivate_resource(res);
263bd687ebfSPeter Grehan 	if (error)
264bd687ebfSPeter Grehan 		return (error);
265bd687ebfSPeter Grehan 
266bd687ebfSPeter Grehan 	error = inthand_remove(res->r_start, ih);
267bd687ebfSPeter Grehan 
268bd687ebfSPeter Grehan 	return (error);
269bd687ebfSPeter Grehan }
270bd687ebfSPeter Grehan 
271bd687ebfSPeter Grehan static int
272bd687ebfSPeter Grehan hrowpic_release_intr(device_t picdev, device_t child, int rid,
273bd687ebfSPeter Grehan     struct resource *res)
274bd687ebfSPeter Grehan {
275bd687ebfSPeter Grehan 	int     error;
276bd687ebfSPeter Grehan 
277bd687ebfSPeter Grehan 	if (rman_get_flags(res) & RF_ACTIVE) {
278bd687ebfSPeter Grehan 		error = bus_deactivate_resource(child, SYS_RES_IRQ, rid, res);
279bd687ebfSPeter Grehan 		if (error)
280bd687ebfSPeter Grehan 			return (error);
281bd687ebfSPeter Grehan 	}
282bd687ebfSPeter Grehan 
283bd687ebfSPeter Grehan 	return (rman_release_resource(res));
284bd687ebfSPeter Grehan }
285bd687ebfSPeter Grehan 
286bd687ebfSPeter Grehan /*
287bd687ebfSPeter Grehan  * Interrupt interface
288bd687ebfSPeter Grehan  */
289bd687ebfSPeter Grehan static void
290bd687ebfSPeter Grehan hrowpic_write_reg(struct hrowpic_softc *sc, u_int reg, u_int bank,
291bd687ebfSPeter Grehan     u_int32_t val)
292bd687ebfSPeter Grehan {
293bd687ebfSPeter Grehan 	if (bank == HPIC_PRIMARY)
294bd687ebfSPeter Grehan 		reg += HPIC_1ST_OFFSET;
295bd687ebfSPeter Grehan 
296bd687ebfSPeter Grehan 	bus_space_write_4(sc->sc_bt, sc->sc_bh, reg, val);
297bd687ebfSPeter Grehan 
298bd687ebfSPeter Grehan 	/*
299bd687ebfSPeter Grehan 	 * XXX Issue a read to force the write to complete
300bd687ebfSPeter Grehan 	 */
301bd687ebfSPeter Grehan 	bus_space_read_4(sc->sc_bt, sc->sc_bh, reg);
302bd687ebfSPeter Grehan }
303bd687ebfSPeter Grehan 
304bd687ebfSPeter Grehan static u_int32_t
305bd687ebfSPeter Grehan hrowpic_read_reg(struct hrowpic_softc *sc, u_int reg, u_int bank)
306bd687ebfSPeter Grehan {
307bd687ebfSPeter Grehan 	if (bank == HPIC_PRIMARY)
308bd687ebfSPeter Grehan 		reg += HPIC_1ST_OFFSET;
309bd687ebfSPeter Grehan 
310bd687ebfSPeter Grehan 	return (bus_space_read_4(sc->sc_bt, sc->sc_bh, reg));
311bd687ebfSPeter Grehan }
312bd687ebfSPeter Grehan 
313bd687ebfSPeter Grehan static void
314bd687ebfSPeter Grehan hrowpic_clear_all(struct hrowpic_softc *sc)
315bd687ebfSPeter Grehan {
316bd687ebfSPeter Grehan 	/*
317bd687ebfSPeter Grehan 	 * Disable all interrupt sources and clear outstanding interrupts
318bd687ebfSPeter Grehan 	 */
319bd687ebfSPeter Grehan 	hrowpic_write_reg(sc, HPIC_ENABLE, HPIC_PRIMARY, 0);
320bd687ebfSPeter Grehan 	hrowpic_write_reg(sc, HPIC_CLEAR,  HPIC_PRIMARY, 0xffffffff);
321bd687ebfSPeter Grehan 	hrowpic_write_reg(sc, HPIC_ENABLE, HPIC_SECONDARY, 0);
322bd687ebfSPeter Grehan 	hrowpic_write_reg(sc, HPIC_CLEAR,  HPIC_SECONDARY, 0xffffffff);
323bd687ebfSPeter Grehan }
324bd687ebfSPeter Grehan 
325bd687ebfSPeter Grehan static void
326bd687ebfSPeter Grehan hrowpic_toggle_irq(struct hrowpic_softc *sc, int irq, int enable)
327bd687ebfSPeter Grehan {
328bd687ebfSPeter Grehan 	u_int roffset;
329bd687ebfSPeter Grehan 	u_int rbit;
330bd687ebfSPeter Grehan 
331bd687ebfSPeter Grehan 	KASSERT((irq > 0) && (irq < HROWPIC_IRQMAX), ("en irq out of range"));
332bd687ebfSPeter Grehan 
333bd687ebfSPeter Grehan 	/*
334bd687ebfSPeter Grehan 	 * Calculate prim/sec register bank for the IRQ, update soft copy,
335bd687ebfSPeter Grehan 	 * and enable the IRQ as an interrupt source
336bd687ebfSPeter Grehan 	 */
337bd687ebfSPeter Grehan 	roffset = HPIC_INT_TO_BANK(irq);
338bd687ebfSPeter Grehan 	rbit = HPIC_INT_TO_REGBIT(irq);
339bd687ebfSPeter Grehan 
340bd687ebfSPeter Grehan 	if (enable)
341bd687ebfSPeter Grehan 		sc->sc_softreg[roffset] |= (1 << rbit);
342bd687ebfSPeter Grehan 	else
343bd687ebfSPeter Grehan 		sc->sc_softreg[roffset] &= ~(1 << rbit);
344bd687ebfSPeter Grehan 
345bd687ebfSPeter Grehan 	hrowpic_write_reg(sc, HPIC_ENABLE, roffset, sc->sc_softreg[roffset]);
346bd687ebfSPeter Grehan }
347bd687ebfSPeter Grehan 
348bd687ebfSPeter Grehan static void
349bd687ebfSPeter Grehan hrowpic_intr(void)
350bd687ebfSPeter Grehan {
351bd687ebfSPeter Grehan 	int irq_lo, irq_hi;
352bd687ebfSPeter Grehan 	int i;
353bd687ebfSPeter Grehan 	struct hrowpic_softc *sc;
354bd687ebfSPeter Grehan 
355bd687ebfSPeter Grehan 	sc = hpicsoftc;
356bd687ebfSPeter Grehan 
357bd687ebfSPeter Grehan 	/*
358bd687ebfSPeter Grehan 	 * Loop through both interrupt sources until they are empty.
359bd687ebfSPeter Grehan 	 * XXX simplistic code, far from optimal.
360bd687ebfSPeter Grehan 	 */
361bd687ebfSPeter Grehan 	do {
362bd687ebfSPeter Grehan 		irq_lo = hrowpic_read_reg(sc, HPIC_STATUS, HPIC_PRIMARY);
363bd687ebfSPeter Grehan 		if (irq_lo) {
364bd687ebfSPeter Grehan 			hrowpic_write_reg(sc, HPIC_CLEAR, HPIC_PRIMARY,
365bd687ebfSPeter Grehan 			    irq_lo);
366bd687ebfSPeter Grehan 			for (i = 0; i < HROWPIC_IRQ_REGNUM; i++) {
367bd687ebfSPeter Grehan 				if (irq_lo & (1 << i)) {
368bd687ebfSPeter Grehan 					/*
369bd687ebfSPeter Grehan 					 * Disable IRQ and call handler
370bd687ebfSPeter Grehan 					 */
371bd687ebfSPeter Grehan 					hrowpic_toggle_irq(sc, i, 0);
372bd687ebfSPeter Grehan 					intr_handle(i);
373bd687ebfSPeter Grehan 				}
374bd687ebfSPeter Grehan 			}
375bd687ebfSPeter Grehan 
376bd687ebfSPeter Grehan 		}
377bd687ebfSPeter Grehan 
378bd687ebfSPeter Grehan 		irq_hi = hrowpic_read_reg(sc, HPIC_STATUS, HPIC_SECONDARY);
379bd687ebfSPeter Grehan 		if (irq_hi) {
380bd687ebfSPeter Grehan 			hrowpic_write_reg(sc, HPIC_CLEAR, HPIC_SECONDARY,
381bd687ebfSPeter Grehan 			    irq_hi);
382bd687ebfSPeter Grehan 			for (i = 0; i < HROWPIC_IRQ_REGNUM; i++) {
383bd687ebfSPeter Grehan 				if (irq_hi & (1 << i)) {
384bd687ebfSPeter Grehan 					/*
385bd687ebfSPeter Grehan 					 * Disable IRQ and call handler
386bd687ebfSPeter Grehan 					 */
387bd687ebfSPeter Grehan 					hrowpic_toggle_irq(sc,
388bd687ebfSPeter Grehan 					    i + HROWPIC_IRQ_REGNUM, 0);
389bd687ebfSPeter Grehan 					intr_handle(i + HROWPIC_IRQ_REGNUM);
390bd687ebfSPeter Grehan 				}
391bd687ebfSPeter Grehan 			}
392bd687ebfSPeter Grehan 		}
393bd687ebfSPeter Grehan 	} while (irq_lo && irq_hi);
394bd687ebfSPeter Grehan }
395bd687ebfSPeter Grehan 
396bd687ebfSPeter Grehan static void
3970bfbe7b9SPeter Wemm hrowpic_ext_enable_irq(uintptr_t irq)
398bd687ebfSPeter Grehan {
399bd687ebfSPeter Grehan 	hrowpic_toggle_irq(hpicsoftc, irq, 1);
400bd687ebfSPeter Grehan }
401bd687ebfSPeter Grehan 
402bd687ebfSPeter Grehan static void
4030bfbe7b9SPeter Wemm hrowpic_ext_disable_irq(uintptr_t irq)
404bd687ebfSPeter Grehan {
405bd687ebfSPeter Grehan 	hrowpic_toggle_irq(hpicsoftc, irq, 0);
406bd687ebfSPeter Grehan }
407bd687ebfSPeter Grehan 
408bd687ebfSPeter Grehan 
409bd687ebfSPeter Grehan /*
410bd687ebfSPeter Grehan  * MacIO interface
411bd687ebfSPeter Grehan  */
412bd687ebfSPeter Grehan 
413bd687ebfSPeter Grehan static device_method_t  hrowpic_macio_methods[] = {
414bd687ebfSPeter Grehan 	/* Device interface */
415bd687ebfSPeter Grehan 	DEVMETHOD(device_probe,         hrowpic_macio_probe),
416bd687ebfSPeter Grehan 	DEVMETHOD(device_attach,        hrowpic_macio_attach),
417bd687ebfSPeter Grehan 
418bd687ebfSPeter Grehan 	{ 0, 0 },
419bd687ebfSPeter Grehan };
420bd687ebfSPeter Grehan 
421bd687ebfSPeter Grehan static driver_t hrowpic_macio_driver = {
422bd687ebfSPeter Grehan 	"hrowpicmacio",
423bd687ebfSPeter Grehan 	hrowpic_macio_methods,
424bd687ebfSPeter Grehan 	0
425bd687ebfSPeter Grehan };
426bd687ebfSPeter Grehan 
427bd687ebfSPeter Grehan static devclass_t hrowpic_macio_devclass;
428bd687ebfSPeter Grehan 
429bd687ebfSPeter Grehan DRIVER_MODULE(hrowpicmacio, macio, hrowpic_macio_driver,
430bd687ebfSPeter Grehan     hrowpic_macio_devclass, 0, 0);
431bd687ebfSPeter Grehan 
432bd687ebfSPeter Grehan static int
433bd687ebfSPeter Grehan hrowpic_macio_probe(device_t dev)
434bd687ebfSPeter Grehan {
435bd687ebfSPeter Grehan         char *type = macio_get_devtype(dev);
436bd687ebfSPeter Grehan 
437bd687ebfSPeter Grehan 	/*
438bd687ebfSPeter Grehan 	 * OpenPIC cells have a type of "open-pic", so this
439bd687ebfSPeter Grehan 	 * is sufficient to identify a Heathrow cell
440bd687ebfSPeter Grehan 	 */
441bd687ebfSPeter Grehan         if (strcmp(type, "interrupt-controller") != 0)
442bd687ebfSPeter Grehan                 return (ENXIO);
443bd687ebfSPeter Grehan 
444bd687ebfSPeter Grehan 	/*
445bd687ebfSPeter Grehan 	 * The description was already printed out in the nexus
446bd687ebfSPeter Grehan 	 * probe, so don't do it again here
447bd687ebfSPeter Grehan 	 */
448bd687ebfSPeter Grehan         device_set_desc(dev, "Heathrow MacIO interrupt cell");
449bd687ebfSPeter Grehan 	device_quiet(dev);
450bd687ebfSPeter Grehan         return (0);
451bd687ebfSPeter Grehan }
452bd687ebfSPeter Grehan 
453bd687ebfSPeter Grehan static int
454bd687ebfSPeter Grehan hrowpic_macio_attach(device_t dev)
455bd687ebfSPeter Grehan {
456bd687ebfSPeter Grehan 	struct hrowpic_softc *sc = hpicsoftc;
457bd687ebfSPeter Grehan 	int rid;
458bd687ebfSPeter Grehan 	int i;
459bd687ebfSPeter Grehan 
460bd687ebfSPeter Grehan 	KASSERT(sc != NULL, ("pic not nexus-probed\n"));
461bd687ebfSPeter Grehan 	sc->sc_maciodev = dev;
462bd687ebfSPeter Grehan 
463bd687ebfSPeter Grehan 	rid = 0;
4645f96beb9SNate Lawson 	sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
465bd687ebfSPeter Grehan 	    RF_ACTIVE);
466bd687ebfSPeter Grehan 
467bd687ebfSPeter Grehan 	if (sc->sc_memr == NULL) {
468bd687ebfSPeter Grehan 		device_printf(dev, "Could not alloc mem resource!\n");
469bd687ebfSPeter Grehan 		return (ENXIO);
470bd687ebfSPeter Grehan 	}
471bd687ebfSPeter Grehan 
472bd687ebfSPeter Grehan 	sc->sc_bt = rman_get_bustag(sc->sc_memr);
473bd687ebfSPeter Grehan 	sc->sc_bh = rman_get_bushandle(sc->sc_memr);
474bd687ebfSPeter Grehan 
475bd687ebfSPeter Grehan 	hrowpic_clear_all(sc);
476bd687ebfSPeter Grehan 
477bd687ebfSPeter Grehan 	/*
478bd687ebfSPeter Grehan 	 * Enable all IRQs that were requested before the h/w
479bd687ebfSPeter Grehan 	 * was probed
480bd687ebfSPeter Grehan 	 */
481bd687ebfSPeter Grehan 	for (i = 0; i < HROWPIC_IRQMAX; i++)
482bd687ebfSPeter Grehan 		if (sc->sc_irq[i]) {
483bd687ebfSPeter Grehan 			hrowpic_toggle_irq(sc, i, 1);
484bd687ebfSPeter Grehan 		}
485bd687ebfSPeter Grehan 
486bd687ebfSPeter Grehan 	return (0);
487bd687ebfSPeter Grehan }
488