Date: Sat, 24 Jul 2010 23:41:10 +0000 (UTC) From: Andrew Turner <andrew@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r210458 - head/sys/arm/s3c2xx0 Message-ID: <201007242341.o6ONfAXB071871@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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 */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201007242341.o6ONfAXB071871>