obio.c revision 265999
1/*	$NetBSD: obio.c,v 1.11 2003/07/15 00:25:05 lukem Exp $	*/
2
3/*-
4 * Copyright (c) 2001, 2002, 2003 Wasabi Systems, Inc.
5 * All rights reserved.
6 *
7 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: stable/10/sys/mips/rt305x/obio.c 265999 2014-05-14 01:35:43Z ian $");
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/bus.h>
37#include <sys/interrupt.h>
38#include <sys/kernel.h>
39#include <sys/module.h>
40#include <sys/rman.h>
41#include <sys/malloc.h>
42
43#include <machine/bus.h>
44
45#include <mips/rt305x/rt305xreg.h>
46#include <mips/rt305x/obiovar.h>
47#include <mips/rt305x/rt305x_icvar.h>
48
49/* MIPS HW interrupts of IRQ/FIQ respectively */
50#define RT305X_INTR		0
51#define RT305X_FAST_INTR	1
52
53/* Interrupt levels */
54#define INTR_IRQ 0
55#define INTR_FIQ 1
56
57
58int irq_priorities[NIRQS] = {
59	INTR_IRQ,	/* SYSCTL */
60	INTR_FIQ,	/* TIMER0 */
61	INTR_FIQ,	/* WDTIMER */
62	INTR_IRQ,	/* Illegal Access */
63	INTR_IRQ,	/* PCM */
64	INTR_IRQ,	/* UART */
65	INTR_IRQ,	/* GPIO */
66	INTR_FIQ,	/* GDMA */
67	INTR_IRQ,	/* NAND */
68	INTR_IRQ,	/* Perfomance Counter */
69	INTR_IRQ,	/* I2S */
70	INTR_IRQ,	/* unknown */
71	INTR_IRQ,	/* UARTLITE */
72	INTR_IRQ,	/* unknown */
73	INTR_IRQ,	/* unknown */
74	INTR_IRQ,	/* unknown */
75	INTR_IRQ,	/* unknown */
76	INTR_IRQ,	/* EtherNet Switch */
77	INTR_FIQ,	/* OTG */
78	INTR_IRQ,	/* unknown */
79	INTR_IRQ,	/* unknown */
80	INTR_IRQ,	/* unknown */
81	INTR_IRQ,	/* unknown */
82	INTR_IRQ,	/* unknown */
83	INTR_IRQ,	/* unknown */
84	INTR_IRQ,	/* unknown */
85	INTR_IRQ,	/* unknown */
86	INTR_IRQ,	/* unknown */
87	INTR_IRQ,	/* unknown */
88	INTR_IRQ,	/* unknown */
89	INTR_IRQ,	/* unknown */
90	INTR_IRQ,	/* unknown */
91};
92
93
94#define REG_READ(o) *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1(INTCTL_BASE + (o)))
95#define REG_WRITE(o,v) (REG_READ(o)) = (v)
96
97static int	obio_activate_resource(device_t, device_t, int, int,
98		    struct resource *);
99static device_t	obio_add_child(device_t, u_int, const char *, int);
100static struct resource *
101		obio_alloc_resource(device_t, device_t, int, int *, u_long,
102		    u_long, u_long, u_int);
103static int	obio_attach(device_t);
104static int	obio_deactivate_resource(device_t, device_t, int, int,
105		    struct resource *);
106static struct resource_list *
107		obio_get_resource_list(device_t, device_t);
108static void	obio_add_res_child(device_t, const char *, int, long, int, int);
109static void	obio_hinted_child(device_t, const char *, int);
110static int	obio_intr(void *);
111static int	obio_probe(device_t);
112static int	obio_release_resource(device_t, device_t, int, int,
113		    struct resource *);
114static int	obio_setup_intr(device_t, device_t, struct resource *, int,
115		    driver_filter_t *, driver_intr_t *, void *, void **);
116static int	obio_teardown_intr(device_t, device_t, struct resource *,
117		    void *);
118
119static void
120obio_mask_irq(void *source)
121{
122	int irq;
123	uint32_t irqmask;
124
125	irq = (int)source;
126	irqmask = 1 << irq;
127
128	/* disable IRQ */
129	rt305x_ic_set(IC_INT_DIS, irqmask);
130}
131
132static void
133obio_unmask_irq(void *source)
134{
135	int irq;
136	uint32_t irqmask;
137
138	irq = (int)source;
139	irqmask = 1 << irq;
140
141	/* enable IRQ */
142	rt305x_ic_set(IC_INT_ENA, irqmask);
143
144}
145
146
147static int
148obio_probe(device_t dev)
149{
150
151	return (BUS_PROBE_NOWILDCARD);
152}
153
154static int
155obio_attach(device_t dev)
156{
157	struct obio_softc *sc = device_get_softc(dev);
158	int rid;
159
160	sc->oba_mem_rman.rm_type = RMAN_ARRAY;
161	sc->oba_mem_rman.rm_descr = "OBIO memory";
162	if (rman_init(&sc->oba_mem_rman) != 0 ||
163	    rman_manage_region(&sc->oba_mem_rman, OBIO_MEM_START,
164	        OBIO_MEM_END) != 0)
165		panic("obio_attach: failed to set up I/O rman");
166
167	sc->oba_irq_rman.rm_type = RMAN_ARRAY;
168	sc->oba_irq_rman.rm_descr = "OBIO IRQ";
169	if (rman_init(&sc->oba_irq_rman) != 0 ||
170	    rman_manage_region(&sc->oba_irq_rman, 0, NIRQS-1) != 0)
171		panic("obio_attach: failed to set up IRQ rman");
172
173	/* Hook up our interrupt handler. */
174	if ((sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
175	    RT305X_INTR, RT305X_INTR, 1,
176	    RF_SHAREABLE | RF_ACTIVE)) == NULL) {
177		device_printf(dev, "unable to allocate IRQ resource\n");
178		return (ENXIO);
179	}
180
181	if ((bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC, obio_intr, NULL,
182	    sc, &sc->sc_ih))) {
183		device_printf(dev,
184		    "WARNING: unable to register interrupt handler\n");
185		return (ENXIO);
186	}
187
188	/* Hook up our FAST interrupt handler. */
189	if ((sc->sc_fast_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
190	    RT305X_FAST_INTR, RT305X_FAST_INTR, 1,
191	    RF_SHAREABLE | RF_ACTIVE)) == NULL) {
192		device_printf(dev, "unable to allocate IRQ resource\n");
193		return (ENXIO);
194	}
195
196	if ((bus_setup_intr(dev, sc->sc_fast_irq, INTR_TYPE_MISC, obio_intr,
197	    NULL, sc, &sc->sc_fast_ih))) {
198		device_printf(dev,
199		    "WARNING: unable to register interrupt handler\n");
200		return (ENXIO);
201	}
202
203	/* disable all interrupts */
204	rt305x_ic_set(IC_INT_DIS, IC_INT_MASK|IC_LINE_GLOBAL);
205
206	bus_generic_probe(dev);
207
208	obio_add_res_child(dev, "rt305x_sysctl", 0,
209	    SYSCTL_BASE, (SYSCTL_END - SYSCTL_BASE + 1),
210	    IC_SYSCTL);
211	obio_add_res_child(dev, "rt305x_ic", 0,
212	    INTCTL_BASE, (INTCTL_END - INTCTL_BASE + 1),
213	    -1);
214#ifdef notyet
215	obio_add_res_child(dev, "timer",0,
216	    TIMER_BASE, (TIMER_END - TIMER_BASE  + 1),
217	    IC_TIMER0);
218	obio_add_res_child(dev, "rt305x_memc", 0,
219	    MEMCTRL_BASE, (MEMCTRL_END - MEMCTRL_BASE + 1),
220	    -1);
221	obio_add_res_child(dev, "pcm", 	0,
222	    PCM_BASE, (PCM_END - PCM_BASE  + 1),
223	    IC_PCM);
224	obio_add_res_child(dev, "uart", 0,
225	    UART_BASE, (UART_END - UART_BASE + 1),
226	    IC_UART);
227#endif
228	obio_add_res_child(dev, "gpio", 0,
229	    PIO_BASE, (PIO_END - PIO_BASE  + 1),
230	    IC_PIO);
231#ifdef notyet
232	obio_add_res_child(dev, "rt305x_dma", 0,
233	    GDMA_BASE, (GDMA_END - GDMA_BASE + 1),
234	    IC_DMA);
235	obio_add_res_child(dev, "rt305x_nandc", 0,
236	    NANDFC_BASE, (NANDFC_END - NANDFC_BASE  + 1),
237	    IC_NAND);
238	obio_add_res_child(dev, "i2c", 	0,
239	    I2C_BASE, (I2C_END - I2C_BASE  + 1),
240	    -1);
241	obio_add_res_child(dev, "i2s", 0,
242	    I2S_BASE, (I2S_END - I2S_BASE  + 1),
243	    IC_I2S);
244	obio_add_res_child(dev, "spi", 0,
245	    SPI_BASE, (SPI_END - SPI_BASE  + 1),
246	    -1);
247#endif
248	obio_add_res_child(dev, "uart", 1,
249	    UARTLITE_BASE, (UARTLITE_END - UARTLITE_BASE + 1),
250	    IC_UARTLITE);
251	obio_add_res_child(dev, "cfi", 	0,
252	    FLASH_BASE, (FLASH_END - FLASH_BASE  + 1),
253	    -1);
254	obio_add_res_child(dev, "dotg", 0,
255	    USB_OTG_BASE, (USB_OTG_END - USB_OTG_BASE  + 1),
256	    IC_OTG);
257	obio_add_res_child(dev, "switch", 0,
258	    ETHSW_BASE, (ETHSW_END - ETHSW_BASE  + 1),
259	    IC_ETHSW);
260
261	bus_enumerate_hinted_children(dev);
262	bus_generic_attach(dev);
263
264	/* enable IC */
265	rt305x_ic_set(IC_INT_ENA, IC_LINE_GLOBAL);
266
267	return (0);
268}
269
270static struct resource *
271obio_alloc_resource(device_t bus, device_t child, int type, int *rid,
272    u_long start, u_long end, u_long count, u_int flags)
273{
274	struct obio_softc		*sc = device_get_softc(bus);
275	struct obio_ivar		*ivar = device_get_ivars(child);
276	struct resource			*rv;
277	struct resource_list_entry	*rle;
278	struct rman			*rm;
279	int				 isdefault, needactivate, passthrough;
280
281	isdefault = (start == 0UL && end == ~0UL && count == 1);
282	needactivate = flags & RF_ACTIVE;
283	passthrough = (device_get_parent(child) != bus);
284	rle = NULL;
285
286	if (passthrough)
287		return (BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type,
288		    rid, start, end, count, flags));
289
290	/*
291	 * If this is an allocation of the "default" range for a given RID,
292	 * and we know what the resources for this device are (ie. they aren't
293	 * maintained by a child bus), then work out the start/end values.
294	 */
295	if (isdefault) {
296		rle = resource_list_find(&ivar->resources, type, *rid);
297		if (rle == NULL)
298			return (NULL);
299		if (rle->res != NULL) {
300			panic("%s: resource entry is busy", __func__);
301		}
302		start = rle->start;
303		end = rle->end;
304		count = rle->count;
305	}
306
307	switch (type) {
308	case SYS_RES_IRQ:
309		rm = &sc->oba_irq_rman;
310		break;
311	case SYS_RES_MEMORY:
312		rm = &sc->oba_mem_rman;
313		break;
314	default:
315		printf("%s: unknown resource type %d\n", __func__, type);
316		return (0);
317	}
318
319	rv = rman_reserve_resource(rm, start, end, count, flags, child);
320	if (rv == 0) {
321		printf("%s: could not reserve resource\n", __func__);
322		return (0);
323	}
324
325	rman_set_rid(rv, *rid);
326
327	if (needactivate) {
328		if (bus_activate_resource(child, type, *rid, rv)) {
329			printf("%s: could not activate resource\n", __func__);
330			rman_release_resource(rv);
331			return (0);
332		}
333	}
334
335	return (rv);
336}
337
338static int
339obio_activate_resource(device_t bus, device_t child, int type, int rid,
340    struct resource *r)
341{
342
343	/*
344	 * If this is a memory resource, track the direct mapping
345	 * in the uncached MIPS KSEG1 segment.
346	 */
347	if (type == SYS_RES_MEMORY) {
348		void *vaddr;
349
350		vaddr = (void *)MIPS_PHYS_TO_KSEG1((intptr_t)rman_get_start(r));
351		rman_set_virtual(r, vaddr);
352		rman_set_bustag(r, mips_bus_space_generic);
353		rman_set_bushandle(r, (bus_space_handle_t)vaddr);
354	}
355
356	return (rman_activate_resource(r));
357}
358
359static int
360obio_deactivate_resource(device_t bus, device_t child, int type, int rid,
361    struct resource *r)
362{
363
364	return (rman_deactivate_resource(r));
365}
366
367static int
368obio_release_resource(device_t dev, device_t child, int type,
369    int rid, struct resource *r)
370{
371	struct resource_list *rl;
372	struct resource_list_entry *rle;
373
374	rl = obio_get_resource_list(dev, child);
375	if (rl == NULL)
376		return (EINVAL);
377	rle = resource_list_find(rl, type, rid);
378	if (rle == NULL)
379		return (EINVAL);
380	rman_release_resource(r);
381	rle->res = NULL;
382
383	return (0);
384}
385
386static int
387obio_setup_intr(device_t dev, device_t child, struct resource *ires,
388		int flags, driver_filter_t *filt, driver_intr_t *handler,
389		void *arg, void **cookiep)
390{
391	struct obio_softc *sc = device_get_softc(dev);
392	struct intr_event *event;
393	int irq, error, priority;
394	uint32_t irqmask;
395
396	irq = rman_get_start(ires);
397
398	if (irq >= NIRQS)
399		panic("%s: bad irq %d", __func__, irq);
400
401	event = sc->sc_eventstab[irq];
402	if (event == NULL) {
403		error = intr_event_create(&event, (void *)irq, 0, irq,
404		    obio_mask_irq, obio_unmask_irq,
405		    NULL, NULL, "obio intr%d:", irq);
406
407		sc->sc_eventstab[irq] = event;
408	}
409	else
410		panic("obio: Can't share IRQs");
411
412	intr_event_add_handler(event, device_get_nameunit(child), filt,
413	    handler, arg, intr_priority(flags), flags, cookiep);
414
415	irqmask = 1 << irq;
416	priority = irq_priorities[irq];
417
418	if (priority == INTR_FIQ)
419		rt305x_ic_set(IC_INTTYPE, rt305x_ic_get(IC_INTTYPE) | irqmask);
420	else
421		rt305x_ic_set(IC_INTTYPE, rt305x_ic_get(IC_INTTYPE) & ~irqmask);
422
423	/* enable */
424	obio_unmask_irq((void*)irq);
425
426	return (0);
427}
428
429static int
430obio_teardown_intr(device_t dev, device_t child, struct resource *ires,
431    void *cookie)
432{
433	struct obio_softc *sc = device_get_softc(dev);
434	int irq, result, priority;
435	uint32_t irqmask;
436
437	irq = rman_get_start(ires);
438	if (irq >= NIRQS)
439		panic("%s: bad irq %d", __func__, irq);
440
441	if (sc->sc_eventstab[irq] == NULL)
442		panic("Trying to teardown unoccupied IRQ");
443
444	irqmask = (1 << irq);
445	priority = irq_priorities[irq];
446
447	if (priority == INTR_FIQ)
448		rt305x_ic_set(IC_INTTYPE, rt305x_ic_get(IC_INTTYPE) & ~irqmask);
449	else
450		rt305x_ic_set(IC_INTTYPE, rt305x_ic_get(IC_INTTYPE) | irqmask);
451
452	/* disable */
453	obio_mask_irq((void*)irq);
454
455	result = intr_event_remove_handler(cookie);
456	if (!result) {
457		sc->sc_eventstab[irq] = NULL;
458	}
459
460	return (result);
461}
462
463static int
464obio_intr(void *arg)
465{
466	struct obio_softc *sc = arg;
467	struct intr_event *event;
468	uint32_t irqstat;
469	int irq;
470
471	irqstat = rt305x_ic_get(IC_IRQ0STAT);
472	irqstat |= rt305x_ic_get(IC_IRQ1STAT);
473
474	irq = 0;
475	while (irqstat != 0) {
476		if ((irqstat & 1) == 1) {
477			event = sc->sc_eventstab[irq];
478			if (!event || TAILQ_EMPTY(&event->ie_handlers))
479				continue;
480
481			/* TODO: pass frame as an argument*/
482			/* TODO: log stray interrupt */
483			intr_event_handle(event, NULL);
484		}
485		irq++;
486		irqstat >>= 1;
487	}
488
489	return (FILTER_HANDLED);
490}
491
492static void
493obio_add_res_child(device_t bus, const char *dname, int dunit,
494    long maddr, int msize, int irq)
495{
496	device_t		child;
497	int			result;
498
499	child = BUS_ADD_CHILD(bus, 0, dname, dunit);
500
501	result = bus_set_resource(child, SYS_RES_MEMORY, 0,
502	    maddr, msize);
503	if (result != 0)
504		device_printf(bus, "warning: bus_set_resource() failed\n");
505
506	if (irq != -1) {
507		result = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
508		if (result != 0)
509			device_printf(bus,
510			    "warning: bus_set_resource() failed\n");
511	}
512}
513
514static void
515obio_hinted_child(device_t bus, const char *dname, int dunit)
516{
517	long			maddr;
518	int			msize;
519	int			irq;
520
521	/*
522	 * Set hard-wired resources for hinted child using
523	 * specific RIDs.
524	 */
525	resource_long_value(dname, dunit, "maddr", &maddr);
526	resource_int_value(dname, dunit, "msize", &msize);
527
528
529	if (resource_int_value(dname, dunit, "irq", &irq) == 0) irq = -1;
530
531	obio_add_res_child(bus, dname, dunit, maddr, msize, irq);
532}
533
534static device_t
535obio_add_child(device_t bus, u_int order, const char *name, int unit)
536{
537	device_t		child;
538	struct obio_ivar	*ivar;
539
540	ivar = malloc(sizeof(struct obio_ivar), M_DEVBUF, M_WAITOK | M_ZERO);
541	if (ivar == NULL) {
542		printf("Failed to allocate ivar\n");
543		return (0);
544	}
545	resource_list_init(&ivar->resources);
546
547	child = device_add_child_ordered(bus, order, name, unit);
548	if (child == NULL) {
549		printf("Can't add child %s%d ordered\n", name, unit);
550		return (0);
551	}
552
553	device_set_ivars(child, ivar);
554
555	return (child);
556}
557
558/*
559 * Helper routine for bus_generic_rl_get_resource/bus_generic_rl_set_resource
560 * Provides pointer to resource_list for these routines
561 */
562static struct resource_list *
563obio_get_resource_list(device_t dev, device_t child)
564{
565	struct obio_ivar *ivar;
566
567	ivar = device_get_ivars(child);
568	return (&(ivar->resources));
569}
570
571static int
572obio_print_all_resources(device_t dev)
573{
574	struct obio_ivar *ivar = device_get_ivars(dev);
575	struct resource_list *rl = &ivar->resources;
576	int retval = 0;
577
578	if (STAILQ_FIRST(rl))
579		retval += printf(" at");
580
581	retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
582	retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
583
584	return (retval);
585}
586
587static int
588obio_print_child(device_t bus, device_t child)
589{
590	int retval = 0;
591
592	retval += bus_print_child_header(bus, child);
593	retval += obio_print_all_resources(child);
594	if (device_get_flags(child))
595		retval += printf(" flags %#x", device_get_flags(child));
596	retval += printf(" on %s\n", device_get_nameunit(bus));
597
598	return (retval);
599}
600
601static device_method_t obio_methods[] = {
602	DEVMETHOD(bus_activate_resource,	obio_activate_resource),
603	DEVMETHOD(bus_add_child,		obio_add_child),
604	DEVMETHOD(bus_alloc_resource,		obio_alloc_resource),
605	DEVMETHOD(bus_deactivate_resource,	obio_deactivate_resource),
606	DEVMETHOD(bus_get_resource_list,	obio_get_resource_list),
607	DEVMETHOD(bus_hinted_child,		obio_hinted_child),
608	DEVMETHOD(bus_print_child,		obio_print_child),
609	DEVMETHOD(bus_release_resource,		obio_release_resource),
610	DEVMETHOD(bus_setup_intr,		obio_setup_intr),
611	DEVMETHOD(bus_teardown_intr,		obio_teardown_intr),
612	DEVMETHOD(device_attach,		obio_attach),
613	DEVMETHOD(device_probe,			obio_probe),
614        DEVMETHOD(bus_get_resource,		bus_generic_rl_get_resource),
615        DEVMETHOD(bus_set_resource,		bus_generic_rl_set_resource),
616
617	{0, 0},
618};
619
620static driver_t obio_driver = {
621	"obio",
622	obio_methods,
623	sizeof(struct obio_softc),
624};
625static devclass_t obio_devclass;
626
627DRIVER_MODULE(obio, nexus, obio_driver, obio_devclass, 0, 0);
628