svn commit: r210458 - head/sys/arm/s3c2xx0

Andrew Turner andrew at FreeBSD.org
Sat Jul 24 23:41:10 UTC 2010


Author: andrew
Date: Sat Jul 24 23:41:09 2010
New Revision: 210458
URL: http://svn.freebsd.org/changeset/base/210458

Log:
  Allow external interrupts.
  
  - Set the external pin to interrupt in bus_setup_intr
  - Implement bus_config_intr for external interrupts
  - Extend arm_{,un}mask_irq to work with external interrupts
  
  Approved by:	imp (mentor)

Modified:
  head/sys/arm/s3c2xx0/s3c24x0.c
  head/sys/arm/s3c2xx0/s3c24x0reg.h

Modified: head/sys/arm/s3c2xx0/s3c24x0.c
==============================================================================
--- head/sys/arm/s3c2xx0/s3c24x0.c	Sat Jul 24 22:28:29 2010	(r210457)
+++ head/sys/arm/s3c2xx0/s3c24x0.c	Sat Jul 24 23:41:09 2010	(r210458)
@@ -118,6 +118,8 @@ static int	s3c24x0_setup_intr(device_t, 
         driver_filter_t *, driver_intr_t *, void *, void **);
 static int	s3c24x0_teardown_intr(device_t, device_t, struct resource *,
 	void *);
+static int	s3c24x0_config_intr(device_t, int, enum intr_trigger,
+	enum intr_polarity);
 static struct resource *s3c24x0_alloc_resource(device_t, device_t, int, int *,
         u_long, u_long, u_long, u_int);
 static int s3c24x0_activate_resource(device_t, device_t, int, int,
@@ -134,6 +136,7 @@ static device_method_t s3c24x0_methods[]
 	DEVMETHOD(device_identify, s3c24x0_identify),
 	DEVMETHOD(bus_setup_intr, s3c24x0_setup_intr),
 	DEVMETHOD(bus_teardown_intr, s3c24x0_teardown_intr),
+	DEVMETHOD(bus_config_intr, s3c24x0_config_intr),
 	DEVMETHOD(bus_alloc_resource, s3c24x0_alloc_resource),
 	DEVMETHOD(bus_activate_resource, s3c24x0_activate_resource),
 	DEVMETHOD(bus_release_resource,	s3c24x0_release_resource),
@@ -176,6 +179,30 @@ s3c24x0_add_child(device_t bus, int prio
 	return (child);
 }
 
+static void
+s3c24x0_enable_ext_intr(unsigned int irq)
+{
+	uint32_t reg, value;
+	int offset;
+
+	if (irq <= 7) {
+		reg = GPIO_PFCON;
+		offset = irq * 2;
+	} else if (irq <= 23) {
+		reg = GPIO_PGCON;
+		offset = (irq - 8) * 2;
+	} else
+		return;
+
+	/* Make the pin an interrupt source */
+	value = bus_space_read_4(s3c2xx0_softc->sc_iot,
+	    s3c2xx0_softc->sc_gpio_ioh, reg);
+	value &= ~(3 << offset);
+	value |= 2 << offset;
+	bus_space_write_4(s3c2xx0_softc->sc_iot, s3c2xx0_softc->sc_gpio_ioh,
+	    reg, value);
+}
+
 static int
 s3c24x0_setup_intr(device_t dev, device_t child,
         struct resource *ires,  int flags, driver_filter_t *filt,
@@ -189,6 +216,10 @@ s3c24x0_setup_intr(device_t dev, device_
 		return (error);
 
 	for (irq = rman_get_start(ires); irq <= rman_get_end(ires); irq++) {
+		if (irq >= S3C24X0_EXTIRQ_MIN && irq <= S3C24X0_EXTIRQ_MAX) {
+			/* Enable the external interrupt pin */
+			s3c24x0_enable_ext_intr(irq - S3C24X0_EXTIRQ_MIN);
+		}
 		arm_unmask_irq(irq);
 	}
 	return (0);
@@ -201,6 +232,59 @@ s3c24x0_teardown_intr(device_t dev, devi
 	return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie));
 }
 
+static int
+s3c24x0_config_intr(device_t dev, int irq, enum intr_trigger trig,
+	enum intr_polarity pol)
+{
+	uint32_t mask, reg, value;
+	int offset;
+
+	/* Only external interrupts can be configured */
+	if (irq < S3C24X0_EXTIRQ_MIN || irq > S3C24X0_EXTIRQ_MAX)
+		return (EINVAL);
+
+	/* There is no standard trigger or polarity for the bus */
+	if (trig == INTR_TRIGGER_CONFORM || pol == INTR_POLARITY_CONFORM)
+		return (EINVAL);
+
+	irq -= S3C24X0_EXTIRQ_MIN;
+
+	/* Get the bits to set */
+	mask = 0;
+	if (pol == INTR_POLARITY_LOW) {
+		mask = 2;
+	} else if (pol == INTR_POLARITY_HIGH) {
+		mask = 4;
+	}
+	if (trig == INTR_TRIGGER_LEVEL) {
+		mask >>= 2;
+	}
+
+	/* Get the register to set */
+	if (irq <= 7) {
+		reg = GPIO_EXTINT(0);
+		offset = irq * 4;
+	} else if (irq <= 15) {
+		reg = GPIO_EXTINT(1);
+		offset = (irq - 8) * 4;
+	} else if (irq <= 23) {
+		reg = GPIO_EXTINT(2);
+		offset = (irq - 16) * 4;
+	} else {
+		return (EINVAL);
+	}
+
+	/* Set the new signaling method */
+	value = bus_space_read_4(s3c2xx0_softc->sc_iot,
+	    s3c2xx0_softc->sc_gpio_ioh, reg);
+	value &= ~(7 << offset);
+	value |= mask << offset;
+	bus_space_write_4(s3c2xx0_softc->sc_iot,
+	    s3c2xx0_softc->sc_gpio_ioh, reg, value);
+
+	return (0);
+} 
+
 static struct resource *
 s3c24x0_alloc_resource(device_t bus, device_t child, int type, int *rid,
         u_long start, u_long end, u_long count, u_int flags)
@@ -356,6 +440,7 @@ s3c24x0_attach(device_t dev)
 	bus_space_tag_t iot;
 	device_t child;
 	unsigned int i, j;
+	u_long irqmax;
 
 	s3c2xx0_softc = &(sc->sc_sx);
 	sc->sc_sx.sc_iot = iot = &s3c2xx0_bs_tag;
@@ -363,10 +448,6 @@ s3c24x0_attach(device_t dev)
 	s3c2xx0_softc->s3c2xx0_irq_rman.rm_descr = "S3C24X0 IRQs";
 	s3c2xx0_softc->s3c2xx0_mem_rman.rm_type = RMAN_ARRAY;
 	s3c2xx0_softc->s3c2xx0_mem_rman.rm_descr = "S3C24X0 Device Registers";
-	if (rman_init(&s3c2xx0_softc->s3c2xx0_irq_rman) != 0 ||
-	    rman_manage_region(&s3c2xx0_softc->s3c2xx0_irq_rman, 0,
-	    S3C2410_SUBIRQ_MAX) != 0) /* XXX Change S3C2440_SUBIRQ_MAX depending on micro */
-		panic("s3c24x0_attach: failed to set up IRQ rman");
 	/* Manage the registor memory space */
 	if ((rman_init(&s3c2xx0_softc->s3c2xx0_mem_rman) != 0) ||
 	    (rman_manage_region(&s3c2xx0_softc->s3c2xx0_mem_rman,
@@ -388,6 +469,22 @@ s3c24x0_attach(device_t dev)
 	 */
 	s3c24x0_identify_cpu(dev);
 
+	/*
+	 * Manage the interrupt space.
+	 * We need to put this after s3c24x0_identify_cpu as the avaliable
+	 * interrupts change depending on which CPU we have.
+	 */
+	if (sc->sc_sx.sc_cpu == CPU_S3C2410)
+		irqmax = S3C2410_SUBIRQ_MAX;
+	else
+		irqmax = S3C2440_SUBIRQ_MAX;
+	if (rman_init(&s3c2xx0_softc->s3c2xx0_irq_rman) != 0 ||
+	    rman_manage_region(&s3c2xx0_softc->s3c2xx0_irq_rman, 0,
+	    irqmax) != 0 ||
+	    rman_manage_region(&s3c2xx0_softc->s3c2xx0_irq_rman,
+	    S3C24X0_EXTIRQ_MIN, S3C24X0_EXTIRQ_MAX))
+		panic("s3c24x0_attach: failed to set up IRQ rman");
+
 	/* calculate current clock frequency */
 	s3c24x0_clock_freq(&sc->sc_sx);
 	device_printf(dev, "fclk %d MHz hclk %d MHz pclk %d MHz\n",
@@ -607,6 +704,33 @@ arm_get_next_irq(int last __unused)
 				return (irq);
 
 			return (S3C24X0_SUBIRQ_MIN + subirq);
+
+		case S3C24X0_INT_0:
+		case S3C24X0_INT_1:
+		case S3C24X0_INT_2:
+		case S3C24X0_INT_3:
+			/* There is a 1:1 mapping to the IRQ we are handling */
+			return S3C24X0_INT_EXT(irq);
+
+		case S3C24X0_INT_4_7:
+		case S3C24X0_INT_8_23:
+			/* Find the external interrupt being called */
+			subirq = 0x7fffff;
+			subirq &= bus_space_read_4(&s3c2xx0_bs_tag,
+			    s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTPEND);
+			subirq &= ~bus_space_read_4(&s3c2xx0_bs_tag,
+			    s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTMASK);
+			if (subirq == 0)
+				return (irq);
+
+			subirq = ffs(subirq) - 1;
+
+			/* Clear the external irq pending bit */
+			bus_space_write_4(&s3c2xx0_bs_tag,
+			    s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTPEND,
+			    (1 << subirq));
+
+			return S3C24X0_INT_EXT(subirq);
 		}
 
 		return (irq);
@@ -619,18 +743,28 @@ arm_mask_irq(uintptr_t irq)
 {
 	u_int32_t mask;
 
+	if (irq >= S3C24X0_INT_EXT(0) && irq <= S3C24X0_INT_EXT(3)) {
+		/* External interrupt 0..3 are directly mapped to irq 0..3 */
+		irq -= S3C24X0_EXTIRQ_MIN;
+	}
 	if (irq < S3C24X0_SUBIRQ_MIN) {
 		mask = bus_space_read_4(&s3c2xx0_bs_tag,
 		    s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK);
 		mask |= (1 << irq);
 		bus_space_write_4(&s3c2xx0_bs_tag, 
 		    s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK, mask);
-	} else {
+	} else if (irq < S3C24X0_EXTIRQ_MIN) {
 		mask = bus_space_read_4(&s3c2xx0_bs_tag,
 		    s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK);
 		mask |= (1 << (irq - S3C24X0_SUBIRQ_MIN));
 		bus_space_write_4(&s3c2xx0_bs_tag, 
 		    s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK, mask);
+	} else {
+		mask = bus_space_read_4(&s3c2xx0_bs_tag,
+		    s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTMASK);
+		mask |= (1 << (irq - S3C24X0_EXTIRQ_MIN));
+		bus_space_write_4(&s3c2xx0_bs_tag, 
+		    s3c2xx0_softc->sc_intctl_ioh, GPIO_EINTMASK, mask);
 	}
 }
 
@@ -639,17 +773,27 @@ arm_unmask_irq(uintptr_t irq)
 {
 	u_int32_t mask;
 
+	if (irq >= S3C24X0_INT_EXT(0) && irq <= S3C24X0_INT_EXT(3)) {
+		/* External interrupt 0..3 are directly mapped to irq 0..3 */
+		irq -= S3C24X0_EXTIRQ_MIN;
+	}
 	if (irq < S3C24X0_SUBIRQ_MIN) {
 		mask = bus_space_read_4(&s3c2xx0_bs_tag,
 		    s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK);
 		mask &= ~(1 << irq);
 		bus_space_write_4(&s3c2xx0_bs_tag,
 		    s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK, mask);
-	} else {
+	} else if (irq < S3C24X0_EXTIRQ_MIN) {
 		mask = bus_space_read_4(&s3c2xx0_bs_tag,
 		    s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK);
 		mask &= ~(1 << (irq - S3C24X0_SUBIRQ_MIN));
 		bus_space_write_4(&s3c2xx0_bs_tag, 
 		    s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK, mask);
+	} else {
+		mask = bus_space_read_4(&s3c2xx0_bs_tag,
+		    s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTMASK);
+		mask &= ~(1 << (irq - S3C24X0_EXTIRQ_MIN));
+		bus_space_write_4(&s3c2xx0_bs_tag, 
+		    s3c2xx0_softc->sc_intctl_ioh, GPIO_EINTMASK, mask);
 	}
 }

Modified: head/sys/arm/s3c2xx0/s3c24x0reg.h
==============================================================================
--- head/sys/arm/s3c2xx0/s3c24x0reg.h	Sat Jul 24 22:28:29 2010	(r210457)
+++ head/sys/arm/s3c2xx0/s3c24x0reg.h	Sat Jul 24 23:41:09 2010	(r210458)
@@ -207,7 +207,10 @@
 #define	S3C24X0_INT_BFLT 	7	/* Battery fault */
 #define	S3C24X0_INT_8_23	5	/* Ext int 8..23 */
 #define	S3C24X0_INT_4_7 	4	/* Ext int 4..7 */
-#define	S3C24X0_INT_EXT(n)	(n) /* External interrupt [3:0] for 24{1,4}0 */
+#define	S3C24X0_INT_3		3
+#define	S3C24X0_INT_2		2
+#define	S3C24X0_INT_1		1
+#define	S3C24X0_INT_0		0
 
 /* 24{1,4}0 has more than 32 interrupt sources.  These are sub-sources
  * that are OR-ed into main interrupt sources, and controlled via
@@ -230,6 +233,15 @@
 #define	S3C24X0_INT_TXD0	(S3C24X0_SUBIRQ_MIN+1)	/* UART0 Tx */
 #define	S3C24X0_INT_RXD0	(S3C24X0_SUBIRQ_MIN+0)	/* UART0 Rx */
 
+/*
+ * Support for external interrupts. We use values from 48
+ * to allow new CPU's to allocate new subirq's.
+ */
+#define	S3C24X0_EXTIRQ_MIN	48
+#define	S3C24X0_EXTIRQ_COUNT	24
+#define	S3C24X0_EXTIRQ_MAX	(S3C24X0_EXTIRQ_MIN + S3C24X0_EXTIRQ_COUNT - 1)
+#define	S3C24X0_INT_EXT(n)	(S3C24X0_EXTIRQ_MIN + (n))
+
 /* DMA controller */
 /* XXX */
 


More information about the svn-src-all mailing list