Home | History | Annotate | Line # | Download | only in broadcom
bcm2835_intr.c revision 1.1
      1 /*	$NetBSD: bcm2835_intr.c,v 1.1 2012/07/26 06:21:57 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.1 2012/07/26 06:21:57 skrll Exp $");
     34 
     35 #define _INTR_PRIVATE
     36 
     37 #include <sys/param.h>
     38 #include <sys/proc.h>
     39 #include <sys/device.h>
     40 
     41 #include <machine/intr.h>
     42 #include <sys/bus.h>
     43 
     44 #include <arm/pic/picvar.h>
     45 
     46 #include <arm/broadcom/bcm_amba.h>
     47 #include <arm/broadcom/bcm2835reg.h>
     48 
     49 static void bcm2835_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
     50 static void bcm2835_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
     51 static int bcm2835_pic_find_pending_irqs(struct pic_softc *);
     52 static void bcm2835_pic_establish_irq(struct pic_softc *, struct intrsource *);
     53 static void bcm2835_pic_source_name(struct pic_softc *, int, char *,
     54     size_t);
     55 
     56 static int  bcm2835_icu_match(device_t, cfdata_t, void *);
     57 static void bcm2835_icu_attach(device_t, device_t, void *);
     58 
     59 static struct pic_ops bcm2835_picops = {
     60 	.pic_unblock_irqs = bcm2835_pic_unblock_irqs,
     61 	.pic_block_irqs = bcm2835_pic_block_irqs,
     62 	.pic_find_pending_irqs = bcm2835_pic_find_pending_irqs,
     63 	.pic_establish_irq = bcm2835_pic_establish_irq,
     64 	.pic_source_name = bcm2835_pic_source_name,
     65 };
     66 
     67 struct pic_softc bcm2835_pic = {
     68 	.pic_ops = &bcm2835_picops,
     69 	.pic_maxsources = BCM2835_NIRQ,
     70 	.pic_name = "bcm2835 pic",
     71 };
     72 
     73 struct bcm2835icu_softc {
     74 	device_t		sc_dev;
     75 	bus_space_tag_t		sc_iot;
     76 	bus_space_handle_t	sc_ioh;
     77 	struct pic_softc	*sc_pic;
     78 };
     79 
     80 struct bcm2835icu_softc *bcmicu_sc;
     81 
     82 #define read_bcm2835reg(o)	\
     83 	bus_space_read_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o))
     84 
     85 #define write_bcm2835reg(o, v)	\
     86 	bus_space_write_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o), (v))
     87 
     88 
     89 #define bcm2835_barrier() \
     90 	bus_space_barrier(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, 0, \
     91 	    BCM2835_ARMICU_SIZE, BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
     92 
     93 static const char * const bcm2835_sources[BCM2835_NIRQ] = {
     94 	"(unused  0)",	"(unused  1)",	"(unused  2)",	"timer3",
     95 	"(unused  4)",	"(unused  5)",	"(unused  6)",	"jpeg",
     96 	"(unused  8)",	"usb",		"(unused 10)",	"(unused 11)"
     97 	"(unused 12)",	"(unused 13)",	"(unused 14)",	"(unused 15)"
     98 	"(unused 16)",	"(unused 17)",	"dma2",		"dma3",
     99 	"(unused 20)",	"(unused 21)",	"(unused 22)",	"(unused 23)",
    100 	"(unused 24)",	"(unused 25)",	"(unused 26)",	"(unused 27)",
    101 	"(unused 28)",	"aux",		"(unused 30)",	"(unused 31)",
    102 	"(unused 32)",	"(unused 33)",	"(unused 34)",	"(unused 35)",
    103 	"(unused 36)",	"(unused 37)",	"(unused 38)",	"(unused 39)",
    104 	"(unused 40)",	"(unused 41)",	"(unused 42)",	"i2c spl slv",
    105 	"(unused 44)",	"pwa0",		"pwa1",		"(unused 47)",
    106 	"smi",		"gpio[0]",	"gpio[1]",	"gpio[2]",
    107 	"gpio[3]",	"i2c",		"spi",		"pcm",
    108 	"sdio",		"uart",		"(unused 58)",	"(unused 59)",
    109 	"(unused 60)",	"(unused 61)",	"emmc",		"(unused 63)",
    110 	"Timer",	"Mailbox",	"Doorbell0",	"Doorbell1",
    111 	"GPU0 Halted",	"GPU1 Halted",	"Illegal #1",	"Illegal #0"
    112 };
    113 
    114 #define	BCM2835_INTBIT_PENDING1		__BIT(8)
    115 #define	BCM2835_INTBIT_PENDING2		__BIT(9)
    116 #define	BCM2835_INTBIT_ARM		__BITS(0,7)
    117 #define	BCM2835_INTBIT_GPU0		__BITS(10,14)
    118 #define	BCM2835_INTBIT_GPU1		__BITS(15,20)
    119 
    120 CFATTACH_DECL_NEW(bcmicu, sizeof(struct bcm2835icu_softc),
    121     bcm2835_icu_match, bcm2835_icu_attach, NULL, NULL);
    122 
    123 static int
    124 bcm2835_icu_match(device_t parent, cfdata_t cf, void *aux)
    125 {
    126 	struct amba_attach_args *aaa = aux;
    127 
    128 	if (strcmp(aaa->aaa_name, "icu") != 0)
    129 		return 0;
    130 
    131 	return 1;
    132 }
    133 
    134 static void
    135 bcm2835_icu_attach(device_t parent, device_t self, void *aux)
    136 {
    137 	struct bcm2835icu_softc *sc = device_private(self);
    138 	struct amba_attach_args *aaa = aux;
    139 
    140 	sc->sc_dev = self;
    141 	sc->sc_iot = aaa->aaa_iot;
    142 	sc->sc_pic = &bcm2835_pic;
    143 
    144 	if (bus_space_map(aaa->aaa_iot, aaa->aaa_addr, aaa->aaa_size, 0,
    145 	    &sc->sc_ioh)) {
    146 		aprint_error_dev(self, "unable to map device\n");
    147 		return;
    148 	}
    149 
    150 	bcmicu_sc = sc;
    151 	pic_add(sc->sc_pic, 0);
    152 	aprint_normal("\n");
    153 }
    154 
    155 void
    156 bcm2835_irq_handler(void *frame)
    157 {
    158 	struct cpu_info * const ci = curcpu();
    159 	const int oldipl = ci->ci_cpl;
    160 	const uint32_t oldipl_mask = __BIT(oldipl);
    161 	int ipl_mask = 0;
    162 
    163 	ci->ci_data.cpu_nintr++;
    164 
    165 	bcm2835_barrier();
    166 	ipl_mask = bcm2835_pic_find_pending_irqs(&bcm2835_pic);
    167 
    168 	/*
    169 	 * Record the pending_ipls and deliver them if we can.
    170 	 */
    171 	if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
    172 		pic_do_pending_ints(I32_bit, oldipl, frame);
    173 }
    174 
    175 
    176 static void
    177 bcm2835_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
    178     uint32_t irq_mask)
    179 {
    180 
    181 	write_bcm2835reg(BCM2835_INTC_ENABLEBASE + (irqbase >> 3), irq_mask);
    182 	bcm2835_barrier();
    183 }
    184 
    185 static void
    186 bcm2835_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
    187     uint32_t irq_mask)
    188 {
    189 
    190 	write_bcm2835reg(BCM2835_INTC_DISABLEBASE + (irqbase >> 3), irq_mask);
    191 	bcm2835_barrier();
    192 }
    193 
    194 /*
    195  * Called with interrupts disabled
    196  */
    197 static int
    198 bcm2835_pic_find_pending_irqs(struct pic_softc *pic)
    199 {
    200 	int ipl = 0;
    201 	uint32_t bpending, gpu0irq, gpu1irq, armirq;
    202 
    203 	bcm2835_barrier();
    204 	bpending = read_bcm2835reg(BCM2835_INTC_IRQBPENDING);
    205 	if (bpending == 0)
    206 		return 0;
    207 
    208 	armirq = bpending & BCM2835_INTBIT_ARM;
    209 	gpu0irq = bpending & BCM2835_INTBIT_GPU0;
    210 	gpu1irq = bpending & BCM2835_INTBIT_GPU1;
    211 
    212 	if (armirq) {
    213 		ipl |= pic_mark_pending_sources(pic, BCM2835_INT_BASICBASE,
    214 		    armirq);
    215 
    216 	}
    217 
    218 	if (gpu0irq || (bpending & BCM2835_INTBIT_PENDING1)) {
    219 		uint32_t pending1;
    220 
    221 		pending1 = read_bcm2835reg(BCM2835_INTC_IRQ1PENDING);
    222 		ipl |= pic_mark_pending_sources(pic, BCM2835_INT_GPU0BASE,
    223 		    pending1);
    224 	}
    225 	if (gpu1irq || (bpending & BCM2835_INTBIT_PENDING2)) {
    226 		uint32_t pending2;
    227 
    228 		pending2 = read_bcm2835reg(BCM2835_INTC_IRQ2PENDING);
    229 		ipl |= pic_mark_pending_sources(pic, BCM2835_INT_GPU1BASE,
    230 		    pending2);
    231 	}
    232 
    233 	return ipl;
    234 }
    235 
    236 static void
    237 bcm2835_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
    238 {
    239 
    240 	/* Nothing really*/
    241 	KASSERT(is->is_irq < BCM2835_NIRQ);
    242 	KASSERT(is->is_type == IST_LEVEL);
    243 }
    244 
    245 static void
    246 bcm2835_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
    247 {
    248 
    249 	strlcpy(buf, bcm2835_sources[irq], len);
    250 }
    251