Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 5 Apr 2016 13:41:51 +0000 (UTC)
From:      Svatopluk Kraus <skra@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r297581 - in head/sys/arm: broadcom/bcm2835 conf
Message-ID:  <201604051341.u35DfpQo013530@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: skra
Date: Tue Apr  5 13:41:51 2016
New Revision: 297581
URL: https://svnweb.freebsd.org/changeset/base/297581

Log:
  Implement bcm2836 interrupt controller for INTRNG and enable it
  on RPI2 by default.
  
  Differential Revision:	https://reviews.freebsd.org/D5822

Modified:
  head/sys/arm/broadcom/bcm2835/bcm2836.c
  head/sys/arm/broadcom/bcm2835/bcm2836.h
  head/sys/arm/broadcom/bcm2835/bcm2836_mp.c
  head/sys/arm/conf/RPI2

Modified: head/sys/arm/broadcom/bcm2835/bcm2836.c
==============================================================================
--- head/sys/arm/broadcom/bcm2835/bcm2836.c	Tue Apr  5 13:37:03 2016	(r297580)
+++ head/sys/arm/broadcom/bcm2835/bcm2836.c	Tue Apr  5 13:41:51 2016	(r297581)
@@ -1,5 +1,6 @@
 /*
  * Copyright 2015 Andrew Turner.
+ * Copyright 2016 Svatopluk Kraus
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -28,19 +29,33 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include "opt_platform.h"
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/bus.h>
+#include <sys/cpuset.h>
 #include <sys/kernel.h>
 #include <sys/module.h>
+#include <sys/proc.h>
 #include <sys/rman.h>
+#ifdef SMP
+#include <sys/smp.h>
+#endif
 
 #include <machine/bus.h>
+#include <machine/intr.h>
 #include <machine/resource.h>
+#ifdef SMP
+#include <machine/smp.h>
+#endif
 
 #include <dev/ofw/ofw_bus_subr.h>
 #include <dev/ofw/ofw_bus.h>
 
+#ifdef ARM_INTRNG
+#include "pic_if.h"
+#else
 #include <arm/broadcom/bcm2835/bcm2836.h>
 
 #define	ARM_LOCAL_BASE	0x40000000
@@ -55,7 +70,703 @@ __FBSDID("$FreeBSD$");
 #define	 INT_PENDING_MASK		0x011f
 #define	MAILBOX0_IRQ			4
 #define	MAILBOX0_IRQEN			(1 << 0)
+#endif
+
+#ifdef ARM_INTRNG
+#define	BCM_LINTC_CONTROL_REG		0x00
+#define	BCM_LINTC_PRESCALER_REG		0x08
+#define	BCM_LINTC_GPU_ROUTING_REG	0x0c
+#define	BCM_LINTC_PMU_ROUTING_SET_REG	0x10
+#define	BCM_LINTC_PMU_ROUTING_CLR_REG	0x14
+#define	BCM_LINTC_TIMER_CFG_REG(n)	(0x40 + (n) * 4)
+#define	BCM_LINTC_MBOX_CFG_REG(n)	(0x50 + (n) * 4)
+#define	BCM_LINTC_PENDING_REG(n)	(0x60 + (n) * 4)
+#define	BCM_LINTC_MBOX0_SET_REG(n)	(0x80 + (n) * 16)
+#define	BCM_LINTC_MBOX1_SET_REG(n)	(0x84 + (n) * 16)
+#define	BCM_LINTC_MBOX2_SET_REG(n)	(0x88 + (n) * 16)
+#define	BCM_LINTC_MBOX3_SET_REG(n)	(0x8C + (n) * 16)
+#define	BCM_LINTC_MBOX0_CLR_REG(n)	(0xC0 + (n) * 16)
+#define	BCM_LINTC_MBOX1_CLR_REG(n)	(0xC4 + (n) * 16)
+#define	BCM_LINTC_MBOX2_CLR_REG(n)	(0xC8 + (n) * 16)
+#define	BCM_LINTC_MBOX3_CLR_REG(n)	(0xCC + (n) * 16)
+
+/* Prescaler Register */
+#define	BCM_LINTC_PSR_19_2		0x80000000	/* 19.2 MHz */
+
+/* GPU Interrupt Routing Register */
+#define	BCM_LINTC_GIRR_IRQ_CORE(n)	(n)
+#define	BCM_LINTC_GIRR_FIQ_CORE(n)	((n) << 2)
+
+/* PMU Interrupt Routing Register */
+#define	BCM_LINTC_PIRR_IRQ_EN_CORE(n)	(1 << (n))
+#define	BCM_LINTC_PIRR_FIQ_EN_CORE(n)	(1 << ((n) + 4))
+
+/* Timer Config Register */
+#define	BCM_LINTC_TCR_IRQ_EN_TIMER(n)	(1 << (n))
+#define	BCM_LINTC_TCR_FIQ_EN_TIMER(n)	(1 << ((n) + 4))
+
+/* MBOX Config Register */
+#define	BCM_LINTC_MCR_IRQ_EN_MBOX(n)	(1 << (n))
+#define	BCM_LINTC_MCR_FIQ_EN_MBOX(n)	(1 << ((n) + 4))
+
+#define	BCM_LINTC_CNTPSIRQ_IRQ		0
+#define	BCM_LINTC_CNTPNSIRQ_IRQ		1
+#define	BCM_LINTC_CNTHPIRQ_IRQ		2
+#define	BCM_LINTC_CNTVIRQ_IRQ		3
+#define	BCM_LINTC_MBOX0_IRQ		4
+#define	BCM_LINTC_MBOX1_IRQ		5
+#define	BCM_LINTC_MBOX2_IRQ		6
+#define	BCM_LINTC_MBOX3_IRQ		7
+#define	BCM_LINTC_GPU_IRQ		8
+#define	BCM_LINTC_PMU_IRQ		9
+#define	BCM_LINTC_AXI_IRQ		10
+#define	BCM_LINTC_LTIMER_IRQ		11
+
+#define	BCM_LINTC_NIRQS			12
+
+#define	BCM_LINTC_TIMER0_IRQ		BCM_LINTC_CNTPSIRQ_IRQ
+#define	BCM_LINTC_TIMER1_IRQ		BCM_LINTC_CNTPNSIRQ_IRQ
+#define	BCM_LINTC_TIMER2_IRQ		BCM_LINTC_CNTHPIRQ_IRQ
+#define	BCM_LINTC_TIMER3_IRQ		BCM_LINTC_CNTVIRQ_IRQ
+
+#define	BCM_LINTC_TIMER0_IRQ_MASK	(1 << BCM_LINTC_TIMER0_IRQ)
+#define	BCM_LINTC_TIMER1_IRQ_MASK	(1 << BCM_LINTC_TIMER1_IRQ)
+#define	BCM_LINTC_TIMER2_IRQ_MASK	(1 << BCM_LINTC_TIMER2_IRQ)
+#define	BCM_LINTC_TIMER3_IRQ_MASK	(1 << BCM_LINTC_TIMER3_IRQ)
+#define	BCM_LINTC_MBOX0_IRQ_MASK	(1 << BCM_LINTC_MBOX0_IRQ)
+#define	BCM_LINTC_GPU_IRQ_MASK		(1 << BCM_LINTC_GPU_IRQ)
+#define	BCM_LINTC_PMU_IRQ_MASK		(1 << BCM_LINTC_PMU_IRQ)
+
+#define	BCM_LINTC_UP_PENDING_MASK	\
+    (BCM_LINTC_TIMER0_IRQ_MASK |	\
+     BCM_LINTC_TIMER1_IRQ_MASK |	\
+     BCM_LINTC_TIMER2_IRQ_MASK |	\
+     BCM_LINTC_TIMER3_IRQ_MASK |	\
+     BCM_LINTC_GPU_IRQ_MASK |		\
+     BCM_LINTC_PMU_IRQ_MASK)
+
+#define	BCM_LINTC_SMP_PENDING_MASK	\
+    (BCM_LINTC_UP_PENDING_MASK |	\
+     BCM_LINTC_MBOX0_IRQ_MASK)
+
+#ifdef SMP
+#define BCM_LINTC_PENDING_MASK		BCM_LINTC_SMP_PENDING_MASK
+#else
+#define BCM_LINTC_PENDING_MASK		BCM_LINTC_UP_PENDING_MASK
+#endif
+
+struct bcm_lintc_irqsrc {
+	struct intr_irqsrc	bli_isrc;
+	u_int			bli_irq;
+	union {
+		u_int		bli_mask;	/* for timers */
+		u_int		bli_value;	/* for GPU */
+	};
+};
+
+struct bcm_lintc_softc {
+	device_t		bls_dev;
+	struct mtx		bls_mtx;
+	struct resource *	bls_mem;
+	bus_space_tag_t		bls_bst;
+	bus_space_handle_t	bls_bsh;
+	struct bcm_lintc_irqsrc	bls_isrcs[BCM_LINTC_NIRQS];
+};
+
+static struct bcm_lintc_softc *bcm_lintc_sc;
+
+#ifdef SMP
+#define BCM_LINTC_NIPIS		32	/* only mailbox 0 is used for IPI */
+CTASSERT(INTR_IPI_COUNT <= BCM_LINTC_NIPIS);
+#endif
+
+#define	BCM_LINTC_LOCK(sc)		mtx_lock_spin(&(sc)->bls_mtx)
+#define	BCM_LINTC_UNLOCK(sc)		mtx_unlock_spin(&(sc)->bls_mtx)
+#define	BCM_LINTC_LOCK_INIT(sc)		mtx_init(&(sc)->bls_mtx,	\
+    device_get_nameunit((sc)->bls_dev), "bmc_local_intc", MTX_SPIN)
+#define	BCM_LINTC_LOCK_DESTROY(sc)	mtx_destroy(&(sc)->bls_mtx)
+
+#define	bcm_lintc_read_4(sc, reg)		\
+    bus_space_read_4((sc)->bls_bst, (sc)->bls_bsh, (reg))
+#define	bcm_lintc_write_4(sc, reg, val)		\
+    bus_space_write_4((sc)->bls_bst, (sc)->bls_bsh, (reg), (val))
+
+static inline void
+bcm_lintc_rwreg_clr(struct bcm_lintc_softc *sc, uint32_t reg,
+    uint32_t mask)
+{
+
+	bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) & ~mask);
+}
+
+static inline void
+bcm_lintc_rwreg_set(struct bcm_lintc_softc *sc, uint32_t reg,
+    uint32_t mask)
+{
+
+	bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) | mask);
+}
+
+static void
+bcm_lintc_timer_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
+{
+	cpuset_t *cpus;
+	uint32_t cpu;
+
+	cpus = &bli->bli_isrc.isrc_cpu;
+
+	BCM_LINTC_LOCK(sc);
+	for (cpu = 0; cpu < 4; cpu++)
+		if (CPU_ISSET(cpu, cpus))
+			bcm_lintc_rwreg_clr(sc, BCM_LINTC_TIMER_CFG_REG(cpu),
+			    bli->bli_mask);
+	BCM_LINTC_UNLOCK(sc);
+}
+
+static void
+bcm_lintc_timer_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
+{
+	cpuset_t *cpus;
+	uint32_t cpu;
+
+	cpus = &bli->bli_isrc.isrc_cpu;
+
+	BCM_LINTC_LOCK(sc);
+	for (cpu = 0; cpu < 4; cpu++)
+		if (CPU_ISSET(cpu, cpus))
+			bcm_lintc_rwreg_set(sc, BCM_LINTC_TIMER_CFG_REG(cpu),
+			    bli->bli_mask);
+	BCM_LINTC_UNLOCK(sc);
+}
+
+static inline void
+bcm_lintc_gpu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
+{
+
+	/* It's accessed just and only by one core. */
+	bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, 0);
+}
+
+static inline void
+bcm_lintc_gpu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
+{
+
+	/* It's accessed just and only by one core. */
+	bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, bli->bli_value);
+}
+
+static inline void
+bcm_lintc_pmu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
+{
+	cpuset_t *cpus;
+	uint32_t cpu, mask;
+
+	mask = 0;
+	cpus = &bli->bli_isrc.isrc_cpu;
+
+	BCM_LINTC_LOCK(sc);
+	for (cpu = 0; cpu < 4; cpu++)
+		if (CPU_ISSET(cpu, cpus))
+			mask |= BCM_LINTC_PIRR_IRQ_EN_CORE(cpu);
+	/* Write-clear register. */
+	bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_CLR_REG, mask);
+	BCM_LINTC_UNLOCK(sc);
+}
+
+static inline void
+bcm_lintc_pmu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
+{
+	cpuset_t *cpus;
+	uint32_t cpu, mask;
+
+	mask = 0;
+	cpus = &bli->bli_isrc.isrc_cpu;
+
+	BCM_LINTC_LOCK(sc);
+	for (cpu = 0; cpu < 4; cpu++)
+		if (CPU_ISSET(cpu, cpus))
+			mask |= BCM_LINTC_PIRR_IRQ_EN_CORE(cpu);
+	/* Write-set register. */
+	bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_SET_REG, mask);
+	BCM_LINTC_UNLOCK(sc);
+}
+
+static void
+bcm_lintc_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
+{
+
+	switch (bli->bli_irq) {
+	case BCM_LINTC_TIMER0_IRQ:
+	case BCM_LINTC_TIMER1_IRQ:
+	case BCM_LINTC_TIMER2_IRQ:
+	case BCM_LINTC_TIMER3_IRQ:
+		bcm_lintc_timer_mask(sc, bli);
+		return;
+	case BCM_LINTC_MBOX0_IRQ:
+	case BCM_LINTC_MBOX1_IRQ:
+	case BCM_LINTC_MBOX2_IRQ:
+	case BCM_LINTC_MBOX3_IRQ:
+		return;
+	case BCM_LINTC_GPU_IRQ:
+		bcm_lintc_gpu_mask(sc, bli);
+		return;
+	case BCM_LINTC_PMU_IRQ:
+		bcm_lintc_pmu_mask(sc, bli);
+		return;
+	default:
+		panic("%s: not implemented for irq %u", __func__, bli->bli_irq);
+	}
+}
+
+static void
+bcm_lintc_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli)
+{
+
+	switch (bli->bli_irq) {
+	case BCM_LINTC_TIMER0_IRQ:
+	case BCM_LINTC_TIMER1_IRQ:
+	case BCM_LINTC_TIMER2_IRQ:
+	case BCM_LINTC_TIMER3_IRQ:
+		bcm_lintc_timer_unmask(sc, bli);
+		return;
+	case BCM_LINTC_MBOX0_IRQ:
+	case BCM_LINTC_MBOX1_IRQ:
+	case BCM_LINTC_MBOX2_IRQ:
+	case BCM_LINTC_MBOX3_IRQ:
+		return;
+	case BCM_LINTC_GPU_IRQ:
+		bcm_lintc_gpu_unmask(sc, bli);
+		return;
+	case BCM_LINTC_PMU_IRQ:
+		bcm_lintc_pmu_unmask(sc, bli);
+		return;
+	default:
+		panic("%s: not implemented for irq %u", __func__, bli->bli_irq);
+	}
+}
+
+#ifdef SMP
+static inline void
+bcm_lintc_ipi_write(struct bcm_lintc_softc *sc, cpuset_t cpus, u_int ipi)
+{
+	u_int cpu;
+	uint32_t mask;
+
+	mask = 1 << ipi;
+	for (cpu = 0; cpu < mp_ncpus; cpu++)
+		if (CPU_ISSET(cpu, &cpus))
+			bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_SET_REG(cpu),
+			    mask);
+}
+
+static inline void
+bcm_lintc_ipi_dispatch(struct bcm_lintc_softc *sc, u_int cpu,
+    struct trapframe *tf)
+{
+	u_int ipi;
+	uint32_t mask;
+
+	mask = bcm_lintc_read_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu));
+	if (mask == 0) {
+		device_printf(sc->bls_dev, "Spurious ipi detected\n");
+		return;
+	}
+
+	for (ipi = 0; mask != 0; mask >>= 1, ipi++) {
+		if ((mask & 0x01) == 0)
+			continue;
+		/*
+		 * Clear an IPI before dispatching to not miss anyone
+		 * and make sure that it's observed by everybody.
+		 */
+		bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu), 1 << ipi);
+		dsb();
+		intr_ipi_dispatch(ipi, tf);
+	}
+}
+#endif
+
+static inline void
+bcm_lintc_irq_dispatch(struct bcm_lintc_softc *sc, u_int irq,
+    struct trapframe *tf)
+{
+	struct bcm_lintc_irqsrc *bli;
+
+	bli = &sc->bls_isrcs[irq];
+	if (intr_isrc_dispatch(&bli->bli_isrc, tf) != 0)
+		device_printf(sc->bls_dev, "Stray irq %u detected\n", irq);
+}
+
+static int
+bcm_lintc_intr(void *arg)
+{
+	struct bcm_lintc_softc *sc;
+	u_int cpu;
+	uint32_t num, reg;
+	struct trapframe *tf;
+
+	sc = arg;
+	cpu = PCPU_GET(cpuid);
+	tf = curthread->td_intr_frame;
+
+	for (num = 0; ; num++) {
+		reg = bcm_lintc_read_4(sc, BCM_LINTC_PENDING_REG(cpu));
+		if ((reg & BCM_LINTC_PENDING_MASK) == 0)
+			break;
+#ifdef SMP
+		if (reg & BCM_LINTC_MBOX0_IRQ_MASK)
+			bcm_lintc_ipi_dispatch(sc, cpu, tf);
+#endif
+		if (reg & BCM_LINTC_TIMER0_IRQ_MASK)
+			bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER0_IRQ, tf);
+		if (reg & BCM_LINTC_TIMER1_IRQ_MASK)
+			bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER1_IRQ, tf);
+		if (reg & BCM_LINTC_TIMER2_IRQ_MASK)
+			bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER2_IRQ, tf);
+		if (reg & BCM_LINTC_TIMER3_IRQ_MASK)
+			bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER3_IRQ, tf);
+		if (reg & BCM_LINTC_GPU_IRQ_MASK)
+			bcm_lintc_irq_dispatch(sc, BCM_LINTC_GPU_IRQ, tf);
+		if (reg & BCM_LINTC_PMU_IRQ_MASK)
+			bcm_lintc_irq_dispatch(sc, BCM_LINTC_PMU_IRQ, tf);
+
+		arm_irq_memory_barrier(0); /* XXX */
+	}
+	reg &= ~BCM_LINTC_PENDING_MASK;
+	if (reg != 0)
+		device_printf(sc->bls_dev, "Unknown interrupt(s) %x\n", reg);
+	else if (num == 0)
+		device_printf(sc->bls_dev, "Spurious interrupt detected\n");
+
+	return (FILTER_HANDLED);
+}
+
+static void
+bcm_lintc_disable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+
+	bcm_lintc_mask(device_get_softc(dev), (struct bcm_lintc_irqsrc *)isrc);
+}
+
+static void
+bcm_lintc_enable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+	struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
+
+	arm_irq_memory_barrier(bli->bli_irq);
+	bcm_lintc_unmask(device_get_softc(dev), bli);
+}
+
+static int
+bcm_lintc_map_intr(device_t dev, struct intr_map_data *data,
+    struct intr_irqsrc **isrcp)
+{
+	struct bcm_lintc_softc *sc;
+
+	if (data->type != INTR_MAP_DATA_FDT)
+		return (ENOTSUP);
+	if (data->fdt.ncells != 1 || data->fdt.cells[0] >= BCM_LINTC_NIRQS)
+		return (EINVAL);
+
+	sc = device_get_softc(dev);
+	*isrcp = &sc->bls_isrcs[data->fdt.cells[0]].bli_isrc;
+	return (0);
+}
 
+static void
+bcm_lintc_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+	struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
+
+	if (bli->bli_irq == BCM_LINTC_GPU_IRQ)
+		bcm_lintc_gpu_mask(device_get_softc(dev), bli);
+	else {
+		/*
+		 * Handler for PPI interrupt does not make sense much unless
+		 * there is one bound ithread for each core for it. Thus the
+		 * interrupt can be masked on current core only while ithread
+		 * bounded to this core ensures unmasking on the same core.
+		 */
+		panic ("%s: handlers are not supported", __func__);
+	}
+}
+
+static void
+bcm_lintc_post_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+	struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc;
+
+	if (bli->bli_irq == BCM_LINTC_GPU_IRQ)
+		bcm_lintc_gpu_unmask(device_get_softc(dev), bli);
+	else {
+		/* See comment in bcm_lintc_pre_ithread(). */
+		panic ("%s: handlers are not supported", __func__);
+	}
+}
+
+static void
+bcm_lintc_post_filter(device_t dev, struct intr_irqsrc *isrc)
+{
+}
+
+static int
+bcm_lintc_setup_intr(device_t dev, struct intr_irqsrc *isrc,
+    struct resource *res, struct intr_map_data *data)
+{
+	struct bcm_lintc_softc *sc;
+
+	if (isrc->isrc_handlers == 0 && isrc->isrc_flags & INTR_ISRCF_PPI) {
+		sc = device_get_softc(dev);
+		BCM_LINTC_LOCK(sc);
+		CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu);
+		BCM_LINTC_UNLOCK(sc);
+	}
+	return (0);
+}
+
+#ifdef SMP
+static bool
+bcm_lint_init_on_ap(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli,
+    u_int cpu)
+{
+	struct intr_irqsrc *isrc;
+
+	isrc = &bli->bli_isrc;
+
+	KASSERT(isrc->isrc_flags & INTR_ISRCF_PPI,
+	    ("%s: irq %d is not PPI", __func__, bli->bli_irq));
+
+	if (isrc->isrc_handlers == 0)
+		return (false);
+	if (isrc->isrc_flags & INTR_ISRCF_BOUND)
+		return (CPU_ISSET(cpu, &isrc->isrc_cpu));
+
+	CPU_SET(cpu, &isrc->isrc_cpu);
+	return (true);
+}
+
+static void
+bcm_lintc_init_rwreg_on_ap(struct bcm_lintc_softc *sc, u_int cpu, u_int irq,
+    uint32_t reg, uint32_t mask)
+{
+
+	if (bcm_lint_init_on_ap(sc, &sc->bls_isrcs[irq], cpu))
+		bcm_lintc_rwreg_set(sc, reg, mask);
+}
+
+static void
+bcm_lintc_init_pmu_on_ap(struct bcm_lintc_softc *sc, u_int cpu)
+{
+
+	if (bcm_lint_init_on_ap(sc, &sc->bls_isrcs[BCM_LINTC_PMU_IRQ], cpu)) {
+		/* Write-set register. */
+		bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_SET_REG,
+		    BCM_LINTC_PIRR_IRQ_EN_CORE(cpu));
+	}
+}
+
+static void
+bcm_lintc_init_secondary(device_t dev)
+{
+	u_int cpu;
+	struct bcm_lintc_softc *sc;
+
+	cpu = PCPU_GET(cpuid);
+	sc = device_get_softc(dev);
+
+	BCM_LINTC_LOCK(sc);
+	bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER0_IRQ,
+	    BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(0));
+	bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER1_IRQ,
+	    BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(1));
+	bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER2_IRQ,
+	    BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(2));
+	bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER3_IRQ,
+	    BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(3));
+	bcm_lintc_init_pmu_on_ap(sc, cpu);
+	BCM_LINTC_UNLOCK(sc);
+}
+
+static void
+bcm_lintc_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus,
+    u_int ipi)
+{
+	struct bcm_lintc_softc *sc = device_get_softc(dev);
+
+	KASSERT(isrc == &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc,
+	    ("%s: bad ISRC %p argument", __func__, isrc));
+	bcm_lintc_ipi_write(sc, cpus, ipi);
+}
+
+static int
+bcm_lintc_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc **isrcp)
+{
+	struct bcm_lintc_softc *sc = device_get_softc(dev);
+
+	KASSERT(ipi < BCM_LINTC_NIPIS, ("%s: too high ipi %u", __func__, ipi));
+
+	*isrcp = &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc;
+	return (0);
+}
+#endif
+
+static int
+bcm_lintc_pic_attach(struct bcm_lintc_softc *sc)
+{
+	struct bcm_lintc_irqsrc *bisrcs;
+	int error;
+	u_int flags;
+	uint32_t irq;
+	const char *name;
+	intptr_t xref;
+
+	bisrcs = sc->bls_isrcs;
+	name = device_get_nameunit(sc->bls_dev);
+	for (irq = 0; irq < BCM_LINTC_NIRQS; irq++) {
+		bisrcs[irq].bli_irq = irq;
+		switch (irq) {
+		case BCM_LINTC_TIMER0_IRQ:
+			bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(0);
+			flags = INTR_ISRCF_PPI;
+			break;
+		case BCM_LINTC_TIMER1_IRQ:
+			bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(1);
+			flags = INTR_ISRCF_PPI;
+			break;
+		case BCM_LINTC_TIMER2_IRQ:
+			bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(2);
+			flags = INTR_ISRCF_PPI;
+			break;
+		case BCM_LINTC_TIMER3_IRQ:
+			bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(3);
+			flags = INTR_ISRCF_PPI;
+			break;
+		case BCM_LINTC_MBOX0_IRQ:
+		case BCM_LINTC_MBOX1_IRQ:
+		case BCM_LINTC_MBOX2_IRQ:
+		case BCM_LINTC_MBOX3_IRQ:
+			bisrcs[irq].bli_value = 0;	/* not used */
+			flags = INTR_ISRCF_IPI;
+			break;
+		case BCM_LINTC_GPU_IRQ:
+			bisrcs[irq].bli_value = BCM_LINTC_GIRR_IRQ_CORE(0);
+			flags = 0;
+			break;
+		case BCM_LINTC_PMU_IRQ:
+			bisrcs[irq].bli_value = 0;	/* not used */
+			flags = INTR_ISRCF_PPI;
+			break;
+		default:
+			bisrcs[irq].bli_value = 0;	/* not used */
+			flags = 0;
+			break;
+		}
+
+		error = intr_isrc_register(&bisrcs[irq].bli_isrc, sc->bls_dev,
+		    flags, "%s,%u", name, irq);
+		if (error != 0)
+			return (error);
+	}
+
+	xref = OF_xref_from_node(ofw_bus_get_node(sc->bls_dev));
+	error = intr_pic_register(sc->bls_dev, xref);
+	if (error != 0)
+		return (error);
+
+	return (intr_pic_claim_root(sc->bls_dev, xref, bcm_lintc_intr, sc, 0));
+}
+
+static int
+bcm_lintc_probe(device_t dev)
+{
+
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (!ofw_bus_is_compatible(dev, "brcm,bcm2836-l1-intc"))
+		return (ENXIO);
+	device_set_desc(dev, "BCM2836 Interrupt Controller");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+bcm_lintc_attach(device_t dev)
+{
+	struct bcm_lintc_softc *sc;
+	int cpu, rid;
+
+	sc = device_get_softc(dev);
+
+	sc->bls_dev = dev;
+	if (bcm_lintc_sc != NULL)
+		return (ENXIO);
+
+	rid = 0;
+	sc->bls_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+	    RF_ACTIVE);
+	if (sc->bls_mem == NULL) {
+		device_printf(dev, "could not allocate memory resource\n");
+		return (ENXIO);
+	}
+
+	sc->bls_bst = rman_get_bustag(sc->bls_mem);
+	sc->bls_bsh = rman_get_bushandle(sc->bls_mem);
+
+	bcm_lintc_write_4(sc, BCM_LINTC_CONTROL_REG, 0);
+	bcm_lintc_write_4(sc, BCM_LINTC_PRESCALER_REG, BCM_LINTC_PSR_19_2);
+
+	/* Disable all timers on all cores. */
+	for (cpu = 0; cpu < 4; cpu++)
+		bcm_lintc_write_4(sc, BCM_LINTC_TIMER_CFG_REG(cpu), 0);
+
+#ifdef SMP
+	/* Enable mailbox 0 on all cores used for IPI. */
+	for (cpu = 0; cpu < 4; cpu++)
+		bcm_lintc_write_4(sc, BCM_LINTC_MBOX_CFG_REG(cpu),
+		    BCM_LINTC_MCR_IRQ_EN_MBOX(0));
+#endif
+
+	if (bcm_lintc_pic_attach(sc) != 0) {
+		device_printf(dev, "could not attach PIC\n");
+		return (ENXIO);
+	}
+
+	BCM_LINTC_LOCK_INIT(sc);
+	bcm_lintc_sc = sc;
+	return (0);
+}
+
+static device_method_t bcm_lintc_methods[] = {
+	DEVMETHOD(device_probe,		bcm_lintc_probe),
+	DEVMETHOD(device_attach,	bcm_lintc_attach),
+
+	DEVMETHOD(pic_disable_intr,	bcm_lintc_disable_intr),
+	DEVMETHOD(pic_enable_intr,	bcm_lintc_enable_intr),
+	DEVMETHOD(pic_map_intr,		bcm_lintc_map_intr),
+	DEVMETHOD(pic_post_filter,	bcm_lintc_post_filter),
+	DEVMETHOD(pic_post_ithread,	bcm_lintc_post_ithread),
+	DEVMETHOD(pic_pre_ithread,	bcm_lintc_pre_ithread),
+	DEVMETHOD(pic_setup_intr,	bcm_lintc_setup_intr),
+#ifdef SMP
+	DEVMETHOD(pic_init_secondary,	bcm_lintc_init_secondary),
+	DEVMETHOD(pic_ipi_send,		bcm_lintc_ipi_send),
+	DEVMETHOD(pic_ipi_setup,	bcm_lintc_ipi_setup),
+#endif
+
+	DEVMETHOD_END
+};
+
+static driver_t bcm_lintc_driver = {
+	"local_intc",
+	bcm_lintc_methods,
+	sizeof(struct bcm_lintc_softc),
+};
+
+static devclass_t bcm_lintc_devclass;
+
+EARLY_DRIVER_MODULE(local_intc, simplebus, bcm_lintc_driver, bcm_lintc_devclass,
+    0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
+#else
 /*
  * A driver for features of the bcm2836.
  */
@@ -214,3 +925,4 @@ static driver_t bcm2836_driver = {
 
 EARLY_DRIVER_MODULE(bcm2836, nexus, bcm2836_driver, bcm2836_devclass, 0, 0,
     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
+#endif

Modified: head/sys/arm/broadcom/bcm2835/bcm2836.h
==============================================================================
--- head/sys/arm/broadcom/bcm2835/bcm2836.h	Tue Apr  5 13:37:03 2016	(r297580)
+++ head/sys/arm/broadcom/bcm2835/bcm2836.h	Tue Apr  5 13:41:51 2016	(r297581)
@@ -30,10 +30,11 @@
 #ifndef _BCM2815_BCM2836_H
 #define	_BCM2815_BCM2836_H
 
+#ifndef ARM_INTRNG
 #define	BCM2836_GPU_IRQ		8
 
 int bcm2836_get_next_irq(int);
 void bcm2836_mask_irq(uintptr_t);
 void bcm2836_unmask_irq(uintptr_t);
-
+#endif
 #endif

Modified: head/sys/arm/broadcom/bcm2835/bcm2836_mp.c
==============================================================================
--- head/sys/arm/broadcom/bcm2835/bcm2836_mp.c	Tue Apr  5 13:37:03 2016	(r297580)
+++ head/sys/arm/broadcom/bcm2835/bcm2836_mp.c	Tue Apr  5 13:41:51 2016	(r297581)
@@ -139,6 +139,7 @@ platform_mp_start_ap(void)
 	}
 }
 
+#ifndef ARM_INTRNG
 void
 pic_ipi_send(cpuset_t cpus, u_int ipi)
 {
@@ -176,3 +177,4 @@ void
 pic_ipi_clear(int ipi)
 {
 }
+#endif

Modified: head/sys/arm/conf/RPI2
==============================================================================
--- head/sys/arm/conf/RPI2	Tue Apr  5 13:37:03 2016	(r297580)
+++ head/sys/arm/conf/RPI2	Tue Apr  5 13:41:51 2016	(r297581)
@@ -24,6 +24,8 @@ include 	"std.armv6"
 include 	"../broadcom/bcm2835/std.rpi"
 include 	"../broadcom/bcm2835/std.bcm2836"
 
+options 	ARM_INTRNG
+
 options 	HZ=100
 options 	SCHED_ULE		# ULE scheduler
 options 	SMP			# Enable multiple cores



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201604051341.u35DfpQo013530>