From owner-svn-src-head@FreeBSD.ORG Wed Jan 1 20:03:50 2014 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 21CC28F5; Wed, 1 Jan 2014 20:03:50 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 0152F1136; Wed, 1 Jan 2014 20:03:50 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id s01K3npM009765; Wed, 1 Jan 2014 20:03:49 GMT (envelope-from zbb@svn.freebsd.org) Received: (from zbb@localhost) by svn.freebsd.org (8.14.7/8.14.7/Submit) id s01K3ngn009757; Wed, 1 Jan 2014 20:03:49 GMT (envelope-from zbb@svn.freebsd.org) Message-Id: <201401012003.s01K3ngn009757@svn.freebsd.org> From: Zbigniew Bodek Date: Wed, 1 Jan 2014 20:03:49 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r260161 - in head/sys/arm: arm include X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 01 Jan 2014 20:03:50 -0000 Author: zbb Date: Wed Jan 1 20:03:48 2014 New Revision: 260161 URL: http://svnweb.freebsd.org/changeset/base/260161 Log: Add polarity and level support to ARM GIC Add suport for setting triggering level and polarity in GIC. New function pointer was added to nexus which corresponds to the function which sets level/sense in the hardware (GIC). Submitted by: Wojciech Macek Obtained from: Semihalf Modified: head/sys/arm/arm/gic.c head/sys/arm/arm/intr.c head/sys/arm/arm/nexus.c head/sys/arm/include/intr.h Modified: head/sys/arm/arm/gic.c ============================================================================== --- head/sys/arm/arm/gic.c Wed Jan 1 19:38:15 2014 (r260160) +++ head/sys/arm/arm/gic.c Wed Jan 1 20:03:48 2014 (r260161) @@ -83,6 +83,15 @@ __FBSDID("$FreeBSD$"); #define GICC_ABPR 0x001C /* v1 ICCABPR */ #define GICC_IIDR 0x00FC /* v1 ICCIIDR*/ +/* First bit is a polarity bit (0 - low, 1 - high) */ +#define GICD_ICFGR_POL_LOW (0 << 0) +#define GICD_ICFGR_POL_HIGH (1 << 0) +#define GICD_ICFGR_POL_MASK 0x1 +/* Second bit is a trigger bit (0 - level, 1 - edge) */ +#define GICD_ICFGR_TRIG_LVL (0 << 1) +#define GICD_ICFGR_TRIG_EDGE (1 << 1) +#define GICD_ICFGR_TRIG_MASK 0x2 + struct arm_gic_softc { struct resource * gic_res[3]; bus_space_tag_t gic_c_bst; @@ -90,6 +99,9 @@ struct arm_gic_softc { bus_space_handle_t gic_c_bsh; bus_space_handle_t gic_d_bsh; uint8_t ver; + device_t dev; + struct mtx mutex; + uint32_t nirqs; }; static struct resource_spec arm_gic_spec[] = { @@ -109,6 +121,8 @@ static struct arm_gic_softc *arm_gic_sc #define gic_d_write_4(reg, val) \ bus_space_write_4(arm_gic_sc->gic_d_bst, arm_gic_sc->gic_d_bsh, reg, val) +static int gic_config_irq(int irq, enum intr_trigger trig, + enum intr_polarity pol); static void gic_post_filter(void *); static int @@ -157,19 +171,20 @@ arm_gic_attach(device_t dev) struct arm_gic_softc *sc; int i; uint32_t icciidr; - uint32_t nirqs; if (arm_gic_sc) return (ENXIO); sc = device_get_softc(dev); + sc->dev = dev; if (bus_alloc_resources(dev, arm_gic_spec, sc->gic_res)) { device_printf(dev, "could not allocate resources\n"); return (ENXIO); } - arm_post_filter = gic_post_filter; + /* Initialize mutex */ + mtx_init(&sc->mutex, "GIC lock", "", MTX_SPIN); /* Distributor Interface */ sc->gic_d_bst = rman_get_bustag(sc->gic_res[0]); @@ -185,31 +200,35 @@ arm_gic_attach(device_t dev) gic_d_write_4(GICD_CTLR, 0x00); /* Get the number of interrupts */ - nirqs = gic_d_read_4(GICD_TYPER); - nirqs = 32 * ((nirqs & 0x1f) + 1); + sc->nirqs = gic_d_read_4(GICD_TYPER); + sc->nirqs = 32 * ((sc->nirqs & 0x1f) + 1); + + /* Set up function pointers */ + arm_post_filter = gic_post_filter; + arm_config_irq = gic_config_irq; icciidr = gic_c_read_4(GICC_IIDR); - device_printf(dev,"pn 0x%x, arch 0x%x, rev 0x%x, implementer 0x%x nirqs %u\n", + device_printf(dev,"pn 0x%x, arch 0x%x, rev 0x%x, implementer 0x%x sc->nirqs %u\n", icciidr>>20, (icciidr>>16) & 0xF, (icciidr>>12) & 0xf, - (icciidr & 0xfff), nirqs); + (icciidr & 0xfff), sc->nirqs); /* Set all global interrupts to be level triggered, active low. */ - for (i = 32; i < nirqs; i += 32) { - gic_d_write_4(GICD_ICFGR(i >> 5), 0x00000000); + for (i = 32; i < sc->nirqs; i += 16) { + gic_d_write_4(GICD_ICFGR(i >> 4), 0x00000000); } /* Disable all interrupts. */ - for (i = 32; i < nirqs; i += 32) { + for (i = 32; i < sc->nirqs; i += 32) { gic_d_write_4(GICD_ICENABLER(i >> 5), 0xFFFFFFFF); } - for (i = 0; i < nirqs; i += 4) { + for (i = 0; i < sc->nirqs; i += 4) { gic_d_write_4(GICD_IPRIORITYR(i >> 2), 0); gic_d_write_4(GICD_ITARGETSR(i >> 2), 1 << 0 | 1 << 8 | 1 << 16 | 1 << 24); } /* Set all the interrupts to be in Group 0 (secure) */ - for (i = 0; i < nirqs; i += 32) { + for (i = 0; i < sc->nirqs; i += 32) { gic_d_write_4(GICD_IGROUPR(i >> 5), 0); } @@ -290,6 +309,58 @@ arm_unmask_irq(uintptr_t nb) gic_d_write_4(GICD_ISENABLER(nb >> 5), (1UL << (nb & 0x1F))); } +static int +gic_config_irq(int irq, enum intr_trigger trig, + enum intr_polarity pol) +{ + uint32_t reg; + uint32_t mask; + + /* Function is public-accessible, so validate input arguments */ + if ((irq < 0) || (irq >= arm_gic_sc->nirqs)) + goto invalid_args; + if ((trig != INTR_TRIGGER_EDGE) && (trig != INTR_TRIGGER_LEVEL) && + (trig != INTR_TRIGGER_CONFORM)) + goto invalid_args; + if ((pol != INTR_POLARITY_HIGH) && (pol != INTR_POLARITY_LOW) && + (pol != INTR_POLARITY_CONFORM)) + goto invalid_args; + + mtx_lock_spin(&arm_gic_sc->mutex); + + reg = gic_d_read_4(GICD_ICFGR(irq >> 4)); + mask = (reg >> 2*(irq % 16)) & 0x3; + + if (pol == INTR_POLARITY_LOW) { + mask &= ~GICD_ICFGR_POL_MASK; + mask |= GICD_ICFGR_POL_LOW; + } else if (pol == INTR_POLARITY_HIGH) { + mask &= ~GICD_ICFGR_POL_MASK; + mask |= GICD_ICFGR_POL_HIGH; + } + + if (trig == INTR_TRIGGER_LEVEL) { + mask &= ~GICD_ICFGR_TRIG_MASK; + mask |= GICD_ICFGR_TRIG_LVL; + } else if (trig == INTR_TRIGGER_EDGE) { + mask &= ~GICD_ICFGR_TRIG_MASK; + mask |= GICD_ICFGR_TRIG_EDGE; + } + + /* Set mask */ + reg = reg & ~(0x3 << 2*(irq % 16)); + reg = reg | (mask << 2*(irq % 16)); + gic_d_write_4(GICD_ICFGR(irq >> 4), reg); + + mtx_unlock_spin(&arm_gic_sc->mutex); + + return (0); + +invalid_args: + device_printf(arm_gic_sc->dev, "gic_config_irg, invalid parameters\n"); + return (EINVAL); +} + #ifdef SMP void pic_ipi_send(cpuset_t cpus, u_int ipi) Modified: head/sys/arm/arm/intr.c ============================================================================== --- head/sys/arm/arm/intr.c Wed Jan 1 19:38:15 2014 (r260160) +++ head/sys/arm/arm/intr.c Wed Jan 1 20:03:48 2014 (r260161) @@ -59,6 +59,8 @@ static struct intr_event *intr_events[NI void arm_handler_execute(struct trapframe *, int); void (*arm_post_filter)(void *) = NULL; +int (*arm_config_irq)(int irq, enum intr_trigger trig, + enum intr_polarity pol) = NULL; /* * Pre-format intrnames into an array of fixed-size strings containing spaces. Modified: head/sys/arm/arm/nexus.c ============================================================================== --- head/sys/arm/arm/nexus.c Wed Jan 1 19:38:15 2014 (r260160) +++ head/sys/arm/arm/nexus.c Wed Jan 1 20:03:48 2014 (r260161) @@ -85,6 +85,8 @@ static struct resource *nexus_alloc_reso #endif static int nexus_activate_resource(device_t, device_t, int, int, struct resource *); +static int nexus_config_intr(device_t dev, int irq, enum intr_trigger trig, + enum intr_polarity pol); static int nexus_deactivate_resource(device_t, device_t, int, int, struct resource *); @@ -103,6 +105,7 @@ static device_method_t nexus_methods[] = DEVMETHOD(bus_alloc_resource, nexus_alloc_resource), #endif DEVMETHOD(bus_activate_resource, nexus_activate_resource), + DEVMETHOD(bus_config_intr, nexus_config_intr), DEVMETHOD(bus_deactivate_resource, nexus_deactivate_resource), DEVMETHOD(bus_setup_intr, nexus_setup_intr), DEVMETHOD(bus_teardown_intr, nexus_teardown_intr), @@ -225,6 +228,18 @@ nexus_alloc_resource(device_t bus, devic #endif static int +nexus_config_intr(device_t dev, int irq, enum intr_trigger trig, + enum intr_polarity pol) +{ + int ret = ENODEV; + + if (arm_config_irq) + ret = (*arm_config_irq)(irq, trig, pol); + + return (ret); +} + +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) { Modified: head/sys/arm/include/intr.h ============================================================================== --- head/sys/arm/include/intr.h Wed Jan 1 19:38:15 2014 (r260160) +++ head/sys/arm/include/intr.h Wed Jan 1 20:03:48 2014 (r260161) @@ -68,6 +68,7 @@ #endif #include +#include int arm_get_next_irq(int); void arm_mask_irq(uintptr_t); @@ -77,6 +78,8 @@ void arm_setup_irqhandler(const char *, void *, int, int, void **); int arm_remove_irqhandler(int, void *); extern void (*arm_post_filter)(void *); +extern int (*arm_config_irq)(int irq, enum intr_trigger trig, + enum intr_polarity pol); void gic_init_secondary(void);