Home | History | Annotate | Line # | Download | only in broadcom
bcm2835_intr.c revision 1.1.2.2
      1  1.1.2.2  jdc /*	$NetBSD: bcm2835_intr.c,v 1.1.2.2 2012/08/09 06:36:49 jdc Exp $	*/
      2  1.1.2.2  jdc 
      3  1.1.2.2  jdc /*-
      4  1.1.2.2  jdc  * Copyright (c) 2012 The NetBSD Foundation, Inc.
      5  1.1.2.2  jdc  * All rights reserved.
      6  1.1.2.2  jdc  *
      7  1.1.2.2  jdc  * This code is derived from software contributed to The NetBSD Foundation
      8  1.1.2.2  jdc  * by Nick Hudson
      9  1.1.2.2  jdc  *
     10  1.1.2.2  jdc  * Redistribution and use in source and binary forms, with or without
     11  1.1.2.2  jdc  * modification, are permitted provided that the following conditions
     12  1.1.2.2  jdc  * are met:
     13  1.1.2.2  jdc  * 1. Redistributions of source code must retain the above copyright
     14  1.1.2.2  jdc  *    notice, this list of conditions and the following disclaimer.
     15  1.1.2.2  jdc  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.1.2.2  jdc  *    notice, this list of conditions and the following disclaimer in the
     17  1.1.2.2  jdc  *    documentation and/or other materials provided with the distribution.
     18  1.1.2.2  jdc  *
     19  1.1.2.2  jdc  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  1.1.2.2  jdc  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  1.1.2.2  jdc  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  1.1.2.2  jdc  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  1.1.2.2  jdc  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  1.1.2.2  jdc  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  1.1.2.2  jdc  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  1.1.2.2  jdc  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  1.1.2.2  jdc  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  1.1.2.2  jdc  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  1.1.2.2  jdc  * POSSIBILITY OF SUCH DAMAGE.
     30  1.1.2.2  jdc  */
     31  1.1.2.2  jdc 
     32  1.1.2.2  jdc #include <sys/cdefs.h>
     33  1.1.2.2  jdc __KERNEL_RCSID(0, "$NetBSD: bcm2835_intr.c,v 1.1.2.2 2012/08/09 06:36:49 jdc Exp $");
     34  1.1.2.2  jdc 
     35  1.1.2.2  jdc #define _INTR_PRIVATE
     36  1.1.2.2  jdc 
     37  1.1.2.2  jdc #include <sys/param.h>
     38  1.1.2.2  jdc #include <sys/proc.h>
     39  1.1.2.2  jdc #include <sys/device.h>
     40  1.1.2.2  jdc 
     41  1.1.2.2  jdc #include <machine/intr.h>
     42  1.1.2.2  jdc #include <sys/bus.h>
     43  1.1.2.2  jdc 
     44  1.1.2.2  jdc #include <arm/pic/picvar.h>
     45  1.1.2.2  jdc 
     46  1.1.2.2  jdc #include <arm/broadcom/bcm_amba.h>
     47  1.1.2.2  jdc #include <arm/broadcom/bcm2835reg.h>
     48  1.1.2.2  jdc 
     49  1.1.2.2  jdc static void bcm2835_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
     50  1.1.2.2  jdc static void bcm2835_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
     51  1.1.2.2  jdc static int bcm2835_pic_find_pending_irqs(struct pic_softc *);
     52  1.1.2.2  jdc static void bcm2835_pic_establish_irq(struct pic_softc *, struct intrsource *);
     53  1.1.2.2  jdc static void bcm2835_pic_source_name(struct pic_softc *, int, char *,
     54  1.1.2.2  jdc     size_t);
     55  1.1.2.2  jdc 
     56  1.1.2.2  jdc static int  bcm2835_icu_match(device_t, cfdata_t, void *);
     57  1.1.2.2  jdc static void bcm2835_icu_attach(device_t, device_t, void *);
     58  1.1.2.2  jdc 
     59  1.1.2.2  jdc static struct pic_ops bcm2835_picops = {
     60  1.1.2.2  jdc 	.pic_unblock_irqs = bcm2835_pic_unblock_irqs,
     61  1.1.2.2  jdc 	.pic_block_irqs = bcm2835_pic_block_irqs,
     62  1.1.2.2  jdc 	.pic_find_pending_irqs = bcm2835_pic_find_pending_irqs,
     63  1.1.2.2  jdc 	.pic_establish_irq = bcm2835_pic_establish_irq,
     64  1.1.2.2  jdc 	.pic_source_name = bcm2835_pic_source_name,
     65  1.1.2.2  jdc };
     66  1.1.2.2  jdc 
     67  1.1.2.2  jdc struct pic_softc bcm2835_pic = {
     68  1.1.2.2  jdc 	.pic_ops = &bcm2835_picops,
     69  1.1.2.2  jdc 	.pic_maxsources = BCM2835_NIRQ,
     70  1.1.2.2  jdc 	.pic_name = "bcm2835 pic",
     71  1.1.2.2  jdc };
     72  1.1.2.2  jdc 
     73  1.1.2.2  jdc struct bcm2835icu_softc {
     74  1.1.2.2  jdc 	device_t		sc_dev;
     75  1.1.2.2  jdc 	bus_space_tag_t		sc_iot;
     76  1.1.2.2  jdc 	bus_space_handle_t	sc_ioh;
     77  1.1.2.2  jdc 	struct pic_softc	*sc_pic;
     78  1.1.2.2  jdc };
     79  1.1.2.2  jdc 
     80  1.1.2.2  jdc struct bcm2835icu_softc *bcmicu_sc;
     81  1.1.2.2  jdc 
     82  1.1.2.2  jdc #define read_bcm2835reg(o)	\
     83  1.1.2.2  jdc 	bus_space_read_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o))
     84  1.1.2.2  jdc 
     85  1.1.2.2  jdc #define write_bcm2835reg(o, v)	\
     86  1.1.2.2  jdc 	bus_space_write_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o), (v))
     87  1.1.2.2  jdc 
     88  1.1.2.2  jdc 
     89  1.1.2.2  jdc #define bcm2835_barrier() \
     90  1.1.2.2  jdc 	bus_space_barrier(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, 0, \
     91  1.1.2.2  jdc 	    BCM2835_ARMICU_SIZE, BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
     92  1.1.2.2  jdc 
     93  1.1.2.2  jdc static const char * const bcm2835_sources[BCM2835_NIRQ] = {
     94  1.1.2.2  jdc 	"(unused  0)",	"(unused  1)",	"(unused  2)",	"timer3",
     95  1.1.2.2  jdc 	"(unused  4)",	"(unused  5)",	"(unused  6)",	"jpeg",
     96  1.1.2.2  jdc 	"(unused  8)",	"usb",		"(unused 10)",	"(unused 11)"
     97  1.1.2.2  jdc 	"(unused 12)",	"(unused 13)",	"(unused 14)",	"(unused 15)"
     98  1.1.2.2  jdc 	"(unused 16)",	"(unused 17)",	"dma2",		"dma3",
     99  1.1.2.2  jdc 	"(unused 20)",	"(unused 21)",	"(unused 22)",	"(unused 23)",
    100  1.1.2.2  jdc 	"(unused 24)",	"(unused 25)",	"(unused 26)",	"(unused 27)",
    101  1.1.2.2  jdc 	"(unused 28)",	"aux",		"(unused 30)",	"(unused 31)",
    102  1.1.2.2  jdc 	"(unused 32)",	"(unused 33)",	"(unused 34)",	"(unused 35)",
    103  1.1.2.2  jdc 	"(unused 36)",	"(unused 37)",	"(unused 38)",	"(unused 39)",
    104  1.1.2.2  jdc 	"(unused 40)",	"(unused 41)",	"(unused 42)",	"i2c spl slv",
    105  1.1.2.2  jdc 	"(unused 44)",	"pwa0",		"pwa1",		"(unused 47)",
    106  1.1.2.2  jdc 	"smi",		"gpio[0]",	"gpio[1]",	"gpio[2]",
    107  1.1.2.2  jdc 	"gpio[3]",	"i2c",		"spi",		"pcm",
    108  1.1.2.2  jdc 	"sdio",		"uart",		"(unused 58)",	"(unused 59)",
    109  1.1.2.2  jdc 	"(unused 60)",	"(unused 61)",	"emmc",		"(unused 63)",
    110  1.1.2.2  jdc 	"Timer",	"Mailbox",	"Doorbell0",	"Doorbell1",
    111  1.1.2.2  jdc 	"GPU0 Halted",	"GPU1 Halted",	"Illegal #1",	"Illegal #0"
    112  1.1.2.2  jdc };
    113  1.1.2.2  jdc 
    114  1.1.2.2  jdc #define	BCM2835_INTBIT_PENDING1		__BIT(8)
    115  1.1.2.2  jdc #define	BCM2835_INTBIT_PENDING2		__BIT(9)
    116  1.1.2.2  jdc #define	BCM2835_INTBIT_ARM		__BITS(0,7)
    117  1.1.2.2  jdc #define	BCM2835_INTBIT_GPU0		__BITS(10,14)
    118  1.1.2.2  jdc #define	BCM2835_INTBIT_GPU1		__BITS(15,20)
    119  1.1.2.2  jdc 
    120  1.1.2.2  jdc CFATTACH_DECL_NEW(bcmicu, sizeof(struct bcm2835icu_softc),
    121  1.1.2.2  jdc     bcm2835_icu_match, bcm2835_icu_attach, NULL, NULL);
    122  1.1.2.2  jdc 
    123  1.1.2.2  jdc static int
    124  1.1.2.2  jdc bcm2835_icu_match(device_t parent, cfdata_t cf, void *aux)
    125  1.1.2.2  jdc {
    126  1.1.2.2  jdc 	struct amba_attach_args *aaa = aux;
    127  1.1.2.2  jdc 
    128  1.1.2.2  jdc 	if (strcmp(aaa->aaa_name, "icu") != 0)
    129  1.1.2.2  jdc 		return 0;
    130  1.1.2.2  jdc 
    131  1.1.2.2  jdc 	return 1;
    132  1.1.2.2  jdc }
    133  1.1.2.2  jdc 
    134  1.1.2.2  jdc static void
    135  1.1.2.2  jdc bcm2835_icu_attach(device_t parent, device_t self, void *aux)
    136  1.1.2.2  jdc {
    137  1.1.2.2  jdc 	struct bcm2835icu_softc *sc = device_private(self);
    138  1.1.2.2  jdc 	struct amba_attach_args *aaa = aux;
    139  1.1.2.2  jdc 
    140  1.1.2.2  jdc 	sc->sc_dev = self;
    141  1.1.2.2  jdc 	sc->sc_iot = aaa->aaa_iot;
    142  1.1.2.2  jdc 	sc->sc_pic = &bcm2835_pic;
    143  1.1.2.2  jdc 
    144  1.1.2.2  jdc 	if (bus_space_map(aaa->aaa_iot, aaa->aaa_addr, aaa->aaa_size, 0,
    145  1.1.2.2  jdc 	    &sc->sc_ioh)) {
    146  1.1.2.2  jdc 		aprint_error_dev(self, "unable to map device\n");
    147  1.1.2.2  jdc 		return;
    148  1.1.2.2  jdc 	}
    149  1.1.2.2  jdc 
    150  1.1.2.2  jdc 	bcmicu_sc = sc;
    151  1.1.2.2  jdc 	pic_add(sc->sc_pic, 0);
    152  1.1.2.2  jdc 	aprint_normal("\n");
    153  1.1.2.2  jdc }
    154  1.1.2.2  jdc 
    155  1.1.2.2  jdc void
    156  1.1.2.2  jdc bcm2835_irq_handler(void *frame)
    157  1.1.2.2  jdc {
    158  1.1.2.2  jdc 	struct cpu_info * const ci = curcpu();
    159  1.1.2.2  jdc 	const int oldipl = ci->ci_cpl;
    160  1.1.2.2  jdc 	const uint32_t oldipl_mask = __BIT(oldipl);
    161  1.1.2.2  jdc 	int ipl_mask = 0;
    162  1.1.2.2  jdc 
    163  1.1.2.2  jdc 	ci->ci_data.cpu_nintr++;
    164  1.1.2.2  jdc 
    165  1.1.2.2  jdc 	bcm2835_barrier();
    166  1.1.2.2  jdc 	ipl_mask = bcm2835_pic_find_pending_irqs(&bcm2835_pic);
    167  1.1.2.2  jdc 
    168  1.1.2.2  jdc 	/*
    169  1.1.2.2  jdc 	 * Record the pending_ipls and deliver them if we can.
    170  1.1.2.2  jdc 	 */
    171  1.1.2.2  jdc 	if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
    172  1.1.2.2  jdc 		pic_do_pending_ints(I32_bit, oldipl, frame);
    173  1.1.2.2  jdc }
    174  1.1.2.2  jdc 
    175  1.1.2.2  jdc 
    176  1.1.2.2  jdc static void
    177  1.1.2.2  jdc bcm2835_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
    178  1.1.2.2  jdc     uint32_t irq_mask)
    179  1.1.2.2  jdc {
    180  1.1.2.2  jdc 
    181  1.1.2.2  jdc 	write_bcm2835reg(BCM2835_INTC_ENABLEBASE + (irqbase >> 3), irq_mask);
    182  1.1.2.2  jdc 	bcm2835_barrier();
    183  1.1.2.2  jdc }
    184  1.1.2.2  jdc 
    185  1.1.2.2  jdc static void
    186  1.1.2.2  jdc bcm2835_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
    187  1.1.2.2  jdc     uint32_t irq_mask)
    188  1.1.2.2  jdc {
    189  1.1.2.2  jdc 
    190  1.1.2.2  jdc 	write_bcm2835reg(BCM2835_INTC_DISABLEBASE + (irqbase >> 3), irq_mask);
    191  1.1.2.2  jdc 	bcm2835_barrier();
    192  1.1.2.2  jdc }
    193  1.1.2.2  jdc 
    194  1.1.2.2  jdc /*
    195  1.1.2.2  jdc  * Called with interrupts disabled
    196  1.1.2.2  jdc  */
    197  1.1.2.2  jdc static int
    198  1.1.2.2  jdc bcm2835_pic_find_pending_irqs(struct pic_softc *pic)
    199  1.1.2.2  jdc {
    200  1.1.2.2  jdc 	int ipl = 0;
    201  1.1.2.2  jdc 	uint32_t bpending, gpu0irq, gpu1irq, armirq;
    202  1.1.2.2  jdc 
    203  1.1.2.2  jdc 	bcm2835_barrier();
    204  1.1.2.2  jdc 	bpending = read_bcm2835reg(BCM2835_INTC_IRQBPENDING);
    205  1.1.2.2  jdc 	if (bpending == 0)
    206  1.1.2.2  jdc 		return 0;
    207  1.1.2.2  jdc 
    208  1.1.2.2  jdc 	armirq = bpending & BCM2835_INTBIT_ARM;
    209  1.1.2.2  jdc 	gpu0irq = bpending & BCM2835_INTBIT_GPU0;
    210  1.1.2.2  jdc 	gpu1irq = bpending & BCM2835_INTBIT_GPU1;
    211  1.1.2.2  jdc 
    212  1.1.2.2  jdc 	if (armirq) {
    213  1.1.2.2  jdc 		ipl |= pic_mark_pending_sources(pic, BCM2835_INT_BASICBASE,
    214  1.1.2.2  jdc 		    armirq);
    215  1.1.2.2  jdc 
    216  1.1.2.2  jdc 	}
    217  1.1.2.2  jdc 
    218  1.1.2.2  jdc 	if (gpu0irq || (bpending & BCM2835_INTBIT_PENDING1)) {
    219  1.1.2.2  jdc 		uint32_t pending1;
    220  1.1.2.2  jdc 
    221  1.1.2.2  jdc 		pending1 = read_bcm2835reg(BCM2835_INTC_IRQ1PENDING);
    222  1.1.2.2  jdc 		ipl |= pic_mark_pending_sources(pic, BCM2835_INT_GPU0BASE,
    223  1.1.2.2  jdc 		    pending1);
    224  1.1.2.2  jdc 	}
    225  1.1.2.2  jdc 	if (gpu1irq || (bpending & BCM2835_INTBIT_PENDING2)) {
    226  1.1.2.2  jdc 		uint32_t pending2;
    227  1.1.2.2  jdc 
    228  1.1.2.2  jdc 		pending2 = read_bcm2835reg(BCM2835_INTC_IRQ2PENDING);
    229  1.1.2.2  jdc 		ipl |= pic_mark_pending_sources(pic, BCM2835_INT_GPU1BASE,
    230  1.1.2.2  jdc 		    pending2);
    231  1.1.2.2  jdc 	}
    232  1.1.2.2  jdc 
    233  1.1.2.2  jdc 	return ipl;
    234  1.1.2.2  jdc }
    235  1.1.2.2  jdc 
    236  1.1.2.2  jdc static void
    237  1.1.2.2  jdc bcm2835_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
    238  1.1.2.2  jdc {
    239  1.1.2.2  jdc 
    240  1.1.2.2  jdc 	/* Nothing really*/
    241  1.1.2.2  jdc 	KASSERT(is->is_irq < BCM2835_NIRQ);
    242  1.1.2.2  jdc 	KASSERT(is->is_type == IST_LEVEL);
    243  1.1.2.2  jdc }
    244  1.1.2.2  jdc 
    245  1.1.2.2  jdc static void
    246  1.1.2.2  jdc bcm2835_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
    247  1.1.2.2  jdc {
    248  1.1.2.2  jdc 
    249  1.1.2.2  jdc 	strlcpy(buf, bcm2835_sources[irq], len);
    250  1.1.2.2  jdc }
    251