svn commit: r236939 - in user/jceel/soc2012_armv6/sys: arm/arm arm/conf arm/include arm/lpc boot/fdt/dts conf dev/fdt

Jakub Wojciech Klama jceel at FreeBSD.org
Tue Jun 12 01:14:00 UTC 2012


Author: jceel
Date: Tue Jun 12 01:13:59 2012
New Revision: 236939
URL: http://svn.freebsd.org/changeset/base/236939

Log:
  Refactored interrupt routing mechanism. Uses NEWBUS interface
  pic_if.m similar to powerpc implementation. It's organized in
  hierarchy where top-level interrupt controller is ARM core
  itself serving one IRQ. SoC interrupt controllers can bind
  handlers to this IRQ and provide more multiplexed IRQs to
  children.
  
  Example implementation includes LPC3250 interrupt controller
  (lpc_intc.c).
  
  It's not bug-free, but tested on LPC3250 (arm/lpc) port.

Added:
  user/jceel/soc2012_armv6/sys/arm/arm/intrng.c
  user/jceel/soc2012_armv6/sys/arm/arm/pic_if.m
Modified:
  user/jceel/soc2012_armv6/sys/arm/arm/nexus.c
  user/jceel/soc2012_armv6/sys/arm/conf/EA3250
  user/jceel/soc2012_armv6/sys/arm/include/fdt.h
  user/jceel/soc2012_armv6/sys/arm/include/intr.h
  user/jceel/soc2012_armv6/sys/arm/lpc/lpc_intc.c
  user/jceel/soc2012_armv6/sys/arm/lpc/lpcreg.h
  user/jceel/soc2012_armv6/sys/boot/fdt/dts/ea3250.dts
  user/jceel/soc2012_armv6/sys/conf/files.arm
  user/jceel/soc2012_armv6/sys/conf/options.arm
  user/jceel/soc2012_armv6/sys/dev/fdt/fdt_common.c
  user/jceel/soc2012_armv6/sys/dev/fdt/fdtbus.c
  user/jceel/soc2012_armv6/sys/dev/fdt/simplebus.c

Added: user/jceel/soc2012_armv6/sys/arm/arm/intrng.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/jceel/soc2012_armv6/sys/arm/arm/intrng.c	Tue Jun 12 01:13:59 2012	(r236939)
@@ -0,0 +1,333 @@
+/*-
+ * Copyright (c) 2012 Jakub Wojciech Klama <jceel at FreeBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by Mark Brinicombe
+ *	for the NetBSD Project.
+ * 4. The name of the company nor the name of the author may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/syslog.h> 
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/bus.h>
+#include <sys/interrupt.h>
+#include <sys/conf.h>
+#include <machine/atomic.h>
+#include <machine/intr.h>
+#include <machine/cpu.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "pic_if.h"
+
+#define	IRQ_PIC_IDX(_irq)	((_irq >> 8) & 0xff)
+#define	IRQ_VECTOR_IDX(_irq)	((_irq) & 0xff)
+#define	IRQ_GEN(_pic, _irq)	(((_pic) << 8) | ((_irq) & 0xff))
+#define	CORE_PIC_IDX		(0)
+#define	CORE_PIC_NODE		(0xffffffff)
+
+#ifdef DEBUG
+#define debugf(fmt, args...) do { printf("%s(): ", __func__);	\
+    printf(fmt,##args); } while (0)
+#else
+#define debugf(fmt, args...)
+#endif
+
+typedef void (*mask_fn)(void *);
+
+struct arm_intr_controller {
+	device_t		ic_dev;
+	phandle_t		ic_node;
+	struct arm_intr_data	ic_id;
+};
+
+struct arm_intr_handler {
+	device_t		ih_dev;
+	int			ih_intrcnt;
+	int			ih_irq;
+	struct intr_event *	ih_event;
+	struct arm_intr_controller *ih_pic;
+	struct arm_intr_controller *ih_self;
+};
+
+static void arm_mask_irq(void *);
+static void arm_unmask_irq(void *);
+static void arm_eoi(void *);
+
+static struct arm_intr_handler arm_intrs[NIRQ];
+static struct arm_intr_controller arm_pics[NPIC];
+
+void
+arm_dispatch_irq(device_t dev, struct trapframe *tf, int irq)
+{
+	struct arm_intr_handler *ih = NULL;
+	void *arg;
+	int i;
+
+	debugf("pic %s, tf %p, irq %d\n", device_get_nameunit(dev), tf, irq);
+
+	for (i = 0; arm_intrs[i].ih_dev != NULL; i++) {
+		if (arm_intrs[i].ih_pic->ic_dev == dev &&
+		    arm_intrs[i].ih_irq == irq) {
+			ih = &arm_intrs[i];
+			break;
+		}
+	}
+
+	if (ih == NULL)
+		panic("arm_dispatch_irq: unknown irq");
+
+	debugf("requested by %s\n", device_get_nameunit(ih->ih_dev));
+
+	arg = tf;
+
+	/* XXX */
+	for (i = 0; arm_pics[i].ic_dev != NULL; i++)
+		arm_pics[i].ic_id.tf = tf;
+
+	ih->ih_intrcnt++;
+	if (intr_event_handle(ih->ih_event, tf) != 0) {
+		/* Stray IRQ */
+		arm_mask_irq(ih);
+	}
+}
+
+void	arm_handler_execute(struct trapframe *, int);
+
+static struct arm_intr_handler *
+arm_lookup_intr_handler(device_t pic, int irq)
+{
+	int i;
+
+	for (i = 0; i < NIRQ; i++) {
+		if (arm_intrs[i].ih_pic != NULL &&
+		    arm_intrs[i].ih_pic->ic_dev == pic &&
+		    arm_intrs[i].ih_irq == irq)
+			return (&arm_intrs[i]);
+
+		if (arm_intrs[i].ih_dev == NULL)
+			return (&arm_intrs[i]);
+	}
+
+	return NULL;
+}
+
+int
+arm_fdt_map_irq(phandle_t ic, int irq)
+{
+	int i;
+
+	debugf("ic %08x irq %d\n", ic, irq);
+
+	if (ic == CORE_PIC_NODE)
+		return (IRQ_GEN(CORE_PIC_IDX, irq));
+
+	for (i = 0; arm_pics[i].ic_node != 0; i++) {
+		if (arm_pics[i].ic_node	== ic)
+			return (IRQ_GEN(i, irq));
+	}
+
+	/* 
+	 * Interrupt controller is not registered yet, so
+	 * we map a stub for it. 'i' is pointing to free
+	 * first slot in arm_pics table.
+	 */
+	arm_pics[i].ic_node = ic;
+	return (IRQ_GEN(i, irq));
+}
+
+const char *
+arm_describe_irq(int irq)
+{
+	struct arm_intr_controller *pic;
+	static char buffer[32];
+
+	pic = &arm_pics[IRQ_PIC_IDX(irq)];
+	sprintf(buffer, "%s:%d", device_get_nameunit(pic->ic_dev),
+	    IRQ_VECTOR_IDX(irq));
+
+	return (buffer);
+}
+
+void
+arm_register_pic(device_t dev)
+{
+	struct arm_intr_controller *ic = NULL;
+	phandle_t node;
+	int i;
+
+	node = ofw_bus_get_node(dev);
+
+	/* Find room for IC */
+	for (i = 0; i < NPIC; i++) {
+		if (arm_pics[i].ic_dev != NULL)
+			continue;
+
+		if (arm_pics[i].ic_node == node) {
+			ic = &arm_pics[i];
+			break;
+		}
+
+		if (arm_pics[i].ic_node == 0) {
+			ic = &arm_pics[i];
+			break;
+		}
+	}
+
+	if (ic == NULL)
+		panic("not enough room to register interrupt controller");
+
+	ic->ic_dev = dev;
+	ic->ic_node = node;
+
+	debugf("device %s node %08x\n", device_get_nameunit(dev), ic->ic_node);
+
+	device_printf(dev, "registered as interrupt controller\n");
+}
+
+void
+arm_setup_irqhandler(device_t dev, driver_filter_t *filt, 
+    void (*hand)(void*), void *arg, int irq, int flags, void **cookiep)
+{
+	struct arm_intr_controller *pic;
+	struct arm_intr_handler *ih;
+	struct arm_intr_data *id;
+	int error;
+
+	if (irq < 0)
+		return;
+
+	pic = &arm_pics[IRQ_PIC_IDX(irq)];
+	ih = arm_lookup_intr_handler(pic->ic_dev, IRQ_VECTOR_IDX(irq));
+
+	debugf("setup irq %d on %s\n", IRQ_VECTOR_IDX(irq),
+	    device_get_nameunit(pic->ic_dev));
+
+	debugf("pic %p, ih %p\n", pic, ih);
+
+	if (ih->ih_event == NULL) {
+		error = intr_event_create(&ih->ih_event, (void *)ih, 0, irq,
+		    (mask_fn)arm_mask_irq, (mask_fn)arm_unmask_irq,
+		    arm_eoi, NULL, "intr%d:", irq);
+		
+		if (error)
+			return;
+
+		ih->ih_dev = dev;
+		ih->ih_irq = IRQ_VECTOR_IDX(irq);
+		ih->ih_pic = pic;
+
+		arm_unmask_irq(ih);
+
+		debugf("self interrupt controller %p\n", ih->ih_self);
+#if 0
+		last_printed += 
+		    snprintf(intrnames + last_printed,
+		    MAXCOMLEN + 1,
+		    "irq%d: %s", irq, device_get_nameunit(dev));
+		last_printed++;
+		intrcnt_tab[irq] = intrcnt_index;
+		intrcnt_index++;
+		
+#endif
+	}
+
+	if (flags & INTR_CONTROLLER) {
+		struct arm_intr_controller *pic = NULL;
+		int i;
+		for (i = 0; i < NPIC; i++) {
+			if (arm_pics[i].ic_dev == dev)
+				pic = &arm_pics[i];
+		}
+
+		id = &pic->ic_id;
+		id->arg = arg;
+		arg = id;
+	}
+
+	intr_event_add_handler(ih->ih_event, device_get_nameunit(dev), filt, hand, arg,
+	    intr_priority(flags), flags, cookiep);
+
+	debugf("done\n");
+}
+
+int
+arm_remove_irqhandler(int irq, void *cookie)
+{
+	/*
+	struct intr_event *event;
+	int error;
+
+	event = intr_events[irq];
+	arm_mask_irq(irq);
+	
+	error = intr_event_remove_handler(cookie);
+
+	if (!TAILQ_EMPTY(&event->ie_handlers))
+		arm_unmask_irq(irq);
+	return (error);
+	*/
+	return (ENXIO);
+}
+
+void
+arm_mask_irq(void *arg)
+{
+	struct arm_intr_handler *ih = (struct arm_intr_handler *)arg;
+
+	PIC_MASK(ih->ih_pic->ic_dev, ih->ih_irq);
+}
+
+void
+arm_unmask_irq(void *arg)
+{
+	struct arm_intr_handler *ih = (struct arm_intr_handler *)arg;
+
+	PIC_UNMASK(ih->ih_pic->ic_dev, ih->ih_irq);
+}
+
+void
+arm_eoi(void *arg)
+{
+	struct arm_intr_handler *ih = (struct arm_intr_handler *)arg;
+
+	PIC_EOI(ih->ih_pic->ic_dev, ih->ih_irq);
+}
+
+void dosoftints(void);
+void
+dosoftints(void)
+{
+}
+

Modified: user/jceel/soc2012_armv6/sys/arm/arm/nexus.c
==============================================================================
--- user/jceel/soc2012_armv6/sys/arm/arm/nexus.c	Tue Jun 12 00:14:54 2012	(r236938)
+++ user/jceel/soc2012_armv6/sys/arm/arm/nexus.c	Tue Jun 12 01:13:59 2012	(r236939)
@@ -61,6 +61,8 @@ __FBSDID("$FreeBSD$");
 #include <machine/resource.h>
 #include <machine/intr.h>
 
+#include "pic_if.h"
+
 static MALLOC_DEFINE(M_NEXUSDEV, "nexusdev", "Nexus device");
 
 struct nexus_device {
@@ -70,6 +72,7 @@ struct nexus_device {
 #define DEVTONX(dev)	((struct nexus_device *)device_get_ivars(dev))
 
 static struct rman mem_rman;
+static device_t nexus_dev;
 
 static	int nexus_probe(device_t);
 static	int nexus_attach(device_t);
@@ -82,6 +85,11 @@ static	int nexus_activate_resource(devic
 static int nexus_setup_intr(device_t dev, device_t child, struct resource *res,
     int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep);
 static int nexus_teardown_intr(device_t, device_t, struct resource *, void *);
+static void nexus_pic_config(device_t, int, enum intr_trigger, enum intr_polarity);
+static void nexus_pic_mask(device_t, int);
+static void nexus_pic_unmask(device_t, int);
+static void nexus_pic_eoi(device_t, int);
+void arm_handler_execute(struct trapframe *tf, int irqnb);
 
 static device_method_t nexus_methods[] = {
 	/* Device interface */
@@ -94,6 +102,11 @@ static device_method_t nexus_methods[] =
 	DEVMETHOD(bus_activate_resource,	nexus_activate_resource),
 	DEVMETHOD(bus_setup_intr,	nexus_setup_intr),
 	DEVMETHOD(bus_teardown_intr,	nexus_teardown_intr),
+	/* Interrupt controller interface */
+	DEVMETHOD(pic_config,		nexus_pic_config),
+	DEVMETHOD(pic_mask,		nexus_pic_mask),
+	DEVMETHOD(pic_unmask,		nexus_pic_unmask),
+	DEVMETHOD(pic_eoi,		nexus_pic_eoi),
 	{ 0, 0 }
 };
 
@@ -107,9 +120,8 @@ static devclass_t nexus_devclass;
 static int
 nexus_probe(device_t dev)
 {
-
 	device_quiet(dev);	/* suppress attach message for neatness */
-
+	
 	return (BUS_PROBE_DEFAULT);
 }
 
@@ -121,7 +133,7 @@ nexus_setup_intr(device_t dev, device_t 
 	if ((rman_get_flags(res) & RF_SHAREABLE) == 0)
 		flags |= INTR_EXCL;
 
-	arm_setup_irqhandler(device_get_nameunit(child), 
+	arm_setup_irqhandler(child, 
 	    filt, intr, arg, rman_get_start(res), flags, cookiep);
 	return (0);
 }
@@ -144,6 +156,10 @@ nexus_attach(device_t dev)
 	if (rman_init(&mem_rman) || rman_manage_region(&mem_rman, 0, ~0))
 		panic("nexus_probe mem_rman");
 
+	/* Register core interrupt controller */
+	nexus_dev = dev;
+	arm_register_pic(dev);
+
 	/*
 	 * First, deal with the children we know about already
 	 */
@@ -250,4 +266,36 @@ nexus_activate_resource(device_t bus, de
 	return (rman_activate_resource(r));
 }
 
+static void
+nexus_pic_config(device_t bus, int irq, enum intr_trigger trig,
+    enum intr_polarity pol)
+{
+	/* unused */
+}
+
+static void
+nexus_pic_mask(device_t bus, int irq)
+{
+	/* unused */
+}
+
+static void
+nexus_pic_unmask(device_t bus, int irq)
+{
+	/* unused */
+}
+
+static void
+nexus_pic_eoi(device_t bus, int irq)
+{
+	/* unused */
+}
+
+void
+arm_handler_execute(struct trapframe *tf, int irqnb)
+{
+	/* Dispatch root interrupt from core */
+	arm_dispatch_irq(nexus_dev, tf, 0);
+}
+
 DRIVER_MODULE(nexus, root, nexus_driver, nexus_devclass, 0, 0);

Added: user/jceel/soc2012_armv6/sys/arm/arm/pic_if.m
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/jceel/soc2012_armv6/sys/arm/arm/pic_if.m	Tue Jun 12 01:13:59 2012	(r236939)
@@ -0,0 +1,54 @@
+#-
+# Copyright (c) 2012 Jakub Wojciech Klama <jceel at FreeBSD.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+
+#include <sys/bus.h>
+
+INTERFACE pic;
+
+METHOD void config {
+	device_t	dev;
+	int		irq;
+	enum intr_trigger trig;
+	enum intr_polarity pol;
+};
+
+METHOD void eoi {
+	device_t	dev;
+	int		irq;
+};
+
+METHOD void mask {
+	device_t	dev;
+	int		irq;
+};
+
+METHOD void unmask {
+	device_t	dev;
+	int		irq;
+};
+

Modified: user/jceel/soc2012_armv6/sys/arm/conf/EA3250
==============================================================================
--- user/jceel/soc2012_armv6/sys/arm/conf/EA3250	Tue Jun 12 00:14:54 2012	(r236938)
+++ user/jceel/soc2012_armv6/sys/arm/conf/EA3250	Tue Jun 12 01:13:59 2012	(r236939)
@@ -25,6 +25,7 @@ options 	BOOTP
 options 	BOOTP_NFSROOT
 options 	BOOTP_NFSV3
 options 	BOOTP_WIRED_TO=lpe0
+options		ARM_INTRNG
 
 #options 	ROOTDEVNAME=\"ufs:/dev/da0a\"
 

Modified: user/jceel/soc2012_armv6/sys/arm/include/fdt.h
==============================================================================
--- user/jceel/soc2012_armv6/sys/arm/include/fdt.h	Tue Jun 12 00:14:54 2012	(r236938)
+++ user/jceel/soc2012_armv6/sys/arm/include/fdt.h	Tue Jun 12 01:13:59 2012	(r236939)
@@ -42,10 +42,11 @@
 #include <machine/intr.h>
 
 /* Max interrupt number */
-#define FDT_INTR_MAX	NIRQ
+#define FDT_INTR_MAX	(0xffff)
 
 /* Map phandle/intpin pair to global IRQ number */ 
-#define	FDT_MAP_IRQ(node, pin)	(pin)
+#define	FDT_MAP_IRQ(node, pin)	(arm_fdt_map_irq(node, pin))
+#define	FDT_DESCRIBE_IRQ(irq)	(arm_describe_irq(irq))
 
 /*
  * Bus space tag. XXX endianess info needs to be derived from the blob.

Modified: user/jceel/soc2012_armv6/sys/arm/include/intr.h
==============================================================================
--- user/jceel/soc2012_armv6/sys/arm/include/intr.h	Tue Jun 12 00:14:54 2012	(r236938)
+++ user/jceel/soc2012_armv6/sys/arm/include/intr.h	Tue Jun 12 01:13:59 2012	(r236939)
@@ -39,6 +39,33 @@
 #ifndef _MACHINE_INTR_H_
 #define _MACHINE_INTR_H_
 
+#include <machine/psl.h>
+#include <dev/ofw/openfirm.h>
+
+#include "opt_global.h"
+
+#if defined(ARM_INTRNG)
+
+#define	NIRQ		255
+#define	NPIC		16
+#define	INTR_CONTROLLER	INTR_MD1
+
+struct arm_intr_data {
+	void *			arg;
+	struct trapframe *	tf;
+};
+
+int arm_fdt_map_irq(phandle_t ic, int irq);
+const char *arm_describe_irq(int irq);
+void arm_register_pic(device_t dev);
+void arm_unregister_pic(device_t dev);
+void arm_dispatch_irq(device_t dev, struct trapframe *tf, int irq);
+void arm_setup_irqhandler(device_t dev, int (*)(void*), void (*)(void*), 
+    void *, int, int, void **);    
+int arm_remove_irqhandler(int, void *);
+
+#else
+
 /* XXX move to std.* files? */
 #ifdef CPU_XSCALE_81342
 #define NIRQ		128
@@ -56,8 +83,6 @@
 #define NIRQ		32
 #endif
 
-#include <machine/psl.h>
-
 int arm_get_next_irq(int);
 void arm_mask_irq(uintptr_t);
 void arm_unmask_irq(uintptr_t);
@@ -66,6 +91,8 @@ void arm_setup_irqhandler(const char *, 
 int arm_remove_irqhandler(int, void *);
 extern void (*arm_post_filter)(void *);
 
+#endif	/* !ARM_INTRNG */
+
 void gic_init_secondary(void);
 
 #endif	/* _MACHINE_INTR_H */

Modified: user/jceel/soc2012_armv6/sys/arm/lpc/lpc_intc.c
==============================================================================
--- user/jceel/soc2012_armv6/sys/arm/lpc/lpc_intc.c	Tue Jun 12 00:14:54 2012	(r236938)
+++ user/jceel/soc2012_armv6/sys/arm/lpc/lpc_intc.c	Tue Jun 12 01:13:59 2012	(r236939)
@@ -47,22 +47,29 @@ __FBSDID("$FreeBSD$");
 
 #include <arm/lpc/lpcreg.h>
 
+#include "pic_if.h"
+
 struct lpc_intc_softc {
-	struct resource *	li_res;
+	device_t		li_dev;
+	struct resource *	li_mem_res;
+	struct resource *	li_irq_res;
 	bus_space_tag_t		li_bst;
 	bus_space_handle_t	li_bsh;
+	void *			li_intrhand;
 };
 
 static int lpc_intc_probe(device_t);
 static int lpc_intc_attach(device_t);
-static void lpc_intc_eoi(void *);
-
-static struct lpc_intc_softc *intc_softc = NULL;
-
-#define	intc_read_4(reg)		\
-    bus_space_read_4(intc_softc->li_bst, intc_softc->li_bsh, reg)
-#define	intc_write_4(reg, val)		\
-    bus_space_write_4(intc_softc->li_bst, intc_softc->li_bsh, reg, val)
+static int lpc_intc_intr(void *);
+static void lpc_intc_config(device_t, int, enum intr_trigger, enum intr_polarity);
+static void lpc_intc_mask(device_t, int);
+static void lpc_intc_unmask(device_t, int);
+static void lpc_intc_eoi(device_t, int);
+
+#define	intc_read_4(_sc, _reg)		\
+    bus_space_read_4((_sc)->li_bst, (_sc)->li_bsh, _reg)
+#define	intc_write_4(_sc, _reg, _val)		\
+    bus_space_write_4((_sc)->li_bst, (_sc)->li_bsh, _reg, _val)
 
 static int
 lpc_intc_probe(device_t dev)
@@ -81,144 +88,123 @@ lpc_intc_attach(device_t dev)
 	struct lpc_intc_softc *sc = device_get_softc(dev);
 	int rid = 0;
 
-	if (intc_softc)
-		return (ENXIO);
-
-	sc->li_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 
+	sc->li_dev = dev;
+	sc->li_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 
 	    RF_ACTIVE);
-	if (!sc->li_res) {
-		device_printf(dev, "could not alloc resources\n");
+	if (!sc->li_mem_res) {
+		device_printf(dev, "could not alloc memory resource\n");
 		return (ENXIO);
 	}
 
-	sc->li_bst = rman_get_bustag(sc->li_res);
-	sc->li_bsh = rman_get_bushandle(sc->li_res);
-	intc_softc = sc;
-	arm_post_filter = lpc_intc_eoi;
+	rid = 0;
+	sc->li_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+	    RF_ACTIVE | RF_SHAREABLE);
+	if (!sc->li_irq_res) {
+		device_printf(dev, "could not alloc interrupt resource\n");
+		return (ENXIO); // XXX
+	}
 
-	/* Clear interrupt status registers and disable all interrupts */
-	intc_write_4(LPC_INTC_MIC_ER, 0);
-	intc_write_4(LPC_INTC_SIC1_ER, 0);
-	intc_write_4(LPC_INTC_SIC2_ER, 0);
-	intc_write_4(LPC_INTC_MIC_RSR, ~0);
-	intc_write_4(LPC_INTC_SIC1_RSR, ~0);
-	intc_write_4(LPC_INTC_SIC2_RSR, ~0);
-	return (0);
-}
+	sc->li_bst = rman_get_bustag(sc->li_mem_res);
+	sc->li_bsh = rman_get_bushandle(sc->li_mem_res);
 
-static device_method_t lpc_intc_methods[] = {
-	DEVMETHOD(device_probe,		lpc_intc_probe),
-	DEVMETHOD(device_attach,	lpc_intc_attach),
-	{ 0, 0 }
-};
+	arm_register_pic(dev);
 
-static driver_t lpc_intc_driver = {
-	"pic",
-	lpc_intc_methods,
-	sizeof(struct lpc_intc_softc),
-};
-
-static devclass_t lpc_intc_devclass;
+	if (bus_setup_intr(dev, sc->li_irq_res, INTR_TYPE_MISC | INTR_CONTROLLER,
+	    lpc_intc_intr, NULL, sc, &sc->li_intrhand)) {
+		device_printf(dev, "could not setup interrupt handler\n");
+		return (ENXIO); // XXX
+	}
 
-DRIVER_MODULE(pic, simplebus, lpc_intc_driver, lpc_intc_devclass, 0, 0);
+	/* Clear interrupt status registers and disable all interrupts */
+	intc_write_4(sc, LPC_INTC_ER, 0);
+	intc_write_4(sc, LPC_INTC_RSR, ~0);
+	return (0);
+}
 
-int
-arm_get_next_irq(int last)
+static int
+lpc_intc_intr(void *arg)
 {
+	struct arm_intr_data *id = (struct arm_intr_data *)arg;
+	struct lpc_intc_softc *sc = (struct lpc_intc_softc *)id->arg;
 	uint32_t value;
 	int i;
 
-	/* IRQs 0-31 are mapped to LPC_INTC_MIC_SR */
-	value = intc_read_4(LPC_INTC_MIC_SR);
-	for (i = 0; i < 32; i++) {
-		if (value & (1 << i))
-			return (i);
-	}
-
-	/* IRQs 32-63 are mapped to LPC_INTC_SIC1_SR */
-	value = intc_read_4(LPC_INTC_SIC1_SR);
+	value = intc_read_4(sc, LPC_INTC_SR);
 	for (i = 0; i < 32; i++) {
 		if (value & (1 << i))
-			return (i + 32);
+			arm_dispatch_irq(sc->li_dev, id->tf, i);
 	}
 
-	/* IRQs 64-95 are mapped to LPC_INTC_SIC2_SR */
-	value = intc_read_4(LPC_INTC_SIC2_SR);
-	for (i = 0; i < 32; i++) {
-		if (value & (1 << i))
-			return (i + 64);
-	}
+	return (FILTER_HANDLED);
+}
 
-	return (-1);
+static void
+lpc_intc_config(device_t dev, int irq, enum intr_trigger trig,
+    enum intr_polarity pol)
+{
+	/* no-op */
 }
 
-void
-arm_mask_irq(uintptr_t nb)
+static void
+lpc_intc_mask(device_t dev, int irq)
 {
-	int reg;
+	struct lpc_intc_softc *sc = device_get_softc(dev);
 	uint32_t value;
 
-	/* Make sure that interrupt isn't active already */
-	lpc_intc_eoi((void *)nb);
-
-	if (nb > 63) {
-		nb -= 64;
-		reg = LPC_INTC_SIC2_ER;
-	} else if (nb > 31) {
-		nb -= 32;
-		reg = LPC_INTC_SIC1_ER;
-	} else
-		reg = LPC_INTC_MIC_ER;
+	/* Make sure interrupt isn't active already */
+	lpc_intc_eoi(dev, irq);
 
 	/* Clear bit in ER register */
-	value = intc_read_4(reg);
-	value &= ~(1 << nb);
-	intc_write_4(reg, value);
+	value = intc_read_4(sc, LPC_INTC_ER);
+	value &= ~(1 << irq);
+	intc_write_4(sc, LPC_INTC_ER, value);
 }
 
-void
-arm_unmask_irq(uintptr_t nb)
+static void
+lpc_intc_unmask(device_t dev, int irq)
 {
-	int reg;
+	struct lpc_intc_softc *sc = device_get_softc(dev);
 	uint32_t value;
 
-	if (nb > 63) {
-		nb -= 64;
-		reg = LPC_INTC_SIC2_ER;
-	} else if (nb > 31) {
-		nb -= 32;
-		reg = LPC_INTC_SIC1_ER;
-	} else
-		reg = LPC_INTC_MIC_ER;
-
 	/* Set bit in ER register */
-	value = intc_read_4(reg);
-	value |= (1 << nb);
-	intc_write_4(reg, value);
+	value = intc_read_4(sc, LPC_INTC_ER);
+	value |= (1 << irq);
+	intc_write_4(sc, LPC_INTC_ER, value);
 }
 
 static void
-lpc_intc_eoi(void *data)
+lpc_intc_eoi(device_t dev, int irq)
 {
-	int reg;
-	int nb = (int)data;
+	struct lpc_intc_softc *sc = device_get_softc(dev);
 	uint32_t value;
+	
+	/* Set bit in RSR register */
+	value = intc_read_4(sc, LPC_INTC_RSR);
+	value |= (1 << irq);
+	intc_write_4(sc, LPC_INTC_RSR, value);
+}
 
-	if (nb > 63) {
-		nb -= 64;
-		reg = LPC_INTC_SIC2_RSR;
-	} else if (nb > 31) {
-		nb -= 32;
-		reg = LPC_INTC_SIC1_RSR;
-	} else
-		reg = LPC_INTC_MIC_RSR;
+static device_method_t lpc_intc_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		lpc_intc_probe),
+	DEVMETHOD(device_attach,	lpc_intc_attach),
+	/* Interrupt controller interface */
+	DEVMETHOD(pic_config,		lpc_intc_config),
+	DEVMETHOD(pic_mask,		lpc_intc_mask),
+	DEVMETHOD(pic_unmask,		lpc_intc_unmask),
+	DEVMETHOD(pic_eoi,		lpc_intc_eoi),
+	{ 0, 0 }
+};
 
-	/* Set bit in RSR register */
-	value = intc_read_4(reg);
-	value |= (1 << nb);
-	intc_write_4(reg, value);
+static driver_t lpc_intc_driver = {
+	"pic",
+	lpc_intc_methods,
+	sizeof(struct lpc_intc_softc),
+};
 
-}
+static devclass_t lpc_intc_devclass;
+
+DRIVER_MODULE(pic, simplebus, lpc_intc_driver, lpc_intc_devclass, 0, 0);
 
 struct fdt_fixup_entry fdt_fixup_table[] = {
 	{ NULL, NULL }
@@ -228,8 +214,11 @@ static int
 fdt_pic_decode_ic(phandle_t node, pcell_t *intr, int *interrupt, int *trig,
     int *pol)
 {
+#if 0
+	// XXX
 	if (!fdt_is_compatible(node, "lpc,pic"))
 		return (ENXIO);
+#endif
 
 	*interrupt = fdt32_to_cpu(intr[0]);
 	*trig = INTR_TRIGGER_CONFORM;

Modified: user/jceel/soc2012_armv6/sys/arm/lpc/lpcreg.h
==============================================================================
--- user/jceel/soc2012_armv6/sys/arm/lpc/lpcreg.h	Tue Jun 12 00:14:54 2012	(r236938)
+++ user/jceel/soc2012_armv6/sys/arm/lpc/lpcreg.h	Tue Jun 12 01:13:59 2012	(r236939)
@@ -37,24 +37,12 @@
  * Interrupt controller (from UM10326: LPC32x0 User manual, page 87)
 
  */
-#define	LPC_INTC_MIC_ER			0x0000
-#define	LPC_INTC_MIC_RSR		0x0004
-#define	LPC_INTC_MIC_SR			0x0008
-#define	LPC_INTC_MIC_APR		0x000c
-#define	LPC_INTC_MIC_ATR		0x0010
-#define	LPC_INTC_MIC_ITR		0x0014
-#define	LPC_INTC_SIC1_ER		0x4000
-#define	LPC_INTC_SIC1_RSR		0x4004
-#define	LPC_INTC_SIC1_SR		0x4008
-#define	LPC_INTC_SIC1_APR		0x400c
-#define	LPC_INTC_SIC1_ATR		0x4010
-#define	LPC_INTC_SIC1_ITR		0x4014
-#define	LPC_INTC_SIC2_ER		0x8000
-#define	LPC_INTC_SIC2_RSR		0x8004
-#define	LPC_INTC_SIC2_SR		0x8008
-#define	LPC_INTC_SIC2_APR		0x800c
-#define	LPC_INTC_SIC2_ATR		0x8010
-#define	LPC_INTC_SIC2_ITR		0x8014
+#define	LPC_INTC_ER			0x0000
+#define	LPC_INTC_RSR			0x0004
+#define	LPC_INTC_SR			0x0008
+#define	LPC_INTC_APR			0x000c
+#define	LPC_INTC_ATR			0x0010
+#define	LPC_INTC_ITR			0x0014
 
 
 /*

Modified: user/jceel/soc2012_armv6/sys/boot/fdt/dts/ea3250.dts
==============================================================================
--- user/jceel/soc2012_armv6/sys/boot/fdt/dts/ea3250.dts	Tue Jun 12 00:14:54 2012	(r236938)
+++ user/jceel/soc2012_armv6/sys/boot/fdt/dts/ea3250.dts	Tue Jun 12 01:13:59 2012	(r236939)
@@ -75,11 +75,30 @@
 			reg = <0x4000 0x4000>;
 		};
 
-		PIC: pic at 8000 {
+		MIC: pic at 8000 {
 			interrupt-controller;
 			#address-cells = <0>;
 			#interrupt-cells = <1>;
-			reg = <0x8000 0xc000>;
+			reg = <0x8000 0x1000>;
+			interrupts = <0>;
+			compatible = "lpc,pic";
+		};
+
+		SIC1: pic at c000 {
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <1>;
+			reg = <0xc000 0x1000>;
+			interrupts = <0>;
+			compatible = "lpc,pic";
+		};
+
+		SIC2: pic at 10000 {
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <1>;
+			reg = <0x10000 0x1000>;
+			interrupts = <0>;
 			compatible = "lpc,pic";
 		};
 
@@ -88,14 +107,14 @@
 			reg = <0x44000 0x4000
 			       0x4c000 0x4000>;
 			interrupts = <16 17>;
-			interrupt-parent = <&PIC>;
+			interrupt-parent = <&MIC>;
 		};
 
 		rtc at 24000 {
 			compatible = "lpc,rtc";
 			reg = <0x24000 0x4000>;
-			interrupts = <52>;
-			interrupt-parent = <&PIC>;
+			interrupts = <20>;
+			interrupt-parent = <&SIC1>;
 		};
 
 		serial0: serial at 14000 {
@@ -105,7 +124,7 @@
 			reg-shift = <2>;
 			clock-frequency = <0>;
 			interrupts = <26>;
-			interrupt-parent = <&PIC>;
+			interrupt-parent = <&MIC>;
 		};
 
 		serial1: serial at 18000 {
@@ -115,7 +134,7 @@
 			reg-shift = <2>;
 			clock-frequency = <0>;
 			interrupts = <25>;
-			interrupt-parent = <&PIC>;
+			interrupt-parent = <&MIC>;
 		};
 
 		serial2: serial at 80000 {
@@ -125,7 +144,7 @@
 			reg-shift = <2>;
 			clock-frequency = <13000000>;
 			interrupts = <7>;
-			interrupt-parent = <&PIC>;
+			interrupt-parent = <&MIC>;
 		};
 
 		serial3: serial at 88000 {
@@ -135,7 +154,7 @@
 			reg-shift = <2>;
 			clock-frequency = <13000000>;
 			interrupts = <8>;
-			interrupt-parent = <&PIC>;
+			interrupt-parent = <&MIC>;
 		};
 
 		serial4: serial at 90000 {
@@ -145,7 +164,7 @@
 			clock-frequency = <13000000>;
 			current-speed = <115200>;
 			interrupts = <9>;
-			interrupt-parent = <&PIC>;
+			interrupt-parent = <&MIC>;
 		};
 
 		serial5: serial at 98000 {
@@ -155,7 +174,7 @@
 			reg-shift = <2>;
 			clock-frequency = <13000000>;
 			interrupts = <10>;
-			interrupt-parent = <&PIC>;
+			interrupt-parent = <&MIC>;
 		};
 
 		serial6: serial at 1c000 {

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-user mailing list