1220297Sadrian/*	$NetBSD: obio.c,v 1.11 2003/07/15 00:25:05 lukem Exp $	*/
2220297Sadrian
3220297Sadrian/*-
4220297Sadrian * Copyright (c) 2001, 2002, 2003 Wasabi Systems, Inc.
5220297Sadrian * All rights reserved.
6220297Sadrian *
7220297Sadrian * Written by Jason R. Thorpe for Wasabi Systems, Inc.
8220297Sadrian *
9220297Sadrian * Redistribution and use in source and binary forms, with or without
10220297Sadrian * modification, are permitted provided that the following conditions
11220297Sadrian * are met:
12220297Sadrian * 1. Redistributions of source code must retain the above copyright
13220297Sadrian *    notice, this list of conditions and the following disclaimer.
14220297Sadrian * 2. Redistributions in binary form must reproduce the above copyright
15220297Sadrian *    notice, this list of conditions and the following disclaimer in the
16220297Sadrian *    documentation and/or other materials provided with the distribution.
17220297Sadrian *
18220297Sadrian * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
19220297Sadrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20220297Sadrian * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21220297Sadrian * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
22220297Sadrian * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23220297Sadrian * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24220297Sadrian * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25220297Sadrian * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26220297Sadrian * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27220297Sadrian * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28220297Sadrian * POSSIBILITY OF SUCH DAMAGE.
29220297Sadrian */
30220297Sadrian
31220297Sadrian#include <sys/cdefs.h>
32220297Sadrian__FBSDID("$FreeBSD$");
33220297Sadrian
34220297Sadrian#include <sys/param.h>
35220297Sadrian#include <sys/systm.h>
36220297Sadrian#include <sys/bus.h>
37220297Sadrian#include <sys/interrupt.h>
38220297Sadrian#include <sys/kernel.h>
39220297Sadrian#include <sys/module.h>
40220297Sadrian#include <sys/rman.h>
41220297Sadrian#include <sys/malloc.h>
42220297Sadrian
43220297Sadrian#include <machine/bus.h>
44220297Sadrian
45220297Sadrian#include <mips/rt305x/rt305xreg.h>
46220297Sadrian#include <mips/rt305x/obiovar.h>
47220297Sadrian#include <mips/rt305x/rt305x_icvar.h>
48220297Sadrian
49220297Sadrian/* MIPS HW interrupts of IRQ/FIQ respectively */
50220297Sadrian#define RT305X_INTR		0
51220297Sadrian#define RT305X_FAST_INTR	1
52220297Sadrian
53220297Sadrian/* Interrupt levels */
54220297Sadrian#define INTR_IRQ 0
55220297Sadrian#define INTR_FIQ 1
56220297Sadrian
57220297Sadrian
58220297Sadrianint irq_priorities[NIRQS] = {
59220297Sadrian	INTR_IRQ,	/* SYSCTL */
60220297Sadrian	INTR_FIQ,	/* TIMER0 */
61220297Sadrian	INTR_FIQ,	/* WDTIMER */
62220297Sadrian	INTR_IRQ,	/* Illegal Access */
63220297Sadrian	INTR_IRQ,	/* PCM */
64220297Sadrian	INTR_IRQ,	/* UART */
65220297Sadrian	INTR_IRQ,	/* GPIO */
66220297Sadrian	INTR_FIQ,	/* GDMA */
67220297Sadrian	INTR_IRQ,	/* NAND */
68220297Sadrian	INTR_IRQ,	/* Perfomance Counter */
69220297Sadrian	INTR_IRQ,	/* I2S */
70220297Sadrian	INTR_IRQ,	/* unknown */
71220297Sadrian	INTR_IRQ,	/* UARTLITE */
72220297Sadrian	INTR_IRQ,	/* unknown */
73220297Sadrian	INTR_IRQ,	/* unknown */
74220297Sadrian	INTR_IRQ,	/* unknown */
75220297Sadrian	INTR_IRQ,	/* unknown */
76220297Sadrian	INTR_IRQ,	/* EtherNet Switch */
77220297Sadrian	INTR_FIQ,	/* OTG */
78220297Sadrian	INTR_IRQ,	/* unknown */
79220297Sadrian	INTR_IRQ,	/* unknown */
80220297Sadrian	INTR_IRQ,	/* unknown */
81220297Sadrian	INTR_IRQ,	/* unknown */
82220297Sadrian	INTR_IRQ,	/* unknown */
83220297Sadrian	INTR_IRQ,	/* unknown */
84220297Sadrian	INTR_IRQ,	/* unknown */
85220297Sadrian	INTR_IRQ,	/* unknown */
86220297Sadrian	INTR_IRQ,	/* unknown */
87220297Sadrian	INTR_IRQ,	/* unknown */
88220297Sadrian	INTR_IRQ,	/* unknown */
89220297Sadrian	INTR_IRQ,	/* unknown */
90220297Sadrian	INTR_IRQ,	/* unknown */
91220297Sadrian};
92220297Sadrian
93220297Sadrian
94220297Sadrian#define REG_READ(o) *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1(INTCTL_BASE + (o)))
95220297Sadrian#define REG_WRITE(o,v) (REG_READ(o)) = (v)
96220297Sadrian
97220297Sadrianstatic int	obio_activate_resource(device_t, device_t, int, int,
98220297Sadrian		    struct resource *);
99220297Sadrianstatic device_t	obio_add_child(device_t, u_int, const char *, int);
100220297Sadrianstatic struct resource *
101294883Sjhibbits		obio_alloc_resource(device_t, device_t, int, int *, rman_res_t,
102294883Sjhibbits		    rman_res_t, rman_res_t, u_int);
103220297Sadrianstatic int	obio_attach(device_t);
104220297Sadrianstatic int	obio_deactivate_resource(device_t, device_t, int, int,
105220297Sadrian		    struct resource *);
106220297Sadrianstatic struct resource_list *
107220297Sadrian		obio_get_resource_list(device_t, device_t);
108220297Sadrianstatic void	obio_add_res_child(device_t, const char *, int, long, int, int);
109220297Sadrianstatic void	obio_hinted_child(device_t, const char *, int);
110220297Sadrianstatic int	obio_intr(void *);
111220297Sadrianstatic int	obio_probe(device_t);
112220297Sadrianstatic int	obio_release_resource(device_t, device_t, int, int,
113220297Sadrian		    struct resource *);
114220297Sadrianstatic int	obio_setup_intr(device_t, device_t, struct resource *, int,
115220297Sadrian		    driver_filter_t *, driver_intr_t *, void *, void **);
116220297Sadrianstatic int	obio_teardown_intr(device_t, device_t, struct resource *,
117220297Sadrian		    void *);
118220297Sadrian
119220297Sadrianstatic void
120220297Sadrianobio_mask_irq(void *source)
121220297Sadrian{
122220297Sadrian	int irq;
123220297Sadrian	uint32_t irqmask;
124220297Sadrian
125220297Sadrian	irq = (int)source;
126220297Sadrian	irqmask = 1 << irq;
127220297Sadrian
128220297Sadrian	/* disable IRQ */
129220297Sadrian	rt305x_ic_set(IC_INT_DIS, irqmask);
130220297Sadrian}
131220297Sadrian
132220297Sadrianstatic void
133220297Sadrianobio_unmask_irq(void *source)
134220297Sadrian{
135220297Sadrian	int irq;
136220297Sadrian	uint32_t irqmask;
137220297Sadrian
138220297Sadrian	irq = (int)source;
139220297Sadrian	irqmask = 1 << irq;
140220297Sadrian
141220297Sadrian	/* enable IRQ */
142220297Sadrian	rt305x_ic_set(IC_INT_ENA, irqmask);
143220297Sadrian
144220297Sadrian}
145220297Sadrian
146220297Sadrian
147220297Sadrianstatic int
148220297Sadrianobio_probe(device_t dev)
149220297Sadrian{
150220297Sadrian
151257338Snwhitehorn	return (BUS_PROBE_NOWILDCARD);
152220297Sadrian}
153220297Sadrian
154220297Sadrianstatic int
155220297Sadrianobio_attach(device_t dev)
156220297Sadrian{
157220297Sadrian	struct obio_softc *sc = device_get_softc(dev);
158220297Sadrian	int rid;
159220297Sadrian
160220297Sadrian	sc->oba_mem_rman.rm_type = RMAN_ARRAY;
161220297Sadrian	sc->oba_mem_rman.rm_descr = "OBIO memory";
162220297Sadrian	if (rman_init(&sc->oba_mem_rman) != 0 ||
163220297Sadrian	    rman_manage_region(&sc->oba_mem_rman, OBIO_MEM_START,
164220297Sadrian	        OBIO_MEM_END) != 0)
165220297Sadrian		panic("obio_attach: failed to set up I/O rman");
166220297Sadrian
167220297Sadrian	sc->oba_irq_rman.rm_type = RMAN_ARRAY;
168220297Sadrian	sc->oba_irq_rman.rm_descr = "OBIO IRQ";
169220297Sadrian	if (rman_init(&sc->oba_irq_rman) != 0 ||
170220297Sadrian	    rman_manage_region(&sc->oba_irq_rman, 0, NIRQS-1) != 0)
171220297Sadrian		panic("obio_attach: failed to set up IRQ rman");
172220297Sadrian
173220297Sadrian	/* Hook up our interrupt handler. */
174220297Sadrian	if ((sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
175220297Sadrian	    RT305X_INTR, RT305X_INTR, 1,
176220297Sadrian	    RF_SHAREABLE | RF_ACTIVE)) == NULL) {
177220297Sadrian		device_printf(dev, "unable to allocate IRQ resource\n");
178220297Sadrian		return (ENXIO);
179220297Sadrian	}
180220297Sadrian
181220297Sadrian	if ((bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC, obio_intr, NULL,
182220297Sadrian	    sc, &sc->sc_ih))) {
183220297Sadrian		device_printf(dev,
184220297Sadrian		    "WARNING: unable to register interrupt handler\n");
185220297Sadrian		return (ENXIO);
186220297Sadrian	}
187220297Sadrian
188220297Sadrian	/* Hook up our FAST interrupt handler. */
189220297Sadrian	if ((sc->sc_fast_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
190220297Sadrian	    RT305X_FAST_INTR, RT305X_FAST_INTR, 1,
191220297Sadrian	    RF_SHAREABLE | RF_ACTIVE)) == NULL) {
192220297Sadrian		device_printf(dev, "unable to allocate IRQ resource\n");
193220297Sadrian		return (ENXIO);
194220297Sadrian	}
195220297Sadrian
196220297Sadrian	if ((bus_setup_intr(dev, sc->sc_fast_irq, INTR_TYPE_MISC, obio_intr,
197220297Sadrian	    NULL, sc, &sc->sc_fast_ih))) {
198220297Sadrian		device_printf(dev,
199220297Sadrian		    "WARNING: unable to register interrupt handler\n");
200220297Sadrian		return (ENXIO);
201220297Sadrian	}
202220297Sadrian
203220297Sadrian	/* disable all interrupts */
204220297Sadrian	rt305x_ic_set(IC_INT_DIS, IC_INT_MASK|IC_LINE_GLOBAL);
205220297Sadrian
206220297Sadrian	bus_generic_probe(dev);
207220297Sadrian
208220297Sadrian	obio_add_res_child(dev, "rt305x_sysctl", 0,
209220297Sadrian	    SYSCTL_BASE, (SYSCTL_END - SYSCTL_BASE + 1),
210220297Sadrian	    IC_SYSCTL);
211220297Sadrian	obio_add_res_child(dev, "rt305x_ic", 0,
212220297Sadrian	    INTCTL_BASE, (INTCTL_END - INTCTL_BASE + 1),
213220297Sadrian	    -1);
214220297Sadrian#ifdef notyet
215220297Sadrian	obio_add_res_child(dev, "timer",0,
216220297Sadrian	    TIMER_BASE, (TIMER_END - TIMER_BASE  + 1),
217220297Sadrian	    IC_TIMER0);
218220297Sadrian	obio_add_res_child(dev, "rt305x_memc", 0,
219220297Sadrian	    MEMCTRL_BASE, (MEMCTRL_END - MEMCTRL_BASE + 1),
220220297Sadrian	    -1);
221220297Sadrian	obio_add_res_child(dev, "pcm", 	0,
222220297Sadrian	    PCM_BASE, (PCM_END - PCM_BASE  + 1),
223220297Sadrian	    IC_PCM);
224292703Sadrian#endif
225220297Sadrian	obio_add_res_child(dev, "uart", 0,
226220297Sadrian	    UART_BASE, (UART_END - UART_BASE + 1),
227220297Sadrian	    IC_UART);
228220297Sadrian	obio_add_res_child(dev, "gpio", 0,
229220297Sadrian	    PIO_BASE, (PIO_END - PIO_BASE  + 1),
230220297Sadrian	    IC_PIO);
231220297Sadrian#ifdef notyet
232220297Sadrian	obio_add_res_child(dev, "rt305x_dma", 0,
233220297Sadrian	    GDMA_BASE, (GDMA_END - GDMA_BASE + 1),
234220297Sadrian	    IC_DMA);
235220297Sadrian	obio_add_res_child(dev, "rt305x_nandc", 0,
236220297Sadrian	    NANDFC_BASE, (NANDFC_END - NANDFC_BASE  + 1),
237220297Sadrian	    IC_NAND);
238220297Sadrian	obio_add_res_child(dev, "i2c", 	0,
239220297Sadrian	    I2C_BASE, (I2C_END - I2C_BASE  + 1),
240220297Sadrian	    -1);
241220297Sadrian	obio_add_res_child(dev, "i2s", 0,
242220297Sadrian	    I2S_BASE, (I2S_END - I2S_BASE  + 1),
243220297Sadrian	    IC_I2S);
244292703Sadrian#endif
245220297Sadrian	obio_add_res_child(dev, "spi", 0,
246220297Sadrian	    SPI_BASE, (SPI_END - SPI_BASE  + 1),
247220297Sadrian	    -1);
248220297Sadrian	obio_add_res_child(dev, "uart", 1,
249220297Sadrian	    UARTLITE_BASE, (UARTLITE_END - UARTLITE_BASE + 1),
250220297Sadrian	    IC_UARTLITE);
251292703Sadrian#if !defined(RT5350) && !defined(MT7620)
252220297Sadrian	obio_add_res_child(dev, "cfi", 	0,
253220297Sadrian	    FLASH_BASE, (FLASH_END - FLASH_BASE  + 1),
254220297Sadrian	    -1);
255292703Sadrian	obio_add_res_child(dev, "dwcotg", 0,
256220297Sadrian	    USB_OTG_BASE, (USB_OTG_END - USB_OTG_BASE  + 1),
257220297Sadrian	    IC_OTG);
258292703Sadrian#else
259292703Sadrian	obio_add_res_child(dev, "ehci", 0,
260292703Sadrian	    USB_OTG_BASE, (USB_OTG_END - USB_OTG_BASE  + 1),
261292703Sadrian	    IC_OTG);
262292703Sadrian	obio_add_res_child(dev, "ohci", 0,
263292703Sadrian	    USB_OHCI_BASE, (USB_OHCI_END - USB_OHCI_BASE + 1),
264292703Sadrian	    IC_OTG);
265292703Sadrian#endif
266220297Sadrian	obio_add_res_child(dev, "switch", 0,
267220297Sadrian	    ETHSW_BASE, (ETHSW_END - ETHSW_BASE  + 1),
268220297Sadrian	    IC_ETHSW);
269220297Sadrian
270220297Sadrian	bus_enumerate_hinted_children(dev);
271220297Sadrian	bus_generic_attach(dev);
272220297Sadrian
273220297Sadrian	/* enable IC */
274220297Sadrian	rt305x_ic_set(IC_INT_ENA, IC_LINE_GLOBAL);
275220297Sadrian
276220297Sadrian	return (0);
277220297Sadrian}
278220297Sadrian
279220297Sadrianstatic struct resource *
280220297Sadrianobio_alloc_resource(device_t bus, device_t child, int type, int *rid,
281294883Sjhibbits    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
282220297Sadrian{
283220297Sadrian	struct obio_softc		*sc = device_get_softc(bus);
284220297Sadrian	struct obio_ivar		*ivar = device_get_ivars(child);
285220297Sadrian	struct resource			*rv;
286220297Sadrian	struct resource_list_entry	*rle;
287220297Sadrian	struct rman			*rm;
288220297Sadrian	int				 isdefault, needactivate, passthrough;
289220297Sadrian
290295832Sjhibbits	isdefault = (RMAN_IS_DEFAULT_RANGE(start, end) && count == 1);
291220297Sadrian	needactivate = flags & RF_ACTIVE;
292220297Sadrian	passthrough = (device_get_parent(child) != bus);
293220297Sadrian	rle = NULL;
294220297Sadrian
295220297Sadrian	if (passthrough)
296220297Sadrian		return (BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type,
297220297Sadrian		    rid, start, end, count, flags));
298220297Sadrian
299220297Sadrian	/*
300220297Sadrian	 * If this is an allocation of the "default" range for a given RID,
301220297Sadrian	 * and we know what the resources for this device are (ie. they aren't
302220297Sadrian	 * maintained by a child bus), then work out the start/end values.
303220297Sadrian	 */
304220297Sadrian	if (isdefault) {
305220297Sadrian		rle = resource_list_find(&ivar->resources, type, *rid);
306220297Sadrian		if (rle == NULL)
307220297Sadrian			return (NULL);
308220297Sadrian		if (rle->res != NULL) {
309220297Sadrian			panic("%s: resource entry is busy", __func__);
310220297Sadrian		}
311220297Sadrian		start = rle->start;
312220297Sadrian		end = rle->end;
313220297Sadrian		count = rle->count;
314220297Sadrian	}
315220297Sadrian
316220297Sadrian	switch (type) {
317220297Sadrian	case SYS_RES_IRQ:
318220297Sadrian		rm = &sc->oba_irq_rman;
319220297Sadrian		break;
320220297Sadrian	case SYS_RES_MEMORY:
321220297Sadrian		rm = &sc->oba_mem_rman;
322220297Sadrian		break;
323220297Sadrian	default:
324220297Sadrian		printf("%s: unknown resource type %d\n", __func__, type);
325220297Sadrian		return (0);
326220297Sadrian	}
327220297Sadrian
328220297Sadrian	rv = rman_reserve_resource(rm, start, end, count, flags, child);
329298053Spfg	if (rv == NULL) {
330220297Sadrian		printf("%s: could not reserve resource\n", __func__);
331220297Sadrian		return (0);
332220297Sadrian	}
333220297Sadrian
334220297Sadrian	rman_set_rid(rv, *rid);
335220297Sadrian
336220297Sadrian	if (needactivate) {
337220297Sadrian		if (bus_activate_resource(child, type, *rid, rv)) {
338220297Sadrian			printf("%s: could not activate resource\n", __func__);
339220297Sadrian			rman_release_resource(rv);
340220297Sadrian			return (0);
341220297Sadrian		}
342220297Sadrian	}
343220297Sadrian
344220297Sadrian	return (rv);
345220297Sadrian}
346220297Sadrian
347220297Sadrianstatic int
348220297Sadrianobio_activate_resource(device_t bus, device_t child, int type, int rid,
349220297Sadrian    struct resource *r)
350220297Sadrian{
351220297Sadrian
352220297Sadrian	/*
353220297Sadrian	 * If this is a memory resource, track the direct mapping
354220297Sadrian	 * in the uncached MIPS KSEG1 segment.
355220297Sadrian	 */
356220297Sadrian	if (type == SYS_RES_MEMORY) {
357220297Sadrian		void *vaddr;
358220297Sadrian
359220297Sadrian		vaddr = (void *)MIPS_PHYS_TO_KSEG1((intptr_t)rman_get_start(r));
360220297Sadrian		rman_set_virtual(r, vaddr);
361220297Sadrian		rman_set_bustag(r, mips_bus_space_generic);
362220297Sadrian		rman_set_bushandle(r, (bus_space_handle_t)vaddr);
363220297Sadrian	}
364220297Sadrian
365220297Sadrian	return (rman_activate_resource(r));
366220297Sadrian}
367220297Sadrian
368220297Sadrianstatic int
369220297Sadrianobio_deactivate_resource(device_t bus, device_t child, int type, int rid,
370220297Sadrian    struct resource *r)
371220297Sadrian{
372220297Sadrian
373220297Sadrian	return (rman_deactivate_resource(r));
374220297Sadrian}
375220297Sadrian
376220297Sadrianstatic int
377220297Sadrianobio_release_resource(device_t dev, device_t child, int type,
378220297Sadrian    int rid, struct resource *r)
379220297Sadrian{
380220297Sadrian	struct resource_list *rl;
381220297Sadrian	struct resource_list_entry *rle;
382220297Sadrian
383220297Sadrian	rl = obio_get_resource_list(dev, child);
384220297Sadrian	if (rl == NULL)
385220297Sadrian		return (EINVAL);
386220297Sadrian	rle = resource_list_find(rl, type, rid);
387220297Sadrian	if (rle == NULL)
388220297Sadrian		return (EINVAL);
389220297Sadrian	rman_release_resource(r);
390220297Sadrian	rle->res = NULL;
391220297Sadrian
392220297Sadrian	return (0);
393220297Sadrian}
394220297Sadrian
395220297Sadrianstatic int
396220297Sadrianobio_setup_intr(device_t dev, device_t child, struct resource *ires,
397220297Sadrian		int flags, driver_filter_t *filt, driver_intr_t *handler,
398220297Sadrian		void *arg, void **cookiep)
399220297Sadrian{
400220297Sadrian	struct obio_softc *sc = device_get_softc(dev);
401220297Sadrian	struct intr_event *event;
402220297Sadrian	int irq, error, priority;
403220297Sadrian	uint32_t irqmask;
404220297Sadrian
405220297Sadrian	irq = rman_get_start(ires);
406220297Sadrian
407220297Sadrian	if (irq >= NIRQS)
408220297Sadrian		panic("%s: bad irq %d", __func__, irq);
409220297Sadrian
410220297Sadrian	event = sc->sc_eventstab[irq];
411220297Sadrian	if (event == NULL) {
412220297Sadrian		error = intr_event_create(&event, (void *)irq, 0, irq,
413220297Sadrian		    obio_mask_irq, obio_unmask_irq,
414220297Sadrian		    NULL, NULL, "obio intr%d:", irq);
415220297Sadrian
416220297Sadrian		sc->sc_eventstab[irq] = event;
417220297Sadrian	}
418220297Sadrian	else
419220297Sadrian		panic("obio: Can't share IRQs");
420220297Sadrian
421220297Sadrian	intr_event_add_handler(event, device_get_nameunit(child), filt,
422220297Sadrian	    handler, arg, intr_priority(flags), flags, cookiep);
423220297Sadrian
424220297Sadrian	irqmask = 1 << irq;
425220297Sadrian	priority = irq_priorities[irq];
426220297Sadrian
427220297Sadrian	if (priority == INTR_FIQ)
428220297Sadrian		rt305x_ic_set(IC_INTTYPE, rt305x_ic_get(IC_INTTYPE) | irqmask);
429220297Sadrian	else
430220297Sadrian		rt305x_ic_set(IC_INTTYPE, rt305x_ic_get(IC_INTTYPE) & ~irqmask);
431220297Sadrian
432220297Sadrian	/* enable */
433220297Sadrian	obio_unmask_irq((void*)irq);
434220297Sadrian
435220297Sadrian	return (0);
436220297Sadrian}
437220297Sadrian
438220297Sadrianstatic int
439220297Sadrianobio_teardown_intr(device_t dev, device_t child, struct resource *ires,
440220297Sadrian    void *cookie)
441220297Sadrian{
442220297Sadrian	struct obio_softc *sc = device_get_softc(dev);
443220297Sadrian	int irq, result, priority;
444220297Sadrian	uint32_t irqmask;
445220297Sadrian
446220297Sadrian	irq = rman_get_start(ires);
447220297Sadrian	if (irq >= NIRQS)
448220297Sadrian		panic("%s: bad irq %d", __func__, irq);
449220297Sadrian
450220297Sadrian	if (sc->sc_eventstab[irq] == NULL)
451220297Sadrian		panic("Trying to teardown unoccupied IRQ");
452220297Sadrian
453220297Sadrian	irqmask = (1 << irq);
454220297Sadrian	priority = irq_priorities[irq];
455220297Sadrian
456220297Sadrian	if (priority == INTR_FIQ)
457220297Sadrian		rt305x_ic_set(IC_INTTYPE, rt305x_ic_get(IC_INTTYPE) & ~irqmask);
458220297Sadrian	else
459220297Sadrian		rt305x_ic_set(IC_INTTYPE, rt305x_ic_get(IC_INTTYPE) | irqmask);
460220297Sadrian
461220297Sadrian	/* disable */
462220297Sadrian	obio_mask_irq((void*)irq);
463220297Sadrian
464220297Sadrian	result = intr_event_remove_handler(cookie);
465220297Sadrian	if (!result) {
466220297Sadrian		sc->sc_eventstab[irq] = NULL;
467220297Sadrian	}
468220297Sadrian
469220297Sadrian	return (result);
470220297Sadrian}
471220297Sadrian
472220297Sadrianstatic int
473220297Sadrianobio_intr(void *arg)
474220297Sadrian{
475220297Sadrian	struct obio_softc *sc = arg;
476220297Sadrian	struct intr_event *event;
477220297Sadrian	uint32_t irqstat;
478220297Sadrian	int irq;
479220297Sadrian
480220297Sadrian	irqstat = rt305x_ic_get(IC_IRQ0STAT);
481220297Sadrian	irqstat |= rt305x_ic_get(IC_IRQ1STAT);
482220297Sadrian
483220297Sadrian	irq = 0;
484220297Sadrian	while (irqstat != 0) {
485220297Sadrian		if ((irqstat & 1) == 1) {
486220297Sadrian			event = sc->sc_eventstab[irq];
487220297Sadrian			if (!event || TAILQ_EMPTY(&event->ie_handlers))
488220297Sadrian				continue;
489220297Sadrian
490220297Sadrian			/* TODO: pass frame as an argument*/
491220297Sadrian			/* TODO: log stray interrupt */
492220297Sadrian			intr_event_handle(event, NULL);
493220297Sadrian		}
494220297Sadrian		irq++;
495220297Sadrian		irqstat >>= 1;
496220297Sadrian	}
497220297Sadrian
498220297Sadrian	return (FILTER_HANDLED);
499220297Sadrian}
500220297Sadrian
501220297Sadrianstatic void
502220297Sadrianobio_add_res_child(device_t bus, const char *dname, int dunit,
503220297Sadrian    long maddr, int msize, int irq)
504220297Sadrian{
505220297Sadrian	device_t		child;
506220297Sadrian	int			result;
507220297Sadrian
508220297Sadrian	child = BUS_ADD_CHILD(bus, 0, dname, dunit);
509220297Sadrian
510220297Sadrian	result = bus_set_resource(child, SYS_RES_MEMORY, 0,
511220297Sadrian	    maddr, msize);
512220297Sadrian	if (result != 0)
513220297Sadrian		device_printf(bus, "warning: bus_set_resource() failed\n");
514220297Sadrian
515220297Sadrian	if (irq != -1) {
516220297Sadrian		result = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
517220297Sadrian		if (result != 0)
518220297Sadrian			device_printf(bus,
519220297Sadrian			    "warning: bus_set_resource() failed\n");
520220297Sadrian	}
521220297Sadrian}
522220297Sadrian
523220297Sadrianstatic void
524220297Sadrianobio_hinted_child(device_t bus, const char *dname, int dunit)
525220297Sadrian{
526220297Sadrian	long			maddr;
527220297Sadrian	int			msize;
528220297Sadrian	int			irq;
529220297Sadrian
530220297Sadrian	/*
531220297Sadrian	 * Set hard-wired resources for hinted child using
532220297Sadrian	 * specific RIDs.
533220297Sadrian	 */
534220297Sadrian	resource_long_value(dname, dunit, "maddr", &maddr);
535220297Sadrian	resource_int_value(dname, dunit, "msize", &msize);
536220297Sadrian
537220297Sadrian
538220297Sadrian	if (resource_int_value(dname, dunit, "irq", &irq) == 0) irq = -1;
539220297Sadrian
540220297Sadrian	obio_add_res_child(bus, dname, dunit, maddr, msize, irq);
541220297Sadrian}
542220297Sadrian
543220297Sadrianstatic device_t
544220297Sadrianobio_add_child(device_t bus, u_int order, const char *name, int unit)
545220297Sadrian{
546220297Sadrian	device_t		child;
547220297Sadrian	struct obio_ivar	*ivar;
548220297Sadrian
549220297Sadrian	ivar = malloc(sizeof(struct obio_ivar), M_DEVBUF, M_WAITOK | M_ZERO);
550220297Sadrian	resource_list_init(&ivar->resources);
551220297Sadrian
552220297Sadrian	child = device_add_child_ordered(bus, order, name, unit);
553220297Sadrian	if (child == NULL) {
554220297Sadrian		printf("Can't add child %s%d ordered\n", name, unit);
555220297Sadrian		return (0);
556220297Sadrian	}
557220297Sadrian
558220297Sadrian	device_set_ivars(child, ivar);
559220297Sadrian
560220297Sadrian	return (child);
561220297Sadrian}
562220297Sadrian
563220297Sadrian/*
564220297Sadrian * Helper routine for bus_generic_rl_get_resource/bus_generic_rl_set_resource
565220297Sadrian * Provides pointer to resource_list for these routines
566220297Sadrian */
567220297Sadrianstatic struct resource_list *
568220297Sadrianobio_get_resource_list(device_t dev, device_t child)
569220297Sadrian{
570220297Sadrian	struct obio_ivar *ivar;
571220297Sadrian
572220297Sadrian	ivar = device_get_ivars(child);
573220297Sadrian	return (&(ivar->resources));
574220297Sadrian}
575220297Sadrian
576220297Sadrianstatic int
577220297Sadrianobio_print_all_resources(device_t dev)
578220297Sadrian{
579220297Sadrian	struct obio_ivar *ivar = device_get_ivars(dev);
580220297Sadrian	struct resource_list *rl = &ivar->resources;
581220297Sadrian	int retval = 0;
582220297Sadrian
583220297Sadrian	if (STAILQ_FIRST(rl))
584220297Sadrian		retval += printf(" at");
585220297Sadrian
586297199Sjhibbits	retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
587297199Sjhibbits	retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
588220297Sadrian
589220297Sadrian	return (retval);
590220297Sadrian}
591220297Sadrian
592220297Sadrianstatic int
593220297Sadrianobio_print_child(device_t bus, device_t child)
594220297Sadrian{
595220297Sadrian	int retval = 0;
596220297Sadrian
597220297Sadrian	retval += bus_print_child_header(bus, child);
598220297Sadrian	retval += obio_print_all_resources(child);
599220297Sadrian	if (device_get_flags(child))
600220297Sadrian		retval += printf(" flags %#x", device_get_flags(child));
601220297Sadrian	retval += printf(" on %s\n", device_get_nameunit(bus));
602220297Sadrian
603220297Sadrian	return (retval);
604220297Sadrian}
605220297Sadrian
606220297Sadrianstatic device_method_t obio_methods[] = {
607220297Sadrian	DEVMETHOD(bus_activate_resource,	obio_activate_resource),
608220297Sadrian	DEVMETHOD(bus_add_child,		obio_add_child),
609220297Sadrian	DEVMETHOD(bus_alloc_resource,		obio_alloc_resource),
610220297Sadrian	DEVMETHOD(bus_deactivate_resource,	obio_deactivate_resource),
611220297Sadrian	DEVMETHOD(bus_get_resource_list,	obio_get_resource_list),
612220297Sadrian	DEVMETHOD(bus_hinted_child,		obio_hinted_child),
613220297Sadrian	DEVMETHOD(bus_print_child,		obio_print_child),
614220297Sadrian	DEVMETHOD(bus_release_resource,		obio_release_resource),
615220297Sadrian	DEVMETHOD(bus_setup_intr,		obio_setup_intr),
616220297Sadrian	DEVMETHOD(bus_teardown_intr,		obio_teardown_intr),
617220297Sadrian	DEVMETHOD(device_attach,		obio_attach),
618220297Sadrian	DEVMETHOD(device_probe,			obio_probe),
619220297Sadrian        DEVMETHOD(bus_get_resource,		bus_generic_rl_get_resource),
620220297Sadrian        DEVMETHOD(bus_set_resource,		bus_generic_rl_set_resource),
621220297Sadrian
622220297Sadrian	{0, 0},
623220297Sadrian};
624220297Sadrian
625220297Sadrianstatic driver_t obio_driver = {
626220297Sadrian	"obio",
627220297Sadrian	obio_methods,
628220297Sadrian	sizeof(struct obio_softc),
629220297Sadrian};
630220297Sadrianstatic devclass_t obio_devclass;
631220297Sadrian
632220297SadrianDRIVER_MODULE(obio, nexus, obio_driver, obio_devclass, 0, 0);
633