From owner-svn-src-head@freebsd.org Tue Apr 26 11:15:49 2016 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 8E6F3B1B175; Tue, 26 Apr 2016 11:15:49 +0000 (UTC) (envelope-from manu@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 5E7FA18B8; Tue, 26 Apr 2016 11:15:49 +0000 (UTC) (envelope-from manu@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u3QBFmaY065721; Tue, 26 Apr 2016 11:15:48 GMT (envelope-from manu@FreeBSD.org) Received: (from manu@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u3QBFm59065718; Tue, 26 Apr 2016 11:15:48 GMT (envelope-from manu@FreeBSD.org) Message-Id: <201604261115.u3QBFm59065718@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: manu set sender to manu@FreeBSD.org using -f From: Emmanuel Vadot Date: Tue, 26 Apr 2016 11:15:48 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r298625 - in head/sys/arm: allwinner allwinner/a10 conf 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.21 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: Tue, 26 Apr 2016 11:15:49 -0000 Author: manu Date: Tue Apr 26 11:15:48 2016 New Revision: 298625 URL: https://svnweb.freebsd.org/changeset/base/298625 Log: Convert A10 interrupt controller to INTRNG Reviewed by: skra Approved by: cognet (mentor) Differential Revision: https://reviews.freebsd.org/D5573 Added: head/sys/arm/allwinner/a10/ head/sys/arm/allwinner/a10/a10_intc.c - copied, changed from r298624, head/sys/arm/allwinner/aintc.c Deleted: head/sys/arm/allwinner/aintc.c Modified: head/sys/arm/allwinner/files.a10 head/sys/arm/conf/A10 Copied and modified: head/sys/arm/allwinner/a10/a10_intc.c (from r298624, head/sys/arm/allwinner/aintc.c) ============================================================================== --- head/sys/arm/allwinner/aintc.c Tue Apr 26 10:04:06 2016 (r298624, copy source) +++ head/sys/arm/allwinner/a10/a10_intc.c Tue Apr 26 11:15:48 2016 (r298625) @@ -1,5 +1,6 @@ /*- * Copyright (c) 2012 Ganbold Tsagaankhuu + * Copyright (c) 2016 Emmanuel Vadot * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,13 +28,24 @@ #include __FBSDID("$FreeBSD$"); -#include -#include +#include "opt_platform.h" + +#include #include +#include #include #include #include +#include +#include +#include +#include #include +#include +#include +#ifdef INTRNG +#include +#endif #include #include @@ -42,63 +54,288 @@ __FBSDID("$FreeBSD$"); #include #include +#ifdef INTRNG +#include "pic_if.h" +#endif + /** * Interrupt controller registers * */ -#define SW_INT_VECTOR_REG 0x00 -#define SW_INT_BASE_ADR_REG 0x04 -#define SW_INT_PROTECTION_REG 0x08 -#define SW_INT_NMI_CTRL_REG 0x0c - -#define SW_INT_IRQ_PENDING_REG0 0x10 -#define SW_INT_IRQ_PENDING_REG1 0x14 -#define SW_INT_IRQ_PENDING_REG2 0x18 - -#define SW_INT_FIQ_PENDING_REG0 0x20 -#define SW_INT_FIQ_PENDING_REG1 0x24 -#define SW_INT_FIQ_PENDING_REG2 0x28 - -#define SW_INT_SELECT_REG0 0x30 -#define SW_INT_SELECT_REG1 0x34 -#define SW_INT_SELECT_REG2 0x38 - -#define SW_INT_ENABLE_REG0 0x40 -#define SW_INT_ENABLE_REG1 0x44 -#define SW_INT_ENABLE_REG2 0x48 - -#define SW_INT_MASK_REG0 0x50 -#define SW_INT_MASK_REG1 0x54 -#define SW_INT_MASK_REG2 0x58 - -#define SW_INT_IRQNO_ENMI 0 - -#define SW_INT_IRQ_PENDING_REG(_b) (0x10 + ((_b) * 4)) -#define SW_INT_FIQ_PENDING_REG(_b) (0x20 + ((_b) * 4)) -#define SW_INT_SELECT_REG(_b) (0x30 + ((_b) * 4)) -#define SW_INT_ENABLE_REG(_b) (0x40 + ((_b) * 4)) -#define SW_INT_MASK_REG(_b) (0x50 + ((_b) * 4)) - -static struct ofw_compat_data compat_data[] = { - {"allwinner,sun4i-a10-ic", 1}, - {"allwinner,sun7i-a20-sc-nmi", 1}, - {NULL, 0} +#define SW_INT_VECTOR_REG 0x00 +#define SW_INT_BASE_ADR_REG 0x04 +#define SW_INT_PROTECTION_REG 0x08 +#define SW_INT_NMI_CTRL_REG 0x0c + +#define SW_INT_IRQ_PENDING_REG0 0x10 +#define SW_INT_IRQ_PENDING_REG1 0x14 +#define SW_INT_IRQ_PENDING_REG2 0x18 + +#define SW_INT_FIQ_PENDING_REG0 0x20 +#define SW_INT_FIQ_PENDING_REG1 0x24 +#define SW_INT_FIQ_PENDING_REG2 0x28 + +#define SW_INT_SELECT_REG0 0x30 +#define SW_INT_SELECT_REG1 0x34 +#define SW_INT_SELECT_REG2 0x38 + +#define SW_INT_ENABLE_REG0 0x40 +#define SW_INT_ENABLE_REG1 0x44 +#define SW_INT_ENABLE_REG2 0x48 + +#define SW_INT_MASK_REG0 0x50 +#define SW_INT_MASK_REG1 0x54 +#define SW_INT_MASK_REG2 0x58 + +#define SW_INT_IRQNO_ENMI 0 + +#define A10_INTR_MAX_NIRQS 81 + +#define SW_INT_IRQ_PENDING_REG(_b) (0x10 + ((_b) * 4)) +#define SW_INT_FIQ_PENDING_REG(_b) (0x20 + ((_b) * 4)) +#define SW_INT_SELECT_REG(_b) (0x30 + ((_b) * 4)) +#define SW_INT_ENABLE_REG(_b) (0x40 + ((_b) * 4)) +#define SW_INT_MASK_REG(_b) (0x50 + ((_b) * 4)) + +#ifdef INTRNG +struct a10_intr_irqsrc { + struct intr_irqsrc isrc; + u_int irq; }; +#endif struct a10_aintc_softc { device_t sc_dev; struct resource * aintc_res; bus_space_tag_t aintc_bst; bus_space_handle_t aintc_bsh; - uint8_t ver; + struct mtx mtx; +#ifdef INTRNG + struct a10_intr_irqsrc isrcs[A10_INTR_MAX_NIRQS]; +#endif }; +#define aintc_read_4(sc, reg) \ + bus_space_read_4(sc->aintc_bst, sc->aintc_bsh, reg) +#define aintc_write_4(sc, reg, val) \ + bus_space_write_4(sc->aintc_bst, sc->aintc_bsh, reg, val) + +static __inline void +a10_intr_eoi(struct a10_aintc_softc *sc, u_int irq) +{ + + if (irq != SW_INT_IRQNO_ENMI) + return; + mtx_lock_spin(&sc->mtx); + aintc_write_4(sc, SW_INT_IRQ_PENDING_REG(0), + (1 << SW_INT_IRQNO_ENMI)); + mtx_unlock_spin(&sc->mtx); +} + +static void +a10_intr_unmask(struct a10_aintc_softc *sc, u_int irq) +{ + uint32_t bit, block, value; + + bit = (irq % 32); + block = (irq / 32); + + mtx_lock_spin(&sc->mtx); + value = aintc_read_4(sc, SW_INT_ENABLE_REG(block)); + value |= (1 << bit); + aintc_write_4(sc, SW_INT_ENABLE_REG(block), value); + + value = aintc_read_4(sc, SW_INT_MASK_REG(block)); + value &= ~(1 << bit); + aintc_write_4(sc, SW_INT_MASK_REG(block), value); + mtx_unlock_spin(&sc->mtx); +} + +static void +a10_intr_mask(struct a10_aintc_softc *sc, u_int irq) +{ + uint32_t bit, block, value; + + bit = (irq % 32); + block = (irq / 32); + + mtx_lock_spin(&sc->mtx); + value = aintc_read_4(sc, SW_INT_ENABLE_REG(block)); + value &= ~(1 << bit); + aintc_write_4(sc, SW_INT_ENABLE_REG(block), value); + + value = aintc_read_4(sc, SW_INT_MASK_REG(block)); + value |= (1 << bit); + aintc_write_4(sc, SW_INT_MASK_REG(block), value); + mtx_unlock_spin(&sc->mtx); +} + +static int +a10_pending_irq(struct a10_aintc_softc *sc) +{ + uint32_t value; + int i, b; + + for (i = 0; i < 3; i++) { + value = aintc_read_4(sc, SW_INT_IRQ_PENDING_REG(i)); + if (value == 0) + continue; + for (b = 0; b < 32; b++) + if (value & (1 << b)) { + return (i * 32 + b); + } + } + + return (-1); +} + +#ifndef INTRNG + static struct a10_aintc_softc *a10_aintc_sc = NULL; -#define aintc_read_4(reg) \ - bus_space_read_4(a10_aintc_sc->aintc_bst, a10_aintc_sc->aintc_bsh, reg) -#define aintc_write_4(reg, val) \ - bus_space_write_4(a10_aintc_sc->aintc_bst, a10_aintc_sc->aintc_bsh, reg, val) +int +arm_get_next_irq(int last_irq) +{ + return (a10_pending_irq(a10_aintc_sc)); +} + +void +arm_mask_irq(uintptr_t irq) +{ + a10_intr_mask(a10_aintc_sc, irq); +} + +void +arm_unmask_irq(uintptr_t irq) +{ + a10_intr_unmask(a10_aintc_sc, irq); + a10_intr_eoi(a10_aintc_sc, irq); +} + +#else /* INTRNG */ + +static int +a10_intr(void *arg) +{ + struct a10_aintc_softc *sc = arg; + u_int irq; + + irq = a10_pending_irq(sc); + if (irq == -1 || irq > A10_INTR_MAX_NIRQS) { + device_printf(sc->sc_dev, "Spurious interrupt %d\n", irq); + return (FILTER_HANDLED); + } + + while (irq != -1) { + if (irq > A10_INTR_MAX_NIRQS) { + device_printf(sc->sc_dev, "Spurious interrupt %d\n", + irq); + return (FILTER_HANDLED); + } + if (intr_isrc_dispatch(&sc->isrcs[irq].isrc, + curthread->td_intr_frame) != 0) { + a10_intr_mask(sc, irq); + a10_intr_eoi(sc, irq); + device_printf(sc->sc_dev, + "Stray interrupt %d disabled\n", irq); + } + + arm_irq_memory_barrier(irq); + irq = a10_pending_irq(sc); + } + + return (FILTER_HANDLED); +} + +static int +a10_intr_pic_attach(struct a10_aintc_softc *sc) +{ + int error; + uint32_t irq; + const char *name; + intptr_t xref; + + name = device_get_nameunit(sc->sc_dev); + for (irq = 0; irq < A10_INTR_MAX_NIRQS; irq++) { + sc->isrcs[irq].irq = irq; + + error = intr_isrc_register(&sc->isrcs[irq].isrc, + sc->sc_dev, 0, "%s,%u", name, irq); + if (error != 0) + return (error); + } + + xref = OF_xref_from_node(ofw_bus_get_node(sc->sc_dev)); + error = intr_pic_register(sc->sc_dev, xref); + if (error != 0) + return (error); + + return (intr_pic_claim_root(sc->sc_dev, xref, a10_intr, sc, 0)); +} + +static void +a10_intr_enable_intr(device_t dev, struct intr_irqsrc *isrc) +{ + struct a10_aintc_softc *sc; + u_int irq = ((struct a10_intr_irqsrc *)isrc)->irq; + + sc = device_get_softc(dev); + arm_irq_memory_barrier(irq); + a10_intr_unmask(sc, irq); +} + +static void +a10_intr_disable_intr(device_t dev, struct intr_irqsrc *isrc) +{ + struct a10_aintc_softc *sc; + u_int irq = ((struct a10_intr_irqsrc *)isrc)->irq; + + sc = device_get_softc(dev); + a10_intr_mask(sc, irq); +} + +static int +a10_intr_map_intr(device_t dev, struct intr_map_data *data, + struct intr_irqsrc **isrcp) +{ + struct a10_aintc_softc *sc; + + if (data->type != INTR_MAP_DATA_FDT || data->fdt.ncells != 1 || + data->fdt.cells[0] >= A10_INTR_MAX_NIRQS) + return (EINVAL); + + sc = device_get_softc(dev); + *isrcp = &sc->isrcs[data->fdt.cells[0]].isrc; + return (0); +} + +static void +a10_intr_pre_ithread(device_t dev, struct intr_irqsrc *isrc) +{ + struct a10_aintc_softc *sc = device_get_softc(dev); + u_int irq = ((struct a10_intr_irqsrc *)isrc)->irq; + + a10_intr_mask(sc, irq); + a10_intr_eoi(sc, irq); +} + +static void +a10_intr_post_ithread(device_t dev, struct intr_irqsrc *isrc) +{ + + a10_intr_enable_intr(dev, isrc); +} + +static void +a10_intr_post_filter(device_t dev, struct intr_irqsrc *isrc) +{ + struct a10_aintc_softc *sc = device_get_softc(dev); + u_int irq = ((struct a10_intr_irqsrc *)isrc)->irq; + + a10_intr_eoi(sc, irq); +} + +#endif /* INTRNG */ static int a10_aintc_probe(device_t dev) @@ -107,7 +344,7 @@ a10_aintc_probe(device_t dev) if (!ofw_bus_status_okay(dev)) return (ENXIO); - if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + if (!ofw_bus_is_compatible(dev, "allwinner,sun4i-a10-ic")) return (ENXIO); device_set_desc(dev, "A10 AINTC Interrupt Controller"); return (BUS_PROBE_DEFAULT); @@ -119,40 +356,65 @@ a10_aintc_attach(device_t dev) struct a10_aintc_softc *sc = device_get_softc(dev); int rid = 0; int i; - sc->sc_dev = dev; +#ifndef INTRNG if (a10_aintc_sc) - return (ENXIO); + goto error; - sc->aintc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); + a10_aintc_sc = sc; +#endif + + sc->aintc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &rid, RF_ACTIVE); if (!sc->aintc_res) { device_printf(dev, "could not allocate resource\n"); - return (ENXIO); + goto error; } sc->aintc_bst = rman_get_bustag(sc->aintc_res); sc->aintc_bsh = rman_get_bushandle(sc->aintc_res); - a10_aintc_sc = sc; + mtx_init(&sc->mtx, "A10 AINTC lock", "", MTX_SPIN); /* Disable & clear all interrupts */ for (i = 0; i < 3; i++) { - aintc_write_4(SW_INT_ENABLE_REG(i), 0); - aintc_write_4(SW_INT_MASK_REG(i), 0xffffffff); + aintc_write_4(sc, SW_INT_ENABLE_REG(i), 0); + aintc_write_4(sc, SW_INT_MASK_REG(i), 0xffffffff); } /* enable protection mode*/ - aintc_write_4(SW_INT_PROTECTION_REG, 0x01); + aintc_write_4(sc, SW_INT_PROTECTION_REG, 0x01); /* config the external interrupt source type*/ - aintc_write_4(SW_INT_NMI_CTRL_REG, 0x00); + aintc_write_4(sc, SW_INT_NMI_CTRL_REG, 0x00); + +#ifdef INTRNG + if (a10_intr_pic_attach(sc) != 0) { + device_printf(dev, "could not attach PIC\n"); + return (ENXIO); + } +#endif return (0); + +error: + bus_release_resource(dev, SYS_RES_MEMORY, rid, + sc->aintc_res); + return (ENXIO); } static device_method_t a10_aintc_methods[] = { DEVMETHOD(device_probe, a10_aintc_probe), DEVMETHOD(device_attach, a10_aintc_attach), +#ifdef INTRNG + /* Interrupt controller interface */ + DEVMETHOD(pic_disable_intr, a10_intr_disable_intr), + DEVMETHOD(pic_enable_intr, a10_intr_enable_intr), + DEVMETHOD(pic_map_intr, a10_intr_map_intr), + DEVMETHOD(pic_post_filter, a10_intr_post_filter), + DEVMETHOD(pic_post_ithread, a10_intr_post_ithread), + DEVMETHOD(pic_pre_ithread, a10_intr_pre_ithread), +#endif { 0, 0 } }; @@ -166,57 +428,3 @@ static devclass_t a10_aintc_devclass; EARLY_DRIVER_MODULE(aintc, simplebus, a10_aintc_driver, a10_aintc_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_FIRST); - -int -arm_get_next_irq(int last_irq) -{ - uint32_t value; - int i, b; - - for (i = 0; i < 3; i++) { - value = aintc_read_4(SW_INT_IRQ_PENDING_REG(i)); - for (b = 0; b < 32; b++) - if (value & (1 << b)) { - return (i * 32 + b); - } - } - - return (-1); -} - -void -arm_mask_irq(uintptr_t nb) -{ - uint32_t bit, block, value; - - bit = (nb % 32); - block = (nb / 32); - - value = aintc_read_4(SW_INT_ENABLE_REG(block)); - value &= ~(1 << bit); - aintc_write_4(SW_INT_ENABLE_REG(block), value); - - value = aintc_read_4(SW_INT_MASK_REG(block)); - value |= (1 << bit); - aintc_write_4(SW_INT_MASK_REG(block), value); -} - -void -arm_unmask_irq(uintptr_t nb) -{ - uint32_t bit, block, value; - - bit = (nb % 32); - block = (nb / 32); - - value = aintc_read_4(SW_INT_ENABLE_REG(block)); - value |= (1 << bit); - aintc_write_4(SW_INT_ENABLE_REG(block), value); - - value = aintc_read_4(SW_INT_MASK_REG(block)); - value &= ~(1 << bit); - aintc_write_4(SW_INT_MASK_REG(block), value); - - if(nb == SW_INT_IRQNO_ENMI) /* must clear pending bit when enabled */ - aintc_write_4(SW_INT_IRQ_PENDING_REG(0), (1 << SW_INT_IRQNO_ENMI)); -} Modified: head/sys/arm/allwinner/files.a10 ============================================================================== --- head/sys/arm/allwinner/files.a10 Tue Apr 26 10:04:06 2016 (r298624) +++ head/sys/arm/allwinner/files.a10 Tue Apr 26 11:15:48 2016 (r298625) @@ -1,5 +1,5 @@ # $FreeBSD$ +arm/allwinner/a10/a10_intc.c standard arm/allwinner/a10_padconf.c standard -arm/allwinner/aintc.c standard arm/allwinner/timer.c standard Modified: head/sys/arm/conf/A10 ============================================================================== --- head/sys/arm/conf/A10 Tue Apr 26 10:04:06 2016 (r298624) +++ head/sys/arm/conf/A10 Tue Apr 26 11:15:48 2016 (r298625) @@ -23,6 +23,8 @@ ident A10 include "std.armv6" include "../allwinner/std.a10" +options INTRNG + options SOC_ALLWINNER_A10 options HZ=100