Home | History | Annotate | Line # | Download | only in broadcom
bcm2835_intr.c revision 1.3.12.2
      1 /*	$NetBSD: bcm2835_intr.c,v 1.3.12.2 2015/03/11 20:22:55 snj 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.3.12.2 2015/03/11 20:22:55 snj 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 #if 0
     71 #ifdef MULTIPROCESSOR
     72 int bcm2836mp_ipi_handler(void *);
     73 static void bcm2836mp_cpu_init(struct pic_softc *, struct cpu_info *);
     74 static void bcm2836mp_send_ipi(struct pic_softc *, const kcpuset_t *, u_long);
     75 #endif
     76 #endif
     77 #endif
     78 
     79 #ifdef MULTIPROCESSOR
     80 static void
     81 bcm2835_dummy(struct pic_softc *pic, const kcpuset_t *kcp, u_long ipi)
     82 {
     83 }
     84 #endif
     85 
     86 static int  bcm2835_icu_match(device_t, cfdata_t, void *);
     87 static void bcm2835_icu_attach(device_t, device_t, void *);
     88 
     89 static struct pic_ops bcm2835_picops = {
     90 	.pic_unblock_irqs = bcm2835_pic_unblock_irqs,
     91 	.pic_block_irqs = bcm2835_pic_block_irqs,
     92 	.pic_find_pending_irqs = bcm2835_pic_find_pending_irqs,
     93 	.pic_establish_irq = bcm2835_pic_establish_irq,
     94 	.pic_source_name = bcm2835_pic_source_name,
     95 #if defined(MULTIPROCESSOR)
     96 	.pic_ipi_send = bcm2835_dummy,
     97 #endif
     98 };
     99 
    100 struct pic_softc bcm2835_pic = {
    101 	.pic_ops = &bcm2835_picops,
    102 	.pic_maxsources = BCM2835_NIRQ,
    103 	.pic_name = "bcm2835 pic",
    104 };
    105 
    106 #if defined(BCM2836)
    107 static struct pic_ops bcm2836mp_picops = {
    108 	.pic_unblock_irqs = bcm2836mp_pic_unblock_irqs,
    109 	.pic_block_irqs = bcm2836mp_pic_block_irqs,
    110 	.pic_find_pending_irqs = bcm2836mp_pic_find_pending_irqs,
    111 	.pic_establish_irq = bcm2836mp_pic_establish_irq,
    112 	.pic_source_name = bcm2836mp_pic_source_name,
    113 #if 0 && defined(MULTIPROCESSOR)
    114 	.pic_cpu_init = bcm2836mp_cpu_init,
    115 	.pic_ipi_send = bcm2836mp_send_ipi,
    116 #endif
    117 };
    118 
    119 struct pic_softc bcm2836mp_pic = {
    120 	.pic_ops = &bcm2836mp_picops,
    121 	.pic_maxsources = BCM2836MP_NIRQ,
    122 	.pic_name = "bcm2836 mp pic",
    123 };
    124 #endif
    125 
    126 struct bcm2835icu_softc {
    127 	device_t		sc_dev;
    128 	bus_space_tag_t		sc_iot;
    129 	bus_space_handle_t	sc_ioh;
    130 	struct pic_softc	*sc_pic;
    131 };
    132 
    133 struct bcm2835icu_softc *bcmicu_sc;
    134 
    135 #define read_bcm2835reg(o)	\
    136 	bus_space_read_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o))
    137 
    138 #define write_bcm2835reg(o, v)	\
    139 	bus_space_write_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o), (v))
    140 
    141 
    142 #define bcm2835_barrier() \
    143 	bus_space_barrier(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, 0, \
    144 	    BCM2835_ARMICU_SIZE, BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
    145 
    146 static const char * const bcm2835_sources[BCM2835_NIRQ] = {
    147 	"(unused  0)",	"(unused  1)",	"(unused  2)",	"timer3",
    148 	"(unused  4)",	"(unused  5)",	"(unused  6)",	"jpeg",
    149 	"(unused  8)",	"usb",		"(unused 10)",	"(unused 11)",
    150 	"(unused 12)",	"(unused 13)",	"(unused 14)",	"(unused 15)",
    151 	"dma0",		"dma1",		"dma2",		"dma3",
    152 	"dma4",		"dma5",		"dma6",		"dma7",
    153 	"dma8",		"dma9",		"dma10",	"dma11",
    154 	"dma12",	"aux",		"(unused 30)",	"(unused 31)",
    155 	"(unused 32)",	"(unused 33)",	"(unused 34)",	"(unused 35)",
    156 	"(unused 36)",	"(unused 37)",	"(unused 38)",	"(unused 39)",
    157 	"(unused 40)",	"(unused 41)",	"(unused 42)",	"i2c spl slv",
    158 	"(unused 44)",	"pwa0",		"pwa1",		"(unused 47)",
    159 	"smi",		"gpio[0]",	"gpio[1]",	"gpio[2]",
    160 	"gpio[3]",	"i2c",		"spi",		"pcm",
    161 	"sdio",		"uart",		"(unused 58)",	"(unused 59)",
    162 	"(unused 60)",	"(unused 61)",	"emmc",		"(unused 63)",
    163 	"Timer",	"Mailbox",	"Doorbell0",	"Doorbell1",
    164 	"GPU0 Halted",	"GPU1 Halted",	"Illegal #1",	"Illegal #0"
    165 };
    166 
    167 #if defined(BCM2836)
    168 static const char * const bcm2836mp_sources[BCM2836MP_NIRQ] = {
    169 	"cntpsirq",	"cntpnsirq",	"cnthpirq",	"cntvirq",
    170 	"mailbox0",	"mailbox1",	"mailbox2",	"mailbox3",
    171 };
    172 #endif
    173 
    174 #define	BCM2836_INTBIT_GPUPENDING	__BIT(8)
    175 
    176 #define	BCM2835_INTBIT_PENDING1		__BIT(8)
    177 #define	BCM2835_INTBIT_PENDING2		__BIT(9)
    178 #define	BCM2835_INTBIT_ARM		__BITS(0,7)
    179 #define	BCM2835_INTBIT_GPU0		__BITS(10,14)
    180 #define	BCM2835_INTBIT_GPU1		__BITS(15,20)
    181 
    182 CFATTACH_DECL_NEW(bcmicu, sizeof(struct bcm2835icu_softc),
    183     bcm2835_icu_match, bcm2835_icu_attach, NULL, NULL);
    184 
    185 static int
    186 bcm2835_icu_match(device_t parent, cfdata_t cf, void *aux)
    187 {
    188 	struct amba_attach_args *aaa = aux;
    189 
    190 	if (strcmp(aaa->aaa_name, "icu") != 0)
    191 		return 0;
    192 
    193 	return 1;
    194 }
    195 
    196 static void
    197 bcm2835_icu_attach(device_t parent, device_t self, void *aux)
    198 {
    199 	struct bcm2835icu_softc *sc = device_private(self);
    200 	struct amba_attach_args *aaa = aux;
    201 
    202 	sc->sc_dev = self;
    203 	sc->sc_iot = aaa->aaa_iot;
    204 	sc->sc_pic = &bcm2835_pic;
    205 
    206 	if (bus_space_map(aaa->aaa_iot, aaa->aaa_addr, aaa->aaa_size, 0,
    207 	    &sc->sc_ioh)) {
    208 		aprint_error_dev(self, "unable to map device\n");
    209 		return;
    210 	}
    211 
    212 	bcmicu_sc = sc;
    213 
    214 	pic_add(sc->sc_pic, 0);
    215 
    216 #if defined(BCM2836)
    217 #if 0 && defined(MULTIPROCESSOR)
    218 	aprint_normal(": Multiprocessor");
    219 #endif
    220 	pic_add(&bcm2836mp_pic, BCM2836_INT_LOCALBASE);
    221 #endif
    222 
    223 	aprint_normal("\n");
    224 }
    225 
    226 void
    227 bcm2835_irq_handler(void *frame)
    228 {
    229 	struct cpu_info * const ci = curcpu();
    230 	const int oldipl = ci->ci_cpl;
    231 	const uint32_t oldipl_mask = __BIT(oldipl);
    232 	int ipl_mask = 0;
    233 
    234 	ci->ci_data.cpu_nintr++;
    235 
    236 	bcm2835_barrier();
    237 	ipl_mask = bcm2835_pic_find_pending_irqs(&bcm2835_pic);
    238 #if defined(BCM2836)
    239 	ipl_mask |= bcm2836mp_pic_find_pending_irqs(&bcm2836mp_pic);
    240 #endif
    241 
    242 	/*
    243 	 * Record the pending_ipls and deliver them if we can.
    244 	 */
    245 	if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
    246 		pic_do_pending_ints(I32_bit, oldipl, frame);
    247 }
    248 
    249 static void
    250 bcm2835_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
    251     uint32_t irq_mask)
    252 {
    253 
    254 	write_bcm2835reg(BCM2835_INTC_ENABLEBASE + (irqbase >> 3), irq_mask);
    255 	bcm2835_barrier();
    256 }
    257 
    258 static void
    259 bcm2835_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
    260     uint32_t irq_mask)
    261 {
    262 
    263 	write_bcm2835reg(BCM2835_INTC_DISABLEBASE + (irqbase >> 3), irq_mask);
    264 	bcm2835_barrier();
    265 }
    266 
    267 /*
    268  * Called with interrupts disabled
    269  */
    270 static int
    271 bcm2835_pic_find_pending_irqs(struct pic_softc *pic)
    272 {
    273 	int ipl = 0;
    274 	uint32_t bpending, gpu0irq, gpu1irq, armirq;
    275 
    276 	bcm2835_barrier();
    277 	bpending = read_bcm2835reg(BCM2835_INTC_IRQBPENDING);
    278 	if (bpending == 0)
    279 		return 0;
    280 
    281 	armirq = bpending & BCM2835_INTBIT_ARM;
    282 	gpu0irq = bpending & BCM2835_INTBIT_GPU0;
    283 	gpu1irq = bpending & BCM2835_INTBIT_GPU1;
    284 
    285 	if (armirq) {
    286 		ipl |= pic_mark_pending_sources(pic, BCM2835_INT_BASICBASE,
    287 		    armirq);
    288 
    289 	}
    290 
    291 	if (gpu0irq || (bpending & BCM2835_INTBIT_PENDING1)) {
    292 		uint32_t pending1;
    293 
    294 		pending1 = read_bcm2835reg(BCM2835_INTC_IRQ1PENDING);
    295 		ipl |= pic_mark_pending_sources(pic, BCM2835_INT_GPU0BASE,
    296 		    pending1);
    297 	}
    298 	if (gpu1irq || (bpending & BCM2835_INTBIT_PENDING2)) {
    299 		uint32_t pending2;
    300 
    301 		pending2 = read_bcm2835reg(BCM2835_INTC_IRQ2PENDING);
    302 		ipl |= pic_mark_pending_sources(pic, BCM2835_INT_GPU1BASE,
    303 		    pending2);
    304 	}
    305 
    306 	return ipl;
    307 }
    308 
    309 static void
    310 bcm2835_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
    311 {
    312 
    313 	/* Nothing really*/
    314 	KASSERT(is->is_irq < BCM2835_NIRQ);
    315 	KASSERT(is->is_type == IST_LEVEL);
    316 }
    317 
    318 static void
    319 bcm2835_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
    320 {
    321 
    322 	strlcpy(buf, bcm2835_sources[irq], len);
    323 }
    324 
    325 
    326 #if defined(BCM2836)
    327 
    328 #define	BCM2836MP_TIMER_IRQS	__BITS(3,0)
    329 #define	BCM2836MP_MAILBOX_IRQS	__BITS(4,4)
    330 
    331 #define	BCM2836MP_ALL_IRQS	\
    332      (BCM2836MP_TIMER_IRQS | BCM2836MP_MAILBOX_IRQS)
    333 
    334 static void
    335 bcm2836mp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
    336     uint32_t irq_mask)
    337 {
    338 	const int cpuid = 0;
    339 
    340 //printf("%s: irqbase %zu irq_mask %08x\n", __func__, irqbase, irq_mask);
    341 
    342 	if (irq_mask & BCM2836MP_TIMER_IRQS) {
    343 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
    344 		uint32_t val = bus_space_read_4(al_iot, al_ioh,
    345 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
    346 		val |= mask;
    347 		bus_space_write_4(al_iot, al_ioh,
    348 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
    349 		    val);
    350 		bus_space_barrier(al_iot, al_ioh,
    351 		    BCM2836_LOCAL_TIMER_IRQ_CONTROL_BASE,
    352 		    BCM2836_LOCAL_TIMER_IRQ_CONTROL_SIZE,
    353 		    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
    354 //printf("%s: val %08x\n", __func__, val);
    355 	} else if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
    356 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
    357 		uint32_t val = bus_space_read_4(al_iot, al_ioh,
    358 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
    359 		val |= mask;
    360 		bus_space_write_4(al_iot, al_ioh,
    361 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
    362 		    val);
    363 		bus_space_barrier(al_iot, al_ioh,
    364 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_BASE,
    365 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_SIZE,
    366 		    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
    367 	}
    368 
    369 	return;
    370 }
    371 
    372 static void
    373 bcm2836mp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
    374     uint32_t irq_mask)
    375 {
    376 	const int cpuid = 0;
    377 
    378 //printf("%s: irqbase %zu irq_mask %08x\n", __func__, irqbase, irq_mask);
    379 	if (irq_mask & BCM2836MP_TIMER_IRQS) {
    380 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
    381 		uint32_t val = bus_space_read_4(al_iot, al_ioh,
    382 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
    383 		val &= ~mask;
    384 		bus_space_write_4(al_iot, al_ioh,
    385 		    BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
    386 		    val);
    387 //printf("%s: val %08x\n", __func__, val);
    388 	} else if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
    389 		uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
    390 		uint32_t val = bus_space_read_4(al_iot, al_ioh,
    391 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
    392 		val &= ~mask;
    393 		bus_space_write_4(al_iot, al_ioh,
    394 		    BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
    395 		    val);
    396 	}
    397 
    398 	bcm2835_barrier();
    399 	return;
    400 }
    401 
    402 
    403 static int
    404 bcm2836mp_pic_find_pending_irqs(struct pic_softc *pic)
    405 {
    406 	const int cpuid = 0;
    407 	uint32_t lpending;
    408 	int ipl = 0;
    409 
    410 	bcm2835_barrier();
    411 
    412 	lpending = bus_space_read_4(al_iot, al_ioh,
    413 	    BCM2836_LOCAL_INTC_IRQPENDINGN(cpuid));
    414 
    415 	lpending &= ~BCM2836_INTBIT_GPUPENDING;
    416 	if (lpending & BCM2836MP_ALL_IRQS) {
    417 		ipl |= pic_mark_pending_sources(pic, 0 /* BCM2836_INT_LOCALBASE */,
    418 		    lpending & BCM2836MP_ALL_IRQS);
    419 	}
    420 
    421 	return ipl;
    422 }
    423 
    424 static void
    425 bcm2836mp_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
    426 {
    427 
    428 	/* Nothing really*/
    429 	KASSERT(is->is_irq >= 0);
    430 	KASSERT(is->is_irq < BCM2836MP_NIRQ);
    431 //	KASSERT(is->is_type == IST_LEVEL);
    432 
    433 
    434 }
    435 
    436 static void
    437 bcm2836mp_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
    438 {
    439 	irq %= 32;
    440 	strlcpy(buf, bcm2836mp_sources[irq], len);
    441 }
    442 #endif
    443