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