Home | History | Annotate | Line # | Download | only in broadcom
bcm2835_intr.c revision 1.5
      1 /*	$NetBSD: bcm2835_intr.c,v 1.5 2015/02/28 09:34:34 skrll Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2012 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Nick Hudson
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: bcm2835_intr.c,v 1.5 2015/02/28 09:34:34 skrll Exp $");
     34 
     35 #define _INTR_PRIVATE
     36 
     37 #include "opt_bcm283x.h"
     38 
     39 #include <sys/param.h>
     40 #include <sys/bus.h>
     41 #include <sys/cpu.h>
     42 #include <sys/device.h>
     43 #include <sys/proc.h>
     44 
     45 #include <machine/intr.h>
     46 
     47 #include <arm/locore.h>
     48 
     49 #include <arm/pic/picvar.h>
     50 #include <arm/cortex/gtmr_var.h>
     51 
     52 #include <arm/broadcom/bcm_amba.h>
     53 #include <arm/broadcom/bcm2835reg.h>
     54 #include <arm/broadcom/bcm2835var.h>
     55 
     56 static void bcm2835_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
     57 static void bcm2835_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
     58 static int bcm2835_pic_find_pending_irqs(struct pic_softc *);
     59 static void bcm2835_pic_establish_irq(struct pic_softc *, struct intrsource *);
     60 static void bcm2835_pic_source_name(struct pic_softc *, int, char *,
     61     size_t);
     62 
     63 #if defined(BCM2836)
     64 static void bcm2836mp_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
     65 static void bcm2836mp_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
     66 static int bcm2836mp_pic_find_pending_irqs(struct pic_softc *);
     67 static void bcm2836mp_pic_establish_irq(struct pic_softc *, struct intrsource *);
     68 static void bcm2836mp_pic_source_name(struct pic_softc *, int, char *,
     69     size_t);
     70 #ifdef MULTIPROCESSOR
     71 int bcm2836mp_ipi_handler(void *);
     72 static void bcm2836mp_cpu_init(struct pic_softc *, struct cpu_info *);
     73 static void bcm2836mp_send_ipi(struct pic_softc *, const kcpuset_t *, u_long);
     74 #endif
     75 #endif
     76 
     77 
     78 static int  bcm2835_icu_match(device_t, cfdata_t, void *);
     79 static void bcm2835_icu_attach(device_t, device_t, void *);
     80 
     81 static struct pic_ops bcm2835_picops = {
     82 	.pic_unblock_irqs = bcm2835_pic_unblock_irqs,
     83 	.pic_block_irqs = bcm2835_pic_block_irqs,
     84 	.pic_find_pending_irqs = bcm2835_pic_find_pending_irqs,
     85 	.pic_establish_irq = bcm2835_pic_establish_irq,
     86 	.pic_source_name = bcm2835_pic_source_name,
     87 };
     88 
     89 struct pic_softc bcm2835_pic = {
     90 	.pic_ops = &bcm2835_picops,
     91 	.pic_maxsources = BCM2835_NIRQ,
     92 	.pic_name = "bcm2835 pic",
     93 };
     94 
     95 #if defined(BCM2836)
     96 static struct pic_ops bcm2836mp_picops = {
     97 	.pic_unblock_irqs = bcm2836mp_pic_unblock_irqs,
     98 	.pic_block_irqs = bcm2836mp_pic_block_irqs,
     99 	.pic_find_pending_irqs = bcm2836mp_pic_find_pending_irqs,
    100 	.pic_establish_irq = bcm2836mp_pic_establish_irq,
    101 	.pic_source_name = bcm2836mp_pic_source_name,
    102 #ifdef MULTIPROCESSOR
    103 	.pic_cpu_init = bcm2836mp_cpu_init,
    104 	.pic_ipi_send = bcm2836mp_send_ipi,
    105 #endif
    106 };
    107 
    108 struct pic_softc bcm2836mp_pic = {
    109 	.pic_ops = &bcm2836mp_picops,
    110 	.pic_maxsources = BCM2836MP_NIRQ,
    111 	.pic_name = "bcm2836 mp pic",
    112 };
    113 #endif
    114 
    115 struct bcm2835icu_softc {
    116 	device_t		sc_dev;
    117 	bus_space_tag_t		sc_iot;
    118 	bus_space_handle_t	sc_ioh;
    119 	struct pic_softc	*sc_pic;
    120 };
    121 
    122 struct bcm2835icu_softc *bcmicu_sc;
    123 
    124 #define read_bcm2835reg(o)	\
    125 	bus_space_read_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o))
    126 
    127 #define write_bcm2835reg(o, v)	\
    128 	bus_space_write_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o), (v))
    129 
    130 
    131 #define bcm2835_barrier() \
    132 	bus_space_barrier(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, 0, \
    133 	    BCM2835_ARMICU_SIZE, BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
    134 
    135 static const char * const bcm2835_sources[BCM2835_NIRQ] = {
    136 	"(unused  0)",	"(unused  1)",	"(unused  2)",	"timer3",
    137 	"(unused  4)",	"(unused  5)",	"(unused  6)",	"jpeg",
    138 	"(unused  8)",	"usb",		"(unused 10)",	"(unused 11)",
    139 	"(unused 12)",	"(unused 13)",	"(unused 14)",	"(unused 15)",
    140 	"dma0",		"dma1",		"dma2",		"dma3",
    141 	"dma4",		"dma5",		"dma6",		"dma7",
    142 	"dma8",		"dma9",		"dma10",	"dma11",
    143 	"dma12",	"aux",		"(unused 30)",	"(unused 31)",
    144 	"(unused 32)",	"(unused 33)",	"(unused 34)",	"(unused 35)",
    145 	"(unused 36)",	"(unused 37)",	"(unused 38)",	"(unused 39)",
    146 	"(unused 40)",	"(unused 41)",	"(unused 42)",	"i2c spl slv",
    147 	"(unused 44)",	"pwa0",		"pwa1",		"(unused 47)",
    148 	"smi",		"gpio[0]",	"gpio[1]",	"gpio[2]",
    149 	"gpio[3]",	"i2c",		"spi",		"pcm",
    150 	"sdio",		"uart",		"(unused 58)",	"(unused 59)",
    151 	"(unused 60)",	"(unused 61)",	"emmc",		"(unused 63)",
    152 	"Timer",	"Mailbox",	"Doorbell0",	"Doorbell1",
    153 	"GPU0 Halted",	"GPU1 Halted",	"Illegal #1",	"Illegal #0"
    154 };
    155 
    156 #if defined(BCM2836)
    157 static const char * const bcm2836mp_sources[BCM2836MP_NIRQ] = {
    158 	"cntpsirq",	"cntpnsirq",	"cnthpirq",	"cntvirq",
    159 	"mailbox0",	"mailbox1",	"mailbox2",	"mailbox3",
    160 };
    161 #endif
    162 
    163 #define	BCM2836_INTBIT_GPUPENDING	__BIT(8)
    164 
    165 #define	BCM2835_INTBIT_PENDING1		__BIT(8)
    166 #define	BCM2835_INTBIT_PENDING2		__BIT(9)
    167 #define	BCM2835_INTBIT_ARM		__BITS(0,7)
    168 #define	BCM2835_INTBIT_GPU0		__BITS(10,14)
    169 #define	BCM2835_INTBIT_GPU1		__BITS(15,20)
    170 
    171 CFATTACH_DECL_NEW(bcmicu, sizeof(struct bcm2835icu_softc),
    172     bcm2835_icu_match, bcm2835_icu_attach, NULL, NULL);
    173 
    174 static int
    175 bcm2835_icu_match(device_t parent, cfdata_t cf, void *aux)
    176 {
    177 	struct amba_attach_args *aaa = aux;
    178 
    179 	if (strcmp(aaa->aaa_name, "icu") != 0)
    180 		return 0;
    181 
    182 	return 1;
    183 }
    184 
    185 static void
    186 bcm2835_icu_attach(device_t parent, device_t self, void *aux)
    187 {
    188 	struct bcm2835icu_softc *sc = device_private(self);
    189 	struct amba_attach_args *aaa = aux;
    190 
    191 	sc->sc_dev = self;
    192 	sc->sc_iot = aaa->aaa_iot;
    193 	sc->sc_pic = &bcm2835_pic;
    194 
    195 	if (bus_space_map(aaa->aaa_iot, aaa->aaa_addr, aaa->aaa_size, 0,
    196 	    &sc->sc_ioh)) {
    197 		aprint_error_dev(self, "unable to map device\n");
    198 		return;
    199 	}
    200 
    201 	bcmicu_sc = sc;
    202 
    203 	pic_add(sc->sc_pic, 0);
    204 
    205 #if defined(BCM2836)
    206 #ifdef MULTIPROCESSOR
    207 	aprint_normal(": Multiprocessor");
    208 #endif
    209 	pic_add(&bcm2836mp_pic, BCM2836_INT_LOCALBASE);
    210 #endif
    211 
    212 	aprint_normal("\n");
    213 }
    214 
    215 void
    216 bcm2835_irq_handler(void *frame)
    217 {
    218 	struct cpu_info * const ci = curcpu();
    219 	const int oldipl = ci->ci_cpl;
    220 	const uint32_t oldipl_mask = __BIT(oldipl);
    221 	int ipl_mask = 0;
    222 
    223 	ci->ci_data.cpu_nintr++;
    224 
    225 	bcm2835_barrier();
    226 	ipl_mask = bcm2835_pic_find_pending_irqs(&bcm2835_pic);
    227 #if defined(BCM2836)
    228 	ipl_mask |= bcm2836mp_pic_find_pending_irqs(&bcm2836mp_pic);
    229 #endif
    230 
    231 	/*
    232 	 * Record the pending_ipls and deliver them if we can.
    233 	 */
    234 	if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
    235 		pic_do_pending_ints(I32_bit, oldipl, frame);
    236 }
    237 
    238 static void
    239 bcm2835_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
    240     uint32_t irq_mask)
    241 {
    242 
    243 	write_bcm2835reg(BCM2835_INTC_ENABLEBASE + (irqbase >> 3), irq_mask);
    244 	bcm2835_barrier();
    245 }
    246 
    247 static void
    248 bcm2835_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
    249     uint32_t irq_mask)
    250 {
    251 
    252 	write_bcm2835reg(BCM2835_INTC_DISABLEBASE + (irqbase >> 3), irq_mask);
    253 	bcm2835_barrier();
    254 }
    255 
    256 /*
    257  * Called with interrupts disabled
    258  */
    259 static int
    260 bcm2835_pic_find_pending_irqs(struct pic_softc *pic)
    261 {
    262 	int ipl = 0;
    263 	uint32_t bpending, gpu0irq, gpu1irq, armirq;
    264 
    265 	bcm2835_barrier();
    266 	bpending = read_bcm2835reg(BCM2835_INTC_IRQBPENDING);
    267 	if (bpending == 0)
    268 		return 0;
    269 
    270 	armirq = bpending & BCM2835_INTBIT_ARM;
    271 	gpu0irq = bpending & BCM2835_INTBIT_GPU0;
    272 	gpu1irq = bpending & BCM2835_INTBIT_GPU1;
    273 
    274 	if (armirq) {
    275 		ipl |= pic_mark_pending_sources(pic, BCM2835_INT_BASICBASE,
    276 		    armirq);
    277 
    278 	}
    279 
    280 	if (gpu0irq || (bpending & BCM2835_INTBIT_PENDING1)) {
    281 		uint32_t pending1;
    282 
    283 		pending1 = read_bcm2835reg(BCM2835_INTC_IRQ1PENDING);
    284 		ipl |= pic_mark_pending_sources(pic, BCM2835_INT_GPU0BASE,
    285 		    pending1);
    286 	}
    287 	if (gpu1irq || (bpending & BCM2835_INTBIT_PENDING2)) {
    288 		uint32_t pending2;
    289 
    290 		pending2 = read_bcm2835reg(BCM2835_INTC_IRQ2PENDING);
    291 		ipl |= pic_mark_pending_sources(pic, BCM2835_INT_GPU1BASE,
    292 		    pending2);
    293 	}
    294 
    295 	return ipl;
    296 }
    297 
    298 static void
    299 bcm2835_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
    300 {
    301 
    302 	/* Nothing really*/
    303 	KASSERT(is->is_irq < BCM2835_NIRQ);
    304 	KASSERT(is->is_type == IST_LEVEL);
    305 }
    306 
    307 static void
    308 bcm2835_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
    309 {
    310 
    311 	strlcpy(buf, bcm2835_sources[irq], len);
    312 }
    313 
    314 
    315 #if defined(BCM2836)
    316 
    317 #define	BCM2836MP_TIMER_IRQS	__BITS(3,0)
    318 #define	BCM2836MP_MAILBOX_IRQS	__BITS(4,4)
    319 
    320 #define	BCM2836MP_ALL_IRQS	\
    321      (BCM2836MP_TIMER_IRQS | BCM2836MP_MAILBOX_IRQS)
    322 
    323 static void
    324 bcm2836mp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
    325     uint32_t irq_mask)
    326 {
    327 	const int cpuid = 0;
    328 
    329 //printf("%s: irqbase %zu irq_mask %08x\n", __func__, irqbase, irq_mask);
    330 
    331 	if (irq_mask & BCM2836MP_TIMER_IRQS) {
    332 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
    333 		uint32_t val = bus_space_read_4(al_iot, al_ioh,
    334 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
    335 		val |= mask;
    336 		bus_space_write_4(al_iot, al_ioh,
    337 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
    338 		    val);
    339 		bus_space_barrier(al_iot, al_ioh,
    340 		    BCM2836_LOCAL_TIMER_IRQ_CONTROL_BASE,
    341 		    BCM2836_LOCAL_TIMER_IRQ_CONTROL_SIZE,
    342 		    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
    343 //printf("%s: val %08x\n", __func__, val);
    344 	} else if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
    345 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
    346 		uint32_t val = bus_space_read_4(al_iot, al_ioh,
    347 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
    348 		val |= mask;
    349 		bus_space_write_4(al_iot, al_ioh,
    350 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
    351 		    val);
    352 		bus_space_barrier(al_iot, al_ioh,
    353 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_BASE,
    354 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_SIZE,
    355 		    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
    356 	}
    357 
    358 	return;
    359 }
    360 
    361 static void
    362 bcm2836mp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
    363     uint32_t irq_mask)
    364 {
    365 	const int cpuid = 0;
    366 
    367 //printf("%s: irqbase %zu irq_mask %08x\n", __func__, irqbase, irq_mask);
    368 	if (irq_mask & BCM2836MP_TIMER_IRQS) {
    369 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
    370 		uint32_t val = bus_space_read_4(al_iot, al_ioh,
    371 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
    372 		val &= ~mask;
    373 		bus_space_write_4(al_iot, al_ioh,
    374 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
    375 		    val);
    376 //printf("%s: val %08x\n", __func__, val);
    377 	} else if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
    378 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
    379 		uint32_t val = bus_space_read_4(al_iot, al_ioh,
    380 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
    381 		val &= ~mask;
    382 		bus_space_write_4(al_iot, al_ioh,
    383 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
    384 		    val);
    385 	}
    386 
    387 	bcm2835_barrier();
    388 	return;
    389 }
    390 
    391 
    392 static int
    393 bcm2836mp_pic_find_pending_irqs(struct pic_softc *pic)
    394 {
    395 	const int cpuid = 0;
    396 	uint32_t lpending;
    397 	int ipl = 0;
    398 
    399 	bcm2835_barrier();
    400 
    401 	lpending = bus_space_read_4(al_iot, al_ioh,
    402 	    BCM2836_LOCAL_INTC_IRQPENDINGN(cpuid));
    403 
    404 	lpending &= ~BCM2836_INTBIT_GPUPENDING;
    405 	if (lpending & BCM2836MP_ALL_IRQS) {
    406 		ipl |= pic_mark_pending_sources(pic, 0 /* BCM2836_INT_LOCALBASE */,
    407 		    lpending & BCM2836MP_ALL_IRQS);
    408 	}
    409 
    410 	return ipl;
    411 }
    412 
    413 static void
    414 bcm2836mp_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
    415 {
    416 
    417 	/* Nothing really*/
    418 	KASSERT(is->is_irq >= 0);
    419 	KASSERT(is->is_irq < BCM2836MP_NIRQ);
    420 //	KASSERT(is->is_type == IST_LEVEL);
    421 
    422 
    423 }
    424 
    425 static void
    426 bcm2836mp_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
    427 {
    428 	irq %= 32;
    429 	strlcpy(buf, bcm2836mp_sources[irq], len);
    430 }
    431 #endif
    432